From 3b55a62fdcb1f8222de3c2c8fbed530792c419a0 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 12 Oct 2012 14:53:57 +0000 Subject: GTalkExt, ICQ, IRC, Jabber: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1890 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/GTalkExt/GTalkExt.cpp | 91 - protocols/GTalkExt/GTalkExt.vcxproj | 48 +- protocols/GTalkExt/GTalkExt.vcxproj.filters | 48 +- protocols/GTalkExt/avatar.cpp | 212 -- protocols/GTalkExt/avatar.h | 25 - protocols/GTalkExt/db.cpp | 100 - protocols/GTalkExt/db.h | 31 - protocols/GTalkExt/dllmain.cpp | 62 - protocols/GTalkExt/docs/gtalkext-translation.txt | 25 + protocols/GTalkExt/gtalkext-translation.txt | 25 - protocols/GTalkExt/handlers.cpp | 433 --- protocols/GTalkExt/handlers.h | 27 - protocols/GTalkExt/inbox.cpp | 402 --- protocols/GTalkExt/inbox.h | 25 - protocols/GTalkExt/menu.cpp | 95 - protocols/GTalkExt/menu.h | 24 - protocols/GTalkExt/notifications.cpp | 414 --- protocols/GTalkExt/notifications.h | 42 - protocols/GTalkExt/options.cpp | 297 -- protocols/GTalkExt/options.h | 39 - protocols/GTalkExt/popups.cpp | 104 - protocols/GTalkExt/popups.h | 25 - protocols/GTalkExt/res/settings.rc | 6 +- protocols/GTalkExt/resources.h | 67 - protocols/GTalkExt/src/GTalkExt.cpp | 91 + protocols/GTalkExt/src/avatar.cpp | 212 ++ protocols/GTalkExt/src/avatar.h | 25 + protocols/GTalkExt/src/db.cpp | 100 + protocols/GTalkExt/src/db.h | 31 + protocols/GTalkExt/src/dllmain.cpp | 62 + protocols/GTalkExt/src/handlers.cpp | 433 +++ protocols/GTalkExt/src/handlers.h | 27 + protocols/GTalkExt/src/inbox.cpp | 402 +++ protocols/GTalkExt/src/inbox.h | 25 + protocols/GTalkExt/src/menu.cpp | 95 + protocols/GTalkExt/src/menu.h | 24 + protocols/GTalkExt/src/notifications.cpp | 414 +++ protocols/GTalkExt/src/notifications.h | 42 + protocols/GTalkExt/src/options.cpp | 297 ++ protocols/GTalkExt/src/options.h | 39 + protocols/GTalkExt/src/popups.cpp | 104 + protocols/GTalkExt/src/popups.h | 25 + protocols/GTalkExt/src/resources.h | 67 + protocols/GTalkExt/src/stdafx.cpp | 25 + protocols/GTalkExt/src/stdafx.h | 71 + protocols/GTalkExt/src/targetver.h | 47 + protocols/GTalkExt/src/tipper_items.cpp | 157 + protocols/GTalkExt/src/tipper_items.h | 24 + protocols/GTalkExt/stdafx.cpp | 25 - protocols/GTalkExt/stdafx.h | 71 - protocols/GTalkExt/targetver.h | 47 - protocols/GTalkExt/tipper_items.cpp | 157 - protocols/GTalkExt/tipper_items.h | 24 - protocols/IRCG/Docs/ircg-translation.txt | 409 +++ protocols/IRCG/IRC.rc | 744 ----- protocols/IRCG/IRC_10.vcxproj | 67 +- protocols/IRCG/IRC_10.vcxproj.filters | 105 +- protocols/IRCG/Icons/add.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/apply.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/block.ico | Bin 2038 -> 0 bytes protocols/IRCG/Icons/dcc.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/delete.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/edit.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/irc.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/list.ico | Bin 5430 -> 0 bytes protocols/IRCG/Icons/manager.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/question.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/quick.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/rename.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/server.ico | Bin 5430 -> 0 bytes protocols/IRCG/Icons/show.ico | Bin 2550 -> 0 bytes protocols/IRCG/Icons/whois.ico | Bin 6830 -> 0 bytes protocols/IRCG/Icons/world.ico | Bin 13430 -> 0 bytes protocols/IRCG/MString.cpp | 201 -- protocols/IRCG/MString.h | 2300 --------------- protocols/IRCG/clist.cpp | 247 -- protocols/IRCG/commandmonitor.cpp | 2508 ---------------- protocols/IRCG/commandmonitor.h | 22 - protocols/IRCG/input.cpp | 936 ------ protocols/IRCG/irc.h | 725 ----- protocols/IRCG/irc_dlg.h | 329 --- protocols/IRCG/ircg-translation.txt | 409 --- protocols/IRCG/irclib.cpp | 1505 ---------- protocols/IRCG/irclib.h | 175 -- protocols/IRCG/ircproto.cpp | 1076 ------- protocols/IRCG/main.cpp | 122 - protocols/IRCG/options.cpp | 1962 ------------- protocols/IRCG/output.cpp | 158 - protocols/IRCG/proto_irc/Proto_IRC.rc | Bin 3506 -> 0 bytes protocols/IRCG/proto_irc/Proto_IRC.vcxproj | 4 +- protocols/IRCG/proto_irc/Proto_IRC.vcxproj.filters | 4 +- protocols/IRCG/proto_irc/ico/Away.ico | Bin 5430 -> 0 bytes protocols/IRCG/proto_irc/ico/Offline.ico | Bin 5430 -> 0 bytes protocols/IRCG/proto_irc/ico/Online.ico | Bin 5430 -> 0 bytes protocols/IRCG/proto_irc/res/Away.ico | Bin 0 -> 5430 bytes protocols/IRCG/proto_irc/res/Offline.ico | Bin 0 -> 5430 bytes protocols/IRCG/proto_irc/res/Online.ico | Bin 0 -> 5430 bytes protocols/IRCG/proto_irc/res/Proto_IRC.rc | Bin 0 -> 3508 bytes protocols/IRCG/proto_irc/resource.h | Bin 1086 -> 0 bytes protocols/IRCG/proto_irc/src/resource.h | Bin 0 -> 1086 bytes protocols/IRCG/res/IRC.rc | 744 +++++ protocols/IRCG/res/add.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/apply.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/block.ico | Bin 0 -> 2038 bytes protocols/IRCG/res/dcc.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/delete.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/edit.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/irc.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/list.ico | Bin 0 -> 5430 bytes protocols/IRCG/res/manager.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/question.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/quick.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/rename.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/server.ico | Bin 0 -> 5430 bytes protocols/IRCG/res/show.ico | Bin 0 -> 2550 bytes protocols/IRCG/res/version.rc | 41 + protocols/IRCG/res/whois.ico | Bin 0 -> 6830 bytes protocols/IRCG/res/world.ico | Bin 0 -> 13430 bytes protocols/IRCG/resource.h | 253 -- protocols/IRCG/scripting.cpp | 265 -- protocols/IRCG/services.cpp | 1254 -------- protocols/IRCG/src/MString.cpp | 201 ++ protocols/IRCG/src/MString.h | 2300 +++++++++++++++ protocols/IRCG/src/clist.cpp | 247 ++ protocols/IRCG/src/commandmonitor.cpp | 2508 ++++++++++++++++ protocols/IRCG/src/commandmonitor.h | 22 + protocols/IRCG/src/input.cpp | 936 ++++++ protocols/IRCG/src/irc.h | 725 +++++ protocols/IRCG/src/irc_dlg.h | 329 +++ protocols/IRCG/src/irclib.cpp | 1505 ++++++++++ protocols/IRCG/src/irclib.h | 175 ++ protocols/IRCG/src/ircproto.cpp | 1076 +++++++ protocols/IRCG/src/main.cpp | 122 + protocols/IRCG/src/options.cpp | 1962 +++++++++++++ protocols/IRCG/src/output.cpp | 158 + protocols/IRCG/src/resource.h | 253 ++ protocols/IRCG/src/scripting.cpp | 265 ++ protocols/IRCG/src/services.cpp | 1254 ++++++++ protocols/IRCG/src/tools.cpp | 905 ++++++ protocols/IRCG/src/ui_utils.cpp | 1820 ++++++++++++ protocols/IRCG/src/ui_utils.h | 1108 +++++++ protocols/IRCG/src/userinfo.cpp | 224 ++ protocols/IRCG/src/version.h | 12 + protocols/IRCG/src/windows.cpp | 1406 +++++++++ protocols/IRCG/tools.cpp | 905 ------ protocols/IRCG/ui_utils.cpp | 1820 ------------ protocols/IRCG/ui_utils.h | 1108 ------- protocols/IRCG/userinfo.cpp | 224 -- protocols/IRCG/version.h | 12 - protocols/IRCG/version.rc | 41 - protocols/IRCG/windows.cpp | 1406 --------- protocols/IcqOscarJ/UI/askauthentication.cpp | 96 - protocols/IcqOscarJ/UI/icqoscar.h | 2 - protocols/IcqOscarJ/UI/loginpassword.cpp | 97 - protocols/IcqOscarJ/UI/userinfotab.cpp | 315 -- protocols/IcqOscarJ/capabilities.cpp | 271 -- protocols/IcqOscarJ/capabilities.h | 45 - protocols/IcqOscarJ/chan_01login.cpp | 105 - protocols/IcqOscarJ/chan_02data.cpp | 222 -- protocols/IcqOscarJ/chan_03error.cpp | 35 - protocols/IcqOscarJ/chan_04close.cpp | 314 -- protocols/IcqOscarJ/chan_05ping.cpp | 89 - protocols/IcqOscarJ/changeinfo/changeinfo.h | 122 - protocols/IcqOscarJ/changeinfo/constants.cpp | 198 -- protocols/IcqOscarJ/changeinfo/db.cpp | 224 -- protocols/IcqOscarJ/changeinfo/dlgproc.cpp | 540 ---- protocols/IcqOscarJ/changeinfo/editlist.cpp | 201 -- protocols/IcqOscarJ/changeinfo/editstring.cpp | 367 --- protocols/IcqOscarJ/changeinfo/expandst.ico | Bin 318 -> 0 bytes protocols/IcqOscarJ/changeinfo/icqoscar.h | 2 - protocols/IcqOscarJ/changeinfo/main.cpp | 28 - protocols/IcqOscarJ/changeinfo/upload.cpp | 91 - protocols/IcqOscarJ/channels.h | 47 - protocols/IcqOscarJ/cookies.cpp | 301 -- protocols/IcqOscarJ/cookies.h | 148 - protocols/IcqOscarJ/directpackets.cpp | 293 -- protocols/IcqOscarJ/docs/icqoscarj-translation.txt | 1044 +++++++ protocols/IcqOscarJ/fam_01service.cpp | 983 ------- protocols/IcqOscarJ/fam_02location.cpp | 312 -- protocols/IcqOscarJ/fam_03buddy.cpp | 787 ----- protocols/IcqOscarJ/fam_04message.cpp | 3043 -------------------- protocols/IcqOscarJ/fam_09bos.cpp | 106 - protocols/IcqOscarJ/fam_0alookup.cpp | 130 - protocols/IcqOscarJ/fam_0bstatus.cpp | 62 - protocols/IcqOscarJ/fam_13servclist.cpp | 2068 ------------- protocols/IcqOscarJ/fam_15icqserver.cpp | 1201 -------- protocols/IcqOscarJ/fam_17signon.cpp | 175 -- protocols/IcqOscarJ/families.h | 74 - protocols/IcqOscarJ/globals.h | 57 - protocols/IcqOscarJ/guids.h | 81 - protocols/IcqOscarJ/i18n.cpp | 541 ---- protocols/IcqOscarJ/i18n.h | 70 - protocols/IcqOscarJ/iconlib.cpp | 92 - protocols/IcqOscarJ/iconlib.h | 52 - protocols/IcqOscarJ/icons_pack/ICONS.rc | 132 - protocols/IcqOscarJ/icons_pack/ICONS.vcxproj | 5 +- protocols/IcqOscarJ/icons_pack/res/ICONS.rc | 132 + protocols/IcqOscarJ/icons_pack/res/Xstatus34.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus35.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus36.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus38.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus39.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus40.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus41.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus42.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus45.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus46.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus47.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus48.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus49.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus50.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus51.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus52.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus53.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus54.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus56.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus57.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus58.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus59.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus60.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus61.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus62.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus63.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus65.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus66.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus67.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus68.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus69.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus70.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus71.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus72.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus73.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus74.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus75.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus76.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus77.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus78.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus79.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus81.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus82.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus83.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus84.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/Xstatus86.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus01.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus02.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus03.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus04.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus05.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus06.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus07.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus08.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus09.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus10.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus11.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus12.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus13.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus14.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus15.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus16.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus17.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus18.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus19.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus20.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus21.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus22.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus23.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus24.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus25.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus26.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus27.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus28.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus29.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus30.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus31.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus32.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus33.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus37.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus43.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus44.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus55.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus64.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus80.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/res/xstatus85.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/icons_pack/src/resource.h | 101 + protocols/IcqOscarJ/icos/Xstatus34.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus35.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus36.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus38.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus39.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus40.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus41.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus42.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus45.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus46.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus47.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus48.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus49.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus50.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus51.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus52.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus53.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus54.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus56.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus57.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus58.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus59.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus60.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus61.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus62.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus63.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus65.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus66.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus67.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus68.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus69.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus70.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus71.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus72.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus73.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus74.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus75.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus76.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus77.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus78.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus79.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus81.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus82.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus83.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus84.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/Xstatus86.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/auth_ask.ico | Bin 2038 -> 0 bytes protocols/IcqOscarJ/icos/auth_grant.ico | Bin 2038 -> 0 bytes protocols/IcqOscarJ/icos/auth_revoke.ico | Bin 2038 -> 0 bytes protocols/IcqOscarJ/icos/icq.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/srvlist_add.ico | Bin 2038 -> 0 bytes protocols/IcqOscarJ/icos/xstatus01.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus02.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus03.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus04.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus05.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus06.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus07.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus08.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus09.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus10.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus11.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus12.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus13.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus14.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus15.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus16.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus17.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus18.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus19.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus20.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus21.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus22.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus23.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus24.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus25.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus26.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus27.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus28.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus29.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus30.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus31.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus32.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus33.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus37.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus43.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus44.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus55.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus64.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus80.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icos/xstatus85.ico | Bin 6830 -> 0 bytes protocols/IcqOscarJ/icq_advsearch.cpp | 185 -- protocols/IcqOscarJ/icq_advsearch.h | 32 - protocols/IcqOscarJ/icq_avatar.cpp | 1814 ------------ protocols/IcqOscarJ/icq_avatar.h | 127 - protocols/IcqOscarJ/icq_clients.cpp | 1155 -------- protocols/IcqOscarJ/icq_constants.h | 652 ----- protocols/IcqOscarJ/icq_db.cpp | 399 --- protocols/IcqOscarJ/icq_db.h | 44 - protocols/IcqOscarJ/icq_direct.cpp | 1171 -------- protocols/IcqOscarJ/icq_direct.h | 94 - protocols/IcqOscarJ/icq_directmsg.cpp | 361 --- protocols/IcqOscarJ/icq_fieldnames.cpp | 595 ---- protocols/IcqOscarJ/icq_fieldnames.h | 49 - protocols/IcqOscarJ/icq_filerequests.cpp | 218 -- protocols/IcqOscarJ/icq_filetransfer.cpp | 515 ---- protocols/IcqOscarJ/icq_firstrun.cpp | 124 - protocols/IcqOscarJ/icq_http.cpp | 212 -- protocols/IcqOscarJ/icq_http.h | 48 - protocols/IcqOscarJ/icq_infoupdate.cpp | 401 --- protocols/IcqOscarJ/icq_menu.cpp | 263 -- protocols/IcqOscarJ/icq_opts.cpp | 617 ---- protocols/IcqOscarJ/icq_packet.cpp | 898 ------ protocols/IcqOscarJ/icq_packet.h | 120 - protocols/IcqOscarJ/icq_popups.cpp | 323 --- protocols/IcqOscarJ/icq_popups.h | 41 - protocols/IcqOscarJ/icq_proto.cpp | 2375 --------------- protocols/IcqOscarJ/icq_proto.h | 984 ------- protocols/IcqOscarJ/icq_rates.cpp | 529 ---- protocols/IcqOscarJ/icq_rates.h | 146 - protocols/IcqOscarJ/icq_server.cpp | 444 --- protocols/IcqOscarJ/icq_server.h | 71 - protocols/IcqOscarJ/icq_servlist.cpp | 2829 ------------------ protocols/IcqOscarJ/icq_servlist.h | 172 -- protocols/IcqOscarJ/icq_uploadui.cpp | 1019 ------- protocols/IcqOscarJ/icq_xstatus.cpp | 1380 --------- protocols/IcqOscarJ/icq_xtraz.cpp | 466 --- protocols/IcqOscarJ/icqosc_svcs.cpp | 816 ------ protocols/IcqOscarJ/icqosc_svcs.h | 39 - protocols/IcqOscarJ/icqoscar.cpp | 35 - protocols/IcqOscarJ/icqoscar.h | 134 - protocols/IcqOscarJ/icqoscar8_10.vcxproj | 184 +- protocols/IcqOscarJ/icqoscar8_10.vcxproj.filters | 188 +- protocols/IcqOscarJ/icqoscarj-translation.txt | 1044 ------- protocols/IcqOscarJ/init.cpp | 245 -- protocols/IcqOscarJ/init.h | 40 - protocols/IcqOscarJ/log.cpp | 161 -- protocols/IcqOscarJ/log.h | 38 - protocols/IcqOscarJ/oscar_filetransfer.cpp | 2447 ---------------- protocols/IcqOscarJ/oscar_filetransfer.h | 164 -- protocols/IcqOscarJ/proto_icq/Proto_ICQ.rc | Bin 4316 -> 0 bytes protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj | 4 +- .../IcqOscarJ/proto_icq/Proto_ICQ.vcxproj.filters | 4 +- protocols/IcqOscarJ/proto_icq/icos/Away.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/DND.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/FFC.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/Invisible.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/NA.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/Occupied.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/Offline.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/Online.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/icos/Phone.ico | Bin 5430 -> 0 bytes protocols/IcqOscarJ/proto_icq/res/Away.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/DND.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/FFC.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Invisible.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/NA.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Occupied.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Offline.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Online.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Phone.ico | Bin 0 -> 5430 bytes protocols/IcqOscarJ/proto_icq/res/Proto_ICQ.rc | Bin 0 -> 4240 bytes protocols/IcqOscarJ/proto_icq/resource.h | Bin 1628 -> 0 bytes protocols/IcqOscarJ/proto_icq/src/resource.h | Bin 0 -> 1628 bytes protocols/IcqOscarJ/res/auth_ask.ico | Bin 0 -> 2038 bytes protocols/IcqOscarJ/res/auth_grant.ico | Bin 0 -> 2038 bytes protocols/IcqOscarJ/res/auth_revoke.ico | Bin 0 -> 2038 bytes protocols/IcqOscarJ/res/expandst.ico | Bin 0 -> 318 bytes protocols/IcqOscarJ/res/icq.ico | Bin 0 -> 6830 bytes protocols/IcqOscarJ/res/resources.rc | 595 ++++ protocols/IcqOscarJ/res/srvlist_add.ico | Bin 0 -> 2038 bytes protocols/IcqOscarJ/resource.h | 262 -- protocols/IcqOscarJ/resources.rc | 595 ---- protocols/IcqOscarJ/src/UI/askauthentication.cpp | 96 + protocols/IcqOscarJ/src/UI/icqoscar.h | 2 + protocols/IcqOscarJ/src/UI/loginpassword.cpp | 97 + protocols/IcqOscarJ/src/UI/userinfotab.cpp | 315 ++ protocols/IcqOscarJ/src/capabilities.cpp | 271 ++ protocols/IcqOscarJ/src/capabilities.h | 45 + protocols/IcqOscarJ/src/chan_01login.cpp | 105 + protocols/IcqOscarJ/src/chan_02data.cpp | 222 ++ protocols/IcqOscarJ/src/chan_03error.cpp | 35 + protocols/IcqOscarJ/src/chan_04close.cpp | 314 ++ protocols/IcqOscarJ/src/chan_05ping.cpp | 89 + protocols/IcqOscarJ/src/changeinfo/changeinfo.h | 122 + protocols/IcqOscarJ/src/changeinfo/constants.cpp | 198 ++ protocols/IcqOscarJ/src/changeinfo/db.cpp | 224 ++ protocols/IcqOscarJ/src/changeinfo/dlgproc.cpp | 540 ++++ protocols/IcqOscarJ/src/changeinfo/editlist.cpp | 201 ++ protocols/IcqOscarJ/src/changeinfo/editstring.cpp | 367 +++ protocols/IcqOscarJ/src/changeinfo/icqoscar.h | 2 + protocols/IcqOscarJ/src/changeinfo/main.cpp | 28 + protocols/IcqOscarJ/src/changeinfo/upload.cpp | 91 + protocols/IcqOscarJ/src/channels.h | 47 + protocols/IcqOscarJ/src/cookies.cpp | 301 ++ protocols/IcqOscarJ/src/cookies.h | 148 + protocols/IcqOscarJ/src/directpackets.cpp | 293 ++ protocols/IcqOscarJ/src/fam_01service.cpp | 983 +++++++ protocols/IcqOscarJ/src/fam_02location.cpp | 312 ++ protocols/IcqOscarJ/src/fam_03buddy.cpp | 787 +++++ protocols/IcqOscarJ/src/fam_04message.cpp | 3043 ++++++++++++++++++++ protocols/IcqOscarJ/src/fam_09bos.cpp | 106 + protocols/IcqOscarJ/src/fam_0alookup.cpp | 130 + protocols/IcqOscarJ/src/fam_0bstatus.cpp | 62 + protocols/IcqOscarJ/src/fam_13servclist.cpp | 2068 +++++++++++++ protocols/IcqOscarJ/src/fam_15icqserver.cpp | 1201 ++++++++ protocols/IcqOscarJ/src/fam_17signon.cpp | 175 ++ protocols/IcqOscarJ/src/families.h | 74 + protocols/IcqOscarJ/src/globals.h | 57 + protocols/IcqOscarJ/src/guids.h | 81 + protocols/IcqOscarJ/src/i18n.cpp | 541 ++++ protocols/IcqOscarJ/src/i18n.h | 70 + protocols/IcqOscarJ/src/iconlib.cpp | 92 + protocols/IcqOscarJ/src/iconlib.h | 52 + protocols/IcqOscarJ/src/icq_advsearch.cpp | 185 ++ protocols/IcqOscarJ/src/icq_advsearch.h | 32 + protocols/IcqOscarJ/src/icq_avatar.cpp | 1814 ++++++++++++ protocols/IcqOscarJ/src/icq_avatar.h | 127 + protocols/IcqOscarJ/src/icq_clients.cpp | 1155 ++++++++ protocols/IcqOscarJ/src/icq_constants.h | 652 +++++ protocols/IcqOscarJ/src/icq_db.cpp | 399 +++ protocols/IcqOscarJ/src/icq_db.h | 44 + protocols/IcqOscarJ/src/icq_direct.cpp | 1171 ++++++++ protocols/IcqOscarJ/src/icq_direct.h | 94 + protocols/IcqOscarJ/src/icq_directmsg.cpp | 361 +++ protocols/IcqOscarJ/src/icq_fieldnames.cpp | 595 ++++ protocols/IcqOscarJ/src/icq_fieldnames.h | 49 + protocols/IcqOscarJ/src/icq_filerequests.cpp | 218 ++ protocols/IcqOscarJ/src/icq_filetransfer.cpp | 515 ++++ protocols/IcqOscarJ/src/icq_firstrun.cpp | 124 + protocols/IcqOscarJ/src/icq_http.cpp | 212 ++ protocols/IcqOscarJ/src/icq_http.h | 48 + protocols/IcqOscarJ/src/icq_infoupdate.cpp | 401 +++ protocols/IcqOscarJ/src/icq_menu.cpp | 263 ++ protocols/IcqOscarJ/src/icq_opts.cpp | 617 ++++ protocols/IcqOscarJ/src/icq_packet.cpp | 898 ++++++ protocols/IcqOscarJ/src/icq_packet.h | 120 + protocols/IcqOscarJ/src/icq_popups.cpp | 323 +++ protocols/IcqOscarJ/src/icq_popups.h | 41 + protocols/IcqOscarJ/src/icq_proto.cpp | 2375 +++++++++++++++ protocols/IcqOscarJ/src/icq_proto.h | 984 +++++++ protocols/IcqOscarJ/src/icq_rates.cpp | 529 ++++ protocols/IcqOscarJ/src/icq_rates.h | 146 + protocols/IcqOscarJ/src/icq_server.cpp | 444 +++ protocols/IcqOscarJ/src/icq_server.h | 71 + protocols/IcqOscarJ/src/icq_servlist.cpp | 2829 ++++++++++++++++++ protocols/IcqOscarJ/src/icq_servlist.h | 172 ++ protocols/IcqOscarJ/src/icq_uploadui.cpp | 1019 +++++++ protocols/IcqOscarJ/src/icq_xstatus.cpp | 1381 +++++++++ protocols/IcqOscarJ/src/icq_xtraz.cpp | 466 +++ protocols/IcqOscarJ/src/icqosc_svcs.cpp | 816 ++++++ protocols/IcqOscarJ/src/icqosc_svcs.h | 39 + protocols/IcqOscarJ/src/icqoscar.cpp | 35 + protocols/IcqOscarJ/src/icqoscar.h | 134 + protocols/IcqOscarJ/src/init.cpp | 245 ++ protocols/IcqOscarJ/src/init.h | 40 + protocols/IcqOscarJ/src/log.cpp | 161 ++ protocols/IcqOscarJ/src/log.h | 38 + protocols/IcqOscarJ/src/oscar_filetransfer.cpp | 2447 ++++++++++++++++ protocols/IcqOscarJ/src/oscar_filetransfer.h | 164 ++ protocols/IcqOscarJ/src/resource.h | 176 ++ protocols/IcqOscarJ/src/stdpackets.cpp | 1895 ++++++++++++ protocols/IcqOscarJ/src/stdpackets.h | 43 + protocols/IcqOscarJ/src/tlv.cpp | 391 +++ protocols/IcqOscarJ/src/tlv.h | 81 + protocols/IcqOscarJ/src/utilities.cpp | 2183 ++++++++++++++ protocols/IcqOscarJ/src/utilities.h | 188 ++ protocols/IcqOscarJ/src/version.h | 3 + protocols/IcqOscarJ/stdpackets.cpp | 1895 ------------ protocols/IcqOscarJ/stdpackets.h | 43 - protocols/IcqOscarJ/tlv.cpp | 391 --- protocols/IcqOscarJ/tlv.h | 81 - protocols/IcqOscarJ/utilities.cpp | 2183 -------------- protocols/IcqOscarJ/utilities.h | 188 -- protocols/IcqOscarJ/version.h | 3 - protocols/JabberG/MString.cpp | 201 -- protocols/JabberG/MString.h | 2300 --------------- protocols/JabberG/docs/jabberg-translation.txt | 835 ++++++ protocols/JabberG/icos/add2roster.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/addcontact.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/arrow_down.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/arrow_up.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/auth_revoke.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/bookmarks.ico | Bin 5430 -> 0 bytes protocols/JabberG/icos/command.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/console.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/delete.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/disco_fail.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/disco_in_progress.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/disco_ok.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/filter.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/go.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/grant.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/group.ico | Bin 9062 -> 0 bytes protocols/JabberG/icos/home.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/jabber.ico | Bin 6830 -> 0 bytes protocols/JabberG/icos/key.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/login.ico | Bin 2038 -> 0 bytes protocols/JabberG/icos/message_allow.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/message_deny.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/notes.ico | Bin 9062 -> 0 bytes protocols/JabberG/icos/open.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/openid.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/pages.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/plist_active.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/plist_any.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/plist_default.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/presence_in_allow.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/presence_in_deny.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/presence_out_allow.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/presence_out_deny.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/privacy_lists.ico | Bin 5430 -> 0 bytes protocols/JabberG/icos/query_allow.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/query_deny.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/refresh.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/refresh_node.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/rename.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/request.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/reset_filter.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/roster.ico | Bin 5430 -> 0 bytes protocols/JabberG/icos/rss.ico | Bin 2038 -> 0 bytes protocols/JabberG/icos/save.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/send_note.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/server.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/service_discovery.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/store.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/transport.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/transport_local.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/user2room.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/view_as_list.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/view_as_tree.ico | Bin 2550 -> 0 bytes protocols/JabberG/icos/weather.ico | Bin 2550 -> 0 bytes protocols/JabberG/jabber.cpp | 279 -- protocols/JabberG/jabber.h | 767 ----- protocols/JabberG/jabber.rc | 943 ------ protocols/JabberG/jabber_10.vcxproj | 218 +- protocols/JabberG/jabber_10.vcxproj.filters | 326 +-- protocols/JabberG/jabber_adhoc.cpp | 609 ---- protocols/JabberG/jabber_agent.cpp | 283 -- protocols/JabberG/jabber_bookmarks.cpp | 483 ---- protocols/JabberG/jabber_byte.cpp | 778 ----- protocols/JabberG/jabber_byte.h | 61 - protocols/JabberG/jabber_caps.cpp | 697 ----- protocols/JabberG/jabber_caps.h | 287 -- protocols/JabberG/jabber_captcha.cpp | 232 -- protocols/JabberG/jabber_chat.cpp | 1628 ----------- protocols/JabberG/jabber_console.cpp | 716 ----- protocols/JabberG/jabber_db_utils.h | 279 -- protocols/JabberG/jabber_disco.cpp | 1529 ---------- protocols/JabberG/jabber_disco.h | 493 ---- protocols/JabberG/jabber_events.cpp | 234 -- protocols/JabberG/jabber_file.cpp | 552 ---- protocols/JabberG/jabber_form.cpp | 905 ------ protocols/JabberG/jabber_form2.cpp | 1198 -------- protocols/JabberG/jabber_form2.h | 190 -- protocols/JabberG/jabber_ft.cpp | 551 ---- protocols/JabberG/jabber_groupchat.cpp | 1374 --------- protocols/JabberG/jabber_ibb.cpp | 193 -- protocols/JabberG/jabber_ibb.h | 46 - protocols/JabberG/jabber_icolib.cpp | 733 ----- protocols/JabberG/jabber_icolib.h | 67 - protocols/JabberG/jabber_iq.cpp | 375 --- protocols/JabberG/jabber_iq.h | 526 ---- protocols/JabberG/jabber_iq_handlers.cpp | 775 ----- protocols/JabberG/jabber_iqid.cpp | 1742 ----------- protocols/JabberG/jabber_iqid_muc.cpp | 560 ---- protocols/JabberG/jabber_libstr.cpp | 31 - protocols/JabberG/jabber_list.cpp | 474 --- protocols/JabberG/jabber_list.h | 202 -- protocols/JabberG/jabber_menu.cpp | 1324 --------- protocols/JabberG/jabber_message_handlers.cpp | 87 - protocols/JabberG/jabber_message_manager.cpp | 107 - protocols/JabberG/jabber_message_manager.h | 250 -- protocols/JabberG/jabber_misc.cpp | 642 ----- protocols/JabberG/jabber_notes.cpp | 865 ------ protocols/JabberG/jabber_notes.h | 82 - protocols/JabberG/jabber_opt.cpp | 2331 --------------- protocols/JabberG/jabber_opttree.cpp | 263 -- protocols/JabberG/jabber_opttree.h | 64 - protocols/JabberG/jabber_password.cpp | 99 - protocols/JabberG/jabber_presence_manager.cpp | 51 - protocols/JabberG/jabber_presence_manager.h | 195 -- protocols/JabberG/jabber_privacy.cpp | 2328 --------------- protocols/JabberG/jabber_privacy.h | 435 --- protocols/JabberG/jabber_proto.cpp | 1659 ----------- protocols/JabberG/jabber_proto.h | 1008 ------- protocols/JabberG/jabber_proxy.cpp | 157 - protocols/JabberG/jabber_proxy.h | 29 - protocols/JabberG/jabber_rc.cpp | 814 ------ protocols/JabberG/jabber_rc.h | 314 -- protocols/JabberG/jabber_search.cpp | 762 ----- protocols/JabberG/jabber_search.h | 273 -- protocols/JabberG/jabber_secur.cpp | 469 --- protocols/JabberG/jabber_secur.h | 113 - protocols/JabberG/jabber_send_manager.cpp | 51 - protocols/JabberG/jabber_send_manager.h | 195 -- protocols/JabberG/jabber_std.cpp | 246 -- protocols/JabberG/jabber_svc.cpp | 1138 -------- protocols/JabberG/jabber_thread.cpp | 2160 -------------- protocols/JabberG/jabber_treelist.cpp | 583 ---- protocols/JabberG/jabber_userinfo.cpp | 896 ------ protocols/JabberG/jabber_util.cpp | 1752 ----------- protocols/JabberG/jabber_vcard.cpp | 1250 -------- protocols/JabberG/jabber_ws.cpp | 90 - protocols/JabberG/jabber_xml.cpp | 524 ---- protocols/JabberG/jabber_xml.h | 382 --- protocols/JabberG/jabber_xstatus.cpp | 2138 -------------- protocols/JabberG/jabber_xstatus.h | 191 -- protocols/JabberG/jabber_xstatus/JABBER_XSTATUS.rc | 198 -- .../jabber_xstatus/JABBER_XSTATUS_10.vcxproj | 2 +- .../jabber_xstatus/icos/activities/at_the_spa.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/bicycling.ico | Bin 6830 -> 0 bytes .../icos/activities/brushing_teeth.ico | Bin 6830 -> 0 bytes .../icos/activities/buying_groceries.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/cleaning.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/coding.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/commuting.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/cooking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/cycling.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/dancing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/day_off.ico | Bin 6830 -> 0 bytes .../icos/activities/doing_chores.ico | Bin 6830 -> 0 bytes .../icos/activities/doing_maintenance.ico | Bin 6830 -> 0 bytes .../icos/activities/doing_the_dishes.ico | Bin 6830 -> 0 bytes .../icos/activities/doing_the_laundry.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/drinking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/driving.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/eating.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/exercising.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/fishing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/gaming.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/gardening.ico | Bin 6830 -> 0 bytes .../icos/activities/getting_a_haircut.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/going_out.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/grooming.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/hanging_out.ico | Bin 6830 -> 0 bytes .../icos/activities/having_a_beer.ico | Bin 6830 -> 0 bytes .../icos/activities/having_a_snack.ico | Bin 6830 -> 0 bytes .../icos/activities/having_appointment.ico | Bin 6830 -> 0 bytes .../icos/activities/having_breakfast.ico | Bin 6830 -> 0 bytes .../icos/activities/having_coffee.ico | Bin 6830 -> 0 bytes .../icos/activities/having_dinner.ico | Bin 6830 -> 0 bytes .../icos/activities/having_lunch.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/having_tea.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/hiding.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/hiking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/in_a_car.ico | Bin 6830 -> 0 bytes .../icos/activities/in_a_meeting.ico | Bin 6830 -> 0 bytes .../icos/activities/in_real_life.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/inactive.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/jogging.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/on_a_bus.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/on_a_plane.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/on_a_train.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/on_a_trip.ico | Bin 6830 -> 0 bytes .../icos/activities/on_the_phone.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/on_vacation.ico | Bin 6830 -> 0 bytes .../icos/activities/on_video_phone.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/partying.ico | Bin 6830 -> 0 bytes .../icos/activities/playing_sports.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/praying.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/reading.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/rehearsing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/relaxing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/running.ico | Bin 6830 -> 0 bytes .../icos/activities/running_an_errand.ico | Bin 6830 -> 0 bytes .../icos/activities/scheduled_holiday.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/shaving.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/shopping.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/skiing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/sleeping.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/smoking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/socializing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/studying.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/sunbathing.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/swimming.ico | Bin 6830 -> 0 bytes .../icos/activities/taking_a_bath.ico | Bin 6830 -> 0 bytes .../icos/activities/taking_a_shower.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/talking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/thinking.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/traveling.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/walking.ico | Bin 6830 -> 0 bytes .../icos/activities/walking_the_dog.ico | Bin 6830 -> 0 bytes .../icos/activities/watching_a_movie.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/watching_tv.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/working.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/working_out.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/activities/writing.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/afraid.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/amazed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/amorous.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/angry.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/annoyed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/anxious.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/aroused.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/ashamed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/bored.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/brave.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/calm.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/cautious.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/cold.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/confident.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/confused.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/contemplative.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/contented.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/cranky.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/crazy.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/creative.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/curious.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/dejected.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/depressed.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/disappointed.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/disgusted.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/dismayed.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/distracted.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/embarrassed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/envious.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/excited.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/flirtatious.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/frustrated.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/grateful.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/grieving.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/grumpy.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/guilty.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/happy.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/hopeful.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/hot.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/humbled.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/humiliated.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/hungry.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/hurt.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/impressed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/in_awe.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/in_love.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/indignant.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/interested.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/intoxicated.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/invincible.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/jealous.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/lonely.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/lost.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/lucky.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/mean.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/moody.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/nervous.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/neutral.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/offended.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/outraged.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/playful.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/proud.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/relaxed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/relieved.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/remorseful.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/restless.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/sad.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/sarcastic.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/satisfied.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/serious.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/shocked.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/shy.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/sick.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/sleepy.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/spontaneous.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/stressed.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/strong.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/surprised.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/thankful.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/thirsty.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/tired.ico | Bin 6830 -> 0 bytes .../jabber_xstatus/icos/moods/undefined.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/weak.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/icos/moods/worried.ico | Bin 6830 -> 0 bytes .../JabberG/jabber_xstatus/res/JABBER_XSTATUS.rc | 198 ++ .../jabber_xstatus/res/activities/at_the_spa.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/bicycling.ico | Bin 0 -> 6830 bytes .../res/activities/brushing_teeth.ico | Bin 0 -> 6830 bytes .../res/activities/buying_groceries.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/cleaning.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/coding.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/commuting.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/cooking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/cycling.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/dancing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/day_off.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/doing_chores.ico | Bin 0 -> 6830 bytes .../res/activities/doing_maintenance.ico | Bin 0 -> 6830 bytes .../res/activities/doing_the_dishes.ico | Bin 0 -> 6830 bytes .../res/activities/doing_the_laundry.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/drinking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/driving.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/eating.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/exercising.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/fishing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/gaming.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/gardening.ico | Bin 0 -> 6830 bytes .../res/activities/getting_a_haircut.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/going_out.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/grooming.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/hanging_out.ico | Bin 0 -> 6830 bytes .../res/activities/having_a_beer.ico | Bin 0 -> 6830 bytes .../res/activities/having_a_snack.ico | Bin 0 -> 6830 bytes .../res/activities/having_appointment.ico | Bin 0 -> 6830 bytes .../res/activities/having_breakfast.ico | Bin 0 -> 6830 bytes .../res/activities/having_coffee.ico | Bin 0 -> 6830 bytes .../res/activities/having_dinner.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/having_lunch.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/having_tea.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/hiding.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/hiking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/in_a_car.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/in_a_meeting.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/in_real_life.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/inactive.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/jogging.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_a_bus.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_a_plane.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_a_train.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_a_trip.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_the_phone.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/on_vacation.ico | Bin 0 -> 6830 bytes .../res/activities/on_video_phone.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/partying.ico | Bin 0 -> 6830 bytes .../res/activities/playing_sports.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/praying.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/reading.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/rehearsing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/relaxing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/running.ico | Bin 0 -> 6830 bytes .../res/activities/running_an_errand.ico | Bin 0 -> 6830 bytes .../res/activities/scheduled_holiday.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/shaving.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/shopping.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/skiing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/sleeping.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/smoking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/socializing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/studying.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/sunbathing.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/swimming.ico | Bin 0 -> 6830 bytes .../res/activities/taking_a_bath.ico | Bin 0 -> 6830 bytes .../res/activities/taking_a_shower.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/talking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/thinking.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/traveling.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/walking.ico | Bin 0 -> 6830 bytes .../res/activities/walking_the_dog.ico | Bin 0 -> 6830 bytes .../res/activities/watching_a_movie.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/watching_tv.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/working.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/working_out.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/activities/writing.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/afraid.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/amazed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/amorous.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/angry.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/annoyed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/anxious.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/aroused.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/ashamed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/bored.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/brave.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/calm.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/cautious.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/cold.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/confident.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/confused.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/contemplative.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/contented.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/cranky.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/crazy.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/creative.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/curious.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/dejected.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/depressed.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/disappointed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/disgusted.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/dismayed.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/distracted.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/embarrassed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/envious.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/excited.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/flirtatious.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/frustrated.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/grateful.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/grieving.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/grumpy.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/guilty.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/happy.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/hopeful.ico | Bin 0 -> 6830 bytes protocols/JabberG/jabber_xstatus/res/moods/hot.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/humbled.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/humiliated.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/hungry.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/hurt.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/impressed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/in_awe.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/in_love.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/indignant.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/interested.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/intoxicated.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/invincible.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/jealous.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/lonely.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/lost.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/lucky.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/mean.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/moody.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/nervous.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/neutral.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/offended.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/outraged.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/playful.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/proud.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/relaxed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/relieved.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/remorseful.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/restless.ico | Bin 0 -> 6830 bytes protocols/JabberG/jabber_xstatus/res/moods/sad.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/sarcastic.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/satisfied.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/serious.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/shocked.ico | Bin 0 -> 6830 bytes protocols/JabberG/jabber_xstatus/res/moods/shy.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/sick.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/sleepy.ico | Bin 0 -> 6830 bytes .../jabber_xstatus/res/moods/spontaneous.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/stressed.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/strong.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/surprised.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/thankful.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/thirsty.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/tired.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/undefined.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/weak.ico | Bin 0 -> 6830 bytes .../JabberG/jabber_xstatus/res/moods/worried.ico | Bin 0 -> 6830 bytes protocols/JabberG/jabber_zstream.cpp | 128 - protocols/JabberG/jabberg-translation.txt | 835 ------ protocols/JabberG/proto_jabber/Proto_Jabber.rc | Bin 4042 -> 0 bytes .../JabberG/proto_jabber/Proto_Jabber.vcxproj | 4 +- .../proto_jabber/Proto_Jabber.vcxproj.filters | 4 +- protocols/JabberG/proto_jabber/icos/Away.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/DND.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/FFC.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/Invisible.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/NA.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/Offline.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/icos/Online.ico | Bin 5430 -> 0 bytes protocols/JabberG/proto_jabber/res/Away.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/DND.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/FFC.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/Invisible.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/NA.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/Offline.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/Online.ico | Bin 0 -> 5430 bytes protocols/JabberG/proto_jabber/res/Proto_Jabber.rc | Bin 0 -> 3990 bytes protocols/JabberG/proto_jabber/resource.h | Bin 1452 -> 0 bytes protocols/JabberG/proto_jabber/src/resource.h | Bin 0 -> 1452 bytes protocols/JabberG/res/add2roster.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/addcontact.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/arrow_down.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/arrow_up.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/auth_revoke.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/bookmarks.ico | Bin 0 -> 5430 bytes protocols/JabberG/res/command.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/console.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/delete.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/disco_fail.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/disco_in_progress.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/disco_ok.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/filter.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/go.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/grant.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/group.ico | Bin 0 -> 9062 bytes protocols/JabberG/res/home.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/jabber.ico | Bin 0 -> 6830 bytes protocols/JabberG/res/jabber.rc | 974 +++++++ protocols/JabberG/res/key.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/login.ico | Bin 0 -> 2038 bytes protocols/JabberG/res/message_allow.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/message_deny.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/notes.ico | Bin 0 -> 9062 bytes protocols/JabberG/res/open.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/openid.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/pages.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/plist_active.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/plist_any.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/plist_default.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/presence_in_allow.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/presence_in_deny.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/presence_out_allow.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/presence_out_deny.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/privacy_lists.ico | Bin 0 -> 5430 bytes protocols/JabberG/res/query_allow.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/query_deny.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/refresh.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/refresh_node.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/rename.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/request.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/reset_filter.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/roster.ico | Bin 0 -> 5430 bytes protocols/JabberG/res/rss.ico | Bin 0 -> 2038 bytes protocols/JabberG/res/save.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/send_note.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/server.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/service_discovery.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/store.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/transport.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/transport_local.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/user2room.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/version.rc | 53 + protocols/JabberG/res/view_as_list.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/view_as_tree.ico | Bin 0 -> 2550 bytes protocols/JabberG/res/weather.ico | Bin 0 -> 2550 bytes protocols/JabberG/resource.h | 358 --- protocols/JabberG/src/MString.cpp | 201 ++ protocols/JabberG/src/MString.h | 2300 +++++++++++++++ protocols/JabberG/src/jabber.cpp | 279 ++ protocols/JabberG/src/jabber.h | 767 +++++ protocols/JabberG/src/jabber_adhoc.cpp | 609 ++++ protocols/JabberG/src/jabber_agent.cpp | 283 ++ protocols/JabberG/src/jabber_bookmarks.cpp | 483 ++++ protocols/JabberG/src/jabber_byte.cpp | 778 +++++ protocols/JabberG/src/jabber_byte.h | 61 + protocols/JabberG/src/jabber_caps.cpp | 697 +++++ protocols/JabberG/src/jabber_caps.h | 287 ++ protocols/JabberG/src/jabber_captcha.cpp | 232 ++ protocols/JabberG/src/jabber_chat.cpp | 1628 +++++++++++ protocols/JabberG/src/jabber_console.cpp | 716 +++++ protocols/JabberG/src/jabber_db_utils.h | 279 ++ protocols/JabberG/src/jabber_disco.cpp | 1529 ++++++++++ protocols/JabberG/src/jabber_disco.h | 493 ++++ protocols/JabberG/src/jabber_events.cpp | 234 ++ protocols/JabberG/src/jabber_file.cpp | 552 ++++ protocols/JabberG/src/jabber_form.cpp | 905 ++++++ protocols/JabberG/src/jabber_form2.cpp | 1198 ++++++++ protocols/JabberG/src/jabber_form2.h | 190 ++ protocols/JabberG/src/jabber_ft.cpp | 551 ++++ protocols/JabberG/src/jabber_groupchat.cpp | 1374 +++++++++ protocols/JabberG/src/jabber_ibb.cpp | 193 ++ protocols/JabberG/src/jabber_ibb.h | 46 + protocols/JabberG/src/jabber_icolib.cpp | 733 +++++ protocols/JabberG/src/jabber_icolib.h | 67 + protocols/JabberG/src/jabber_iq.cpp | 375 +++ protocols/JabberG/src/jabber_iq.h | 526 ++++ protocols/JabberG/src/jabber_iq_handlers.cpp | 775 +++++ protocols/JabberG/src/jabber_iqid.cpp | 1742 +++++++++++ protocols/JabberG/src/jabber_iqid_muc.cpp | 560 ++++ protocols/JabberG/src/jabber_libstr.cpp | 31 + protocols/JabberG/src/jabber_list.cpp | 474 +++ protocols/JabberG/src/jabber_list.h | 202 ++ protocols/JabberG/src/jabber_menu.cpp | 1324 +++++++++ protocols/JabberG/src/jabber_message_handlers.cpp | 87 + protocols/JabberG/src/jabber_message_manager.cpp | 107 + protocols/JabberG/src/jabber_message_manager.h | 250 ++ protocols/JabberG/src/jabber_misc.cpp | 642 +++++ protocols/JabberG/src/jabber_notes.cpp | 865 ++++++ protocols/JabberG/src/jabber_notes.h | 82 + protocols/JabberG/src/jabber_opt.cpp | 2331 +++++++++++++++ protocols/JabberG/src/jabber_opttree.cpp | 263 ++ protocols/JabberG/src/jabber_opttree.h | 64 + protocols/JabberG/src/jabber_password.cpp | 99 + protocols/JabberG/src/jabber_presence_manager.cpp | 51 + protocols/JabberG/src/jabber_presence_manager.h | 195 ++ protocols/JabberG/src/jabber_privacy.cpp | 2328 +++++++++++++++ protocols/JabberG/src/jabber_privacy.h | 435 +++ protocols/JabberG/src/jabber_proto.cpp | 1659 +++++++++++ protocols/JabberG/src/jabber_proto.h | 1008 +++++++ protocols/JabberG/src/jabber_proxy.cpp | 157 + protocols/JabberG/src/jabber_proxy.h | 29 + protocols/JabberG/src/jabber_rc.cpp | 814 ++++++ protocols/JabberG/src/jabber_rc.h | 314 ++ protocols/JabberG/src/jabber_search.cpp | 762 +++++ protocols/JabberG/src/jabber_search.h | 273 ++ protocols/JabberG/src/jabber_secur.cpp | 469 +++ protocols/JabberG/src/jabber_secur.h | 113 + protocols/JabberG/src/jabber_send_manager.cpp | 51 + protocols/JabberG/src/jabber_send_manager.h | 195 ++ protocols/JabberG/src/jabber_std.cpp | 246 ++ protocols/JabberG/src/jabber_svc.cpp | 1138 ++++++++ protocols/JabberG/src/jabber_thread.cpp | 2160 ++++++++++++++ protocols/JabberG/src/jabber_treelist.cpp | 583 ++++ protocols/JabberG/src/jabber_userinfo.cpp | 896 ++++++ protocols/JabberG/src/jabber_util.cpp | 1752 +++++++++++ protocols/JabberG/src/jabber_vcard.cpp | 1250 ++++++++ protocols/JabberG/src/jabber_ws.cpp | 90 + protocols/JabberG/src/jabber_xml.cpp | 524 ++++ protocols/JabberG/src/jabber_xml.h | 382 +++ protocols/JabberG/src/jabber_xstatus.cpp | 2138 ++++++++++++++ protocols/JabberG/src/jabber_xstatus.h | 191 ++ protocols/JabberG/src/jabber_zstream.cpp | 128 + protocols/JabberG/src/resource.h | 358 +++ protocols/JabberG/src/ui_utils.cpp | 2574 +++++++++++++++++ protocols/JabberG/src/ui_utils.h | 1392 +++++++++ protocols/JabberG/src/version.h | 3 + protocols/JabberG/ui_utils.cpp | 2574 ----------------- protocols/JabberG/ui_utils.h | 1392 --------- protocols/JabberG/version.h | 3 - protocols/JabberG/version.rc | 94 - 1182 files changed, 125021 insertions(+), 125324 deletions(-) delete mode 100644 protocols/GTalkExt/GTalkExt.cpp delete mode 100644 protocols/GTalkExt/avatar.cpp delete mode 100644 protocols/GTalkExt/avatar.h delete mode 100644 protocols/GTalkExt/db.cpp delete mode 100644 protocols/GTalkExt/db.h delete mode 100644 protocols/GTalkExt/dllmain.cpp create mode 100644 protocols/GTalkExt/docs/gtalkext-translation.txt delete mode 100644 protocols/GTalkExt/gtalkext-translation.txt delete mode 100644 protocols/GTalkExt/handlers.cpp delete mode 100644 protocols/GTalkExt/handlers.h delete mode 100644 protocols/GTalkExt/inbox.cpp delete mode 100644 protocols/GTalkExt/inbox.h delete mode 100644 protocols/GTalkExt/menu.cpp delete mode 100644 protocols/GTalkExt/menu.h delete mode 100644 protocols/GTalkExt/notifications.cpp delete mode 100644 protocols/GTalkExt/notifications.h delete mode 100644 protocols/GTalkExt/options.cpp delete mode 100644 protocols/GTalkExt/options.h delete mode 100644 protocols/GTalkExt/popups.cpp delete mode 100644 protocols/GTalkExt/popups.h delete mode 100644 protocols/GTalkExt/resources.h create mode 100644 protocols/GTalkExt/src/GTalkExt.cpp create mode 100644 protocols/GTalkExt/src/avatar.cpp create mode 100644 protocols/GTalkExt/src/avatar.h create mode 100644 protocols/GTalkExt/src/db.cpp create mode 100644 protocols/GTalkExt/src/db.h create mode 100644 protocols/GTalkExt/src/dllmain.cpp create mode 100644 protocols/GTalkExt/src/handlers.cpp create mode 100644 protocols/GTalkExt/src/handlers.h create mode 100644 protocols/GTalkExt/src/inbox.cpp create mode 100644 protocols/GTalkExt/src/inbox.h create mode 100644 protocols/GTalkExt/src/menu.cpp create mode 100644 protocols/GTalkExt/src/menu.h create mode 100644 protocols/GTalkExt/src/notifications.cpp create mode 100644 protocols/GTalkExt/src/notifications.h create mode 100644 protocols/GTalkExt/src/options.cpp create mode 100644 protocols/GTalkExt/src/options.h create mode 100644 protocols/GTalkExt/src/popups.cpp create mode 100644 protocols/GTalkExt/src/popups.h create mode 100644 protocols/GTalkExt/src/resources.h create mode 100644 protocols/GTalkExt/src/stdafx.cpp create mode 100644 protocols/GTalkExt/src/stdafx.h create mode 100644 protocols/GTalkExt/src/targetver.h create mode 100644 protocols/GTalkExt/src/tipper_items.cpp create mode 100644 protocols/GTalkExt/src/tipper_items.h delete mode 100644 protocols/GTalkExt/stdafx.cpp delete mode 100644 protocols/GTalkExt/stdafx.h delete mode 100644 protocols/GTalkExt/targetver.h delete mode 100644 protocols/GTalkExt/tipper_items.cpp delete mode 100644 protocols/GTalkExt/tipper_items.h create mode 100644 protocols/IRCG/Docs/ircg-translation.txt delete mode 100644 protocols/IRCG/IRC.rc delete mode 100644 protocols/IRCG/Icons/add.ico delete mode 100644 protocols/IRCG/Icons/apply.ico delete mode 100644 protocols/IRCG/Icons/block.ico delete mode 100644 protocols/IRCG/Icons/dcc.ico delete mode 100644 protocols/IRCG/Icons/delete.ico delete mode 100644 protocols/IRCG/Icons/edit.ico delete mode 100644 protocols/IRCG/Icons/irc.ico delete mode 100644 protocols/IRCG/Icons/list.ico delete mode 100644 protocols/IRCG/Icons/manager.ico delete mode 100644 protocols/IRCG/Icons/question.ico delete mode 100644 protocols/IRCG/Icons/quick.ico delete mode 100644 protocols/IRCG/Icons/rename.ico delete mode 100644 protocols/IRCG/Icons/server.ico delete mode 100644 protocols/IRCG/Icons/show.ico delete mode 100644 protocols/IRCG/Icons/whois.ico delete mode 100644 protocols/IRCG/Icons/world.ico delete mode 100644 protocols/IRCG/MString.cpp delete mode 100644 protocols/IRCG/MString.h delete mode 100644 protocols/IRCG/clist.cpp delete mode 100644 protocols/IRCG/commandmonitor.cpp delete mode 100644 protocols/IRCG/commandmonitor.h delete mode 100644 protocols/IRCG/input.cpp delete mode 100644 protocols/IRCG/irc.h delete mode 100644 protocols/IRCG/irc_dlg.h delete mode 100644 protocols/IRCG/ircg-translation.txt delete mode 100644 protocols/IRCG/irclib.cpp delete mode 100644 protocols/IRCG/irclib.h delete mode 100644 protocols/IRCG/ircproto.cpp delete mode 100644 protocols/IRCG/main.cpp delete mode 100644 protocols/IRCG/options.cpp delete mode 100644 protocols/IRCG/output.cpp delete mode 100644 protocols/IRCG/proto_irc/Proto_IRC.rc delete mode 100644 protocols/IRCG/proto_irc/ico/Away.ico delete mode 100644 protocols/IRCG/proto_irc/ico/Offline.ico delete mode 100644 protocols/IRCG/proto_irc/ico/Online.ico create mode 100644 protocols/IRCG/proto_irc/res/Away.ico create mode 100644 protocols/IRCG/proto_irc/res/Offline.ico create mode 100644 protocols/IRCG/proto_irc/res/Online.ico create mode 100644 protocols/IRCG/proto_irc/res/Proto_IRC.rc delete mode 100644 protocols/IRCG/proto_irc/resource.h create mode 100644 protocols/IRCG/proto_irc/src/resource.h create mode 100644 protocols/IRCG/res/IRC.rc create mode 100644 protocols/IRCG/res/add.ico create mode 100644 protocols/IRCG/res/apply.ico create mode 100644 protocols/IRCG/res/block.ico create mode 100644 protocols/IRCG/res/dcc.ico create mode 100644 protocols/IRCG/res/delete.ico create mode 100644 protocols/IRCG/res/edit.ico create mode 100644 protocols/IRCG/res/irc.ico create mode 100644 protocols/IRCG/res/list.ico create mode 100644 protocols/IRCG/res/manager.ico create mode 100644 protocols/IRCG/res/question.ico create mode 100644 protocols/IRCG/res/quick.ico create mode 100644 protocols/IRCG/res/rename.ico create mode 100644 protocols/IRCG/res/server.ico create mode 100644 protocols/IRCG/res/show.ico create mode 100644 protocols/IRCG/res/version.rc create mode 100644 protocols/IRCG/res/whois.ico create mode 100644 protocols/IRCG/res/world.ico delete mode 100644 protocols/IRCG/resource.h delete mode 100644 protocols/IRCG/scripting.cpp delete mode 100644 protocols/IRCG/services.cpp create mode 100644 protocols/IRCG/src/MString.cpp create mode 100644 protocols/IRCG/src/MString.h create mode 100644 protocols/IRCG/src/clist.cpp create mode 100644 protocols/IRCG/src/commandmonitor.cpp create mode 100644 protocols/IRCG/src/commandmonitor.h create mode 100644 protocols/IRCG/src/input.cpp create mode 100644 protocols/IRCG/src/irc.h create mode 100644 protocols/IRCG/src/irc_dlg.h create mode 100644 protocols/IRCG/src/irclib.cpp create mode 100644 protocols/IRCG/src/irclib.h create mode 100644 protocols/IRCG/src/ircproto.cpp create mode 100644 protocols/IRCG/src/main.cpp create mode 100644 protocols/IRCG/src/options.cpp create mode 100644 protocols/IRCG/src/output.cpp create mode 100644 protocols/IRCG/src/resource.h create mode 100644 protocols/IRCG/src/scripting.cpp create mode 100644 protocols/IRCG/src/services.cpp create mode 100644 protocols/IRCG/src/tools.cpp create mode 100644 protocols/IRCG/src/ui_utils.cpp create mode 100644 protocols/IRCG/src/ui_utils.h create mode 100644 protocols/IRCG/src/userinfo.cpp create mode 100644 protocols/IRCG/src/version.h create mode 100644 protocols/IRCG/src/windows.cpp delete mode 100644 protocols/IRCG/tools.cpp delete mode 100644 protocols/IRCG/ui_utils.cpp delete mode 100644 protocols/IRCG/ui_utils.h delete mode 100644 protocols/IRCG/userinfo.cpp delete mode 100644 protocols/IRCG/version.h delete mode 100644 protocols/IRCG/version.rc delete mode 100644 protocols/IRCG/windows.cpp delete mode 100644 protocols/IcqOscarJ/UI/askauthentication.cpp delete mode 100644 protocols/IcqOscarJ/UI/icqoscar.h delete mode 100644 protocols/IcqOscarJ/UI/loginpassword.cpp delete mode 100644 protocols/IcqOscarJ/UI/userinfotab.cpp delete mode 100644 protocols/IcqOscarJ/capabilities.cpp delete mode 100644 protocols/IcqOscarJ/capabilities.h delete mode 100644 protocols/IcqOscarJ/chan_01login.cpp delete mode 100644 protocols/IcqOscarJ/chan_02data.cpp delete mode 100644 protocols/IcqOscarJ/chan_03error.cpp delete mode 100644 protocols/IcqOscarJ/chan_04close.cpp delete mode 100644 protocols/IcqOscarJ/chan_05ping.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/changeinfo.h delete mode 100644 protocols/IcqOscarJ/changeinfo/constants.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/db.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/dlgproc.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/editlist.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/editstring.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/expandst.ico delete mode 100644 protocols/IcqOscarJ/changeinfo/icqoscar.h delete mode 100644 protocols/IcqOscarJ/changeinfo/main.cpp delete mode 100644 protocols/IcqOscarJ/changeinfo/upload.cpp delete mode 100644 protocols/IcqOscarJ/channels.h delete mode 100644 protocols/IcqOscarJ/cookies.cpp delete mode 100644 protocols/IcqOscarJ/cookies.h delete mode 100644 protocols/IcqOscarJ/directpackets.cpp create mode 100644 protocols/IcqOscarJ/docs/icqoscarj-translation.txt delete mode 100755 protocols/IcqOscarJ/fam_01service.cpp delete mode 100755 protocols/IcqOscarJ/fam_02location.cpp delete mode 100644 protocols/IcqOscarJ/fam_03buddy.cpp delete mode 100644 protocols/IcqOscarJ/fam_04message.cpp delete mode 100644 protocols/IcqOscarJ/fam_09bos.cpp delete mode 100644 protocols/IcqOscarJ/fam_0alookup.cpp delete mode 100644 protocols/IcqOscarJ/fam_0bstatus.cpp delete mode 100644 protocols/IcqOscarJ/fam_13servclist.cpp delete mode 100644 protocols/IcqOscarJ/fam_15icqserver.cpp delete mode 100644 protocols/IcqOscarJ/fam_17signon.cpp delete mode 100644 protocols/IcqOscarJ/families.h delete mode 100644 protocols/IcqOscarJ/globals.h delete mode 100644 protocols/IcqOscarJ/guids.h delete mode 100644 protocols/IcqOscarJ/i18n.cpp delete mode 100644 protocols/IcqOscarJ/i18n.h delete mode 100644 protocols/IcqOscarJ/iconlib.cpp delete mode 100644 protocols/IcqOscarJ/iconlib.h delete mode 100644 protocols/IcqOscarJ/icons_pack/ICONS.rc create mode 100644 protocols/IcqOscarJ/icons_pack/res/ICONS.rc create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus34.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus35.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus36.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus38.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus39.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus40.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus41.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus42.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus45.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus46.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus47.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus48.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus49.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus50.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus51.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus52.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus53.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus54.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus56.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus57.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus58.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus59.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus60.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus61.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus62.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus63.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus65.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus66.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus67.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus68.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus69.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus70.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus71.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus72.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus73.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus74.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus75.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus76.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus77.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus78.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus79.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus81.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus82.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus83.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus84.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/Xstatus86.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus01.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus02.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus03.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus04.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus05.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus06.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus07.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus08.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus09.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus10.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus11.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus12.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus13.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus14.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus15.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus16.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus17.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus18.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus19.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus20.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus21.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus22.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus23.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus24.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus25.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus26.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus27.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus28.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus29.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus30.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus31.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus32.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus33.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus37.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus43.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus44.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus55.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus64.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus80.ico create mode 100644 protocols/IcqOscarJ/icons_pack/res/xstatus85.ico create mode 100644 protocols/IcqOscarJ/icons_pack/src/resource.h delete mode 100644 protocols/IcqOscarJ/icos/Xstatus34.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus35.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus36.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus38.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus39.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus40.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus41.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus42.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus45.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus46.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus47.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus48.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus49.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus50.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus51.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus52.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus53.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus54.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus56.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus57.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus58.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus59.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus60.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus61.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus62.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus63.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus65.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus66.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus67.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus68.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus69.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus70.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus71.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus72.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus73.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus74.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus75.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus76.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus77.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus78.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus79.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus81.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus82.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus83.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus84.ico delete mode 100644 protocols/IcqOscarJ/icos/Xstatus86.ico delete mode 100644 protocols/IcqOscarJ/icos/auth_ask.ico delete mode 100644 protocols/IcqOscarJ/icos/auth_grant.ico delete mode 100644 protocols/IcqOscarJ/icos/auth_revoke.ico delete mode 100644 protocols/IcqOscarJ/icos/icq.ico delete mode 100644 protocols/IcqOscarJ/icos/srvlist_add.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus01.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus02.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus03.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus04.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus05.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus06.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus07.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus08.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus09.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus10.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus11.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus12.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus13.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus14.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus15.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus16.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus17.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus18.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus19.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus20.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus21.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus22.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus23.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus24.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus25.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus26.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus27.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus28.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus29.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus30.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus31.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus32.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus33.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus37.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus43.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus44.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus55.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus64.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus80.ico delete mode 100644 protocols/IcqOscarJ/icos/xstatus85.ico delete mode 100644 protocols/IcqOscarJ/icq_advsearch.cpp delete mode 100644 protocols/IcqOscarJ/icq_advsearch.h delete mode 100644 protocols/IcqOscarJ/icq_avatar.cpp delete mode 100644 protocols/IcqOscarJ/icq_avatar.h delete mode 100644 protocols/IcqOscarJ/icq_clients.cpp delete mode 100644 protocols/IcqOscarJ/icq_constants.h delete mode 100644 protocols/IcqOscarJ/icq_db.cpp delete mode 100644 protocols/IcqOscarJ/icq_db.h delete mode 100644 protocols/IcqOscarJ/icq_direct.cpp delete mode 100644 protocols/IcqOscarJ/icq_direct.h delete mode 100644 protocols/IcqOscarJ/icq_directmsg.cpp delete mode 100644 protocols/IcqOscarJ/icq_fieldnames.cpp delete mode 100644 protocols/IcqOscarJ/icq_fieldnames.h delete mode 100644 protocols/IcqOscarJ/icq_filerequests.cpp delete mode 100644 protocols/IcqOscarJ/icq_filetransfer.cpp delete mode 100644 protocols/IcqOscarJ/icq_firstrun.cpp delete mode 100644 protocols/IcqOscarJ/icq_http.cpp delete mode 100644 protocols/IcqOscarJ/icq_http.h delete mode 100644 protocols/IcqOscarJ/icq_infoupdate.cpp delete mode 100644 protocols/IcqOscarJ/icq_menu.cpp delete mode 100644 protocols/IcqOscarJ/icq_opts.cpp delete mode 100644 protocols/IcqOscarJ/icq_packet.cpp delete mode 100644 protocols/IcqOscarJ/icq_packet.h delete mode 100644 protocols/IcqOscarJ/icq_popups.cpp delete mode 100644 protocols/IcqOscarJ/icq_popups.h delete mode 100755 protocols/IcqOscarJ/icq_proto.cpp delete mode 100755 protocols/IcqOscarJ/icq_proto.h delete mode 100644 protocols/IcqOscarJ/icq_rates.cpp delete mode 100644 protocols/IcqOscarJ/icq_rates.h delete mode 100644 protocols/IcqOscarJ/icq_server.cpp delete mode 100644 protocols/IcqOscarJ/icq_server.h delete mode 100644 protocols/IcqOscarJ/icq_servlist.cpp delete mode 100644 protocols/IcqOscarJ/icq_servlist.h delete mode 100644 protocols/IcqOscarJ/icq_uploadui.cpp delete mode 100644 protocols/IcqOscarJ/icq_xstatus.cpp delete mode 100644 protocols/IcqOscarJ/icq_xtraz.cpp delete mode 100755 protocols/IcqOscarJ/icqosc_svcs.cpp delete mode 100644 protocols/IcqOscarJ/icqosc_svcs.h delete mode 100644 protocols/IcqOscarJ/icqoscar.cpp delete mode 100755 protocols/IcqOscarJ/icqoscar.h delete mode 100644 protocols/IcqOscarJ/icqoscarj-translation.txt delete mode 100644 protocols/IcqOscarJ/init.cpp delete mode 100644 protocols/IcqOscarJ/init.h delete mode 100644 protocols/IcqOscarJ/log.cpp delete mode 100644 protocols/IcqOscarJ/log.h delete mode 100644 protocols/IcqOscarJ/oscar_filetransfer.cpp delete mode 100644 protocols/IcqOscarJ/oscar_filetransfer.h delete mode 100644 protocols/IcqOscarJ/proto_icq/Proto_ICQ.rc delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Away.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/DND.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/FFC.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Invisible.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/NA.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Occupied.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Offline.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Online.ico delete mode 100644 protocols/IcqOscarJ/proto_icq/icos/Phone.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Away.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/DND.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/FFC.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Invisible.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/NA.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Occupied.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Offline.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Online.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Phone.ico create mode 100644 protocols/IcqOscarJ/proto_icq/res/Proto_ICQ.rc delete mode 100644 protocols/IcqOscarJ/proto_icq/resource.h create mode 100644 protocols/IcqOscarJ/proto_icq/src/resource.h create mode 100644 protocols/IcqOscarJ/res/auth_ask.ico create mode 100644 protocols/IcqOscarJ/res/auth_grant.ico create mode 100644 protocols/IcqOscarJ/res/auth_revoke.ico create mode 100644 protocols/IcqOscarJ/res/expandst.ico create mode 100644 protocols/IcqOscarJ/res/icq.ico create mode 100644 protocols/IcqOscarJ/res/resources.rc create mode 100644 protocols/IcqOscarJ/res/srvlist_add.ico delete mode 100644 protocols/IcqOscarJ/resource.h delete mode 100644 protocols/IcqOscarJ/resources.rc create mode 100644 protocols/IcqOscarJ/src/UI/askauthentication.cpp create mode 100644 protocols/IcqOscarJ/src/UI/icqoscar.h create mode 100644 protocols/IcqOscarJ/src/UI/loginpassword.cpp create mode 100644 protocols/IcqOscarJ/src/UI/userinfotab.cpp create mode 100644 protocols/IcqOscarJ/src/capabilities.cpp create mode 100644 protocols/IcqOscarJ/src/capabilities.h create mode 100644 protocols/IcqOscarJ/src/chan_01login.cpp create mode 100644 protocols/IcqOscarJ/src/chan_02data.cpp create mode 100644 protocols/IcqOscarJ/src/chan_03error.cpp create mode 100644 protocols/IcqOscarJ/src/chan_04close.cpp create mode 100644 protocols/IcqOscarJ/src/chan_05ping.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/changeinfo.h create mode 100644 protocols/IcqOscarJ/src/changeinfo/constants.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/db.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/dlgproc.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/editlist.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/editstring.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/icqoscar.h create mode 100644 protocols/IcqOscarJ/src/changeinfo/main.cpp create mode 100644 protocols/IcqOscarJ/src/changeinfo/upload.cpp create mode 100644 protocols/IcqOscarJ/src/channels.h create mode 100644 protocols/IcqOscarJ/src/cookies.cpp create mode 100644 protocols/IcqOscarJ/src/cookies.h create mode 100644 protocols/IcqOscarJ/src/directpackets.cpp create mode 100644 protocols/IcqOscarJ/src/fam_01service.cpp create mode 100644 protocols/IcqOscarJ/src/fam_02location.cpp create mode 100644 protocols/IcqOscarJ/src/fam_03buddy.cpp create mode 100644 protocols/IcqOscarJ/src/fam_04message.cpp create mode 100644 protocols/IcqOscarJ/src/fam_09bos.cpp create mode 100644 protocols/IcqOscarJ/src/fam_0alookup.cpp create mode 100644 protocols/IcqOscarJ/src/fam_0bstatus.cpp create mode 100644 protocols/IcqOscarJ/src/fam_13servclist.cpp create mode 100644 protocols/IcqOscarJ/src/fam_15icqserver.cpp create mode 100644 protocols/IcqOscarJ/src/fam_17signon.cpp create mode 100644 protocols/IcqOscarJ/src/families.h create mode 100644 protocols/IcqOscarJ/src/globals.h create mode 100644 protocols/IcqOscarJ/src/guids.h create mode 100644 protocols/IcqOscarJ/src/i18n.cpp create mode 100644 protocols/IcqOscarJ/src/i18n.h create mode 100644 protocols/IcqOscarJ/src/iconlib.cpp create mode 100644 protocols/IcqOscarJ/src/iconlib.h create mode 100644 protocols/IcqOscarJ/src/icq_advsearch.cpp create mode 100644 protocols/IcqOscarJ/src/icq_advsearch.h create mode 100644 protocols/IcqOscarJ/src/icq_avatar.cpp create mode 100644 protocols/IcqOscarJ/src/icq_avatar.h create mode 100644 protocols/IcqOscarJ/src/icq_clients.cpp create mode 100644 protocols/IcqOscarJ/src/icq_constants.h create mode 100644 protocols/IcqOscarJ/src/icq_db.cpp create mode 100644 protocols/IcqOscarJ/src/icq_db.h create mode 100644 protocols/IcqOscarJ/src/icq_direct.cpp create mode 100644 protocols/IcqOscarJ/src/icq_direct.h create mode 100644 protocols/IcqOscarJ/src/icq_directmsg.cpp create mode 100644 protocols/IcqOscarJ/src/icq_fieldnames.cpp create mode 100644 protocols/IcqOscarJ/src/icq_fieldnames.h create mode 100644 protocols/IcqOscarJ/src/icq_filerequests.cpp create mode 100644 protocols/IcqOscarJ/src/icq_filetransfer.cpp create mode 100644 protocols/IcqOscarJ/src/icq_firstrun.cpp create mode 100644 protocols/IcqOscarJ/src/icq_http.cpp create mode 100644 protocols/IcqOscarJ/src/icq_http.h create mode 100644 protocols/IcqOscarJ/src/icq_infoupdate.cpp create mode 100644 protocols/IcqOscarJ/src/icq_menu.cpp create mode 100644 protocols/IcqOscarJ/src/icq_opts.cpp create mode 100644 protocols/IcqOscarJ/src/icq_packet.cpp create mode 100644 protocols/IcqOscarJ/src/icq_packet.h create mode 100644 protocols/IcqOscarJ/src/icq_popups.cpp create mode 100644 protocols/IcqOscarJ/src/icq_popups.h create mode 100644 protocols/IcqOscarJ/src/icq_proto.cpp create mode 100644 protocols/IcqOscarJ/src/icq_proto.h create mode 100644 protocols/IcqOscarJ/src/icq_rates.cpp create mode 100644 protocols/IcqOscarJ/src/icq_rates.h create mode 100644 protocols/IcqOscarJ/src/icq_server.cpp create mode 100644 protocols/IcqOscarJ/src/icq_server.h create mode 100644 protocols/IcqOscarJ/src/icq_servlist.cpp create mode 100644 protocols/IcqOscarJ/src/icq_servlist.h create mode 100644 protocols/IcqOscarJ/src/icq_uploadui.cpp create mode 100644 protocols/IcqOscarJ/src/icq_xstatus.cpp create mode 100644 protocols/IcqOscarJ/src/icq_xtraz.cpp create mode 100644 protocols/IcqOscarJ/src/icqosc_svcs.cpp create mode 100644 protocols/IcqOscarJ/src/icqosc_svcs.h create mode 100644 protocols/IcqOscarJ/src/icqoscar.cpp create mode 100644 protocols/IcqOscarJ/src/icqoscar.h create mode 100644 protocols/IcqOscarJ/src/init.cpp create mode 100644 protocols/IcqOscarJ/src/init.h create mode 100644 protocols/IcqOscarJ/src/log.cpp create mode 100644 protocols/IcqOscarJ/src/log.h create mode 100644 protocols/IcqOscarJ/src/oscar_filetransfer.cpp create mode 100644 protocols/IcqOscarJ/src/oscar_filetransfer.h create mode 100644 protocols/IcqOscarJ/src/resource.h create mode 100644 protocols/IcqOscarJ/src/stdpackets.cpp create mode 100644 protocols/IcqOscarJ/src/stdpackets.h create mode 100644 protocols/IcqOscarJ/src/tlv.cpp create mode 100644 protocols/IcqOscarJ/src/tlv.h create mode 100644 protocols/IcqOscarJ/src/utilities.cpp create mode 100644 protocols/IcqOscarJ/src/utilities.h create mode 100644 protocols/IcqOscarJ/src/version.h delete mode 100644 protocols/IcqOscarJ/stdpackets.cpp delete mode 100644 protocols/IcqOscarJ/stdpackets.h delete mode 100644 protocols/IcqOscarJ/tlv.cpp delete mode 100644 protocols/IcqOscarJ/tlv.h delete mode 100644 protocols/IcqOscarJ/utilities.cpp delete mode 100644 protocols/IcqOscarJ/utilities.h delete mode 100644 protocols/IcqOscarJ/version.h delete mode 100644 protocols/JabberG/MString.cpp delete mode 100644 protocols/JabberG/MString.h create mode 100644 protocols/JabberG/docs/jabberg-translation.txt delete mode 100644 protocols/JabberG/icos/add2roster.ico delete mode 100644 protocols/JabberG/icos/addcontact.ico delete mode 100644 protocols/JabberG/icos/arrow_down.ico delete mode 100644 protocols/JabberG/icos/arrow_up.ico delete mode 100644 protocols/JabberG/icos/auth_revoke.ico delete mode 100644 protocols/JabberG/icos/bookmarks.ico delete mode 100644 protocols/JabberG/icos/command.ico delete mode 100644 protocols/JabberG/icos/console.ico delete mode 100644 protocols/JabberG/icos/delete.ico delete mode 100644 protocols/JabberG/icos/disco_fail.ico delete mode 100644 protocols/JabberG/icos/disco_in_progress.ico delete mode 100644 protocols/JabberG/icos/disco_ok.ico delete mode 100644 protocols/JabberG/icos/filter.ico delete mode 100644 protocols/JabberG/icos/go.ico delete mode 100644 protocols/JabberG/icos/grant.ico delete mode 100644 protocols/JabberG/icos/group.ico delete mode 100644 protocols/JabberG/icos/home.ico delete mode 100644 protocols/JabberG/icos/jabber.ico delete mode 100644 protocols/JabberG/icos/key.ico delete mode 100644 protocols/JabberG/icos/login.ico delete mode 100644 protocols/JabberG/icos/message_allow.ico delete mode 100644 protocols/JabberG/icos/message_deny.ico delete mode 100644 protocols/JabberG/icos/notes.ico delete mode 100644 protocols/JabberG/icos/open.ico delete mode 100644 protocols/JabberG/icos/openid.ico delete mode 100644 protocols/JabberG/icos/pages.ico delete mode 100644 protocols/JabberG/icos/plist_active.ico delete mode 100644 protocols/JabberG/icos/plist_any.ico delete mode 100644 protocols/JabberG/icos/plist_default.ico delete mode 100644 protocols/JabberG/icos/presence_in_allow.ico delete mode 100644 protocols/JabberG/icos/presence_in_deny.ico delete mode 100644 protocols/JabberG/icos/presence_out_allow.ico delete mode 100644 protocols/JabberG/icos/presence_out_deny.ico delete mode 100644 protocols/JabberG/icos/privacy_lists.ico delete mode 100644 protocols/JabberG/icos/query_allow.ico delete mode 100644 protocols/JabberG/icos/query_deny.ico delete mode 100644 protocols/JabberG/icos/refresh.ico delete mode 100644 protocols/JabberG/icos/refresh_node.ico delete mode 100644 protocols/JabberG/icos/rename.ico delete mode 100644 protocols/JabberG/icos/request.ico delete mode 100644 protocols/JabberG/icos/reset_filter.ico delete mode 100644 protocols/JabberG/icos/roster.ico delete mode 100644 protocols/JabberG/icos/rss.ico delete mode 100644 protocols/JabberG/icos/save.ico delete mode 100644 protocols/JabberG/icos/send_note.ico delete mode 100644 protocols/JabberG/icos/server.ico delete mode 100644 protocols/JabberG/icos/service_discovery.ico delete mode 100644 protocols/JabberG/icos/store.ico delete mode 100644 protocols/JabberG/icos/transport.ico delete mode 100644 protocols/JabberG/icos/transport_local.ico delete mode 100644 protocols/JabberG/icos/user2room.ico delete mode 100644 protocols/JabberG/icos/view_as_list.ico delete mode 100644 protocols/JabberG/icos/view_as_tree.ico delete mode 100644 protocols/JabberG/icos/weather.ico delete mode 100644 protocols/JabberG/jabber.cpp delete mode 100644 protocols/JabberG/jabber.h delete mode 100644 protocols/JabberG/jabber.rc delete mode 100644 protocols/JabberG/jabber_adhoc.cpp delete mode 100644 protocols/JabberG/jabber_agent.cpp delete mode 100644 protocols/JabberG/jabber_bookmarks.cpp delete mode 100644 protocols/JabberG/jabber_byte.cpp delete mode 100644 protocols/JabberG/jabber_byte.h delete mode 100644 protocols/JabberG/jabber_caps.cpp delete mode 100644 protocols/JabberG/jabber_caps.h delete mode 100644 protocols/JabberG/jabber_captcha.cpp delete mode 100644 protocols/JabberG/jabber_chat.cpp delete mode 100644 protocols/JabberG/jabber_console.cpp delete mode 100644 protocols/JabberG/jabber_db_utils.h delete mode 100644 protocols/JabberG/jabber_disco.cpp delete mode 100644 protocols/JabberG/jabber_disco.h delete mode 100644 protocols/JabberG/jabber_events.cpp delete mode 100644 protocols/JabberG/jabber_file.cpp delete mode 100644 protocols/JabberG/jabber_form.cpp delete mode 100644 protocols/JabberG/jabber_form2.cpp delete mode 100644 protocols/JabberG/jabber_form2.h delete mode 100644 protocols/JabberG/jabber_ft.cpp delete mode 100644 protocols/JabberG/jabber_groupchat.cpp delete mode 100644 protocols/JabberG/jabber_ibb.cpp delete mode 100644 protocols/JabberG/jabber_ibb.h delete mode 100644 protocols/JabberG/jabber_icolib.cpp delete mode 100644 protocols/JabberG/jabber_icolib.h delete mode 100644 protocols/JabberG/jabber_iq.cpp delete mode 100644 protocols/JabberG/jabber_iq.h delete mode 100644 protocols/JabberG/jabber_iq_handlers.cpp delete mode 100644 protocols/JabberG/jabber_iqid.cpp delete mode 100644 protocols/JabberG/jabber_iqid_muc.cpp delete mode 100644 protocols/JabberG/jabber_libstr.cpp delete mode 100644 protocols/JabberG/jabber_list.cpp delete mode 100644 protocols/JabberG/jabber_list.h delete mode 100644 protocols/JabberG/jabber_menu.cpp delete mode 100644 protocols/JabberG/jabber_message_handlers.cpp delete mode 100644 protocols/JabberG/jabber_message_manager.cpp delete mode 100644 protocols/JabberG/jabber_message_manager.h delete mode 100644 protocols/JabberG/jabber_misc.cpp delete mode 100644 protocols/JabberG/jabber_notes.cpp delete mode 100644 protocols/JabberG/jabber_notes.h delete mode 100644 protocols/JabberG/jabber_opt.cpp delete mode 100644 protocols/JabberG/jabber_opttree.cpp delete mode 100644 protocols/JabberG/jabber_opttree.h delete mode 100644 protocols/JabberG/jabber_password.cpp delete mode 100644 protocols/JabberG/jabber_presence_manager.cpp delete mode 100644 protocols/JabberG/jabber_presence_manager.h delete mode 100644 protocols/JabberG/jabber_privacy.cpp delete mode 100644 protocols/JabberG/jabber_privacy.h delete mode 100644 protocols/JabberG/jabber_proto.cpp delete mode 100644 protocols/JabberG/jabber_proto.h delete mode 100644 protocols/JabberG/jabber_proxy.cpp delete mode 100644 protocols/JabberG/jabber_proxy.h delete mode 100644 protocols/JabberG/jabber_rc.cpp delete mode 100644 protocols/JabberG/jabber_rc.h delete mode 100644 protocols/JabberG/jabber_search.cpp delete mode 100644 protocols/JabberG/jabber_search.h delete mode 100644 protocols/JabberG/jabber_secur.cpp delete mode 100644 protocols/JabberG/jabber_secur.h delete mode 100644 protocols/JabberG/jabber_send_manager.cpp delete mode 100644 protocols/JabberG/jabber_send_manager.h delete mode 100644 protocols/JabberG/jabber_std.cpp delete mode 100644 protocols/JabberG/jabber_svc.cpp delete mode 100644 protocols/JabberG/jabber_thread.cpp delete mode 100644 protocols/JabberG/jabber_treelist.cpp delete mode 100644 protocols/JabberG/jabber_userinfo.cpp delete mode 100644 protocols/JabberG/jabber_util.cpp delete mode 100644 protocols/JabberG/jabber_vcard.cpp delete mode 100644 protocols/JabberG/jabber_ws.cpp delete mode 100644 protocols/JabberG/jabber_xml.cpp delete mode 100644 protocols/JabberG/jabber_xml.h delete mode 100644 protocols/JabberG/jabber_xstatus.cpp delete mode 100644 protocols/JabberG/jabber_xstatus.h delete mode 100644 protocols/JabberG/jabber_xstatus/JABBER_XSTATUS.rc delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/at_the_spa.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/bicycling.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/brushing_teeth.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/buying_groceries.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/cleaning.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/coding.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/commuting.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/cooking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/cycling.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/dancing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/day_off.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/doing_chores.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/doing_maintenance.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/doing_the_dishes.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/doing_the_laundry.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/drinking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/driving.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/eating.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/exercising.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/fishing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/gaming.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/gardening.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/getting_a_haircut.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/going_out.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/grooming.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/hanging_out.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_a_beer.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_a_snack.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_appointment.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_breakfast.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_coffee.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_dinner.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_lunch.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/having_tea.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/hiding.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/hiking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/in_a_car.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/in_a_meeting.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/in_real_life.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/inactive.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/jogging.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_a_bus.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_a_plane.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_a_train.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_a_trip.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_the_phone.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_vacation.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/on_video_phone.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/partying.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/playing_sports.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/praying.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/reading.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/rehearsing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/relaxing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/running.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/running_an_errand.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/scheduled_holiday.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/shaving.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/shopping.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/skiing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/sleeping.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/smoking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/socializing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/studying.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/sunbathing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/swimming.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/taking_a_bath.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/taking_a_shower.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/talking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/thinking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/traveling.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/walking.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/walking_the_dog.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/watching_a_movie.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/watching_tv.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/working.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/working_out.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/activities/writing.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/afraid.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/amazed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/amorous.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/angry.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/annoyed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/anxious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/aroused.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/ashamed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/bored.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/brave.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/calm.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/cautious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/cold.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/confident.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/confused.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/contemplative.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/contented.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/cranky.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/crazy.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/creative.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/curious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/dejected.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/depressed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/disappointed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/disgusted.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/dismayed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/distracted.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/embarrassed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/envious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/excited.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/flirtatious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/frustrated.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/grateful.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/grieving.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/grumpy.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/guilty.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/happy.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/hopeful.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/hot.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/humbled.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/humiliated.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/hungry.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/hurt.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/impressed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/in_awe.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/in_love.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/indignant.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/interested.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/intoxicated.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/invincible.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/jealous.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/lonely.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/lost.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/lucky.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/mean.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/moody.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/nervous.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/neutral.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/offended.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/outraged.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/playful.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/proud.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/relaxed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/relieved.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/remorseful.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/restless.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/sad.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/sarcastic.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/satisfied.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/serious.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/shocked.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/shy.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/sick.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/sleepy.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/spontaneous.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/stressed.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/strong.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/surprised.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/thankful.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/thirsty.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/tired.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/undefined.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/weak.ico delete mode 100644 protocols/JabberG/jabber_xstatus/icos/moods/worried.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/JABBER_XSTATUS.rc create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/at_the_spa.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/bicycling.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/brushing_teeth.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/buying_groceries.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/cleaning.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/coding.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/commuting.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/cooking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/cycling.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/dancing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/day_off.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/doing_chores.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/doing_maintenance.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/doing_the_dishes.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/doing_the_laundry.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/drinking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/driving.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/eating.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/exercising.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/fishing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/gaming.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/gardening.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/getting_a_haircut.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/going_out.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/grooming.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/hanging_out.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_a_beer.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_a_snack.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_appointment.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_breakfast.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_coffee.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_dinner.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_lunch.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/having_tea.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/hiding.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/hiking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/in_a_car.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/in_a_meeting.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/in_real_life.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/inactive.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/jogging.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_a_bus.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_a_plane.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_a_train.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_a_trip.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_the_phone.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_vacation.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/on_video_phone.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/partying.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/playing_sports.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/praying.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/reading.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/rehearsing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/relaxing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/running.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/running_an_errand.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/scheduled_holiday.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/shaving.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/shopping.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/skiing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/sleeping.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/smoking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/socializing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/studying.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/sunbathing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/swimming.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/taking_a_bath.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/taking_a_shower.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/talking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/thinking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/traveling.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/walking.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/walking_the_dog.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/watching_a_movie.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/watching_tv.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/working.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/working_out.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/activities/writing.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/afraid.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/amazed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/amorous.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/angry.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/annoyed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/anxious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/aroused.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/ashamed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/bored.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/brave.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/calm.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/cautious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/cold.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/confident.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/confused.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/contemplative.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/contented.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/cranky.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/crazy.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/creative.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/curious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/dejected.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/depressed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/disappointed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/disgusted.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/dismayed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/distracted.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/embarrassed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/envious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/excited.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/flirtatious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/frustrated.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/grateful.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/grieving.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/grumpy.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/guilty.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/happy.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/hopeful.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/hot.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/humbled.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/humiliated.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/hungry.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/hurt.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/impressed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/in_awe.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/in_love.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/indignant.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/interested.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/intoxicated.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/invincible.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/jealous.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/lonely.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/lost.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/lucky.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/mean.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/moody.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/nervous.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/neutral.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/offended.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/outraged.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/playful.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/proud.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/relaxed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/relieved.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/remorseful.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/restless.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/sad.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/sarcastic.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/satisfied.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/serious.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/shocked.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/shy.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/sick.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/sleepy.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/spontaneous.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/stressed.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/strong.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/surprised.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/thankful.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/thirsty.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/tired.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/undefined.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/weak.ico create mode 100644 protocols/JabberG/jabber_xstatus/res/moods/worried.ico delete mode 100644 protocols/JabberG/jabber_zstream.cpp delete mode 100644 protocols/JabberG/jabberg-translation.txt delete mode 100644 protocols/JabberG/proto_jabber/Proto_Jabber.rc delete mode 100644 protocols/JabberG/proto_jabber/icos/Away.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/DND.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/FFC.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/Invisible.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/NA.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/Offline.ico delete mode 100644 protocols/JabberG/proto_jabber/icos/Online.ico create mode 100644 protocols/JabberG/proto_jabber/res/Away.ico create mode 100644 protocols/JabberG/proto_jabber/res/DND.ico create mode 100644 protocols/JabberG/proto_jabber/res/FFC.ico create mode 100644 protocols/JabberG/proto_jabber/res/Invisible.ico create mode 100644 protocols/JabberG/proto_jabber/res/NA.ico create mode 100644 protocols/JabberG/proto_jabber/res/Offline.ico create mode 100644 protocols/JabberG/proto_jabber/res/Online.ico create mode 100644 protocols/JabberG/proto_jabber/res/Proto_Jabber.rc delete mode 100644 protocols/JabberG/proto_jabber/resource.h create mode 100644 protocols/JabberG/proto_jabber/src/resource.h create mode 100644 protocols/JabberG/res/add2roster.ico create mode 100644 protocols/JabberG/res/addcontact.ico create mode 100644 protocols/JabberG/res/arrow_down.ico create mode 100644 protocols/JabberG/res/arrow_up.ico create mode 100644 protocols/JabberG/res/auth_revoke.ico create mode 100644 protocols/JabberG/res/bookmarks.ico create mode 100644 protocols/JabberG/res/command.ico create mode 100644 protocols/JabberG/res/console.ico create mode 100644 protocols/JabberG/res/delete.ico create mode 100644 protocols/JabberG/res/disco_fail.ico create mode 100644 protocols/JabberG/res/disco_in_progress.ico create mode 100644 protocols/JabberG/res/disco_ok.ico create mode 100644 protocols/JabberG/res/filter.ico create mode 100644 protocols/JabberG/res/go.ico create mode 100644 protocols/JabberG/res/grant.ico create mode 100644 protocols/JabberG/res/group.ico create mode 100644 protocols/JabberG/res/home.ico create mode 100644 protocols/JabberG/res/jabber.ico create mode 100644 protocols/JabberG/res/jabber.rc create mode 100644 protocols/JabberG/res/key.ico create mode 100644 protocols/JabberG/res/login.ico create mode 100644 protocols/JabberG/res/message_allow.ico create mode 100644 protocols/JabberG/res/message_deny.ico create mode 100644 protocols/JabberG/res/notes.ico create mode 100644 protocols/JabberG/res/open.ico create mode 100644 protocols/JabberG/res/openid.ico create mode 100644 protocols/JabberG/res/pages.ico create mode 100644 protocols/JabberG/res/plist_active.ico create mode 100644 protocols/JabberG/res/plist_any.ico create mode 100644 protocols/JabberG/res/plist_default.ico create mode 100644 protocols/JabberG/res/presence_in_allow.ico create mode 100644 protocols/JabberG/res/presence_in_deny.ico create mode 100644 protocols/JabberG/res/presence_out_allow.ico create mode 100644 protocols/JabberG/res/presence_out_deny.ico create mode 100644 protocols/JabberG/res/privacy_lists.ico create mode 100644 protocols/JabberG/res/query_allow.ico create mode 100644 protocols/JabberG/res/query_deny.ico create mode 100644 protocols/JabberG/res/refresh.ico create mode 100644 protocols/JabberG/res/refresh_node.ico create mode 100644 protocols/JabberG/res/rename.ico create mode 100644 protocols/JabberG/res/request.ico create mode 100644 protocols/JabberG/res/reset_filter.ico create mode 100644 protocols/JabberG/res/roster.ico create mode 100644 protocols/JabberG/res/rss.ico create mode 100644 protocols/JabberG/res/save.ico create mode 100644 protocols/JabberG/res/send_note.ico create mode 100644 protocols/JabberG/res/server.ico create mode 100644 protocols/JabberG/res/service_discovery.ico create mode 100644 protocols/JabberG/res/store.ico create mode 100644 protocols/JabberG/res/transport.ico create mode 100644 protocols/JabberG/res/transport_local.ico create mode 100644 protocols/JabberG/res/user2room.ico create mode 100644 protocols/JabberG/res/version.rc create mode 100644 protocols/JabberG/res/view_as_list.ico create mode 100644 protocols/JabberG/res/view_as_tree.ico create mode 100644 protocols/JabberG/res/weather.ico delete mode 100644 protocols/JabberG/resource.h create mode 100644 protocols/JabberG/src/MString.cpp create mode 100644 protocols/JabberG/src/MString.h create mode 100644 protocols/JabberG/src/jabber.cpp create mode 100644 protocols/JabberG/src/jabber.h create mode 100644 protocols/JabberG/src/jabber_adhoc.cpp create mode 100644 protocols/JabberG/src/jabber_agent.cpp create mode 100644 protocols/JabberG/src/jabber_bookmarks.cpp create mode 100644 protocols/JabberG/src/jabber_byte.cpp create mode 100644 protocols/JabberG/src/jabber_byte.h create mode 100644 protocols/JabberG/src/jabber_caps.cpp create mode 100644 protocols/JabberG/src/jabber_caps.h create mode 100644 protocols/JabberG/src/jabber_captcha.cpp create mode 100644 protocols/JabberG/src/jabber_chat.cpp create mode 100644 protocols/JabberG/src/jabber_console.cpp create mode 100644 protocols/JabberG/src/jabber_db_utils.h create mode 100644 protocols/JabberG/src/jabber_disco.cpp create mode 100644 protocols/JabberG/src/jabber_disco.h create mode 100644 protocols/JabberG/src/jabber_events.cpp create mode 100644 protocols/JabberG/src/jabber_file.cpp create mode 100644 protocols/JabberG/src/jabber_form.cpp create mode 100644 protocols/JabberG/src/jabber_form2.cpp create mode 100644 protocols/JabberG/src/jabber_form2.h create mode 100644 protocols/JabberG/src/jabber_ft.cpp create mode 100644 protocols/JabberG/src/jabber_groupchat.cpp create mode 100644 protocols/JabberG/src/jabber_ibb.cpp create mode 100644 protocols/JabberG/src/jabber_ibb.h create mode 100644 protocols/JabberG/src/jabber_icolib.cpp create mode 100644 protocols/JabberG/src/jabber_icolib.h create mode 100644 protocols/JabberG/src/jabber_iq.cpp create mode 100644 protocols/JabberG/src/jabber_iq.h create mode 100644 protocols/JabberG/src/jabber_iq_handlers.cpp create mode 100644 protocols/JabberG/src/jabber_iqid.cpp create mode 100644 protocols/JabberG/src/jabber_iqid_muc.cpp create mode 100644 protocols/JabberG/src/jabber_libstr.cpp create mode 100644 protocols/JabberG/src/jabber_list.cpp create mode 100644 protocols/JabberG/src/jabber_list.h create mode 100644 protocols/JabberG/src/jabber_menu.cpp create mode 100644 protocols/JabberG/src/jabber_message_handlers.cpp create mode 100644 protocols/JabberG/src/jabber_message_manager.cpp create mode 100644 protocols/JabberG/src/jabber_message_manager.h create mode 100644 protocols/JabberG/src/jabber_misc.cpp create mode 100644 protocols/JabberG/src/jabber_notes.cpp create mode 100644 protocols/JabberG/src/jabber_notes.h create mode 100644 protocols/JabberG/src/jabber_opt.cpp create mode 100644 protocols/JabberG/src/jabber_opttree.cpp create mode 100644 protocols/JabberG/src/jabber_opttree.h create mode 100644 protocols/JabberG/src/jabber_password.cpp create mode 100644 protocols/JabberG/src/jabber_presence_manager.cpp create mode 100644 protocols/JabberG/src/jabber_presence_manager.h create mode 100644 protocols/JabberG/src/jabber_privacy.cpp create mode 100644 protocols/JabberG/src/jabber_privacy.h create mode 100644 protocols/JabberG/src/jabber_proto.cpp create mode 100644 protocols/JabberG/src/jabber_proto.h create mode 100644 protocols/JabberG/src/jabber_proxy.cpp create mode 100644 protocols/JabberG/src/jabber_proxy.h create mode 100644 protocols/JabberG/src/jabber_rc.cpp create mode 100644 protocols/JabberG/src/jabber_rc.h create mode 100644 protocols/JabberG/src/jabber_search.cpp create mode 100644 protocols/JabberG/src/jabber_search.h create mode 100644 protocols/JabberG/src/jabber_secur.cpp create mode 100644 protocols/JabberG/src/jabber_secur.h create mode 100644 protocols/JabberG/src/jabber_send_manager.cpp create mode 100644 protocols/JabberG/src/jabber_send_manager.h create mode 100644 protocols/JabberG/src/jabber_std.cpp create mode 100644 protocols/JabberG/src/jabber_svc.cpp create mode 100644 protocols/JabberG/src/jabber_thread.cpp create mode 100644 protocols/JabberG/src/jabber_treelist.cpp create mode 100644 protocols/JabberG/src/jabber_userinfo.cpp create mode 100644 protocols/JabberG/src/jabber_util.cpp create mode 100644 protocols/JabberG/src/jabber_vcard.cpp create mode 100644 protocols/JabberG/src/jabber_ws.cpp create mode 100644 protocols/JabberG/src/jabber_xml.cpp create mode 100644 protocols/JabberG/src/jabber_xml.h create mode 100644 protocols/JabberG/src/jabber_xstatus.cpp create mode 100644 protocols/JabberG/src/jabber_xstatus.h create mode 100644 protocols/JabberG/src/jabber_zstream.cpp create mode 100644 protocols/JabberG/src/resource.h create mode 100644 protocols/JabberG/src/ui_utils.cpp create mode 100644 protocols/JabberG/src/ui_utils.h create mode 100644 protocols/JabberG/src/version.h delete mode 100644 protocols/JabberG/ui_utils.cpp delete mode 100644 protocols/JabberG/ui_utils.h delete mode 100644 protocols/JabberG/version.h delete mode 100644 protocols/JabberG/version.rc (limited to 'protocols') diff --git a/protocols/GTalkExt/GTalkExt.cpp b/protocols/GTalkExt/GTalkExt.cpp deleted file mode 100644 index 7646bd10be..0000000000 --- a/protocols/GTalkExt/GTalkExt.cpp +++ /dev/null @@ -1,91 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** -// GTalkExt.cpp : Defines the exported functions for the DLL application. -//*************************************************************************************** - -#include "stdafx.h" -#include "options.h" -#include "handlers.h" -#include "tipper_items.h" -#include "avatar.h" -#include "menu.h" - - -int hLangpack; - -#define MIID_PLUGINIFACE {0x08B86253, 0xEC6E, 0x4d09, { 0xB7, 0xA9, 0x64, 0xAC, 0xDF, 0x06, 0x27, 0xB8 }} - -PLUGININFOEX pluginInfo={ - sizeof(PLUGININFOEX), - PLUGIN_DESCRIPTION, - PLUGIN_VERSION_DWORD, - "Currently only mail notifications implemented", - "bems", - "bems@vingrad.ru", - COPYRIGHT_STRING, - "http://miranda-ng.org/", - UNICODE_AWARE, //doesn't replace anything built-in - MIID_PLUGINIFACE //{08B86253-EC6E-4d09-B7A9-64ACDF0627B8} -}; - -extern DWORD g_mirandaVersion; - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) -{ - g_mirandaVersion = mirandaVersion; - return &pluginInfo; -} - -HANDLE hModulesLoaded = 0; -HANDLE hAccListChanged = 0; - -extern "C" int __declspec(dllexport) Unload(void) -{ - UnhookOptionsInitialization(); - InitMenus(FALSE); - InitAvaUnit(FALSE); - if (hAccListChanged) UnhookEvent(hAccListChanged); - if (hModulesLoaded) UnhookEvent(hModulesLoaded); - return 0; -} - -HICON g_hPopupIcon = 0; -extern HINSTANCE hInst; - -extern "C" int __declspec(dllexport) Load(void) -{ - g_hPopupIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_POPUP)); - - - mir_getLP(&pluginInfo); - if ( - !mir_getXI(&xi) || - !(hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded)) || - !(hAccListChanged = HookEvent(ME_PROTO_ACCLISTCHANGED, AccListChanged)) || - !InitAvaUnit(TRUE) || - !InitMenus(TRUE) - ) - {Unload(); return 1;}; - - AddTipperItem(); - - return 0; -} \ No newline at end of file diff --git a/protocols/GTalkExt/GTalkExt.vcxproj b/protocols/GTalkExt/GTalkExt.vcxproj index b6877ca108..9ab144d008 100644 --- a/protocols/GTalkExt/GTalkExt.vcxproj +++ b/protocols/GTalkExt/GTalkExt.vcxproj @@ -168,34 +168,34 @@ - - - - - - - - - - - + + + + + + + + + + + Create - + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/protocols/GTalkExt/GTalkExt.vcxproj.filters b/protocols/GTalkExt/GTalkExt.vcxproj.filters index 5f44404546..74f1960ed1 100644 --- a/protocols/GTalkExt/GTalkExt.vcxproj.filters +++ b/protocols/GTalkExt/GTalkExt.vcxproj.filters @@ -15,78 +15,78 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files diff --git a/protocols/GTalkExt/avatar.cpp b/protocols/GTalkExt/avatar.cpp deleted file mode 100644 index 1e55937a44..0000000000 --- a/protocols/GTalkExt/avatar.cpp +++ /dev/null @@ -1,212 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "avatar.h" -#include "resources.h" -#include "options.h" - -static const LPSTR AVA_FILE_NAME_FORMAT = "%s\\%s\\AvatarCache\\Jabber\\" SHORT_PLUGIN_NAME ".pseudoava.png"; -static const LPTSTR AVA_RES_TYPE = _T("PNG"); -static const LPSTR SRMM_MODULE_NAME = "SRMM"; -static const LPSTR SRMM_AVATAR_SETTING_NAME = "Avatar"; - -static const int SET_AVATAR_INTERVAL = 2000; - -void ForceDir(LPSTR dir, int len) -{ - if (GetFileAttributesA(dir) != INVALID_FILE_ATTRIBUTES) return; - for (int i = len - 1; i >= 0; i--) - if ('\\' == dir[i]) { - dir[i] = 0; - __try { - ForceDir(dir, i); - } - __finally { - dir[i] = '\\'; - } - CreateDirectoryA(dir, NULL); - } -} - -void ForceFileDir(LPSTR file) -{ - for (int i = lstrlenA(file) - 1; i >= 0; i--) - if ('\\' == file[i]) { - file[i] = 0; - __try { - ForceDir(file, i); - } - __finally { - file[i] = '\\'; - } - break; - } -} - -LPSTR CreateAvaFile(HANDLE *hFile) -{ - char name[MAX_PATH + 2]; - char path[MAX_PATH + 2]; - char full[MAX_PATH + 2]; - - if (CallService(MS_DB_GETPROFILENAME, (WPARAM)sizeof(name), (LPARAM)&name)) - return NULL; - for (int i = lstrlenA(name); i >= 0; i--) - if ('.' == name[i]) { - name[i] = 0; - break; - } - - if (CallService(MS_DB_GETPROFILEPATH, (WPARAM)sizeof(path), (LPARAM)&path)) - return NULL; - sprintf(&full[0], AVA_FILE_NAME_FORMAT, path, name); - - ForceFileDir(&full[0]); - - HANDLE h = 0; - __try { - h = CreateFileA(&full[0], GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (INVALID_HANDLE_VALUE == h) return NULL; - - if (hFile) *hFile = h; else CloseHandle(h); - h = 0; - return _strdup(&full[0]); - } - __finally { - CloseHandle(h); - } -} - -extern HINSTANCE hInst; - -BOOL SaveAvatar(HANDLE hFile) -{ - HRSRC hres = FindResource(hInst, MAKEINTRESOURCE(IDI_PSEUDOAVA), AVA_RES_TYPE); - if (!hres) return FALSE; - - HGLOBAL hglob = LoadResource(hInst, hres); - if (!hglob) return FALSE; - - PVOID p = LockResource(hglob); - if (!p) return FALSE; - - DWORD l = SizeofResource(hInst, hres); - if (!l) return FALSE; - - DWORD written; - if (!WriteFile(hFile, p, l, &written, NULL)) return FALSE; - return written == l; -} - -struct AVACHANGED { - HANDLE hTimer; - HANDLE hContact; -}; - -VOID CALLBACK CallSetAvatar(PVOID lpParameter, BOOLEAN TimerOrWaitFired) -{ - Thread_Push(0); - __try { - AVACHANGED *ach = (AVACHANGED*)lpParameter; - __try { - SetAvatar(ach->hContact); - DeleteTimerQueueTimer(NULL, ach->hTimer, NULL); - } - __finally { - free(ach); - } - } - __finally { - Thread_Pop(); - } -} - -int AvaChanged(WPARAM wParam, LPARAM lParam) -{ - if (!lParam && DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { - BOOL enqueued = FALSE; - AVACHANGED *ach = (AVACHANGED*)malloc(sizeof(AVACHANGED)); - __try { - ach->hContact = (HANDLE)wParam; - enqueued = CreateTimerQueueTimer(&ach->hTimer, NULL, CallSetAvatar, ach, SET_AVATAR_INTERVAL, 0, WT_EXECUTEONLYONCE); - } - __finally { - if (!enqueued) free(ach); - } - } - return 0; -} - -CRITICAL_SECTION g_csSetAvatar; -HANDLE hAvaChanged = 0; -BOOL initialized = FALSE; - -BOOL InitAvaUnit(BOOL init) -{ - if (init) { - hAvaChanged = HookEvent(ME_AV_AVATARCHANGED, AvaChanged); - InitializeCriticalSection(&g_csSetAvatar); - initialized = TRUE; - return hAvaChanged != 0; - } - else { - if (initialized) { - initialized = FALSE; - DeleteCriticalSection(&g_csSetAvatar); - } - if (hAvaChanged) { - UnhookEvent(hAvaChanged); - hAvaChanged = 0; - } - return TRUE; - } -} - -void SetAvatar(HANDLE hContact) -{ - EnterCriticalSection(&g_csSetAvatar); - __try { - avatarCacheEntry *ava = (avatarCacheEntry*)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); - if (ava && GetFileAttributes(&ava->szFilename[0]) != INVALID_FILE_ATTRIBUTES) - return; - - HANDLE hFile; - LPSTR avaFile = CreateAvaFile(&hFile); - if (avaFile) - __try { - BOOL saved = SaveAvatar(hFile); - CloseHandle(hFile); hFile = 0; - if (saved){ - if (ava) CallService(MS_AV_SETAVATAR, (WPARAM)hContact, (LPARAM)""); - CallService(MS_AV_SETAVATAR, (WPARAM)hContact, (LPARAM)avaFile); - DBWriteContactSettingString(hContact, SRMM_MODULE_NAME, SRMM_AVATAR_SETTING_NAME, avaFile); - } - } - __finally { - free(avaFile); - CloseHandle(hFile); - } - } - __finally { - LeaveCriticalSection(&g_csSetAvatar); - } -} \ No newline at end of file diff --git a/protocols/GTalkExt/avatar.h b/protocols/GTalkExt/avatar.h deleted file mode 100644 index f07631deff..0000000000 --- a/protocols/GTalkExt/avatar.h +++ /dev/null @@ -1,25 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -void SetAvatar(HANDLE hContact); -BOOL InitAvaUnit(BOOL init); \ No newline at end of file diff --git a/protocols/GTalkExt/db.cpp b/protocols/GTalkExt/db.cpp deleted file mode 100644 index a1658dbdcf..0000000000 --- a/protocols/GTalkExt/db.cpp +++ /dev/null @@ -1,100 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "StdAfx.h" -#include "options.h" - -char *WtoA(LPCTSTR W) -{ - char* result = (char*)malloc(lstrlen(W) + 1); - __try { - int i; - for (i = 0; W[i]; i++) { - result[i] = W[i]; - } - - result[i] = 0; - } - __except( - free(result), - EXCEPTION_CONTINUE_SEARCH - ) {} - return result; -} - -LPTSTR ReadJidSetting(LPCSTR name, LPCTSTR jid) -{ - char *ansiJid = WtoA(jid); - __try { - DBVARIANT dbv = {0}; - __try { - if (DBGetContactSettingTString(0, name, ansiJid, &dbv)) - { - LPTSTR result = (LPTSTR)malloc(2 * sizeof(TCHAR)); - result[0] = '0'; - result[1] = NULL; - return result; - } - - return _tcsdup(dbv.ptszVal); - } - __finally { - DBFreeVariant(&dbv); - } - } - __finally { - free(ansiJid); - } - - assert(false); - return NULL; // relax compiler -} - -void WriteJidSetting(LPCSTR name, LPCTSTR jid, LPCTSTR setting) -{ - char *ansiJid = WtoA(jid); - __try { - DBWriteContactSettingTString(0, name, ansiJid, setting); - } - __finally { - free(ansiJid); - } -} - -void RenewPseudocontactHandles() -{ - int count = 0; - PROTOACCOUNT **protos; - ProtoEnumAccounts(&count, &protos); - for (int i = 0; i < count; i++) { - DBDeleteContactSetting(0, protos[i]->szModuleName, PSEUDOCONTACT_LINK); - DBDeleteContactSetting(0, protos[i]->szModuleName, "GMailExtNotifyContact"); // remove this - } - - HANDLE hContact = db_find_first(); - while (hContact) { - if (DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { - LPCSTR proto = (LPCSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - DBWriteContactSettingDword(0, proto, PSEUDOCONTACT_LINK, (DWORD)hContact); - } - hContact = db_find_next(hContact); - }; -} \ No newline at end of file diff --git a/protocols/GTalkExt/db.h b/protocols/GTalkExt/db.h deleted file mode 100644 index 9db6cc94ce..0000000000 --- a/protocols/GTalkExt/db.h +++ /dev/null @@ -1,31 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once -#include "resources.h" - -static const LPSTR LAST_MAIL_TIME_FROM_JID = SHORT_PLUGIN_NAME ".LastMailTimeFromJid"; -static const LPSTR LAST_THREAD_ID_FROM_JID = SHORT_PLUGIN_NAME ".LastThreadIdFromJid"; - -LPTSTR ReadJidSetting(LPCSTR name, LPCTSTR jid); -void WriteJidSetting(LPCSTR name, LPCTSTR jid, LPCTSTR setting); -char *WtoA(LPCTSTR W); -void RenewPseudocontactHandles(); diff --git a/protocols/GTalkExt/dllmain.cpp b/protocols/GTalkExt/dllmain.cpp deleted file mode 100644 index e1097a3ea6..0000000000 --- a/protocols/GTalkExt/dllmain.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "notifications.h" -#include "options.h" -#include "popups.h" - -HINSTANCE hInst = 0; - -DWORD itlsSettings = TLS_OUT_OF_INDEXES; -DWORD itlsRecursion = TLS_OUT_OF_INDEXES; -DWORD itlsPopupHook = TLS_OUT_OF_INDEXES; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) -{ - hInst = hinstDLL; - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - if (((itlsSettings = TlsAlloc()) == TLS_OUT_OF_INDEXES) || - ((itlsRecursion = TlsAlloc()) == TLS_OUT_OF_INDEXES) || - ((itlsPopupHook = TlsAlloc()) == TLS_OUT_OF_INDEXES)) - return FALSE; - break; - - case DLL_THREAD_ATTACH: - TlsSetValue(itlsPopupHook, - (PVOID)SetWindowsHookEx(WH_CALLWNDPROCRET, PopupHookProc, NULL, GetCurrentThreadId())); - break; - - case DLL_THREAD_DETACH: - UnhookWindowsHookEx((HHOOK)TlsGetValue(itlsPopupHook)); - break; - - case DLL_PROCESS_DETACH: - TlsFree(itlsSettings); - TlsFree(itlsRecursion); - TlsFree(itlsPopupHook); - break; - } - - return TRUE; -} diff --git a/protocols/GTalkExt/docs/gtalkext-translation.txt b/protocols/GTalkExt/docs/gtalkext-translation.txt new file mode 100644 index 0000000000..f5a7c6ac5c --- /dev/null +++ b/protocols/GTalkExt/docs/gtalkext-translation.txt @@ -0,0 +1,25 @@ +; Common strings that belong to many files +;[] + +; ../../protocols/GTalkExt/res/settings.rc +;[0 means default timeout] +;[Add message snip to notification] +;[Background color] +;[Basic HTML] +;[Choose GMail view you use in web interface] +;[Clear pseudocontact history before adding new events] +;[I don't know] +;[If both colors set to the same value, default colors will be used] +;[Mark history event read when popup closed] +;[NOTE\n\nThis will work only if this Jabber account is actually GTalk] +;[Notify in contact list] +;[Notify in fullscreen mode too] +;[Popup notifications (needs popup plugin)] +;[Standard view] +;[Supress foreign popups for pseudocontact] +;[Test] +;[Text color] +;[This works only if password is saved in the database. Has no effect on links in pseudocontact message log] +;[Timeout] +;[Try to login before open mailbox] +;[Use this if your popup plugin does not correctly detect fullscreen mode. It will take away your keyboard focus] diff --git a/protocols/GTalkExt/gtalkext-translation.txt b/protocols/GTalkExt/gtalkext-translation.txt deleted file mode 100644 index f5a7c6ac5c..0000000000 --- a/protocols/GTalkExt/gtalkext-translation.txt +++ /dev/null @@ -1,25 +0,0 @@ -; Common strings that belong to many files -;[] - -; ../../protocols/GTalkExt/res/settings.rc -;[0 means default timeout] -;[Add message snip to notification] -;[Background color] -;[Basic HTML] -;[Choose GMail view you use in web interface] -;[Clear pseudocontact history before adding new events] -;[I don't know] -;[If both colors set to the same value, default colors will be used] -;[Mark history event read when popup closed] -;[NOTE\n\nThis will work only if this Jabber account is actually GTalk] -;[Notify in contact list] -;[Notify in fullscreen mode too] -;[Popup notifications (needs popup plugin)] -;[Standard view] -;[Supress foreign popups for pseudocontact] -;[Test] -;[Text color] -;[This works only if password is saved in the database. Has no effect on links in pseudocontact message log] -;[Timeout] -;[Try to login before open mailbox] -;[Use this if your popup plugin does not correctly detect fullscreen mode. It will take away your keyboard focus] diff --git a/protocols/GTalkExt/handlers.cpp b/protocols/GTalkExt/handlers.cpp deleted file mode 100644 index 7bd814a802..0000000000 --- a/protocols/GTalkExt/handlers.cpp +++ /dev/null @@ -1,433 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "StdAfx.h" -#include "handlers.h" -#include "db.h" -#include "notifications.h" -#include "options.h" -#include "popups.h" - -static const LPCTSTR JABBER_IQID = _T("mir_"); -static const LPCTSTR JABBER_IQID_FORMAT = _T("mir_%d"); - -static const LPCTSTR NOTIFY_FEATURE_XMLNS = _T("google:mail:notify"); -static const LPCTSTR SETTING_FEATURE_XMLNS = _T("google:setting"); -static const LPCTSTR DISCOVERY_XMLNS = _T("http://jabber.org/protocol/disco#info"); - -static const LPCTSTR MESSAGE_URL_FORMAT_STANDARD = _T("%s/#inbox/%x%08x"); -static const LPCTSTR MESSAGE_URL_FORMAT_HTML = _T("%s/h/?v=c&th=%x%08x"); - -static const LPCTSTR ATTRNAME_TYPE = _T("type"); -static const LPCTSTR ATTRNAME_FROM = _T("from"); -static const LPCTSTR ATTRNAME_TO = _T("to"); -static const LPCTSTR ATTRNAME_URL = _T("url"); -static const LPCTSTR ATTRNAME_TID = _T("tid"); -static const LPCTSTR ATTRNAME_UNREAD = _T("unread"); -static const LPCTSTR ATTRNAME_XMLNS = _T("xmlns"); -static const LPCTSTR ATTRNAME_ID = _T("id"); -static const LPCTSTR ATTRNAME_TOTAL_MATCHED = _T("total-matched"); -static const LPCTSTR ATTRNAME_NAME = _T("name"); -static const LPCTSTR ATTRNAME_ADDRESS = _T("address"); -static const LPCTSTR ATTRNAME_RESULT_TIME = _T("result-time"); -static const LPCTSTR ATTRNAME_NEWER_THAN_TIME = _T("newer-than-time"); -static const LPCTSTR ATTRNAME_NEWER_THAN_TID = _T("newer-than-tid"); -static const LPCTSTR ATTRNAME_VALUE = _T("value"); -static const LPCTSTR ATTRNAME_VAR = _T("var"); - -static const LPCTSTR IQTYPE_RESULT = _T("result"); -static const LPCTSTR IQTYPE_SET = _T("set"); -static const LPCTSTR IQTYPE_GET = _T("get"); - -static const LPCTSTR NODENAME_MAILBOX = _T("mailbox"); -static const LPCTSTR NODENAME_QUERY = _T("query"); -static const LPCTSTR NODENAME_IQ = _T("iq"); -static const LPCTSTR NODENAME_USERSETTING = _T("usersetting"); -static const LPCTSTR NODENAME_MAILNOTIFICATIONS = _T("mailnotifications"); -static const LPCTSTR NODENAME_SUBJECT = _T("subject"); -static const LPCTSTR NODENAME_SNIPPET = _T("snippet"); -static const LPCTSTR NODENAME_SENDERS = _T("senders"); -static const LPCTSTR NODENAME_FEATURE = _T("feature"); -static const LPCTSTR NODENAME_NEW_MAIL = _T("new-mail"); - -static const LPCTSTR SETTING_TRUE = _T("true"); - -static const DWORD RESPONSE_TIMEOUT = 1000 * 60 * 60; -static const DWORD TIMER_INTERVAL = 1000 * 60 * 2; - -XML_API xi = {0}; - -#include - -void FormatMessageUrl(LPCTSTR format, LPTSTR buf, LPCTSTR mailbox, LPCTSTR tid) -{ - ULARGE_INTEGER iTid; iTid.QuadPart = _tstoi64(tid); - int l = lstrlen(buf); - wsprintf(buf, format, mailbox, iTid.HighPart, iTid.LowPart); - assert(l >= lstrlen(buf)); -} - -void MakeUrlHex(LPTSTR url, LPCTSTR tid) -{ - ULARGE_INTEGER iTid; iTid.QuadPart = _tstoi64(tid); - LPTSTR tidInUrl = _tcsstr(url, tid); - LPTSTR trail = tidInUrl + lstrlen(tid); - wsprintf(tidInUrl, _T("%x%08x"), iTid.HighPart, iTid.LowPart); - wmemmove(tidInUrl + lstrlen(tidInUrl), trail, lstrlen(trail) + 1); -} - -LPTSTR ExtractJid(LPCTSTR jidWithRes) -{ - int l; - for (l = 0; jidWithRes[l] && jidWithRes[l] != '/'; l++) {}; - assert('/' == jidWithRes[l]); - - LPTSTR result = (LPTSTR)malloc((l + 1) * sizeof(TCHAR)); - __try { - memcpy(result, jidWithRes, l * sizeof(TCHAR)); - result[l] = 0; - } - __except ( - free(result), - EXCEPTION_CONTINUE_SEARCH - ) {}; - - return result; -} - -BOOL TimerHandler(IJabberInterface *ji, HXML node, void *pUserData); - -BOOL InternalListHandler(IJabberInterface *ji, HXML node, LPCTSTR jid, LPCTSTR mailboxUrl) -{ - ULONGLONG maxTid = 0; - LPCTSTR sMaxTid = NULL; - int unreadCount = 0; - for (int i = 0; i < xi.getChildCount(node); i++) { - LPCTSTR sTid = xi.getAttrValue(xi.getChild(node, i), ATTRNAME_TID); - ULONGLONG tid = _tcstoui64(sTid, NULL, 10); - if (tid > maxTid) { - maxTid = tid; - sMaxTid = sTid; - } - - HXML senders = xi.getChildByPath(xi.getChild(node, i), NODENAME_SENDERS, FALSE); - for (int j = 0; j < xi.getChildCount(senders); j++) - if (xi.getAttrValue(xi.getChild(senders, j), ATTRNAME_UNREAD)) { - unreadCount++; - break; - } - } - - LPCSTR acc = GetJidAcc(jid); - if (!acc) return FALSE; - - if (!unreadCount) { - SetupPseudocontact(jid, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED), acc); - return TRUE; - } - - DWORD settings = ReadNotificationSettings(acc); - - if (unreadCount > 5) { - CloseNotifications(acc, mailboxUrl, jid, FALSE); - UnreadMailNotification(acc, jid, mailboxUrl, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED)); - } - else - for (int i = 0; i < xi.getChildCount(node); i++) { - MAIL_THREAD_NOTIFICATION mtn = {0}; - HXML thread = xi.getChild(node, i); - - mtn.subj = xi.getText(xi.getChildByPath(thread, NODENAME_SUBJECT, FALSE)); - mtn.snip = xi.getText(xi.getChildByPath(thread, NODENAME_SNIPPET, FALSE)); - - int threadUnreadCount = 0; - HXML senders = xi.getChildByPath(thread, NODENAME_SENDERS, FALSE); - for (int j = 0; threadUnreadCount < SENDER_COUNT && j < xi.getChildCount(senders); j++) { - HXML sender = xi.getChild(senders, j); - if (xi.getAttrValue(sender, ATTRNAME_UNREAD)) { - mtn.senders[threadUnreadCount].name = xi.getAttrValue(sender, ATTRNAME_NAME); - mtn.senders[threadUnreadCount].addr = xi.getAttrValue(sender, ATTRNAME_ADDRESS); - threadUnreadCount++; - } - } - - LPCTSTR url = xi.getAttrValue(thread, ATTRNAME_URL); - LPCTSTR tid = xi.getAttrValue(thread, ATTRNAME_TID); - - if (ReadCheckbox(0, IDC_STANDARDVIEW, settings)) - FormatMessageUrl(MESSAGE_URL_FORMAT_STANDARD, (LPTSTR)url, mailboxUrl, tid); - else - if (ReadCheckbox(0, IDC_HTMLVIEW, settings)) - FormatMessageUrl(MESSAGE_URL_FORMAT_HTML, (LPTSTR)url, mailboxUrl, tid); - else - MakeUrlHex((LPTSTR)url, tid); - - CloseNotifications(acc, url, jid, i); - UnreadThreadNotification(acc, jid, url, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED), &mtn); - } - - LPCTSTR time = xi.getAttrValue(node, ATTRNAME_RESULT_TIME); - WriteJidSetting(LAST_MAIL_TIME_FROM_JID, jid, time); - WriteJidSetting(LAST_THREAD_ID_FROM_JID, jid, sMaxTid); - return TRUE; -} - -BOOL MailListHandler(IJabberInterface *ji, HXML node, void *pUserData) -{ - LPCTSTR jidWithRes = xi.getAttrValue(node, ATTRNAME_TO); - __try { - if (!node || lstrcmp(xi.getAttrValue(node, ATTRNAME_TYPE), IQTYPE_RESULT)) return TRUE; - - LPCTSTR jid = xi.getAttrValue(node, ATTRNAME_FROM); - assert(jid); - - node = xi.getChildByPath(node, NODENAME_MAILBOX, FALSE); - if (!node) return TRUE; // empty list - - LPCTSTR url = xi.getAttrValue(node, ATTRNAME_URL); - - return InternalListHandler(ji, node, jid, url); - } - __finally { - if (jidWithRes) - ji->Net()->AddTemporaryIqHandler(TimerHandler, JABBER_IQ_TYPE_RESULT, 0, - (PVOID)_tcsdup(jidWithRes), TIMER_INTERVAL); - // Never get a real result stanza. Results elapsed request after WAIT_TIMER_INTERVAL ms - } -} - -void RequestMail(LPCTSTR jidWithRes, IJabberInterface *ji) -{ - HXML child = NULL; - HXML node = xi.createNode(NODENAME_IQ, NULL, FALSE); - __try { - xi.addAttr(node, ATTRNAME_TYPE, IQTYPE_GET); - xi.addAttr(node, ATTRNAME_FROM, jidWithRes); - - UINT uID; - LPTSTR lastMailTime = NULL; - LPTSTR lastThreadId = NULL; - __try { - LPTSTR jid = ExtractJid(jidWithRes); - __try { - xi.addAttr(node, ATTRNAME_TO, jid); - lastMailTime = ReadJidSetting(LAST_MAIL_TIME_FROM_JID, jid); - lastThreadId = ReadJidSetting(LAST_THREAD_ID_FROM_JID, jid); - } - __finally { - free(jid); - } - - LPTSTR id = (LPTSTR)malloc((_tcslen(JABBER_IQID) + 10 + 1) * sizeof(id[0])); // max int fits 10 chars - __try { - wsprintf(id, JABBER_IQID_FORMAT, uID = ji->Net()->SerialNext()); - xi.addAttr(node, ATTRNAME_ID, id); - } - __finally { - free(id); - } - - child = xi.addChild(node, NODENAME_QUERY, NULL); - xi.addAttr(child, ATTRNAME_XMLNS, NOTIFY_FEATURE_XMLNS); - xi.addAttr(child, ATTRNAME_NEWER_THAN_TIME, lastMailTime); - xi.addAttr(child, ATTRNAME_NEWER_THAN_TID, lastThreadId); - } - __finally { - if (lastMailTime) free(lastMailTime); - if (lastThreadId) free(lastThreadId); - } - - IJabberNetInterface* piNet = ji->Net(); - if ( piNet ) - if (piNet->SendXmlNode(node)) - piNet->AddTemporaryIqHandler(MailListHandler, JABBER_IQ_TYPE_RESULT, (int)uID, NULL, RESPONSE_TIMEOUT); - } - __finally { - if (child) xi.destroyNode(child); - if (node) xi.destroyNode(node); - } -} - -BOOL TimerHandler(IJabberInterface *ji, HXML node, void *pUserData) -{ - __try { - assert(!node); // should not intercept real "mir_0" id - RequestMail((LPCTSTR)pUserData, ji); - return FALSE; - } - __finally { - free(pUserData); - } -} - -BOOL NewMailHandler(IJabberInterface *ji, HXML node, void *pUserData) -{ - HXML response = xi.createNode(NODENAME_IQ, NULL, FALSE); - __try { - xi.addAttr(response, ATTRNAME_TYPE, IQTYPE_RESULT); - - LPCTSTR attr = xi.getAttrValue(node, ATTRNAME_ID); - if (!attr) return FALSE; - xi.addAttr(response, ATTRNAME_ID, attr); - - attr = xi.getAttrValue(node, ATTRNAME_FROM); - if (attr) xi.addAttr(response, ATTRNAME_TO, attr); - - attr = xi.getAttrValue(node, ATTRNAME_TO); - if (!attr) return FALSE; - xi.addAttr(response, ATTRNAME_FROM, attr); - - int bytesSent = ji->Net()->SendXmlNode(response); - RequestMail(attr, ji); - return bytesSent > 0; - } - __finally { - xi.destroyNode(response); - } -} - -void SetNotificationSetting(LPCTSTR jidWithResource, IJabberInterface *ji) -{ - HXML child = NULL; - HXML node = xi.createNode(NODENAME_IQ, NULL, FALSE); - __try { - xi.addAttr(node, ATTRNAME_TYPE, IQTYPE_SET); - xi.addAttr(node, ATTRNAME_FROM, jidWithResource); - - LPTSTR jid = ExtractJid(jidWithResource); - __try { - xi.addAttr(node, ATTRNAME_TO, jid); - } - __finally { - free(jid); - } - - LPTSTR id = (LPTSTR)malloc((_tcslen(JABBER_IQID) + 10 + 1) * sizeof(id[0])); // max int fits 10 chars - __try { - wsprintf(id, JABBER_IQID_FORMAT, ji->Net()->SerialNext()); - xi.addAttr(node, ATTRNAME_ID, id); - } - __finally { - free(id); - } - - child = xi.addChild(node, NODENAME_USERSETTING, NULL); - xi.addAttr(child, ATTRNAME_XMLNS, SETTING_FEATURE_XMLNS); - - child = xi.addChild(child, NODENAME_MAILNOTIFICATIONS, NULL); - xi.addAttr(child, ATTRNAME_VALUE, SETTING_TRUE); - - ji->Net()->SendXmlNode(node); - } - __finally { - if (child) xi.destroyNode(child); - if (node) xi.destroyNode(node); - } -} - -BOOL DiscoverHandler(IJabberInterface *ji, HXML node, void *pUserData) -{ - if (!node) return FALSE; - - LPCTSTR jid = xi.getAttrValue(node, ATTRNAME_TO); - assert(jid); - node = xi.getChildByAttrValue(node, NODENAME_QUERY, ATTRNAME_XMLNS, DISCOVERY_XMLNS); - - HXML child = xi.getChildByAttrValue(node, NODENAME_FEATURE, ATTRNAME_VAR, SETTING_FEATURE_XMLNS); - if (child) SetNotificationSetting(jid, ji); - - child = xi.getChildByAttrValue(node, NODENAME_FEATURE, ATTRNAME_VAR, NOTIFY_FEATURE_XMLNS); - if (child) { - ji->Net()->AddIqHandler(NewMailHandler, JABBER_IQ_TYPE_SET, NOTIFY_FEATURE_XMLNS, NODENAME_NEW_MAIL); - RequestMail(jid, ji); - } - - return FALSE; -} - -extern DWORD itlsRecursion; - -BOOL SendHandler(IJabberInterface *ji, HXML node, void *pUserData) -{ - HXML queryNode = xi.getChildByAttrValue(node, NODENAME_QUERY, ATTRNAME_XMLNS, DISCOVERY_XMLNS); - if (!queryNode) return FALSE; - if (lstrcmp(xi.getName(node), NODENAME_IQ)) return FALSE; - if (lstrcmp(xi.getAttrValue(node, ATTRNAME_TYPE), IQTYPE_GET)) return FALSE; - - if (TlsGetValue(itlsRecursion)) return FALSE; - TlsSetValue(itlsRecursion, (PVOID)TRUE); - __try { - UINT id = ji->Net()->SerialNext(); - HXML newNode = xi.createNode(NODENAME_IQ, NULL, FALSE); - __try { - xi.addAttr(newNode, ATTRNAME_TYPE, IQTYPE_GET); - xi.addAttr(newNode, ATTRNAME_TO, xi.getAttrValue(node, ATTRNAME_TO)); - - LPTSTR idAttr = (LPTSTR)malloc(((int)_tcslen(JABBER_IQID) + 10) * sizeof(TCHAR)); - __try { - wsprintf(idAttr, JABBER_IQID_FORMAT, id); - xi.addAttr(newNode, ATTRNAME_ID, idAttr); - } - __finally { - free(idAttr); - } - - xi.addAttr(xi.addChild(newNode, NODENAME_QUERY, NULL), ATTRNAME_XMLNS, DISCOVERY_XMLNS); - ji->Net()->SendXmlNode(newNode); - } - __finally { - xi.destroyNode(newNode); - } - - ji->Net()->AddTemporaryIqHandler(DiscoverHandler, JABBER_IQ_TYPE_RESULT, id, NULL, RESPONSE_TIMEOUT); - return FALSE; - } - __finally { - TlsSetValue(itlsRecursion, (PVOID)FALSE); - } -} - -int AccListChanged(WPARAM wParam, LPARAM lParam) -{ - if (PRAC_ADDED == wParam) { - IJabberInterface *japi = getJabberApi(((PROTOACCOUNT*)lParam)->szModuleName); - if (japi) japi->Net()->AddSendHandler(SendHandler); - } - return 0; -} - -int ModulesLoaded(WPARAM wParam, LPARAM lParam) -{ - RenewPseudocontactHandles(); - DetectPopupModule(); - - int count; - PROTOACCOUNT **protos; - ProtoEnumAccounts(&count, &protos); - for (int i = 0; i < count; i++) { - IJabberInterface *japi = getJabberApi(protos[i]->szModuleName); - if (japi) japi->Net()->AddSendHandler(SendHandler); - } - - HookOptionsInitialization(); - - return 0; -} \ No newline at end of file diff --git a/protocols/GTalkExt/handlers.h b/protocols/GTalkExt/handlers.h deleted file mode 100644 index 10ffa8cb81..0000000000 --- a/protocols/GTalkExt/handlers.h +++ /dev/null @@ -1,27 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -extern HANDLE hModulesLoaded; - -int ModulesLoaded(WPARAM wParam, LPARAM lParam); -int AccListChanged(WPARAM wParam, LPARAM lParam); \ No newline at end of file diff --git a/protocols/GTalkExt/inbox.cpp b/protocols/GTalkExt/inbox.cpp deleted file mode 100644 index 53a4aa2fcb..0000000000 --- a/protocols/GTalkExt/inbox.cpp +++ /dev/null @@ -1,402 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "inbox.h" -#include "notifications.h" -#include "db.h" -#include "options.h" - -static const LPTSTR COMMON_GMAIL_HOST1 = _T("gmail.com"); -static const LPTSTR COMMON_GMAIL_HOST2 = _T("googlemail.com"); - -static const LPSTR AUTH_REQUEST_URL = "https://www.google.com/accounts/ClientAuth"; -static const LPSTR AUTH_REQUEST_PARAMS = "Email=%s&Passwd=%s&" - "accountType=HOSTED_OR_GOOGLE&" - "skipvpage=true&" - "PersistentCookie=false"; - -static const LPSTR ISSUE_TOKEN_REQUEST_URL = "https://www.google.com/accounts/IssueAuthToken"; -static const LPSTR ISSUE_TOKEN_REQUEST_PARAMS = "SID=%s&LSID=%s&" - "Session=true&" - "skipvpage=true&" - "service=gaia"; - -static const LPSTR TOKEN_AUTH_URL = "https://www.google.com/accounts/TokenAuth?"\ - "auth=%s&" - "service=mail&" - "continue=%s&" - "source=googletalk"; - - -static const NETLIBHTTPHEADER HEADER_URL_ENCODED = {"Content-Type", "application/x-www-form-urlencoded"}; -static const int HTTP_OK = 200; - -static const LPSTR SID_KEY_NAME = "SID="; -static const LPSTR LSID_KEY_NAME = "LSID="; - -static const LPSTR LOGIN_PASS_SETTING_NAME = "LoginPassword"; - -static const LPTSTR INBOX_URL_FORMAT = _T("https://mail.google.com/%s%s/#inbox"); - -static const DWORD SIZE_OF_JABBER_OPTIONS = 243 * sizeof(DWORD); - -// 3 lines from netlib.h -#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID) -#define NLH_INVALID 0 -#define NLH_USER 'USER' - -char to_hex(char code) { - static char hex[] = "0123456789abcdef"; - return hex[code & 15]; -} - -char *url_encode(char *str) { - char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; - while (*pstr) { - if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == ',' || *pstr == '~') - *pbuf++ = *pstr; - else if (*pstr == ' ') - *pbuf++ = '+'; - else - *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); - pstr++; - } - *pbuf = '\0'; - return buf; -} - -LPSTR HttpPost(HANDLE hUser, LPSTR reqUrl, LPSTR reqParams) -{ - NETLIBHTTPREQUEST nlhr = {0}; - nlhr.cbSize = sizeof(nlhr); - nlhr.requestType = REQUEST_POST; - nlhr.flags = NLHRF_GENERATEHOST | NLHRF_SMARTAUTHHEADER | NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP | NLHRF_NODUMPHEADERS; - nlhr.szUrl = reqUrl; - nlhr.headers = (NETLIBHTTPHEADER*)&HEADER_URL_ENCODED; - nlhr.headersCount = 1; - nlhr.pData = reqParams; - nlhr.dataLength = lstrlenA(reqParams); - - NETLIBHTTPREQUEST *pResp = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hUser, (LPARAM)&nlhr); - if (!pResp) return NULL; - __try { - if (HTTP_OK == pResp->resultCode) - return _strdup(pResp->pData); - else - return NULL; - } - __finally { - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pResp); - } -} - -LPSTR MakeRequest(HANDLE hUser, LPSTR reqUrl, LPSTR reqParamsFormat, LPSTR p1, LPSTR p2) -{ - LPSTR encodedP1 = url_encode(p1); - __try { - LPSTR encodedP2 = url_encode(p2); - __try { - LPSTR reqParams = (LPSTR)malloc(lstrlenA(reqParamsFormat) + 1 + lstrlenA(encodedP1) + lstrlenA(encodedP2)); - __try { - sprintf(reqParams, reqParamsFormat, encodedP1, encodedP2); - return HttpPost(hUser, reqUrl, reqParams); - } - __finally { - free(reqParams); - } - } - __finally { - free(encodedP2); - } - } - __finally { - free(encodedP1); - } -} - -LPSTR FindSid(LPSTR resp, LPSTR *LSID) -{ - LPSTR SID = strstr(resp, SID_KEY_NAME); - *LSID = strstr(resp, LSID_KEY_NAME); - if (!SID || !*LSID) return NULL; - - if (SID - 1 == *LSID) SID = strstr(SID + 1, SID_KEY_NAME); - if (!SID) return NULL; - - SID += lstrlenA(SID_KEY_NAME); - LPSTR term = strstr(SID, "\n"); - if (term) term[0] = 0; - - *LSID += lstrlenA(LSID_KEY_NAME); - term = strstr(*LSID, "\n"); - if (term) term[0] = 0; - - return SID; -} - -void DoOpenUrl(LPSTR tokenResp, LPSTR url) -{ - LPSTR encodedUrl = url_encode(url); - __try { - LPSTR encodedToken = url_encode(tokenResp); - __try { - LPSTR composedUrl = (LPSTR)malloc(lstrlenA(TOKEN_AUTH_URL) + 1 + lstrlenA(encodedToken) + lstrlenA(encodedUrl)); - __try { - sprintf(composedUrl, TOKEN_AUTH_URL, encodedToken, encodedUrl); - ShellExecuteA(0, NULL, composedUrl, NULL, NULL, SW_SHOW); - } - __finally { - free(composedUrl); - } - } - __finally { - free(encodedToken); - } - } - __finally { - free(encodedUrl); - } -} - -BOOL AuthAndOpen(HANDLE hUser, LPSTR url, LPSTR mailbox, LPSTR pwd) -{ - LPSTR authResp = MakeRequest(hUser, AUTH_REQUEST_URL, AUTH_REQUEST_PARAMS, mailbox, pwd); - if (!authResp) return FALSE; - - __try { - LPSTR LSID; - LPSTR SID = FindSid(authResp, &LSID); - LPSTR tokenResp = MakeRequest(hUser, ISSUE_TOKEN_REQUEST_URL, ISSUE_TOKEN_REQUEST_PARAMS, SID, LSID); - if (!tokenResp) return FALSE; - - __try { - DoOpenUrl(tokenResp, url); - return TRUE; - } - __finally { - free(tokenResp); - } - } - __finally { - free(authResp); - } -} - -struct OPEN_URL_HEADER { - LPSTR url; - LPSTR mailbox; - LPSTR pwd; - LPCSTR acc; -}; - -HANDLE FindNetUserHandle(LPCSTR acc) -{ - IJabberInterface *ji = getJabberApi(acc); - if (!ji) return NULL; - - PBYTE m_psProto = *(PBYTE*)((PBYTE)ji + sizeof(*ji)); // see CJabberInterface in jabber_proto.h - - PHANDLE pResult = (PHANDLE)(m_psProto + // see CJabberProto in jabber_proto.h - sizeof(PVOID) + // skip vtable ptr - sizeof(PVOID) + // skip m_ThreadInfo - SIZE_OF_JABBER_OPTIONS); // skip m_options - - for (int i=0; i < 100; i++) { - __try { - if (GetNetlibHandleType(*pResult) == NLH_USER) - break; - } - __except (EXCEPTION_EXECUTE_HANDLER){ - } - pResult++; - } - - assert(GetNetlibHandleType(*pResult) == NLH_USER); - return *pResult; -} - -unsigned __stdcall OpenUrlThread(OPEN_URL_HEADER* data) -{ - __try { - HANDLE hUser = FindNetUserHandle(data->acc); - if (!hUser || !AuthAndOpen(hUser, data->url, data->mailbox, data->pwd)) - ShellExecuteA(0, NULL, data->url, NULL, NULL, SW_SHOW); - } - __finally { - free(data); - } - return 0; -} - -void __forceinline DecryptString(LPSTR str, int len) -{ - for (--len; len >= 0; len--) - { - const char c = str[len] ^ 0xc3; - if (c) str[len] = c; - } -} - -int GetMailboxPwd(LPCSTR acc, LPCTSTR mailbox, LPSTR *pwd, int buffSize) -{ - char buff[256]; - - DBCONTACTGETSETTING cgs; - DBVARIANT dbv; - cgs.szModule = acc; - cgs.szSetting = LOGIN_PASS_SETTING_NAME; - cgs.pValue = &dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = &buff[0]; - dbv.cchVal = sizeof(buff); - if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, 0, (LPARAM)&cgs)) - return 0; - - int result = dbv.cchVal; - - if (pwd) { - if (buffSize < result + 1) result = buffSize - 1; - memcpy(*pwd, &buff, result + 1); - DecryptString(*pwd, result); - } - - return result; -} - -BOOL OpenUrlWithAuth(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) -{ - int pwdLen = GetMailboxPwd(acc, mailbox, NULL, 0); - if (!pwdLen++) return FALSE; - - int urlLen = lstrlen(url) + 1; - int mailboxLen = lstrlen(mailbox) + 1; - - OPEN_URL_HEADER *data = (OPEN_URL_HEADER*)malloc(sizeof(OPEN_URL_HEADER) + urlLen + mailboxLen + pwdLen); - __try { - data->url = (LPSTR)data + sizeof(OPEN_URL_HEADER); - LPSTR ansi = WtoA(url); - __try { - memcpy(data->url, ansi, urlLen); - } - __finally { - free(ansi); - } - - data->mailbox = data->url + urlLen; - ansi = WtoA(mailbox); - __try { - memcpy(data->mailbox, ansi, mailboxLen); - } - __finally { - free(ansi); - } - - data->pwd = data->mailbox + mailboxLen; - if (!GetMailboxPwd(acc, mailbox, &data->pwd, pwdLen)) return FALSE; - - data->acc = acc; - - if (HANDLE h = mir_forkthreadex((pThreadFuncEx)OpenUrlThread, data, NULL)) { - CloseHandle(h); - data = NULL; - } - else return FALSE; - } - __finally { - free(data); - } - - return TRUE; -} - -unsigned __stdcall ShellExecuteThread(PVOID param) -{ - __try { - ShellExecute(0, NULL, (LPTSTR)param, NULL, NULL, SW_SHOW); - } - __finally { - free(param); - } - return 0; -} - -void StartShellExecuteThread(LPCTSTR url) -{ - LPTSTR urlCopy = _tcsdup(url); - __try { - if (HANDLE h = mir_forkthreadex(ShellExecuteThread, urlCopy, NULL)) { - CloseHandle(h); - urlCopy = NULL; - } - } - __finally { - free(urlCopy); - } -} - -void OpenUrl(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) -{ - extern DWORD itlsSettings; - if (!ReadCheckbox(0, IDC_AUTHONMAILBOX, (DWORD)TlsGetValue(itlsSettings)) || - !OpenUrlWithAuth(acc, mailbox, url)) - StartShellExecuteThread(url); -} - -LPTSTR CraftInboxUrl(LPTSTR jid) -{ - LPTSTR host = _tcsstr(jid, _T("@")) + 1; - - LPTSTR result = (LPTSTR)malloc((lstrlen(INBOX_URL_FORMAT) + 1 + lstrlen(jid)) * sizeof(TCHAR)); - __try { - if (lstrcmpi(host, COMMON_GMAIL_HOST1) && lstrcmpi(host, COMMON_GMAIL_HOST2)) - wsprintf(result, INBOX_URL_FORMAT, _T("a/"), host); // hosted - else - wsprintf(result, INBOX_URL_FORMAT, NULL, _T("mail")); // common - } - __except ( - free(result), - EXCEPTION_CONTINUE_SEARCH - ) {} - - return result; -} - -void OpenContactInbox(HANDLE hContact) -{ - LPSTR acc = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (!acc) return; - - DBVARIANT dbv; - if (!DBGetContactSettingTString(0, acc, "jid", &dbv)) - __try { - LPTSTR url = CraftInboxUrl(dbv.ptszVal); - __try { - OpenUrl(acc, dbv.ptszVal, url); - } - __finally { - free(url); - } - } - __finally { - DBFreeVariant(&dbv); - } -} diff --git a/protocols/GTalkExt/inbox.h b/protocols/GTalkExt/inbox.h deleted file mode 100644 index 0b00128ab9..0000000000 --- a/protocols/GTalkExt/inbox.h +++ /dev/null @@ -1,25 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -void OpenUrl(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url); -void OpenContactInbox(HANDLE hContact); \ No newline at end of file diff --git a/protocols/GTalkExt/menu.cpp b/protocols/GTalkExt/menu.cpp deleted file mode 100644 index 26c81a165f..0000000000 --- a/protocols/GTalkExt/menu.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "menu.h" -#include "resources.h" -#include "options.h" -#include "inbox.h" - -static const LPSTR MS_GTALKEXT_OPENMAILBOX = SHORT_PLUGIN_NAME "/OpenMailbox"; -static const LPTSTR _T(OPEN_MAILBOX_ITEM_CAPTION) = _T("Open mailbox"); - -HANDLE hOpenMailboxService = 0; -HANDLE hOpenMailboxMenuItem = 0; -HANDLE hOnPrebuildMenu = 0; - -INT_PTR OpenMailboxMenuHandler(WPARAM wParam, LPARAM lParam) -{ - if (DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) - OpenContactInbox((HANDLE)wParam); - return 0; -} - -int OnPrebuildMenu(WPARAM wParam, LPARAM lParam) -{ - CLISTMENUITEM cmi = {0}; - cmi.cbSize = sizeof(cmi); - cmi.flags = CMIM_FLAGS; - if (!DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) - cmi.flags |= CMIF_HIDDEN; - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hOpenMailboxMenuItem, (LPARAM)&cmi); - return 0; -} - -BOOL InitMenus(BOOL init) -{ - if (init) { - hOpenMailboxService = (HANDLE)CreateServiceFunction(MS_GTALKEXT_OPENMAILBOX, OpenMailboxMenuHandler); - if (!hOpenMailboxService) { - InitMenus(FALSE); - return FALSE; - } - - extern HICON g_hPopupIcon; - - CLISTMENUITEM cmi = {0}; - cmi.cbSize = sizeof(cmi); - cmi.flags = CMIF_TCHAR; - cmi.hIcon = g_hPopupIcon; - cmi.ptszName = _T(OPEN_MAILBOX_ITEM_CAPTION); - cmi.pszService = MS_GTALKEXT_OPENMAILBOX; - hOpenMailboxMenuItem = Menu_AddContactMenuItem(&cmi); - - if (!hOpenMailboxMenuItem) { - InitMenus(FALSE); - return FALSE; - } - - hOnPrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildMenu); - if (!hOnPrebuildMenu) { - InitMenus(FALSE); - return FALSE; - } - } - else { - if (hOnPrebuildMenu) { - UnhookEvent(hOnPrebuildMenu); - hOnPrebuildMenu = 0; - } - if (hOpenMailboxService) { - DestroyServiceFunction(hOpenMailboxService); - hOpenMailboxService = 0; - } - } - - return TRUE; -} \ No newline at end of file diff --git a/protocols/GTalkExt/menu.h b/protocols/GTalkExt/menu.h deleted file mode 100644 index c06457672a..0000000000 --- a/protocols/GTalkExt/menu.h +++ /dev/null @@ -1,24 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -BOOL InitMenus(BOOL init); \ No newline at end of file diff --git a/protocols/GTalkExt/notifications.cpp b/protocols/GTalkExt/notifications.cpp deleted file mode 100644 index 9a1819a7f1..0000000000 --- a/protocols/GTalkExt/notifications.cpp +++ /dev/null @@ -1,414 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "StdAfx.h" -#include "notifications.h" -#include "db.h" -#include "options.h" -#include "avatar.h" -#include "inbox.h" - -static const LPTSTR TEMP_WINDOW_CLASS_NAME = _T("AntiShittyFullscreenDetectionWindowClass"); -static const LPTSTR _T(NUMBER_EMAILS_MESSAGE) = _T("You've received an e-mail\n%s unread threads"); - -static const LPTSTR PLUGIN_DATA_PROP_NAME = _T("{DB5CE833-C3AC-4851-831C-DDEBD9FA0508}"); -static const LPTSTR EVT_DELETED_HOOK_PROP_NAME = _T("{87CBD2BC-8806-413C-8FD5-1D61ABCA4AF8}"); - -#define EVENT_DELETED_MSG RegisterWindowMessage(_T("{B9B00536-86A0-4BCE-B2FE-4ABD409C22AE}")) -#define MESSAGE_CLOSEPOPUP RegisterWindowMessage(_T("{7A60EA87-3E77-41DF-8A69-59B147F0C9C6}")) - -static const LPSTR CLIST_MODULE_NAME = "CList"; -static const LPSTR CONTACT_DISPLAY_NAME_SETTING = "MyHandle"; -static const LPSTR STATUS_MSG_SETTING = "StatusMsg"; -static const LPSTR UNREAD_THREADS_SETTING = "UnreadThreads"; - -struct POPUP_DATA_HEADER { - BOOL MarkRead; - HANDLE hDbEvent; - HANDLE hContact; - LPTSTR jid; - LPTSTR url; -}; - -extern DWORD itlsSettings; -BOOL isOriginalPopups = FALSE; - -LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_NCCREATE: - return 1; - - case WM_GETMINMAXINFO: - PMINMAXINFO info = (PMINMAXINFO)lParam; - info->ptMaxPosition.x = -100; - info->ptMaxPosition.y = -100; - info->ptMaxSize.x = 10; - info->ptMaxSize.y = 10; - info->ptMaxTrackSize.x = 10; - info->ptMaxTrackSize.y = 10; - info->ptMinTrackSize.x = 10; - info->ptMinTrackSize.y = 10; - return 0; - } - return DefWindowProc(wnd, msg, wParam, lParam); -} - -LPCSTR GetJidAcc(LPCTSTR jid) -{ - int count = 0; - PROTOACCOUNT **protos; - ProtoEnumAccounts(&count, &protos); - - DBVARIANT dbv; - for (int i = 0; i < count; i++) - if (getJabberApi(protos[i]->szModuleName)) - if (!DBGetContactSettingTString(0, protos[i]->szModuleName, "jid", &dbv)) - __try { - if (!lstrcmpi(jid, dbv.ptszVal)) return protos[i]->szModuleName; - } - __finally { - DBFreeVariant(&dbv); - } - - return NULL; -} - -void MarkEventRead(HANDLE hCnt, HANDLE hEvt) -{ - DWORD settings = (DWORD)TlsGetValue(itlsSettings); - if (ReadCheckbox(0, IDC_POPUPSENABLED, settings) && - ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, settings) && - ReadCheckbox(0, IDC_MARKEVENTREAD, settings) && - (CallService(MS_DB_EVENT_MARKREAD, (WPARAM)hCnt, (LPARAM)hEvt) != (INT_PTR)-1)) - CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hCnt, (LPARAM)hEvt); - -} - -int OnEventDeleted(WPARAM hContact, LPARAM hDbEvent, LPARAM wnd) -{ - if (DBGetContactSettingByte((HANDLE)hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { - CallService(MS_CLIST_REMOVEEVENT, hContact, hDbEvent); - PostMessage((HWND)wnd, EVENT_DELETED_MSG, hContact, hDbEvent); - } - - return 0; -} - -LRESULT CALLBACK PopupProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (EVENT_DELETED_MSG == msg) { - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); - if ((HANDLE)lParam == ppdh->hDbEvent) ppdh->hDbEvent = NULL; - return 0; - } - else - if (MESSAGE_CLOSEPOPUP == msg) { - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); - ppdh->MarkRead = TRUE; - PUDeletePopUp(wnd); - } - - switch (msg) { - case UM_INITPOPUP: { - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); - SetProp(wnd, PLUGIN_DATA_PROP_NAME, (HANDLE)ppdh); - SetProp(wnd, EVT_DELETED_HOOK_PROP_NAME, - HookEventParam(ME_DB_EVENT_DELETED, OnEventDeleted, (LPARAM)wnd)); - return 0; - } - - case UM_FREEPLUGINDATA: { - HANDLE hHook = GetProp(wnd, EVT_DELETED_HOOK_PROP_NAME); - RemoveProp(wnd, EVT_DELETED_HOOK_PROP_NAME); - UnhookEvent(hHook); - - LPCSTR acc = NULL; - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); - __try { - if (ppdh->MarkRead && ppdh->hDbEvent && (acc = GetJidAcc(ppdh->jid))) { - ReadNotificationSettings(acc); - MarkEventRead(ppdh->hContact, ppdh->hDbEvent); - CallService(MS_CLIST_REMOVEEVENT, (WPARAM)ppdh->hContact, (LPARAM)ppdh->hDbEvent); - } - - } - __finally { - RemoveProp(wnd, PLUGIN_DATA_PROP_NAME); - free(ppdh); - } - - return 0; - } - - case WM_LBUTTONUP: { - LPCSTR acc = NULL; - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); - __try { - if (!(acc = GetJidAcc(ppdh->jid))) return 0; - - ReadNotificationSettings(acc); - OpenUrl(acc, ppdh->jid, ppdh->url); - } - __finally { - CloseNotifications(acc, ppdh->url, ppdh->jid, TRUE); - } - return 0; - } - - case WM_RBUTTONUP: - SendMessage(wnd, MESSAGE_CLOSEPOPUP, 0, 0); - return 0; - } - return DefWindowProc(wnd, msg, wParam, lParam); -} - -HWND DoAddPopup(POPUPDATAT *data) -{ - WNDCLASS cls = {0}; - cls.lpfnWndProc = WndProc; - cls.lpszClassName = TEMP_WINDOW_CLASS_NAME; - - HWND result = 0; - HWND handle = 0; - __try { - if (ReadCheckbox(0, IDC_POPUPSINFULLSCREEN, (DWORD)TlsGetValue(itlsSettings))) { - RegisterClass(&cls); - handle = CreateWindowEx(WS_EX_TOOLWINDOW, TEMP_WINDOW_CLASS_NAME, NULL, WS_OVERLAPPED | WS_VISIBLE, - -100, -100, 10, 10, NULL, NULL, NULL, NULL); - if (handle) { - ShowWindow(handle, SW_MINIMIZE); - ShowWindow(handle, SW_RESTORE); - } - } - result = (HWND)CallService(MS_POPUP_ADDPOPUPT, (WPARAM) data, APF_RETURN_HWND); - } - __finally { - if (handle) DestroyWindow(handle); - } - - return result; -} - -void FormatPseudocontactDisplayName(LPTSTR buff, LPCTSTR jid, LPCTSTR unreadCount) -{ - if (lstrcmp(unreadCount, _T("0"))) - wsprintf(buff, _T("%s [%s]"), jid, unreadCount); - else - wsprintf(buff, _T("%s"), jid); -} - -HANDLE SetupPseudocontact(LPCTSTR jid, LPCTSTR unreadCount, LPCSTR acc, LPCTSTR displayName) -{ - HANDLE result = (HANDLE)DBGetContactSettingDword(0, acc, PSEUDOCONTACT_LINK, 0); - if (!result || !DBGetContactSettingByte(result, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { - result = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); - DBWriteContactSettingDword(0, acc, PSEUDOCONTACT_LINK, (DWORD)result); - DBWriteContactSettingByte(result, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 1); - CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)result, (LPARAM)acc); - } - - SetAvatar(result); - - BOOL allocateName = !displayName; - __try { - if (allocateName) { - displayName = (LPCTSTR)malloc((lstrlen(jid) + lstrlen(unreadCount) + 3 + 1) * sizeof(TCHAR)); - FormatPseudocontactDisplayName((LPTSTR)displayName, jid, unreadCount); - } - - DBWriteContactSettingTString(result, CLIST_MODULE_NAME, CONTACT_DISPLAY_NAME_SETTING, displayName); - } - __finally { - if (allocateName) free((PVOID)displayName); - } - - DBWriteContactSettingTString(result, CLIST_MODULE_NAME, STATUS_MSG_SETTING, TranslateTS(MAIL_NOTIFICATIONS)); - DBWriteContactSettingTString(result, SHORT_PLUGIN_NAME, UNREAD_THREADS_SETTING, unreadCount); - - return result; -} - -HANDLE AddCListNotification(HANDLE hContact, LPCSTR acc, POPUPDATAT *data, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) -{ - int lurl = (lstrlen(url) + 1) * sizeof(WCHAR); - LPSTR utf8 = (LPSTR)malloc(sizeof(data->lptzText) + sizeof(WCHAR) * 2 + lurl); - __try { - DBEVENTINFO dbei = {0}; - - dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, &data->lptzText[0], -1, utf8, sizeof(data->lptzText), NULL, NULL) - 1; - - if (utf8[dbei.cbBlob - 1] != 10) { - utf8[dbei.cbBlob++] = 13; - utf8[dbei.cbBlob++] = 10; - } - - dbei.cbBlob += WideCharToMultiByte(CP_UTF8, 0, url, -1, utf8 + dbei.cbBlob, lurl, NULL, NULL); - - dbei.pBlob = (PBYTE)utf8; - dbei.cbSize = sizeof(dbei); - dbei.szModule = (LPSTR)acc; - dbei.timestamp = time(NULL); - dbei.flags = DBEF_UTF; - dbei.eventType = EVENTTYPE_MESSAGE; - return (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); - } - __finally { - free(utf8); - } -} - -BOOL UsePopups() -{ - return ServiceExists(MS_POPUP_QUERY) && - CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0) && - ReadCheckbox(0, IDC_POPUPSENABLED, (DWORD)TlsGetValue(itlsSettings)); -} - -void ShowNotification(LPCSTR acc, POPUPDATAT *data, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) -{ - HANDLE hCnt = SetupPseudocontact(jid, unreadCount, acc, &data->lptzContactName[0]); - HANDLE hEvt = ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, (DWORD)TlsGetValue(itlsSettings)) - ? AddCListNotification(hCnt, acc, data, jid, url, unreadCount) : NULL; - - if (!UsePopups()) return; - - extern HICON g_hPopupIcon; - data->lchIcon = g_hPopupIcon; - data->iSeconds = (int)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, 0); - data->colorBack = (COLORREF)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, 0); - data->colorText = (COLORREF)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, 0); - if (data->colorBack == data->colorText) { - data->colorBack = 0; - data->colorText = 0; - } - - data->PluginWindowProc = PopupProc; - int lurl = (lstrlen(url) + 1) * sizeof(TCHAR); - int ljid = (lstrlen(jid) + 1) * sizeof(TCHAR); - data->PluginData = malloc(sizeof(POPUP_DATA_HEADER) + lurl + ljid); - __try { - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)data->PluginData; - - ppdh->MarkRead = FALSE; - ppdh->hContact = hCnt; - ppdh->hDbEvent = hEvt; - - ppdh->jid = (LPTSTR)((PBYTE)ppdh + sizeof(*ppdh)); - memcpy(ppdh->jid, jid, ljid); - - ppdh->url = (LPTSTR)((PBYTE)ppdh->jid + ljid); - memcpy(ppdh->url, url, lurl); - - HWND code = DoAddPopup(data); - if ((code == (HWND)-1) || (isOriginalPopups && !code)) - return; - data->PluginData = NULL; // freed in popup wndproc - } - __finally { - free(data->PluginData); - } -} - -void UnreadMailNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) -{ - POPUPDATAT data = {0}; - - FormatPseudocontactDisplayName(&data.lptzContactName[0], jid, unreadCount); - wsprintf(&data.lptzText[0], TranslateT(NUMBER_EMAILS_MESSAGE), unreadCount); - - ShowNotification(acc, &data, jid, url, unreadCount); -} - -void UnreadThreadNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount, const MAIL_THREAD_NOTIFICATION *mtn) -{ - POPUPDATAT data = {0}; - - FormatPseudocontactDisplayName(&data.lptzContactName[0], jid, unreadCount); - LPTSTR senders = (LPTSTR)malloc(SENDER_COUNT * 100 * sizeof(TCHAR)); - LPTSTR currSender = senders; - __try { - for (int i = 0; i < SENDER_COUNT && mtn->senders[i].addr; i++) { - wsprintf(currSender, _T(" %s <%s>\n"), mtn->senders[i].name, mtn->senders[i].addr); - currSender += lstrlen(currSender); - } - - if (ReadCheckbox(0, IDC_ADDSNIP, (DWORD)TlsGetValue(itlsSettings))) - wsprintf(&data.lptzText[0], TranslateTS(FULL_NOTIFICATION_FORMAT), mtn->subj, senders, mtn->snip); - else - wsprintf(&data.lptzText[0], TranslateTS(SHORT_NOTIFICATION_FORMAT), mtn->subj, senders); - } - __finally { - free(senders); - } - - ShowNotification(acc, &data, jid, url, unreadCount); -} - -void ClearNotificationContactHistory(LPCSTR acc) -{ - HANDLE hEvent = 0; - HANDLE hContact = (HANDLE)DBGetContactSettingDword(0, acc, PSEUDOCONTACT_LINK, 0); - if (hContact && DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) - while ((hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0)) && - !CallService(MS_DB_EVENT_DELETE, (WPARAM)hContact, (LPARAM)hEvent)) {}; -} - -DWORD ReadNotificationSettings(LPCSTR acc) -{ - DWORD result = ReadCheckboxes(0, acc); - TlsSetValue(itlsSettings, (PVOID)result); - return result; -} - -struct POPUP_IDENT_STRINGS { - LPCTSTR url; - LPCTSTR jid; -}; - -BOOL CALLBACK ClosePopupFunc(__in HWND hwnd, __in LPARAM lParam) -{ - DWORD pid = 0; - GetWindowThreadProcessId(hwnd, &pid); - if (pid != GetCurrentProcessId()) return TRUE; - - POPUP_IDENT_STRINGS *ppis = (POPUP_IDENT_STRINGS*)lParam; - POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)GetProp(hwnd, PLUGIN_DATA_PROP_NAME); - if (!ppdh) return TRUE; - - if (!lstrcmpi(ppis->url, ppdh->url) && !lstrcmpi(ppis->jid, ppdh->jid)) - SendMessage(hwnd, MESSAGE_CLOSEPOPUP, 0, 0); - - return TRUE; -} - -void CloseNotifications(LPCSTR acc, LPCTSTR url, LPCTSTR jid, BOOL PopupsOnly) -{ - DWORD settings = (DWORD)TlsGetValue(itlsSettings); - if (acc && - !PopupsOnly && - ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, settings) && - ReadCheckbox(0, IDC_CLEARPSEUDOCONTACTLOG, settings)) - ClearNotificationContactHistory(acc); - - POPUP_IDENT_STRINGS pis = {url, jid}; - EnumWindows(ClosePopupFunc, (LPARAM)&pis); -} \ No newline at end of file diff --git a/protocols/GTalkExt/notifications.h b/protocols/GTalkExt/notifications.h deleted file mode 100644 index 94d6e6353f..0000000000 --- a/protocols/GTalkExt/notifications.h +++ /dev/null @@ -1,42 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -static const int SENDER_COUNT = 10; - -struct SENDER { - LPCTSTR name; - LPCTSTR addr; -}; - -struct MAIL_THREAD_NOTIFICATION { - LPCTSTR subj; - LPCTSTR snip; - SENDER senders[SENDER_COUNT]; -}; - -void UnreadMailNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount); -void UnreadThreadNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount, const MAIL_THREAD_NOTIFICATION *mtn); -void CloseNotifications(LPCSTR acc, LPCTSTR url, LPCTSTR jid, BOOL PopupsOnly); -DWORD ReadNotificationSettings(LPCSTR acc); -HANDLE SetupPseudocontact(LPCTSTR jid, LPCTSTR unreadCount, LPCSTR acc, LPCTSTR displayName = NULL); -LPCSTR GetJidAcc(LPCTSTR jid); \ No newline at end of file diff --git a/protocols/GTalkExt/options.cpp b/protocols/GTalkExt/options.cpp deleted file mode 100644 index e64e23679c..0000000000 --- a/protocols/GTalkExt/options.cpp +++ /dev/null @@ -1,297 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "options.h" - -static const LPTSTR ACCOUNT_PROP_NAME = _T("{BF447EBA-27AE-4DB7-893C-FC42A3F74D75}"); -static const LPTSTR DIALOG_INITIALIZED_PROP_NAME = _T("{5EE59FE5-679A-4A29-B0A1-03092E7AC20E}"); - -static const LPTSTR POPUPS_OPTIONS_GROUP = _T("Popups"); -static const LPTSTR NETWORK_OPTIONS_GROUP = _T("Network"); - -static const LPSTR NOTIFY_SETTINGS_FROM_MOD_NAME = SHORT_PLUGIN_NAME ".NotifySettingsFromModName"; - -static const LPTSTR TEST_LETTER_SUBJECT = _T("Why C sucks"); -static const LPTSTR TEST_LETTER_INBOX = _T("brickstrace@gmail.com [1]"); -static const LPTSTR TEST_LETTER_SENDER = _T(" bems \n"); -static const LPTSTR TEST_LETTER_SNIP = - _T("* Primitive type system\n") - _T("* No overloading\n") - _T("* Limited possibility of data abstraction, polymorphism, subtyping and code reuse\n") - _T("* No metaprogramming except preprocessor macros\n") - _T("* No exceptions"); - -HANDLE hOptionsHook = 0; -extern HINSTANCE hInst; - -void CheckControlsEnabled(HWND wnd) -{ - BOOL PopupsEnabled = (SendMessage(GetDlgItem(wnd, IDC_POPUPSENABLED), BM_GETSTATE, 0, 0) & BST_CHECKED) == BST_CHECKED; - EnableWindow(GetDlgItem(wnd, IDC_POPUPSINFULLSCREEN), PopupsEnabled); - EnableWindow(GetDlgItem(wnd, IDC_POPUPSINFULLSCREENLABEL), PopupsEnabled); - - BOOL CListEnabled = (SendMessage(GetDlgItem(wnd, IDC_PSEUDOCONTACTENABLED), BM_GETSTATE, 0, 0) & BST_CHECKED) == BST_CHECKED; - EnableWindow(GetDlgItem(wnd, IDC_CLEARPSEUDOCONTACTLOG), CListEnabled); - EnableWindow(GetDlgItem(wnd, IDC_SUPRESSFOREIGN), CListEnabled); - - EnableWindow(GetDlgItem(wnd, IDC_MARKEVENTREAD), PopupsEnabled && CListEnabled); - EnableWindow(GetDlgItem(wnd, IDC_ADDSNIP), PopupsEnabled || CListEnabled); - - EnableWindow(GetDlgItem(wnd, IDC_MAILBOXVIEWLABEL), PopupsEnabled || CListEnabled); - EnableWindow(GetDlgItem(wnd, IDC_UNKNOWNVIEW), PopupsEnabled || CListEnabled); - EnableWindow(GetDlgItem(wnd, IDC_STANDARDVIEW), PopupsEnabled || CListEnabled); - EnableWindow(GetDlgItem(wnd, IDC_HTMLVIEW), PopupsEnabled || CListEnabled); -} - -BOOL ReadCheckbox(HWND wnd, int id, DWORD controls) -{ - BOOL result = ((controls >> (id - IDC_BASE)) & 1); - if (id != IDC_STANDARDVIEW && id != IDC_HTMLVIEW) result = !result; - if (wnd) Button_SetCheck(GetDlgItem(wnd, id), result); - return result; -} - -DWORD ReadCheckboxes(HWND wnd, LPCSTR mod) -{ - DWORD controls = DBGetContactSettingDword(0, NOTIFY_SETTINGS_FROM_MOD_NAME, mod, 0); - ReadCheckbox(wnd, IDC_POPUPSENABLED, controls); - ReadCheckbox(wnd, IDC_PSEUDOCONTACTENABLED, controls); - ReadCheckbox(wnd, IDC_CLEARPSEUDOCONTACTLOG, controls); - ReadCheckbox(wnd, IDC_POPUPSINFULLSCREEN, controls); - ReadCheckbox(wnd, IDC_SUPRESSFOREIGN, controls); - ReadCheckbox(wnd, IDC_MARKEVENTREAD, controls); - ReadCheckbox(wnd, IDC_AUTHONMAILBOX, controls); - ReadCheckbox(wnd, IDC_ADDSNIP, controls); - ReadCheckbox(wnd, IDC_UNKNOWNVIEW, controls); - ReadCheckbox(wnd, IDC_STANDARDVIEW, controls); - ReadCheckbox(wnd, IDC_HTMLVIEW, controls); - return controls; -} - -DWORD GetCheckboxSaveValue(HWND wnd, int id) -{ - BOOL val = Button_GetCheck(GetDlgItem(wnd, id)); - if (id != IDC_STANDARDVIEW && id != IDC_HTMLVIEW) val = !val; - return val ? (1 << (id - IDC_BASE)) : 0; -} - -void SaveControls(HWND wnd, LPCSTR mod) -{ - DWORD controls = GetCheckboxSaveValue(wnd, IDC_CLEARPSEUDOCONTACTLOG) | - GetCheckboxSaveValue(wnd, IDC_POPUPSINFULLSCREEN) | - GetCheckboxSaveValue(wnd, IDC_POPUPSENABLED) | - GetCheckboxSaveValue(wnd, IDC_PSEUDOCONTACTENABLED) | - GetCheckboxSaveValue(wnd, IDC_SUPRESSFOREIGN) | - GetCheckboxSaveValue(wnd, IDC_MARKEVENTREAD) | - GetCheckboxSaveValue(wnd, IDC_AUTHONMAILBOX) | - GetCheckboxSaveValue(wnd, IDC_ADDSNIP) | - GetCheckboxSaveValue(wnd, IDC_UNKNOWNVIEW) | - GetCheckboxSaveValue(wnd, IDC_STANDARDVIEW) | - GetCheckboxSaveValue(wnd, IDC_HTMLVIEW); - - DBWriteContactSettingDword(0, NOTIFY_SETTINGS_FROM_MOD_NAME, mod, controls); -} - -INT_PTR CALLBACK AccOptionsDlgProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - SetProp(wnd, ACCOUNT_PROP_NAME, (HANDLE)lParam); - TranslateDialogDefault(wnd); - ReadCheckboxes(wnd, (LPCSTR)lParam); - CheckControlsEnabled(wnd); - break; - - case WM_CTLCOLORSTATIC: - if (GetDlgItem(wnd, IDC_WARNBAR) == (HWND)lParam) - return (INT_PTR)CreateSolidBrush(0x55AAFF); // orange - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_POPUPSENABLED: - case IDC_PSEUDOCONTACTENABLED: - if (HIWORD(wParam) == BN_CLICKED) CheckControlsEnabled(wnd); - // no break - - case IDC_CLEARPSEUDOCONTACTLOG: - case IDC_POPUPSINFULLSCREEN: - case IDC_SUPRESSFOREIGN: - case IDC_MARKEVENTREAD: - case IDC_AUTHONMAILBOX: - case IDC_ADDSNIP: - case IDC_UNKNOWNVIEW: - case IDC_STANDARDVIEW: - case IDC_HTMLVIEW: - if (HIWORD(wParam) == BN_CLICKED) PropSheet_Changed(GetParent(wnd), wnd); - } - break; - - case WM_NOTIFY: - if (!((LPNMHDR)lParam)->idFrom && ((LPNMHDR)lParam)->code == PSN_APPLY) - SaveControls(wnd, (LPCSTR)GetProp(wnd, ACCOUNT_PROP_NAME)); - break; - } - return 0; -} - -void ShowTestPopup(HWND wnd) -{ - POPUPDATAT data = {0}; - wsprintf(&data.lptzContactName[0], TEST_LETTER_INBOX); - wsprintf(&data.lptzText[0], TranslateTS(FULL_NOTIFICATION_FORMAT), - TEST_LETTER_SUBJECT, TEST_LETTER_SENDER, TEST_LETTER_SNIP); - - int len = SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXTLENGTH, 0, 0) + 1; - LPTSTR timeout = (LPTSTR)malloc(len * sizeof(TCHAR)); - __try { - SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXT, len, (LPARAM)timeout); - data.iSeconds = _ttoi(timeout); - } - __finally { - free(timeout); - } - - extern HICON g_hPopupIcon; - data.lchIcon = g_hPopupIcon; - data.colorBack = (COLORREF)SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_GETCOLOUR, 0, 0); - data.colorText = (COLORREF)SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_GETCOLOUR, 0, 0); - if (data.colorBack == data.colorText) { - data.colorBack = 0; - data.colorText = 0; - } - CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&data, 0); -} - -INT_PTR CALLBACK PopupsOptionsDlgProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(wnd); - SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_SETCOLOUR, 0, - (LPARAM)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, 0)); - SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_SETCOLOUR, 0, - (LPARAM)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, 0)); - - {LPTSTR timeout = (LPTSTR)malloc(11 * sizeof(TCHAR)); - __try { - wsprintf(timeout, _T("%d"), DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, 0)); - SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_SETTEXT, 0, (LPARAM)timeout); - } - __finally { - free(timeout); - }} - - SetProp(wnd, DIALOG_INITIALIZED_PROP_NAME, (HANDLE)TRUE); - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDC_TESTBUTTON && HIWORD(wParam) == BN_CLICKED) - ShowTestPopup(wnd); - - if (GetProp(wnd, DIALOG_INITIALIZED_PROP_NAME)) - switch (LOWORD(wParam)) { - case IDC_BACKCOLORPICKER: - case IDC_TEXTCOLORPICKER: - if (HIWORD(wParam) == CPN_COLOURCHANGED) PropSheet_Changed(GetParent(wnd), wnd); - break; - - case IDC_TIMEOUTEDIT: - if (HIWORD(wParam) == EN_CHANGE) PropSheet_Changed(GetParent(wnd), wnd); - } - break; - - case WM_NOTIFY: - if (!((LPNMHDR)lParam)->idFrom && ((LPNMHDR)lParam)->code == PSN_APPLY) - DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, - (DWORD)SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_GETCOLOUR, 0, 0)); - DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, - (DWORD)SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_GETCOLOUR, 0, 0)); - - int len = SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXTLENGTH, 0, 0) + 1; - LPTSTR timeout = (LPTSTR)malloc(len * sizeof(TCHAR)); - __try { - SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXT, len, (LPARAM)timeout); - DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, _ttoi(timeout)); - } - __finally { - free(timeout); - } - break; - } - return 0; -} - -void AddPopupsPage(WPARAM wParam) -{ - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.ptszTitle = MAIL_NOTIFICATIONS; - odp.pfnDlgProc = PopupsOptionsDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUPSETTINGS); - odp.hInstance = hInst; - odp.ptszGroup = POPUPS_OPTIONS_GROUP; - odp.flags = ODPF_UNICODE | ODPF_USERINFOTAB; - - Options_AddPage(wParam, &odp); -} - -void AddAccPage(LPCTSTR acc, LPCSTR mod, WPARAM wParam) -{ - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.pszTitle = (LPSTR)acc; - odp.pfnDlgProc = AccOptionsDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAILSETTINGS); - odp.hInstance = hInst; - odp.ptszGroup = NETWORK_OPTIONS_GROUP; - odp.flags = ODPF_UNICODE | ODPF_USERINFOTAB; - odp.ptszTab = MAIL_NOTIFICATIONS; - odp.dwInitParam = (LPARAM)mod; - - Options_AddPage(wParam, &odp); -} - -int OptionsInitialization(WPARAM wParam, LPARAM lParam) -{ - int count; - PROTOACCOUNT **accs; - CallService(MS_PROTO_ENUMACCOUNTS, (WPARAM)&count, (LPARAM)&accs); - for (int i = 0; i < count; i++) - if (getJabberApi(accs[i]->szModuleName)) AddAccPage(accs[i]->tszAccountName, accs[i]->szModuleName, wParam); - - if (ServiceExists(MS_POPUP_ADDPOPUPT)) AddPopupsPage(wParam); - return FALSE; -} - -BOOL HookOptionsInitialization() -{ - return (hOptionsHook = HookEvent(ME_OPT_INITIALISE, OptionsInitialization)) != 0; -} - -void UnhookOptionsInitialization() -{ - if (hOptionsHook) { - UnhookEvent(hOptionsHook); - hOptionsHook = 0; - } -} \ No newline at end of file diff --git a/protocols/GTalkExt/options.h b/protocols/GTalkExt/options.h deleted file mode 100644 index bc720e22ed..0000000000 --- a/protocols/GTalkExt/options.h +++ /dev/null @@ -1,39 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -#include "resources.h" - -static const LPTSTR MAIL_NOTIFICATIONS = _T("GMail notifications"); -static const LPTSTR FULL_NOTIFICATION_FORMAT = _T("subject\n %s\nfrom\n%s\n%s\n"); -static const LPTSTR SHORT_NOTIFICATION_FORMAT = _T("subject\n %s\nfrom\n%s"); - -static const LPSTR PSEUDOCONTACT_LINK = "GTalkExtNotifyContact"; -static const LPSTR PSEUDOCONTACT_FLAG = "IsNotifyContact"; -static const LPSTR BACK_COLOR_SETTING = "BackColor"; -static const LPSTR TEXT_COLOR_SETTING = "TextColor"; -static const LPSTR TIMEOUT_SETTING = "Timeout"; - -BOOL HookOptionsInitialization(); -void UnhookOptionsInitialization(); -DWORD ReadCheckboxes(HWND wnd, LPCSTR mod); -BOOL ReadCheckbox(HWND wnd, int id, DWORD controls); \ No newline at end of file diff --git a/protocols/GTalkExt/popups.cpp b/protocols/GTalkExt/popups.cpp deleted file mode 100644 index 99ab94470b..0000000000 --- a/protocols/GTalkExt/popups.cpp +++ /dev/null @@ -1,104 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" -#include "popups.h" -#include "options.h" - -static const LPTSTR YAPP_WND_CLASS1 = _T("YAPPYAPPWindowClass"); -static const LPTSTR YAPP_WND_CLASS2 = _T("YAPPWinClass"); - -extern BOOL isOriginalPopups; - -LRESULT CALLBACK PopupHookProc(int nCode, WPARAM wParam, LPARAM lParam) -{ - PCWPRETSTRUCT cs = (PCWPRETSTRUCT)lParam; - if ((HC_ACTION == nCode) && - (WM_CREATE == cs->message) && - (-1 != cs->lResult) && - ServiceExists(MS_POPUP_GETCONTACT)) { - - // with YAPP we can't call MS_POPUP_GETCONTACT on a random window - TCHAR ClassName[32]; - GetClassName(cs->hwnd, ClassName, sizeof(ClassName) / sizeof(TCHAR)); - if (isOriginalPopups || - !lstrcmp(YAPP_WND_CLASS1, ClassName) || - !lstrcmp(YAPP_WND_CLASS2, ClassName)) { - - HANDLE hContact = (HANDLE)CallService(MS_POPUP_GETCONTACT, (WPARAM)cs->hwnd, 0); - if (hContact != (HANDLE)-1 && - hContact != (HANDLE)0x80000000 && - DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { - LPCSTR proto = (LPCSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - DWORD checkboxes = ReadCheckboxes(0, proto); - if (ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, checkboxes) && - ReadCheckbox(0, IDC_SUPRESSFOREIGN, checkboxes)) - PostMessage(cs->hwnd, WM_CLOSE, 0, 0); - } - } - } - return CallNextHookEx(0, nCode, wParam, lParam); -} - -typedef PLUGININFOEX* (MIRANDAPLUGININFOEX) (DWORD mirandaVersion); - -static GUID POPUP_GUID1 = {0x26a9125d, 0x7863, 0x4e01, {0xaf, 0xe, 0xd1, 0x4e, 0xf9, 0x5c, 0x50, 0x54}}; -static GUID POPUP_GUID2 = {0x26a9125d, 0x7863, 0x4e01, {0xaf, 0xe, 0xd1, 0x4e, 0xf9, 0x5c, 0x50, 0x53}}; - -DWORD g_mirandaVersion = 0; - -BOOL IsOriginalPopupModule(HMODULE hMod) -{ - MIRANDAPLUGININFOEX *MirandaPluginInfoEx = (MIRANDAPLUGININFOEX*)GetProcAddress(hMod, "MirandaPluginInfoEx"); - if (!MirandaPluginInfoEx) return FALSE; - - PLUGININFOEX *PluginInfoEx = MirandaPluginInfoEx(g_mirandaVersion); - if (!PluginInfoEx) return FALSE; - - GUID *guid1 = (GUID*)&PluginInfoEx->uuid; - GUID *guid2 = (GUID*)&POPUP_GUID1; - GUID *guid3 = (GUID*)&POPUP_GUID2; - return (IsEqualGUID(*guid1, *guid2) || IsEqualGUID(*guid1, *guid3)); -} - -extern BOOL isOriginalPopups; - -void DetectPopupModule() -{ - DWORD bytesNeeded; - if (!EnumProcessModules(GetCurrentProcess(), NULL, 0, &bytesNeeded)) - return; - - HMODULE *mods = (HMODULE*)malloc(bytesNeeded); - __try { - if (!EnumProcessModules(GetCurrentProcess(), mods, bytesNeeded, &bytesNeeded)) - return; - - for (DWORD i = 0; i < (bytesNeeded / sizeof(HMODULE)); i++) - if (IsOriginalPopupModule(mods[i])) { - isOriginalPopups = TRUE; - break; - } - } - __finally { - free(mods); - } -} diff --git a/protocols/GTalkExt/popups.h b/protocols/GTalkExt/popups.h deleted file mode 100644 index f9e142e0e6..0000000000 --- a/protocols/GTalkExt/popups.h +++ /dev/null @@ -1,25 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -LRESULT CALLBACK PopupHookProc(int nCode, WPARAM wParam, LPARAM lParam); -void DetectPopupModule(); \ No newline at end of file diff --git a/protocols/GTalkExt/res/settings.rc b/protocols/GTalkExt/res/settings.rc index 3e8eb0f0e0..efad07e0b9 100644 --- a/protocols/GTalkExt/res/settings.rc +++ b/protocols/GTalkExt/res/settings.rc @@ -1,4 +1,4 @@ -#include "resources.h" +#include "..\src\resources.h" #include "winres.h" #include "m_utils.h" @@ -80,5 +80,5 @@ VS_VERSION_INFO VERSIONINFO } } -IDI_POPUP ICON "res\\PopupIcon.ico" -IDI_PSEUDOAVA PNG "res\\pseudoava.png" \ No newline at end of file +IDI_POPUP ICON "PopupIcon.ico" +IDI_PSEUDOAVA PNG "pseudoava.png" \ No newline at end of file diff --git a/protocols/GTalkExt/resources.h b/protocols/GTalkExt/resources.h deleted file mode 100644 index d72e34dcef..0000000000 --- a/protocols/GTalkExt/resources.h +++ /dev/null @@ -1,67 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -#define SHORT_PLUGIN_NAME "GTalkExt" - -#define IDD_MAILSETTINGS 2001 - -#define IDC_BASE 1001 -#define IDC_POPUPSENABLED IDC_BASE + 0 -#define IDC_PSEUDOCONTACTENABLED IDC_BASE + 1 -#define IDC_CLEARPSEUDOCONTACTLOG IDC_BASE + 2 -#define IDC_POPUPSINFULLSCREEN IDC_BASE + 3 -#define IDC_SUPRESSFOREIGN IDC_BASE + 4 -#define IDC_MARKEVENTREAD IDC_BASE + 5 -#define IDC_AUTHONMAILBOX IDC_BASE + 6 -#define IDC_ADDSNIP IDC_BASE + 7 -#define IDC_UNKNOWNVIEW IDC_BASE + 8 -#define IDC_STANDARDVIEW IDC_BASE + 9 -#define IDC_HTMLVIEW IDC_BASE + 10 -#define IDC_POPUPSINFULLSCREENLABEL IDC_BASE + 32 -#define IDC_NOTE IDC_BASE + 33 -#define IDC_WARNBAR IDC_BASE + 34 -#define IDC_AUTHONMAILBOXLABEL IDC_BASE + 35 -#define IDC_MAILBOXVIEWLABEL IDC_BASE + 36 - -#define IDD_POPUPSETTINGS 2002 - -#define IDC_BACKCOLORLABEL 1001 -#define IDC_BACKCOLORPICKER 1002 -#define IDC_TEXTCOLORLABEL 1003 -#define IDC_TEXTCOLORPICKER 1004 -#define IDC_TIMEOUTLABEL 1005 -#define IDC_TIMEOUTEDIT 1006 -#define IDC_DEFCOLORSLABEL 1007 -#define IDC_DEFTIMEOUTLABEL 1008 -#define IDC_TESTBUTTON 1009 -#define IDC_GROUP 1010 - -#define IDI_POPUP 3001 -#define IDI_PSEUDOAVA 3002 - -#define PLUGIN_VERSION_STRING "0.0.0.20 BETA" -#define PLUGIN_FILE_VERSION 0, 0, 0, 20 -#define PLUGIN_VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 0, 20) - -#define PLUGIN_DESCRIPTION "GTalk extensions for Jabber protocol" -#define COPYRIGHT_STRING "2010, 11 bems" diff --git a/protocols/GTalkExt/src/GTalkExt.cpp b/protocols/GTalkExt/src/GTalkExt.cpp new file mode 100644 index 0000000000..7646bd10be --- /dev/null +++ b/protocols/GTalkExt/src/GTalkExt.cpp @@ -0,0 +1,91 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** +// GTalkExt.cpp : Defines the exported functions for the DLL application. +//*************************************************************************************** + +#include "stdafx.h" +#include "options.h" +#include "handlers.h" +#include "tipper_items.h" +#include "avatar.h" +#include "menu.h" + + +int hLangpack; + +#define MIID_PLUGINIFACE {0x08B86253, 0xEC6E, 0x4d09, { 0xB7, 0xA9, 0x64, 0xAC, 0xDF, 0x06, 0x27, 0xB8 }} + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + PLUGIN_DESCRIPTION, + PLUGIN_VERSION_DWORD, + "Currently only mail notifications implemented", + "bems", + "bems@vingrad.ru", + COPYRIGHT_STRING, + "http://miranda-ng.org/", + UNICODE_AWARE, //doesn't replace anything built-in + MIID_PLUGINIFACE //{08B86253-EC6E-4d09-B7A9-64ACDF0627B8} +}; + +extern DWORD g_mirandaVersion; + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + g_mirandaVersion = mirandaVersion; + return &pluginInfo; +} + +HANDLE hModulesLoaded = 0; +HANDLE hAccListChanged = 0; + +extern "C" int __declspec(dllexport) Unload(void) +{ + UnhookOptionsInitialization(); + InitMenus(FALSE); + InitAvaUnit(FALSE); + if (hAccListChanged) UnhookEvent(hAccListChanged); + if (hModulesLoaded) UnhookEvent(hModulesLoaded); + return 0; +} + +HICON g_hPopupIcon = 0; +extern HINSTANCE hInst; + +extern "C" int __declspec(dllexport) Load(void) +{ + g_hPopupIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_POPUP)); + + + mir_getLP(&pluginInfo); + if ( + !mir_getXI(&xi) || + !(hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded)) || + !(hAccListChanged = HookEvent(ME_PROTO_ACCLISTCHANGED, AccListChanged)) || + !InitAvaUnit(TRUE) || + !InitMenus(TRUE) + ) + {Unload(); return 1;}; + + AddTipperItem(); + + return 0; +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/avatar.cpp b/protocols/GTalkExt/src/avatar.cpp new file mode 100644 index 0000000000..1e55937a44 --- /dev/null +++ b/protocols/GTalkExt/src/avatar.cpp @@ -0,0 +1,212 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "avatar.h" +#include "resources.h" +#include "options.h" + +static const LPSTR AVA_FILE_NAME_FORMAT = "%s\\%s\\AvatarCache\\Jabber\\" SHORT_PLUGIN_NAME ".pseudoava.png"; +static const LPTSTR AVA_RES_TYPE = _T("PNG"); +static const LPSTR SRMM_MODULE_NAME = "SRMM"; +static const LPSTR SRMM_AVATAR_SETTING_NAME = "Avatar"; + +static const int SET_AVATAR_INTERVAL = 2000; + +void ForceDir(LPSTR dir, int len) +{ + if (GetFileAttributesA(dir) != INVALID_FILE_ATTRIBUTES) return; + for (int i = len - 1; i >= 0; i--) + if ('\\' == dir[i]) { + dir[i] = 0; + __try { + ForceDir(dir, i); + } + __finally { + dir[i] = '\\'; + } + CreateDirectoryA(dir, NULL); + } +} + +void ForceFileDir(LPSTR file) +{ + for (int i = lstrlenA(file) - 1; i >= 0; i--) + if ('\\' == file[i]) { + file[i] = 0; + __try { + ForceDir(file, i); + } + __finally { + file[i] = '\\'; + } + break; + } +} + +LPSTR CreateAvaFile(HANDLE *hFile) +{ + char name[MAX_PATH + 2]; + char path[MAX_PATH + 2]; + char full[MAX_PATH + 2]; + + if (CallService(MS_DB_GETPROFILENAME, (WPARAM)sizeof(name), (LPARAM)&name)) + return NULL; + for (int i = lstrlenA(name); i >= 0; i--) + if ('.' == name[i]) { + name[i] = 0; + break; + } + + if (CallService(MS_DB_GETPROFILEPATH, (WPARAM)sizeof(path), (LPARAM)&path)) + return NULL; + sprintf(&full[0], AVA_FILE_NAME_FORMAT, path, name); + + ForceFileDir(&full[0]); + + HANDLE h = 0; + __try { + h = CreateFileA(&full[0], GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE == h) return NULL; + + if (hFile) *hFile = h; else CloseHandle(h); + h = 0; + return _strdup(&full[0]); + } + __finally { + CloseHandle(h); + } +} + +extern HINSTANCE hInst; + +BOOL SaveAvatar(HANDLE hFile) +{ + HRSRC hres = FindResource(hInst, MAKEINTRESOURCE(IDI_PSEUDOAVA), AVA_RES_TYPE); + if (!hres) return FALSE; + + HGLOBAL hglob = LoadResource(hInst, hres); + if (!hglob) return FALSE; + + PVOID p = LockResource(hglob); + if (!p) return FALSE; + + DWORD l = SizeofResource(hInst, hres); + if (!l) return FALSE; + + DWORD written; + if (!WriteFile(hFile, p, l, &written, NULL)) return FALSE; + return written == l; +} + +struct AVACHANGED { + HANDLE hTimer; + HANDLE hContact; +}; + +VOID CALLBACK CallSetAvatar(PVOID lpParameter, BOOLEAN TimerOrWaitFired) +{ + Thread_Push(0); + __try { + AVACHANGED *ach = (AVACHANGED*)lpParameter; + __try { + SetAvatar(ach->hContact); + DeleteTimerQueueTimer(NULL, ach->hTimer, NULL); + } + __finally { + free(ach); + } + } + __finally { + Thread_Pop(); + } +} + +int AvaChanged(WPARAM wParam, LPARAM lParam) +{ + if (!lParam && DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { + BOOL enqueued = FALSE; + AVACHANGED *ach = (AVACHANGED*)malloc(sizeof(AVACHANGED)); + __try { + ach->hContact = (HANDLE)wParam; + enqueued = CreateTimerQueueTimer(&ach->hTimer, NULL, CallSetAvatar, ach, SET_AVATAR_INTERVAL, 0, WT_EXECUTEONLYONCE); + } + __finally { + if (!enqueued) free(ach); + } + } + return 0; +} + +CRITICAL_SECTION g_csSetAvatar; +HANDLE hAvaChanged = 0; +BOOL initialized = FALSE; + +BOOL InitAvaUnit(BOOL init) +{ + if (init) { + hAvaChanged = HookEvent(ME_AV_AVATARCHANGED, AvaChanged); + InitializeCriticalSection(&g_csSetAvatar); + initialized = TRUE; + return hAvaChanged != 0; + } + else { + if (initialized) { + initialized = FALSE; + DeleteCriticalSection(&g_csSetAvatar); + } + if (hAvaChanged) { + UnhookEvent(hAvaChanged); + hAvaChanged = 0; + } + return TRUE; + } +} + +void SetAvatar(HANDLE hContact) +{ + EnterCriticalSection(&g_csSetAvatar); + __try { + avatarCacheEntry *ava = (avatarCacheEntry*)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + if (ava && GetFileAttributes(&ava->szFilename[0]) != INVALID_FILE_ATTRIBUTES) + return; + + HANDLE hFile; + LPSTR avaFile = CreateAvaFile(&hFile); + if (avaFile) + __try { + BOOL saved = SaveAvatar(hFile); + CloseHandle(hFile); hFile = 0; + if (saved){ + if (ava) CallService(MS_AV_SETAVATAR, (WPARAM)hContact, (LPARAM)""); + CallService(MS_AV_SETAVATAR, (WPARAM)hContact, (LPARAM)avaFile); + DBWriteContactSettingString(hContact, SRMM_MODULE_NAME, SRMM_AVATAR_SETTING_NAME, avaFile); + } + } + __finally { + free(avaFile); + CloseHandle(hFile); + } + } + __finally { + LeaveCriticalSection(&g_csSetAvatar); + } +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/avatar.h b/protocols/GTalkExt/src/avatar.h new file mode 100644 index 0000000000..f07631deff --- /dev/null +++ b/protocols/GTalkExt/src/avatar.h @@ -0,0 +1,25 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +void SetAvatar(HANDLE hContact); +BOOL InitAvaUnit(BOOL init); \ No newline at end of file diff --git a/protocols/GTalkExt/src/db.cpp b/protocols/GTalkExt/src/db.cpp new file mode 100644 index 0000000000..a1658dbdcf --- /dev/null +++ b/protocols/GTalkExt/src/db.cpp @@ -0,0 +1,100 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "StdAfx.h" +#include "options.h" + +char *WtoA(LPCTSTR W) +{ + char* result = (char*)malloc(lstrlen(W) + 1); + __try { + int i; + for (i = 0; W[i]; i++) { + result[i] = W[i]; + } + + result[i] = 0; + } + __except( + free(result), + EXCEPTION_CONTINUE_SEARCH + ) {} + return result; +} + +LPTSTR ReadJidSetting(LPCSTR name, LPCTSTR jid) +{ + char *ansiJid = WtoA(jid); + __try { + DBVARIANT dbv = {0}; + __try { + if (DBGetContactSettingTString(0, name, ansiJid, &dbv)) + { + LPTSTR result = (LPTSTR)malloc(2 * sizeof(TCHAR)); + result[0] = '0'; + result[1] = NULL; + return result; + } + + return _tcsdup(dbv.ptszVal); + } + __finally { + DBFreeVariant(&dbv); + } + } + __finally { + free(ansiJid); + } + + assert(false); + return NULL; // relax compiler +} + +void WriteJidSetting(LPCSTR name, LPCTSTR jid, LPCTSTR setting) +{ + char *ansiJid = WtoA(jid); + __try { + DBWriteContactSettingTString(0, name, ansiJid, setting); + } + __finally { + free(ansiJid); + } +} + +void RenewPseudocontactHandles() +{ + int count = 0; + PROTOACCOUNT **protos; + ProtoEnumAccounts(&count, &protos); + for (int i = 0; i < count; i++) { + DBDeleteContactSetting(0, protos[i]->szModuleName, PSEUDOCONTACT_LINK); + DBDeleteContactSetting(0, protos[i]->szModuleName, "GMailExtNotifyContact"); // remove this + } + + HANDLE hContact = db_find_first(); + while (hContact) { + if (DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { + LPCSTR proto = (LPCSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + DBWriteContactSettingDword(0, proto, PSEUDOCONTACT_LINK, (DWORD)hContact); + } + hContact = db_find_next(hContact); + }; +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/db.h b/protocols/GTalkExt/src/db.h new file mode 100644 index 0000000000..9db6cc94ce --- /dev/null +++ b/protocols/GTalkExt/src/db.h @@ -0,0 +1,31 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once +#include "resources.h" + +static const LPSTR LAST_MAIL_TIME_FROM_JID = SHORT_PLUGIN_NAME ".LastMailTimeFromJid"; +static const LPSTR LAST_THREAD_ID_FROM_JID = SHORT_PLUGIN_NAME ".LastThreadIdFromJid"; + +LPTSTR ReadJidSetting(LPCSTR name, LPCTSTR jid); +void WriteJidSetting(LPCSTR name, LPCTSTR jid, LPCTSTR setting); +char *WtoA(LPCTSTR W); +void RenewPseudocontactHandles(); diff --git a/protocols/GTalkExt/src/dllmain.cpp b/protocols/GTalkExt/src/dllmain.cpp new file mode 100644 index 0000000000..e1097a3ea6 --- /dev/null +++ b/protocols/GTalkExt/src/dllmain.cpp @@ -0,0 +1,62 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "notifications.h" +#include "options.h" +#include "popups.h" + +HINSTANCE hInst = 0; + +DWORD itlsSettings = TLS_OUT_OF_INDEXES; +DWORD itlsRecursion = TLS_OUT_OF_INDEXES; +DWORD itlsPopupHook = TLS_OUT_OF_INDEXES; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + if (((itlsSettings = TlsAlloc()) == TLS_OUT_OF_INDEXES) || + ((itlsRecursion = TlsAlloc()) == TLS_OUT_OF_INDEXES) || + ((itlsPopupHook = TlsAlloc()) == TLS_OUT_OF_INDEXES)) + return FALSE; + break; + + case DLL_THREAD_ATTACH: + TlsSetValue(itlsPopupHook, + (PVOID)SetWindowsHookEx(WH_CALLWNDPROCRET, PopupHookProc, NULL, GetCurrentThreadId())); + break; + + case DLL_THREAD_DETACH: + UnhookWindowsHookEx((HHOOK)TlsGetValue(itlsPopupHook)); + break; + + case DLL_PROCESS_DETACH: + TlsFree(itlsSettings); + TlsFree(itlsRecursion); + TlsFree(itlsPopupHook); + break; + } + + return TRUE; +} diff --git a/protocols/GTalkExt/src/handlers.cpp b/protocols/GTalkExt/src/handlers.cpp new file mode 100644 index 0000000000..7bd814a802 --- /dev/null +++ b/protocols/GTalkExt/src/handlers.cpp @@ -0,0 +1,433 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "StdAfx.h" +#include "handlers.h" +#include "db.h" +#include "notifications.h" +#include "options.h" +#include "popups.h" + +static const LPCTSTR JABBER_IQID = _T("mir_"); +static const LPCTSTR JABBER_IQID_FORMAT = _T("mir_%d"); + +static const LPCTSTR NOTIFY_FEATURE_XMLNS = _T("google:mail:notify"); +static const LPCTSTR SETTING_FEATURE_XMLNS = _T("google:setting"); +static const LPCTSTR DISCOVERY_XMLNS = _T("http://jabber.org/protocol/disco#info"); + +static const LPCTSTR MESSAGE_URL_FORMAT_STANDARD = _T("%s/#inbox/%x%08x"); +static const LPCTSTR MESSAGE_URL_FORMAT_HTML = _T("%s/h/?v=c&th=%x%08x"); + +static const LPCTSTR ATTRNAME_TYPE = _T("type"); +static const LPCTSTR ATTRNAME_FROM = _T("from"); +static const LPCTSTR ATTRNAME_TO = _T("to"); +static const LPCTSTR ATTRNAME_URL = _T("url"); +static const LPCTSTR ATTRNAME_TID = _T("tid"); +static const LPCTSTR ATTRNAME_UNREAD = _T("unread"); +static const LPCTSTR ATTRNAME_XMLNS = _T("xmlns"); +static const LPCTSTR ATTRNAME_ID = _T("id"); +static const LPCTSTR ATTRNAME_TOTAL_MATCHED = _T("total-matched"); +static const LPCTSTR ATTRNAME_NAME = _T("name"); +static const LPCTSTR ATTRNAME_ADDRESS = _T("address"); +static const LPCTSTR ATTRNAME_RESULT_TIME = _T("result-time"); +static const LPCTSTR ATTRNAME_NEWER_THAN_TIME = _T("newer-than-time"); +static const LPCTSTR ATTRNAME_NEWER_THAN_TID = _T("newer-than-tid"); +static const LPCTSTR ATTRNAME_VALUE = _T("value"); +static const LPCTSTR ATTRNAME_VAR = _T("var"); + +static const LPCTSTR IQTYPE_RESULT = _T("result"); +static const LPCTSTR IQTYPE_SET = _T("set"); +static const LPCTSTR IQTYPE_GET = _T("get"); + +static const LPCTSTR NODENAME_MAILBOX = _T("mailbox"); +static const LPCTSTR NODENAME_QUERY = _T("query"); +static const LPCTSTR NODENAME_IQ = _T("iq"); +static const LPCTSTR NODENAME_USERSETTING = _T("usersetting"); +static const LPCTSTR NODENAME_MAILNOTIFICATIONS = _T("mailnotifications"); +static const LPCTSTR NODENAME_SUBJECT = _T("subject"); +static const LPCTSTR NODENAME_SNIPPET = _T("snippet"); +static const LPCTSTR NODENAME_SENDERS = _T("senders"); +static const LPCTSTR NODENAME_FEATURE = _T("feature"); +static const LPCTSTR NODENAME_NEW_MAIL = _T("new-mail"); + +static const LPCTSTR SETTING_TRUE = _T("true"); + +static const DWORD RESPONSE_TIMEOUT = 1000 * 60 * 60; +static const DWORD TIMER_INTERVAL = 1000 * 60 * 2; + +XML_API xi = {0}; + +#include + +void FormatMessageUrl(LPCTSTR format, LPTSTR buf, LPCTSTR mailbox, LPCTSTR tid) +{ + ULARGE_INTEGER iTid; iTid.QuadPart = _tstoi64(tid); + int l = lstrlen(buf); + wsprintf(buf, format, mailbox, iTid.HighPart, iTid.LowPart); + assert(l >= lstrlen(buf)); +} + +void MakeUrlHex(LPTSTR url, LPCTSTR tid) +{ + ULARGE_INTEGER iTid; iTid.QuadPart = _tstoi64(tid); + LPTSTR tidInUrl = _tcsstr(url, tid); + LPTSTR trail = tidInUrl + lstrlen(tid); + wsprintf(tidInUrl, _T("%x%08x"), iTid.HighPart, iTid.LowPart); + wmemmove(tidInUrl + lstrlen(tidInUrl), trail, lstrlen(trail) + 1); +} + +LPTSTR ExtractJid(LPCTSTR jidWithRes) +{ + int l; + for (l = 0; jidWithRes[l] && jidWithRes[l] != '/'; l++) {}; + assert('/' == jidWithRes[l]); + + LPTSTR result = (LPTSTR)malloc((l + 1) * sizeof(TCHAR)); + __try { + memcpy(result, jidWithRes, l * sizeof(TCHAR)); + result[l] = 0; + } + __except ( + free(result), + EXCEPTION_CONTINUE_SEARCH + ) {}; + + return result; +} + +BOOL TimerHandler(IJabberInterface *ji, HXML node, void *pUserData); + +BOOL InternalListHandler(IJabberInterface *ji, HXML node, LPCTSTR jid, LPCTSTR mailboxUrl) +{ + ULONGLONG maxTid = 0; + LPCTSTR sMaxTid = NULL; + int unreadCount = 0; + for (int i = 0; i < xi.getChildCount(node); i++) { + LPCTSTR sTid = xi.getAttrValue(xi.getChild(node, i), ATTRNAME_TID); + ULONGLONG tid = _tcstoui64(sTid, NULL, 10); + if (tid > maxTid) { + maxTid = tid; + sMaxTid = sTid; + } + + HXML senders = xi.getChildByPath(xi.getChild(node, i), NODENAME_SENDERS, FALSE); + for (int j = 0; j < xi.getChildCount(senders); j++) + if (xi.getAttrValue(xi.getChild(senders, j), ATTRNAME_UNREAD)) { + unreadCount++; + break; + } + } + + LPCSTR acc = GetJidAcc(jid); + if (!acc) return FALSE; + + if (!unreadCount) { + SetupPseudocontact(jid, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED), acc); + return TRUE; + } + + DWORD settings = ReadNotificationSettings(acc); + + if (unreadCount > 5) { + CloseNotifications(acc, mailboxUrl, jid, FALSE); + UnreadMailNotification(acc, jid, mailboxUrl, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED)); + } + else + for (int i = 0; i < xi.getChildCount(node); i++) { + MAIL_THREAD_NOTIFICATION mtn = {0}; + HXML thread = xi.getChild(node, i); + + mtn.subj = xi.getText(xi.getChildByPath(thread, NODENAME_SUBJECT, FALSE)); + mtn.snip = xi.getText(xi.getChildByPath(thread, NODENAME_SNIPPET, FALSE)); + + int threadUnreadCount = 0; + HXML senders = xi.getChildByPath(thread, NODENAME_SENDERS, FALSE); + for (int j = 0; threadUnreadCount < SENDER_COUNT && j < xi.getChildCount(senders); j++) { + HXML sender = xi.getChild(senders, j); + if (xi.getAttrValue(sender, ATTRNAME_UNREAD)) { + mtn.senders[threadUnreadCount].name = xi.getAttrValue(sender, ATTRNAME_NAME); + mtn.senders[threadUnreadCount].addr = xi.getAttrValue(sender, ATTRNAME_ADDRESS); + threadUnreadCount++; + } + } + + LPCTSTR url = xi.getAttrValue(thread, ATTRNAME_URL); + LPCTSTR tid = xi.getAttrValue(thread, ATTRNAME_TID); + + if (ReadCheckbox(0, IDC_STANDARDVIEW, settings)) + FormatMessageUrl(MESSAGE_URL_FORMAT_STANDARD, (LPTSTR)url, mailboxUrl, tid); + else + if (ReadCheckbox(0, IDC_HTMLVIEW, settings)) + FormatMessageUrl(MESSAGE_URL_FORMAT_HTML, (LPTSTR)url, mailboxUrl, tid); + else + MakeUrlHex((LPTSTR)url, tid); + + CloseNotifications(acc, url, jid, i); + UnreadThreadNotification(acc, jid, url, xi.getAttrValue(node, ATTRNAME_TOTAL_MATCHED), &mtn); + } + + LPCTSTR time = xi.getAttrValue(node, ATTRNAME_RESULT_TIME); + WriteJidSetting(LAST_MAIL_TIME_FROM_JID, jid, time); + WriteJidSetting(LAST_THREAD_ID_FROM_JID, jid, sMaxTid); + return TRUE; +} + +BOOL MailListHandler(IJabberInterface *ji, HXML node, void *pUserData) +{ + LPCTSTR jidWithRes = xi.getAttrValue(node, ATTRNAME_TO); + __try { + if (!node || lstrcmp(xi.getAttrValue(node, ATTRNAME_TYPE), IQTYPE_RESULT)) return TRUE; + + LPCTSTR jid = xi.getAttrValue(node, ATTRNAME_FROM); + assert(jid); + + node = xi.getChildByPath(node, NODENAME_MAILBOX, FALSE); + if (!node) return TRUE; // empty list + + LPCTSTR url = xi.getAttrValue(node, ATTRNAME_URL); + + return InternalListHandler(ji, node, jid, url); + } + __finally { + if (jidWithRes) + ji->Net()->AddTemporaryIqHandler(TimerHandler, JABBER_IQ_TYPE_RESULT, 0, + (PVOID)_tcsdup(jidWithRes), TIMER_INTERVAL); + // Never get a real result stanza. Results elapsed request after WAIT_TIMER_INTERVAL ms + } +} + +void RequestMail(LPCTSTR jidWithRes, IJabberInterface *ji) +{ + HXML child = NULL; + HXML node = xi.createNode(NODENAME_IQ, NULL, FALSE); + __try { + xi.addAttr(node, ATTRNAME_TYPE, IQTYPE_GET); + xi.addAttr(node, ATTRNAME_FROM, jidWithRes); + + UINT uID; + LPTSTR lastMailTime = NULL; + LPTSTR lastThreadId = NULL; + __try { + LPTSTR jid = ExtractJid(jidWithRes); + __try { + xi.addAttr(node, ATTRNAME_TO, jid); + lastMailTime = ReadJidSetting(LAST_MAIL_TIME_FROM_JID, jid); + lastThreadId = ReadJidSetting(LAST_THREAD_ID_FROM_JID, jid); + } + __finally { + free(jid); + } + + LPTSTR id = (LPTSTR)malloc((_tcslen(JABBER_IQID) + 10 + 1) * sizeof(id[0])); // max int fits 10 chars + __try { + wsprintf(id, JABBER_IQID_FORMAT, uID = ji->Net()->SerialNext()); + xi.addAttr(node, ATTRNAME_ID, id); + } + __finally { + free(id); + } + + child = xi.addChild(node, NODENAME_QUERY, NULL); + xi.addAttr(child, ATTRNAME_XMLNS, NOTIFY_FEATURE_XMLNS); + xi.addAttr(child, ATTRNAME_NEWER_THAN_TIME, lastMailTime); + xi.addAttr(child, ATTRNAME_NEWER_THAN_TID, lastThreadId); + } + __finally { + if (lastMailTime) free(lastMailTime); + if (lastThreadId) free(lastThreadId); + } + + IJabberNetInterface* piNet = ji->Net(); + if ( piNet ) + if (piNet->SendXmlNode(node)) + piNet->AddTemporaryIqHandler(MailListHandler, JABBER_IQ_TYPE_RESULT, (int)uID, NULL, RESPONSE_TIMEOUT); + } + __finally { + if (child) xi.destroyNode(child); + if (node) xi.destroyNode(node); + } +} + +BOOL TimerHandler(IJabberInterface *ji, HXML node, void *pUserData) +{ + __try { + assert(!node); // should not intercept real "mir_0" id + RequestMail((LPCTSTR)pUserData, ji); + return FALSE; + } + __finally { + free(pUserData); + } +} + +BOOL NewMailHandler(IJabberInterface *ji, HXML node, void *pUserData) +{ + HXML response = xi.createNode(NODENAME_IQ, NULL, FALSE); + __try { + xi.addAttr(response, ATTRNAME_TYPE, IQTYPE_RESULT); + + LPCTSTR attr = xi.getAttrValue(node, ATTRNAME_ID); + if (!attr) return FALSE; + xi.addAttr(response, ATTRNAME_ID, attr); + + attr = xi.getAttrValue(node, ATTRNAME_FROM); + if (attr) xi.addAttr(response, ATTRNAME_TO, attr); + + attr = xi.getAttrValue(node, ATTRNAME_TO); + if (!attr) return FALSE; + xi.addAttr(response, ATTRNAME_FROM, attr); + + int bytesSent = ji->Net()->SendXmlNode(response); + RequestMail(attr, ji); + return bytesSent > 0; + } + __finally { + xi.destroyNode(response); + } +} + +void SetNotificationSetting(LPCTSTR jidWithResource, IJabberInterface *ji) +{ + HXML child = NULL; + HXML node = xi.createNode(NODENAME_IQ, NULL, FALSE); + __try { + xi.addAttr(node, ATTRNAME_TYPE, IQTYPE_SET); + xi.addAttr(node, ATTRNAME_FROM, jidWithResource); + + LPTSTR jid = ExtractJid(jidWithResource); + __try { + xi.addAttr(node, ATTRNAME_TO, jid); + } + __finally { + free(jid); + } + + LPTSTR id = (LPTSTR)malloc((_tcslen(JABBER_IQID) + 10 + 1) * sizeof(id[0])); // max int fits 10 chars + __try { + wsprintf(id, JABBER_IQID_FORMAT, ji->Net()->SerialNext()); + xi.addAttr(node, ATTRNAME_ID, id); + } + __finally { + free(id); + } + + child = xi.addChild(node, NODENAME_USERSETTING, NULL); + xi.addAttr(child, ATTRNAME_XMLNS, SETTING_FEATURE_XMLNS); + + child = xi.addChild(child, NODENAME_MAILNOTIFICATIONS, NULL); + xi.addAttr(child, ATTRNAME_VALUE, SETTING_TRUE); + + ji->Net()->SendXmlNode(node); + } + __finally { + if (child) xi.destroyNode(child); + if (node) xi.destroyNode(node); + } +} + +BOOL DiscoverHandler(IJabberInterface *ji, HXML node, void *pUserData) +{ + if (!node) return FALSE; + + LPCTSTR jid = xi.getAttrValue(node, ATTRNAME_TO); + assert(jid); + node = xi.getChildByAttrValue(node, NODENAME_QUERY, ATTRNAME_XMLNS, DISCOVERY_XMLNS); + + HXML child = xi.getChildByAttrValue(node, NODENAME_FEATURE, ATTRNAME_VAR, SETTING_FEATURE_XMLNS); + if (child) SetNotificationSetting(jid, ji); + + child = xi.getChildByAttrValue(node, NODENAME_FEATURE, ATTRNAME_VAR, NOTIFY_FEATURE_XMLNS); + if (child) { + ji->Net()->AddIqHandler(NewMailHandler, JABBER_IQ_TYPE_SET, NOTIFY_FEATURE_XMLNS, NODENAME_NEW_MAIL); + RequestMail(jid, ji); + } + + return FALSE; +} + +extern DWORD itlsRecursion; + +BOOL SendHandler(IJabberInterface *ji, HXML node, void *pUserData) +{ + HXML queryNode = xi.getChildByAttrValue(node, NODENAME_QUERY, ATTRNAME_XMLNS, DISCOVERY_XMLNS); + if (!queryNode) return FALSE; + if (lstrcmp(xi.getName(node), NODENAME_IQ)) return FALSE; + if (lstrcmp(xi.getAttrValue(node, ATTRNAME_TYPE), IQTYPE_GET)) return FALSE; + + if (TlsGetValue(itlsRecursion)) return FALSE; + TlsSetValue(itlsRecursion, (PVOID)TRUE); + __try { + UINT id = ji->Net()->SerialNext(); + HXML newNode = xi.createNode(NODENAME_IQ, NULL, FALSE); + __try { + xi.addAttr(newNode, ATTRNAME_TYPE, IQTYPE_GET); + xi.addAttr(newNode, ATTRNAME_TO, xi.getAttrValue(node, ATTRNAME_TO)); + + LPTSTR idAttr = (LPTSTR)malloc(((int)_tcslen(JABBER_IQID) + 10) * sizeof(TCHAR)); + __try { + wsprintf(idAttr, JABBER_IQID_FORMAT, id); + xi.addAttr(newNode, ATTRNAME_ID, idAttr); + } + __finally { + free(idAttr); + } + + xi.addAttr(xi.addChild(newNode, NODENAME_QUERY, NULL), ATTRNAME_XMLNS, DISCOVERY_XMLNS); + ji->Net()->SendXmlNode(newNode); + } + __finally { + xi.destroyNode(newNode); + } + + ji->Net()->AddTemporaryIqHandler(DiscoverHandler, JABBER_IQ_TYPE_RESULT, id, NULL, RESPONSE_TIMEOUT); + return FALSE; + } + __finally { + TlsSetValue(itlsRecursion, (PVOID)FALSE); + } +} + +int AccListChanged(WPARAM wParam, LPARAM lParam) +{ + if (PRAC_ADDED == wParam) { + IJabberInterface *japi = getJabberApi(((PROTOACCOUNT*)lParam)->szModuleName); + if (japi) japi->Net()->AddSendHandler(SendHandler); + } + return 0; +} + +int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + RenewPseudocontactHandles(); + DetectPopupModule(); + + int count; + PROTOACCOUNT **protos; + ProtoEnumAccounts(&count, &protos); + for (int i = 0; i < count; i++) { + IJabberInterface *japi = getJabberApi(protos[i]->szModuleName); + if (japi) japi->Net()->AddSendHandler(SendHandler); + } + + HookOptionsInitialization(); + + return 0; +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/handlers.h b/protocols/GTalkExt/src/handlers.h new file mode 100644 index 0000000000..10ffa8cb81 --- /dev/null +++ b/protocols/GTalkExt/src/handlers.h @@ -0,0 +1,27 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +extern HANDLE hModulesLoaded; + +int ModulesLoaded(WPARAM wParam, LPARAM lParam); +int AccListChanged(WPARAM wParam, LPARAM lParam); \ No newline at end of file diff --git a/protocols/GTalkExt/src/inbox.cpp b/protocols/GTalkExt/src/inbox.cpp new file mode 100644 index 0000000000..53a4aa2fcb --- /dev/null +++ b/protocols/GTalkExt/src/inbox.cpp @@ -0,0 +1,402 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "inbox.h" +#include "notifications.h" +#include "db.h" +#include "options.h" + +static const LPTSTR COMMON_GMAIL_HOST1 = _T("gmail.com"); +static const LPTSTR COMMON_GMAIL_HOST2 = _T("googlemail.com"); + +static const LPSTR AUTH_REQUEST_URL = "https://www.google.com/accounts/ClientAuth"; +static const LPSTR AUTH_REQUEST_PARAMS = "Email=%s&Passwd=%s&" + "accountType=HOSTED_OR_GOOGLE&" + "skipvpage=true&" + "PersistentCookie=false"; + +static const LPSTR ISSUE_TOKEN_REQUEST_URL = "https://www.google.com/accounts/IssueAuthToken"; +static const LPSTR ISSUE_TOKEN_REQUEST_PARAMS = "SID=%s&LSID=%s&" + "Session=true&" + "skipvpage=true&" + "service=gaia"; + +static const LPSTR TOKEN_AUTH_URL = "https://www.google.com/accounts/TokenAuth?"\ + "auth=%s&" + "service=mail&" + "continue=%s&" + "source=googletalk"; + + +static const NETLIBHTTPHEADER HEADER_URL_ENCODED = {"Content-Type", "application/x-www-form-urlencoded"}; +static const int HTTP_OK = 200; + +static const LPSTR SID_KEY_NAME = "SID="; +static const LPSTR LSID_KEY_NAME = "LSID="; + +static const LPSTR LOGIN_PASS_SETTING_NAME = "LoginPassword"; + +static const LPTSTR INBOX_URL_FORMAT = _T("https://mail.google.com/%s%s/#inbox"); + +static const DWORD SIZE_OF_JABBER_OPTIONS = 243 * sizeof(DWORD); + +// 3 lines from netlib.h +#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID) +#define NLH_INVALID 0 +#define NLH_USER 'USER' + +char to_hex(char code) { + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; +} + +char *url_encode(char *str) { + char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; + while (*pstr) { + if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == ',' || *pstr == '~') + *pbuf++ = *pstr; + else if (*pstr == ' ') + *pbuf++ = '+'; + else + *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); + pstr++; + } + *pbuf = '\0'; + return buf; +} + +LPSTR HttpPost(HANDLE hUser, LPSTR reqUrl, LPSTR reqParams) +{ + NETLIBHTTPREQUEST nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_POST; + nlhr.flags = NLHRF_GENERATEHOST | NLHRF_SMARTAUTHHEADER | NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP | NLHRF_NODUMPHEADERS; + nlhr.szUrl = reqUrl; + nlhr.headers = (NETLIBHTTPHEADER*)&HEADER_URL_ENCODED; + nlhr.headersCount = 1; + nlhr.pData = reqParams; + nlhr.dataLength = lstrlenA(reqParams); + + NETLIBHTTPREQUEST *pResp = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hUser, (LPARAM)&nlhr); + if (!pResp) return NULL; + __try { + if (HTTP_OK == pResp->resultCode) + return _strdup(pResp->pData); + else + return NULL; + } + __finally { + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pResp); + } +} + +LPSTR MakeRequest(HANDLE hUser, LPSTR reqUrl, LPSTR reqParamsFormat, LPSTR p1, LPSTR p2) +{ + LPSTR encodedP1 = url_encode(p1); + __try { + LPSTR encodedP2 = url_encode(p2); + __try { + LPSTR reqParams = (LPSTR)malloc(lstrlenA(reqParamsFormat) + 1 + lstrlenA(encodedP1) + lstrlenA(encodedP2)); + __try { + sprintf(reqParams, reqParamsFormat, encodedP1, encodedP2); + return HttpPost(hUser, reqUrl, reqParams); + } + __finally { + free(reqParams); + } + } + __finally { + free(encodedP2); + } + } + __finally { + free(encodedP1); + } +} + +LPSTR FindSid(LPSTR resp, LPSTR *LSID) +{ + LPSTR SID = strstr(resp, SID_KEY_NAME); + *LSID = strstr(resp, LSID_KEY_NAME); + if (!SID || !*LSID) return NULL; + + if (SID - 1 == *LSID) SID = strstr(SID + 1, SID_KEY_NAME); + if (!SID) return NULL; + + SID += lstrlenA(SID_KEY_NAME); + LPSTR term = strstr(SID, "\n"); + if (term) term[0] = 0; + + *LSID += lstrlenA(LSID_KEY_NAME); + term = strstr(*LSID, "\n"); + if (term) term[0] = 0; + + return SID; +} + +void DoOpenUrl(LPSTR tokenResp, LPSTR url) +{ + LPSTR encodedUrl = url_encode(url); + __try { + LPSTR encodedToken = url_encode(tokenResp); + __try { + LPSTR composedUrl = (LPSTR)malloc(lstrlenA(TOKEN_AUTH_URL) + 1 + lstrlenA(encodedToken) + lstrlenA(encodedUrl)); + __try { + sprintf(composedUrl, TOKEN_AUTH_URL, encodedToken, encodedUrl); + ShellExecuteA(0, NULL, composedUrl, NULL, NULL, SW_SHOW); + } + __finally { + free(composedUrl); + } + } + __finally { + free(encodedToken); + } + } + __finally { + free(encodedUrl); + } +} + +BOOL AuthAndOpen(HANDLE hUser, LPSTR url, LPSTR mailbox, LPSTR pwd) +{ + LPSTR authResp = MakeRequest(hUser, AUTH_REQUEST_URL, AUTH_REQUEST_PARAMS, mailbox, pwd); + if (!authResp) return FALSE; + + __try { + LPSTR LSID; + LPSTR SID = FindSid(authResp, &LSID); + LPSTR tokenResp = MakeRequest(hUser, ISSUE_TOKEN_REQUEST_URL, ISSUE_TOKEN_REQUEST_PARAMS, SID, LSID); + if (!tokenResp) return FALSE; + + __try { + DoOpenUrl(tokenResp, url); + return TRUE; + } + __finally { + free(tokenResp); + } + } + __finally { + free(authResp); + } +} + +struct OPEN_URL_HEADER { + LPSTR url; + LPSTR mailbox; + LPSTR pwd; + LPCSTR acc; +}; + +HANDLE FindNetUserHandle(LPCSTR acc) +{ + IJabberInterface *ji = getJabberApi(acc); + if (!ji) return NULL; + + PBYTE m_psProto = *(PBYTE*)((PBYTE)ji + sizeof(*ji)); // see CJabberInterface in jabber_proto.h + + PHANDLE pResult = (PHANDLE)(m_psProto + // see CJabberProto in jabber_proto.h + sizeof(PVOID) + // skip vtable ptr + sizeof(PVOID) + // skip m_ThreadInfo + SIZE_OF_JABBER_OPTIONS); // skip m_options + + for (int i=0; i < 100; i++) { + __try { + if (GetNetlibHandleType(*pResult) == NLH_USER) + break; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + } + pResult++; + } + + assert(GetNetlibHandleType(*pResult) == NLH_USER); + return *pResult; +} + +unsigned __stdcall OpenUrlThread(OPEN_URL_HEADER* data) +{ + __try { + HANDLE hUser = FindNetUserHandle(data->acc); + if (!hUser || !AuthAndOpen(hUser, data->url, data->mailbox, data->pwd)) + ShellExecuteA(0, NULL, data->url, NULL, NULL, SW_SHOW); + } + __finally { + free(data); + } + return 0; +} + +void __forceinline DecryptString(LPSTR str, int len) +{ + for (--len; len >= 0; len--) + { + const char c = str[len] ^ 0xc3; + if (c) str[len] = c; + } +} + +int GetMailboxPwd(LPCSTR acc, LPCTSTR mailbox, LPSTR *pwd, int buffSize) +{ + char buff[256]; + + DBCONTACTGETSETTING cgs; + DBVARIANT dbv; + cgs.szModule = acc; + cgs.szSetting = LOGIN_PASS_SETTING_NAME; + cgs.pValue = &dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = &buff[0]; + dbv.cchVal = sizeof(buff); + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, 0, (LPARAM)&cgs)) + return 0; + + int result = dbv.cchVal; + + if (pwd) { + if (buffSize < result + 1) result = buffSize - 1; + memcpy(*pwd, &buff, result + 1); + DecryptString(*pwd, result); + } + + return result; +} + +BOOL OpenUrlWithAuth(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) +{ + int pwdLen = GetMailboxPwd(acc, mailbox, NULL, 0); + if (!pwdLen++) return FALSE; + + int urlLen = lstrlen(url) + 1; + int mailboxLen = lstrlen(mailbox) + 1; + + OPEN_URL_HEADER *data = (OPEN_URL_HEADER*)malloc(sizeof(OPEN_URL_HEADER) + urlLen + mailboxLen + pwdLen); + __try { + data->url = (LPSTR)data + sizeof(OPEN_URL_HEADER); + LPSTR ansi = WtoA(url); + __try { + memcpy(data->url, ansi, urlLen); + } + __finally { + free(ansi); + } + + data->mailbox = data->url + urlLen; + ansi = WtoA(mailbox); + __try { + memcpy(data->mailbox, ansi, mailboxLen); + } + __finally { + free(ansi); + } + + data->pwd = data->mailbox + mailboxLen; + if (!GetMailboxPwd(acc, mailbox, &data->pwd, pwdLen)) return FALSE; + + data->acc = acc; + + if (HANDLE h = mir_forkthreadex((pThreadFuncEx)OpenUrlThread, data, NULL)) { + CloseHandle(h); + data = NULL; + } + else return FALSE; + } + __finally { + free(data); + } + + return TRUE; +} + +unsigned __stdcall ShellExecuteThread(PVOID param) +{ + __try { + ShellExecute(0, NULL, (LPTSTR)param, NULL, NULL, SW_SHOW); + } + __finally { + free(param); + } + return 0; +} + +void StartShellExecuteThread(LPCTSTR url) +{ + LPTSTR urlCopy = _tcsdup(url); + __try { + if (HANDLE h = mir_forkthreadex(ShellExecuteThread, urlCopy, NULL)) { + CloseHandle(h); + urlCopy = NULL; + } + } + __finally { + free(urlCopy); + } +} + +void OpenUrl(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url) +{ + extern DWORD itlsSettings; + if (!ReadCheckbox(0, IDC_AUTHONMAILBOX, (DWORD)TlsGetValue(itlsSettings)) || + !OpenUrlWithAuth(acc, mailbox, url)) + StartShellExecuteThread(url); +} + +LPTSTR CraftInboxUrl(LPTSTR jid) +{ + LPTSTR host = _tcsstr(jid, _T("@")) + 1; + + LPTSTR result = (LPTSTR)malloc((lstrlen(INBOX_URL_FORMAT) + 1 + lstrlen(jid)) * sizeof(TCHAR)); + __try { + if (lstrcmpi(host, COMMON_GMAIL_HOST1) && lstrcmpi(host, COMMON_GMAIL_HOST2)) + wsprintf(result, INBOX_URL_FORMAT, _T("a/"), host); // hosted + else + wsprintf(result, INBOX_URL_FORMAT, NULL, _T("mail")); // common + } + __except ( + free(result), + EXCEPTION_CONTINUE_SEARCH + ) {} + + return result; +} + +void OpenContactInbox(HANDLE hContact) +{ + LPSTR acc = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (!acc) return; + + DBVARIANT dbv; + if (!DBGetContactSettingTString(0, acc, "jid", &dbv)) + __try { + LPTSTR url = CraftInboxUrl(dbv.ptszVal); + __try { + OpenUrl(acc, dbv.ptszVal, url); + } + __finally { + free(url); + } + } + __finally { + DBFreeVariant(&dbv); + } +} diff --git a/protocols/GTalkExt/src/inbox.h b/protocols/GTalkExt/src/inbox.h new file mode 100644 index 0000000000..0b00128ab9 --- /dev/null +++ b/protocols/GTalkExt/src/inbox.h @@ -0,0 +1,25 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +void OpenUrl(LPCSTR acc, LPCTSTR mailbox, LPCTSTR url); +void OpenContactInbox(HANDLE hContact); \ No newline at end of file diff --git a/protocols/GTalkExt/src/menu.cpp b/protocols/GTalkExt/src/menu.cpp new file mode 100644 index 0000000000..26c81a165f --- /dev/null +++ b/protocols/GTalkExt/src/menu.cpp @@ -0,0 +1,95 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "menu.h" +#include "resources.h" +#include "options.h" +#include "inbox.h" + +static const LPSTR MS_GTALKEXT_OPENMAILBOX = SHORT_PLUGIN_NAME "/OpenMailbox"; +static const LPTSTR _T(OPEN_MAILBOX_ITEM_CAPTION) = _T("Open mailbox"); + +HANDLE hOpenMailboxService = 0; +HANDLE hOpenMailboxMenuItem = 0; +HANDLE hOnPrebuildMenu = 0; + +INT_PTR OpenMailboxMenuHandler(WPARAM wParam, LPARAM lParam) +{ + if (DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) + OpenContactInbox((HANDLE)wParam); + return 0; +} + +int OnPrebuildMenu(WPARAM wParam, LPARAM lParam) +{ + CLISTMENUITEM cmi = {0}; + cmi.cbSize = sizeof(cmi); + cmi.flags = CMIM_FLAGS; + if (!DBGetContactSettingByte((HANDLE)wParam, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) + cmi.flags |= CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hOpenMailboxMenuItem, (LPARAM)&cmi); + return 0; +} + +BOOL InitMenus(BOOL init) +{ + if (init) { + hOpenMailboxService = (HANDLE)CreateServiceFunction(MS_GTALKEXT_OPENMAILBOX, OpenMailboxMenuHandler); + if (!hOpenMailboxService) { + InitMenus(FALSE); + return FALSE; + } + + extern HICON g_hPopupIcon; + + CLISTMENUITEM cmi = {0}; + cmi.cbSize = sizeof(cmi); + cmi.flags = CMIF_TCHAR; + cmi.hIcon = g_hPopupIcon; + cmi.ptszName = _T(OPEN_MAILBOX_ITEM_CAPTION); + cmi.pszService = MS_GTALKEXT_OPENMAILBOX; + hOpenMailboxMenuItem = Menu_AddContactMenuItem(&cmi); + + if (!hOpenMailboxMenuItem) { + InitMenus(FALSE); + return FALSE; + } + + hOnPrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildMenu); + if (!hOnPrebuildMenu) { + InitMenus(FALSE); + return FALSE; + } + } + else { + if (hOnPrebuildMenu) { + UnhookEvent(hOnPrebuildMenu); + hOnPrebuildMenu = 0; + } + if (hOpenMailboxService) { + DestroyServiceFunction(hOpenMailboxService); + hOpenMailboxService = 0; + } + } + + return TRUE; +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/menu.h b/protocols/GTalkExt/src/menu.h new file mode 100644 index 0000000000..c06457672a --- /dev/null +++ b/protocols/GTalkExt/src/menu.h @@ -0,0 +1,24 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +BOOL InitMenus(BOOL init); \ No newline at end of file diff --git a/protocols/GTalkExt/src/notifications.cpp b/protocols/GTalkExt/src/notifications.cpp new file mode 100644 index 0000000000..9a1819a7f1 --- /dev/null +++ b/protocols/GTalkExt/src/notifications.cpp @@ -0,0 +1,414 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "StdAfx.h" +#include "notifications.h" +#include "db.h" +#include "options.h" +#include "avatar.h" +#include "inbox.h" + +static const LPTSTR TEMP_WINDOW_CLASS_NAME = _T("AntiShittyFullscreenDetectionWindowClass"); +static const LPTSTR _T(NUMBER_EMAILS_MESSAGE) = _T("You've received an e-mail\n%s unread threads"); + +static const LPTSTR PLUGIN_DATA_PROP_NAME = _T("{DB5CE833-C3AC-4851-831C-DDEBD9FA0508}"); +static const LPTSTR EVT_DELETED_HOOK_PROP_NAME = _T("{87CBD2BC-8806-413C-8FD5-1D61ABCA4AF8}"); + +#define EVENT_DELETED_MSG RegisterWindowMessage(_T("{B9B00536-86A0-4BCE-B2FE-4ABD409C22AE}")) +#define MESSAGE_CLOSEPOPUP RegisterWindowMessage(_T("{7A60EA87-3E77-41DF-8A69-59B147F0C9C6}")) + +static const LPSTR CLIST_MODULE_NAME = "CList"; +static const LPSTR CONTACT_DISPLAY_NAME_SETTING = "MyHandle"; +static const LPSTR STATUS_MSG_SETTING = "StatusMsg"; +static const LPSTR UNREAD_THREADS_SETTING = "UnreadThreads"; + +struct POPUP_DATA_HEADER { + BOOL MarkRead; + HANDLE hDbEvent; + HANDLE hContact; + LPTSTR jid; + LPTSTR url; +}; + +extern DWORD itlsSettings; +BOOL isOriginalPopups = FALSE; + +LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_NCCREATE: + return 1; + + case WM_GETMINMAXINFO: + PMINMAXINFO info = (PMINMAXINFO)lParam; + info->ptMaxPosition.x = -100; + info->ptMaxPosition.y = -100; + info->ptMaxSize.x = 10; + info->ptMaxSize.y = 10; + info->ptMaxTrackSize.x = 10; + info->ptMaxTrackSize.y = 10; + info->ptMinTrackSize.x = 10; + info->ptMinTrackSize.y = 10; + return 0; + } + return DefWindowProc(wnd, msg, wParam, lParam); +} + +LPCSTR GetJidAcc(LPCTSTR jid) +{ + int count = 0; + PROTOACCOUNT **protos; + ProtoEnumAccounts(&count, &protos); + + DBVARIANT dbv; + for (int i = 0; i < count; i++) + if (getJabberApi(protos[i]->szModuleName)) + if (!DBGetContactSettingTString(0, protos[i]->szModuleName, "jid", &dbv)) + __try { + if (!lstrcmpi(jid, dbv.ptszVal)) return protos[i]->szModuleName; + } + __finally { + DBFreeVariant(&dbv); + } + + return NULL; +} + +void MarkEventRead(HANDLE hCnt, HANDLE hEvt) +{ + DWORD settings = (DWORD)TlsGetValue(itlsSettings); + if (ReadCheckbox(0, IDC_POPUPSENABLED, settings) && + ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, settings) && + ReadCheckbox(0, IDC_MARKEVENTREAD, settings) && + (CallService(MS_DB_EVENT_MARKREAD, (WPARAM)hCnt, (LPARAM)hEvt) != (INT_PTR)-1)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hCnt, (LPARAM)hEvt); + +} + +int OnEventDeleted(WPARAM hContact, LPARAM hDbEvent, LPARAM wnd) +{ + if (DBGetContactSettingByte((HANDLE)hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { + CallService(MS_CLIST_REMOVEEVENT, hContact, hDbEvent); + PostMessage((HWND)wnd, EVENT_DELETED_MSG, hContact, hDbEvent); + } + + return 0; +} + +LRESULT CALLBACK PopupProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (EVENT_DELETED_MSG == msg) { + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); + if ((HANDLE)lParam == ppdh->hDbEvent) ppdh->hDbEvent = NULL; + return 0; + } + else + if (MESSAGE_CLOSEPOPUP == msg) { + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); + ppdh->MarkRead = TRUE; + PUDeletePopUp(wnd); + } + + switch (msg) { + case UM_INITPOPUP: { + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); + SetProp(wnd, PLUGIN_DATA_PROP_NAME, (HANDLE)ppdh); + SetProp(wnd, EVT_DELETED_HOOK_PROP_NAME, + HookEventParam(ME_DB_EVENT_DELETED, OnEventDeleted, (LPARAM)wnd)); + return 0; + } + + case UM_FREEPLUGINDATA: { + HANDLE hHook = GetProp(wnd, EVT_DELETED_HOOK_PROP_NAME); + RemoveProp(wnd, EVT_DELETED_HOOK_PROP_NAME); + UnhookEvent(hHook); + + LPCSTR acc = NULL; + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); + __try { + if (ppdh->MarkRead && ppdh->hDbEvent && (acc = GetJidAcc(ppdh->jid))) { + ReadNotificationSettings(acc); + MarkEventRead(ppdh->hContact, ppdh->hDbEvent); + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)ppdh->hContact, (LPARAM)ppdh->hDbEvent); + } + + } + __finally { + RemoveProp(wnd, PLUGIN_DATA_PROP_NAME); + free(ppdh); + } + + return 0; + } + + case WM_LBUTTONUP: { + LPCSTR acc = NULL; + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)PUGetPluginData(wnd); + __try { + if (!(acc = GetJidAcc(ppdh->jid))) return 0; + + ReadNotificationSettings(acc); + OpenUrl(acc, ppdh->jid, ppdh->url); + } + __finally { + CloseNotifications(acc, ppdh->url, ppdh->jid, TRUE); + } + return 0; + } + + case WM_RBUTTONUP: + SendMessage(wnd, MESSAGE_CLOSEPOPUP, 0, 0); + return 0; + } + return DefWindowProc(wnd, msg, wParam, lParam); +} + +HWND DoAddPopup(POPUPDATAT *data) +{ + WNDCLASS cls = {0}; + cls.lpfnWndProc = WndProc; + cls.lpszClassName = TEMP_WINDOW_CLASS_NAME; + + HWND result = 0; + HWND handle = 0; + __try { + if (ReadCheckbox(0, IDC_POPUPSINFULLSCREEN, (DWORD)TlsGetValue(itlsSettings))) { + RegisterClass(&cls); + handle = CreateWindowEx(WS_EX_TOOLWINDOW, TEMP_WINDOW_CLASS_NAME, NULL, WS_OVERLAPPED | WS_VISIBLE, + -100, -100, 10, 10, NULL, NULL, NULL, NULL); + if (handle) { + ShowWindow(handle, SW_MINIMIZE); + ShowWindow(handle, SW_RESTORE); + } + } + result = (HWND)CallService(MS_POPUP_ADDPOPUPT, (WPARAM) data, APF_RETURN_HWND); + } + __finally { + if (handle) DestroyWindow(handle); + } + + return result; +} + +void FormatPseudocontactDisplayName(LPTSTR buff, LPCTSTR jid, LPCTSTR unreadCount) +{ + if (lstrcmp(unreadCount, _T("0"))) + wsprintf(buff, _T("%s [%s]"), jid, unreadCount); + else + wsprintf(buff, _T("%s"), jid); +} + +HANDLE SetupPseudocontact(LPCTSTR jid, LPCTSTR unreadCount, LPCSTR acc, LPCTSTR displayName) +{ + HANDLE result = (HANDLE)DBGetContactSettingDword(0, acc, PSEUDOCONTACT_LINK, 0); + if (!result || !DBGetContactSettingByte(result, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { + result = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); + DBWriteContactSettingDword(0, acc, PSEUDOCONTACT_LINK, (DWORD)result); + DBWriteContactSettingByte(result, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 1); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)result, (LPARAM)acc); + } + + SetAvatar(result); + + BOOL allocateName = !displayName; + __try { + if (allocateName) { + displayName = (LPCTSTR)malloc((lstrlen(jid) + lstrlen(unreadCount) + 3 + 1) * sizeof(TCHAR)); + FormatPseudocontactDisplayName((LPTSTR)displayName, jid, unreadCount); + } + + DBWriteContactSettingTString(result, CLIST_MODULE_NAME, CONTACT_DISPLAY_NAME_SETTING, displayName); + } + __finally { + if (allocateName) free((PVOID)displayName); + } + + DBWriteContactSettingTString(result, CLIST_MODULE_NAME, STATUS_MSG_SETTING, TranslateTS(MAIL_NOTIFICATIONS)); + DBWriteContactSettingTString(result, SHORT_PLUGIN_NAME, UNREAD_THREADS_SETTING, unreadCount); + + return result; +} + +HANDLE AddCListNotification(HANDLE hContact, LPCSTR acc, POPUPDATAT *data, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) +{ + int lurl = (lstrlen(url) + 1) * sizeof(WCHAR); + LPSTR utf8 = (LPSTR)malloc(sizeof(data->lptzText) + sizeof(WCHAR) * 2 + lurl); + __try { + DBEVENTINFO dbei = {0}; + + dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, &data->lptzText[0], -1, utf8, sizeof(data->lptzText), NULL, NULL) - 1; + + if (utf8[dbei.cbBlob - 1] != 10) { + utf8[dbei.cbBlob++] = 13; + utf8[dbei.cbBlob++] = 10; + } + + dbei.cbBlob += WideCharToMultiByte(CP_UTF8, 0, url, -1, utf8 + dbei.cbBlob, lurl, NULL, NULL); + + dbei.pBlob = (PBYTE)utf8; + dbei.cbSize = sizeof(dbei); + dbei.szModule = (LPSTR)acc; + dbei.timestamp = time(NULL); + dbei.flags = DBEF_UTF; + dbei.eventType = EVENTTYPE_MESSAGE; + return (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + } + __finally { + free(utf8); + } +} + +BOOL UsePopups() +{ + return ServiceExists(MS_POPUP_QUERY) && + CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0) && + ReadCheckbox(0, IDC_POPUPSENABLED, (DWORD)TlsGetValue(itlsSettings)); +} + +void ShowNotification(LPCSTR acc, POPUPDATAT *data, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) +{ + HANDLE hCnt = SetupPseudocontact(jid, unreadCount, acc, &data->lptzContactName[0]); + HANDLE hEvt = ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, (DWORD)TlsGetValue(itlsSettings)) + ? AddCListNotification(hCnt, acc, data, jid, url, unreadCount) : NULL; + + if (!UsePopups()) return; + + extern HICON g_hPopupIcon; + data->lchIcon = g_hPopupIcon; + data->iSeconds = (int)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, 0); + data->colorBack = (COLORREF)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, 0); + data->colorText = (COLORREF)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, 0); + if (data->colorBack == data->colorText) { + data->colorBack = 0; + data->colorText = 0; + } + + data->PluginWindowProc = PopupProc; + int lurl = (lstrlen(url) + 1) * sizeof(TCHAR); + int ljid = (lstrlen(jid) + 1) * sizeof(TCHAR); + data->PluginData = malloc(sizeof(POPUP_DATA_HEADER) + lurl + ljid); + __try { + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)data->PluginData; + + ppdh->MarkRead = FALSE; + ppdh->hContact = hCnt; + ppdh->hDbEvent = hEvt; + + ppdh->jid = (LPTSTR)((PBYTE)ppdh + sizeof(*ppdh)); + memcpy(ppdh->jid, jid, ljid); + + ppdh->url = (LPTSTR)((PBYTE)ppdh->jid + ljid); + memcpy(ppdh->url, url, lurl); + + HWND code = DoAddPopup(data); + if ((code == (HWND)-1) || (isOriginalPopups && !code)) + return; + data->PluginData = NULL; // freed in popup wndproc + } + __finally { + free(data->PluginData); + } +} + +void UnreadMailNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount) +{ + POPUPDATAT data = {0}; + + FormatPseudocontactDisplayName(&data.lptzContactName[0], jid, unreadCount); + wsprintf(&data.lptzText[0], TranslateT(NUMBER_EMAILS_MESSAGE), unreadCount); + + ShowNotification(acc, &data, jid, url, unreadCount); +} + +void UnreadThreadNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount, const MAIL_THREAD_NOTIFICATION *mtn) +{ + POPUPDATAT data = {0}; + + FormatPseudocontactDisplayName(&data.lptzContactName[0], jid, unreadCount); + LPTSTR senders = (LPTSTR)malloc(SENDER_COUNT * 100 * sizeof(TCHAR)); + LPTSTR currSender = senders; + __try { + for (int i = 0; i < SENDER_COUNT && mtn->senders[i].addr; i++) { + wsprintf(currSender, _T(" %s <%s>\n"), mtn->senders[i].name, mtn->senders[i].addr); + currSender += lstrlen(currSender); + } + + if (ReadCheckbox(0, IDC_ADDSNIP, (DWORD)TlsGetValue(itlsSettings))) + wsprintf(&data.lptzText[0], TranslateTS(FULL_NOTIFICATION_FORMAT), mtn->subj, senders, mtn->snip); + else + wsprintf(&data.lptzText[0], TranslateTS(SHORT_NOTIFICATION_FORMAT), mtn->subj, senders); + } + __finally { + free(senders); + } + + ShowNotification(acc, &data, jid, url, unreadCount); +} + +void ClearNotificationContactHistory(LPCSTR acc) +{ + HANDLE hEvent = 0; + HANDLE hContact = (HANDLE)DBGetContactSettingDword(0, acc, PSEUDOCONTACT_LINK, 0); + if (hContact && DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) + while ((hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0)) && + !CallService(MS_DB_EVENT_DELETE, (WPARAM)hContact, (LPARAM)hEvent)) {}; +} + +DWORD ReadNotificationSettings(LPCSTR acc) +{ + DWORD result = ReadCheckboxes(0, acc); + TlsSetValue(itlsSettings, (PVOID)result); + return result; +} + +struct POPUP_IDENT_STRINGS { + LPCTSTR url; + LPCTSTR jid; +}; + +BOOL CALLBACK ClosePopupFunc(__in HWND hwnd, __in LPARAM lParam) +{ + DWORD pid = 0; + GetWindowThreadProcessId(hwnd, &pid); + if (pid != GetCurrentProcessId()) return TRUE; + + POPUP_IDENT_STRINGS *ppis = (POPUP_IDENT_STRINGS*)lParam; + POPUP_DATA_HEADER *ppdh = (POPUP_DATA_HEADER*)GetProp(hwnd, PLUGIN_DATA_PROP_NAME); + if (!ppdh) return TRUE; + + if (!lstrcmpi(ppis->url, ppdh->url) && !lstrcmpi(ppis->jid, ppdh->jid)) + SendMessage(hwnd, MESSAGE_CLOSEPOPUP, 0, 0); + + return TRUE; +} + +void CloseNotifications(LPCSTR acc, LPCTSTR url, LPCTSTR jid, BOOL PopupsOnly) +{ + DWORD settings = (DWORD)TlsGetValue(itlsSettings); + if (acc && + !PopupsOnly && + ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, settings) && + ReadCheckbox(0, IDC_CLEARPSEUDOCONTACTLOG, settings)) + ClearNotificationContactHistory(acc); + + POPUP_IDENT_STRINGS pis = {url, jid}; + EnumWindows(ClosePopupFunc, (LPARAM)&pis); +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/notifications.h b/protocols/GTalkExt/src/notifications.h new file mode 100644 index 0000000000..94d6e6353f --- /dev/null +++ b/protocols/GTalkExt/src/notifications.h @@ -0,0 +1,42 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +static const int SENDER_COUNT = 10; + +struct SENDER { + LPCTSTR name; + LPCTSTR addr; +}; + +struct MAIL_THREAD_NOTIFICATION { + LPCTSTR subj; + LPCTSTR snip; + SENDER senders[SENDER_COUNT]; +}; + +void UnreadMailNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount); +void UnreadThreadNotification(LPCSTR acc, LPCTSTR jid, LPCTSTR url, LPCTSTR unreadCount, const MAIL_THREAD_NOTIFICATION *mtn); +void CloseNotifications(LPCSTR acc, LPCTSTR url, LPCTSTR jid, BOOL PopupsOnly); +DWORD ReadNotificationSettings(LPCSTR acc); +HANDLE SetupPseudocontact(LPCTSTR jid, LPCTSTR unreadCount, LPCSTR acc, LPCTSTR displayName = NULL); +LPCSTR GetJidAcc(LPCTSTR jid); \ No newline at end of file diff --git a/protocols/GTalkExt/src/options.cpp b/protocols/GTalkExt/src/options.cpp new file mode 100644 index 0000000000..e64e23679c --- /dev/null +++ b/protocols/GTalkExt/src/options.cpp @@ -0,0 +1,297 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "options.h" + +static const LPTSTR ACCOUNT_PROP_NAME = _T("{BF447EBA-27AE-4DB7-893C-FC42A3F74D75}"); +static const LPTSTR DIALOG_INITIALIZED_PROP_NAME = _T("{5EE59FE5-679A-4A29-B0A1-03092E7AC20E}"); + +static const LPTSTR POPUPS_OPTIONS_GROUP = _T("Popups"); +static const LPTSTR NETWORK_OPTIONS_GROUP = _T("Network"); + +static const LPSTR NOTIFY_SETTINGS_FROM_MOD_NAME = SHORT_PLUGIN_NAME ".NotifySettingsFromModName"; + +static const LPTSTR TEST_LETTER_SUBJECT = _T("Why C sucks"); +static const LPTSTR TEST_LETTER_INBOX = _T("brickstrace@gmail.com [1]"); +static const LPTSTR TEST_LETTER_SENDER = _T(" bems \n"); +static const LPTSTR TEST_LETTER_SNIP = + _T("* Primitive type system\n") + _T("* No overloading\n") + _T("* Limited possibility of data abstraction, polymorphism, subtyping and code reuse\n") + _T("* No metaprogramming except preprocessor macros\n") + _T("* No exceptions"); + +HANDLE hOptionsHook = 0; +extern HINSTANCE hInst; + +void CheckControlsEnabled(HWND wnd) +{ + BOOL PopupsEnabled = (SendMessage(GetDlgItem(wnd, IDC_POPUPSENABLED), BM_GETSTATE, 0, 0) & BST_CHECKED) == BST_CHECKED; + EnableWindow(GetDlgItem(wnd, IDC_POPUPSINFULLSCREEN), PopupsEnabled); + EnableWindow(GetDlgItem(wnd, IDC_POPUPSINFULLSCREENLABEL), PopupsEnabled); + + BOOL CListEnabled = (SendMessage(GetDlgItem(wnd, IDC_PSEUDOCONTACTENABLED), BM_GETSTATE, 0, 0) & BST_CHECKED) == BST_CHECKED; + EnableWindow(GetDlgItem(wnd, IDC_CLEARPSEUDOCONTACTLOG), CListEnabled); + EnableWindow(GetDlgItem(wnd, IDC_SUPRESSFOREIGN), CListEnabled); + + EnableWindow(GetDlgItem(wnd, IDC_MARKEVENTREAD), PopupsEnabled && CListEnabled); + EnableWindow(GetDlgItem(wnd, IDC_ADDSNIP), PopupsEnabled || CListEnabled); + + EnableWindow(GetDlgItem(wnd, IDC_MAILBOXVIEWLABEL), PopupsEnabled || CListEnabled); + EnableWindow(GetDlgItem(wnd, IDC_UNKNOWNVIEW), PopupsEnabled || CListEnabled); + EnableWindow(GetDlgItem(wnd, IDC_STANDARDVIEW), PopupsEnabled || CListEnabled); + EnableWindow(GetDlgItem(wnd, IDC_HTMLVIEW), PopupsEnabled || CListEnabled); +} + +BOOL ReadCheckbox(HWND wnd, int id, DWORD controls) +{ + BOOL result = ((controls >> (id - IDC_BASE)) & 1); + if (id != IDC_STANDARDVIEW && id != IDC_HTMLVIEW) result = !result; + if (wnd) Button_SetCheck(GetDlgItem(wnd, id), result); + return result; +} + +DWORD ReadCheckboxes(HWND wnd, LPCSTR mod) +{ + DWORD controls = DBGetContactSettingDword(0, NOTIFY_SETTINGS_FROM_MOD_NAME, mod, 0); + ReadCheckbox(wnd, IDC_POPUPSENABLED, controls); + ReadCheckbox(wnd, IDC_PSEUDOCONTACTENABLED, controls); + ReadCheckbox(wnd, IDC_CLEARPSEUDOCONTACTLOG, controls); + ReadCheckbox(wnd, IDC_POPUPSINFULLSCREEN, controls); + ReadCheckbox(wnd, IDC_SUPRESSFOREIGN, controls); + ReadCheckbox(wnd, IDC_MARKEVENTREAD, controls); + ReadCheckbox(wnd, IDC_AUTHONMAILBOX, controls); + ReadCheckbox(wnd, IDC_ADDSNIP, controls); + ReadCheckbox(wnd, IDC_UNKNOWNVIEW, controls); + ReadCheckbox(wnd, IDC_STANDARDVIEW, controls); + ReadCheckbox(wnd, IDC_HTMLVIEW, controls); + return controls; +} + +DWORD GetCheckboxSaveValue(HWND wnd, int id) +{ + BOOL val = Button_GetCheck(GetDlgItem(wnd, id)); + if (id != IDC_STANDARDVIEW && id != IDC_HTMLVIEW) val = !val; + return val ? (1 << (id - IDC_BASE)) : 0; +} + +void SaveControls(HWND wnd, LPCSTR mod) +{ + DWORD controls = GetCheckboxSaveValue(wnd, IDC_CLEARPSEUDOCONTACTLOG) | + GetCheckboxSaveValue(wnd, IDC_POPUPSINFULLSCREEN) | + GetCheckboxSaveValue(wnd, IDC_POPUPSENABLED) | + GetCheckboxSaveValue(wnd, IDC_PSEUDOCONTACTENABLED) | + GetCheckboxSaveValue(wnd, IDC_SUPRESSFOREIGN) | + GetCheckboxSaveValue(wnd, IDC_MARKEVENTREAD) | + GetCheckboxSaveValue(wnd, IDC_AUTHONMAILBOX) | + GetCheckboxSaveValue(wnd, IDC_ADDSNIP) | + GetCheckboxSaveValue(wnd, IDC_UNKNOWNVIEW) | + GetCheckboxSaveValue(wnd, IDC_STANDARDVIEW) | + GetCheckboxSaveValue(wnd, IDC_HTMLVIEW); + + DBWriteContactSettingDword(0, NOTIFY_SETTINGS_FROM_MOD_NAME, mod, controls); +} + +INT_PTR CALLBACK AccOptionsDlgProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + SetProp(wnd, ACCOUNT_PROP_NAME, (HANDLE)lParam); + TranslateDialogDefault(wnd); + ReadCheckboxes(wnd, (LPCSTR)lParam); + CheckControlsEnabled(wnd); + break; + + case WM_CTLCOLORSTATIC: + if (GetDlgItem(wnd, IDC_WARNBAR) == (HWND)lParam) + return (INT_PTR)CreateSolidBrush(0x55AAFF); // orange + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_POPUPSENABLED: + case IDC_PSEUDOCONTACTENABLED: + if (HIWORD(wParam) == BN_CLICKED) CheckControlsEnabled(wnd); + // no break + + case IDC_CLEARPSEUDOCONTACTLOG: + case IDC_POPUPSINFULLSCREEN: + case IDC_SUPRESSFOREIGN: + case IDC_MARKEVENTREAD: + case IDC_AUTHONMAILBOX: + case IDC_ADDSNIP: + case IDC_UNKNOWNVIEW: + case IDC_STANDARDVIEW: + case IDC_HTMLVIEW: + if (HIWORD(wParam) == BN_CLICKED) PropSheet_Changed(GetParent(wnd), wnd); + } + break; + + case WM_NOTIFY: + if (!((LPNMHDR)lParam)->idFrom && ((LPNMHDR)lParam)->code == PSN_APPLY) + SaveControls(wnd, (LPCSTR)GetProp(wnd, ACCOUNT_PROP_NAME)); + break; + } + return 0; +} + +void ShowTestPopup(HWND wnd) +{ + POPUPDATAT data = {0}; + wsprintf(&data.lptzContactName[0], TEST_LETTER_INBOX); + wsprintf(&data.lptzText[0], TranslateTS(FULL_NOTIFICATION_FORMAT), + TEST_LETTER_SUBJECT, TEST_LETTER_SENDER, TEST_LETTER_SNIP); + + int len = SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXTLENGTH, 0, 0) + 1; + LPTSTR timeout = (LPTSTR)malloc(len * sizeof(TCHAR)); + __try { + SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXT, len, (LPARAM)timeout); + data.iSeconds = _ttoi(timeout); + } + __finally { + free(timeout); + } + + extern HICON g_hPopupIcon; + data.lchIcon = g_hPopupIcon; + data.colorBack = (COLORREF)SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_GETCOLOUR, 0, 0); + data.colorText = (COLORREF)SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_GETCOLOUR, 0, 0); + if (data.colorBack == data.colorText) { + data.colorBack = 0; + data.colorText = 0; + } + CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&data, 0); +} + +INT_PTR CALLBACK PopupsOptionsDlgProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(wnd); + SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_SETCOLOUR, 0, + (LPARAM)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, 0)); + SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_SETCOLOUR, 0, + (LPARAM)DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, 0)); + + {LPTSTR timeout = (LPTSTR)malloc(11 * sizeof(TCHAR)); + __try { + wsprintf(timeout, _T("%d"), DBGetContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, 0)); + SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_SETTEXT, 0, (LPARAM)timeout); + } + __finally { + free(timeout); + }} + + SetProp(wnd, DIALOG_INITIALIZED_PROP_NAME, (HANDLE)TRUE); + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_TESTBUTTON && HIWORD(wParam) == BN_CLICKED) + ShowTestPopup(wnd); + + if (GetProp(wnd, DIALOG_INITIALIZED_PROP_NAME)) + switch (LOWORD(wParam)) { + case IDC_BACKCOLORPICKER: + case IDC_TEXTCOLORPICKER: + if (HIWORD(wParam) == CPN_COLOURCHANGED) PropSheet_Changed(GetParent(wnd), wnd); + break; + + case IDC_TIMEOUTEDIT: + if (HIWORD(wParam) == EN_CHANGE) PropSheet_Changed(GetParent(wnd), wnd); + } + break; + + case WM_NOTIFY: + if (!((LPNMHDR)lParam)->idFrom && ((LPNMHDR)lParam)->code == PSN_APPLY) + DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, BACK_COLOR_SETTING, + (DWORD)SendMessage(GetDlgItem(wnd, IDC_BACKCOLORPICKER), CPM_GETCOLOUR, 0, 0)); + DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, TEXT_COLOR_SETTING, + (DWORD)SendMessage(GetDlgItem(wnd, IDC_TEXTCOLORPICKER), CPM_GETCOLOUR, 0, 0)); + + int len = SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXTLENGTH, 0, 0) + 1; + LPTSTR timeout = (LPTSTR)malloc(len * sizeof(TCHAR)); + __try { + SendMessage(GetDlgItem(wnd, IDC_TIMEOUTEDIT), WM_GETTEXT, len, (LPARAM)timeout); + DBWriteContactSettingDword(0, SHORT_PLUGIN_NAME, TIMEOUT_SETTING, _ttoi(timeout)); + } + __finally { + free(timeout); + } + break; + } + return 0; +} + +void AddPopupsPage(WPARAM wParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.ptszTitle = MAIL_NOTIFICATIONS; + odp.pfnDlgProc = PopupsOptionsDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUPSETTINGS); + odp.hInstance = hInst; + odp.ptszGroup = POPUPS_OPTIONS_GROUP; + odp.flags = ODPF_UNICODE | ODPF_USERINFOTAB; + + Options_AddPage(wParam, &odp); +} + +void AddAccPage(LPCTSTR acc, LPCSTR mod, WPARAM wParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.pszTitle = (LPSTR)acc; + odp.pfnDlgProc = AccOptionsDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAILSETTINGS); + odp.hInstance = hInst; + odp.ptszGroup = NETWORK_OPTIONS_GROUP; + odp.flags = ODPF_UNICODE | ODPF_USERINFOTAB; + odp.ptszTab = MAIL_NOTIFICATIONS; + odp.dwInitParam = (LPARAM)mod; + + Options_AddPage(wParam, &odp); +} + +int OptionsInitialization(WPARAM wParam, LPARAM lParam) +{ + int count; + PROTOACCOUNT **accs; + CallService(MS_PROTO_ENUMACCOUNTS, (WPARAM)&count, (LPARAM)&accs); + for (int i = 0; i < count; i++) + if (getJabberApi(accs[i]->szModuleName)) AddAccPage(accs[i]->tszAccountName, accs[i]->szModuleName, wParam); + + if (ServiceExists(MS_POPUP_ADDPOPUPT)) AddPopupsPage(wParam); + return FALSE; +} + +BOOL HookOptionsInitialization() +{ + return (hOptionsHook = HookEvent(ME_OPT_INITIALISE, OptionsInitialization)) != 0; +} + +void UnhookOptionsInitialization() +{ + if (hOptionsHook) { + UnhookEvent(hOptionsHook); + hOptionsHook = 0; + } +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/options.h b/protocols/GTalkExt/src/options.h new file mode 100644 index 0000000000..bc720e22ed --- /dev/null +++ b/protocols/GTalkExt/src/options.h @@ -0,0 +1,39 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +#include "resources.h" + +static const LPTSTR MAIL_NOTIFICATIONS = _T("GMail notifications"); +static const LPTSTR FULL_NOTIFICATION_FORMAT = _T("subject\n %s\nfrom\n%s\n%s\n"); +static const LPTSTR SHORT_NOTIFICATION_FORMAT = _T("subject\n %s\nfrom\n%s"); + +static const LPSTR PSEUDOCONTACT_LINK = "GTalkExtNotifyContact"; +static const LPSTR PSEUDOCONTACT_FLAG = "IsNotifyContact"; +static const LPSTR BACK_COLOR_SETTING = "BackColor"; +static const LPSTR TEXT_COLOR_SETTING = "TextColor"; +static const LPSTR TIMEOUT_SETTING = "Timeout"; + +BOOL HookOptionsInitialization(); +void UnhookOptionsInitialization(); +DWORD ReadCheckboxes(HWND wnd, LPCSTR mod); +BOOL ReadCheckbox(HWND wnd, int id, DWORD controls); \ No newline at end of file diff --git a/protocols/GTalkExt/src/popups.cpp b/protocols/GTalkExt/src/popups.cpp new file mode 100644 index 0000000000..99ab94470b --- /dev/null +++ b/protocols/GTalkExt/src/popups.cpp @@ -0,0 +1,104 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" +#include "popups.h" +#include "options.h" + +static const LPTSTR YAPP_WND_CLASS1 = _T("YAPPYAPPWindowClass"); +static const LPTSTR YAPP_WND_CLASS2 = _T("YAPPWinClass"); + +extern BOOL isOriginalPopups; + +LRESULT CALLBACK PopupHookProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + PCWPRETSTRUCT cs = (PCWPRETSTRUCT)lParam; + if ((HC_ACTION == nCode) && + (WM_CREATE == cs->message) && + (-1 != cs->lResult) && + ServiceExists(MS_POPUP_GETCONTACT)) { + + // with YAPP we can't call MS_POPUP_GETCONTACT on a random window + TCHAR ClassName[32]; + GetClassName(cs->hwnd, ClassName, sizeof(ClassName) / sizeof(TCHAR)); + if (isOriginalPopups || + !lstrcmp(YAPP_WND_CLASS1, ClassName) || + !lstrcmp(YAPP_WND_CLASS2, ClassName)) { + + HANDLE hContact = (HANDLE)CallService(MS_POPUP_GETCONTACT, (WPARAM)cs->hwnd, 0); + if (hContact != (HANDLE)-1 && + hContact != (HANDLE)0x80000000 && + DBGetContactSettingByte(hContact, SHORT_PLUGIN_NAME, PSEUDOCONTACT_FLAG, 0)) { + LPCSTR proto = (LPCSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + DWORD checkboxes = ReadCheckboxes(0, proto); + if (ReadCheckbox(0, IDC_PSEUDOCONTACTENABLED, checkboxes) && + ReadCheckbox(0, IDC_SUPRESSFOREIGN, checkboxes)) + PostMessage(cs->hwnd, WM_CLOSE, 0, 0); + } + } + } + return CallNextHookEx(0, nCode, wParam, lParam); +} + +typedef PLUGININFOEX* (MIRANDAPLUGININFOEX) (DWORD mirandaVersion); + +static GUID POPUP_GUID1 = {0x26a9125d, 0x7863, 0x4e01, {0xaf, 0xe, 0xd1, 0x4e, 0xf9, 0x5c, 0x50, 0x54}}; +static GUID POPUP_GUID2 = {0x26a9125d, 0x7863, 0x4e01, {0xaf, 0xe, 0xd1, 0x4e, 0xf9, 0x5c, 0x50, 0x53}}; + +DWORD g_mirandaVersion = 0; + +BOOL IsOriginalPopupModule(HMODULE hMod) +{ + MIRANDAPLUGININFOEX *MirandaPluginInfoEx = (MIRANDAPLUGININFOEX*)GetProcAddress(hMod, "MirandaPluginInfoEx"); + if (!MirandaPluginInfoEx) return FALSE; + + PLUGININFOEX *PluginInfoEx = MirandaPluginInfoEx(g_mirandaVersion); + if (!PluginInfoEx) return FALSE; + + GUID *guid1 = (GUID*)&PluginInfoEx->uuid; + GUID *guid2 = (GUID*)&POPUP_GUID1; + GUID *guid3 = (GUID*)&POPUP_GUID2; + return (IsEqualGUID(*guid1, *guid2) || IsEqualGUID(*guid1, *guid3)); +} + +extern BOOL isOriginalPopups; + +void DetectPopupModule() +{ + DWORD bytesNeeded; + if (!EnumProcessModules(GetCurrentProcess(), NULL, 0, &bytesNeeded)) + return; + + HMODULE *mods = (HMODULE*)malloc(bytesNeeded); + __try { + if (!EnumProcessModules(GetCurrentProcess(), mods, bytesNeeded, &bytesNeeded)) + return; + + for (DWORD i = 0; i < (bytesNeeded / sizeof(HMODULE)); i++) + if (IsOriginalPopupModule(mods[i])) { + isOriginalPopups = TRUE; + break; + } + } + __finally { + free(mods); + } +} diff --git a/protocols/GTalkExt/src/popups.h b/protocols/GTalkExt/src/popups.h new file mode 100644 index 0000000000..f9e142e0e6 --- /dev/null +++ b/protocols/GTalkExt/src/popups.h @@ -0,0 +1,25 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +LRESULT CALLBACK PopupHookProc(int nCode, WPARAM wParam, LPARAM lParam); +void DetectPopupModule(); \ No newline at end of file diff --git a/protocols/GTalkExt/src/resources.h b/protocols/GTalkExt/src/resources.h new file mode 100644 index 0000000000..d72e34dcef --- /dev/null +++ b/protocols/GTalkExt/src/resources.h @@ -0,0 +1,67 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +#define SHORT_PLUGIN_NAME "GTalkExt" + +#define IDD_MAILSETTINGS 2001 + +#define IDC_BASE 1001 +#define IDC_POPUPSENABLED IDC_BASE + 0 +#define IDC_PSEUDOCONTACTENABLED IDC_BASE + 1 +#define IDC_CLEARPSEUDOCONTACTLOG IDC_BASE + 2 +#define IDC_POPUPSINFULLSCREEN IDC_BASE + 3 +#define IDC_SUPRESSFOREIGN IDC_BASE + 4 +#define IDC_MARKEVENTREAD IDC_BASE + 5 +#define IDC_AUTHONMAILBOX IDC_BASE + 6 +#define IDC_ADDSNIP IDC_BASE + 7 +#define IDC_UNKNOWNVIEW IDC_BASE + 8 +#define IDC_STANDARDVIEW IDC_BASE + 9 +#define IDC_HTMLVIEW IDC_BASE + 10 +#define IDC_POPUPSINFULLSCREENLABEL IDC_BASE + 32 +#define IDC_NOTE IDC_BASE + 33 +#define IDC_WARNBAR IDC_BASE + 34 +#define IDC_AUTHONMAILBOXLABEL IDC_BASE + 35 +#define IDC_MAILBOXVIEWLABEL IDC_BASE + 36 + +#define IDD_POPUPSETTINGS 2002 + +#define IDC_BACKCOLORLABEL 1001 +#define IDC_BACKCOLORPICKER 1002 +#define IDC_TEXTCOLORLABEL 1003 +#define IDC_TEXTCOLORPICKER 1004 +#define IDC_TIMEOUTLABEL 1005 +#define IDC_TIMEOUTEDIT 1006 +#define IDC_DEFCOLORSLABEL 1007 +#define IDC_DEFTIMEOUTLABEL 1008 +#define IDC_TESTBUTTON 1009 +#define IDC_GROUP 1010 + +#define IDI_POPUP 3001 +#define IDI_PSEUDOAVA 3002 + +#define PLUGIN_VERSION_STRING "0.0.0.20 BETA" +#define PLUGIN_FILE_VERSION 0, 0, 0, 20 +#define PLUGIN_VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 0, 20) + +#define PLUGIN_DESCRIPTION "GTalk extensions for Jabber protocol" +#define COPYRIGHT_STRING "2010, 11 bems" diff --git a/protocols/GTalkExt/src/stdafx.cpp b/protocols/GTalkExt/src/stdafx.cpp new file mode 100644 index 0000000000..bdf32c5876 --- /dev/null +++ b/protocols/GTalkExt/src/stdafx.cpp @@ -0,0 +1,25 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/protocols/GTalkExt/src/stdafx.h b/protocols/GTalkExt/src/stdafx.h new file mode 100644 index 0000000000..d9712d7e9c --- /dev/null +++ b/protocols/GTalkExt/src/stdafx.h @@ -0,0 +1,71 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include + +// Windows Header Files: +#include +#include +#include +#include + +#include +#pragma comment(lib, "psapi.lib") + +#include + +// Miranda&Plugins API +#include +#include + +#pragma warning(push) +#pragma warning(disable:4996) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) + +#if _MSC_VER < 1400 + #define _tstoi64 _ttoi + #define _tcstoui64(A,B,C) _ttoi(A) +#endif + +#define WNDCLASS_COLOURPICKER _T("ColourPicker") \ No newline at end of file diff --git a/protocols/GTalkExt/src/targetver.h b/protocols/GTalkExt/src/targetver.h new file mode 100644 index 0000000000..feb11bf4f2 --- /dev/null +++ b/protocols/GTalkExt/src/targetver.h @@ -0,0 +1,47 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif + +#define MIRANDA_VER 0x0A00 diff --git a/protocols/GTalkExt/src/tipper_items.cpp b/protocols/GTalkExt/src/tipper_items.cpp new file mode 100644 index 0000000000..f09be10b32 --- /dev/null +++ b/protocols/GTalkExt/src/tipper_items.cpp @@ -0,0 +1,157 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#include "StdAfx.h" +#include "tipper_items.h" +#include "resources.h" + +static const int MAX_TIPPER_ITEM_PROP = 6 ; + +static const LPSTR VALUE_SETTING_PROP = "DIValue%d"; +static const LPSTR LABEL_SETTING_PROP = "DILabel%d"; + +static const LPSTR LAST_WRITTEN_LABEL_SETTING = "LastWrittenTipperLabel"; + +static LPSTR TipperItemProps[MAX_TIPPER_ITEM_PROP] = { + LABEL_SETTING_PROP, + "DILineAbove%d", + "DITipperVarsFirst%d", + "DIValNewline%d", + VALUE_SETTING_PROP, + "DIVisible%d" +}; + +static const LPSTR TIPPER_ITEMS_MOD_NAME = "Tipper_Items"; +static const LPSTR TIPPER_ITEM_COUNT_SETTING = "DINumValues"; +static const LPTSTR UNREAD_THREADS_RAW = _T("%raw:") _T(SHORT_PLUGIN_NAME) _T("/UnreadThreads%"); +static const LPTSTR UNREAD_THREADS_LABEL = _T("Unread threads:"); + +void ShiftTipperSettings(LPSTR buff, int count, LPSTR format) +{ + for (int i = count; i > 0; i--) { + DBCONTACTWRITESETTING cws; + DBCONTACTGETSETTING cgs; + cgs.szModule = TIPPER_ITEMS_MOD_NAME; + sprintf(buff, format, i - 1); + cgs.szSetting = buff; + cgs.pValue = &cws.value; + + if (CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&cgs)) break; + __try { + if (DBVT_ASCIIZ == cws.value.type) { + DBFreeVariant(&cws.value); + cws.value.type = DBVT_WCHAR; + if (CallService(MS_DB_CONTACT_GETSETTING_STR, 0, (LPARAM)&cgs)) break; + } + + if (CallService(MS_DB_CONTACT_GETSETTING_STR, 0, (LPARAM)&cgs)) break; + + cws.szModule = TIPPER_ITEMS_MOD_NAME; + sprintf(buff, format, i); + cws.szSetting = buff; + CallService(MS_DB_CONTACT_WRITESETTING, 0, (LPARAM)&cws); + } + __finally { + DBFreeVariant(&cws.value); + } + } +} + +void SetLabelProp(int index, LPSTR setting) +{ + sprintf(setting, LABEL_SETTING_PROP, index); + + DBVARIANT dbv1 = {0}; + if (!DBGetContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, &dbv1)) + __try { + DBVARIANT dbv2 = {0}; + if (!DBGetContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, &dbv2)) + __try { + if (!lstrcmp(dbv1.ptszVal, dbv2.ptszVal)) { + LPTSTR label = TranslateTS(UNREAD_THREADS_LABEL); + DBWriteContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, label); + DBWriteContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, label); + } + } + __finally { + DBFreeVariant(&dbv2); + } + } + __finally { + DBFreeVariant(&dbv1); + } +} + +void AddTipperItem() +{ + unsigned short itemCount = DBGetContactSettingWord(0, TIPPER_ITEMS_MOD_NAME, + TIPPER_ITEM_COUNT_SETTING , unsigned short(-1)); + if (unsigned short(-1) == itemCount) return; + + int i, l = 0; + for (i = itemCount; i > 0; i /= 10) l++; // var setting path + l += 30; // const setting part + + LPSTR setting = (LPSTR)malloc(l * sizeof(TCHAR)); + __try { + for (i = 0; i < itemCount; i++) { + sprintf(setting, VALUE_SETTING_PROP, i); + + DBVARIANT dbv = {0}; + if (!DBGetContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, &dbv)) + __try { + if (!lstrcmp(UNREAD_THREADS_RAW, dbv.ptszVal)) { + SetLabelProp(i, setting); + return; + } + } + __finally { + DBFreeVariant(&dbv); + } + } + + for (i = 0; i < MAX_TIPPER_ITEM_PROP; i++) + ShiftTipperSettings(setting, itemCount, TipperItemProps[i]); + + #define WRITE_TIPPER_PROP(type, index, value)\ + sprintf(setting, TipperItemProps[##index##], 0);\ + DBWriteContactSetting##type##(0, TIPPER_ITEMS_MOD_NAME, setting, ##value##) + + LPTSTR label = TranslateTS(UNREAD_THREADS_LABEL); + + DBWriteContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, label); + + WRITE_TIPPER_PROP(TString, 0, label); + WRITE_TIPPER_PROP(Byte, 1, 0); + WRITE_TIPPER_PROP(Byte, 2, 0); + WRITE_TIPPER_PROP(Byte, 3, 0); + WRITE_TIPPER_PROP(TString, 4, UNREAD_THREADS_RAW); + WRITE_TIPPER_PROP(Byte, 5, 1); + + #undef WRITE_TIPPER_PROP + } + __finally { + free(setting); + } + + DBWriteContactSettingWord(0, TIPPER_ITEMS_MOD_NAME, + TIPPER_ITEM_COUNT_SETTING, itemCount + 1); +} \ No newline at end of file diff --git a/protocols/GTalkExt/src/tipper_items.h b/protocols/GTalkExt/src/tipper_items.h new file mode 100644 index 0000000000..0b94d1fd24 --- /dev/null +++ b/protocols/GTalkExt/src/tipper_items.h @@ -0,0 +1,24 @@ +//*************************************************************************************** +// +// Google Extension plugin for the Miranda IM's Jabber protocol +// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//*************************************************************************************** + +#pragma once + +void AddTipperItem(); \ No newline at end of file diff --git a/protocols/GTalkExt/stdafx.cpp b/protocols/GTalkExt/stdafx.cpp deleted file mode 100644 index bdf32c5876..0000000000 --- a/protocols/GTalkExt/stdafx.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/protocols/GTalkExt/stdafx.h b/protocols/GTalkExt/stdafx.h deleted file mode 100644 index d9712d7e9c..0000000000 --- a/protocols/GTalkExt/stdafx.h +++ /dev/null @@ -1,71 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -#include "targetver.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include -#include -#include - -// Windows Header Files: -#include -#include -#include -#include - -#include -#pragma comment(lib, "psapi.lib") - -#include - -// Miranda&Plugins API -#include -#include - -#pragma warning(push) -#pragma warning(disable:4996) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#pragma warning(pop) - -#if _MSC_VER < 1400 - #define _tstoi64 _ttoi - #define _tcstoui64(A,B,C) _ttoi(A) -#endif - -#define WNDCLASS_COLOURPICKER _T("ColourPicker") \ No newline at end of file diff --git a/protocols/GTalkExt/targetver.h b/protocols/GTalkExt/targetver.h deleted file mode 100644 index feb11bf4f2..0000000000 --- a/protocols/GTalkExt/targetver.h +++ /dev/null @@ -1,47 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -// The following macros define the minimum required platform. The minimum required platform -// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run -// your application. The macros work by enabling all features available on platform versions up to and -// including the version specified. - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. -#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. -#endif - -#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. -#endif - -#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. -#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. -#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. -#endif - -#define MIRANDA_VER 0x0A00 diff --git a/protocols/GTalkExt/tipper_items.cpp b/protocols/GTalkExt/tipper_items.cpp deleted file mode 100644 index f09be10b32..0000000000 --- a/protocols/GTalkExt/tipper_items.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#include "StdAfx.h" -#include "tipper_items.h" -#include "resources.h" - -static const int MAX_TIPPER_ITEM_PROP = 6 ; - -static const LPSTR VALUE_SETTING_PROP = "DIValue%d"; -static const LPSTR LABEL_SETTING_PROP = "DILabel%d"; - -static const LPSTR LAST_WRITTEN_LABEL_SETTING = "LastWrittenTipperLabel"; - -static LPSTR TipperItemProps[MAX_TIPPER_ITEM_PROP] = { - LABEL_SETTING_PROP, - "DILineAbove%d", - "DITipperVarsFirst%d", - "DIValNewline%d", - VALUE_SETTING_PROP, - "DIVisible%d" -}; - -static const LPSTR TIPPER_ITEMS_MOD_NAME = "Tipper_Items"; -static const LPSTR TIPPER_ITEM_COUNT_SETTING = "DINumValues"; -static const LPTSTR UNREAD_THREADS_RAW = _T("%raw:") _T(SHORT_PLUGIN_NAME) _T("/UnreadThreads%"); -static const LPTSTR UNREAD_THREADS_LABEL = _T("Unread threads:"); - -void ShiftTipperSettings(LPSTR buff, int count, LPSTR format) -{ - for (int i = count; i > 0; i--) { - DBCONTACTWRITESETTING cws; - DBCONTACTGETSETTING cgs; - cgs.szModule = TIPPER_ITEMS_MOD_NAME; - sprintf(buff, format, i - 1); - cgs.szSetting = buff; - cgs.pValue = &cws.value; - - if (CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&cgs)) break; - __try { - if (DBVT_ASCIIZ == cws.value.type) { - DBFreeVariant(&cws.value); - cws.value.type = DBVT_WCHAR; - if (CallService(MS_DB_CONTACT_GETSETTING_STR, 0, (LPARAM)&cgs)) break; - } - - if (CallService(MS_DB_CONTACT_GETSETTING_STR, 0, (LPARAM)&cgs)) break; - - cws.szModule = TIPPER_ITEMS_MOD_NAME; - sprintf(buff, format, i); - cws.szSetting = buff; - CallService(MS_DB_CONTACT_WRITESETTING, 0, (LPARAM)&cws); - } - __finally { - DBFreeVariant(&cws.value); - } - } -} - -void SetLabelProp(int index, LPSTR setting) -{ - sprintf(setting, LABEL_SETTING_PROP, index); - - DBVARIANT dbv1 = {0}; - if (!DBGetContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, &dbv1)) - __try { - DBVARIANT dbv2 = {0}; - if (!DBGetContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, &dbv2)) - __try { - if (!lstrcmp(dbv1.ptszVal, dbv2.ptszVal)) { - LPTSTR label = TranslateTS(UNREAD_THREADS_LABEL); - DBWriteContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, label); - DBWriteContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, label); - } - } - __finally { - DBFreeVariant(&dbv2); - } - } - __finally { - DBFreeVariant(&dbv1); - } -} - -void AddTipperItem() -{ - unsigned short itemCount = DBGetContactSettingWord(0, TIPPER_ITEMS_MOD_NAME, - TIPPER_ITEM_COUNT_SETTING , unsigned short(-1)); - if (unsigned short(-1) == itemCount) return; - - int i, l = 0; - for (i = itemCount; i > 0; i /= 10) l++; // var setting path - l += 30; // const setting part - - LPSTR setting = (LPSTR)malloc(l * sizeof(TCHAR)); - __try { - for (i = 0; i < itemCount; i++) { - sprintf(setting, VALUE_SETTING_PROP, i); - - DBVARIANT dbv = {0}; - if (!DBGetContactSettingTString(0, TIPPER_ITEMS_MOD_NAME, setting, &dbv)) - __try { - if (!lstrcmp(UNREAD_THREADS_RAW, dbv.ptszVal)) { - SetLabelProp(i, setting); - return; - } - } - __finally { - DBFreeVariant(&dbv); - } - } - - for (i = 0; i < MAX_TIPPER_ITEM_PROP; i++) - ShiftTipperSettings(setting, itemCount, TipperItemProps[i]); - - #define WRITE_TIPPER_PROP(type, index, value)\ - sprintf(setting, TipperItemProps[##index##], 0);\ - DBWriteContactSetting##type##(0, TIPPER_ITEMS_MOD_NAME, setting, ##value##) - - LPTSTR label = TranslateTS(UNREAD_THREADS_LABEL); - - DBWriteContactSettingTString(0, SHORT_PLUGIN_NAME, LAST_WRITTEN_LABEL_SETTING, label); - - WRITE_TIPPER_PROP(TString, 0, label); - WRITE_TIPPER_PROP(Byte, 1, 0); - WRITE_TIPPER_PROP(Byte, 2, 0); - WRITE_TIPPER_PROP(Byte, 3, 0); - WRITE_TIPPER_PROP(TString, 4, UNREAD_THREADS_RAW); - WRITE_TIPPER_PROP(Byte, 5, 1); - - #undef WRITE_TIPPER_PROP - } - __finally { - free(setting); - } - - DBWriteContactSettingWord(0, TIPPER_ITEMS_MOD_NAME, - TIPPER_ITEM_COUNT_SETTING, itemCount + 1); -} \ No newline at end of file diff --git a/protocols/GTalkExt/tipper_items.h b/protocols/GTalkExt/tipper_items.h deleted file mode 100644 index 0b94d1fd24..0000000000 --- a/protocols/GTalkExt/tipper_items.h +++ /dev/null @@ -1,24 +0,0 @@ -//*************************************************************************************** -// -// Google Extension plugin for the Miranda IM's Jabber protocol -// Copyright (c) 2011 bems@jabber.org, George Hazan (ghazan@jabber.ru) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -//*************************************************************************************** - -#pragma once - -void AddTipperItem(); \ No newline at end of file diff --git a/protocols/IRCG/Docs/ircg-translation.txt b/protocols/IRCG/Docs/ircg-translation.txt new file mode 100644 index 0000000000..2c072af2d4 --- /dev/null +++ b/protocols/IRCG/Docs/ircg-translation.txt @@ -0,0 +1,409 @@ +; Common strings that belong to many files +;[Auto] +;[Channel manager] +;[DCC ERROR: Unable to automatically resolve external IP] +;[Default network] +;[IRC Error] +;[IRC error] +;[IRC warning] +;[Ignore] +;[Jerk] +;[Network] +;[Off] +;[On] +;[Please enter the reason] +;[Question] +;[Quick connect] +;[Send notice] +;[The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically.] +;[Topic] +;[User information] + +; ../../protocols/IRCG/IRC.rc +;[&Accept] +;[&Add] +;[&Cancel] +;[&Clear all] +;[&Close] +;[&Del] +;[&Deny] +;[&Edit] +;[&Join] +;[&OK] +;[&Query] +;[&Refresh] +;[&Save] +;[&Set] +;['Old style' mode changes] +;[(*) Queries from users on your contactlist are never ignored] +;[(*) blank to set this mask for all networks] +;[Add server] +;[Address] +;[Alias] +;[Alternate nick] +;[Alternative nick] +;[Attempt reverse DCC (good if firewalled)] +;[Auth] +;[Auto-accept from:] +;[Automatically join on invite] +;[Away Info] +;[Bans] +;[Basic] +;[C&onnect] +;[CTCP] +;[CTCP Chat Request] +;[CTCP information] +;[Channel modes] +;[Channels] +;[Channels on server] +;[Check every (s):] +;[Client-to-Client Chats] +;[Client-to-Client File Transfers] +;[Client-to-Client Protocol] +;[DCC] +;[Disable tray balloon on error] +;[Disconnect DCC chats when disconnecting from server] +;[Don't check if more than (users):] +;[Enable] +;[Enable (*)] +;[Enable UTF8 autodetection] +;[Excepts] +;[Fear the monkeys!!!] +;[Filter by] +;[Force visible (-i)] +;[Full name (e-mail)] +;[Get IP address from server] +;[Hidden] +;[Host address] +;[Hostmask] +;[Ident] +;[Ignore DCC Chat requests] +;[Ignore DCC Chat requests from unknown contacts] +;[Ignore channel messages by default] +;[Ignore events] +;[Ignore filetransfer requests] +;[Ignore mask ( nick!user@host )] +;[Ignore users] +;[Internet address] +;[Invite only] +;[Invites] +;[Keep connection alive] +;[Key:] +;[Manually set external IP:] +;[Messages] +;[Moderated] +;[Name] +;[Network (*)] +;[Nick] +;[No external messages] +;[Normal] +;[Notices] +;[Online detection mode] +;[Only Ops set topic] +;[Other] +;[Packet size (b):] +;[Password] +;[Password:] +;[Perform] +;[Perform on event:] +;[Ping] +;[Port] +;[Port range] +;[Private] +;[Queries] +;[Quit message:] +;[Reconnect] +;[Rejoin channel if kicked] +;[Rejoin channels on reconnect] +;[Retry count] +;[SSL] +;[Scripting support] +;[Secret] +;[Send mode:] +;[Send-ahead] +;[Server] +;[Server code page:] +;[Server description] +;[Server name] +;[Server:] +;[Show addresses] +;[Show server window on startup] +;[Spin1] +;[Spin2] +;[Strip colors] +;[System] +;[The server returned the following information. Please note that this information might be misleading and/or falsified] +;[Time] +;[Update online statuses for users] +;[Update statuses in channel nicklist] +;[Use server window] +;[Use the options to set modes for this channel. You are usually required to be op. or higher to modify.] +;[User] +;[User ID (Ident)] +;[User info - Required] +;[User limit:] +;[User modes] +;[Userinfo] +;[Version] +;[Wait (s)] +;[Wildcard enabled network search] +;[everyone] +;[everyone on the contact list] +;[none] +;[only while connecting] + +; ../../protocols/IRCG/clist.cpp +;[CTCP chat request from %s] + +; ../../protocols/IRCG/commandmonitor.cpp +;[%s sets mode %s] +;[%s sets mode %s%s] +;[(probably truncated by server)] +;[*Disconnected*] +;[Ban'n Kick] +;[CTCP %s reply from %s: %s] +;[CTCP %s requested by %s] +;[CTCP ERROR: Malformed CTCP command received from %s!%s@%s. Possible attempt to take control of your irc client registered] +;[CTCP FINGER requested by %s] +;[CTCP PING reply from %s: %u sec(s)] +;[CTCP PING requested by %s] +;[CTCP SOURCE requested by %s] +;[CTCP TIME requested by %s] +;[CTCP USERINFO requested by %s] +;[CTCP VERSION requested by %s] +;[Change nickname] +;[DCC ERROR: Malformed CTCP request from %s [%s]] +;[DCC: Chat request from %s denied] +;[DCC: File transfer request from %s denied] +;[DCC: File transfer resume request from %s denied] +;[DCC: Reverse file transfer request from %s denied [No local IP]] +;[Done: %u channels] +;[Downloading list (%u%%) - %u channels] +;[Downloading list - %u channels] +;[Please enter the hostmask (nick!user@host)\nNOTE! Contacts on your contact list are never ignored] +;[Unknown] + +; ../../protocols/IRCG/input.cpp +;[%s is not ignored now] +;[%s on %s is now ignored (+%s)] +;[%s was not ignored] +;[Aborted] +;[CTCP %s request sent to %s] +;[DCC CHAT request sent to %s] +;[DCC ERROR: Unable to bind port] +;[Ignore system is disabled] +;[Ignore system is enabled] +;[Incorrect parameters. Usage: /sleep [ms], ms should be greater than 0 and less than 4000.] +;[Input command] +;[Outgoing commands are not shown] +;[Outgoing commands are shown] +;[Please enter the reply] +;[The buddy check function is disabled] +;[The buddy check function is enabled] +;[The time interval for the buddy check function is now %u seconds] +;[The time interval for the buddy check function is now at default setting] +;[This command is not recommended on a network of this size!\r\nIt will probably cause high CPU usage and/or high bandwidth\r\nusage for around %u to %u minute(s).\r\n\r\nDo you want to continue?] + +; ../../protocols/IRCG/irclib.cpp +;[DCC ERROR: Unable to bind local port for passive filetransfer] +;[Failed to connect to] + +; ../../protocols/IRCG/ircproto.cpp +;[%s client-to-client connections] +;[%s server connection] +;[Connection can not be established! You have not completed all necessary fields (Nickname, User ID and m_name).] +;[DCC ERROR: No valid files specified] +;[DCC ERROR: Unable to bind local port] +;[DCC file transfer request sent to %s [%s]] +;[DCC reversed file transfer request sent to %s [%s]] +;[Information] +;[Nickname] +;[Please choose an IRC-network to go online. This network will be the default.] +;[The IRC protocol depends on another plugin called \'Chat\'\n\nDo you want to download it from the Miranda IM web site now?] +;[The dcc chat connection is not active] +;[The protocol is not online] + +; ../../protocols/IRCG/options.cpp +;[] +;[",IDC_STATIC,71,75,8,8 - LTEXT "Alternative nick",IDC_STATIC,231,8,68,8,0,WS_EX_TRANSPARENT - GROUPBOX "Ident",IDC_STATIC,150,59,154,42 - LTEXT "System",IDC_STATIC,210,65,39,8,0,WS_EX_TRANSPARENT - LTEXT "Port",IDC_STATIC,256,65,35,8,0,WS_EX_TRANSPARENT - GROUPBOX "Default network",IDC_STATIC,2,0,142,134 - GROUPBOX "User info - Required",IDC_STATIC,150,0,154,59 - GROUPBOX "Other",IDC_STATIC,2,134,302,92 - GROUPBOX "Reconnect",IDC_STATIC,150,101,154,33 - LTEXT "Wait (s)",IDC_STATIC,210,108,45,8,0,WS_EX_TRANSPARENT - LTEXT "Retry count",IDC_STATIC,256,108,43,8,0,WS_EX_TRANSPARENT - LTEXT "Fear the monkeys!!!",IDC_STATIC,72,4,63,8,NOT WS_VISIBLE - LTEXT "Check every (s):",IDC_STATIC,158,190,108,8 - EDITTEXT IDC_SSL,107,53,28,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT - LTEXT "SSL",IDC_STATIC,107,45,28,8,0,WS_EX_TRANSPARENT - CONTROL "Don't check if more than (users):",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,158,212,108,8 -END - -IDD_INFO DIALOGEX 0, 0, 267, 214 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "User information" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_INFO_NICK,6,63,60,97,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP - PUSHBUTTON "Ping",IDC_PING,12,142,50,14 - PUSHBUTTON "Version",IDC_VERSION,76,142,50,14 - PUSHBUTTON "Time",IDC_TIME,140,142,50,14 - PUSHBUTTON "Userinfo",IDC_USERINFO,204,142,50,14 - DEFPUSHBUTTON "&Refresh",ID_INFO_GO,93,194,50,14 - PUSHBUTTON "&Query",ID_INFO_QUERY,152,194,50,14,WS_GROUP - DEFPUSHBUTTON "&Close",IDOK,211,194,50,14,WS_GROUP - EDITTEXT IDC_INFO_NAME,71,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_ADDRESS,136,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_ID,201,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_AUTH,6,85,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_SERVER,71,85,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_AWAY2,136,85,125,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - EDITTEXT IDC_INFO_CHANNELS,136,108,125,20,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP - EDITTEXT IDC_INFO_OTHER,6,108,125,20,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP - LTEXT "Nick",IDC_STATIC,6,55,60,8 - LTEXT "Name",IDC_STATIC,71,55,59,8 - LTEXT "Address",IDC_STATIC,136,55,59,8,SS_NOTIFY - LTEXT "Channels",IDC_STATIC,136,100,119,8 - LTEXT "Auth",IDC_STATIC,6,77,59,8 - LTEXT "Server",IDC_STATIC,71,77,59,8 - LTEXT "User",IDC_STATIC,201,55,60,8 - LTEXT "Away Info",IDC_STATIC,136,77,125,8 - LTEXT "Other",IDC_STATIC,6,100,124,8 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,52,268,1 - LTEXT "",IDC_WHITERECT,0,0,267,52 - ICON "",IDC_LOGO,228,16,20,20,SS_REALSIZEIMAGE - LTEXT "The server returned the following information. Please note that this information might be misleading and/or falsified",IDC_TEXT,12,30,204,18 - LTEXT "",IDC_CAPTION,8,5,201,21 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,190,268,1 - GROUPBOX "CTCP information",IDC_STATIC,6,132,255,54 - EDITTEXT IDC_REPLY,12,160,243,20,ES_MULTILINE | ES_READONLY | NOT WS_TABSTOP - LTEXT "-",IDC_AWAYTIME,8,19,205,8 -END - -IDD_NICK DIALOGEX 0, 0, 180, 90 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Question" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_ENICK,5,47,170,71,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "&OK",IDOK,65,71,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,125,71,50,14,WS_GROUP - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,180,1 - LTEXT "",IDC_WHITERECT,0,0,179,38 - ICON "",IDC_LOGO,141,5,20,20,SS_REALSIZEIMAGE - LTEXT "",IDC_TEXT,13,16,121,18 - LTEXT "",IDC_CAPTION,5,5,125,11 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,65,180,1 -END - -IDD_PREFS_OTHER DIALOGEX 0, 0, 304, 225 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Perform",IDC_STATIC,4,4,136,152 - CONTROL "Enable",IDC_PERFORM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,18,107,10 - COMBOBOX IDC_PERFORMCOMBO,9,40,125,99,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_PERFORMEDIT,9,60,125,68,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | WS_GROUP - CONTROL "&Set",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,35,134,30,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "&Del",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,84,134,30,14,WS_EX_NOACTIVATE | 0x10000000L - GROUPBOX "Alias",IDC_STATIC,144,4,157,122 - EDITTEXT IDC_ALIASEDIT,152,18,142,102,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL - LTEXT "Perform on event:",IDC_STATIC,16,32,110,8,0,WS_EX_TRANSPARENT - GROUPBOX "Scripting support",IDC_STATIC,145,128,156,28 - CONTROL "Enable",IDC_SCRIPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,153,140,126,10 - GROUPBOX "Other",IDC_STATIC,4,156,297,66 - LTEXT "Quit message:",IDC_STATIC,12,168,136,8 - EDITTEXT IDC_QUITMESSAGE,12,176,282,12,ES_AUTOHSCROLL - COMBOBOX IDC_CODEPAGE,148,192,146,79,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Server code page:",IDC_STATIC,12,194,130,8 - CONTROL "Enable UTF8 autodetection",IDC_UTF_AUTODETECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,208,282,10 -END - -IDD_ADDSERVER DIALOGEX 0, 0, 182, 136 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT -CAPTION "Add server" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_ADD_COMBO,7,20,168,90,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_ADD_SERVER,7,44,120,12,ES_AUTOHSCROLL - EDITTEXT IDC_ADD_ADDRESS,7,68,120,12,ES_AUTOHSCROLL | WS_GROUP - EDITTEXT IDC_ADD_PORT,7,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT - EDITTEXT IDC_ADD_PORT2,80,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT - CONTROL "On",IDC_ON,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,143,52,25,10 - CONTROL "Auto",IDC_AUTO,"Button",BS_AUTORADIOBUTTON,143,69,30,10 - CONTROL "Off",IDC_OFF,"Button",BS_AUTORADIOBUTTON,143,86,25,10 - DEFPUSHBUTTON "&OK",IDOK,63,115,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,125,115,50,14 - CONTROL "Host address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,7,60,120,8,WS_EX_TRANSPARENT - LTEXT "->",IDC_STATIC,64,94,8,8 - LTEXT "Port range",IDC_STATIC,7,84,87,8,0,WS_EX_TRANSPARENT - LTEXT "Server description",IDC_STATIC,7,36,120,8,0,WS_EX_TRANSPARENT - LTEXT "Network",IDC_STATIC,7,12,107,8,0,WS_EX_TRANSPARENT - GROUPBOX "SSL",IDC_STATIC,136,38,39,67 -END - -IDD_LIST DIALOGEX 0, 0, 360, 212 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Channels on server" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - PUSHBUTTON "&Close",IDOK,306,183,50,14 - DEFPUSHBUTTON "&Join",IDC_JOIN,251,183,50,14,WS_DISABLED - CONTROL "List1",IDC_INFO_LISTVIEW,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,4,7,352,172 - EDITTEXT IDC_FILTER_STRING,68,183,143,13,ES_AUTOHSCROLL - CONTROL "List1",IDC_INFO_LISTVIEW2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,4,7,352,172 - LTEXT "Filter by",IDC_FILTER_BTN,7,185,56,8 - EDITTEXT IDC_TEXT,4,200,351,10,ES_AUTOHSCROLL | WS_DISABLED | NOT WS_BORDER,WS_EX_STATICEDGE -END - -IDD_QUICKCONN DIALOGEX 0, 0, 201, 165 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_SERVERCOMBO,12,54,177,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_SERVER,12,78,177,12,ES_AUTOHSCROLL - GROUPBOX "SSL",IDC_GRBOX_SSL,12,94,177,21,WS_GROUP | WS_TABSTOP - CONTROL "Off",IDC_SSL_OFF,"Button",BS_AUTORADIOBUTTON,36,102,42,10 - CONTROL "Auto",IDC_SSL_AUTO,"Button",BS_AUTORADIOBUTTON,87,102,42,10 - CONTROL "On",IDC_SSL_ON,"Button",BS_AUTORADIOBUTTON,138,102,44,10 - EDITTEXT IDC_PORT,12,124,36,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT - EDITTEXT IDC_PORT2,63,124,36,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT - EDITTEXT IDC_PASS,116,124,73,12,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "C&onnect",IDOK,83,146,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,139,146,50,14 - CONTROL "Internet address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP,12,70,130,8,WS_EX_TRANSPARENT - LTEXT "Port range",IDC_STATIC,12,116,63,8,0,WS_EX_TRANSPARENT - LTEXT "Password",IDC_STATIC,116,116,73,8,0,WS_EX_TRANSPARENT - LTEXT "Server name",IDC_STATIC,12,46,177,8,0,WS_EX_TRANSPARENT - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,140,201,1 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,201,1 - LTEXT "",IDC_WHITERECT,0,0,201,38 - ICON "",IDC_LOGO,159,5,20,20,SS_REALSIZEIMAGE - LTEXT "",IDC_TEXT,18,16,138,18 - LTEXT "",IDC_CAPTION,12,5,143,11 - LTEXT "->",IDC_STATIC,51,126,8,8,0,WS_EX_TRANSPARENT -END - -IDD_USERINFO DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_WILDCARD,12,91,40,12,ES_AUTOHSCROLL - EDITTEXT IDC_USER,66,91,40,12,ES_AUTOHSCROLL - EDITTEXT IDC_HOST,120,91,89,12,ES_AUTOHSCROLL - PUSHBUTTON "&Save",IDC_BUTTON,159,107,50,14,WS_DISABLED - LTEXT "Nick",IDC_STATIC,12,83,40,8 - LTEXT "User",IDC_STATIC,66,83,40,8 - LTEXT "Address",IDC_STATIC,120,83,89,8 - LTEXT "@",IDC_STATIC,109,90,8,8 - GROUPBOX "Hostmask",IDC_STATIC,6,73,209,52 - LTEXT "",IDC_DEFAULT,12,30,197,37 - LTEXT "!",IDC_STATIC,57,90,8,8 - PUSHBUTTON "&Clear all",IDC_BUTTON2,96,107,50,14 - GROUPBOX "Online detection mode",IDC_STATIC,6,7,209,66 - CONTROL "Basic",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,23,17,33,10 - CONTROL "Wildcard enabled network search",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,69,17,122,10 -END - -IDD_CHANMANAGER DIALOGEX 0, 0, 271, 303 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Channel manager" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_TOPIC,13,56,192,103,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - CONTROL "&Set",IDC_APPLYTOPIC,"MButtonClass",WS_DISABLED | WS_TABSTOP,226,54,28,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "Bans",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP | WS_TABSTOP,16,87,69,10 - CONTROL "Invites",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,90,87,74,10 - CONTROL "Excepts",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,166,87,86,10 - LISTBOX IDC_LIST,15,101,203,82,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_GROUP | WS_TABSTOP - CONTROL "&Add",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,100,28,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,116,28,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "&Del",IDC_REMOVE,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,132,28,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "Only Ops set topic",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,211,111,10 - CONTROL "No external messages",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,224,109,10 - CONTROL "Invite only",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,237,106,10 - CONTROL "Moderated",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,250,106,10 - CONTROL "Key:",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,211,45,10 - EDITTEXT IDC_KEY,183,209,57,12,ES_AUTOHSCROLL | WS_DISABLED - CONTROL "User limit:",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,224,46,10 - EDITTEXT IDC_LIMIT,183,224,25,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED - CONTROL "Private",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,237,73,10 - CONTROL "Secret",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,250,80,10 - CONTROL "&Set",IDC_APPLYMODES,"MButtonClass",WS_DISABLED | WS_TABSTOP,215,257,28,14,WS_EX_NOACTIVATE | 0x10000000L - DEFPUSHBUTTON "&Close",IDOK,212,284,50,14 - GROUPBOX "Topic",IDC_STATIC,6,45,256,28 - GROUPBOX "User modes",IDC_STATIC,6,73,256,118 - GROUPBOX "Channel modes",IDC_STATIC,6,197,256,82 - CONTROL "Hidden",IDC_NOTOP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE,217,73,45,10 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,271,1 - LTEXT "",IDC_WHITERECT,0,0,271,38 - ICON "",IDC_LOGO,236,5,21,20,SS_REALSIZEIMAGE - LTEXT "Use the options to set modes for this channel. You are usually required to be op. or higher to modify.",IDC_TEXT,18,16,219,18 - LTEXT "",IDC_CAPTION,12,5,210,11 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,279,255,1 - CONTROL "Strip colors",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,260,108,14 -END - -IDD_QUESTION DIALOGEX 0, 0, 230, 97 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Question" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_EDIT,5,48,220,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "&OK",IDOK,116,78,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,175,78,50,14,WS_GROUP - EDITTEXT IDC_HIDDENEDIT,5,78,40,14,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER | NOT WS_TABSTOP - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,230,1 - LTEXT "",IDC_WHITERECT,0,0,229,38 - ICON "",IDC_LOGO,193,5,20,20,SS_REALSIZEIMAGE - LTEXT "",IDC_TEXT,11,16,179,18 - LTEXT "",IDC_CAPTION,5,5,184,11 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,71,230,1 -END - -IDD_PREFS_CTCP DIALOGEX 0, 0, 304, 220 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_COMBO,104,40,52,85,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Normal",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,104,24,76,10 - CONTROL "Send-ahead",IDC_FAST,"Button",BS_AUTORADIOBUTTON,188,24,102,10 - CONTROL "Attempt reverse DCC (good if firewalled)",IDC_PASSIVE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,62,273,10 - CONTROL "none",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,104,94,162,10 - CONTROL "everyone on the contact list",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,104,105,186,10 - CONTROL "everyone",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,104,116,186,10 - CONTROL "Disconnect DCC chats when disconnecting from server",IDC_DISC, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,135,257,10 - CONTROL "Manually set external IP:",IDC_ENABLEIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,164,130,10 - EDITTEXT IDC_IP,146,162,144,14,ES_AUTOHSCROLL - EDITTEXT IDC_USERINFO,16,196,274,14,ES_AUTOHSCROLL - GROUPBOX "Client-to-Client File Transfers",IDC_STATIC,8,6,289,75 - LTEXT "User information",IDC_STATIC,16,188,144,8 - GROUPBOX "Client-to-Client Protocol",IDC_STATIC,8,151,289,67 - GROUPBOX "Client-to-Client Chats",IDC_STATIC,8,81,289,70 - LTEXT "Send mode:",IDC_STATIC,16,25,79,8 - LTEXT "Packet size (b):",IDC_STATIC,16,44,88,8 - CONTROL "Get IP address from server",IDC_FROMSERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,176,227,10 - LTEXT "Auto-accept from:",IDC_STATIC,16,106,82,8 - CONTROL "Send notice",IDC_SENDNOTICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,43,101,10 -END - -IDD_MESSAGEBOX DIALOGEX 0, 0, 220, 68 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT -CAPTION "CTCP Chat Request" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - PUSHBUTTON "&Accept",IDOK,50,47,50,14 - DEFPUSHBUTTON "&Deny",IDCANCEL,120,47,50,14 - LTEXT "",IDC_TEXT,43,13,170,31,0,WS_EX_TRANSPARENT - ICON "",IDC_LOGO,7,13,21,20 -END - -IDD_PREFS_IGNORE DIALOGEX 0, 0, 304, 220 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Enable (*)",IDC_ENABLEIGNORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,78,10 - CONTROL "Ignore channel messages by default",IDC_IGNORECHANNEL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,108,18,180,10 - CONTROL "List1",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,16,33,240,104 - CONTROL "&Add",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,43,27,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,68,27,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "&Del",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,93,27,14,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "Ignore filetransfer requests",IDC_IGNOREFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,170,240,10 - CONTROL "Ignore DCC Chat requests",IDC_IGNORECHAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,185,240,10 - CONTROL "Ignore DCC Chat requests from unknown contacts",IDC_IGNOREUNKNOWN, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,200,256,10 - GROUPBOX "Ignore users",-1,8,6,289,150 - GROUPBOX "Other",-1,8,156,289,62 - CONTROL "(*) Queries from users on your contactlist are never ignored",IDC_CUSTOM, - "Hyperlink",WS_TABSTOP | 0x1,16,142,274,9 -END - -IDD_ADDIGNORE DIALOGEX 0, 0, 220, 126 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_MASK,7,15,137,14,ES_AUTOHSCROLL - EDITTEXT IDC_NETWORK,150,15,63,14,ES_AUTOHSCROLL - CONTROL "Queries",IDC_Q,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,47,54,10 - CONTROL "Messages",IDC_M,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,47,64,10 - CONTROL "Notices",IDC_N,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,47,57,10 - CONTROL "Invites",IDC_I,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,66,54,10 - CONTROL "CTCP",IDC_C,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,66,64,10 - CONTROL "DCC",IDC_D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,66,57,10 - DEFPUSHBUTTON "&Accept",IDOK,93,105,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,163,105,50,14 - LTEXT "Ignore mask ( nick!user@host )",IDC_STATIC,7,7,136,8 - LTEXT "Network (*)",IDC_STATIC,150,7,63,8 - GROUPBOX "Ignore events",IDC_STATIC,7,36,206,46 - CTEXT "(*) blank to set this mask for all networks",IDC_STATIC,7,90,206,8 -END - -IDD_ACCMGRUI DIALOGEX 0, 0, 186, 134 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_SERVERCOMBO,55,5,125,90,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_SERVER,5,21,88,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP | NOT WS_TABSTOP - EDITTEXT IDC_PORT,96,21,27,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT - EDITTEXT IDC_PORT2,126,21,27,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT - EDITTEXT IDC_PASS,54,38,125,12,ES_PASSWORD | ES_AUTOHSCROLL - EDITTEXT IDC_NICK,87,64,91,13,ES_AUTOHSCROLL - EDITTEXT IDC_NICK2,87,81,91,13,ES_AUTOHSCROLL - EDITTEXT IDC_NAME,87,98,91,13,ES_AUTOHSCROLL - EDITTEXT IDC_USERID,87,115,91,13,ES_AUTOHSCROLL - LTEXT "Server:",IDC_STATIC,5,7,45,8 - LTEXT "Password:",IDC_STATIC,6,41,43,8 - LTEXT "Nick",IDC_STATIC,8,66,77,8 - LTEXT "Alternate nick",IDC_STATIC,8,83,76,8 - LTEXT "Full name (e-mail)",IDC_STATIC,8,100,77,8 - LTEXT "User ID (Ident)",IDC_STATIC,8,117,74,8 - EDITTEXT IDC_SSL,155,21,23,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PREFS_CONNECT, DIALOG - BEGIN - LEFTMARGIN, 2 - VERTGUIDE, 10 - VERTGUIDE, 135 - VERTGUIDE, 144 - VERTGUIDE, 158 - VERTGUIDE, 210 - VERTGUIDE, 229 - HORZGUIDE, 16 - HORZGUIDE, 30 - HORZGUIDE, 39 - HORZGUIDE, 53 - HORZGUIDE, 61 - HORZGUIDE, 73 - HORZGUIDE, 75 - HORZGUIDE, 116 - HORZGUIDE, 134 - HORZGUIDE, 145 - END - - IDD_INFO, DIALOG - BEGIN - VERTGUIDE, 6 - VERTGUIDE, 10 - VERTGUIDE, 261 - BOTTOMMARGIN, 208 - HORZGUIDE, 38 - HORZGUIDE, 49 - HORZGUIDE, 71 - HORZGUIDE, 94 - HORZGUIDE, 118 - HORZGUIDE, 135 - HORZGUIDE, 146 - HORZGUIDE, 163 - HORZGUIDE, 180 - HORZGUIDE, 194 - END - - IDD_NICK, DIALOG - BEGIN - BOTTOMMARGIN, 85 - HORZGUIDE, 5 - HORZGUIDE, 65 - END - - IDD_PREFS_OTHER, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 291 - VERTGUIDE, 10 - VERTGUIDE, 128 - VERTGUIDE, 145 - VERTGUIDE, 220 - VERTGUIDE, 262 - VERTGUIDE, 283 - BOTTOMMARGIN, 217 - HORZGUIDE, 6 - HORZGUIDE, 28 - HORZGUIDE, 49 - HORZGUIDE, 117 - HORZGUIDE, 124 - HORZGUIDE, 131 - HORZGUIDE, 145 - HORZGUIDE, 174 - END - - IDD_ADDSERVER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 175 - VERTGUIDE, 127 - VERTGUIDE, 136 - VERTGUIDE, 143 - TOPMARGIN, 7 - BOTTOMMARGIN, 129 - HORZGUIDE, 20 - HORZGUIDE, 44 - HORZGUIDE, 68 - HORZGUIDE, 92 - END - - IDD_LIST, DIALOG - BEGIN - LEFTMARGIN, 4 - RIGHTMARGIN, 356 - VERTGUIDE, 16 - VERTGUIDE, 70 - VERTGUIDE, 128 - VERTGUIDE, 182 - TOPMARGIN, 7 - BOTTOMMARGIN, 203 - HORZGUIDE, 19 - HORZGUIDE, 138 - HORZGUIDE, 179 - END - - IDD_QUICKCONN, DIALOG - BEGIN - VERTGUIDE, 12 - VERTGUIDE, 189 - BOTTOMMARGIN, 160 - HORZGUIDE, 5 - HORZGUIDE, 38 - HORZGUIDE, 54 - HORZGUIDE, 78 - HORZGUIDE, 124 - HORZGUIDE, 140 - END - - IDD_USERINFO, DIALOG - BEGIN - LEFTMARGIN, 6 - RIGHTMARGIN, 215 - VERTGUIDE, 62 - TOPMARGIN, 7 - BOTTOMMARGIN, 125 - HORZGUIDE, 22 - HORZGUIDE, 30 - HORZGUIDE, 73 - HORZGUIDE, 91 - HORZGUIDE, 114 - END - - IDD_CHANMANAGER, DIALOG - BEGIN - VERTGUIDE, 6 - VERTGUIDE, 15 - VERTGUIDE, 134 - VERTGUIDE, 262 - BOTTOMMARGIN, 298 - HORZGUIDE, 5 - HORZGUIDE, 22 - HORZGUIDE, 40 - HORZGUIDE, 45 - HORZGUIDE, 73 - HORZGUIDE, 191 - HORZGUIDE, 279 - END - - IDD_QUESTION, DIALOG - BEGIN - VERTGUIDE, 5 - BOTTOMMARGIN, 92 - HORZGUIDE, 5 - HORZGUIDE, 72 - END - - IDD_PREFS_CTCP, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 291 - VERTGUIDE, 10 - VERTGUIDE, 27 - VERTGUIDE, 37 - VERTGUIDE, 83 - VERTGUIDE, 98 - VERTGUIDE, 140 - VERTGUIDE, 154 - VERTGUIDE, 182 - VERTGUIDE, 199 - VERTGUIDE, 220 - VERTGUIDE, 260 - VERTGUIDE, 284 - BOTTOMMARGIN, 212 - HORZGUIDE, 23 - HORZGUIDE, 42 - HORZGUIDE, 61 - HORZGUIDE, 75 - HORZGUIDE, 104 - HORZGUIDE, 134 - HORZGUIDE, 145 - HORZGUIDE, 163 - HORZGUIDE, 190 - END - - IDD_MESSAGEBOX, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 213 - VERTGUIDE, 43 - VERTGUIDE, 75 - VERTGUIDE, 145 - TOPMARGIN, 7 - BOTTOMMARGIN, 61 - HORZGUIDE, 13 - END - - IDD_PREFS_IGNORE, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 291 - VERTGUIDE, 10 - VERTGUIDE, 250 - VERTGUIDE, 258 - BOTTOMMARGIN, 212 - HORZGUIDE, 17 - HORZGUIDE, 27 - HORZGUIDE, 140 - HORZGUIDE, 150 - END - - IDD_ADDIGNORE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 213 - VERTGUIDE, 20 - VERTGUIDE, 80 - VERTGUIDE, 150 - TOPMARGIN, 7 - BOTTOMMARGIN, 119 - HORZGUIDE, 15 - HORZGUIDE, 36 - HORZGUIDE, 52 - HORZGUIDE, 71 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// TEXT -// - -IDR_SERVERS TEXT "Docs\\IRC_servers.ini" -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/protocols/IRCG/IRC_10.vcxproj b/protocols/IRCG/IRC_10.vcxproj index 0bd68e3977..f528b26a37 100644 --- a/protocols/IRCG/IRC_10.vcxproj +++ b/protocols/IRCG/IRC_10.vcxproj @@ -193,58 +193,39 @@ - - - - - - + + + + + + Create - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + diff --git a/protocols/IRCG/IRC_10.vcxproj.filters b/protocols/IRCG/IRC_10.vcxproj.filters index 202bb2d6da..fcd43c9931 100644 --- a/protocols/IRCG/IRC_10.vcxproj.filters +++ b/protocols/IRCG/IRC_10.vcxproj.filters @@ -19,142 +19,85 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Documentation - - - Documentation - Documentation - - Documentation - - + Resource Files - + Resource Files diff --git a/protocols/IRCG/Icons/add.ico b/protocols/IRCG/Icons/add.ico deleted file mode 100644 index a6a7e6f38c..0000000000 Binary files a/protocols/IRCG/Icons/add.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/apply.ico b/protocols/IRCG/Icons/apply.ico deleted file mode 100644 index 19957e4ac8..0000000000 Binary files a/protocols/IRCG/Icons/apply.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/block.ico b/protocols/IRCG/Icons/block.ico deleted file mode 100644 index 073acb134f..0000000000 Binary files a/protocols/IRCG/Icons/block.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/dcc.ico b/protocols/IRCG/Icons/dcc.ico deleted file mode 100644 index 3d3b83d936..0000000000 Binary files a/protocols/IRCG/Icons/dcc.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/delete.ico b/protocols/IRCG/Icons/delete.ico deleted file mode 100644 index 9108e38cfd..0000000000 Binary files a/protocols/IRCG/Icons/delete.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/edit.ico b/protocols/IRCG/Icons/edit.ico deleted file mode 100644 index 0c3764bec4..0000000000 Binary files a/protocols/IRCG/Icons/edit.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/irc.ico b/protocols/IRCG/Icons/irc.ico deleted file mode 100644 index 27cc764c94..0000000000 Binary files a/protocols/IRCG/Icons/irc.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/list.ico b/protocols/IRCG/Icons/list.ico deleted file mode 100644 index a7004e37aa..0000000000 Binary files a/protocols/IRCG/Icons/list.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/manager.ico b/protocols/IRCG/Icons/manager.ico deleted file mode 100644 index 217534bc74..0000000000 Binary files a/protocols/IRCG/Icons/manager.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/question.ico b/protocols/IRCG/Icons/question.ico deleted file mode 100644 index 0454d67afb..0000000000 Binary files a/protocols/IRCG/Icons/question.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/quick.ico b/protocols/IRCG/Icons/quick.ico deleted file mode 100644 index 078f7490c9..0000000000 Binary files a/protocols/IRCG/Icons/quick.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/rename.ico b/protocols/IRCG/Icons/rename.ico deleted file mode 100644 index 0434c1bd02..0000000000 Binary files a/protocols/IRCG/Icons/rename.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/server.ico b/protocols/IRCG/Icons/server.ico deleted file mode 100644 index db008452f0..0000000000 Binary files a/protocols/IRCG/Icons/server.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/show.ico b/protocols/IRCG/Icons/show.ico deleted file mode 100644 index ce7136ae4a..0000000000 Binary files a/protocols/IRCG/Icons/show.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/whois.ico b/protocols/IRCG/Icons/whois.ico deleted file mode 100644 index e66f079830..0000000000 Binary files a/protocols/IRCG/Icons/whois.ico and /dev/null differ diff --git a/protocols/IRCG/Icons/world.ico b/protocols/IRCG/Icons/world.ico deleted file mode 100644 index f462de9a04..0000000000 Binary files a/protocols/IRCG/Icons/world.ico and /dev/null differ diff --git a/protocols/IRCG/MString.cpp b/protocols/IRCG/MString.cpp deleted file mode 100644 index 70016e427e..0000000000 --- a/protocols/IRCG/MString.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "irc.h" -#include "MString.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -CNilMStringData CMBaseString::m_nil; - -CMStringData* CMBaseString::Allocate( int nChars, int nCharSize ) -{ - CMStringData* pData; - nChars++; // nil char - size_t nDataBytes = nCharSize * nChars; - size_t nTotalSize = nDataBytes + sizeof(CMStringData); - - pData = static_cast(malloc(nTotalSize)); - if (pData == NULL) - return NULL; - - pData->nRefs = 1; - pData->nAllocLength = nChars - 1; - pData->nDataLength = 0; - return pData; -} - -void CMBaseString::Free(CMStringData* pData) -{ - free(pData); -} - -CMStringData* CMBaseString::Realloc(CMStringData* pData, int nChars, int nCharSize) -{ - CMStringData* pNewData; - nChars++; // nil char - ULONG nDataBytes = nCharSize * nChars; - ULONG nTotalSize = nDataBytes + sizeof(CMStringData); - - pNewData = static_cast(realloc(pData, nTotalSize)); - if (pNewData == NULL) - return NULL; - - pNewData->nAllocLength = nChars - 1; - return pNewData; -} - -CMStringData* CMBaseString::GetNilString() -{ - m_nil.AddRef(); - return &m_nil; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CMStringData - -void* CMStringData::data() -{ - return (this + 1); -} - -void CMStringData::AddRef() -{ - InterlockedIncrement(&nRefs); -} - -bool CMStringData::IsLocked() const -{ - return nRefs < 0; -} - -bool CMStringData::IsShared() const -{ - return (nRefs > 1); -} - -void CMStringData::Lock() -{ - nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary - if ( nRefs == 0 ) - nRefs = -1; -} - -void CMStringData::Release() -{ - if (InterlockedDecrement(&nRefs) <= 0) - CMBaseString::Free(this); -} - -void CMStringData::Unlock() -{ - if (IsLocked()) - { - nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary - if (nRefs == 0) - nRefs = 1; - } -} - -CNilMStringData::CNilMStringData() -{ - nRefs = 2; // Never gets freed - nDataLength = 0; - nAllocLength = 0; - achNil[0] = 0; - achNil[1] = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// ChTraitsCRT - -#if _MSC_VER < 1400 -static HINSTANCE hCrt = NULL; - -typedef int ( __cdecl *_vscprintf_func )( LPCSTR pszFormat, va_list args ); -static _vscprintf_func _vscprintf_ptr = NULL; - -typedef int ( __cdecl *_vscwprintf_func )( LPCWSTR pszFormat, va_list args ); -static _vscwprintf_func _vscwprintf_ptr = NULL; - -typedef int ( __cdecl *_vsnprintf_func )( char*, size_t, const char*, va_list ); -static _vsnprintf_func _vsnprintf_ptr = NULL; - -typedef int ( __cdecl *_vsnwprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); -static _vsnwprintf_func _vsnwprintf_ptr = NULL; - -typedef int ( __cdecl *vswprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); -static vswprintf_func vswprintf_ptr = NULL; - -typedef int ( __cdecl *vsprintf_func )( char*, size_t, const char*, va_list ); -static vsprintf_func vsprintf_ptr = NULL; - -static void checkCrt( void ) -{ - if ( hCrt == NULL ) { - hCrt = GetModuleHandleA( "msvcrt.dll" ); - _vscprintf_ptr = (_vscprintf_func)GetProcAddress( hCrt, "_vscprintf" ); - _vscwprintf_ptr = (_vscwprintf_func)GetProcAddress( hCrt, "_vscwprintf" ); - _vsnprintf_ptr = (_vsnprintf_func)GetProcAddress( hCrt, "_vsnprintf" ); - _vsnwprintf_ptr = (_vsnwprintf_func)GetProcAddress( hCrt, "_vsnwprintf" ); - vswprintf_ptr = (vswprintf_func)GetProcAddress( hCrt, "vswprintf" ); - vsprintf_ptr = (vsprintf_func)GetProcAddress( hCrt, "vsprintf" ); -} } -#endif - -int __stdcall ChTraitsCRT::GetFormattedLength( LPCWSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vscwprintf_ptr != NULL ) - return _vscwprintf_ptr( pszFormat, args ); - - WCHAR buf[ 4000 ]; - return vswprintf_ptr( buf, SIZEOF(buf), pszFormat, args ); - #else - return _vscwprintf( pszFormat, args ); - #endif -} - -int __stdcall ChTraitsCRT::Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vsnwprintf_ptr != NULL ) - return _vsnwprintf_ptr( pszBuffer, nLength, pszFormat, args ); - - return vswprintf_ptr( pszBuffer, nLength, pszFormat, args ); - #else - return _vsnwprintf( pszBuffer, nLength, pszFormat, args ); - #endif -} - -///////////////////////////////////////////////////////////////////////////////////////// -// ChTraitsCRT - -int __stdcall ChTraitsCRT::GetFormattedLength( LPCSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vscprintf_ptr != NULL ) - return _vscprintf_ptr( pszFormat, args ); - - char buf[4000]; - return vsprintf_ptr( buf, sizeof(buf), pszFormat, args ); - #else - return _vscprintf( pszFormat, args ); - #endif -} - -int __stdcall ChTraitsCRT::Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - return _vsnprintf( pszBuffer, nlength, pszFormat, args ); - #else - return vsprintf_s( pszBuffer, nlength, pszFormat, args ); - #endif -} - diff --git a/protocols/IRCG/MString.h b/protocols/IRCG/MString.h deleted file mode 100644 index 7cc16ff4a3..0000000000 --- a/protocols/IRCG/MString.h +++ /dev/null @@ -1,2300 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef __MINGW32__ -#include - -__inline size_t strnlen(const char *string, size_t maxlen) -{ - const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} -__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) -{ - const wchar_t *end = wmemchr (string, L'\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} - -/* FIXME: This may be wrong assumption about _AtlGetConversionACP */ -#define _AtlGetConversionACP() CP_THREAD_ACP -/* FIXME: This is unsafe */ -#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) -/* FIXME: This is quite silly implementation of _mbsstr */ -#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) -#define __max(x,y) (((x)<(y))?(y):(x)) -#endif /* __MINGW32__ */ - -struct CMStringData -{ - int nDataLength; // Length of currently used data in XCHARs (not including terminating null) - int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) - long nRefs; // Reference count: negative == locked - // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data - void* data(); - void AddRef(); - bool IsLocked() const; - bool IsShared() const; - void Lock(); - void Release(); - void Unlock(); -}; - -class CNilMStringData : public CMStringData -{ -public: - CNilMStringData(); - -public: - wchar_t achNil[2]; -}; - -template< typename BaseType = char > -class ChTraitsBase -{ -public: - typedef char XCHAR; - typedef LPSTR PXSTR; - typedef LPCSTR PCXSTR; - typedef wchar_t YCHAR; - typedef LPWSTR PYSTR; - typedef LPCWSTR PCYSTR; -}; - -template<> -class ChTraitsBase< wchar_t > -{ -public: - typedef wchar_t XCHAR; - typedef LPWSTR PXSTR; - typedef LPCWSTR PCXSTR; - typedef char YCHAR; - typedef LPSTR PYSTR; - typedef LPCSTR PCYSTR; -}; - -class CMBaseString -{ -public: - static CMStringData* Allocate(int nChars, int nCharSize); - static void Free(CMStringData* pData); - static CMStringData* Realloc(CMStringData* pData, int nChars, int nCharSize); - -protected: - static CMStringData* GetNilString(); - static CNilMStringData m_nil; -}; - -template< typename BaseType > -class CMSimpleStringT : public CMBaseString -{ -public: - typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; - typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; - typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; - typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; - typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; - typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; - -public: - explicit CMSimpleStringT() - { - CMStringData* pData = GetNilString(); - Attach(pData); - } - - CMSimpleStringT(const CMSimpleStringT& strSrc) - { - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pNewData = CloneData( pSrcData ); - Attach( pNewData ); - } - - CMSimpleStringT(PCXSTR pszSrc) - { - int nLength = StringLength( pszSrc ); - CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); - if (pData != NULL) - { - Attach( pData ); - SetLength( nLength ); - CopyChars( m_pszData, nLength, pszSrc, nLength ); - } - } - CMSimpleStringT(const XCHAR* pchSrc, int nLength) - { - CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); - if ( pData != NULL ) - { - Attach( pData ); - SetLength( nLength ); - CopyChars( m_pszData, nLength, pchSrc, nLength ); - } - } - ~CMSimpleStringT() - { - CMStringData* pData = GetData(); - pData->Release(); - } - - operator CMSimpleStringT&() - { - return *(CMSimpleStringT*)this; - } - - CMSimpleStringT& operator=(const CMSimpleStringT& strSrc ) - { - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pOldData = GetData(); - if ( pSrcData != pOldData) - { - if ( pOldData->IsLocked()) - SetString( strSrc.GetString(), strSrc.GetLength()); - else - { - CMStringData* pNewData = CloneData( pSrcData ); - pOldData->Release(); - Attach( pNewData ); - } - } - - return *this; - } - - CMSimpleStringT& operator=(PCXSTR pszSrc) - { - SetString( pszSrc ); - return *this; - } - - CMSimpleStringT& operator+=( const CMSimpleStringT& strSrc ) - { - Append( strSrc ); - - return *this; - } - - CMSimpleStringT& operator+=( PCXSTR pszSrc ) - { - Append( pszSrc ); - - return *this; - } - CMSimpleStringT& operator+=( char ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - CMSimpleStringT& operator+=( unsigned char ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - CMSimpleStringT& operator+=( wchar_t ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - - XCHAR operator[]( int iChar ) const - { - return m_pszData[iChar]; - } - - operator PCXSTR() const - { - return m_pszData; - } - - PCXSTR c_str() const - { - return m_pszData; - } - - void Append( PCXSTR pszSrc ) - { - Append( pszSrc, StringLength( pszSrc )); - } - void Append( PCXSTR pszSrc, int nLength ) - { - // See comment in SetString() about why we do this - UINT_PTR nOffset = pszSrc - GetString(); - - UINT nOldLength = GetLength(); - if (nOldLength < 0) - { - // protects from underflow - nOldLength = 0; - } - - //Make sure we don't read pass end of the terminating NULL - int nSrcLength = StringLength(pszSrc); - nLength = nLength > nSrcLength ? nSrcLength: nLength; - - int nNewLength = nOldLength+nLength; - PXSTR pszBuffer = GetBuffer( nNewLength ); - if ( nOffset <= nOldLength ) - { - pszSrc = pszBuffer+nOffset; - // No need to call CopyCharsOverlapped, since the destination is - // beyond the end of the original buffer - } - CopyChars( pszBuffer+nOldLength, nLength, pszSrc, nLength ); - ReleaseBufferSetLength( nNewLength ); - } - void AppendChar( XCHAR ch ) - { - UINT nOldLength = GetLength(); - int nNewLength = nOldLength+1; - PXSTR pszBuffer = GetBuffer( nNewLength ); - pszBuffer[nOldLength] = ch; - ReleaseBufferSetLength( nNewLength ); - } - void Append( const CMSimpleStringT& strSrc ) - { - Append( strSrc.GetString(), strSrc.GetLength()); - } - void Empty() - { - CMStringData* pOldData = GetData(); - if ( pOldData->nDataLength == 0 ) - return; - - if ( pOldData->IsLocked()) - { - // Don't reallocate a locked buffer that's shrinking - SetLength( 0 ); - } - else - { - pOldData->Release(); - CMStringData* pNewData = GetNilString(); - Attach( pNewData ); - } - } - void FreeExtra() - { - CMStringData* pOldData = GetData(); - int nLength = pOldData->nDataLength; - if ( pOldData->nAllocLength == nLength ) - return; - - if ( !pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking - { - CMStringData* pNewData = Allocate( nLength, sizeof( XCHAR )); - if ( pNewData == NULL ) { - SetLength( nLength ); - return; - } - - CopyChars( PXSTR( pNewData->data()), nLength, PCXSTR( pOldData->data()), nLength ); - - pOldData->Release(); - Attach( pNewData ); - SetLength( nLength ); - } - } - - int GetAllocLength() const - { - return GetData()->nAllocLength; - } - XCHAR GetAt( int iChar ) const - { - return m_pszData[iChar]; - } - PXSTR GetBuffer() - { - CMStringData* pData = GetData(); - if ( pData->IsShared()) - Fork( pData->nDataLength ); - - return m_pszData; - } - PXSTR GetBuffer( int nMinBufferLength ) - { - return PrepareWrite( nMinBufferLength ); - } - PXSTR GetBufferSetLength( int nLength ) - { - PXSTR pszBuffer = GetBuffer( nLength ); - SetLength( nLength ); - - return pszBuffer; - } - int GetLength() const - { - return GetData()->nDataLength; - } - - PCXSTR GetString() const - { - return m_pszData; - } - bool IsEmpty() const - { - return GetLength() == 0; - } - PXSTR LockBuffer() - { - CMStringData* pData = GetData(); - if ( pData->IsShared()) - { - Fork( pData->nDataLength ); - pData = GetData(); // Do it again, because the fork might have changed it - } - pData->Lock(); - - return m_pszData; - } - void UnlockBuffer() - { - CMStringData* pData = GetData(); - pData->Unlock(); - } - void Preallocate( int nLength ) - { - PrepareWrite( nLength ); - } - void ReleaseBuffer( int nNewLength = -1 ) - { - if ( nNewLength == -1 ) - { - int nAlloc = GetData()->nAllocLength; - nNewLength = StringLengthN( m_pszData, nAlloc); - } - SetLength( nNewLength ); - } - void ReleaseBufferSetLength( int nNewLength ) - { - SetLength( nNewLength ); - } - void Truncate( int nNewLength ) - { - GetBuffer( nNewLength ); - ReleaseBufferSetLength( nNewLength ); - } - void SetAt( int iChar, XCHAR ch ) - { - int nLength = GetLength(); - PXSTR pszBuffer = GetBuffer(); - pszBuffer[iChar] = ch; - ReleaseBufferSetLength( nLength ); - - } - void SetString( PCXSTR pszSrc ) - { - SetString( pszSrc, StringLength( pszSrc )); - } - void SetString( PCXSTR pszSrc, int nLength ) - { - if ( nLength == 0 ) - { - Empty(); - } - else - { - - UINT nOldLength = GetLength(); - UINT_PTR nOffset = pszSrc - GetString(); - - PXSTR pszBuffer = GetBuffer( nLength ); - if ( nOffset <= nOldLength ) - { - CopyCharsOverlapped( pszBuffer, GetAllocLength(), - pszBuffer+nOffset, nLength ); - } - else - { - CopyChars( pszBuffer, GetAllocLength(), pszSrc, nLength ); - } - ReleaseBufferSetLength( nLength ); - } - } -public: - friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) - { - CMSimpleStringT s; - - Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength()); - - return s; - } - - friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, PCXSTR psz2) - { - CMSimpleStringT s; - - Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 )); - - return s; - } - - friend CMSimpleStringT __stdcall operator+(PCXSTR psz1, const CMSimpleStringT& str2) - { - CMSimpleStringT s; - - Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength()); - - return s; - } - - static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); -#pragma warning (pop) - } - static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars ) - { - #if _MSC_VER >= 1400 - memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); - #else - memcpy(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); - #endif - } - - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); -#pragma warning (pop) - } - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) - { - #if _MSC_VER >= 1400 - memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); - #else - memmove(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); - #endif - } - static int __stdcall StringLength(const char* psz) - { - if (psz == NULL) - { - return(0); - } - return (int(strlen(psz))); - } - static int __stdcall StringLength(const wchar_t* psz) - { - if (psz == NULL) - return 0; - - return int(wcslen(psz)); - } - static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar ) - { - if ( psz == NULL ) - return 0; - - return int( strnlen( psz, sizeInXChar )); - } - static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar ) - { - if ( psz == NULL ) - return 0; - - return int( wcsnlen( psz, sizeInXChar )); - } -protected: - static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) - { - int nNewLength = nLength1+nLength2; - PXSTR pszBuffer = strResult.GetBuffer(nNewLength); - CopyChars(pszBuffer, nLength1, psz1, nLength1 ); - CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); - strResult.ReleaseBufferSetLength(nNewLength); - } - // Implementation -private: - void Attach(CMStringData* pData) - { - m_pszData = static_cast(pData->data()); - } - void Fork(int nLength) - { - CMStringData* pOldData = GetData(); - int nOldLength = pOldData->nDataLength; - CMStringData* pNewData = Allocate(nLength, sizeof(XCHAR)); - if (pNewData != NULL) - { - int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0' - CopyChars( PXSTR( pNewData->data()), nCharsToCopy, PCXSTR( pOldData->data()), nCharsToCopy ); - pNewData->nDataLength = nOldLength; - pOldData->Release(); - Attach(pNewData); - } - } - CMStringData* GetData() const - { - return (reinterpret_cast(m_pszData) - 1); - } - PXSTR PrepareWrite( int nLength ) - { - CMStringData* pOldData = GetData(); - int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false - int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false - if ((nShared | nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data - PrepareWrite2(nLength); - - return m_pszData; - } - void PrepareWrite2(int nLength) - { - CMStringData* pOldData = GetData(); - if (pOldData->nDataLength > nLength) - nLength = pOldData->nDataLength; - - if (pOldData->IsShared()) - { - Fork(nLength); - } - else if (pOldData->nAllocLength < nLength) - { - // Grow exponentially, until we hit 1K. - int nNewLength = pOldData->nAllocLength; - if ( nNewLength > 1024 ) - nNewLength += 1024; - else - nNewLength *= 2; - - if ( nNewLength < nLength ) - nNewLength = nLength; - - Reallocate( nNewLength ); - } - } - void Reallocate( int nLength ) - { - CMStringData* pOldData = GetData(); - if ( pOldData->nAllocLength >= nLength || nLength <= 0) - return; - - CMStringData* pNewData = Realloc( pOldData, nLength, sizeof( XCHAR )); - if ( pNewData != NULL ) - Attach( pNewData ); - } - - void SetLength( int nLength ) - { - GetData()->nDataLength = nLength; - m_pszData[nLength] = 0; - } - - static CMStringData* __stdcall CloneData(CMStringData* pData) - { - CMStringData* pNewData = NULL; - - if (!pData->IsLocked()) { - pNewData = pData; - pNewData->AddRef(); - } - - return pNewData; - } - -public : - // typedef CStrBufT CStrBuf; -private: - PXSTR m_pszData; -}; - - -template< typename _CharType = char > -class ChTraitsCRT : public ChTraitsBase< _CharType > -{ -public: - static char* __stdcall CharNext( const char* p ) - { - return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ))); - } - - static int __stdcall IsDigit( char ch ) - { - return _ismbcdigit( ch ); - } - - static int __stdcall IsSpace( char ch ) - { - return _ismbcspace( ch ); - } - - static int __stdcall StringCompare( LPCSTR pszA, LPCSTR pszB ) - { - return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) - { - return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCollate( LPCSTR pszA, LPCSTR pszB ) - { - return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) - { - return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static LPCSTR __stdcall StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) - { - return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ), - reinterpret_cast< const unsigned char* >( pszMatch ))); - } - - static LPSTR __stdcall StringFindString( LPSTR pszBlock, LPCSTR pszMatch ) - { - return const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch )); - } - - static LPCSTR __stdcall StringFindChar( LPCSTR pszBlock, char chMatch ) - { - return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch )); - } - - static LPCSTR __stdcall StringFindCharRev( LPCSTR psz, char ch ) - { - return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch )); - } - - static LPCSTR __stdcall StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) - { - return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ), - reinterpret_cast< const unsigned char* >( pszMatch ))); - } - - static int __stdcall StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) - { - return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); - } - - static int __stdcall StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) - { - return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); - } - - static LPSTR __stdcall StringUppercase( LPSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz )) ); -#pragma warning (pop) - } - - static LPSTR __stdcall StringLowercase( LPSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz )) ); -#pragma warning (pop) - } - - static LPSTR __stdcall StringUppercase( LPSTR psz, size_t size ) - { - #if _MSC_VER >= 1400 - _mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size); - #else - _mbsupr(reinterpret_cast< unsigned char* >( psz )); - #endif - return psz; - } - - static LPSTR __stdcall StringLowercase( LPSTR psz, size_t size ) - { - #if _MSC_VER >= 1400 - _mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size ); - #else - _mbslwr(reinterpret_cast< unsigned char* >( psz )); - #endif - return psz; - } - - static LPSTR __stdcall StringReverse( LPSTR psz ) - { - return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz )) ); - } - - static int __stdcall GetFormattedLength( LPCSTR pszFormat, va_list args ); - - static int __stdcall Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return vsprintf( pszBuffer, pszFormat, args ); -#pragma warning (pop) - - } - - static int __stdcall Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ); - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) - { - // Returns required buffer length in XCHARs - return int( strlen( pszSrc )); - } - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) - { - (void)pszSrc; - // Returns required buffer length in XCHARs - return nLength; - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSource ) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1; - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSource, int nLength ) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL ); - } - - static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1 ) - { - if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } - // nLen is in XCHARs - memcpy_s( pszDest, nDestLength*sizeof( char ), - pszSrc, nSrcLength*sizeof( char )); - } - - static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) - { - // nLen is in XCHARs - ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL ); - } - - static void ConvertToOem( _CharType* pstrString) - { - BOOL fSuccess=::CharToOemA(pstrString, pstrString); - } - - static void ConvertToAnsi( _CharType* pstrString) - { - BOOL fSuccess=::OemToCharA(pstrString, pstrString); - } - - static void ConvertToOem( _CharType* pstrString, size_t size) - { - if(size>UINT_MAX) - { - return; - } - DWORD dwSize=static_cast(size); - BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize); - } - - static void ConvertToAnsi( _CharType* pstrString, size_t size) - { - if(size>UINT_MAX) - return; - - DWORD dwSize=static_cast(size); - BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize); - } - - static void __stdcall FloodCharacters( char ch, int nLength, char* pch ) - { - // nLength is in XCHARs - memset( pch, ch, nLength ); - } - - static BSTR __stdcall AllocSysString( const char* pchData, int nDataLength ) - { - int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); - BSTR bstr = ::SysAllocStringLen( NULL, nLen ); - if ( bstr != NULL ) - ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, bstr, nLen ); - - return bstr; - } - - static BOOL __stdcall ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) - { - int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); - BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen ); - if ( bSuccess ) - ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen ); - - return bSuccess; - } - - static int __stdcall SafeStringLen( LPCSTR psz ) - { - // returns length in bytes - return (psz != NULL) ? int( strlen( psz )) : 0; - } - - static int __stdcall SafeStringLen( LPCWSTR psz ) - { - // returns length in wchar_ts - return (psz != NULL) ? int( wcslen( psz )) : 0; - } - - static int __stdcall GetCharLen( const wchar_t* pch ) - { - // returns char length - return 1; - } - - static int __stdcall GetCharLen( const char* pch ) - { - // returns char length - return int( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); - } - - static DWORD __stdcall GetEnvironmentVariable( LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize ) - { - return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize ); - } -}; - -// specialization for wchar_t -template<> -class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > -{ - static DWORD __stdcall _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) - { - return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize ); - } - -public: - static LPWSTR __stdcall CharNext( LPCWSTR psz ) - { - return const_cast< LPWSTR >( psz+1 ); - } - - static int __stdcall IsDigit( wchar_t ch ) - { - return iswdigit( static_cast(ch)); - } - - static int __stdcall IsSpace( wchar_t ch ) - { - return iswspace( static_cast(ch)); - } - - static int __stdcall StringCompare( LPCWSTR pszA, LPCWSTR pszB ) - { - return wcscmp( pszA, pszB ); - } - - static int __stdcall StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) - { - return _wcsicmp( pszA, pszB ); - } - - static int __stdcall StringCollate( LPCWSTR pszA, LPCWSTR pszB ) - { - return wcscoll( pszA, pszB ); - } - - static int __stdcall StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) - { - return _wcsicoll( pszA, pszB ); - } - - static LPCWSTR __stdcall StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) - { - return wcsstr( pszBlock, pszMatch ); - } - - static LPWSTR __stdcall StringFindString( LPWSTR pszBlock, LPCWSTR pszMatch ) - { - return const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch )); - } - - static LPCWSTR __stdcall StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) - { - return wcschr( pszBlock, chMatch ); - } - - static LPCWSTR __stdcall StringFindCharRev( LPCWSTR psz, wchar_t ch ) - { - return wcsrchr( psz, ch ); - } - - static LPCWSTR __stdcall StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) - { - return wcspbrk( pszBlock, pszMatch ); - } - - static int __stdcall StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) - { - return (int)wcsspn( pszBlock, pszSet ); - } - - static int __stdcall StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) - { - return (int)wcscspn( pszBlock, pszSet ); - } - - static LPWSTR __stdcall StringUppercase( LPWSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return _wcsupr( psz ); -#pragma warning (pop) - } - - static LPWSTR __stdcall StringLowercase( LPWSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return _wcslwr( psz ); -#pragma warning (pop) - } - - static LPWSTR __stdcall StringUppercase( LPWSTR psz, size_t ) - { - return _wcsupr( psz ); - } - - static LPWSTR __stdcall StringLowercase( LPWSTR psz, size_t ) - { - return _wcslwr( psz ); - } - - static LPWSTR __stdcall StringReverse( LPWSTR psz ) - { - return _wcsrev( psz ); - } - - static int __stdcall GetFormattedLength( LPCWSTR pszFormat, va_list args); - - static int __stdcall Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return vswprintf( pszBuffer, pszFormat, args ); -#pragma warning (pop) - } - - static int __stdcall Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args); - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, NULL, 0 )-1; - } - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nLength, NULL, 0 ); - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc ) - { - // Returns required buffer size in wchar_ts - return (int)wcslen( pszSrc ); - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) - { - (void)pszSrc; - // Returns required buffer size in wchar_ts - return nLength; - } - - static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) - { - // nLen is in wchar_ts - ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength ); - } - - static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1 ) - { - if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } - // nLen is in wchar_ts - #if _MSC_VER >= 1400 - wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); - #else - wmemcpy(pszDest, pszSrc, nDestLength); - #endif - } - - static void __stdcall FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) - { - // nLength is in XCHARs - for ( int i = 0; i < nLength; i++ ) - { - psz[i] = ch; - } - } - - static BSTR __stdcall AllocSysString( const wchar_t* pchData, int nDataLength ) - { - return ::SysAllocStringLen( pchData, nDataLength ); - } - - static BOOL __stdcall ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) - { - return ::SysReAllocStringLen( pbstr, pchData, nDataLength ); - } - - static int __stdcall SafeStringLen( LPCSTR psz ) - { - // returns length in bytes - return (psz != NULL) ? (int)strlen( psz ) : 0; - } - - static int __stdcall SafeStringLen( LPCWSTR psz ) - { - // returns length in wchar_ts - return (psz != NULL) ? (int)wcslen( psz ) : 0; - } - - static int __stdcall GetCharLen( const wchar_t* pch ) - { - (void)pch; - // returns char length - return 1; - } - - static int __stdcall GetCharLen( const char* pch ) - { - // returns char length - return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); - } - - static DWORD __stdcall GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) - { - return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize ); - } - - static void __stdcall ConvertToOem( LPWSTR /*psz*/ ) - { - } - - static void __stdcall ConvertToAnsi( LPWSTR /*psz*/ ) - { - } - - static void __stdcall ConvertToOem( LPWSTR /*psz*/, size_t ) - { - } - - static void __stdcall ConvertToAnsi( LPWSTR /*psz*/, size_t ) - { - } -}; - -template< typename BaseType, class StringTraits > -class CMStringT : public CMSimpleStringT< BaseType > -{ -public: - typedef CMSimpleStringT< BaseType> CThisSimpleString; - typedef typename CThisSimpleString::XCHAR XCHAR; - typedef typename CThisSimpleString::PXSTR PXSTR; - typedef typename CThisSimpleString::PCXSTR PCXSTR; - typedef typename CThisSimpleString::YCHAR YCHAR; - typedef typename CThisSimpleString::PYSTR PYSTR; - typedef typename CThisSimpleString::PCYSTR PCYSTR; - -public: - CMStringT() : CThisSimpleString() - { - } - - static void __stdcall Construct( CMStringT* pString ) - { - new( pString ) CMStringT; - } - - // Copy constructor - CMStringT( const CMStringT& strSrc ) : - CThisSimpleString( strSrc ) - { - } - - CMStringT( const XCHAR* pszSrc ) : - CThisSimpleString() - { - // nDestLength is in XCHARs - *this = pszSrc; - } - - CMStringT( const YCHAR* pszSrc ) : - CThisSimpleString() - { - *this = pszSrc; - } - - - CMStringT( const unsigned char* pszSrc ) : - CThisSimpleString() - { - *this = reinterpret_cast< const char* >( pszSrc ); - } - - CMStringT( char ch, int nLength = 1 ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer ); - this->ReleaseBufferSetLength( nLength ); - } - } - - CMStringT( wchar_t ch, int nLength = 1 ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - //Convert ch to the BaseType - wchar_t pszCh[2] = { ch , 0 }; - int nBaseTypeCharLen = 1; - - if(ch != L'\0') - { - nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); - } - - XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; - StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 ); - //Allocate enough characters in String and flood (replicate) with the (converted character)*nLength - PXSTR pszBuffer = this->GetBuffer( nLength*nBaseTypeCharLen ); - if (nBaseTypeCharLen == 1) - { //Optimization for a common case - wide char translates to 1 ansi/wide char. - StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer ); - } else - { - XCHAR* p=pszBuffer; - for (int i=0 ; i < nLength ;++i) - { - for (int j=0 ; j < nBaseTypeCharLen ;++j) - { - *p=buffBaseTypeChar[j]; - ++p; - } - } - } - this->ReleaseBufferSetLength( nLength*nBaseTypeCharLen ); - delete [] buffBaseTypeChar; - } - } - - CMStringT( const XCHAR* pch, int nLength ) : - CThisSimpleString( pch, nLength ) - { - } - - CMStringT( const YCHAR* pch, int nLength ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength ); - PXSTR pszBuffer = this->GetBuffer( nDestLength ); - StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength ); - this->ReleaseBufferSetLength( nDestLength ); - } - } - - // Destructor - ~CMStringT() - { - } - - // Assignment operators - CMStringT& operator=( const CMStringT& strSrc ) - { - CThisSimpleString::operator=( strSrc ); - - return *this; - } - - CMStringT& operator=( PCXSTR pszSrc ) - { - CThisSimpleString::operator=( pszSrc ); - - return *this; - } - - CMStringT& operator=( PCYSTR pszSrc ) - { - // nDestLength is in XCHARs - int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0; - if ( nDestLength > 0 ) - { - PXSTR pszBuffer = this->GetBuffer( nDestLength ); - StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc); - this->ReleaseBufferSetLength( nDestLength ); - } - else - { - this->Empty(); - } - - return *this; - } - - CMStringT& operator=( const unsigned char* pszSrc ) - { - return operator=( reinterpret_cast< const char* >( pszSrc )); - } - - CMStringT& operator=( char ch ) - { - char ach[2] = { ch, 0 }; - - return operator=( ach ); - } - - CMStringT& operator=( wchar_t ch ) - { - wchar_t ach[2] = { ch, 0 }; - - return operator=( ach ); - } - -// CMStringT& operator=( const VARIANT& var ); - - CMStringT& operator+=( const CMStringT& str ) - { - CThisSimpleString::operator+=( str ); - return *this; - } - - CMStringT& operator+=( const CThisSimpleString& str ) - { - CThisSimpleString::operator+=( str ); - return *this; - } - - CMStringT& operator+=( PCXSTR pszSrc ) - { - CThisSimpleString::operator+=( pszSrc ); - return *this; - } -// template< int t_nSize > -// CMStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc ) -// { -// CThisSimpleString::operator+=( strSrc ); -// -// return *this; -// } - CMStringT& operator+=( PCYSTR pszSrc ) - { - CMStringT str( pszSrc ); - - return operator+=( str ); - } - - CMStringT& operator+=( char ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - CMStringT& operator+=( unsigned char ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - CMStringT& operator+=( wchar_t ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - // Comparison - - int Compare( PCXSTR psz ) const - { - return StringTraits::StringCompare( this->GetString(), psz ); - } - - int CompareNoCase( PCXSTR psz ) const - { - return StringTraits::StringCompareIgnore( this->GetString(), psz ); - } - - int Collate( PCXSTR psz ) const - { - return StringTraits::StringCollate( this->GetString(), psz ); - } - - int CollateNoCase( PCXSTR psz ) const - { - return StringTraits::StringCollateIgnore( this->GetString(), psz ); - } - - // Advanced manipulation - - // Delete 'nCount' characters, starting at index 'iIndex' - int Delete( int iIndex, int nCount = 1 ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( nCount < 0 ) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount + iIndex > nLength ) - { - nCount = nLength-iIndex; - } - if ( nCount > 0 ) - { - int nNewLength = nLength-nCount; - int nXCHARsToCopy = nLength-(iIndex+nCount)+1; - PXSTR pszBuffer = this->GetBuffer(); - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); - #endif - this->ReleaseBufferSetLength( nNewLength ); - } - - return this->GetLength(); - } - - // Insert character 'ch' before index 'iIndex' - int Insert( int iIndex, XCHAR ch ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( iIndex > this->GetLength()) - iIndex = this->GetLength(); - - int nNewLength = this->GetLength()+1; - - PXSTR pszBuffer = this->GetBuffer( nNewLength ); - - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); - #endif - pszBuffer[iIndex] = ch; - - this->ReleaseBufferSetLength( nNewLength ); - return nNewLength; - } - - // Insert string 'psz' before index 'iIndex' - int Insert( int iIndex, PCXSTR psz ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( iIndex > this->GetLength()) - { - iIndex = this->GetLength(); - } - - // nInsertLength and nNewLength are in XCHARs - int nInsertLength = StringTraits::SafeStringLen( psz ); - int nNewLength = this->GetLength(); - if ( nInsertLength > 0 ) - { - nNewLength += nInsertLength; - - PXSTR pszBuffer = this->GetBuffer( nNewLength ); - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); - memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), psz, nInsertLength*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); - memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR )); - #endif - this->ReleaseBufferSetLength( nNewLength ); - } - - return nNewLength; - } - - // Replace all occurrences of character 'chOld' with character 'chNew' - int Replace( XCHAR chOld, XCHAR chNew ) - { - int nCount = 0; - - // short-circuit the nop case - if ( chOld != chNew ) - { - // otherwise modify each character that matches in the string - bool bCopied = false; - PXSTR pszBuffer = const_cast< PXSTR >( this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). - - int nLength = this->GetLength(); - int iChar = 0; - while( iChar < nLength ) - { - // replace instances of the specified character only - if ( pszBuffer[iChar] == chOld ) - { - if ( !bCopied ) - { - bCopied = true; - pszBuffer = this->GetBuffer( nLength ); - } - pszBuffer[iChar] = chNew; - nCount++; - } - iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer ); - } - if ( bCopied ) - { - this->ReleaseBufferSetLength( nLength ); - } - } - - return nCount; - } - - // Replace all occurrences of string 'pszOld' with string 'pszNew' - int Replace( PCXSTR pszOld, PCXSTR pszNew ) - { - // can't have empty or NULL lpszOld - - // nSourceLen is in XCHARs - int nSourceLen = StringTraits::SafeStringLen( pszOld ); - if ( nSourceLen == 0 ) - return 0; - // nReplacementLen is in XCHARs - int nReplacementLen = StringTraits::SafeStringLen( pszNew ); - - // loop once to figure out the size of the result string - int nCount = 0; - { - PCXSTR pszStart = this->GetString(); - PCXSTR pszEnd = pszStart+this->GetLength(); - while( pszStart < pszEnd ) - { - PCXSTR pszTarget; - while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL) - { - nCount++; - pszStart = pszTarget+nSourceLen; - } - pszStart += StringTraits::SafeStringLen( pszStart )+1; - } - } - - // if any changes were made, make them - if ( nCount > 0 ) - { - // if the buffer is too small, just - // allocate a new buffer (slow but sure) - int nOldLength = this->GetLength(); - int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; - - PXSTR pszBuffer = this->GetBuffer( __max( nNewLength, nOldLength )); - - PXSTR pszStart = pszBuffer; - PXSTR pszEnd = pszStart+nOldLength; - - // loop again to actually do the work - while( pszStart < pszEnd ) - { - PXSTR pszTarget; - while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL ) - { - int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); - memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), - pszTarget+nSourceLen, nBalance*sizeof( XCHAR )); - memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), - pszNew, nReplacementLen*sizeof( XCHAR )); - pszStart = pszTarget+nReplacementLen; - pszTarget[nReplacementLen+nBalance] = 0; - nOldLength += (nReplacementLen-nSourceLen); - } - pszStart += StringTraits::SafeStringLen( pszStart )+1; - } - this->ReleaseBufferSetLength( nNewLength ); - } - - return nCount; - } - - // Remove all occurrences of character 'chRemove' - int Remove( XCHAR chRemove ) - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - - PXSTR pszSource = pszBuffer; - PXSTR pszDest = pszBuffer; - PXSTR pszEnd = pszBuffer+nLength; - - while( pszSource < pszEnd ) - { - PXSTR pszNewSource = StringTraits::CharNext( pszSource ); - if ( *pszSource != chRemove ) - { - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - size_t NewSourceGap = (pszNewSource-pszSource); - PXSTR pszNewDest = pszDest + NewSourceGap; - size_t i = 0; - for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) - { - *pszDest = *pszSource; - pszSource++; - pszDest++; - } - } - pszSource = pszNewSource; - } - *pszDest = 0; - int nCount = int( pszSource-pszDest ); - this->ReleaseBufferSetLength( nLength-nCount ); - - return nCount; - } - - CMStringT Tokenize( PCXSTR pszTokens, int& iStart ) const - { - if ( (pszTokens == NULL) || (*pszTokens == (XCHAR)0)) - { - if (iStart < this->GetLength()) - return CMStringT( this->GetString()+iStart ); - } - else - { - PCXSTR pszPlace = this->GetString()+iStart; - PCXSTR pszEnd = this->GetString()+this->GetLength(); - if ( pszPlace < pszEnd ) - { - int nIncluding = StringTraits::StringSpanIncluding( pszPlace, pszTokens ); - - if ( (pszPlace+nIncluding) < pszEnd ) - { - pszPlace += nIncluding; - int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens ); - - int iFrom = iStart+nIncluding; - int nUntil = nExcluding; - iStart = iFrom+nUntil+1; - - return Mid( iFrom, nUntil ); - } - } - } - - // return empty string, done tokenizing - iStart = -1; - - return CMStringT(); - } - - // find routines - - // Find the first occurrence of character 'ch', starting at index 'iStart' - int Find( XCHAR ch, int iStart = 0 ) const - { - // nLength is in XCHARs - int nLength = this->GetLength(); - if ( iStart < 0 || iStart >= nLength) - return -1; - - // find first single character - PCXSTR psz = StringTraits::StringFindChar( this->GetString()+iStart, ch ); - - // return -1 if not found and index otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // look for a specific sub-string - - // Find the first occurrence of string 'pszSub', starting at index 'iStart' - int Find( PCXSTR pszSub, int iStart = 0 ) const - { - // iStart is in XCHARs - if(pszSub == NULL) - return -1; - - // nLength is in XCHARs - int nLength = this->GetLength(); - if ( iStart < 0 || iStart > nLength ) - return -1; - - // find first matching substring - PCXSTR psz = StringTraits::StringFindString( this->GetString()+iStart, pszSub ); - - // return -1 for not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // Find the first occurrence of any of the characters in string 'pszCharSet' - int FindOneOf( PCXSTR pszCharSet ) const - { - PCXSTR psz = StringTraits::StringScanSet( this->GetString(), pszCharSet ); - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // Find the last occurrence of character 'ch' - int ReverseFind( XCHAR ch ) const - { - // find last single character - PCXSTR psz = StringTraits::StringFindCharRev( this->GetString(), ch ); - - // return -1 if not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // manipulation - - // Convert the string to uppercase - CMStringT& MakeUpper() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringUppercase( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // Convert the string to lowercase - CMStringT& MakeLower() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringLowercase( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // Reverse the string - CMStringT& MakeReverse() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringReverse( pszBuffer ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // trimming - - // Remove all trailing whitespace - CMStringT& TrimRight() - { - // find beginning of trailing spaces by starting - // at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( StringTraits::IsSpace( *psz )) - { - if ( pszLast == NULL ) - pszLast = psz; - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at trailing space start - int iLast = int( pszLast-this->GetString()); - - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all leading whitespace - CMStringT& TrimLeft() - { - // find first non-space character - - PCXSTR psz = this->GetString(); - - while( StringTraits::IsSpace( *psz )) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Remove all leading and trailing whitespace - CMStringT& Trim() - { - return TrimRight().TrimLeft(); - } - - // Remove all leading and trailing occurrences of character 'chTarget' - CMStringT& Trim( XCHAR chTarget ) - { - return TrimRight( chTarget ).TrimLeft( chTarget ); - } - - // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' - CMStringT& Trim( PCXSTR pszTargets ) - { - return TrimRight( pszTargets ).TrimLeft( pszTargets ); - } - - // trimming anything (either side) - - // Remove all trailing occurrences of character 'chTarget' - CMStringT& TrimRight( XCHAR chTarget ) - { - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( *psz == chTarget ) - { - if ( pszLast == NULL ) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at left-most matching character - int iLast = int( pszLast-this->GetString()); - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all trailing occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimRight( PCXSTR pszTargets ) - { - // if we're not trimming anything, we're not doing any work - if ( (pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( StringTraits::StringFindChar( pszTargets, *psz ) != NULL ) - { - if ( pszLast == NULL ) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at left-most matching character - int iLast = int( pszLast-this->GetString()); - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all leading occurrences of character 'chTarget' - CMStringT& TrimLeft( XCHAR chTarget ) - { - // find first non-matching character - PCXSTR psz = this->GetString(); - - while( chTarget == *psz ) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Remove all leading occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimLeft( PCXSTR pszTargets ) - { - // if we're not trimming anything, we're not doing any work - if ( (pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - PCXSTR psz = this->GetString(); - while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL)) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Convert the string to the OEM character set - void AnsiToOem() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::ConvertToOem( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - } - - // Convert the string to the ANSI character set - void OemToAnsi() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::ConvertToAnsi( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - } - - // Very simple sub-string extraction - - // Return the substring starting at index 'iFirst' - CMStringT Mid( int iFirst ) const - { - return Mid( iFirst, this->GetLength()-iFirst ); - } - - // Return the substring starting at index 'iFirst', with length 'nCount' - CMStringT Mid( int iFirst, int nCount ) const - { - // nCount is in XCHARs - - // out-of-bounds requests return sensible things - if (iFirst < 0) - iFirst = 0; - if (nCount < 0) - nCount = 0; - - if ( (iFirst + nCount) > this->GetLength()) - nCount = this->GetLength()-iFirst; - - if ( iFirst > this->GetLength()) - nCount = 0; - - // optimize case of returning entire string - if ( (iFirst == 0) && ((iFirst+nCount) == this->GetLength())) - return *this; - - return CMStringT( this->GetString()+iFirst, nCount ); - } - - // Return the substring consisting of the rightmost 'nCount' characters - CMStringT Right( int nCount ) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount >= nLength ) - { - return *this; - } - - return CMStringT( this->GetString()+nLength-nCount, nCount ); - } - - // Return the substring consisting of the leftmost 'nCount' characters - CMStringT Left( int nCount ) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount >= nLength ) - return *this; - - return CMStringT( this->GetString(), nCount ); - } - - // Return the substring consisting of the leftmost characters in the set 'pszCharSet' - CMStringT SpanIncluding( PCXSTR pszCharSet ) const - { - return Left( StringTraits::StringSpanIncluding( this->GetString(), pszCharSet )); - } - - // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' - CMStringT SpanExcluding( PCXSTR pszCharSet ) const - { - return Left( StringTraits::StringSpanExcluding( this->GetString(), pszCharSet )); - } - - // Format data using format string 'pszFormat' - void Format( PCXSTR pszFormat, ... ); - - // Append formatted data using format string 'pszFormat' - void AppendFormat( PCXSTR pszFormat, ... ); - - void AppendFormatV( PCXSTR pszFormat, va_list args ) - { - int nCurrentLength = this->GetLength(); - int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args ); - PXSTR pszBuffer = this->GetBuffer( nCurrentLength+nAppendLength ); - StringTraits::Format( pszBuffer+nCurrentLength, - nAppendLength+1, pszFormat, args ); - this->ReleaseBufferSetLength( nCurrentLength+nAppendLength ); - } - - void FormatV( PCXSTR pszFormat, va_list args ) - { - int nLength = StringTraits::GetFormattedLength( pszFormat, args ); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::Format( pszBuffer, nLength+1, pszFormat, args ); - this->ReleaseBufferSetLength( nLength ); - } - - // OLE BSTR support - - // Allocate a BSTR containing a copy of the string - BSTR AllocSysString() const - { - BSTR bstrResult = StringTraits::AllocSysString( this->GetString(), this->GetLength()); - return bstrResult; - } - - BSTR SetSysString( BSTR* pbstr ) const - { - StringTraits::ReAllocSysString( this->GetString(), pbstr, this->GetLength()); - return *pbstr; - } - - // Set the string to the value of environment variable 'pszVar' - BOOL GetEnvironmentVariable( PCXSTR pszVar ) - { - ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 ); - BOOL bRetVal = FALSE; - - if ( nLength == 0 ) - { - this->Empty(); - } - else - { - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength ); - this->ReleaseBuffer(); - bRetVal = TRUE; - } - - return bRetVal; - } - - // Load the string from resource 'nID' - BOOL LoadString( UINT nID ) - { - HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID ); - if ( hInst == NULL ) - return FALSE; - - return LoadString( hInst, nID ); - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, const CMStringT& str2 ) - { - CMStringT strResult; - - Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, PCXSTR psz2 ) - { - CMStringT strResult; - - Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 )); - - return strResult; - } - - friend CMStringT __stdcall operator+( PCXSTR psz1, const CMStringT& str2 ) - { - CMStringT strResult; - - Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, wchar_t ch2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch2 ); - - Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, char ch2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch2 ); - - Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); - - return strResult; - } - - friend CMStringT __stdcall operator+( wchar_t ch1, const CMStringT& str2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch1 ); - - Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( char ch1, const CMStringT& str2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch1 ); - - Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); - - return strResult; - } - - friend bool __stdcall operator==( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) == 0; - } - - friend bool __stdcall operator==( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) == 0; - } - - friend bool __stdcall operator==( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) == 0; - } - - friend bool __stdcall operator==( const CMStringT& str1, PCYSTR psz2 ) - { - CMStringT str2( psz2 ); - - return str1 == str2; - } - - friend bool __stdcall operator==( PCYSTR psz1, const CMStringT& str2 ) - { - CMStringT str1( psz1 ); - - return str1 == str2; - } - - friend bool __stdcall operator!=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) != 0; - } - - friend bool __stdcall operator!=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) != 0; - } - - friend bool __stdcall operator!=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) != 0; - } - - friend bool __stdcall operator!=( const CMStringT& str1, PCYSTR psz2 ) - { - CMStringT str2( psz2 ); - - return str1 != str2; - } - - friend bool __stdcall operator!=( PCYSTR psz1, const CMStringT& str2 ) - { - CMStringT str1( psz1 ); - - return str1 != str2; - } - - friend bool __stdcall operator<( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) < 0; - } - - friend bool __stdcall operator<( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) < 0; - } - - friend bool __stdcall operator<( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) > 0; - } - - friend bool __stdcall operator>( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) > 0; - } - - friend bool __stdcall operator>( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) > 0; - } - - friend bool __stdcall operator>( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) < 0; - } - - friend bool __stdcall operator<=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) <= 0; - } - - friend bool __stdcall operator<=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) <= 0; - } - - friend bool __stdcall operator<=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) >= 0; - } - - friend bool __stdcall operator>=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) >= 0; - } - - friend bool __stdcall operator>=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) >= 0; - } - - friend bool __stdcall operator>=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) <= 0; - } - - friend bool __stdcall operator==( XCHAR ch1, const CMStringT& str2 ) - { - return (str2.GetLength() == 1) && (str2[0] == ch1); - } - - friend bool __stdcall operator==( const CMStringT& str1, XCHAR ch2 ) - { - return (str1.GetLength() == 1) && (str1[0] == ch2); - } - - friend bool __stdcall operator!=( XCHAR ch1, const CMStringT& str2 ) - { - return (str2.GetLength() != 1) || (str2[0] != ch1); - } - - friend bool __stdcall operator!=( const CMStringT& str1, XCHAR ch2 ) - { - return (str1.GetLength() != 1) || (str1[0] != ch2); - } -}; - -template< typename BaseType, class StringTraits > -inline void CMStringT::Format(PCXSTR pszFormat, ... ) -{ - va_list argList; - va_start( argList, pszFormat ); - FormatV( pszFormat, argList ); - va_end( argList ); -} - -template< typename BaseType, class StringTraits > -inline void CMStringT::AppendFormat(PCXSTR pszFormat, ... ) -{ - va_list argList; - va_start( argList, pszFormat ); - AppendFormatV( pszFormat, argList ); - va_end( argList ); -} - -typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; -typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; -typedef CMStringT< TCHAR, ChTraitsCRT< TCHAR > > CMString; diff --git a/protocols/IRCG/clist.cpp b/protocols/IRCG/clist.cpp deleted file mode 100644 index 94bb460db9..0000000000 --- a/protocols/IRCG/clist.cpp +++ /dev/null @@ -1,247 +0,0 @@ - -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -BOOL CIrcProto::CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) -{ - HANDLE hContact; - HANDLE hc; - TCHAR szNick[256]; - char szService[256]; - bool bFlag = false; - - CONTACT usertemp = { (TCHAR*)name.c_str(), NULL, NULL, false, false, true}; - hc = CList_FindContact( &usertemp ); - if ( hc && DBGetContactSettingByte( hc, "CList", "NotOnList", 0) == 0 - && DBGetContactSettingByte(hc,"CList", "Hidden", 0) == 0) - { - bFlag = true; - } - - CMString contactname = name; contactname += _T(DCCSTRING); - - CONTACT user = { (TCHAR*)contactname.c_str(), NULL, NULL, false, false, true}; - hContact = CList_AddContact(&user, false, false); - setByte(hContact, "DCC", 1); - - DCCINFO* pdci = new DCCINFO; - pdci->sHostmask = hostmask; - pdci->hContact = hContact; - pdci->dwAdr = (DWORD) adr; - pdci->iPort = port; - pdci->iType = DCC_CHAT; - pdci->bSender = false; - pdci->sContactName = name; - - if ( m_DCCChatAccept == 3 || m_DCCChatAccept == 2 && bFlag ) { - CDccSession* dcc = new CDccSession( this, pdci ); - - CDccSession* olddcc = FindDCCSession(hContact); - if ( olddcc ) - olddcc->Disconnect(); - - AddDCCSession(hContact, dcc); - dcc->Connect(); - if (getByte( "MirVerAutoRequest", 1)) - PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), name.c_str()); - } - else { - CLISTEVENT cle = {0}; - cle.cbSize = sizeof(cle); - cle.hContact = (HANDLE)hContact; - cle.hDbEvent = (HANDLE)"dccchat"; - cle.flags = CLEF_TCHAR; - cle.hIcon = LoadIconEx(IDI_DCC); - mir_snprintf( szService, sizeof(szService),"%s/DblClickEvent", m_szModuleName); - cle.pszService = szService ; - mir_sntprintf( szNick, SIZEOF(szNick), TranslateT("CTCP chat request from %s"), name.c_str()); - cle.ptszTooltip = szNick; - cle.lParam = (LPARAM)pdci; - - if ( CallService( MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0)) - CallService( MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)"dccchat"); - CallService( MS_CLIST_ADDEVENT,(WPARAM) hContact,(LPARAM) &cle); - } - return TRUE; -} - -HANDLE CIrcProto::CList_AddContact(CONTACT * user, bool InList, bool SetOnline) -{ - if (user->name == NULL) - return 0; - - HANDLE hContact = CList_FindContact(user); - if ( hContact ) { - if ( InList ) - DBDeleteContactSetting( hContact, "CList", "NotOnList" ); - setTString(hContact, "Nick", user->name); - DBDeleteContactSetting(hContact, "CList", "Hidden"); - if (SetOnline && getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE) - setWord(hContact, "Status", ID_STATUS_ONLINE); - return hContact; - } - - // here we create a new one since no one is to be found - hContact = (HANDLE) CallService( MS_DB_CONTACT_ADD, 0, 0); - if ( hContact ) { - CallService( MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM)m_szModuleName ); - - if ( InList ) - DBDeleteContactSetting(hContact, "CList", "NotOnList"); - else - DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); - DBDeleteContactSetting(hContact, "CList", "Hidden"); - setTString(hContact, "Nick", user->name); - setTString(hContact, "Default", user->name); - setWord(hContact, "Status", SetOnline ? ID_STATUS_ONLINE:ID_STATUS_OFFLINE); - if ( !InList && getByte( "MirVerAutoRequestTemp", 0)) - PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user->name); - return hContact; - } - return false; -} - -HANDLE CIrcProto::CList_SetOffline(struct CONTACT * user) -{ - DBVARIANT dbv; - HANDLE hContact = CList_FindContact(user); - if ( hContact ) { - if ( !getTString( hContact, "Default", &dbv )) { - setString(hContact, "User", ""); - setString(hContact, "Host", ""); - setTString(hContact, "Nick", dbv.ptszVal); - setWord(hContact, "Status", ID_STATUS_OFFLINE); - DBFreeVariant(&dbv); - return hContact; - } } - - return 0; -} - -bool CIrcProto::CList_SetAllOffline(BYTE ChatsToo) -{ - DBVARIANT dbv; - - DisconnectAllDCCSessions(false); - - HANDLE hContact = db_find_first(); - while ( hContact ) { - char* szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0 ); - if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { - if ( getByte( hContact, "ChatRoom", 0 ) == 0 ) { - if ( getByte(hContact, "DCC", 0 ) != 0 ) { - if ( ChatsToo ) - setWord(hContact, "Status", ID_STATUS_OFFLINE); - } - else if ( !getTString( hContact, "Default", &dbv )) { - setTString( hContact, "Nick", dbv.ptszVal); - setWord( hContact, "Status", ID_STATUS_OFFLINE ); - DBFreeVariant( &dbv ); - } - DBDeleteContactSetting( hContact, m_szModuleName, "IP" ); - setString( hContact, "User", "" ); - setString( hContact, "Host", "" ); - } } - - hContact = db_find_next(hContact); - } - return true; -} - -HANDLE CIrcProto::CList_FindContact (CONTACT* user) -{ - if ( !user || !user->name ) - return 0; - - TCHAR* lowercasename = mir_tstrdup( user->name ); - CharLower(lowercasename); - - char *szProto; - DBVARIANT dbv1; - DBVARIANT dbv2; - DBVARIANT dbv3; - DBVARIANT dbv4; - DBVARIANT dbv5; - HANDLE hContact = db_find_first(); - while (hContact) { - szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); - if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { - if ( getByte( hContact, "ChatRoom", 0) == 0) { - HANDLE hContact_temp = NULL; - TCHAR* DBDefault = NULL; - TCHAR* DBNick = NULL; - TCHAR* DBWildcard = NULL; - TCHAR* DBUser = NULL; - TCHAR* DBHost = NULL; - if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; - if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; - if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; - if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; - if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; - - if ( DBWildcard ) - CharLower( DBWildcard ); - if ( IsChannel( user->name )) { - if ( DBDefault && !lstrcmpi( DBDefault, user->name )) - hContact_temp = (HANDLE)-1; - } - else if ( user->ExactNick && DBNick && !lstrcmpi( DBNick, user->name )) - hContact_temp = hContact; - - else if ( user->ExactOnly && DBDefault && !lstrcmpi( DBDefault, user->name )) - hContact_temp = hContact; - - else if ( user->ExactWCOnly ) { - if ( DBWildcard && !lstrcmpi( DBWildcard, lowercasename ) - || ( DBWildcard && !lstrcmpi( DBNick, lowercasename ) && !WCCmp( DBWildcard, lowercasename )) - || ( !DBWildcard && !lstrcmpi(DBNick, lowercasename))) - { - hContact_temp = hContact; - } - } - else if ( _tcschr(user->name, ' ' ) == 0 ) { - if (( DBDefault && !lstrcmpi(DBDefault, user->name) || DBNick && !lstrcmpi(DBNick, user->name) || - DBWildcard && WCCmp( DBWildcard, lowercasename )) - && ( WCCmp(DBUser, user->user) && WCCmp(DBHost, user->host))) - { - hContact_temp = hContact; - } } - - if ( DBDefault ) DBFreeVariant(&dbv1); - if ( DBNick ) DBFreeVariant(&dbv2); - if ( DBWildcard ) DBFreeVariant(&dbv3); - if ( DBUser ) DBFreeVariant(&dbv4); - if ( DBHost ) DBFreeVariant(&dbv5); - - if ( hContact_temp != NULL ) { - mir_free(lowercasename); - if ( hContact_temp != (HANDLE)-1 ) - return hContact_temp; - return 0; - } } } - - hContact = db_find_next(hContact); - } - mir_free(lowercasename); - return 0; -} diff --git a/protocols/IRCG/commandmonitor.cpp b/protocols/IRCG/commandmonitor.cpp deleted file mode 100644 index 79d4579ae6..0000000000 --- a/protocols/IRCG/commandmonitor.cpp +++ /dev/null @@ -1,2508 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -// This file holds functions that are called upon receiving -// certain commands from the server. - -#include "irc.h" - -using namespace irc; - -VOID CALLBACK IdentTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - ppro->KillChatTimer( ppro->IdentTimer ); - if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) - return; - - if ( ppro->IsConnected() && ppro->m_identTimer ) - ppro->KillIdent(); -} - -VOID CALLBACK TimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - ppro->KillChatTimer( ppro->InitTimer ); - if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) - return; - - if ( ppro->m_forceVisible ) - ppro->PostIrcMessage( _T("/MODE %s -i"), ppro->m_info.sNick.c_str()); - - if ( lstrlenA( ppro->m_myHost ) == 0 && ppro->IsConnected()) - ppro->DoUserhostWithReason(2, (_T("S") + ppro->m_info.sNick).c_str(), true, _T("%s"), ppro->m_info.sNick.c_str()); -} - -VOID CALLBACK KeepAliveTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - if ( !ppro->m_sendKeepAlive || ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING )) { - ppro->KillChatTimer( ppro->KeepAliveTimer ); - return; - } - - TCHAR temp2[270]; - if ( !ppro->m_info.sServerName.IsEmpty()) - mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %s"), ppro->m_info.sServerName.c_str()); - else - mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %u"), time(0)); - - if ( ppro->IsConnected()) - ppro->SendIrcMessage( temp2, false ); -} - -VOID CALLBACK OnlineNotifTimerProc3( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - if ( !ppro->m_channelAwayNotification || - ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || - ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { - ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); - ppro->m_channelsToWho = _T(""); - return; - } - - CMString name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); - if ( name.IsEmpty()) { - ppro->m_channelsToWho = _T(""); - int count = (int)CallServiceSync(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)ppro->m_szModuleName); - for ( int i = 0; i < count; i++ ) { - GC_INFO gci = {0}; - gci.Flags = BYINDEX | NAME | TYPE | COUNT; - gci.iItem = i; - gci.pszModule = ppro->m_szModuleName; - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) - if ( gci.iCount <= ppro->m_onlineNotificationLimit ) - ppro->m_channelsToWho += CMString(gci.pszName) + _T(" "); - } } - - if ( ppro->m_channelsToWho.IsEmpty()) { - ppro->SetChatTimer( ppro->OnlineNotifTimer3, 60*1000, OnlineNotifTimerProc3 ); - return; - } - - name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); - ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); - CMString temp = GetWordAddress( ppro->m_channelsToWho.c_str(), 1 ); - ppro->m_channelsToWho = temp; - if ( ppro->m_iTempCheckTime ) - ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc3 ); - else - ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc3 ); -} - -VOID CALLBACK OnlineNotifTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || - ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { - ppro->KillChatTimer( ppro->OnlineNotifTimer ); - ppro->m_namesToWho = _T(""); - return; - } - - CMString name = GetWord( ppro->m_namesToWho.c_str(), 0); - CMString name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); - - if ( name.IsEmpty() && name2.IsEmpty()) { - DBVARIANT dbv; - char* szProto; - - HANDLE hContact = db_find_first(); - while ( hContact ) { - szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); - if ( szProto != NULL && !lstrcmpiA( szProto, ppro->m_szModuleName )) { - BYTE bRoom = ppro->getByte(hContact, "ChatRoom", 0); - if ( bRoom == 0 ) { - BYTE bDCC = ppro->getByte(hContact, "DCC", 0); - BYTE bHidden = DBGetContactSettingByte(hContact,"CList", "Hidden", 0); - if ( bDCC == 0 && bHidden == 0 ) { - if ( !ppro->getTString( hContact, "Default", &dbv )) { - BYTE bAdvanced = ppro->getByte(hContact, "AdvancedMode", 0) ; - if ( !bAdvanced ) { - DBFreeVariant( &dbv ); - if ( !ppro->getTString( hContact, "Nick", &dbv )) { - ppro->m_namesToUserhost += CMString(dbv.ptszVal) + _T(" "); - DBFreeVariant( &dbv ); - } - } - else { - DBFreeVariant( &dbv ); - DBVARIANT dbv2; - - TCHAR* DBNick = NULL; - TCHAR* DBWildcard = NULL; - if ( !ppro->getTString( hContact, "Nick", &dbv )) - DBNick = dbv.ptszVal; - if ( !ppro->getTString( hContact, "UWildcard", &dbv2 )) - DBWildcard = dbv2.ptszVal; - - if ( DBNick && ( !DBWildcard || !WCCmp(CharLower(DBWildcard), CharLower(DBNick)))) - ppro->m_namesToWho += CMString(DBNick) + _T(" "); - else if ( DBWildcard ) - ppro->m_namesToWho += CMString(DBWildcard) + _T(" "); - - if ( DBNick ) DBFreeVariant(&dbv); - if ( DBWildcard ) DBFreeVariant(&dbv2); - } } } } } - - hContact = db_find_next(hContact); - } } - - if ( ppro->m_namesToWho.IsEmpty() && ppro->m_namesToUserhost.IsEmpty()) { - ppro->SetChatTimer( ppro->OnlineNotifTimer, 60*1000, OnlineNotifTimerProc ); - return; - } - - name = GetWord( ppro->m_namesToWho.c_str(), 0); - name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); - CMString temp; - if ( !name.IsEmpty()) { - ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); - temp = GetWordAddress( ppro->m_namesToWho.c_str(), 1 ); - ppro->m_namesToWho = temp; - } - - if ( !name2.IsEmpty()) { - CMString params; - for ( int i = 0; i < 3; i++ ) { - params = _T(""); - for ( int j = 0; j < 5; j++ ) - params += GetWord( ppro->m_namesToUserhost, i *5 + j) + _T(" "); - - if ( params[0] != ' ' ) - ppro->DoUserhostWithReason(1, CMString(_T("S")) + params, true, params); - } - temp = GetWordAddress( ppro->m_namesToUserhost.c_str(), 15 ); - ppro->m_namesToUserhost = temp; - } - - if ( ppro->m_iTempCheckTime ) - ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc ); - else - ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc ); -} - -int CIrcProto::AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg) -{ - if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) - return 0; - - CMString S = DoColorCodes( msg, TRUE, FALSE ); - - DBEVENTINFO dbei = {0}; - dbei.cbSize = sizeof(dbei); - dbei.szModule = m_szModuleName; - dbei.eventType = EVENTTYPE_MESSAGE; - dbei.timestamp = (DWORD)time(NULL); - dbei.flags = DBEF_SENT + DBEF_UTF; - dbei.pBlob = ( PBYTE )mir_utf8encodeW( S.c_str()); - dbei.cbBlob = (DWORD)strlen(( char* )dbei.pBlob) + 1; - CallService( MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei); - mir_free( dbei.pBlob ); - return 1; -} - -void __cdecl CIrcProto::ResolveIPThread(LPVOID di) -{ - IPRESOLVE* ipr = (IPRESOLVE *) di; - - EnterCriticalSection( &m_resolve); - - if ( ipr != NULL && (ipr->iType == IP_AUTO && lstrlenA(m_myHost) == 0 || ipr->iType == IP_MANUAL )) { - hostent* myhost = gethostbyname( ipr->sAddr.c_str()); - if ( myhost ) { - IN_ADDR in; - memcpy( &in, myhost->h_addr, 4 ); - if ( ipr->iType == IP_AUTO ) - mir_snprintf( m_myHost, sizeof( m_myHost ), "%s", inet_ntoa( in )); - else - mir_snprintf( m_mySpecifiedHostIP, sizeof( m_mySpecifiedHostIP ), "%s", inet_ntoa( in )); - } } - - LeaveCriticalSection( &m_resolve ); - delete ipr; -} - -bool CIrcProto::OnIrc_PING(const CIrcMessage* pmsg) -{ - TCHAR szResponse[100]; - mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); - SendIrcMessage( szResponse ); - return false; -} - -bool CIrcProto::OnIrc_WELCOME( const CIrcMessage* pmsg ) -{ - if ( pmsg->parameters[0] != m_info.sNick ) - m_info.sNick = pmsg->parameters[0]; - - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - static TCHAR host[1024]; - int i = 0; - CMString word = GetWord( pmsg->parameters[1].c_str(), i ); - while ( !word.IsEmpty()) { - if ( _tcschr( word.c_str(), '!') && _tcschr( word.c_str(), '@' )) { - lstrcpyn( host, word.c_str(), SIZEOF(host)); - TCHAR* p1 = _tcschr( host, '@' ); - if ( p1 ) - ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(p1+1), IP_AUTO )); - } - - word = GetWord(pmsg->parameters[1].c_str(), ++i); - } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOTOOLONG( const CIrcMessage* pmsg ) -{ - CMString command = GetNextUserhostReason(2); - if ( command[0] == 'U' ) - ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_BACKFROMAWAY( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - int Temp = m_iStatus; - m_iStatus = m_iDesiredStatus = ID_STATUS_ONLINE; - ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_ONLINE); - - if ( m_perform ) - DoPerform( "Event: Available" ); - } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_SETAWAY( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - int Temp = m_iDesiredStatus; - m_iStatus = m_iDesiredStatus = ID_STATUS_AWAY; - ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_AWAY); - - if ( m_perform ) { - switch ( m_iStatus ) { - case ID_STATUS_AWAY: - DoPerform( "Event: Away" ); - break; - case ID_STATUS_NA: - DoPerform( "Event: N/A" ); - break; - case ID_STATUS_DND: - DoPerform( "Event: DND" ); - break; - case ID_STATUS_OCCUPIED: - DoPerform( "Event: Occupied" ); - break; - case ID_STATUS_OUTTOLUNCH: - DoPerform( "Event: Out for lunch" ); - break; - case ID_STATUS_ONTHEPHONE: - DoPerform( "Event: On the phone" ); - break; - default: - m_iStatus = ID_STATUS_AWAY; - DoPerform( "Event: Away" ); - break; - } } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_JOIN( const CIrcMessage* pmsg ) -{ - if (pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming && pmsg->prefix.sNick != m_info.sNick) { - CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; - DoEvent(GC_EVENT_JOIN, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), NULL, _T("Normal"), host.c_str(), NULL, true, false); - DoEvent(GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[0].c_str(),pmsg->prefix.sNick.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_QUIT( const CIrcMessage* pmsg ) -{ - if (pmsg->m_bIncoming) - { - CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; - DoEvent(GC_EVENT_QUIT, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>0?pmsg->parameters[0].c_str():NULL, NULL, host.c_str(), NULL, true, false); - struct CONTACT user = { (LPTSTR)pmsg->prefix.sNick.c_str(), (LPTSTR)pmsg->prefix.sUser.c_str(), (LPTSTR)pmsg->prefix.sHost.c_str(), false, false, false}; - CList_SetOffline( &user ); - if ( pmsg->prefix.sNick == m_info.sNick ) { - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - gce.cbSize = sizeof(GCEVENT); - gcd.pszID = NULL; - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); - } - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_PART( const CIrcMessage* pmsg ) -{ - if ( pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming ) { - CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; - DoEvent(GC_EVENT_PART, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>1?pmsg->parameters[1].c_str():NULL, NULL, host.c_str(), NULL, true, false); - if ( pmsg->prefix.sNick == m_info.sNick ) { - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - CMString S = MakeWndID( pmsg->parameters[0].c_str()); - gce.cbSize = sizeof(GCEVENT); - gcd.ptszID = ( TCHAR* )S.c_str(); - gce.dwFlags = GC_TCHAR; - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); - } - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_KICK( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) - DoEvent( GC_EVENT_KICK, pmsg->parameters[0].c_str(), pmsg->parameters[1].c_str(), pmsg->parameters.getCount()>2?pmsg->parameters[2].c_str():NULL, pmsg->prefix.sNick.c_str(), NULL, NULL, true, false); - else - ShowMessage( pmsg ); - - if ( pmsg->parameters[1] == m_info.sNick ) { - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - CMString S = MakeWndID( pmsg->parameters[0].c_str()); - gce.cbSize = sizeof(GCEVENT); - gce.dwFlags = GC_TCHAR; - gcd.ptszID = ( TCHAR* )S.c_str(); - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); - - if ( m_rejoinIfKicked ) { - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if ( wi && wi->pszPassword ) - PostIrcMessage( _T("/JOIN %s %s"), pmsg->parameters[0].c_str(), wi->pszPassword); - else - PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[0].c_str()); - } } - - return true; -} - -bool CIrcProto::OnIrc_MODEQUERY( const CIrcMessage* pmsg ) -{ - if ( pmsg->parameters.getCount() > 2 && pmsg->m_bIncoming && IsChannel( pmsg->parameters[1] )) { - CMString sPassword = _T(""); - CMString sLimit = _T(""); - bool bAdd = false; - int iParametercount = 3; - - LPCTSTR p1 = pmsg->parameters[2].c_str(); - while ( *p1 != '\0' ) { - if ( *p1 == '+' ) - bAdd = true; - if ( *p1 == '-' ) - bAdd = false; - if ( *p1 == 'l' && bAdd ) { - if (( int )pmsg->parameters.getCount() > iParametercount ) - sLimit = pmsg->parameters[ iParametercount ]; - iParametercount++; - } - if ( *p1 == 'k' && bAdd ) { - if (( int )pmsg->parameters.getCount() > iParametercount ) - sPassword = pmsg->parameters[ iParametercount ]; - iParametercount++; - } - - p1++; - } - - AddWindowItemData( pmsg->parameters[1].c_str(), sLimit.IsEmpty() ? 0 : sLimit.c_str(), pmsg->parameters[2].c_str(), sPassword.IsEmpty() ? 0 : sPassword.c_str(), 0 ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_MODE( const CIrcMessage* pmsg ) -{ - bool flag = false; - bool bContainsValidModes = false; - CMString sModes = _T(""); - CMString sParams = _T(""); - - if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { - if ( IsChannel( pmsg->parameters[0] )) { - bool bAdd = false; - int iParametercount = 2; - LPCTSTR p1 = pmsg->parameters[1].c_str(); - - while ( *p1 != '\0' ) { - if ( *p1 == '+' ) { - bAdd = true; - sModes += _T("+"); - } - if ( *p1 == '-' ) { - bAdd = false; - sModes += _T("-"); - } - if ( *p1 == 'l' && bAdd && iParametercount < (int)pmsg->parameters.getCount()) { - bContainsValidModes = true; - sModes += _T("l"); - sParams += _T(" ") + pmsg->parameters[iParametercount]; - iParametercount++; - } - if ( *p1 == 'b' || *p1 == 'k' && iParametercount < (int)pmsg->parameters.getCount()) { - bContainsValidModes = true; - sModes += *p1; - sParams += _T(" ") + pmsg->parameters[iParametercount]; - iParametercount++; - } - if ( strchr( sUserModes.c_str(), (char)*p1 )) { - CMString sStatus = ModeToStatus( *p1 ); - if (( int )pmsg->parameters.getCount() > iParametercount ) { - if ( !_tcscmp(pmsg->parameters[2].c_str(), m_info.sNick.c_str())) { - char cModeBit = -1; - CHANNELINFO* wi = (CHANNELINFO *)DoEvent( GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, false, false, 0 ); - switch (*p1) { - case 'v': cModeBit = 0; break; - case 'h': cModeBit = 1; break; - case 'o': cModeBit = 2; break; - case 'a': cModeBit = 3; break; - case 'q': cModeBit = 4; break; - } - - // set bit for own mode on this channel (voice/hop/op/admin/owner) - if ( bAdd && cModeBit >= 0 ) - wi->OwnMode |= ( 1 << cModeBit ); - else - wi->OwnMode &= ~( 1 << cModeBit ); - - DoEvent( GC_EVENT_SETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0 ); - } - DoEvent( bAdd ? GC_EVENT_ADDSTATUS : GC_EVENT_REMOVESTATUS, pmsg->parameters[0].c_str(), pmsg->parameters[iParametercount].c_str(), pmsg->prefix.sNick.c_str(), sStatus.c_str(), NULL, NULL, m_oldStyleModes?false:true, false); - iParametercount++; - } - } - else if (*p1 != 'b' && *p1 != ' ' && *p1 != '+' && *p1 != '-' ) { - bContainsValidModes = true; - if (*p1 != 'l' && *p1 != 'k') - sModes += *p1; - flag = true; - } - - p1++; - } - - if ( m_oldStyleModes ) { - TCHAR temp[256]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), - pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); - - CMString sMessage = temp; - for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) - sMessage += _T(" ") + pmsg->parameters[i]; - - DoEvent( GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false ); - } - else if ( bContainsValidModes ) { - for ( int i = iParametercount; i < (int)pmsg->parameters.getCount(); i++ ) - sParams += _T(" ") + pmsg->parameters[i]; - - TCHAR temp[4000]; - mir_sntprintf( temp, 3999, TranslateT( "%s sets mode %s%s" ), pmsg->prefix.sNick.c_str(), sModes.c_str(), sParams.c_str()); - DoEvent(GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), temp, NULL, NULL, NULL, true, false); - } - - if ( flag ) - PostIrcMessage( _T("/MODE %s"), pmsg->parameters[0].c_str()); - } - else { - TCHAR temp[256]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); - - CMString sMessage = temp; - for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) - sMessage += _T(" ") + pmsg->parameters[i]; - - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false); - } - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_NICK( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { - bool bIsMe = pmsg->prefix.sNick.c_str() == m_info.sNick ? true : false; - - if ( m_info.sNick == pmsg->prefix.sNick && pmsg->parameters.getCount() > 0 ) { - m_info.sNick = pmsg->parameters[0]; - setTString("Nick", m_info.sNick.c_str()); - } - - CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; - DoEvent(GC_EVENT_NICK, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, host.c_str(), NULL, true, bIsMe); - DoEvent(GC_EVENT_CHUID, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, NULL, NULL, true, false); - - struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; - HANDLE hContact = CList_FindContact(&user); - if (hContact) { - if ( getWord(hContact, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) - setWord(hContact, "Status", ID_STATUS_ONLINE); - setTString(hContact, "Nick", pmsg->parameters[0].c_str()); - setTString(hContact, "User", pmsg->prefix.sUser.c_str()); - setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); - } - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_NOTICE( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - if ( IsCTCP( pmsg )) - return true; - - if ( !m_ignore || !IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'n' )) { - CMString S; - CMString S2; - CMString S3; - if ( pmsg->prefix.sNick.GetLength() > 0 ) - S = pmsg->prefix.sNick; - else - S = m_info.sNetwork; - S3 = m_info.sNetwork; - if ( IsChannel( pmsg->parameters[0] )) - S2 = pmsg->parameters[0].c_str(); - else { - GC_INFO gci = {0}; - gci.Flags = BYID | TYPE; - gci.pszModule = m_szModuleName; - - CMString S3 = GetWord( pmsg->parameters[1].c_str(), 0); - if ( S3[0] == '[' && S3[1] == '#' && S3[S3.GetLength()-1] == ']' ) { - S3.Delete(S3.GetLength()-1, 1); - S3.Delete(0,1); - CMString Wnd = MakeWndID( S3.c_str()); - gci.pszID = ( TCHAR* )Wnd.c_str(); - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) - S2 = GetWord( gci.pszID, 0 ); - else - S2 = _T(""); - } - else S2 = _T(""); - } - DoEvent(GC_EVENT_NOTICE, S2.IsEmpty() ? 0 : S2.c_str(), S.c_str(), pmsg->parameters[1].c_str(), NULL, S3.c_str(), NULL, true, false); - } - } - else ShowMessage( pmsg ); - - return true; -} - -bool CIrcProto::OnIrc_YOURHOST( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - static const TCHAR* lpszFmt = _T("Your host is %99[^ \x5b,], running version %99s"); - TCHAR szHostName[100], szVersion[100]; - if ( _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szHostName, &szVersion) > 0 ) - m_info.sServerName = szHostName; - if ( pmsg->parameters[0] != m_info.sNick) - m_info.sNick = pmsg->parameters[0]; - } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_INVITE( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && ( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'i' ))) - return true; - - if ( pmsg->m_bIncoming && m_joinOnInvite && pmsg->parameters.getCount() >1 && lstrcmpi(pmsg->parameters[0].c_str(), m_info.sNick.c_str()) == 0 ) - PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[1].c_str()); - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_PINGPONG( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->sCommand == _T("PING")) { - TCHAR szResponse[100]; - mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); - SendIrcMessage( szResponse ); - } - - return true; -} - -bool CIrcProto::OnIrc_PRIVMSG( const CIrcMessage* pmsg ) -{ - if ( pmsg->parameters.getCount() > 1 ) { - if ( IsCTCP( pmsg )) - return true; - - CMString mess = pmsg->parameters[1]; - bool bIsChannel = IsChannel(pmsg->parameters[0]); - - if ( pmsg->m_bIncoming && !bIsChannel ) { - CCSDATA ccs = {0}; - PROTORECVEVENT pre; - - mess = DoColorCodes( mess.c_str(), TRUE, FALSE ); - ccs.szProtoService = PSR_MESSAGE; - - struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; - - if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_MESSAGE )) - if ( !CList_FindContact( &user )) - return true; - - if (( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' ))) { - HANDLE hContact = CList_FindContact( &user ); - if ( !hContact || ( hContact && DBGetContactSettingByte( hContact,"CList", "Hidden", 0) == 1 )) - return true; - } - - ccs.hContact = CList_AddContact( &user, false, true ); - ccs.lParam = (LPARAM)⪯ - pre.timestamp = (DWORD)time(NULL); - pre.flags = PREF_UTF; - pre.szMessage = mir_utf8encodeW( mess.c_str()); - setTString(ccs.hContact, "User", pmsg->prefix.sUser.c_str()); - setTString(ccs.hContact, "Host", pmsg->prefix.sHost.c_str()); - CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); - mir_free( pre.szMessage ); - return true; - } - - if ( bIsChannel ) { - if ( !(pmsg->m_bIncoming && m_ignore && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm' ))) { - if ( !pmsg->m_bIncoming ) - ReplaceString( mess, _T("%%"), _T("%")); - DoEvent(GC_EVENT_MESSAGE, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); - } - return true; - } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::IsCTCP( const CIrcMessage* pmsg ) -{ - // is it a ctcp command, i e is the first and last characer of a PRIVMSG or NOTICE text ASCII 1 - CMString mess = pmsg->parameters[1]; - if ( !( mess.GetLength() > 3 && mess[0] == 1 && mess[ mess.GetLength()-1] == 1 )) - return false; - - // set mess to contain the ctcp command, excluding the leading and trailing ASCII 1 - mess.Delete(0,1); - mess.Delete(mess.GetLength()-1,1); - - // exploit??? - if ( mess.Find(1) != -1 || mess.Find( _T("%newl")) != -1 ) { - TCHAR temp[4096]; - mir_sntprintf(temp, SIZEOF(temp), TranslateT( "CTCP ERROR: Malformed CTCP command received from %s!%s@%s. Possible attempt to take control of your irc client registered"), pmsg->prefix.sNick.c_str(), pmsg->prefix.sUser.c_str(), pmsg->prefix.sHost.c_str()); - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); - return true; - } - - // extract the type of ctcp command - CMString ocommand = GetWord(mess.c_str(), 0); - CMString command = GetWord(mess.c_str(), 0); - command.MakeLower(); - - // should it be ignored? - if ( m_ignore ) { - if ( IsChannel( pmsg->parameters[0] )) { - if ( command == _T("action") && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm')) - return true; - } - else { - if ( command == _T("action")) { - if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' )) - return true; - } - else if ( command == _T("dcc")) { - if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'd' )) - return true; - } - else if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'c' )) - return true; - } } - - if ( pmsg->sCommand == _T("PRIVMSG")) { - // incoming ACTION - if ( command == _T("action")) { - mess.Delete(0,6); - - if ( IsChannel( pmsg->parameters[0] )) { - if ( mess.GetLength() > 1 ) { - mess.Delete(0,1); - if ( !pmsg->m_bIncoming ) - ReplaceString(mess, _T("%%"), _T("%")); - - DoEvent(GC_EVENT_ACTION, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); - } - } - else if (pmsg->m_bIncoming) - { - mess.Insert(0, pmsg->prefix.sNick.c_str()); - mess.Insert(0, _T("* ")); - mess.Insert(mess.GetLength(), _T(" *")); - CIrcMessage msg = *pmsg; - msg.parameters[1] = mess; - OnIrc_PRIVMSG(&msg); - } - } - // incoming FINGER - else if (pmsg->m_bIncoming && command == _T("finger")) { - PostIrcMessage( _T("/NOTICE %s \001FINGER %s (%s)\001"), pmsg->prefix.sNick.c_str(), m_name, m_userID); - - TCHAR temp[300]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP FINGER requested by %s"), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming VERSION - else if (pmsg->m_bIncoming && command == _T("version")) { - PostIrcMessage( _T("/NOTICE %s \001VERSION Miranda NG %s (IRC v.%s%s), (c) 2003-09 J.Persson, G.Hazan\001"), - pmsg->prefix.sNick.c_str(), _T("%mirver"), _T("%version"), - _T(" Unicode")); - - TCHAR temp[300]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP VERSION requested by %s"), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming SOURCE - else if (pmsg->m_bIncoming && command == _T("source")) { - PostIrcMessage( _T("/NOTICE %s \001SOURCE Get Miranda IRC here: http://miranda-ng.org/ \001"), pmsg->prefix.sNick.c_str()); - - TCHAR temp[300]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP SOURCE requested by %s"), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming USERINFO - else if (pmsg->m_bIncoming && command == _T("userinfo")) { - PostIrcMessage( _T("/NOTICE %s \001USERINFO %s\001"), pmsg->prefix.sNick.c_str(), m_userInfo ); - - TCHAR temp[300]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP USERINFO requested by %s") , pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming PING - else if (pmsg->m_bIncoming && command == _T("ping")) { - PostIrcMessage( _T("/NOTICE %s \001%s\001"), pmsg->prefix.sNick.c_str(), mess.c_str()); - - TCHAR temp[300]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP PING requested by %s"), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming TIME - else if (pmsg->m_bIncoming && command == _T("time")) { - TCHAR temp[300]; - time_t tim = time(NULL); - lstrcpyn( temp, _tctime( &tim ), 25 ); - PostIrcMessage( _T("/NOTICE %s \001TIME %s\001"), pmsg->prefix.sNick.c_str(), temp); - - mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP TIME requested by %s"), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } - - // incoming DCC request... lots of stuff happening here... - else if (pmsg->m_bIncoming && command == _T("dcc")) { - CMString type = GetWord(mess.c_str(), 1); - type.MakeLower(); - - // components of a dcc message - CMString sFile = _T(""); - DWORD dwAdr = 0; - int iPort = 0; - unsigned __int64 dwSize = 0; - CMString sToken = _T(""); - bool bIsChat = ( type == _T("chat")); - - // 1. separate the dcc command into the correct pieces - if ( bIsChat || type == _T("send")) { - // if the filename is surrounded by quotes, do this - if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { - int end = 0; - int begin = mess.Find('\"', 0); - if ( begin >= 0 ) { - end = mess.Find('\"', begin + 1); - if ( end >= 0 ) { - sFile = mess.Mid(begin+1, end-begin-1); - - begin = mess.Find(' ', end); - if ( begin >= 0 ) { - CMString rest = mess.Mid(begin, mess.GetLength()); - dwAdr = _tcstoul(GetWord(rest.c_str(), 0).c_str(), NULL, 10); - iPort = _ttoi(GetWord(rest.c_str(), 1).c_str()); - dwSize = _ttoi64(GetWord(rest.c_str(), 2).c_str()); - sToken = GetWord(rest.c_str(), 3); - } } } - } - // ... or try another method of separating the dcc command - else if ( !GetWord(mess.c_str(), (bIsChat) ? 4 : 5 ).IsEmpty()) { - int index = (bIsChat) ? 4 : 5; - bool bFlag = false; - - // look for the part of the ctcp command that contains adress, port and size - while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { - CMString sTemp; - - if ( type == _T("chat")) - sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); - else - sTemp = GetWord(mess.c_str(), index-2) + GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); - - // if all characters are number it indicates we have found the adress, port and size parameters - int ind = 0; - while ( sTemp[ind] != '\0' ) { - if ( !_istdigit( sTemp[ind] )) - break; - ind++; - } - - if ( sTemp[ind] == '\0' && GetWord( mess.c_str(), index + ((bIsChat) ? 1 : 2 )).IsEmpty()) - bFlag = true; - index++; - } - - if ( bFlag ) { - TCHAR* p1 = _tcsdup( GetWordAddress(mess.c_str(), 2 )); - TCHAR* p2 = ( TCHAR* )GetWordAddress( p1, index-5 ); - - if ( type == _T("send")) { - if ( p2 > p1 ) { - p2--; - while( p2 != p1 && *p2 == ' ' ) { - *p2 = '\0'; - p2--; - } - sFile = p1; - } - } - else sFile = _T("chat"); - - free( p1 ); - - dwAdr = _tcstoul(GetWord(mess.c_str(), index - (bIsChat?2:3)).c_str(), NULL, 10); - iPort = _ttoi(GetWord(mess.c_str(), index - (bIsChat?1:2)).c_str()); - dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); - sToken = GetWord(mess.c_str(), index); - } } - } - else if (type == _T("accept") || type == _T("resume")) { - // if the filename is surrounded by quotes, do this - if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { - int end = 0; - int begin = mess.Find('\"', 0); - if ( begin >= 0 ) { - end = mess.Find('\"', begin + 1); - if ( end >= 0 ) { - sFile = mess.Mid(begin+1, end); - - begin = mess.Find(' ', end); - if ( begin >= 0 ) { - CMString rest = mess.Mid(begin, mess.GetLength()); - iPort = _ttoi(GetWord(rest.c_str(), 0).c_str()); - dwSize = _ttoi(GetWord(rest.c_str(), 1).c_str()); - sToken = GetWord(rest.c_str(), 2); - } } } - } - // ... or try another method of separating the dcc command - else if ( !GetWord(mess.c_str(), 4).IsEmpty()) { - int index = 4; - bool bFlag = false; - - // look for the part of the ctcp command that contains adress, port and size - while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { - CMString sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); - - // if all characters are number it indicates we have found the adress, port and size parameters - int ind = 0; - - while ( sTemp[ind] != '\0' ) { - if ( !_istdigit( sTemp[ind] )) - break; - ind++; - } - - if ( sTemp[ind] == '\0' && GetWord(mess.c_str(), index + 2).IsEmpty()) - bFlag = true; - index++; - } - if ( bFlag ) { - TCHAR* p1 = _tcsdup(GetWordAddress(mess.c_str(), 2)); - TCHAR* p2 = ( TCHAR* )GetWordAddress(p1, index-4); - - if ( p2 > p1 ) { - p2--; - while( p2 != p1 && *p2 == ' ' ) { - *p2 = '\0'; - p2--; - } - sFile = p1; - } - - free( p1 ); - - iPort = _ttoi(GetWord(mess.c_str(), index-2).c_str()); - dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); - sToken = GetWord(mess.c_str(), index); - } } } - // end separating dcc commands - - // 2. Check for malformed dcc commands or other errors - if ( bIsChat || type == _T("send")) { - TCHAR szTemp[256]; - szTemp[0] = '\0'; - - unsigned long ulAdr = 0; - if ( m_manualHost ) - ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); - else - ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); - - if ( bIsChat && !m_DCCChatEnabled) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); - - else if(type == _T("send") && !m_DCCFileEnabled) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer request from %s denied"),pmsg->prefix.sNick.c_str()); - - else if(type == _T("send") && !iPort && ulAdr == 0) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Reverse file transfer request from %s denied [No local IP]"),pmsg->prefix.sNick.c_str()); - - if ( sFile.IsEmpty() || dwAdr == 0 || dwSize == 0 || iPort == 0 && sToken.IsEmpty()) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); - - if ( szTemp[0] ) { - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - return true; - } - - // remove path from the filename if the remote client (stupidly) sent it - CMString sFileCorrected = sFile; - int i = sFile.ReverseFind( '\\' ); - if (i != -1 ) - sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); - sFile = sFileCorrected; - } - else if ( type == _T("accept") || type == _T("resume")) { - TCHAR szTemp[256]; - szTemp[0] = '\0'; - - if ( type == _T("resume") && !m_DCCFileEnabled) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer resume request from %s denied"),pmsg->prefix.sNick.c_str()); - - if ( sToken.IsEmpty() && iPort == 0 || sFile.IsEmpty()) - mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); - - if ( szTemp[0] ) { - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - return true; - } - - // remove path from the filename if the remote client (stupidly) sent it - CMString sFileCorrected = sFile; - int i = sFile.ReverseFind( '\\' ); - if ( i != -1 ) - sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); - sFile = sFileCorrected; - } - - // 3. Take proper actions considering type of command - - // incoming chat request - if ( bIsChat ) { - CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), 0, 0, false, false, true}; - HANDLE hContact = CList_FindContact( &user ); - - // check if it should be ignored - if ( m_DCCChatIgnore == 1 || - m_DCCChatIgnore == 2 && hContact && - DBGetContactSettingByte(hContact,"CList", "NotOnList", 0) == 0 && - DBGetContactSettingByte(hContact,"CList", "Hidden", 0) == 0) - { - CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; - CList_AddDCCChat(pmsg->prefix.sNick, host, dwAdr, iPort); // add a CHAT event to the clist - } - else { - TCHAR szTemp[512]; - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } } - - // remote requested that the file should be resumed - if ( type == _T("resume")) { - CDccSession* dcc; - if ( sToken.IsEmpty()) - dcc = FindDCCSendByPort( iPort ); - else - dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); // reverse ft - - if ( dcc ) { - InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME); - dcc->dwResumePos = dwSize; // dwSize is the resume position - PostIrcMessage( _T("/PRIVMSG %s \001DCC ACCEPT %s\001"), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 2)); - } } - - // remote accepted your request for a file resume - if ( type == _T("accept")) { - CDccSession* dcc; - if ( sToken.IsEmpty()) - dcc = FindDCCRecvByPortAndName(iPort, pmsg->prefix.sNick.c_str()); - else - dcc = FindPassiveDCCRecv(pmsg->prefix.sNick, sToken); // reverse ft - - if ( dcc ) { - InterlockedExchange( &dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME ); - dcc->dwResumePos = dwSize; // dwSize is the resume position - SetEvent( dcc->hEvent ); - } } - - if ( type == _T("send")) { - CMString sTokenBackup = sToken; - bool bTurbo = false; // TDCC indicator - - if ( !sToken.IsEmpty() && sToken[sToken.GetLength()-1] == 'T' ) { - bTurbo = true; - sToken.Delete(sToken.GetLength()-1,1); - } - - // if a token exists and the port is non-zero it is the remote - // computer telling us that is has accepted to act as server for - // a reverse filetransfer. The plugin should connect to that computer - // and start sedning the file (if the token is valid). Compare to DCC RECV - if ( !sToken.IsEmpty() && iPort ) { - CDccSession* dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); - if ( dcc ) { - dcc->SetupPassive( dwAdr, iPort ); - dcc->Connect(); - } - } - else { - struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; - if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_FILE )) - if ( !CList_FindContact( &user )) - return true; - - HANDLE hContact = CList_AddContact( &user, false, true ); - if ( hContact ) { - DCCINFO* di = new DCCINFO; - di->hContact = hContact; - di->sFile = sFile; - di->dwSize = dwSize; - di->sContactName = pmsg->prefix.sNick; - di->dwAdr = dwAdr; - di->iPort = iPort; - di->iType = DCC_SEND; - di->bSender = false; - di->bTurbo = bTurbo; - di->bSSL = false; - di->bReverse = (iPort == 0 && !sToken.IsEmpty()) ? true : false; - if ( di->bReverse ) - di->sToken = sTokenBackup; - - setTString(hContact, "User", pmsg->prefix.sUser.c_str()); - setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); - - TCHAR* tszTemp = ( TCHAR* )sFile.c_str(); - - PROTORECVFILET pre = {0}; - pre.flags = PREF_TCHAR; - pre.timestamp = (DWORD)time(NULL); - pre.fileCount = 1; - pre.ptszFiles = &tszTemp; - pre.lParam = (LPARAM)di; - - CCSDATA ccs = {0}; - ccs.szProtoService = PSR_FILE; - ccs.hContact = hContact; - ccs.lParam = (LPARAM) & pre; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } } } - // end type == "send" - } - else if ( pmsg->m_bIncoming ) { - TCHAR temp[300]; - mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s requested by %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); - } } - - // handle incoming ctcp in notices. This technique is used for replying to CTCP queries - else if(pmsg->sCommand == _T("NOTICE")) { - TCHAR szTemp[300]; - szTemp[0] = '\0'; - - //if we got incoming CTCP Version for contact in CList - then write its as MirVer for that contact! - if (pmsg->m_bIncoming && command == _T("version")) - { - struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; - HANDLE hContact = CList_FindContact(&user); - if (hContact) - setTString( hContact, "MirVer", DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); - } - - // if the whois window is visible and the ctcp reply belongs to the user in it, then show the reply in the whois window - if ( m_whoisDlg && IsWindowVisible( m_whoisDlg->GetHwnd())) { - m_whoisDlg->m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - if ( lstrcmpi(szTemp, pmsg->prefix.sNick.c_str()) == 0 ) { - if ( pmsg->m_bIncoming && (command == _T("version") || command == _T("userinfo") || command == _T("time"))) { - SetActiveWindow( m_whoisDlg->GetHwnd()); - m_whoisDlg->m_Reply.SetText( DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); - return true; - } - if (pmsg->m_bIncoming && command == _T("ping")) { - SetActiveWindow( m_whoisDlg->GetHwnd()); - int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); - TCHAR szTemp[30]; - if ( s == 1 ) - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u second"), s ); - else - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u seconds"), s ); - - m_whoisDlg->m_Reply.SetText( DoColorCodes( szTemp, TRUE, FALSE )); - return true; - } } } - - //... else show the reply in the current window - if ( pmsg->m_bIncoming && command == _T("ping")) { - int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP PING reply from %s: %u sec(s)"), pmsg->prefix.sNick.c_str(), s); - DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); - } - else { - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s reply from %s: %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 1)); - DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); - } } - - return true; -} - -bool CIrcProto::OnIrc_NAMES( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) - sNamesList += pmsg->parameters[3] + _T(" "); - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_ENDNAMES( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - CMString name = _T("a"); - int i = 0; - BOOL bFlag = false; - - // Is the user on the names list? - while ( !name.IsEmpty()) { - name = GetWord( sNamesList.c_str(), i ); - i++; - if ( !name.IsEmpty()) { - int index = 0; - while ( _tcschr( sUserModePrefixes.c_str(), name[index] )) - index++; - - if ( !lstrcmpi( name.Mid(index, name.GetLength()).c_str(), m_info.sNick.c_str())) { - bFlag = true; - break; - } } } - - if ( bFlag ) { - const TCHAR* sChanName = pmsg->parameters[1].c_str(); - if ( sChanName[0] == '@' || sChanName[0] == '*' || sChanName[0] == '=' ) - sChanName++; - - // Add a new chat window - GCSESSION gcw = {0}; - CMString sID = MakeWndID( sChanName ); - BYTE btOwnMode = 0; - gcw.cbSize = sizeof(GCSESSION); - gcw.iType = GCW_CHATROOM; - gcw.dwFlags = GC_TCHAR; - gcw.ptszID = sID.c_str(); - gcw.pszModule = m_szModuleName; - gcw.ptszName = sChanName; - if ( !CallServiceSync( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw )) { - DBVARIANT dbv; - GCDEST gcd = {0}; - GCEVENT gce = {0}; - CMString sTemp; - int i = 0; - - PostIrcMessage( _T("/MODE %s"), sChanName ); - - gcd.ptszID = ( TCHAR* )sID.c_str(); - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_ADDGROUP; - gce.time = 0; - gce.dwFlags = GC_TCHAR; - - //register the statuses - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - - gce.ptszStatus = _T("Owner"); - CallChatEvent(0, (LPARAM)&gce); - gce.ptszStatus = _T("Admin"); - CallChatEvent(0, (LPARAM)&gce); - gce.ptszStatus = _T("Op"); - CallChatEvent(0, (LPARAM)&gce); - gce.ptszStatus = _T("Halfop"); - CallChatEvent(0, (LPARAM)&gce); - gce.ptszStatus = _T("Voice"); - CallChatEvent(0, (LPARAM)&gce); - gce.ptszStatus = _T("Normal"); - CallChatEvent(0, (LPARAM)&gce); - - i = 0; - sTemp = GetWord(sNamesList.c_str(), i); - - // Fill the nicklist - while ( !sTemp.IsEmpty()) { - CMString sStat; - CMString sTemp2 = sTemp; - sStat = PrefixToStatus(sTemp[0]); - - // fix for networks like freshirc where they allow more than one prefix - while ( PrefixToStatus(sTemp[0]) != _T("Normal")) - sTemp.Delete(0,1); - - gcd.iType = GC_EVENT_JOIN; - gce.ptszUID = sTemp.c_str(); - gce.ptszNick = sTemp.c_str(); - gce.ptszStatus = sStat.c_str(); - BOOL bIsMe = ( !lstrcmpi( gce.ptszNick, m_info.sNick.c_str())) ? TRUE : FALSE; - if ( bIsMe ) { - char BitNr = -1; - switch ( sTemp2[0] ) { - case '+': BitNr = 0; break; - case '%': BitNr = 1; break; - case '@': BitNr = 2; break; - case '!': BitNr = 3; break; - case '*': BitNr = 4; break; - } - if (BitNr >=0) - btOwnMode = ( 1 << BitNr ); - else - btOwnMode = 0; - } - gce.dwFlags = GC_TCHAR; - gce.bIsMe = bIsMe; - gce.time = bIsMe?time(0):0; - CallChatEvent(0, (LPARAM)&gce); - DoEvent( GC_EVENT_SETCONTACTSTATUS, sChanName, sTemp.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE ); - // fix for networks like freshirc where they allow more than one prefix - if ( PrefixToStatus( sTemp2[0]) != _T("Normal")) { - sTemp2.Delete(0,1); - sStat = PrefixToStatus(sTemp2[0]); - while ( sStat != _T("Normal")) { - DoEvent( GC_EVENT_ADDSTATUS, sID.c_str(), sTemp.c_str(), _T("system"), sStat.c_str(), NULL, NULL, false, false, 0 ); - sTemp2.Delete(0,1); - sStat = PrefixToStatus(sTemp2[0]); - } } - - i++; - sTemp = GetWord(sNamesList.c_str(), i); - } - - //Set the item data for the window - { - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, sChanName, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if (!wi) - wi = new CHANNELINFO; - wi->OwnMode = btOwnMode; - wi->pszLimit = 0; - wi->pszMode = 0; - wi->pszPassword = 0; - wi->pszTopic = 0; - wi->codepage = getCodepage(); - DoEvent(GC_EVENT_SETITEMDATA, sChanName, NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0); - - if ( !sTopic.IsEmpty() && !lstrcmpi(GetWord(sTopic.c_str(), 0).c_str(), sChanName )) { - DoEvent(GC_EVENT_TOPIC, sChanName, sTopicName.IsEmpty() ? NULL : sTopicName.c_str(), GetWordAddress(sTopic.c_str(), 1), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); - AddWindowItemData(sChanName, 0, 0, 0, GetWordAddress(sTopic.c_str(), 1)); - sTopic = _T(""); - sTopicName = _T(""); - sTopicTime = _T(""); - } } - - gcd.ptszID = (TCHAR*)sID.c_str(); - gcd.iType = GC_EVENT_CONTROL; - gce.cbSize = sizeof(GCEVENT); - gce.dwFlags = GC_TCHAR; - gce.bIsMe = false; - gce.dwItemData = false; - gce.pszNick = NULL; - gce.pszStatus = NULL; - gce.pszText = NULL; - gce.pszUID = NULL; - gce.pszUserInfo = NULL; - gce.time = time(0); - gce.pDest = &gcd; - - if ( !getTString( "JTemp", &dbv )) { - CMString command = _T("a"); - CMString save = _T(""); - int i = 0; - - while ( !command.IsEmpty()) { - command = GetWord( dbv.ptszVal, i ); - i++; - if ( !command.IsEmpty()) { - CMString S = command.Mid(1, command.GetLength()); - if ( !lstrcmpi( sChanName, S.c_str())) - break; - - save += command + _T(" "); - } } - - if ( !command.IsEmpty()) { - save += GetWordAddress( dbv.ptszVal, i ); - switch ( command[0] ) { - case 'M': - CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); - break; - case 'X': - CallChatEvent( WINDOW_MAXIMIZE, (LPARAM)&gce); - break; - default: - CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); - break; - } - } - else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); - - if ( save.IsEmpty()) - DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); - else - setTString("JTemp", save.c_str()); - DBFreeVariant(&dbv); - } - else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); - - { gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); - } } } } - - sNamesList = _T(""); - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_INITIALTOPIC( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { - AddWindowItemData( pmsg->parameters[1].c_str(), 0, 0, 0, pmsg->parameters[2].c_str()); - sTopic = pmsg->parameters[1] + _T(" ") + pmsg->parameters[2]; - sTopicName = _T(""); - sTopicTime = _T(""); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_INITIALTOPICNAME( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) { - TCHAR tTimeBuf[128], *tStopStr; - time_t ttTopicTime; - sTopicName = pmsg->parameters[2]; - ttTopicTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); - _tcsftime(tTimeBuf, 128, _T("%#c"), localtime(&ttTopicTime)); - sTopicTime = tTimeBuf; - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_TOPIC( const CIrcMessage* pmsg ) -{ - if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { - DoEvent( GC_EVENT_TOPIC, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str(), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); - AddWindowItemData(pmsg->parameters[0].c_str(), 0, 0, 0, pmsg->parameters[1].c_str()); - } - ShowMessage( pmsg ); - return true; -} - -static void __stdcall sttShowDlgList( void* param ) -{ - CIrcProto* ppro = ( CIrcProto* )param; - if ( ppro->m_listDlg == NULL ) { - ppro->m_listDlg = new CListDlg( ppro ); - ppro->m_listDlg->Show(); - } - SetEvent( ppro->m_evWndCreate ); -} - -bool CIrcProto::OnIrc_LISTSTART( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - CallFunctionAsync( sttShowDlgList, this ); - WaitForSingleObject( m_evWndCreate, INFINITE ); - m_channelNumber = 0; - } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_LIST( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming == 1 && m_listDlg && pmsg->parameters.getCount() > 2 ) { - m_channelNumber++; - LVITEM lvItem; - HWND hListView = GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW ); - lvItem.iItem = ListView_GetItemCount( hListView ); - lvItem.mask = LVIF_TEXT | LVIF_PARAM; - lvItem.iSubItem = 0; - lvItem.pszText = (TCHAR*)pmsg->parameters[1].c_str(); - lvItem.lParam = lvItem.iItem; - lvItem.iItem = ListView_InsertItem( hListView, &lvItem ); - lvItem.mask = LVIF_TEXT; - lvItem.iSubItem =1; - lvItem.pszText = (TCHAR*)pmsg->parameters[pmsg->parameters.getCount()-2].c_str(); - ListView_SetItem( hListView, &lvItem ); - - TCHAR* temp = mir_tstrdup( pmsg->parameters[pmsg->parameters.getCount()-1] ); - TCHAR* find = _tcsstr( temp , _T("[+")); - TCHAR* find2 = _tcsstr( temp , _T("]")); - TCHAR* save = temp; - if ( find == temp && find2 != NULL && find+8 >= find2 ) { - temp = _tcsstr( temp, _T("]")); - if ( lstrlen(temp) > 1 ) { - temp++; - temp[0] = '\0'; - lvItem.iSubItem =2; - lvItem.pszText = save; - ListView_SetItem(hListView,&lvItem); - temp[0] = ' '; - temp++; - } - else temp =save; - } - - lvItem.iSubItem =3; - CMString S = DoColorCodes(temp, TRUE, FALSE); - lvItem.pszText = ( TCHAR* )S.c_str(); - ListView_SetItem( hListView, &lvItem ); - temp = save; - mir_free( temp ); - - int percent = 100; - if ( m_noOfChannels > 0 ) - percent = (int)(m_channelNumber*100) / m_noOfChannels; - - TCHAR text[100]; - if ( percent < 100) - mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list (%u%%) - %u channels"), percent, m_channelNumber); - else - mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list - %u channels"), m_channelNumber); - m_listDlg->m_status.SetText( text ); - } - - return true; -} - -bool CIrcProto::OnIrc_LISTEND( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_listDlg ) { - EnableWindow(GetDlgItem(m_listDlg->GetHwnd(), IDC_JOIN), true); - ListView_SetSelectionMark(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 0); - ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 1, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 2, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 3, LVSCW_AUTOSIZE); - m_listDlg->UpdateList(); - - TCHAR text[100]; - mir_sntprintf( text, SIZEOF(text), TranslateT("Done: %u channels"), m_channelNumber ); - int percent = 100; - if ( m_noOfChannels > 0 ) - percent = (int)(m_channelNumber*100) / m_noOfChannels; - if ( percent < 70 ) { - lstrcat( text, _T(" ")); - lstrcat( text, TranslateT("(probably truncated by server)")); - } - SetDlgItemText( m_listDlg->GetHwnd(), IDC_TEXT, text ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_BANLIST( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { - if ( m_managerDlg->GetHwnd() && ( - m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("367") || - m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("346") || - m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("348")) && - !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) - { - CMString S = pmsg->parameters[2]; - if ( pmsg->parameters.getCount() > 3 ) { - S += _T(" - "); - S += pmsg->parameters[3]; - if ( pmsg->parameters.getCount() > 4 ) { - S += _T(" - ( "); - time_t time = StrToInt( pmsg->parameters[4].c_str()); - S += _tctime( &time ); - ReplaceString( S, _T("\n"), _T(" ")); - S += _T(")"); - } } - - SendDlgItemMessage(m_managerDlg->GetHwnd(), IDC_LIST, LB_ADDSTRING, 0, (LPARAM)S.c_str()); - } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_BANLISTEND( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - if ( m_managerDlg->GetHwnd() && - ( m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("368") - || m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("347") - || m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("349")) && - !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) - { - if ( strchr( sChannelModes.c_str(), 'b' )) - m_managerDlg->m_radio1.Enable(); - if ( strchr( sChannelModes.c_str(), 'I' )) - m_managerDlg->m_radio2.Enable(); - if ( strchr( sChannelModes.c_str(), 'e' )) - m_managerDlg->m_radio3.Enable(); - if ( !IsDlgButtonChecked(m_managerDlg->GetHwnd(), IDC_NOTOP)) - m_managerDlg->m_add.Enable(); - } } - - ShowMessage( pmsg ); - return true; -} - -static void __stdcall sttShowWhoisWnd( void* param ) -{ - CIrcMessage* pmsg = ( CIrcMessage* )param; - CIrcProto* ppro = ( CIrcProto* )pmsg->m_proto; - if ( ppro->m_whoisDlg == NULL ) { - ppro->m_whoisDlg = new CWhoisDlg( ppro ); - ppro->m_whoisDlg->Show(); - } - SetEvent( ppro->m_evWndCreate ); - - ppro->m_whoisDlg->ShowMessage( pmsg ); - delete pmsg; -} - -bool CIrcProto::OnIrc_WHOIS_NAME( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 5 && m_manualWhoisCount > 0 ) { - CallFunctionAsync( sttShowWhoisWnd, new CIrcMessage( *pmsg )); - WaitForSingleObject( m_evWndCreate, INFINITE ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_CHANNELS( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) - m_whoisDlg->m_InfoChannels.SetText( pmsg->parameters[2].c_str()); - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_AWAY( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) - m_whoisDlg->m_InfoAway2.SetText( pmsg->parameters[2].c_str()); - if ( m_manualWhoisCount < 1 && pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) - WhoisAwayReply = pmsg->parameters[2]; - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_OTHER( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { - TCHAR temp[1024], temp2[1024]; - m_whoisDlg->m_InfoOther.GetText( temp, 1000 ); - lstrcat( temp, _T("%s\r\n")); - mir_sntprintf( temp2, 1020, temp, pmsg->parameters[2].c_str()); - m_whoisDlg->m_InfoOther.SetText( temp2 ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_END( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 && m_manualWhoisCount < 1 ) { - CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, true}; - HANDLE hContact = CList_FindContact( &user ); - if ( hContact ) - ProtoBroadcastAck( m_szModuleName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM)WhoisAwayReply.c_str()); - } - - m_manualWhoisCount--; - if (m_manualWhoisCount < 0) - m_manualWhoisCount = 0; - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_IDLE( const CIrcMessage* pmsg ) -{ - int D = 0; - int H = 0; - int M = 0; - int S = 0; - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { - S = StrToInt(pmsg->parameters[2].c_str()); - D = S/(60*60*24); - S -= (D * 60 * 60 *24); - H = S/(60*60); - S -= (H * 60 * 60); - M = S/60; - S -= (M * 60 ); - - TCHAR temp[100]; - if ( D ) - mir_sntprintf(temp, 99, _T("%ud, %uh, %um, %us"), D, H, M, S); - else if (H) - mir_sntprintf(temp, 99, _T("%uh, %um, %us"), H, M, S); - else if (M) - mir_sntprintf(temp, 99, _T("%um, %us"), M, S); - else if (S) - mir_sntprintf(temp, 99, _T("%us"), S); - else - temp[0] = 0; - - TCHAR temp3[256]; - TCHAR tTimeBuf[128], *tStopStr; - time_t ttTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); - _tcsftime(tTimeBuf, 128, _T("%c"), localtime(&ttTime)); - mir_sntprintf( temp3, SIZEOF(temp3), _T("online since %s, idle %s"), tTimeBuf, temp); - m_whoisDlg->m_AwayTime.SetText( temp3 ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_SERVER( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) - m_whoisDlg->m_InfoServer.SetText( pmsg->parameters[2].c_str()); - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_AUTH( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { - if ( pmsg->sCommand == _T("330")) - m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); - else if ( pmsg->parameters[2] == _T("is an identified user") || pmsg->parameters[2] == _T("is a registered nick")) - m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); - else - OnIrc_WHOIS_OTHER( pmsg ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHOIS_NO_USER( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 && !IsChannel( pmsg->parameters[1] )) { - if ( m_whoisDlg ) - m_whoisDlg->ShowMessageNoUser( pmsg ); - - CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, false}; - HANDLE hContact = CList_FindContact( &user ); - if ( hContact ) { - AddOutgoingMessageToDB( hContact, (TCHAR*)((CMString)_T("> ") + pmsg->parameters[2] + (CMString)_T(": ") + pmsg->parameters[1]).c_str()); - - DBVARIANT dbv; - if ( !getTString( hContact, "Default", &dbv )) { - setTString( hContact, "Nick", dbv.ptszVal ); - - DBVARIANT dbv2; - if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) - DoUserhostWithReason(1, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); - else { - if ( !getTString( hContact, "UWildcard", &dbv2 )) { - DoUserhostWithReason(2, ((CMString)_T("S") + dbv2.ptszVal).c_str(), true, dbv2.ptszVal ); - DBFreeVariant(&dbv2); - } - else DoUserhostWithReason(2, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); - } - setString(hContact, "User", ""); - setString(hContact, "Host", ""); - DBFreeVariant(&dbv); - } } } - - ShowMessage( pmsg ); - return true; -} - -static void __stdcall sttShowNickWnd( void* param ) -{ - CIrcMessage* pmsg = ( CIrcMessage* )param; - CIrcProto* ppro = pmsg->m_proto; - if ( ppro->m_nickDlg == NULL ) { - ppro->m_nickDlg = new CNickDlg( ppro ); - ppro->m_nickDlg->Show(); - } - SetEvent( ppro->m_evWndCreate ); - SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_CAPTION ), TranslateT("Change nickname")); - SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_TEXT ), pmsg->parameters.getCount() > 2 ? pmsg->parameters[2].c_str() : _T("")); - ppro->m_nickDlg->m_Enick.SetText( pmsg->parameters[1].c_str()); - ppro->m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); - delete pmsg; -} - -bool CIrcProto::OnIrc_NICK_ERR( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - if ( nickflag && ((m_alternativeNick[0] != 0)) && (pmsg->parameters.getCount() > 2 && _tcscmp(pmsg->parameters[1].c_str(), m_alternativeNick))) { - TCHAR m[200]; - mir_sntprintf( m, SIZEOF(m), _T("NICK %s"), m_alternativeNick ); - if ( IsConnected()) - SendIrcMessage( m ); - } - else { - CallFunctionAsync( sttShowNickWnd, new CIrcMessage( *pmsg )); - WaitForSingleObject( m_evWndCreate, INFINITE ); - } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_JOINERROR( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming ) { - DBVARIANT dbv; - if ( !getTString( "JTemp", &dbv )) { - CMString command = _T("a"); - CMString save = _T(""); - int i = 0; - - while ( !command.IsEmpty()) { - command = GetWord( dbv.ptszVal, i ); - i++; - - if ( !command.IsEmpty() && pmsg->parameters[0] == command.Mid(1, command.GetLength())) - save += command + _T(" "); - } - - DBFreeVariant(&dbv); - - if ( save.IsEmpty()) - DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); - else - setTString( "JTemp", save.c_str()); - } } - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_UNKNOWN( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { - if ( pmsg->parameters[0] == _T("WHO") && GetNextUserhostReason(2) != _T("U")) - return true; - if ( pmsg->parameters[0] == _T("USERHOST") && GetNextUserhostReason(1) != _T("U")) - return true; - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_ENDMOTD( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && !bPerformDone ) - DoOnConnect( pmsg ); - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_NOOFCHANNELS( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) - m_noOfChannels = StrToInt( pmsg->parameters[1].c_str()); - - if ( pmsg->m_bIncoming && !bPerformDone ) - DoOnConnect( pmsg ); - - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_ERROR( const CIrcMessage* pmsg ) -{ - if ( pmsg->m_bIncoming && !m_disableErrorPopups && m_iDesiredStatus != ID_STATUS_OFFLINE) { - MIRANDASYSTRAYNOTIFY msn; - msn.cbSize = sizeof(MIRANDASYSTRAYNOTIFY); - msn.szProto = m_szModuleName; - msn.tszInfoTitle = TranslateT("IRC error"); - - CMString S; - if ( pmsg->parameters.getCount() > 0 ) - S = DoColorCodes( pmsg->parameters[0].c_str(), TRUE, FALSE ); - else - S = TranslateT( "Unknown" ); - - msn.tszInfo = ( TCHAR* )S.c_str(); - msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; - msn.uTimeout = 15000; - CallService( MS_CLIST_SYSTRAY_NOTIFY, 0, ( LPARAM )&msn ); - } - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHO_END( const CIrcMessage* pmsg ) -{ - CMString command = GetNextUserhostReason(2); - if ( command[0] == 'S' ) { - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - // is it a channel? - if ( IsChannel( pmsg->parameters[1] )) { - CMString S; - CMString User = GetWord( m_whoReply.c_str(), 0 ); - while ( !User.IsEmpty()) { - if ( GetWord( m_whoReply.c_str(), 3)[0] == 'G' ) { - S += User; - S += _T("\t"); - DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_AWAY, FALSE, FALSE); - } - else DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); - - CMString SS = GetWordAddress( m_whoReply.c_str(), 4 ); - if ( SS.IsEmpty()) - break; - m_whoReply = SS; - User = GetWord(m_whoReply.c_str(), 0); - } - - DoEvent( GC_EVENT_SETSTATUSEX, pmsg->parameters[1].c_str(), NULL, S.IsEmpty() ? NULL : S.c_str(), NULL, NULL, GC_SSE_TABDELIMITED, FALSE, FALSE); - return true; - } - - /// if it is not a channel - TCHAR* UserList = mir_tstrdup( m_whoReply.c_str()); - const TCHAR* p1= UserList; - m_whoReply = _T(""); - CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, true, false}; - HANDLE hContact = CList_FindContact( &user ); - - if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 1 ) { - DBVARIANT dbv1, dbv2, dbv3, dbv4, dbv5, dbv6, dbv7; - TCHAR *DBDefault = NULL, *DBNick = NULL, *DBWildcard = NULL; - TCHAR *DBUser = NULL, *DBHost = NULL, *DBManUser = NULL, *DBManHost = NULL; - if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; - if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; - if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; - if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; - if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; - if ( !getTString(hContact, "User", &dbv6)) DBManUser = dbv6.ptszVal; - if ( !getTString(hContact, "Host", &dbv7)) DBManHost = dbv7.ptszVal; - if ( DBWildcard ) - CharLower( DBWildcard ); - - CMString nick; - CMString user; - CMString host; - CMString away = GetWord(p1, 3); - - while ( !away.IsEmpty()) { - nick = GetWord(p1, 0); - user = GetWord(p1, 1); - host = GetWord(p1, 2); - if (( DBWildcard && WCCmp( DBWildcard, nick.c_str()) || DBNick && !lstrcmpi(DBNick, nick.c_str()) || DBDefault && !lstrcmpi(DBDefault, nick.c_str())) - && (WCCmp(DBUser, user.c_str()) && WCCmp(DBHost, host.c_str()))) - { - if (away[0] == 'G' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_AWAY) - setWord(hContact, "Status", ID_STATUS_AWAY); - else if (away[0] == 'H' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_ONLINE) - setWord(hContact, "Status", ID_STATUS_ONLINE); - - if (( DBNick && lstrcmpi( nick.c_str(), DBNick)) || !DBNick ) - setTString( hContact, "Nick", nick.c_str()); - if (( DBManUser && lstrcmpi( user.c_str(), DBManUser)) || !DBManUser ) - setTString( hContact, "User", user.c_str()); - if (( DBManHost && lstrcmpi(host.c_str(), DBManHost)) || !DBManHost ) - setTString(hContact, "Host", host.c_str()); - - goto LBL_Exit; - } - p1 = GetWordAddress(p1, 4); - away = GetWord(p1, 3); - } - - if ( DBWildcard && DBNick && !WCCmp( CharLower( DBWildcard ), CharLower( DBNick ))) { - setTString(hContact, "Nick", DBDefault); - - DoUserhostWithReason(2, ((CMString)_T("S") + DBWildcard).c_str(), true, DBWildcard); - - setString(hContact, "User", ""); - setString(hContact, "Host", ""); - goto LBL_Exit; - } - - if ( getWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) { - setWord(hContact, "Status", ID_STATUS_OFFLINE); - setTString(hContact, "Nick", DBDefault); - setString(hContact, "User", ""); - setString(hContact, "Host", ""); - } -LBL_Exit: - if ( DBDefault ) DBFreeVariant(&dbv1); - if ( DBNick ) DBFreeVariant(&dbv2); - if ( DBWildcard ) DBFreeVariant(&dbv3); - if ( DBUser ) DBFreeVariant(&dbv4); - if ( DBHost ) DBFreeVariant(&dbv5); - if ( DBManUser ) DBFreeVariant(&dbv6); - if ( DBManHost ) DBFreeVariant(&dbv7); - } - mir_free( UserList ); - } - } - else ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_WHO_REPLY( const CIrcMessage* pmsg ) -{ - CMString command = PeekAtReasons(2); - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 6 && command[0] == 'S' ) { - m_whoReply.AppendFormat( _T("%s %s %s %s "), pmsg->parameters[5].c_str(), pmsg->parameters[2].c_str(), pmsg->parameters[3].c_str(), pmsg->parameters[6].c_str()); - if ( lstrcmpi( pmsg->parameters[5].c_str(), m_info.sNick.c_str()) == 0 ) { - TCHAR host[1024]; - lstrcpyn( host, pmsg->parameters[3].c_str(), 1024 ); - ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(host), IP_AUTO )); - } } - - if ( command[0] == 'U' ) - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_TRYAGAIN( const CIrcMessage* pmsg ) -{ - CMString command = _T(""); - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { - if ( pmsg->parameters[1] == _T("WHO")) - command = GetNextUserhostReason(2); - - if ( pmsg->parameters[1] == _T("USERHOST")) - command = GetNextUserhostReason(1); - } - if (command[0] == 'U') - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_USERHOST_REPLY( const CIrcMessage* pmsg ) -{ - CMString command = _T(""); - if ( pmsg->m_bIncoming ) { - command = GetNextUserhostReason(1); - if ( !command.IsEmpty() && command != _T("U") && pmsg->parameters.getCount() > 1 ) { - CONTACT finduser = {NULL, NULL, NULL, false, false, false}; - TCHAR* p1 = NULL; - TCHAR* p2 = NULL; - int awaystatus = 0; - CMString sTemp; - CMString host; - CMString user; - CMString nick; - CMString mask; - CMString mess; - CMString channel; - int i; - int j; - - // Status-check pre-processing: Setup check-list - OBJLIST checklist( 10 ); - if ( command[0] == 'S' ) { - j = 0; - sTemp = GetWord(command.c_str(), 0); - sTemp.Delete(0,1); - while ( !sTemp.IsEmpty()) { - checklist.insert( new CMString( sTemp )); - j++; - sTemp = GetWord(command.c_str(), j); - } } - - // Cycle through results - j = 0; - sTemp = GetWord( pmsg->parameters[1].c_str(), j ); - while ( !sTemp.IsEmpty()) { - p1 = mir_tstrdup( sTemp.c_str()); - p2 = p1; - - // Pull out host, user and nick - p2 = _tcschr(p1, '@'); - if ( p2 ) { - *p2 = '\0'; - p2++; - host = p2; - } - p2 = _tcschr(p1, '='); - if ( p2 ) { - if (*(p2-1) == '*') - *(p2-1) = '\0'; // remove special char for IRCOps - *p2 = '\0'; - p2++; - awaystatus = *p2; - p2++; - user = p2; - nick = p1; - } - mess = _T(""); - mask = nick + _T("!") + user + _T("@") + host; - if ( host.IsEmpty() || user.IsEmpty() || nick.IsEmpty()) { - mir_free( p1 ); - continue; - } - - // Do command - switch ( command[0] ) { - case 'S': // Status check - { - finduser.name = (TCHAR*)nick.c_str(); - finduser.host = (TCHAR*)host.c_str(); - finduser.user = (TCHAR*)user.c_str(); - - HANDLE hContact = CList_FindContact(&finduser); - if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 0 ) { - setWord(hContact, "Status", awaystatus == '-'? ID_STATUS_AWAY : ID_STATUS_ONLINE); - setTString(hContact, "User", user.c_str()); - setTString(hContact, "Host", host.c_str()); - setTString(hContact, "Nick", nick.c_str()); - - // If user found, remove from checklist - for ( i = 0; i < checklist.getCount(); i++ ) - if ( !lstrcmpi(checklist[i].c_str(), nick.c_str())) - checklist.remove( i ); - } - break; - } - case 'I': // m_ignore - mess = _T("/IGNORE %question=\""); - mess += TranslateT("Please enter the hostmask (nick!user@host)\nNOTE! Contacts on your contact list are never ignored"); - mess += (CMString)_T("\",\"") + TranslateT("Ignore") + _T("\",\"*!*@") + host + _T("\""); - if ( m_ignoreChannelDefault ) - mess += _T(" +qnidcm"); - else - mess += _T(" +qnidc"); - break; - - case 'J': // Unignore - mess = _T("/UNIGNORE *!*@") + host; - break; - - case 'B': // Ban - channel = (command.c_str() + 1); - mess = _T("/MODE ") + channel + _T(" +b *!*@") + host; - break; - - case 'K': // Ban & Kick - channel = (command.c_str() + 1); - mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s"), channel.c_str(), host.c_str(), channel.c_str(), nick.c_str()); - break; - - case 'L': // Ban & Kick with reason - channel = (command.c_str() + 1); - mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), - channel.c_str(), host.c_str(), channel.c_str(), nick.c_str(), - TranslateT("Please enter the reason"), TranslateT("Ban'n Kick"), TranslateT("Jerk")); - break; - } - - mir_free( p1 ); - - // Post message - if ( !mess.IsEmpty()) - PostIrcMessageWnd( NULL, NULL, mess.c_str()); - j++; - sTemp = GetWord(pmsg->parameters[1].c_str(), j); - } - - // Status-check post-processing: make buddies in ckeck-list offline - if ( command[0] == 'S' ) { - for ( i = 0; i < checklist.getCount(); i++ ) { - finduser.name = (TCHAR*)checklist[i].c_str(); - finduser.ExactNick = true; - CList_SetOffline( &finduser ); - } } - - return true; - } } - - if ( !pmsg->m_bIncoming || command == _T("U")) - ShowMessage( pmsg ); - return true; -} - -bool CIrcProto::OnIrc_SUPPORT( const CIrcMessage* pmsg ) -{ - static const TCHAR* lpszFmt = _T("Try server %99[^ ,], port %19s"); - TCHAR szAltServer[100]; - TCHAR szAltPort[20]; - if ( pmsg->parameters.getCount() > 1 && _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szAltServer, &szAltPort) == 2 ) { - ShowMessage( pmsg ); - lstrcpynA( m_serverName, _T2A(szAltServer), 99 ); - lstrcpynA( m_portStart, _T2A(szAltPort), 9 ); - - m_noOfChannels = 0; - ConnectToServer(); - return true; - } - - if ( pmsg->m_bIncoming && !bPerformDone ) - DoOnConnect(pmsg); - - if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { - CMString S; - for ( int i = 0; i < pmsg->parameters.getCount(); i++ ) { - TCHAR* temp = mir_tstrdup( pmsg->parameters[i].c_str()); - if ( _tcsstr( temp, _T("CHANTYPES="))) { - TCHAR* p1 = _tcschr( temp, '=' ); - p1++; - if ( lstrlen( p1 ) > 0 ) - sChannelPrefixes = p1; - } - if ( _tcsstr(temp, _T("CHANMODES="))) { - TCHAR* p1 = _tcschr( temp, '=' ); - p1++; - if ( lstrlen( p1 ) > 0) - sChannelModes = ( char* )_T2A( p1 ); - } - if ( _tcsstr( temp, _T("PREFIX="))) { - TCHAR* p1 = _tcschr( temp, '(' ); - TCHAR* p2 = _tcschr( temp, ')' ); - if ( p1 && p2 ) { - p1++; - if ( p1 != p2 ) - sUserModes = ( char* )_T2A( p1 ); - sUserModes = sUserModes.Mid(0, p2-p1); - p2++; - if ( *p2 != '\0' ) - sUserModePrefixes = p2; - } - else { - p1 = _tcschr( temp, '=' ); - p1++; - sUserModePrefixes = p1; - for ( int i =0; i < sUserModePrefixes.GetLength()+1; i++ ) { - if ( sUserModePrefixes[i] == '@' ) - sUserModes.SetAt( i, 'o' ); - else if ( sUserModePrefixes[i] == '+' ) - sUserModes.SetAt( i, 'v' ); - else if ( sUserModePrefixes[i] == '-' ) - sUserModes.SetAt( i, 'u' ); - else if ( sUserModePrefixes[i] == '%' ) - sUserModes.SetAt( i, 'h' ); - else if ( sUserModePrefixes[i] == '!' ) - sUserModes.SetAt( i, 'a' ); - else if ( sUserModePrefixes[i] == '*' ) - sUserModes.SetAt( i, 'q' ); - else if ( sUserModePrefixes[i] == '\0' ) - sUserModes.SetAt( i, '\0' ); - else - sUserModes.SetAt( i, '_' ); - } } } - - mir_free( temp ); - } } - - ShowMessage( pmsg ); - return true; -} - -void CIrcProto::OnIrcDefault( const CIrcMessage* pmsg ) -{ - ShowMessage( pmsg ); -} - -void CIrcProto::OnIrcDisconnected() -{ - m_statusMessage = _T(""); - DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); - bTempDisableCheck = false; - bTempForceCheck = false; - m_iTempCheckTime = 0; - - m_myHost[0] = '\0'; - - int Temp = m_iStatus; - KillIdent(); - KillChatTimer( OnlineNotifTimer ); - KillChatTimer( OnlineNotifTimer3 ); - KillChatTimer( KeepAliveTimer ); - KillChatTimer( InitTimer ); - KillChatTimer( IdentTimer ); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_OFFLINE); - - CMString sDisconn = _T("\0035\002"); - sDisconn += TranslateT("*Disconnected*"); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, sDisconn.c_str(), NULL, NULL, NULL, true, false); - - { - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - gce.cbSize = sizeof(GCEVENT); - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); - } - - if ( !Miranda_Terminated()) - CList_SetAllOffline( m_disconnectDCCChats ); - - // restore the original nick, cause it might be changed - memcpy( m_nick, m_pNick, sizeof( m_nick )); - setTString( "Nick", m_pNick ); - - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof( clmi ); - clmi.flags = CMIM_FLAGS | CMIF_GRAYED; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnConnect - -static void __stdcall sttMainThrdOnConnect( void* param ) -{ - CIrcProto* ppro = ( CIrcProto* )param; - - ppro->SetChatTimer( ppro->InitTimer, 1*1000, TimerProc ); - if ( ppro->m_identTimer ) - ppro->SetChatTimer( ppro->IdentTimer, 60*1000, IdentTimerProc ); - if ( ppro->m_sendKeepAlive ) - ppro->SetChatTimer( ppro->KeepAliveTimer, 60*1000, KeepAliveTimerProc ); - if ( ppro->m_autoOnlineNotification && !ppro->bTempDisableCheck || ppro->bTempForceCheck ) { - ppro->SetChatTimer( ppro->OnlineNotifTimer, 1000, OnlineNotifTimerProc ); - if ( ppro->m_channelAwayNotification ) - ppro->SetChatTimer( ppro->OnlineNotifTimer3, 3000, OnlineNotifTimerProc3); -} } - -bool CIrcProto::DoOnConnect( const CIrcMessage* ) -{ - bPerformDone = true; - nickflag = true; - - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof( clmi ); - clmi.flags = CMIM_FLAGS; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); - - int Temp = m_iStatus; - m_iStatus = ID_STATUS_ONLINE; - ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE )Temp, m_iStatus ); - - if ( m_iDesiredStatus == ID_STATUS_AWAY ) - PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); - - if ( m_perform ) { - DoPerform( "ALL NETWORKS" ); - if ( IsConnected()) { - DoPerform( _T2A( m_info.sNetwork.c_str())); - switch( m_iStatus ) { - case ID_STATUS_FREECHAT: DoPerform( "Event: Free for chat" ); break; - case ID_STATUS_ONLINE: DoPerform( "Event: Available" ); break; - } } } - - if ( m_rejoinChannels ) { - int count = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); - for ( int i = 0; i < count ; i++ ) { - GC_INFO gci = {0}; - gci.Flags = BYINDEX | DATA | NAME | TYPE; - gci.iItem = i; - gci.pszModule = m_szModuleName; - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci) && gci.iType == GCW_CHATROOM ) { - CHANNELINFO* wi = ( CHANNELINFO* )gci.dwItemData; - if ( wi && wi->pszPassword ) - PostIrcMessage( _T("/JOIN %s %s"), gci.pszName, wi->pszPassword); - else - PostIrcMessage( _T("/JOIN %s"), gci.pszName); - } } } - - DoEvent( GC_EVENT_ADDGROUP, SERVERWINDOW, NULL, NULL, _T("Normal"), NULL, NULL, FALSE, TRUE); - { - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - gce.dwFlags = GC_TCHAR; - gce.cbSize = sizeof(GCEVENT); - gcd.ptszID = SERVERWINDOW; - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - gce.pDest = &gcd; - CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); - } - - CallFunctionAsync( sttMainThrdOnConnect, this ); - nickflag = false; - return 0; -} - -static void __cdecl AwayWarningThread(LPVOID) -{ - MessageBox(NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); -} - -int CIrcProto::DoPerform( const char* event ) -{ - String sSetting = String("PERFORM:") + event; - sSetting.MakeUpper(); - - DBVARIANT dbv; - if ( !getTString( sSetting.c_str(), &dbv )) { - if ( !my_strstri( dbv.ptszVal, _T("/away"))) - PostIrcMessageWnd( NULL, NULL, dbv.ptszVal ); - else - mir_forkthread( AwayWarningThread, NULL ); - DBFreeVariant( &dbv ); - return 1; - } - return 0; -} - -int CIrcProto::IsIgnored( const CMString& nick, const CMString& address, const CMString& host, char type) -{ - return IsIgnored( nick + _T("!") + address + _T("@") + host, type ); -} - -int CIrcProto::IsIgnored( CMString user, char type ) -{ - for ( int i=0; i < m_ignoreItems.getCount(); i++ ) { - const CIrcIgnoreItem& C = m_ignoreItems[i]; - - if ( type == '\0' ) - if ( !lstrcmpi( user.c_str(), C.mask.c_str())) - return i+1; - - bool bUserContainsWild = ( _tcschr( user.c_str(), '*') != NULL || _tcschr( user.c_str(), '?' ) != NULL ); - if ( !bUserContainsWild && WCCmp( C.mask.c_str(), user.c_str()) || - bUserContainsWild && !lstrcmpi( user.c_str(), C.mask.c_str())) - { - if ( C.flags.IsEmpty() || C.flags[0] != '+' ) - continue; - - if ( !_tcschr( C.flags.c_str(), type )) - continue; - - if ( C.network.IsEmpty()) - return i+1; - - if ( IsConnected() && !lstrcmpi( C.network.c_str(), m_info.sNetwork.c_str())) - return i+1; - } } - - return 0; -} - -bool CIrcProto::AddIgnore( const TCHAR* mask, const TCHAR* flags, const TCHAR* network ) -{ - RemoveIgnore( mask ); - m_ignoreItems.insert( new CIrcIgnoreItem( mask, (_T("+") + CMString(flags)).c_str(), network )); - RewriteIgnoreSettings(); - - if ( m_ignoreDlg ) - m_ignoreDlg->RebuildList(); - return true; -} - -bool CIrcProto::RemoveIgnore( const TCHAR* mask ) -{ - int idx; - while (( idx = IsIgnored( mask, '\0')) != 0 ) - m_ignoreItems.remove( idx-1 ); - - RewriteIgnoreSettings(); - - if ( m_ignoreDlg ) - m_ignoreDlg->RebuildList(); - return true; -} diff --git a/protocols/IRCG/commandmonitor.h b/protocols/IRCG/commandmonitor.h deleted file mode 100644 index 940cb9cc02..0000000000 --- a/protocols/IRCG/commandmonitor.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -using namespace irc; diff --git a/protocols/IRCG/input.cpp b/protocols/IRCG/input.cpp deleted file mode 100644 index c564b7844c..0000000000 --- a/protocols/IRCG/input.cpp +++ /dev/null @@ -1,936 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" -#include "version.h" - -#define NICKSUBSTITUTE _T("!_nick_!") - -void CIrcProto::FormatMsg(CMString& text) -{ - TCHAR temp[30]; - lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29); - CharLower(temp); - CMString command = temp; - CMString S = _T(""); - if (command == _T("/quit") || command == _T("/away")) - S = GetWord(text.c_str(), 0) + _T(" :") + GetWordAddress(text.c_str(), 1); - else if (command == _T("/privmsg") || command == _T("/part") || command == _T("/topic") || command == _T("/notice")) { - S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" :"); - if (!GetWord(text.c_str(), 2).IsEmpty()) - S += CMString(GetWordAddress(text.c_str(), 2)); - } - else if (command == _T("/kick")) { - S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" ") + GetWord(text.c_str(), 2) + _T(" :") + GetWordAddress(text.c_str(), 3); - } - else if (command == _T("/nick")) { - if ( !_tcsstr(GetWord(text.c_str(), 1).c_str(), NICKSUBSTITUTE )) { - sNick4Perform = GetWord(text.c_str(), 1); - S = GetWordAddress(text.c_str(), 0); - } - else { - CMString sNewNick = GetWord(text.c_str(), 1); - if ( sNick4Perform == _T("")) { - DBVARIANT dbv; - if ( !getTString( "PNick", &dbv )) { - sNick4Perform = dbv.ptszVal; - DBFreeVariant(&dbv); - } } - - ReplaceString( sNewNick, NICKSUBSTITUTE, sNick4Perform.c_str()); - S = GetWord(text.c_str(), 0) + _T(" ") + sNewNick; - } - } - else S = GetWordAddress(text.c_str(), 0); - - S.Delete(0,1); - text = S; -} - -static void AddCR( CMString& text ) -{ - ReplaceString( text, _T("\n"), _T("\r\n")); - ReplaceString( text, _T("\r\r"), _T("\r")); -} - -CMString CIrcProto::DoAlias( const TCHAR *text, TCHAR *window) -{ - CMString Messageout = _T(""); - const TCHAR* p1 = text; - const TCHAR* p2 = text; - bool LinebreakFlag = false, hasAlias = false; - p2 = _tcsstr(p1, _T("\r\n")); - if ( !p2 ) - p2 = _tcschr(p1, '\0'); - if ( p1 == p2 ) - return (CMString)text; - - do { - if ( LinebreakFlag ) - Messageout += _T("\r\n"); - - TCHAR* line = new TCHAR[p2-p1 +1]; - lstrcpyn(line, p1, p2-p1+1); - TCHAR* test = line; - while ( *test == ' ' ) - test++; - if ( *test == '/' ) { - lstrcpyn(line, GetWordAddress(line, 0), p2-p1+1); - CMString S = line; - delete [] line; - line = new TCHAR[S.GetLength()+2]; - lstrcpyn(line, S.c_str(), S.GetLength()+1); - CMString alias( m_alias ); - const TCHAR* p3 = _tcsstr( alias.c_str(), (GetWord(line, 0)+ _T(" ")).c_str()); - if ( p3 != alias.c_str()) { - CMString S = _T("\r\n"); - S += GetWord(line, 0) + _T(" "); - p3 = _tcsstr( alias.c_str(), S.c_str()); - if ( p3 ) - p3 += 2; - } - if ( p3 != NULL ) { - hasAlias = true; - const TCHAR* p4 = _tcsstr( p3, _T("\r\n")); - if ( !p4 ) - p4 = _tcschr( p3, '\0' ); - - *( TCHAR* )p4 = 0; - CMString S = p3; - ReplaceString( S, _T("##"), window ); - ReplaceString( S, _T("$?"), _T("%question")); - - for ( int index = 1; index < 8; index++ ) { - TCHAR str[5]; - mir_sntprintf( str, SIZEOF(str), _T("#$%u"), index ); - if ( !GetWord(line, index).IsEmpty() && IsChannel( GetWord( line, index ))) - ReplaceString( S, str, GetWord(line, index).c_str()); - else { - CMString S1 = _T("#"); - S1 += GetWord( line, index ); - ReplaceString( S, str, S1.c_str()); - } - } - for ( int index2 = 1; index2 <8; index2++ ) { - TCHAR str[5]; - mir_sntprintf( str, SIZEOF(str), _T("$%u-"), index2 ); - ReplaceString( S, str, GetWordAddress( line, index2 )); - } - for ( int index3 = 1; index3 <8; index3++ ) { - TCHAR str[5]; - mir_sntprintf( str, SIZEOF(str), _T("$%u"), index3 ); - ReplaceString( S, str, GetWord(line, index3).c_str()); - } - Messageout += GetWordAddress(S.c_str(), 1); - } - else Messageout += line; - } - else Messageout += line; - - p1 = p2; - if ( *p1 == '\r' ) - p1 += 2; - p2 = _tcsstr( p1, _T("\r\n")); - if ( !p2 ) - p2 = _tcschr( p1, '\0' ); - delete [] line; - LinebreakFlag = true; - } - while ( *p1 != '\0'); - - return hasAlias ? DoIdentifiers(Messageout, window) : Messageout; -} - -CMString CIrcProto::DoIdentifiers( CMString text, const TCHAR* ) -{ - SYSTEMTIME time; - TCHAR str[2]; - - GetLocalTime( &time ); - ReplaceString( text, _T("%mnick"), m_nick); - ReplaceString( text, _T("%anick"), m_alternativeNick); - ReplaceString( text, _T("%awaymsg"), m_statusMessage.c_str()); - ReplaceString( text, _T("%module"), _A2T(m_szModuleName)); - ReplaceString( text, _T("%name"), m_name); - ReplaceString( text, _T("%newl"), _T("\r\n")); - ReplaceString( text, _T("%network"), m_info.sNetwork.c_str()); - ReplaceString( text, _T("%me"), m_info.sNick.c_str()); - - char mirver[100]; - CallService(MS_SYSTEM_GETVERSIONTEXT, SIZEOF(mirver), LPARAM(mirver)); - ReplaceString(text, _T("%mirver"), _A2T(mirver)); - - ReplaceString(text, _T("%version"), _T(__VERSION_STRING)); - - str[0] = 3; str[1] = '\0'; - ReplaceString(text, _T("%color"), str); - - str[0] = 2; - ReplaceString(text, _T("%bold"), str); - - str[0] = 31; - ReplaceString(text, _T("%underline"), str); - - str[0] = 22; - ReplaceString(text, _T("%italics"), str); - return text; -} - -static void __stdcall sttSetTimerOn( void* _pro ) -{ - CIrcProto* ppro = ( CIrcProto* )_pro; - ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT( "The buddy check function is enabled"), NULL, NULL, NULL, true, false); - ppro->SetChatTimer( ppro->OnlineNotifTimer, 500, OnlineNotifTimerProc ); - if ( ppro->m_channelAwayNotification ) - ppro->SetChatTimer( ppro->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); -} - -static void __stdcall sttSetTimerOff( void* _pro ) -{ - CIrcProto* ppro = ( CIrcProto* )_pro; - ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); - ppro->KillChatTimer( ppro->OnlineNotifTimer ); - ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); -} - -BOOL CIrcProto::DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ) -{ - TCHAR temp[30]; - lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29 ); - CharLower(temp); - CMString command = temp; - CMString one = GetWord(text.c_str(), 1); - CMString two = GetWord(text.c_str(), 2); - CMString three = GetWord(text.c_str(), 3); - CMString therest = GetWordAddress(text.c_str(), 4); - - if ( command == _T("/servershow") || command == _T("/serverhide")) { - if ( m_useServer ) { - GCEVENT gce = {0}; - GCDEST gcd = {0}; - gce.dwFlags = GC_TCHAR; - gcd.iType = GC_EVENT_CONTROL; - gcd.ptszID = SERVERWINDOW; - gcd.pszModule = m_szModuleName; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - CallChatEvent( command == _T("/servershow") ? WINDOW_VISIBLE : WINDOW_HIDDEN, (LPARAM)&gce); - } - return true; - } - - else if (command == _T("/sleep") || command == _T("/wait")) { - if (!one.IsEmpty()) { - int ms; - if (_stscanf(one.c_str(), _T("%d"), &ms) == 1 && ms > 0 && ms <= 4000) - Sleep(ms); - else - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Incorrect parameters. Usage: /sleep [ms], ms should be greater than 0 and less than 4000."), NULL, NULL, NULL, true, false); - } - return true; - } - - if (command == _T("/clear")) { - CMString S; - if ( !one.IsEmpty()) { - if ( one == _T("server")) - S = SERVERWINDOW; - else - S = MakeWndID( one.c_str()); - } - else if ( lstrcmpi( window, SERVERWINDOW) == 0 ) - S = window; - else - S = MakeWndID( window ); - - GCEVENT gce = {0}; - GCDEST gcd = {0}; - gce.cbSize = sizeof(GCEVENT); - gcd.iType = GC_EVENT_CONTROL; - gcd.pszModule = m_szModuleName; - gce.pDest = &gcd; - gce.dwFlags = GC_TCHAR; - gcd.ptszID = (TCHAR*)S.c_str(); - CallChatEvent( WINDOW_CLEARLOG, (LPARAM)&gce); - return true; - } - - if ( command == _T("/ignore")) { - if ( IsConnected()) { - CMString IgnoreFlags; - TCHAR temp[500]; - if ( one.IsEmpty()) { - if ( m_ignore ) - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); - else - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); - return true; - } - if ( !lstrcmpi( one.c_str(), _T("on"))) { - m_ignore = 1; - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); - return true; - } - if ( !lstrcmpi( one.c_str(), _T("off"))) { - m_ignore = 0; - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); - return true; - } - if ( !_tcschr( one.c_str(), '!' ) && !_tcschr( one.c_str(), '@' )) - one += _T("!*@*"); - - if ( !two.IsEmpty() && two[0] == '+' ) { - if ( _tcschr( two.c_str(), 'q')) - IgnoreFlags += 'q'; - if ( _tcschr( two.c_str(), 'n')) - IgnoreFlags += 'n'; - if ( _tcschr( two.c_str(), 'i')) - IgnoreFlags += 'i'; - if ( _tcschr( two.c_str(), 'd')) - IgnoreFlags += 'd'; - if ( _tcschr( two.c_str(), 'c')) - IgnoreFlags += 'c'; - if ( _tcschr( two.c_str(), 'm')) - IgnoreFlags += 'm'; - } - else IgnoreFlags = _T("qnidc"); - - CMString m_network; - if ( three.IsEmpty()) - m_network = m_info.sNetwork; - else - m_network = three; - - AddIgnore( one.c_str(), IgnoreFlags.c_str(), m_network.c_str()); - - mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s on %s is now ignored (+%s)"), one.c_str(), m_network.c_str(), IgnoreFlags.c_str()); - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); - } - return true; - } - - if (command == _T("/unignore")) { - if ( !_tcschr( one.c_str(), '!' ) && !_tcschr(one.c_str(), '@')) - one += _T("!*@*"); - - TCHAR temp[500]; - if ( RemoveIgnore( one.c_str())) - mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is not ignored now"), one.c_str()); - else - mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s was not ignored"), one.c_str()); - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); - return true; - } - - if ( command == _T("/userhost")) { - if ( one.IsEmpty()) - return true; - - DoUserhostWithReason( 1, _T("U"), false, temp ); - return false; - } - - if ( command == _T("/joinx")) { - if ( !one.IsEmpty()) { - for ( int i=1; ; i++ ) { - CMString tmp = GetWord( text.c_str(), i ); - if ( tmp.IsEmpty()) - break; - - AddToJTemp( 'X', tmp ); - } - - PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); - } - return true; - } - - if ( command == _T("/joinm")) { - if ( !one.IsEmpty()) { - for ( int i=1; ; i++ ) { - CMString tmp = GetWord( text.c_str(), i ); - if ( tmp.IsEmpty()) - break; - - AddToJTemp( 'M', tmp ); - } - - PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); - } - return true; - } - - if (command == _T("/nusers")) { - TCHAR szTemp[40]; - CMString S = MakeWndID(window); - GC_INFO gci = {0}; - gci.Flags = BYID|NAME|COUNT; - gci.pszModule = m_szModuleName; - gci.pszID = (TCHAR*)S.c_str(); - if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("users: %u"), gci.iCount); - - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - return true; - } - - if (command == _T("/echo")) { - if ( one.IsEmpty()) - return true; - - if ( !lstrcmpi( one.c_str(), _T("on"))) { - bEcho = TRUE; - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are shown"), NULL, NULL, NULL, true, false); - } - - if ( !lstrcmpi( one.c_str(), _T("off"))) { - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are not shown"), NULL, NULL, NULL, true, false); - bEcho = FALSE; - } - - return true; - } - - if (command == _T("/buddycheck")) { - if ( one.IsEmpty()) { - if (( m_autoOnlineNotification && !bTempDisableCheck) || bTempForceCheck ) - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is enabled"), NULL, NULL, NULL, true, false); - else - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); - return true; - } - if ( !lstrcmpi( one.c_str(), _T("on"))) { - bTempForceCheck = true; - bTempDisableCheck = false; - CallFunctionAsync( sttSetTimerOn, this ); - } - if ( !lstrcmpi( one.c_str(), _T("off"))) { - bTempForceCheck = false; - bTempDisableCheck = true; - CallFunctionAsync( sttSetTimerOff, this ); - } - if ( !lstrcmpi( one.c_str(), _T("time")) && !two.IsEmpty()) { - m_iTempCheckTime = StrToInt( two.c_str()); - if ( m_iTempCheckTime < 10 && m_iTempCheckTime != 0 ) - m_iTempCheckTime = 10; - - if ( m_iTempCheckTime == 0 ) - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The time interval for the buddy check function is now at default setting"), NULL, NULL, NULL, true, false); - else { - TCHAR temp[200]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("The time interval for the buddy check function is now %u seconds"), m_iTempCheckTime); - DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); - } } - return true; - } - - if (command == _T("/whois")) { - if ( one.IsEmpty()) - return false; - m_manualWhoisCount++; - return false; - } - - if ( command == _T("/channelmanager")) { - if ( window && !hContact && IsChannel( window )) { - if ( IsConnected()) { - if ( m_managerDlg != NULL ) { - SetActiveWindow( m_managerDlg->GetHwnd()); - m_managerDlg->Close(); - } - else { - m_managerDlg = new CManagerDlg( this ); - m_managerDlg->Show(); - m_managerDlg->InitManager( 1, window ); - } } } - - return true; - } - - if ( command == _T("/who")) { - if ( one.IsEmpty()) - return true; - - DoUserhostWithReason( 2, _T("U"), false, _T("%s"), one.c_str()); - return false; - } - - if (command == _T("/hop")) { - if ( !IsChannel( window )) - return true; - - PostIrcMessage( _T("/PART %s"), window ); - - if (( one.IsEmpty() || !IsChannel( one ))) { - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if ( wi && wi->pszPassword ) - PostIrcMessage( _T("/JOIN %s %s"), window, wi->pszPassword); - else - PostIrcMessage( _T("/JOIN %s"), window); - return true; - } - - GCEVENT gce = {0}; - GCDEST gcd = {0}; - gcd.iType = GC_EVENT_CONTROL; - CMString S = MakeWndID(window); - gcd.ptszID = (TCHAR*)S.c_str(); - gcd.pszModule = m_szModuleName; - gce.cbSize = sizeof(GCEVENT); - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); - - PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); - return true; - } - - if (command == _T("/list" )) { - if ( m_listDlg == NULL ) { - m_listDlg = new CListDlg( this ); - m_listDlg->Show(); - } - SetActiveWindow( m_listDlg->GetHwnd()); - int minutes = ( int )m_noOfChannels/4000; - int minutes2 = ( int )m_noOfChannels/9000; - - TCHAR text[256]; - mir_sntprintf( text, SIZEOF(text), TranslateT("This command is not recommended on a network of this size!\r\nIt will probably cause high CPU usage and/or high bandwidth\r\nusage for around %u to %u minute(s).\r\n\r\nDo you want to continue?"), minutes2, minutes); - if ( m_noOfChannels < 4000 || ( m_noOfChannels >= 4000 && MessageBox( NULL, text, TranslateT("IRC warning") , MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES)) { - ListView_DeleteAllItems( GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW )); - PostIrcMessage( _T("/lusers" )); - return false; - } - m_listDlg->m_status.SetText( TranslateT("Aborted")); - return true; - } - - if (command == _T("/me")) { - if ( one.IsEmpty()) - return true; - - TCHAR szTemp[4000]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\001ACTION %s\001"), GetWordAddress(text.c_str(), 1)); - PostIrcMessageWnd( window, hContact, szTemp ); - return true; - } - - if (command == _T("/ame")) { - if ( one.IsEmpty()) - return true; - - CMString S = _T("/ME ") + DoIdentifiers(GetWordAddress(text.c_str(), 1), window); - ReplaceString( S, _T("%"), _T("%%")); - DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); - return true; - } - - if (command == _T("/amsg")) { - if ( one.IsEmpty()) - return true; - - CMString S = DoIdentifiers( GetWordAddress(text.c_str(), 1), window ); - ReplaceString( S, _T("%"), _T("%%")); - DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); - return true; - } - - if (command == _T("/msg")) { - if ( one.IsEmpty() || two.IsEmpty()) - return true; - - TCHAR szTemp[4000]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); - - PostIrcMessageWnd(window, hContact, szTemp); - return true; - } - - if (command == _T("/query")) { - if ( one.IsEmpty() || IsChannel(one.c_str())) - return true; - - CONTACT user = { (TCHAR*)one.c_str(), NULL, NULL, false, false, false}; - HANDLE hContact2 = CList_AddContact(&user, false, false); - if ( hContact2 ) { - if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) - DoUserhostWithReason(1, (_T("S") + one).c_str(), true, one.c_str()); - else { - DBVARIANT dbv1; - if ( !getTString( hContact, "UWildcard", &dbv1 )) { - CMString S = _T("S"); - S += dbv1.ptszVal; - DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal); - DBFreeVariant(&dbv1); - } - else { - CMString S = _T("S"); - S += one; - DoUserhostWithReason(2, S.c_str(), true, one.c_str()); - } } - - CallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact2, 0 ); - } - - if ( !two.IsEmpty()) { - TCHAR szTemp[4000]; - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); - PostIrcMessageWnd( window, hContact, szTemp ); - } - return true; - } - - if (command == _T("/ctcp")) { - if ( one.IsEmpty() || two.IsEmpty()) - return true; - - TCHAR szTemp[1000]; - unsigned long ulAdr = 0; - if ( m_manualHost ) - ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); - else - ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); - - // if it is not dcc or if it is dcc and a local ip exist - if ( lstrcmpi( two.c_str(), _T("dcc")) != 0 || ulAdr ) { - if ( lstrcmpi( two.c_str(), _T("ping")) == 0 ) - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s %u\001"), one.c_str(), two.c_str(), time(0)); - else - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s\001"), one.c_str(), GetWordAddress(text.c_str(), 2)); - PostIrcMessageWnd( window, hContact, szTemp ); - } - - if ( lstrcmpi(two.c_str(), _T("dcc")) != 0 ) { - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s request sent to %s"), two.c_str(), one.c_str()); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } - - return true; - } - - if (command == _T("/dcc")) { - if ( one.IsEmpty() || two.IsEmpty()) - return true; - - if ( lstrcmpi( one.c_str(), _T("send")) == 0 ) { - TCHAR szTemp[1000]; - unsigned long ulAdr = 0; - - if ( m_manualHost ) - ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); - else - ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); - - if ( ulAdr ) { - CONTACT user = { (TCHAR*)two.c_str(), NULL, NULL, false, false, true }; - HANDLE hContact = CList_AddContact( &user, false, false ); - if ( hContact ) { - CMString s; - - if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) - DoUserhostWithReason( 1, (_T("S") + two).c_str(), true, two.c_str()); - else { - DBVARIANT dbv1; - CMString S = _T("S"); - if ( !getTString( hContact, "UWildcard", &dbv1 )) { - S += dbv1.ptszVal; - DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal ); - DBFreeVariant( &dbv1 ); - } - else { - S += two; - DoUserhostWithReason( 2, S.c_str(), true, two.c_str()); - } } - - if ( three.IsEmpty()) - CallService( MS_FILE_SENDFILE, ( WPARAM )hContact, 0 ); - else { - CMString temp = GetWordAddress(text.c_str(), 3); - TCHAR* pp[2]; - TCHAR* p = ( TCHAR* )temp.c_str(); - pp[0] = p; - pp[1] = NULL; - CallService( MS_FILE_SENDSPECIFICFILES, (WPARAM)hContact, (LPARAM)pp ); - } } - } - else { - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } - return true; - } - - if ( lstrcmpi( one.c_str(), _T("chat")) == 0 ) { - TCHAR szTemp[1000]; - - unsigned long ulAdr = 0; - if ( m_manualHost ) - ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); - else - ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); - - if ( ulAdr ) { - CMString contact = two; contact += _T(DCCSTRING); - CONTACT user = { (TCHAR*)contact.c_str(), NULL, NULL, false, false, true}; - HANDLE hContact = CList_AddContact( &user, false, false ); - setByte(hContact, "DCC", 1); - - int iPort = 0; - if ( hContact ) { - DCCINFO* dci = new DCCINFO; - dci->hContact = hContact; - dci->sContactName = two; - dci->iType = DCC_CHAT; - dci->bSender = true; - - CDccSession* dcc = new CDccSession(this, dci); - CDccSession* olddcc = FindDCCSession(hContact); - if ( olddcc ) - olddcc->Disconnect(); - AddDCCSession(hContact, dcc); - iPort = dcc->Connect(); - } - - if ( iPort != 0 ) { - PostIrcMessage( _T("/CTCP %s DCC CHAT chat %u %u"), two.c_str(), ulAdr, iPort ); - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC CHAT request sent to %s"), two.c_str(), one.c_str()); - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } - else { - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to bind port")); - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } - } - else { - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); - DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - } } - return true; - } - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct DoInputRequestParam -{ - DoInputRequestParam( CIrcProto* _pro, const TCHAR* _str ) : - ppro( _pro ), - str( mir_tstrdup( _str )) - {} - - CIrcProto* ppro; - TCHAR* str; -}; - -static void __stdcall DoInputRequestAliasApcStub( void* _par ) -{ - DoInputRequestParam* param = ( DoInputRequestParam* )_par; - CIrcProto* ppro = param->ppro; - TCHAR* str = param->str; - - TCHAR* infotext = NULL; - TCHAR* title = NULL; - TCHAR* defaulttext = NULL; - CMString command = ( TCHAR* )str; - TCHAR* p = _tcsstr(( TCHAR* )str, _T("%question")); - if ( p[9] == '=' && p[10] == '\"' ) { - infotext = &p[11]; - p = _tcschr( infotext, '\"' ); - if ( p ) { - *p = '\0'; - p++; - if ( *p == ',' && p[1] == '\"' ) { - p++; p++; - title = p; - p = _tcschr( title, '\"' ); - if ( p ) { - *p = '\0'; - p++; - if ( *p == ',' && p[1] == '\"' ) { - p++; p++; - defaulttext = p; - p = _tcschr( defaulttext, '\"' ); - if ( p ) - *p = '\0'; - } } } } } - - CQuestionDlg* dlg = new CQuestionDlg( ppro ); - dlg->Show(); - HWND question_hWnd = dlg->GetHwnd(); - - if ( title ) - SetDlgItemText( question_hWnd, IDC_CAPTION, title); - else - SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Input command")); - - if ( infotext ) - SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), infotext ); - else - SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter the reply")); - - if ( defaulttext ) - SetWindowText( GetDlgItem( question_hWnd, IDC_EDIT), defaulttext ); - - SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, command.c_str()); - dlg->Activate(); - - mir_free( str ); - delete param; -} - -bool CIrcProto::PostIrcMessage( const TCHAR* fmt, ... ) -{ - if ( !fmt || lstrlen(fmt) < 1 || lstrlen(fmt) > 4000 ) - return 0; - - va_list marker; - va_start( marker, fmt ); - static TCHAR szBuf[4*1024]; - mir_vsntprintf( szBuf, SIZEOF(szBuf), fmt, marker ); - va_end( marker ); - - return PostIrcMessageWnd(NULL, NULL, szBuf); -} - -bool CIrcProto::PostIrcMessageWnd( TCHAR* window, HANDLE hContact, const TCHAR* szBuf ) -{ - DBVARIANT dbv; - TCHAR windowname[256]; - BYTE bDCC = 0; - - if ( hContact ) - bDCC = getByte( hContact, "DCC", 0 ); - - if ( !IsConnected() && !bDCC || !szBuf || lstrlen(szBuf) < 1 ) - return 0; - - if ( hContact && !getTString( hContact, "Nick", &dbv )) { - lstrcpyn( windowname, dbv.ptszVal, 255); - DBFreeVariant(&dbv); - } - else if ( window ) - lstrcpyn( windowname, window, 255 ); - else - lstrcpyn( windowname, SERVERWINDOW, 255 ); - - if ( lstrcmpi( window, SERVERWINDOW) != 0 ) { - TCHAR* p1 = _tcschr( windowname, ' ' ); - if ( p1 ) - *p1 = '\0'; - } - - // remove unecessary linebreaks, and do the aliases - CMString Message = szBuf; - AddCR( Message ); - RemoveLinebreaks( Message ); - if ( !hContact && IsConnected()) { - Message = DoAlias( Message.c_str(), windowname ); - - if ( Message.Find( _T("%question")) != -1 ) { - CallFunctionAsync( DoInputRequestAliasApcStub, new DoInputRequestParam( this, Message )); - return 1; - } - - ReplaceString( Message, _T("%newl"), _T("\r\n")); - RemoveLinebreaks( Message ); - } - - if ( Message.IsEmpty()) - return 0; - - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, windowname, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - int codepage = ( wi ) ? wi->codepage : getCodepage(); - - // process the message - while ( !Message.IsEmpty()) { - // split the text into lines, and do an automatic textsplit on long lies as well - bool flag = false; - CMString DoThis = _T(""); - int index = Message.Find( _T("\r\n"), 0 ); - if ( index == -1 ) - index = Message.GetLength(); - - if ( index > 464 ) - index = 432; - DoThis = Message.Mid(0, index); - Message.Delete(0, index); - if ( Message.Find( _T("\r\n"), 0 ) == 0 ) - Message.Delete( 0, 2 ); - - //do this if it's a /raw - if ( IsConnected() && ( GetWord(DoThis.c_str(), 0) == _T("/raw") || GetWord(DoThis.c_str(), 0) == _T("/quote"))) { - if ( GetWord( DoThis.c_str(), 1 ).IsEmpty()) - continue; - - CMString S = GetWordAddress( DoThis.c_str(), 1 ); - SendIrcMessage( S.c_str(), true, codepage ); - continue; - } - - // Do this if the message is not a command - if ( (GetWord( DoThis.c_str(), 0)[0] != '/') || // not a command - ( (GetWord( DoThis.c_str(), 0)[0] == '/') && (GetWord( DoThis.c_str(), 0)[1] == '/')) || // or double backslash at the beginning - hContact ) { - CMString S = _T("/PRIVMSG "); - if ( lstrcmpi(window, SERVERWINDOW) == 0 && !m_info.sServerName.IsEmpty()) - S += m_info.sServerName + _T(" ") + DoThis; - else - S += CMString(windowname) + _T(" ") + DoThis; - - DoThis = S; - flag = true; - } - - // and here we send it unless the command was a hardcoded one that should not be sent - if ( DoHardcodedCommand( DoThis, windowname, hContact )) - continue; - - if ( !IsConnected() && !bDCC ) - continue; - - if ( !flag && IsConnected()) - DoThis = DoIdentifiers(DoThis, windowname); - - if ( hContact ) { - if ( flag && bDCC ) { - CDccSession* dcc = FindDCCSession( hContact ); - if ( dcc ) { - FormatMsg( DoThis ); - CMString mess = GetWordAddress(DoThis.c_str(), 2); - if ( mess[0] == ':' ) - mess.Delete(0,1); - mess += '\n'; - dcc->SendStuff( mess.c_str()); - } - } - else if ( IsConnected()) { - FormatMsg( DoThis ); - SendIrcMessage( DoThis.c_str(), false, codepage ); - } - } - else { - FormatMsg( DoThis ); - SendIrcMessage( DoThis.c_str(), true, codepage ); - } } - - return 1; -} diff --git a/protocols/IRCG/irc.h b/protocols/IRCG/irc.h deleted file mode 100644 index 9fe6584d87..0000000000 --- a/protocols/IRCG/irc.h +++ /dev/null @@ -1,725 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef _IRCWIN_H_ -#define _IRCWIN_H_ - -#define MIRANDA_VER 0x0A00 -#define _WIN32_WINNT 0x0501 -#define _WIN32_IE 0x0501 - -#include "m_stdhdr.h" - -#define _CRT_SECURE_NO_WARNINGS - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "newpluginapi.h" -#include "m_system.h" -#include "m_system_cpp.h" -#include "m_protocols.h" -#include "m_protomod.h" -#include "m_protosvc.h" -#include "m_protoint.h" -#include "m_clist.h" -#include "m_options.h" -#include "m_database.h" -#include "m_utils.h" -#include "m_skin.h" -#include "m_netlib.h" -#include "m_clui.h" -#include "m_langpack.h" -#include "m_message.h" -#include "m_userinfo.h" -#include "m_addcontact.h" -#include "m_button.h" -#include "m_genmenu.h" -#include "m_file.h" -#include "m_ignore.h" -#include "m_chat.h" -#include "m_icolib.h" -#include "m_ircscript.h" -#include "win2k.h" - -#include "resource.h" - -#define IRC_QUICKCONNECT "/QuickConnectMenu" -#define IRC_JOINCHANNEL "/JoinChannelMenu" -#define IRC_CHANGENICK "/ChangeNickMenu" -#define IRC_SHOWLIST "/ShowListMenu" -#define IRC_SHOWSERVER "/ShowServerMenu" -#define IRC_UM_CHANSETTINGS "/UMenuChanSettings" -#define IRC_UM_WHOIS "/UMenuWhois" -#define IRC_UM_DISCONNECT "/UMenuDisconnect" -#define IRC_UM_IGNORE "/UMenuIgnore" - -#define STR_QUITMESSAGE "\002Miranda NG!\002 Smaller, Faster, Easier. http://miranda-ng.org/" -#define STR_USERINFO "I'm a happy Miranda NG user! Get it here: http://miranda-ng.org/" -#define STR_AWAYMESSAGE "I'm away from the computer." // Default away -#define DCCSTRING " (DCC)" -#define SERVERSMODULE "IRC Servers" -#define SERVERWINDOW _T("Network log") - -#define DCC_CHAT 1 -#define DCC_SEND 2 - -#define FILERESUME_CANCEL 11 - -struct CIrcProto; - -#include "mstring.h" -typedef CMStringA String; - -// special service for tweaking performance, implemented in chat.dll -#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr" -typedef int (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam); -typedef struct { - GETEVENTFUNC pfnAddEvent; -} - GCPTRS; - -#define IP_AUTO 1 -#define IP_MANUAL 2 - -struct IPRESOLVE // Contains info about the channels -{ - IPRESOLVE( const char* _addr, int _type ) : - sAddr( _addr ), - iType( _type ) - {} - - ~IPRESOLVE() - {} - - String sAddr; - int iType; -}; - -struct CHANNELINFO // Contains info about the channels -{ - TCHAR* pszTopic; - TCHAR* pszMode; - TCHAR* pszPassword; - TCHAR* pszLimit; - BYTE OwnMode; /* own mode on the channel. Bitmask: - 0: voice - 1: halfop - 2: op - 3: admin - 4: owner */ - int codepage; -}; - -struct SERVER_INFO // Contains info about different servers -{ - ~SERVER_INFO(); - - char *m_name, *m_address, *m_group; - int m_portStart, m_portEnd, m_iSSL; -}; - -struct PERFORM_INFO // Contains 'm_perform buffer' for different networks -{ - PERFORM_INFO( const char* szSetting, const TCHAR* value ) : - mSetting( szSetting ), - mText( value ) - {} - - ~PERFORM_INFO() - {} - - String mSetting; - CMString mText; -}; - -struct CONTACT // Contains info about users -{ - TCHAR* name; - TCHAR* user; - TCHAR* host; - bool ExactOnly; - bool ExactWCOnly; - bool ExactNick; -}; - -struct TDbSetting -{ - int offset; - char* name; - int type; - size_t size; - union - { - int defValue; - TCHAR* defStr; - }; -}; - -#include "irclib.h" -using namespace irc; - -#include "irc_dlg.h" - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CIrcProto; -typedef void ( __cdecl CIrcProto::*IrcThreadFunc )( void* param ); -typedef int ( __cdecl CIrcProto::*IrcEventFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFuncParam )( WPARAM, LPARAM, LPARAM ); - -typedef bool (CIrcProto::*PfnIrcMessageHandler)(const CIrcMessage* pmsg); - -struct CIrcHandler -{ - CIrcHandler( const TCHAR* _name, PfnIrcMessageHandler _handler ) : - m_name( _name ), - m_handler( _handler ) - {} - - const TCHAR* m_name; - PfnIrcMessageHandler m_handler; -}; - -struct CIrcProto : public PROTO_INTERFACE, public MZeroedObject -{ - CIrcProto( const char*, const TCHAR* ); - ~CIrcProto(); - - // Protocol interface - - virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); - virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); - - virtual int __cdecl Authorize( HANDLE hContact ); - virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); - virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); - - virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); - - virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); - virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); - virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); - virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); - - virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); - virtual HICON __cdecl GetIcon( int iconIndex ); - virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); - - virtual HANDLE __cdecl SearchBasic( const PROTOCHAR* id ); - virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR* email ); - virtual HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName ); - virtual HWND __cdecl SearchAdvanced( HWND owner ); - virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); - - virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); - virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); - - virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); - virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); - virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); - virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); - - virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); - virtual int __cdecl SetStatus( int iNewStatus ); - - virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); - virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); - virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); - virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); - - virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); - - virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); - - // Services - INT_PTR __cdecl SvcCreateAccMgrUI( WPARAM, LPARAM ); - INT_PTR __cdecl GetMyAwayMsg( WPARAM, LPARAM ); - - INT_PTR __cdecl OnChangeNickMenuCommand( WPARAM, LPARAM ); - INT_PTR __cdecl OnDoubleclicked( WPARAM, LPARAM ); - INT_PTR __cdecl OnJoinChat( WPARAM, LPARAM ); - INT_PTR __cdecl OnJoinMenuCommand( WPARAM, LPARAM ); - INT_PTR __cdecl OnLeaveChat( WPARAM, LPARAM ); - INT_PTR __cdecl OnMenuChanSettings( WPARAM, LPARAM ); - INT_PTR __cdecl OnMenuDisconnect( WPARAM , LPARAM ); - INT_PTR __cdecl OnMenuIgnore( WPARAM, LPARAM ); - INT_PTR __cdecl OnMenuWhois( WPARAM, LPARAM ); - INT_PTR __cdecl OnQuickConnectMenuCommand(WPARAM, LPARAM ); - INT_PTR __cdecl OnShowListMenuCommand( WPARAM, LPARAM ); - INT_PTR __cdecl OnShowServerMenuCommand( WPARAM, LPARAM ); - - // Events - int __cdecl OnContactDeleted( WPARAM, LPARAM ); - int __cdecl OnInitOptionsPages( WPARAM, LPARAM ); - int __cdecl OnInitUserInfo( WPARAM, LPARAM ); - int __cdecl OnModulesLoaded( WPARAM, LPARAM ); - int __cdecl OnMenuPreBuild( WPARAM, LPARAM ); - int __cdecl OnPreShutdown( WPARAM, LPARAM ); - int __cdecl OnDbSettingChanged( WPARAM, LPARAM ); - - int __cdecl GCEventHook( WPARAM, LPARAM ); - int __cdecl GCMenuHook( WPARAM, LPARAM ); - - // Data - - char m_serverName[100]; - char m_password [500]; - TCHAR m_identSystem[10]; - char m_network[30]; - char m_portStart[10]; - char m_portEnd[10]; - int m_iSSL; - TCHAR m_identPort[10]; - TCHAR m_retryWait[10]; - TCHAR m_retryCount[10]; - TCHAR m_nick[30], m_pNick[30]; - TCHAR m_alternativeNick[30]; - TCHAR m_name[200]; - TCHAR m_userID[200]; - TCHAR m_quitMessage[400]; - TCHAR m_userInfo[500]; - char m_myHost[50]; - char m_mySpecifiedHost[500]; - char m_mySpecifiedHostIP[50]; - char m_myLocalHost[50]; - WORD m_myLocalPort; - TCHAR* m_alias; - int m_serverComboSelection; - int m_quickComboSelection; - int m_onlineNotificationTime; - int m_onlineNotificationLimit; - BYTE m_scriptingEnabled; - BYTE m_IPFromServer; - BYTE m_showAddresses; - BYTE m_disconnectDCCChats; - BYTE m_disableErrorPopups; - BYTE m_rejoinChannels; - BYTE m_rejoinIfKicked; - BYTE m_hideServerWindow; - BYTE m_ident; - BYTE m_identTimer; - BYTE m_retry; - BYTE m_disableDefaultServer; - BYTE m_autoOnlineNotification; - BYTE m_sendKeepAlive; - BYTE m_joinOnInvite; - BYTE m_perform; - BYTE m_forceVisible; - BYTE m_ignore; - BYTE m_ignoreChannelDefault; - BYTE m_useServer; - BYTE m_DCCFileEnabled; - BYTE m_DCCChatEnabled; - BYTE m_DCCChatAccept; - BYTE m_DCCChatIgnore; - BYTE m_DCCPassive; - BYTE m_DCCMode; - WORD m_DCCPacketSize; - BYTE m_manualHost; - BYTE m_oldStyleModes; - BYTE m_channelAwayNotification; - BYTE m_sendNotice; - BYTE m_utfAutodetect; - int m_codepage; - COLORREF colors[16]; - HICON hIcon[13]; - - OBJLIST vUserhostReasons; - OBJLIST vWhoInProgress; - - CRITICAL_SECTION cs; - CRITICAL_SECTION m_gchook; - CRITICAL_SECTION m_resolve; - HANDLE m_evWndCreate; - - CMString m_statusMessage; - bool m_bMbotInstalled; - int m_iTempCheckTime; - - CIrcSessionInfo si; - - int m_iRetryCount; - int m_portCount; - DWORD m_bConnectRequested; - DWORD m_bConnectThreadRunning; - - HGENMENU hMenuRoot, hMenuQuick, hMenuServer, hMenuJoin, hMenuNick, hMenuList; - HANDLE hNetlib, hNetlibDCC; - - bool bTempDisableCheck, bTempForceCheck, bEcho; - bool nickflag; - - bool bPerformDone; - - CJoinDlg* m_joinDlg; - CListDlg* m_listDlg; - CManagerDlg* m_managerDlg; - CNickDlg* m_nickDlg; - CWhoisDlg* m_whoisDlg; - CQuickDlg* m_quickDlg; - CIgnorePrefsDlg* m_ignoreDlg; - - int m_noOfChannels, m_manualWhoisCount; - String sChannelModes, sUserModes; - CMString sChannelPrefixes, sUserModePrefixes, WhoisAwayReply; - - CDlgBase::CreateParam OptCreateAccount, OptCreateConn, OptCreateIgnore, OptCreateOther; - - //clist.cpp - HANDLE CList_AddContact(struct CONTACT * user, bool InList, bool SetOnline); - bool CList_SetAllOffline(BYTE ChatsToo); - HANDLE CList_SetOffline(struct CONTACT * user); - - bool CList_AddEvent(struct CONTACT * user, HICON Icon, HANDLE event, const char * tooltip, int type ) ; - HANDLE CList_FindContact (struct CONTACT * user); - BOOL CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) ; - - //commandmonitor.cpp - UINT_PTR IdentTimer, InitTimer, KeepAliveTimer, OnlineNotifTimer, OnlineNotifTimer3; - - int AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg); - bool DoOnConnect(const CIrcMessage *pmsg); - int DoPerform(const char* event); - void __cdecl ResolveIPThread( void* di ); - - bool AddIgnore(const TCHAR* mask, const TCHAR* mode, const TCHAR* network) ; - int IsIgnored(const CMString& nick, const CMString& address, const CMString& host, char type) ; - int IsIgnored(CMString user, char type); - bool RemoveIgnore(const TCHAR* mask) ; - - //input.cpp - CMString DoAlias( const TCHAR *text, TCHAR *window); - BOOL DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ); - CMString DoIdentifiers( CMString text, const TCHAR* window ); - void FormatMsg(CMString& text); - bool PostIrcMessageWnd(TCHAR* pszWindow, HANDLE hContact,const TCHAR* szBuf); - bool PostIrcMessage( const TCHAR* fmt, ...); - - // irclib.cpp - UINT_PTR DCCTimer; - void SendIrcMessage( const TCHAR*, bool bNotify = true, int codepage = -1 ); - - // ircproto.cpp - void __cdecl AckBasicSearch( void* param ); - void __cdecl AckMessageFail( void* info ); - void __cdecl AckMessageFailDcc( void* info ); - void __cdecl AckMessageSuccess( void* info ); - - int SetStatusInternal( int iNewStatus, bool bIsInternal ); - - //options.cpp - HWND m_hwndConnect; - - OBJLIST m_ignoreItems; - - int m_channelNumber; - CMString m_whoReply; - CMString sNamesList; - CMString sTopic; - CMString sTopicName; - CMString sTopicTime; - CMString m_namesToWho; - CMString m_channelsToWho; - CMString m_namesToUserhost; - - void InitPrefs(void); - void InitIgnore(void); - - void ReadSettings( TDbSetting* sets, int count ); - void RewriteIgnoreSettings( void ); - void WriteSettings( TDbSetting* sets, int count ); - - //output - BOOL ShowMessage (const CIrcMessage* pmsg); - - //scripting.cpp - INT_PTR __cdecl Scripting_InsertRawIn(WPARAM wParam,LPARAM lParam); - INT_PTR __cdecl Scripting_InsertRawOut(WPARAM wParam,LPARAM lParam); - INT_PTR __cdecl Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam); - INT_PTR __cdecl Scripting_InsertGuiOut(WPARAM wParam,LPARAM lParam); - INT_PTR __cdecl Scripting_GetIrcData(WPARAM wparam, LPARAM lparam); - BOOL Scripting_TriggerMSPRawIn(char ** pszRaw); - BOOL Scripting_TriggerMSPRawOut(char ** pszRaw); - BOOL Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce); - BOOL Scripting_TriggerMSPGuiOut(GCHOOK * gch); - - // services.cpp - void ConnectToServer(void); - void DisconnectFromServer(void); - void DoNetlibLog( const char* fmt, ... ); - void IrcHookEvent( const char*, IrcEventFunc ); - void InitMainMenus(void); - - void ircFork( IrcThreadFunc, void* arg ); - HANDLE ircForkEx( IrcThreadFunc, void* arg ); - - UINT_PTR RetryTimer; - - void __cdecl ConnectServerThread( void* ); - void __cdecl DisconnectServerThread( void* ); - - //tools.cpp - void AddToJTemp(TCHAR op, CMString& sCommand); - bool AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic); - INT_PTR CallChatEvent(WPARAM wParam, LPARAM lParam); - void CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ); - INT_PTR DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe,time_t timestamp = 1); - void FindLocalIP(HANDLE con); - bool FreeWindowItemData(CMString window, CHANNELINFO* wis); - bool IsChannel(const char* sName); - bool IsChannel(const TCHAR* sName); - void KillChatTimer(UINT_PTR &nIDEvent); - CMString MakeWndID(const TCHAR* sWindow); - CMString ModeToStatus(int sMode); - CMString PrefixToStatus(int cPrefix); - int SetChannelSBText(CMString sWindow, CHANNELINFO * wi); - void SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc); - - void ClearUserhostReasons(int type); - void DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...); - CMString GetNextUserhostReason(int type); - CMString PeekAtReasons(int type); - - int getByte( const char* name, BYTE defaultValue ); - int getByte( HANDLE hContact, const char* name, BYTE defaultValue ); - int getDword( const char* name, DWORD defaultValue ); - int getDword( HANDLE hContact, const char* name, DWORD defaultValue ); - int getString( const char* name, DBVARIANT* ); - int getString( HANDLE hContact, const char* name, DBVARIANT* ); - int getTString( const char* name, DBVARIANT* ); - int getTString( HANDLE hContact, const char* name, DBVARIANT* ); - int getWord( const char* name, WORD defaultValue ); - int getWord( HANDLE hContact, const char* name, WORD defaultValue ); - - void setByte( const char* name, BYTE value ); - void setByte( HANDLE hContact, const char* name, BYTE value ); - void setDword( const char* name, DWORD value ); - void setDword( HANDLE hContact, const char* name, DWORD value ); - void setString( const char* name, const char* value ); - void setString( HANDLE hContact, const char* name, const char* value ); - void setTString( const char* name, const TCHAR* value ); - void setTString( HANDLE hContact, const char* name, const TCHAR* value ); - void setWord( const char* name, int value ); - void setWord( HANDLE hContact, const char* name, int value ); - - // userinfo.cpp - void __cdecl AckUserInfoSearch( void* hContact ); - - //////////////////////////////////////////////////////////////////////////////////////// - // former CIrcSession class - - void AddDCCSession(HANDLE hContact, CDccSession* dcc); - void AddDCCSession(DCCINFO* pdci, CDccSession* dcc); - void RemoveDCCSession(HANDLE hContact); - void RemoveDCCSession(DCCINFO* pdci); - - CDccSession* FindDCCSession(HANDLE hContact); - CDccSession* FindDCCSession(DCCINFO* pdci); - CDccSession* FindDCCSendByPort(int iPort); - CDccSession* FindDCCRecvByPortAndName(int iPort, const TCHAR* szName); - CDccSession* FindPassiveDCCSend(int iToken); - CDccSession* FindPassiveDCCRecv(CMString sName, CMString sToken); - - void DisconnectAllDCCSessions(bool Shutdown); - void CheckDCCTimeout(void); - - bool Connect(const CIrcSessionInfo& info); - void Disconnect(void); - void KillIdent(void); - - int NLSend(const TCHAR* fmt, ...); - int NLSend(const char* fmt, ...); - int NLSend(const unsigned char* buf, int cbBuf); - int NLSendNoScript( const unsigned char* buf, int cbBuf); - int NLReceive(unsigned char* buf, int cbBuf); - void InsertIncomingEvent(TCHAR* pszRaw); - - __inline bool IsConnected() const { return con != NULL; } - - // send-to-stream operators - int getCodepage() const; - __inline void setCodepage( int aPage ) { codepage = aPage; } - - CIrcSessionInfo m_info; - -protected : - int codepage; - HANDLE con; - HANDLE hBindPort; - void DoReceive(); - LIST m_dcc_chats; - LIST m_dcc_xfers; - -private : - CRITICAL_SECTION m_dcc; // protect the dcc objects - - void createMessageFromPchar( const char* p ); - void Notify(const CIrcMessage* pmsg); - void __cdecl ThreadProc( void *pparam ); - - //////////////////////////////////////////////////////////////////////////////////////// - // former CIrcMonitor class - - bool OnIrc_PING(const CIrcMessage* pmsg); - bool OnIrc_WELCOME(const CIrcMessage* pmsg); - bool OnIrc_YOURHOST(const CIrcMessage* pmsg); - bool OnIrc_NICK(const CIrcMessage* pmsg); - bool OnIrc_PRIVMSG(const CIrcMessage* pmsg); - bool OnIrc_JOIN(const CIrcMessage* pmsg); - bool OnIrc_QUIT(const CIrcMessage* pmsg); - bool OnIrc_PART(const CIrcMessage* pmsg); - bool OnIrc_KICK(const CIrcMessage* pmsg); - bool OnIrc_MODE(const CIrcMessage* pmsg); - bool OnIrc_USERHOST_REPLY(const CIrcMessage* pmsg); - bool OnIrc_MODEQUERY(const CIrcMessage* pmsg); - bool OnIrc_NAMES(const CIrcMessage* pmsg); - bool OnIrc_ENDNAMES(const CIrcMessage* pmsg); - bool OnIrc_INITIALTOPIC(const CIrcMessage* pmsg); - bool OnIrc_INITIALTOPICNAME(const CIrcMessage* pmsg); - bool OnIrc_TOPIC(const CIrcMessage* pmsg); - bool OnIrc_TRYAGAIN(const CIrcMessage* pmsg); - bool OnIrc_NOTICE(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_NAME(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_CHANNELS(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_SERVER(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_AWAY(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_IDLE(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_END(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_OTHER(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_AUTH(const CIrcMessage* pmsg); - bool OnIrc_WHOIS_NO_USER(const CIrcMessage* pmsg); - bool OnIrc_NICK_ERR(const CIrcMessage* pmsg); - bool OnIrc_ENDMOTD(const CIrcMessage* pmsg); - bool OnIrc_LISTSTART(const CIrcMessage* pmsg); - bool OnIrc_LIST(const CIrcMessage* pmsg); - bool OnIrc_LISTEND(const CIrcMessage* pmsg); - bool OnIrc_BANLIST(const CIrcMessage* pmsg); - bool OnIrc_BANLISTEND(const CIrcMessage* pmsg); - bool OnIrc_SUPPORT(const CIrcMessage* pmsg); - bool OnIrc_BACKFROMAWAY(const CIrcMessage* pmsg); - bool OnIrc_SETAWAY(const CIrcMessage* pmsg); - bool OnIrc_JOINERROR(const CIrcMessage* pmsg); - bool OnIrc_UNKNOWN(const CIrcMessage* pmsg); - bool OnIrc_ERROR(const CIrcMessage* pmsg); - bool OnIrc_NOOFCHANNELS(const CIrcMessage* pmsg); - bool OnIrc_PINGPONG(const CIrcMessage* pmsg); - bool OnIrc_INVITE(const CIrcMessage* pmsg); - bool OnIrc_WHO_END(const CIrcMessage* pmsg); - bool OnIrc_WHO_REPLY(const CIrcMessage* pmsg); - bool OnIrc_WHOTOOLONG(const CIrcMessage* pmsg); - - bool IsCTCP(const CIrcMessage* pmsg); - - void OnIrcDefault(const CIrcMessage* pmsg); - void OnIrcDisconnected(); - - static OBJLIST m_handlers; - - PfnIrcMessageHandler FindMethod(const TCHAR* lpszName); - - void OnIrcMessage(const CIrcMessage* pmsg); - CMString sNick4Perform; -}; - -// map actual member functions to their associated IRC command. -// put any number of this macro in the class's constructor. -#define IRC_MAP_ENTRY(name, member) \ - m_handlers.insert( new CIrcHandler( _T(name), &CIrcProto::OnIrc_##member )); - -///////////////////////////////////////////////////////////////////////////////////////// -// Functions - -//main.cpp -extern HINSTANCE hInst; - -extern LIST g_Instances; - -extern OBJLIST g_servers; - -void UpgradeCheck(void); - -CIrcProto* GetTimerOwner( UINT_PTR eventId ); - -VOID CALLBACK IdentTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK KeepAliveTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK OnlineNotifTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK OnlineNotifTimerProc3( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK DCCTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); -VOID CALLBACK RetryTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); - -// options.cpp - -void InitServers(void); -void RereadServers(void); - -void InitContactMenus(void); -void UninitContactMenus(void); - -void WindowSetIcon(HWND hWnd, int iconId); -void WindowFreeIcon(HWND hWnd); - -void AddIcons(void); -void UninitIcons(void); -HICON LoadIconEx(int iIndex, bool big = false); -HANDLE GetIconHandle(int iconId); -void ReleaseIconEx(HICON hIcon); - -// services.cpp - -extern BOOL bChatInstalled, m_bMbotInstalled; - -//tools.cpp -int __stdcall WCCmp(const TCHAR* wild, const TCHAR* string); -char* __stdcall IrcLoadFile(TCHAR * szPath); -CMString __stdcall GetWord(const TCHAR* text, int index); -CMString& __stdcall ReplaceString (CMString& text, const TCHAR* replaceme, const TCHAR* newword); -const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index); -void __stdcall RemoveLinebreaks( CMString& Message ); -TCHAR* __stdcall my_strstri(const TCHAR *s1, const TCHAR *s2) ; -TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent); - -String& __stdcall ReplaceString (String& text, const char* replaceme, const char* newword); -String __stdcall GetWord(const char* text, int index); - -#pragma comment(lib,"comctl32.lib") - -#endif diff --git a/protocols/IRCG/irc_dlg.h b/protocols/IRCG/irc_dlg.h deleted file mode 100644 index 887e9f0d0c..0000000000 --- a/protocols/IRCG/irc_dlg.h +++ /dev/null @@ -1,329 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "ui_utils.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// Dialogs - -struct CMessageBoxDlg : public CProtoDlgBase -{ - DCCINFO* pdci; - - CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ); - - CCtrlButton m_Ok; - void OnOk( CCtrlButton* ); - - virtual void OnInitDialog(); -}; - -struct CCoolIrcDlg : public CProtoDlgBase -{ - CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent = NULL ); - - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - virtual void OnInitDialog(); - virtual void OnDestroy(); -}; - -struct CWhoisDlg : public CCoolIrcDlg -{ - CWhoisDlg( CIrcProto* _pro ); - - CCtrlCombo m_InfoNick; - CCtrlEdit m_Reply; - CCtrlBase m_Caption, m_AwayTime; - CCtrlBase m_InfoName, m_InfoId, m_InfoAddress, m_InfoChannels, m_InfoAuth, - m_InfoServer, m_InfoAway2, m_InfoOther; - CCtrlButton m_Ping, m_Version, m_Time, m_userInfo, m_Refresh, m_Query; - - void ShowMessage( const CIrcMessage* ); - void ShowMessageNoUser( const CIrcMessage* ); - - void OnGo( CCtrlButton* ); - void OnQuery( CCtrlButton* ); - void OnPing( CCtrlButton* ); - void OnUserInfo( CCtrlButton* ); - void OnTime( CCtrlButton* ); - void OnVersion( CCtrlButton* ); - - virtual void OnInitDialog(); - virtual void OnClose(); - virtual void OnDestroy(); -}; - -struct CNickDlg : public CCoolIrcDlg -{ - CNickDlg( CIrcProto* _pro ); - - CCtrlCombo m_Enick; - CCtrlButton m_Ok; - - virtual void OnInitDialog(); - virtual void OnDestroy(); - - void OnOk( CCtrlButton* ); -}; - -struct CListDlg : public CProtoDlgBase -{ - CListDlg( CIrcProto* _pro ); - - virtual void OnInitDialog(); - virtual void OnChange( CCtrlBase* ctrl ); - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - virtual void OnDestroy(); - virtual int Resizer(UTILRESIZECONTROL *urc); - - TCHAR m_title[255]; - CCtrlListView m_list, m_list2; - CCtrlEdit m_filter, m_status; - UINT_PTR m_timer; - - CCtrlButton m_Join; - void OnJoin( CCtrlButton* ); - - void List_OnColumnClick( CCtrlListView::TEventInfo* ev ); - - void UpdateList( void ); -}; - -struct CJoinDlg : public CCoolIrcDlg -{ - CJoinDlg( CIrcProto* _pro ); - - virtual void OnInitDialog(); - virtual void OnDestroy(); - - CCtrlButton m_Ok; - void OnOk( CCtrlButton* ); -}; - -struct CQuickDlg : public CCoolIrcDlg -{ - CQuickDlg( CIrcProto* _pro ); - - virtual void OnInitDialog(); - virtual void OnDestroy(); - - CCtrlCombo m_serverCombo; - void OnServerCombo( CCtrlData* ); - - CCtrlButton m_Ok; - void OnOk( CCtrlButton* ); - -private: - struct SERVER_INFO* m_si; -}; - -struct CManagerDlg : public CCoolIrcDlg -{ - CManagerDlg( CIrcProto* _pro ); - - CCtrlCheck m_check1, m_check2, m_check3, m_check4, m_check5, m_check6, m_check7, m_check8, m_check9; - CCtrlEdit m_key, m_limit; - CCtrlCombo m_topic; - CCtrlCheck m_radio1, m_radio2, m_radio3; - CCtrlMButton m_add, m_edit, m_remove, m_applyTopic, m_applyModes; - CCtrlListBox m_list; - - virtual void OnInitDialog(); - virtual void OnClose(); - virtual void OnDestroy(); - - void OnCheck( CCtrlData* ); - void OnCheck5( CCtrlData* ); - void OnCheck6( CCtrlData* ); - void OnRadio( CCtrlData* ); - - void OnAdd( CCtrlButton* ); - void OnEdit( CCtrlButton* ); - void OnRemove( CCtrlButton* ); - - void OnListDblClick( CCtrlListBox* ); - void OnChangeList( CCtrlListBox* ); - void OnChangeModes( CCtrlData* ); - void OnChangeTopic( CCtrlData* ); - - void OnApplyModes( CCtrlButton* ); - void OnApplyTopic( CCtrlButton* ); - - void ApplyQuestion(); - void CloseQuestion(); - void InitManager( int mode, const TCHAR* window ); -}; - -struct CQuestionDlg : public CCoolIrcDlg -{ - CQuestionDlg( CIrcProto* _pro, CManagerDlg* owner = NULL ); - - virtual void OnInitDialog(); - virtual void OnClose(); - - CCtrlButton m_Ok; - void OnOk( CCtrlButton* ); - - void Activate(); - -private: - CManagerDlg* m_owner; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// options - -//---- the first property page: Account ------------------------------------------------- - -struct CConnectPrefsDlg : public CProtoDlgBase -{ - bool m_serverlistModified; - - CCtrlCombo m_serverCombo; - CCtrlEdit m_server, m_port, m_port2, m_pass; - CCtrlMButton m_add, m_edit, m_del; - CCtrlEdit m_nick, m_nick2, m_name, m_userID; - - CCtrlCheck m_ident, m_identTimer; - CCtrlEdit m_identSystem, m_identPort; - - CCtrlCheck m_retry; - CCtrlEdit m_retryCount, m_retryWait; - - CCtrlCheck m_forceVisible, m_rejoinOnKick, m_rejoinChannels, m_disableError, - m_address, m_useServer, m_showServer, m_keepAlive, m_autoJoin, - m_oldStyle, m_onlineNotif, m_channelAway, m_enableServer; - CCtrlEdit m_onlineTimer, m_limit, m_spin1, m_spin2, m_ssl; - - CConnectPrefsDlg( CIrcProto* _pro ); - - static CDlgBase* Create( void* param ) { return new CConnectPrefsDlg(( CIrcProto* )param ); } - - virtual void OnInitDialog(); - virtual void OnApply(); - - void OnServerCombo( CCtrlData* ); - void OnAddServer( CCtrlButton* ); - void OnDeleteServer( CCtrlButton* ); - void OnEditServer( CCtrlButton* ); - void OnStartup( CCtrlData* ); - void OnIdent( CCtrlData* ); - void OnUseServer( CCtrlData* ); - void OnOnlineNotif( CCtrlData* ); - void OnChannelAway( CCtrlData* ); - void OnRetry( CCtrlData* ); -}; - -//---- the second property page: DCC/CTCP ----------------------------------------------- - -struct CCtcpPrefsDlg : public CProtoDlgBase -{ - CCtrlCombo m_combo; - CCtrlCheck m_slow, m_fast, m_disc, m_passive, m_sendNotice, m_enableIP, m_fromServer; - CCtrlEdit m_ip, m_userInfo; - CCtrlCheck m_radio1, m_radio2, m_radio3; - - CCtcpPrefsDlg( CIrcProto* _pro ); - - static CDlgBase* Create( void* param ) { return new CCtcpPrefsDlg(( CIrcProto* )param ); } - - virtual void OnInitDialog(); - virtual void OnApply(); - - void OnClicked( CCtrlData* ); -}; - -//---- the third property page: Other --------------------------------------------------- - -struct COtherPrefsDlg : public CProtoDlgBase -{ - bool m_performlistModified; - - CCtrlButton m_url; - CCtrlMButton m_add, m_delete; - CCtrlCombo m_performCombo, m_codepage; - CCtrlEdit m_pertormEdit, m_quitMessage, m_alias; - CCtrlCheck m_perform, m_scripting, m_autodetect; - - COtherPrefsDlg( CIrcProto* _pro ); - - static CDlgBase* Create( void* param ) { return new COtherPrefsDlg(( CIrcProto* )param ); } - - virtual void OnInitDialog(); - virtual void OnApply(); - virtual void OnDestroy(); - - void OnUrl( CCtrlButton* ); - void OnPerformCombo( CCtrlData* ); - void OnCodePage( CCtrlData* ); - void OnPerformEdit( CCtrlData* ); - void OnPerform( CCtrlData* ); - void OnAdd( CCtrlButton* ); - void OnDelete( CCtrlButton* ); - - void addPerformComboValue( int idx, const char* szValueName ); -}; - -//---- the fourth property page: Ignore ------------------------------------------------- - -struct CIgnorePrefsDlg : public CProtoDlgBase -{ - CCtrlMButton m_add, m_edit, m_del; - CCtrlCheck m_enable, m_ignoreChat, m_ignoreFile, m_ignoreChannel, m_ignoreUnknown; - CCtrlListView m_list; - - CIgnorePrefsDlg( CIrcProto* _pro ); - - static CDlgBase* Create( void* param ) { return new CIgnorePrefsDlg(( CIrcProto* )param ); } - - virtual void OnInitDialog(); - virtual void OnDestroy(); - virtual void OnApply(); - - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - void List_OnColumnClick( CCtrlListView::TEventInfo* ); - void OnEnableIgnore( CCtrlData* ); - void OnIgnoreChat( CCtrlData* ); - void OnAdd( CCtrlButton* ); - void OnEdit( CCtrlButton* ); - void OnDelete( CCtrlButton* ); - - void FixButtons( void ); - void RebuildList( void ); - void UpdateList( void ); -}; - -struct CAddIgnoreDlg : public CProtoDlgBase -{ - CCtrlButton m_Ok; - CIgnorePrefsDlg* m_owner; - - TCHAR szOldMask[500]; - - CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* parent ); - - virtual void OnInitDialog(); - virtual void OnClose(); - - void OnOk( CCtrlButton* ); -}; diff --git a/protocols/IRCG/ircg-translation.txt b/protocols/IRCG/ircg-translation.txt deleted file mode 100644 index 2c072af2d4..0000000000 --- a/protocols/IRCG/ircg-translation.txt +++ /dev/null @@ -1,409 +0,0 @@ -; Common strings that belong to many files -;[Auto] -;[Channel manager] -;[DCC ERROR: Unable to automatically resolve external IP] -;[Default network] -;[IRC Error] -;[IRC error] -;[IRC warning] -;[Ignore] -;[Jerk] -;[Network] -;[Off] -;[On] -;[Please enter the reason] -;[Question] -;[Quick connect] -;[Send notice] -;[The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically.] -;[Topic] -;[User information] - -; ../../protocols/IRCG/IRC.rc -;[&Accept] -;[&Add] -;[&Cancel] -;[&Clear all] -;[&Close] -;[&Del] -;[&Deny] -;[&Edit] -;[&Join] -;[&OK] -;[&Query] -;[&Refresh] -;[&Save] -;[&Set] -;['Old style' mode changes] -;[(*) Queries from users on your contactlist are never ignored] -;[(*) blank to set this mask for all networks] -;[Add server] -;[Address] -;[Alias] -;[Alternate nick] -;[Alternative nick] -;[Attempt reverse DCC (good if firewalled)] -;[Auth] -;[Auto-accept from:] -;[Automatically join on invite] -;[Away Info] -;[Bans] -;[Basic] -;[C&onnect] -;[CTCP] -;[CTCP Chat Request] -;[CTCP information] -;[Channel modes] -;[Channels] -;[Channels on server] -;[Check every (s):] -;[Client-to-Client Chats] -;[Client-to-Client File Transfers] -;[Client-to-Client Protocol] -;[DCC] -;[Disable tray balloon on error] -;[Disconnect DCC chats when disconnecting from server] -;[Don't check if more than (users):] -;[Enable] -;[Enable (*)] -;[Enable UTF8 autodetection] -;[Excepts] -;[Fear the monkeys!!!] -;[Filter by] -;[Force visible (-i)] -;[Full name (e-mail)] -;[Get IP address from server] -;[Hidden] -;[Host address] -;[Hostmask] -;[Ident] -;[Ignore DCC Chat requests] -;[Ignore DCC Chat requests from unknown contacts] -;[Ignore channel messages by default] -;[Ignore events] -;[Ignore filetransfer requests] -;[Ignore mask ( nick!user@host )] -;[Ignore users] -;[Internet address] -;[Invite only] -;[Invites] -;[Keep connection alive] -;[Key:] -;[Manually set external IP:] -;[Messages] -;[Moderated] -;[Name] -;[Network (*)] -;[Nick] -;[No external messages] -;[Normal] -;[Notices] -;[Online detection mode] -;[Only Ops set topic] -;[Other] -;[Packet size (b):] -;[Password] -;[Password:] -;[Perform] -;[Perform on event:] -;[Ping] -;[Port] -;[Port range] -;[Private] -;[Queries] -;[Quit message:] -;[Reconnect] -;[Rejoin channel if kicked] -;[Rejoin channels on reconnect] -;[Retry count] -;[SSL] -;[Scripting support] -;[Secret] -;[Send mode:] -;[Send-ahead] -;[Server] -;[Server code page:] -;[Server description] -;[Server name] -;[Server:] -;[Show addresses] -;[Show server window on startup] -;[Spin1] -;[Spin2] -;[Strip colors] -;[System] -;[The server returned the following information. Please note that this information might be misleading and/or falsified] -;[Time] -;[Update online statuses for users] -;[Update statuses in channel nicklist] -;[Use server window] -;[Use the options to set modes for this channel. You are usually required to be op. or higher to modify.] -;[User] -;[User ID (Ident)] -;[User info - Required] -;[User limit:] -;[User modes] -;[Userinfo] -;[Version] -;[Wait (s)] -;[Wildcard enabled network search] -;[everyone] -;[everyone on the contact list] -;[none] -;[only while connecting] - -; ../../protocols/IRCG/clist.cpp -;[CTCP chat request from %s] - -; ../../protocols/IRCG/commandmonitor.cpp -;[%s sets mode %s] -;[%s sets mode %s%s] -;[(probably truncated by server)] -;[*Disconnected*] -;[Ban'n Kick] -;[CTCP %s reply from %s: %s] -;[CTCP %s requested by %s] -;[CTCP ERROR: Malformed CTCP command received from %s!%s@%s. Possible attempt to take control of your irc client registered] -;[CTCP FINGER requested by %s] -;[CTCP PING reply from %s: %u sec(s)] -;[CTCP PING requested by %s] -;[CTCP SOURCE requested by %s] -;[CTCP TIME requested by %s] -;[CTCP USERINFO requested by %s] -;[CTCP VERSION requested by %s] -;[Change nickname] -;[DCC ERROR: Malformed CTCP request from %s [%s]] -;[DCC: Chat request from %s denied] -;[DCC: File transfer request from %s denied] -;[DCC: File transfer resume request from %s denied] -;[DCC: Reverse file transfer request from %s denied [No local IP]] -;[Done: %u channels] -;[Downloading list (%u%%) - %u channels] -;[Downloading list - %u channels] -;[Please enter the hostmask (nick!user@host)\nNOTE! Contacts on your contact list are never ignored] -;[Unknown] - -; ../../protocols/IRCG/input.cpp -;[%s is not ignored now] -;[%s on %s is now ignored (+%s)] -;[%s was not ignored] -;[Aborted] -;[CTCP %s request sent to %s] -;[DCC CHAT request sent to %s] -;[DCC ERROR: Unable to bind port] -;[Ignore system is disabled] -;[Ignore system is enabled] -;[Incorrect parameters. Usage: /sleep [ms], ms should be greater than 0 and less than 4000.] -;[Input command] -;[Outgoing commands are not shown] -;[Outgoing commands are shown] -;[Please enter the reply] -;[The buddy check function is disabled] -;[The buddy check function is enabled] -;[The time interval for the buddy check function is now %u seconds] -;[The time interval for the buddy check function is now at default setting] -;[This command is not recommended on a network of this size!\r\nIt will probably cause high CPU usage and/or high bandwidth\r\nusage for around %u to %u minute(s).\r\n\r\nDo you want to continue?] - -; ../../protocols/IRCG/irclib.cpp -;[DCC ERROR: Unable to bind local port for passive filetransfer] -;[Failed to connect to] - -; ../../protocols/IRCG/ircproto.cpp -;[%s client-to-client connections] -;[%s server connection] -;[Connection can not be established! You have not completed all necessary fields (Nickname, User ID and m_name).] -;[DCC ERROR: No valid files specified] -;[DCC ERROR: Unable to bind local port] -;[DCC file transfer request sent to %s [%s]] -;[DCC reversed file transfer request sent to %s [%s]] -;[Information] -;[Nickname] -;[Please choose an IRC-network to go online. This network will be the default.] -;[The IRC protocol depends on another plugin called \'Chat\'\n\nDo you want to download it from the Miranda IM web site now?] -;[The dcc chat connection is not active] -;[The protocol is not online] - -; ../../protocols/IRCG/options.cpp -;[] -;[m_name, p2->m_name ); -} - -OBJLIST CIrcProto::m_handlers( 30, CompareHandlers ); - -//////////////////////////////////////////////////////////////////// - -CIrcMessage::CIrcMessage( CIrcProto* _pro, const TCHAR* lpszCmdLine, int codepage, bool bIncoming, bool bNotify ) : - m_proto( _pro ), - m_bIncoming( bIncoming ), - m_bNotify( bNotify ), - m_codePage( codepage ), - parameters( 10 ) -{ - ParseIrcCommand(lpszCmdLine); -} - -CIrcMessage::CIrcMessage(const CIrcMessage& m) : - sCommand( m.sCommand ), - m_bIncoming( m.m_bIncoming ), - m_bNotify( m.m_bNotify ), - m_codePage( m.m_codePage ), - m_proto( m.m_proto ), - parameters( m.parameters.getCount()) -{ - prefix.sNick = m.prefix.sNick; - prefix.sUser = m.prefix.sUser; - prefix.sHost = m.prefix.sHost; - - for ( int i=0; i < m.parameters.getCount(); i++ ) - parameters.insert( new CMString( m.parameters[i] )); -} - -CIrcMessage::~CIrcMessage() -{ -} - -void CIrcMessage::Reset() -{ - prefix.sNick = prefix.sUser = prefix.sHost = sCommand = _T(""); - m_bIncoming = false; - m_bNotify = true; - - parameters.destroy(); -} - -CIrcMessage& CIrcMessage::operator = (const CIrcMessage& m) -{ - if ( &m != this ) { - sCommand = m.sCommand; - parameters = m.parameters; - prefix.sNick = m.prefix.sNick; - prefix.sUser = m.prefix.sUser; - prefix.sHost = m.prefix.sHost; - m_bIncoming = m.m_bIncoming; - m_bNotify = m.m_bNotify; - } - return *this; -} - -CIrcMessage& CIrcMessage::operator = (const TCHAR* lpszCmdLine) -{ - Reset(); - ParseIrcCommand(lpszCmdLine); - return *this; -} - -void CIrcMessage::ParseIrcCommand(const TCHAR* lpszCmdLine) -{ - const TCHAR* p1 = lpszCmdLine; - const TCHAR* p2 = lpszCmdLine; - - // prefix exists ? - if ( *p1 == ':' ) { - // break prefix into its components (nick!user@host) - p2 = ++p1; - while( *p2 && !_tcschr( _T(" !"), *p2 )) - ++p2; - prefix.sNick.SetString(p1, p2 - p1); - if ( *p2 != '!' ) - goto end_of_prefix; - p1 = ++p2; - while( *p2 && !_tcschr( _T(" @"), *p2 )) - ++p2; - prefix.sUser.SetString(p1, p2 - p1); - if ( *p2 != '@' ) - goto end_of_prefix; - p1 = ++p2; - while( *p2 && *p2 != ' ' ) - ++p2; - prefix.sHost.SetString(p1, p2 - p1); -end_of_prefix : - while( *p2 && *p2 == ' ' ) - ++p2; - p1 = p2; - } - - // get command - p2 = p1; - while( *p2 && *p2 != ' ' ) - ++p2; - - sCommand.SetString(p1, p2 - p1); - sCommand.MakeUpper(); - while( *p2 && *p2 == ' ' ) - ++p2; - p1 = p2; - - // get parameters - while( *p1 ) { - if ( *p1 == ':' ) { - ++p1; - - // seek end-of-message - while( *p2 ) - ++p2; - parameters.insert( new CMString(p1, p2 - p1)); - break; - } - else { - // seek end of parameter - while( *p2 && *p2 != ' ' ) - ++p2; - parameters.insert( new CMString(p1, p2 - p1)); - // see next parameter - while( *p2 && *p2 == ' ' ) - ++p2; - p1 = p2; -} } } - -//////////////////////////////////////////////////////////////////// - -int CIrcProto::getCodepage() const -{ - return ( con != NULL ) ? codepage : CP_ACP; -} - -void CIrcProto::SendIrcMessage( const TCHAR* msg, bool bNotify, int codepage ) -{ - if ( codepage == -1 ) - codepage = getCodepage(); - - if ( this ) { - char* str = mir_t2a_cp( msg, codepage ); - rtrim( str ); - int cbLen = (int)strlen( str ); - str = ( char* )mir_realloc( str, cbLen+3 ); - strcat( str, "\r\n" ); - NLSend(( const BYTE* )str, cbLen+2 ); - mir_free( str ); - - if ( bNotify ) { - CIrcMessage ircMsg( this, msg, codepage ); - if ( !ircMsg.sCommand.IsEmpty() && ircMsg.sCommand != _T("QUIT")) - Notify( &ircMsg ); -} } } - -bool CIrcProto::Connect(const CIrcSessionInfo& info) -{ - codepage = m_codepage; - - NETLIBOPENCONNECTION ncon = { 0 }; - ncon.cbSize = sizeof(ncon); - ncon.szHost = info.sServer.c_str(); - ncon.wPort = info.iPort; - con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM) hNetlib, (LPARAM) & ncon); - if (con == NULL) { - TCHAR szTemp[300]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0035%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)."), - TranslateT("Failed to connect to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); - return false; - } - - FindLocalIP(con); // get the local ip used for filetransfers etc - - if ( info.m_iSSL > 0 ) { - if ( !CallService( MS_NETLIB_STARTSSL, ( WPARAM ) con, 0 ) && info.m_iSSL == 2 ) { - Netlib_CloseHandle( con ); - con = NULL; - m_info.Reset(); - return false; - } } - - if ( Miranda_Terminated()) { - Disconnect(); - return false; - } - - m_info = info; - - // start receiving messages from host - ircFork( &CIrcProto::ThreadProc, NULL ); - Sleep( 100 ); - if ( info.sPassword.GetLength()) - NLSend( "PASS %s\r\n", info.sPassword.c_str()); - NLSend( _T("NICK %s\r\n"), info.sNick.c_str()); - - CMString m_userID = GetWord(info.sUserID.c_str(), 0); - TCHAR szHostName[MAX_PATH]; - DWORD cbHostName = SIZEOF( szHostName ); - GetComputerName(szHostName, &cbHostName); - CMString HostName = GetWord(szHostName, 0); - if ( m_userID.IsEmpty()) - m_userID = _T("Miranda"); - if ( HostName.IsEmpty()) - HostName= _T("host"); - NLSend( _T("USER %s %s %s :%s\r\n"), m_userID.c_str(), HostName.c_str(), _T("server"), info.sFullName.c_str()); - - return con != NULL; -} - -void CIrcProto::Disconnect(void) -{ - static const DWORD dwServerTimeout = 5 * 1000; - - if ( con == NULL ) - return; - - KillIdent(); - - if ( m_quitMessage && m_quitMessage[0] ) - NLSend( _T("QUIT :%s\r\n"), m_quitMessage); - else - NLSend( "QUIT \r\n" ); - - Sleep(50); - - if ( con ) - Netlib_Shutdown(con); - - m_info.Reset(); - return; -} - -void CIrcProto::Notify(const CIrcMessage* pmsg) -{ - OnIrcMessage(pmsg); -} - -int CIrcProto::NLSend( const unsigned char* buf, int cbBuf) -{ - if ( m_bMbotInstalled && m_scriptingEnabled ) { - int iVal = NULL; - char * pszTemp = 0; - pszTemp = ( char* ) mir_alloc( lstrlenA((const char *) buf ) + 1); - lstrcpynA(pszTemp, (const char *)buf, lstrlenA ((const char *)buf) + 1); - - if ( Scripting_TriggerMSPRawOut(&pszTemp) && pszTemp ) { - if (con) - iVal = Netlib_Send(con, (const char*)pszTemp, lstrlenA(pszTemp), MSG_DUMPASTEXT); - } - if ( pszTemp ) - mir_free( pszTemp ); - - return iVal; - } - - if (con) - return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); - - return 0; -} - -int CIrcProto::NLSend( const TCHAR* fmt, ...) -{ - va_list marker; - va_start(marker, fmt); - - TCHAR szBuf[1024*4]; - mir_vsntprintf(szBuf, SIZEOF(szBuf), fmt, marker); - va_end(marker); - - char* buf = mir_t2a_cp( szBuf, getCodepage()); - int result = NLSend((unsigned char*)buf, (int)strlen(buf)); - mir_free( buf ); - return result; -} - -int CIrcProto::NLSend( const char* fmt, ...) -{ - va_list marker; - va_start(marker, fmt); - - char szBuf[1024*4]; - int cbLen = mir_vsnprintf(szBuf, SIZEOF(szBuf), fmt, marker); - va_end(marker); - - return NLSend((unsigned char*)szBuf, cbLen ); -} - -int CIrcProto::NLSendNoScript( const unsigned char* buf, int cbBuf) -{ - if ( con ) - return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); - - return 0; -} - -int CIrcProto::NLReceive(unsigned char* buf, int cbBuf) -{ - return Netlib_Recv( con, (char*)buf, cbBuf, MSG_DUMPASTEXT ); -} - -void CIrcProto::KillIdent() -{ - if ( hBindPort ) { - HANDLE hPort = hBindPort; - hBindPort = NULL; - Netlib_CloseHandle( hPort ); - } -} - -void CIrcProto::InsertIncomingEvent(TCHAR* pszRaw) -{ - CIrcMessage msg( this, pszRaw, true); - Notify( &msg ); - return; -} - -void CIrcProto::createMessageFromPchar( const char* p ) -{ - TCHAR* ptszMsg; - if ( codepage != CP_UTF8 && m_utfAutodetect ) { - if ( mir_utf8decodecp( NEWSTR_ALLOCA(p), codepage, &ptszMsg ) == NULL ) - ptszMsg = mir_a2t_cp( p, codepage ); - } - else ptszMsg = mir_a2t_cp( p, codepage ); - CIrcMessage msg( this, ptszMsg, codepage, true ); - Notify( &msg ); - mir_free( ptszMsg ); -} - -void CIrcProto::DoReceive() -{ - char chBuf[1024*4+1]; - int cbInBuf = 0; - - if ( m_info.bIdentServer && m_info.iIdentServerPort != NULL ) { - NETLIBBIND nb = {0}; - nb.cbSize = sizeof(NETLIBBIND); - nb.pfnNewConnectionV2 = DoIdent; - nb.pExtra = this; - nb.wPort = m_info.iIdentServerPort; - hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)hNetlib,(LPARAM) &nb); - if ( !hBindPort || nb.wPort != m_info.iIdentServerPort ) { - DoNetlibLog("Error: unable to bind local port %u", m_info.iIdentServerPort); - KillIdent(); - } } - - while( con ) { - int nLinesProcessed = 0; - - int cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); - if ( cbRead <= 0 ) - break; - - cbInBuf += cbRead; - chBuf[cbInBuf] = '\0'; - - char* pStart = chBuf; - while( *pStart ) { - char* pEnd; - - // seek end-of-line - for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) - ; - if ( *pEnd == '\0' ) - break; // uncomplete message. stop parsing. - - ++nLinesProcessed; - - // replace end-of-line with NULLs and skip - while( *pEnd == '\r' || *pEnd == '\n' ) - *pEnd++ = '\0'; - - // process single message by monitor objects - if ( *pStart ) { - if ( m_bMbotInstalled && m_scriptingEnabled ) { - char* pszTemp = mir_strdup( pStart ); - - if ( Scripting_TriggerMSPRawIn( &pszTemp ) && pszTemp ) { - char* p1 = pszTemp; - // replace end-of-line with NULLs - while( *p1 != '\0' ) { - if ( *p1 == '\r' || *p1 == '\n') - *p1 = '\0'; - p1++; - } - - createMessageFromPchar( pszTemp ); - } - - mir_free( pszTemp ); - } - else createMessageFromPchar( pStart ); - } - - cbInBuf -= pEnd - pStart; - pStart = pEnd; - } - - // discard processed messages - if ( nLinesProcessed != 0 ) - memmove(chBuf, pStart, cbInBuf+1); - } - - if ( con ) { - Netlib_CloseHandle(con); - con = NULL; - } - - // notify monitor objects that the connection has been closed - Notify(NULL); -} - -void __cdecl CIrcProto::ThreadProc( void* ) -{ - DoReceive(); - m_info.Reset(); -} - -void CIrcProto::AddDCCSession(HANDLE, CDccSession* dcc) -{ - EnterCriticalSection(&m_dcc); - - CDccSession* p = m_dcc_chats.find(dcc); - if ( p ) - m_dcc_chats.remove( p ); - - m_dcc_chats.insert( dcc ); - - LeaveCriticalSection(&m_dcc); -} - -void CIrcProto::AddDCCSession(DCCINFO*, CDccSession* dcc) -{ - EnterCriticalSection(&m_dcc); - - m_dcc_xfers.insert( dcc ); - - LeaveCriticalSection(&m_dcc); -} - -void CIrcProto::RemoveDCCSession(HANDLE hContact) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_chats.getCount(); i++ ) - if ( m_dcc_chats[i]->di->hContact == hContact ) { - m_dcc_chats.remove( i ); - break; - } - - LeaveCriticalSection(&m_dcc); -} - -void CIrcProto::RemoveDCCSession(DCCINFO* pdci) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) - if ( m_dcc_xfers[i]->di == pdci ) { - m_dcc_xfers.remove( i ); - break; - } - - LeaveCriticalSection(&m_dcc); -} - -CDccSession* CIrcProto::FindDCCSession(HANDLE hContact) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_chats.getCount(); i++ ) - if ( m_dcc_chats[i]->di->hContact == hContact ) { - LeaveCriticalSection(&m_dcc); - return m_dcc_chats[ i ]; - } - - LeaveCriticalSection(&m_dcc); - return 0; -} - -CDccSession* CIrcProto::FindDCCSession(DCCINFO* pdci) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) - if ( m_dcc_xfers[i]->di == pdci ) { - LeaveCriticalSection(&m_dcc); - return m_dcc_xfers[ i ]; - } - - LeaveCriticalSection(&m_dcc); - return 0; -} - -CDccSession* CIrcProto::FindDCCSendByPort(int iPort) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { - CDccSession* p = m_dcc_xfers[i]; - if ( p->di->iType == DCC_SEND && p->di->bSender && iPort == p->di->iPort ) { - LeaveCriticalSection(&m_dcc); - return p; - } - } - - LeaveCriticalSection(&m_dcc); - return 0; -} - -CDccSession* CIrcProto::FindDCCRecvByPortAndName(int iPort, const TCHAR* szName) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { - CDccSession* p = m_dcc_xfers[i]; - DBVARIANT dbv; - if ( !getTString(p->di->hContact, "Nick", &dbv)) { - if ( p->di->iType == DCC_SEND && !p->di->bSender && !lstrcmpi( szName, dbv.ptszVal) && iPort == p->di->iPort ) { - DBFreeVariant(&dbv); - LeaveCriticalSection(&m_dcc); - return p; - } - DBFreeVariant(&dbv); - } - } - - LeaveCriticalSection(&m_dcc); - return 0; -} - -CDccSession* CIrcProto::FindPassiveDCCSend(int iToken) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { - if ( m_dcc_xfers[ i ]->iToken == iToken ) { - LeaveCriticalSection(&m_dcc); - return m_dcc_xfers[ i ]; - } - } - - LeaveCriticalSection(&m_dcc); - return 0; -} - -CDccSession* CIrcProto::FindPassiveDCCRecv(CMString sName, CMString sToken) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { - CDccSession* p = m_dcc_xfers[i]; - if ( sToken == p->di->sToken && sName == p->di->sContactName ) { - LeaveCriticalSection(&m_dcc); - return p; - } - } - LeaveCriticalSection(&m_dcc); - return 0; -} - -void CIrcProto::DisconnectAllDCCSessions(bool Shutdown) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_chats.getCount(); i++ ) - if ( m_disconnectDCCChats || Shutdown ) - m_dcc_chats[i]->Disconnect(); - - LeaveCriticalSection(&m_dcc); -} - -void CIrcProto::CheckDCCTimeout(void) -{ - EnterCriticalSection(&m_dcc); - - for ( int i=0; i < m_dcc_chats.getCount(); i++ ) { - CDccSession* p = m_dcc_chats[i]; - if ( time(0) > p->tLastActivity + DCCCHATTIMEOUT ) - p->Disconnect(); - } - - for ( int j=0; j < m_dcc_xfers.getCount(); j++ ) { - CDccSession* p = m_dcc_xfers[j]; - if ( time(0) > p->tLastActivity + DCCSENDTIMEOUT ) - p->Disconnect(); - } - - LeaveCriticalSection(&m_dcc); -} - -//////////////////////////////////////////////////////////////////// - -CIrcIgnoreItem::CIrcIgnoreItem( const TCHAR* _mask, const TCHAR* _flags, const TCHAR* _network ) : - mask( _mask ), - flags( _flags ), - network( _network ) -{ -} - -CIrcIgnoreItem::CIrcIgnoreItem( int codepage, const char* _mask, const char* _flags, const char* _network ) : - mask( (TCHAR *)_A2T( _mask, codepage )), - flags( (TCHAR *)_A2T( _flags, codepage )), - network( (TCHAR *)_A2T( _network, codepage )) -{ -} - -CIrcIgnoreItem::~CIrcIgnoreItem() -{ -} - -//////////////////////////////////////////////////////////////////// - -CIrcSessionInfo::CIrcSessionInfo() : - iPort(0), - bIdentServer(false), - iIdentServerPort(0) -{ -} - -CIrcSessionInfo::CIrcSessionInfo(const CIrcSessionInfo& si) : - sServer(si.sServer), - sServerName(si.sServerName), - iPort(si.iPort), - sNick(si.sNick), - sUserID(si.sUserID), - sFullName(si.sFullName), - sPassword(si.sPassword), - bIdentServer(si.bIdentServer), - m_iSSL(si.m_iSSL), - sIdentServerType(si.sIdentServerType), - sNetwork(si.sNetwork), - iIdentServerPort(si.iIdentServerPort) -{ -} - -void CIrcSessionInfo::Reset() -{ - sServer = ""; - sServerName = _T(""); - iPort = 0; - sNick = _T(""); - sUserID = _T(""); - sFullName = _T(""); - sPassword = ""; - bIdentServer = false; - bNickFlag = false; - m_iSSL = 0; - sIdentServerType = _T(""); - iIdentServerPort = 0; - sNetwork = _T(""); -} - -//////////////////////////////////////////////////////////////////// - -void CIrcProto::OnIrcMessage(const CIrcMessage* pmsg) -{ - if ( pmsg != NULL ) { - PfnIrcMessageHandler pfn = FindMethod( pmsg->sCommand.c_str()); - if ( pfn ) { - // call member function. if it returns 'false', - // call the default handling - __try - { - if ( !(this->*pfn)( pmsg )) - OnIrcDefault( pmsg ); - } - __except( EXCEPTION_EXECUTE_HANDLER ) // dedicated to Sava :) - { - DoNetlibLog( "IRC handler feels sick: %S", pmsg->sCommand.c_str()); - } - } - else // handler not found. call default handler - OnIrcDefault( pmsg ); - } - else OnIrcDisconnected(); -} - -PfnIrcMessageHandler CIrcProto::FindMethod(const TCHAR* lpszName) -{ - CIrcHandler temp( lpszName, NULL ); - CIrcHandler* p = m_handlers.find( &temp ); - return ( p == NULL ) ? NULL : p->m_handler; -} - -//////////////////////////////////////////////////////////////////// - -#define IPC_ADDR_SIZE 4 /* Size of IP address, change for IPv6. */ - -char* ConvertIntegerToIP(unsigned long int_ip_addr) -{ - IN_ADDR intemp; - IN_ADDR in; - intemp.S_un.S_addr = int_ip_addr; - - in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; - in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; - in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; - in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; - - return inet_ntoa( in ); -} - -unsigned long ConvertIPToInteger( char* IP ) -{ - IN_ADDR in; - IN_ADDR intemp; - - if ( IP == 0 || lstrlenA(IP) == 0) - return 0; - - intemp.S_un.S_addr = inet_addr(IP); - - in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; - in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; - in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; - in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; - return in.S_un.S_addr; -} - -//////////////////////////////////////////////////////////////////// - -// initialize basic stuff needed for the dcc objects, also start a timer for checking the status of connections (timeouts) -CDccSession::CDccSession( CIrcProto* _pro, DCCINFO* pdci ) : - m_proto( _pro ), - NewFileName(0), - dwWhatNeedsDoing(0), - tLastPercentageUpdate(0), - dwTotal(0), - iGlobalToken(), - dwResumePos(0), - hEvent(0), - con(0), - hBindPort(0) -{ - tLastActivity = time(0); - - di = pdci; // Setup values passed to the constructor - - ZeroMemory(&pfts, sizeof(PROTOFILETRANSFERSTATUS)); - pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); - - if(di->iType == DCC_SEND && di->bSender == false) - hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - if(nDcc == 0) - m_proto->SetChatTimer(m_proto->DCCTimer, 20*1000, DCCTimerProc); - - nDcc++; // increase the count of existing objects - - iGlobalToken++; - if(iGlobalToken == 1000) - iGlobalToken = 1; - iToken = iGlobalToken; - - iPacketSize = m_proto->getWord( "PacketSize", 4096 ); - - if ( di->dwAdr ) - m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff -} - -CDccSession::~CDccSession() // destroy all that needs destroying -{ - if ( di->iType == DCC_SEND ) { - // ack SUCCESS or FAILURE - if (dwTotal == di->dwSize ) - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (void *)di, 0); - else - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); - } - - if ( di->iType == DCC_CHAT ) { - CDccSession* dcc = m_proto->FindDCCSession(di->hContact); - if ( dcc && this == dcc ) { - m_proto->RemoveDCCSession(di->hContact); // objects automatically remove themselves from the list of objects - m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); - } } - - if ( di->iType == DCC_SEND ) - m_proto->RemoveDCCSession( di ); - - if ( hEvent != NULL ) { - SetEvent( hEvent ); - CloseHandle( hEvent ); - hEvent = NULL; - } - - delete di; - nDcc--; - - if ( nDcc < 0 ) - nDcc = 0; - - if ( nDcc == 0 ) - m_proto->KillChatTimer( m_proto->DCCTimer ); // destroy the timer when no dcc objects remain -} - -int CDccSession::NLSend(const unsigned char* buf, int cbBuf) -{ - tLastActivity = time(0); - - if (con) - return Netlib_Send(con, (const char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); - - return 0; -} - -int CDccSession::NLReceive(const unsigned char* buf, int cbBuf) -{ - int n = 0; - - if(con) - n = Netlib_Recv(con, (char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); - - tLastActivity = time(0); - return n; -} - -int CDccSession::SendStuff(const TCHAR* fmt) -{ - String buf = _T2A( fmt, m_proto->getCodepage()); - return NLSend(( const unsigned char* )buf.c_str(), buf.GetLength()); -} - -// called when the user wants to connect/create a new connection given the parameters in the constructor. -int CDccSession::Connect() -{ - if ( !di->bSender || di->bReverse ) { - if ( !con ) - mir_forkthread( ConnectProc, this ); // spawn a new thread for time consuming activities, ie when connecting to a remote computer - return true; - } - - if ( !con ) - return SetupConnection(); // no need to spawn thread for setting up a listening port locally - - return false; -} - -void __cdecl CDccSession::ConnectProc( void *pparam ) -{ - CDccSession* pThis = (CDccSession*)pparam; - if ( !pThis->con ) - pThis->SetupConnection(); -} - -// small function to setup the address and port of the remote computer fror passive filetransfers -void CDccSession::SetupPassive(DWORD adress, DWORD port) -{ - di->dwAdr = adress; - di->iPort = (int)port; - - m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff -} - -int CDccSession::SetupConnection() -{ - // if it is a dcc chat connection make sure it is "offline" to begin with, since no connection exists still - if ( di->iType == DCC_CHAT ) - m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); - - // Set up stuff needed for the filetransfer dialog (if it is a filetransfer) - if ( di->iType == DCC_SEND ) { - file[0] = ( TCHAR* )di->sFileAndPath.c_str(); - file[1] = 0; - - pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); - pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); - pfts.hContact = di->hContact; - pfts.flags = PFTS_TCHAR + ((di->bSender) ? PFTS_SENDING : PFTS_RECEIVING); - pfts.totalFiles = 1; - pfts.currentFileNumber = 0; - pfts.totalBytes = di->dwSize; - pfts.currentFileSize = pfts.totalBytes; - pfts.ptszFiles = file; - pfts.totalProgress = 0; - pfts.currentFileProgress = 0; - pfts.currentFileTime = (unsigned long)time(0); - } - - // create a listening socket for outgoing chat/send requests. The remote computer connects to this computer. Used for both chat and filetransfer. - if ( di->bSender && !di->bReverse ) { - NETLIBBIND nb = {0}; - nb.cbSize = sizeof(NETLIBBIND); - nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() - nb.pExtra = (void *)this; - nb.wPort = 0; - hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); - - if ( hBindPort == NULL ) { - delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. - return 0; - } - - di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) - return nb.wPort; // return the created port so it can be sent to the remote computer in a ctcp/dcc command - } - - // If a remote computer initiates a chat session this is used to connect to the remote computer (user already accepted at this point). - // also used for connecting to a remote computer for remote file transfers - if ( di->iType == DCC_CHAT && !di->bSender || di->iType == DCC_SEND && di->bSender && di->bReverse ) { - NETLIBOPENCONNECTION ncon = { 0 }; - ncon.cbSize = sizeof(ncon); - ncon.szHost = ConvertIntegerToIP(di->dwAdr); - ncon.wPort = (WORD) di->iPort; - con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); - } - - - // If a remote computer initiates a filetransfer this is used to connect to that computer (the user has chosen to accept but it is possible the file exists/needs to be resumed etc still) - if ( di->iType == DCC_SEND && !di->bSender ) { - - // this following code is for miranda to be able to show the resume/overwrite etc dialog if the file that we are receiving already exists. - // It must be done before we create the connection or else the other party will begin sending packets while the user is still deciding if - // s/he wants to resume/cancel or whatever. Just the way dcc is... - - // if the file exists (dialog is shown) WaitForSingleObject() till the dialog is closed and PS_FILERESUME has been processed. - // dwWhatNeedsDoing will be set using InterlockedExchange() (from other parts of the code depending on action) before SetEvent() is called. - // If the user has chosen rename then InterlockedExchange() will be used for setting NewFileName to a string containing the new name. - // Furthermore dwResumePos will be set using InterlockedExchange() to indicate what the file position to start from is. - if ( ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (void *)di, (LPARAM)&pfts)) { - WaitForSingleObject( hEvent, INFINITE ); - switch( dwWhatNeedsDoing ) { - case FILERESUME_RENAME: - // If the user has chosen to rename the file we need to change variables accordingly. NewFileName has been set using - // InterlockedExchange() - if ( NewFileName) { // the user has chosen to rename the new incoming file. - di->sFileAndPath = NewFileName; - - int i = di->sFileAndPath.ReverseFind( '\\' ); - if ( i != -1 ) { - di->sPath = di->sFileAndPath.Mid(0, i+1); - di->sFile = di->sFileAndPath.Mid(i+1, di->sFileAndPath.GetLength()); - } - - pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); - pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); - pfts.totalBytes = di->dwSize; - pfts.currentFileSize = pfts.totalBytes; - - delete[] NewFileName; - NewFileName = NULL; - } - break; - - case FILERESUME_OVERWRITE: - case FILERESUME_RESUME : - // no action needed at this point, just break out of the switch statement - break; - - case FILERESUME_CANCEL : - return FALSE; - - case FILERESUME_SKIP : - default: - delete this; // per usual dcc objects destroy themselves when they fail or when connection is closed - return FALSE; - } } - - // hack for passive filetransfers - if ( di->iType == DCC_SEND && !di->bSender && di->bReverse ) { - NETLIBBIND nb = {0}; - nb.cbSize = sizeof(NETLIBBIND); - nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() - nb.pExtra = (void *)this; - nb.wPort = 0; - hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); - - if ( hBindPort == NULL ) { - m_proto->DoEvent(GC_EVENT_INFORMATION, 0, m_proto->m_info.sNick.c_str(), LPGENT("DCC ERROR: Unable to bind local port for passive filetransfer"), NULL, NULL, NULL, true, false); - delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. - return 0; - } - - di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) - - CMString sFileWithQuotes = di->sFile; - - // if spaces in the filename surround with quotes - if ( sFileWithQuotes.Find( ' ', 0 ) != -1 ) { - sFileWithQuotes.Insert( 0, _T("\"")); - sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); - } - - // send out DCC RECV command for passive filetransfers - unsigned long ulAdr = 0; - if ( m_proto->m_manualHost ) - ulAdr = ConvertIPToInteger( m_proto->m_mySpecifiedHostIP ); - else - ulAdr = m_proto->m_IPFromServer ? ConvertIPToInteger( m_proto->m_myHost ) : nb.dwExternalIP; - - if ( di->iPort && ulAdr ) - m_proto->PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u %s"), di->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, di->iPort, di->dwSize, di->sToken.c_str()); - - return TRUE; - } - - // connect to the remote computer from which you are receiving the file (now all actions to take (resume/overwrite etc) have been decided - NETLIBOPENCONNECTION ncon = { 0 }; - ncon.cbSize = sizeof(ncon); - ncon.szHost = ConvertIntegerToIP(di->dwAdr); - ncon.wPort = (WORD) di->iPort; - - con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); - } - - // if for some reason the plugin has failed to connect to the remote computer the object is destroyed. - if ( con == NULL ) { - delete this; - return FALSE; // failed to connect - } - - // if it is a chat connection set the user to online now since we now know there is a connection - if ( di->iType == DCC_CHAT ) - m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); - - // spawn a new thread to handle receiving/sending of data for the new chat/filetransfer connection to the remote computer - mir_forkthread( ThreadProc, this ); - - return con != NULL; -} - -// called by netlib for incoming connections on a listening socket (chat/filetransfer) -int CDccSession::IncomingConnection(HANDLE hConnection, DWORD dwIP) -{ - con = hConnection; - if ( con == NULL ) { - delete this; - return false; // failed to connect - } - - m_proto->setDword(di->hContact, "IP", dwIP); // mToolTip stuff - - if ( di->iType == DCC_CHAT ) - m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); // set chat to online - - // same as above, spawn a new thread to handle receiving/sending of data for the new incoming chat/filetransfer connection - mir_forkthread(ThreadProc, this ); - return true; -} - -// here we decide which function to use for communicating with the remote computer, depending on connection type -void __cdecl CDccSession::ThreadProc(void *pparam) -{ - CDccSession* pThis = (CDccSession*)pparam; - - // if it is an incoming connection on a listening port, then we should close the listenting port so only one can connect (the one you offered - // the connection to) can connect and not evil IRCopers with haxxored IRCDs - if ( pThis->hBindPort ) { - Netlib_CloseHandle(pThis->hBindPort); - pThis->hBindPort = NULL; - } - - if ( pThis->di->iType == DCC_CHAT ) - pThis->DoChatReceive(); // dcc chat - - else if ( !pThis->di->bSender ) - pThis->DoReceiveFile(); // receive a file - - else if ( pThis->di->bSender ) - pThis->DoSendFile(); // send a file -} - -// this is done when the user is initiating a filetransfer to a remote computer -void CDccSession::DoSendFile() -{ - // initialize the filetransfer dialog - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); - - WORD wPacketSize = m_proto->getWord( "DCCPacketSize", 1024*4); - - if ( wPacketSize < 256 ) - wPacketSize = 256; - - if ( wPacketSize > 32 * 1024 ) - wPacketSize = 32 * 1024; - - BYTE* chBuf = new BYTE[wPacketSize+1]; - - // is there a connection? - if ( con ) { - // open the file for reading - int hFile = _topen( di->sFileAndPath.c_str(), _O_RDONLY | _O_BINARY, _S_IREAD); - if (hFile >= 0) { - unsigned __int64 dwLastAck = 0; - - // if the user has chosen to resume a file, dwResumePos will contain a value (set using InterlockedExchange()) - // and then the variables and the file pointer are changed accordingly. - if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { - _lseeki64(hFile, dwResumePos, SEEK_SET); - dwTotal = dwResumePos; - dwLastAck = dwResumePos; - pfts.totalProgress = dwResumePos; - pfts.currentFileProgress = dwResumePos; - } - - // initial ack to set the 'percentage-ready meter' to the correct value - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - - tLastActivity = time(0); - - // create a packet receiver to handle receiving ack's from the remote computer. - HANDLE hPackrcver = (HANDLE)CallService( MS_NETLIB_CREATEPACKETRECVER, (WPARAM)con, (LPARAM)sizeof(DWORD)); - NETLIBPACKETRECVER npr; - npr.cbSize = sizeof(NETLIBPACKETRECVER); - npr.dwTimeout = 60*1000; - npr.bufferSize = sizeof(DWORD); - npr.bytesUsed = 0; - - // until the connection is dropped it will spin around in this while() loop - while ( con ) { - // read a packet - int iRead = _read(hFile, chBuf, wPacketSize); - if ( iRead <= 0 ) - break; // break out if everything has already been read - - // send the package - int cbSent = NLSend((unsigned char*)chBuf, iRead); - if ( cbSent <= 0 ) - break; // break out if connection is lost or a transmission error has occured - - if ( !con ) - break; - - dwTotal += cbSent; - - // block connection and receive ack's from remote computer (if applicable) - if ( m_proto->m_DCCMode == 0 ) { - DWORD dwRead = 0; - DWORD dwPacket = NULL; - - do { - dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); - npr.bytesUsed = sizeof(DWORD); - - if ( dwRead <= 0) - break; // connection closed, or a timeout occurred. - - dwPacket = *(DWORD*)npr.buffer; - dwLastAck = ntohl(dwPacket); - - } - while(con && dwTotal != dwLastAck); - - if ( !con || dwRead <= 0 ) - goto DCC_STOP; - } - - if ( m_proto->m_DCCMode == 1 ) { - DWORD dwRead = 0; - DWORD dwPacket = 0; - - do { - dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); - npr.bytesUsed = sizeof(DWORD); - if ( dwRead <= 0) - break; // connection closed, or a timeout occurred. - - dwPacket = *(DWORD*)npr.buffer; - dwLastAck = ntohl(dwPacket); - } - while(con && (di->dwSize != dwTotal - && dwTotal - dwLastAck >= 100*1024 - || di->dwSize == dwTotal // get the last packets when the whole file has been sent - && dwTotal != dwLastAck)); - - if ( !con || dwRead <= 0 ) - goto DCC_STOP; - } - - // update the filetransfer dialog's 'percentage-ready meter' once per second only to save cpu - if ( tLastPercentageUpdate < time(0)) { - tLastPercentageUpdate = time(0); - pfts.totalProgress = dwTotal; - pfts.currentFileProgress = dwTotal; - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - } - - // close the connection once the whole file has been sent an completely ack'ed - if ( dwLastAck >= di->dwSize ) { - Netlib_CloseHandle(con); - con = NULL; - } } - -DCC_STOP: - // need to close the connection if it isn't allready - if ( con ) { - Netlib_CloseHandle(con); - con = NULL; - } - - // ack the progress one final time - tLastActivity = time(0); - pfts.totalProgress = dwTotal; - pfts.currentFileProgress = dwTotal; - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - - _close(hFile); - } - else // file was not possible to open for reading - { - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); - if ( con ) { - Netlib_CloseHandle(con); - con = NULL; - } } } - - delete []chBuf; - delete this; // ... and hopefully all went right, cuz here the object is deleted in any case -} - -// This is called when receiving a file from a remote computer. -void CDccSession::DoReceiveFile() -{ - // initialize the filetransfer dialog - ProtoBroadcastAck( m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); - - BYTE chBuf[1024*32+1]; - - // do some stupid thing so the filetransfer dialog shows the right thing - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); - - // open the file for writing (and reading in case it is a resume) - int hFile = _topen( di->sFileAndPath.c_str(), - (dwWhatNeedsDoing == FILERESUME_RESUME ? _O_APPEND : _O_TRUNC | _O_CREAT) | _O_RDWR | _O_BINARY, - _S_IREAD | _S_IWRITE); - if ( hFile >= 0 ) { - unsigned __int64 dwLastAck = 0; - - // dwResumePos and dwWhatNeedsDoing has possibly been set using InterlockedExchange() - // if set it is a resume and we adjust variables and the file pointer accordingly. - if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { - _lseeki64(hFile, dwResumePos, SEEK_SET); - dwTotal = dwResumePos; - dwLastAck = dwResumePos; - pfts.totalProgress = dwResumePos; - pfts.currentFileProgress = dwResumePos; - } - - // send an initial ack for the percentage-ready meter - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - - // the while loop will spin around till the connection is dropped, locally or by the remote computer. - while ( con ) { - // read - int cbRead = NLReceive((unsigned char*)chBuf, sizeof(chBuf)); - if ( cbRead <= 0 ) - break; - - // write it to the file - _write(hFile, chBuf, cbRead); - - dwTotal += cbRead; - - // this snippet sends out an ack for every 4 kb received in send ahead - // or every packet for normal mode - if ( !di->bTurbo ) { - DWORD no = dwTotal; - no = htonl(no); - NLSend((unsigned char *)&no, sizeof(DWORD)); - dwLastAck = dwTotal; - } - else dwLastAck = dwTotal; - - // sets the 'last update time' to check for timed out connections, and also make sure we only - // ack the 'percentage-ready meter' only once a second to save CPU. - if ( tLastPercentageUpdate < time( 0 )) { - tLastPercentageUpdate = time (0); - pfts.totalProgress = dwTotal; - pfts.currentFileProgress = dwTotal; - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - } - - // if file size is known and everything is received then disconnect - if ( di->dwSize && di->dwSize == dwTotal ) { - Netlib_CloseHandle(con); - con = NULL; - } } - // receiving loop broken locally or by remote computer, just some cleaning up left.... - - pfts.totalProgress = dwTotal; - pfts.currentFileProgress = dwTotal; - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); - _close(hFile); - } - else { - ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); - if ( con ) { // file not possible to open for writing so we ack FAILURE and close the handle - Netlib_CloseHandle(con); - con = NULL; - } } - - delete this; // and finally the object is deleted -} - -// this function handles receiving text in dcc chats and then send it in the protochain. very uncomplicated... -// For sending text the SendStuff() function is called (with the help of some function in CIrcProto to find the right -// Dcc object). See CIrcProto for info on how the dcc objects are stored, retreived and deleted. - -void CDccSession::DoChatReceive() -{ - char chBuf[1024*4+1]; - int cbInBuf = 0; - - // loop to spin around while there is a connection - while( con ) { - int cbRead; - int nLinesProcessed = 0; - - cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); - if ( cbRead <= 0 ) - break; - - cbInBuf += cbRead; - chBuf[cbInBuf] = '\0'; - - char* pStart = chBuf; - while( *pStart ) { - char* pEnd; - - // seek end-of-line - for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) - ; - if ( *pEnd == '\0' ) - break; // uncomplete message. stop parsing. - - ++nLinesProcessed; - - // replace end-of-line with NULLs and skip - while( *pEnd == '\r' || *pEnd == '\n' ) - *pEnd++ = '\0'; - - if ( *pStart ) { - // send it off to some messaging module - - PROTORECVEVENT pre = {0}; - pre.timestamp = (DWORD)time(NULL); -// pre.szMessage = (char*)DoColorCodes((TCHAR*)pStart, true, false); //!!!! // remove color codes - pre.szMessage = pStart; - - CCSDATA ccs = {0}; - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = di->hContact; - ccs.lParam = (LPARAM) ⪯ - - CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); - } - - cbInBuf -= pEnd - pStart; - pStart = pEnd; - } - - // discard processed messages - if ( nLinesProcessed != 0 ) - memmove(chBuf, pStart, cbInBuf+1); - } - - delete this; // delete the object when the connection is dropped -} - -// disconnect the stuff -int CDccSession::Disconnect() -{ - if ( hBindPort ) { - Netlib_CloseHandle(hBindPort); - hBindPort = NULL; - } - - // if 'con' exists it is cuz a connection exists. - // Terminating 'con' will cause any spawned threads to die and then the object will destroy itself. - if ( con ) { - Netlib_CloseHandle(con); - con = NULL; - } - else delete this; // if 'con' do not exist (no connection made so far from the object) the object is destroyed - - return TRUE; -} - -//////////////////////////////////////////////////////////////////// -// check if the dcc chats should disconnect ( default 5 minute timeout ) - -VOID CALLBACK DCCTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( ppro ) - ppro->CheckDCCTimeout(); -} - -// helper function for incoming dcc connections. -void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void * p1) -{ - CDccSession* dcc = (CDccSession*)p1; - dcc->IncomingConnection(hConnection, dwRemoteIP); -} - -// ident server - -void strdel( char* parBuffer, int len ) -{ - char* p; - for ( p = parBuffer+len; *p != 0; p++ ) - p[ -len ] = *p; - - p[ -len ] = '\0'; -} - -void DoIdent(HANDLE hConnection, DWORD, void* extra ) -{ - CIrcProto* ppro = ( CIrcProto* )extra; - - char szBuf[1024]; - int cbTotal = 0; - - for (;;) { - int cbRead = Netlib_Recv(hConnection, szBuf+cbTotal, sizeof(szBuf)-1-cbTotal, 0); - if ( cbRead == SOCKET_ERROR || cbRead == 0) - break; - - cbTotal += cbRead; - szBuf[cbTotal] = '\0'; - -LBL_Parse: - char* EOLPos = strstr(szBuf, "\r\n"); - if (EOLPos == NULL) - continue; - - EOLPos[0] = EOLPos[1] = '\0'; - rtrim( szBuf ); - ppro->DoNetlibLog("Got Ident request: %s", szBuf); - - unsigned int PeerPortNrRcvd = 0, LocalPortNrRcvd = 0; - int iParamCnt = sscanf( szBuf, "%d , %d", &LocalPortNrRcvd, &PeerPortNrRcvd ); - - int cbLen = 0; - char buf[1024*4]; - - if (iParamCnt != 2) - cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : UNKNOWN-ERROR\r\n", szBuf); - else - { - for (int i = 0; i < g_Instances.getCount(); i++) - { - if (PeerPortNrRcvd == g_Instances[i]->m_info.iPort && LocalPortNrRcvd == g_Instances[i]->m_myLocalPort) - { - cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : USERID : " TCHAR_STR_PARAM " : " TCHAR_STR_PARAM "\r\n", - szBuf, g_Instances[i]->m_info.sIdentServerType.c_str() , g_Instances[i]->m_info.sUserID.c_str()); - break; - } - } - - if (cbLen == 0) - cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : INVALID-PORT\r\n", szBuf); - } - - if ( Netlib_Send(hConnection, (const char*)buf, cbLen, 0) > 0) - ppro->DoNetlibLog("Sent Ident answer: %s", buf); - else - ppro->DoNetlibLog("Sending Ident answer failed."); - - if ( ppro->m_identTimer ) - break; - - cbTotal -= EOLPos + 2 - szBuf; - strdel(szBuf, int(EOLPos + 2 - szBuf)); - goto LBL_Parse; - } - Netlib_CloseHandle(hConnection); -} diff --git a/protocols/IRCG/irclib.h b/protocols/IRCG/irclib.h deleted file mode 100644 index 7dcb5a4c01..0000000000 --- a/protocols/IRCG/irclib.h +++ /dev/null @@ -1,175 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef _IRC_H_ -#define _IRC_H_ - -#pragma warning (disable: 4786) - -void DoIdent(HANDLE hConnection, DWORD dwRemoteIP, void* extra); -void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void* extra); -unsigned long ConvertIPToInteger(char * IP); -char* ConvertIntegerToIP(unsigned long int_ip_addr); - -//////////////////////////////////////////////////////////////////// -namespace irc { -//////////////////////////////////////////////////////////////////// - -struct DCCINFO : public MZeroedObject -{ - DWORD dwAdr; - unsigned __int64 dwSize; - DWORD iType; - CMString sToken; - int iPort; - BOOL bTurbo; - BOOL bSSL; - BOOL bSender; - BOOL bReverse; - CMString sPath; - CMString sFile; - CMString sFileAndPath; - CMString sHostmask; - HANDLE hContact; - CMString sContactName; -}; - -class CIrcMessage -{ -public : - struct Prefix - { - CMString sNick, sUser, sHost; - } - prefix; - - CIrcProto* m_proto; - CMString sCommand; - OBJLIST parameters; - bool m_bIncoming; - bool m_bNotify; - int m_codePage; - - //CIrcMessage( CIrcProto* ); // default constructor - CIrcMessage( CIrcProto*, const TCHAR* lpszCmdLine, int codepage, bool bIncoming=false, bool bNotify = true); // parser constructor - CIrcMessage( const CIrcMessage& m ); // copy constructor - ~CIrcMessage(); - - void Reset(); - - CIrcMessage& operator = (const CIrcMessage& m); - CIrcMessage& operator = (const TCHAR* lpszCmdLine); - -private : - void ParseIrcCommand(const TCHAR* lpszCmdLine); -}; - -//////////////////////////////////////////////////////////////////// - -struct CIrcSessionInfo -{ - String sServer; - CMString sServerName; - CMString sNick; - CMString sUserID; - CMString sFullName; - String sPassword; - CMString sIdentServerType; - CMString sNetwork; - bool bIdentServer; - bool bNickFlag; - int m_iSSL; - unsigned int iIdentServerPort; - unsigned int iPort; - - CIrcSessionInfo(); - CIrcSessionInfo(const CIrcSessionInfo& si); - - void Reset(); -}; - -//////////////////////////////////////////////////////////////////// - -struct CIrcIgnoreItem -{ - CIrcIgnoreItem( const TCHAR*, const TCHAR*, const TCHAR* ); - CIrcIgnoreItem( int codepage, const char*, const char*, const char* ); - ~CIrcIgnoreItem(); - - CMString mask, flags, network; -}; - -//////////////////////////////////////////////////////////////////// - -class CDccSession -{ -protected: - CIrcProto* m_proto; - HANDLE con; // connection handle - HANDLE hBindPort; // handle for listening port - static int nDcc; // number of dcc objects - unsigned __int64 dwTotal; // total bytes sent/received - - int iPacketSize; // size of outgoing packets - int iGlobalToken; - - PROTOFILETRANSFERSTATUS pfts; // structure used to setup and update the filetransfer dialogs of miranda - TCHAR* file[2]; - - int SetupConnection(); - void DoSendFile(); - void DoReceiveFile(); - void DoChatReceive(); - int NLSend( const unsigned char* buf, int cbBuf); - int NLReceive(const unsigned char* buf, int cbBuf); - static void __cdecl ThreadProc(void *pparam); - static void __cdecl ConnectProc(void *pparam); - -public: - - CDccSession(CIrcProto*, DCCINFO* pdci); // constructor - ~CDccSession(); // destructor, ÷òî õàðàêòåðíî - - time_t tLastPercentageUpdate; // time of last update of the filetransfer dialog - time_t tLastActivity; // time of last in/out activity of the object - time_t tLastAck; // last acked filesize - - HANDLE hEvent; // Manual object - long dwWhatNeedsDoing; // Set to indicate what FILERESUME_ action is chosen by the user - TCHAR* NewFileName; // contains new file name if FILERESUME_RENAME chosen - unsigned __int64 dwResumePos; // position to resume from if FILERESUME_RESUME - - int iToken; // used to identify (find) objects in reverse dcc filetransfers - - DCCINFO* di; // details regarding the filetrasnfer - - int Connect(); - void SetupPassive( DWORD adr, DWORD port ); - int SendStuff(const TCHAR* fmt); - int IncomingConnection(HANDLE hConnection, DWORD dwIP); - int Disconnect(); -}; - -//////////////////////////////////////////////////////////////////// -}; // end of namespace irc -//////////////////////////////////////////////////////////////////// - -#endif // _IRC_H_ diff --git a/protocols/IRCG/ircproto.cpp b/protocols/IRCG/ircproto.cpp deleted file mode 100644 index 9ff2a1c851..0000000000 --- a/protocols/IRCG/ircproto.cpp +++ /dev/null @@ -1,1076 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" -#include "version.h" - -#include - -static int CompareSessions( const CDccSession* p1, const CDccSession* p2 ) -{ - return INT_PTR( p1->di->hContact ) - INT_PTR( p2->di->hContact ); -} - -CIrcProto::CIrcProto( const char* szModuleName, const TCHAR* tszUserName ) : - m_dcc_chats( 10, CompareSessions ), - m_dcc_xfers( 10, CompareSessions ), - m_ignoreItems( 10 ), - vUserhostReasons( 10 ), - vWhoInProgress( 10 ) -{ - m_iVersion = 2; - m_tszUserName = mir_tstrdup( tszUserName ); - m_szModuleName = mir_strdup( szModuleName ); - - InitializeCriticalSection(&cs); - InitializeCriticalSection(&m_gchook); - m_evWndCreate = ::CreateEvent( NULL, FALSE, FALSE, NULL ); - - CreateProtoService( PS_GETMYAWAYMSG, &CIrcProto::GetMyAwayMsg ); - - CreateProtoService( PS_CREATEACCMGRUI, &CIrcProto::SvcCreateAccMgrUI ); - CreateProtoService( PS_JOINCHAT, &CIrcProto::OnJoinChat ); - CreateProtoService( PS_LEAVECHAT, &CIrcProto::OnLeaveChat ); - - CreateProtoService( IRC_JOINCHANNEL, &CIrcProto::OnJoinMenuCommand ); - CreateProtoService( IRC_QUICKCONNECT, &CIrcProto::OnQuickConnectMenuCommand); - CreateProtoService( IRC_CHANGENICK, &CIrcProto::OnChangeNickMenuCommand ); - CreateProtoService( IRC_SHOWLIST, &CIrcProto::OnShowListMenuCommand ); - CreateProtoService( IRC_SHOWSERVER, &CIrcProto::OnShowServerMenuCommand ); - CreateProtoService( IRC_UM_CHANSETTINGS, &CIrcProto::OnMenuChanSettings ); - CreateProtoService( IRC_UM_WHOIS, &CIrcProto::OnMenuWhois ); - CreateProtoService( IRC_UM_DISCONNECT, &CIrcProto::OnMenuDisconnect ); - CreateProtoService( IRC_UM_IGNORE, &CIrcProto::OnMenuIgnore ); - - CreateProtoService( "/DblClickEvent", &CIrcProto::OnDoubleclicked ); - CreateProtoService( "/InsertRawIn", &CIrcProto::Scripting_InsertRawIn ); - CreateProtoService( "/InsertRawOut", &CIrcProto::Scripting_InsertRawOut ); - CreateProtoService( "/InsertGuiIn", &CIrcProto::Scripting_InsertGuiIn ); - CreateProtoService( "/InsertGuiOut", &CIrcProto::Scripting_InsertGuiOut); - CreateProtoService( "/GetIrcData", &CIrcProto::Scripting_GetIrcData); - - codepage = CP_ACP; - InitializeCriticalSection(&m_resolve); - InitializeCriticalSection(&m_dcc); - - InitPrefs(); - - char text[ MAX_PATH ]; - mir_snprintf( text, sizeof( text ), "%s/Status", m_szProtoName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - - CList_SetAllOffline(true); - AddIcons(); - - IRC_MAP_ENTRY("PING", PING) - IRC_MAP_ENTRY("JOIN", JOIN) - IRC_MAP_ENTRY("QUIT", QUIT) - IRC_MAP_ENTRY("KICK", KICK) - IRC_MAP_ENTRY("MODE", MODE) - IRC_MAP_ENTRY("NICK", NICK) - IRC_MAP_ENTRY("PART", PART) - IRC_MAP_ENTRY("PRIVMSG", PRIVMSG) - IRC_MAP_ENTRY("TOPIC", TOPIC) - IRC_MAP_ENTRY("NOTICE", NOTICE) - IRC_MAP_ENTRY("PING", PINGPONG) - IRC_MAP_ENTRY("PONG", PINGPONG) - IRC_MAP_ENTRY("INVITE", INVITE) - IRC_MAP_ENTRY("ERROR", ERROR) - IRC_MAP_ENTRY("001", WELCOME) - IRC_MAP_ENTRY("002", YOURHOST) - IRC_MAP_ENTRY("005", SUPPORT) - IRC_MAP_ENTRY("223", WHOIS_OTHER) //CodePage info - IRC_MAP_ENTRY("254", NOOFCHANNELS) - IRC_MAP_ENTRY("263", TRYAGAIN) - IRC_MAP_ENTRY("264", WHOIS_OTHER) //Encryption info (SSL connect) - IRC_MAP_ENTRY("301", WHOIS_AWAY) - IRC_MAP_ENTRY("302", USERHOST_REPLY) - IRC_MAP_ENTRY("305", BACKFROMAWAY) - IRC_MAP_ENTRY("306", SETAWAY) - IRC_MAP_ENTRY("307", WHOIS_AUTH) - IRC_MAP_ENTRY("310", WHOIS_OTHER) - IRC_MAP_ENTRY("311", WHOIS_NAME) - IRC_MAP_ENTRY("312", WHOIS_SERVER) - IRC_MAP_ENTRY("313", WHOIS_OTHER) - IRC_MAP_ENTRY("315", WHO_END) - IRC_MAP_ENTRY("317", WHOIS_IDLE) - IRC_MAP_ENTRY("318", WHOIS_END) - IRC_MAP_ENTRY("319", WHOIS_CHANNELS) - IRC_MAP_ENTRY("320", WHOIS_AUTH) - IRC_MAP_ENTRY("321", LISTSTART) - IRC_MAP_ENTRY("322", LIST) - IRC_MAP_ENTRY("323", LISTEND) - IRC_MAP_ENTRY("324", MODEQUERY) - IRC_MAP_ENTRY("330", WHOIS_AUTH) - IRC_MAP_ENTRY("332", INITIALTOPIC) - IRC_MAP_ENTRY("333", INITIALTOPICNAME) - IRC_MAP_ENTRY("352", WHO_REPLY) - IRC_MAP_ENTRY("353", NAMES) - IRC_MAP_ENTRY("366", ENDNAMES) - IRC_MAP_ENTRY("367", BANLIST) - IRC_MAP_ENTRY("368", BANLISTEND) - IRC_MAP_ENTRY("346", BANLIST) - IRC_MAP_ENTRY("347", BANLISTEND) - IRC_MAP_ENTRY("348", BANLIST) - IRC_MAP_ENTRY("349", BANLISTEND) - IRC_MAP_ENTRY("371", WHOIS_OTHER) - IRC_MAP_ENTRY("376", ENDMOTD) - IRC_MAP_ENTRY("401", WHOIS_NO_USER) - IRC_MAP_ENTRY("403", JOINERROR) - IRC_MAP_ENTRY("416", WHOTOOLONG) - IRC_MAP_ENTRY("421", UNKNOWN) - IRC_MAP_ENTRY("422", ENDMOTD) - IRC_MAP_ENTRY("433", NICK_ERR) - IRC_MAP_ENTRY("471", JOINERROR) - IRC_MAP_ENTRY("473", JOINERROR) - IRC_MAP_ENTRY("474", JOINERROR) - IRC_MAP_ENTRY("475", JOINERROR) - IRC_MAP_ENTRY("671", WHOIS_OTHER) //Encryption info (SSL connect) -} - -CIrcProto::~CIrcProto() -{ - if ( con ) { - Netlib_CloseHandle( con ); - con = NULL; - } - - Netlib_CloseHandle(hNetlib); hNetlib = NULL; - Netlib_CloseHandle(hNetlibDCC); hNetlibDCC = NULL; - - m_dcc_chats.destroy(); - m_dcc_xfers.destroy(); - - DeleteCriticalSection( &cs ); - DeleteCriticalSection( &m_gchook ); - - if (hMenuRoot) - CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); - - mir_free( m_alias ); - mir_free( m_szModuleName ); - mir_free( m_tszUserName ); - - CloseHandle( m_evWndCreate ); - DeleteCriticalSection(&m_resolve); - DeleteCriticalSection(&m_dcc); - KillChatTimer(OnlineNotifTimer); - KillChatTimer(OnlineNotifTimer3); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// OnModulesLoaded - performs hook registration - -static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - -static int sttCheckPerform( const char *szSetting, LPARAM lParam ) -{ - if ( !_strnicmp( szSetting, "PERFORM:", 8 )) { - String s = szSetting; - s.MakeUpper(); - if ( s != szSetting ) { - OBJLIST* p = ( OBJLIST* )lParam; - p->insert( new String( szSetting )); - } } - return 0; -} - -int CIrcProto::OnModulesLoaded( WPARAM, LPARAM ) -{ - char szTemp3[256]; - NETLIBUSER nlu = {0}; - TCHAR name[128]; - - DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); - - nlu.cbSize = sizeof(nlu); - nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; - nlu.szSettingsModule = m_szModuleName; - mir_sntprintf( name, SIZEOF(name), TranslateT("%s server connection"), m_tszUserName); - nlu.ptszDescriptiveName = name; - hNetlib=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; - char szTemp2[256]; - mir_snprintf(szTemp2, sizeof(szTemp2), "%s DCC", m_szModuleName); - nlu.szSettingsModule = szTemp2; - mir_sntprintf( name, SIZEOF(name), TranslateT("%s client-to-client connections"), m_tszUserName); - nlu.ptszDescriptiveName = name; - hNetlibDCC=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - //add as a known module in DB Editor ++ - CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)m_szModuleName,0); - mir_snprintf(szTemp3, sizeof(szTemp3), "%s DCC", m_szModuleName); - CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)szTemp3,0); - - if ( ServiceExists("MBot/GetFcnTable")) { - CallService( MS_MBOT_REGISTERIRC, 0, (LPARAM)m_szModuleName); - m_bMbotInstalled = TRUE; - } - - if ( ServiceExists( MS_GC_REGISTER )) { - GCREGISTER gcr = {0}; - gcr.cbSize = sizeof(GCREGISTER); - gcr.dwFlags = GC_CHANMGR | GC_BOLD | GC_ITALICS | GC_UNDERLINE | GC_COLOR | GC_BKGCOLOR | GC_TCHAR; - gcr.iMaxText = 0; - gcr.nColors = 16; - gcr.pColors = colors; - gcr.ptszModuleDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - CallServiceSync( MS_GC_REGISTER, NULL, (LPARAM)&gcr ); - IrcHookEvent( ME_GC_EVENT, &CIrcProto::GCEventHook ); - IrcHookEvent( ME_GC_BUILDMENU, &CIrcProto::GCMenuHook ); - - GCSESSION gcw = {0}; - GCDEST gcd = {0}; - GCEVENT gce = {0}; - - gcw.cbSize = sizeof(GCSESSION); - gcw.dwFlags = GC_TCHAR; - gcw.iType = GCW_SERVER; - gcw.ptszID = SERVERWINDOW; - gcw.pszModule = m_szModuleName; - gcw.ptszName = NEWTSTR_ALLOCA(( TCHAR* )_A2T( m_network )); - CallServiceSync( MS_GC_NEWSESSION, 0, (LPARAM)&gcw ); - - gce.cbSize = sizeof(GCEVENT); - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - gcd.ptszID = SERVERWINDOW; - gcd.pszModule = m_szModuleName; - gcd.iType = GC_EVENT_CONTROL; - - gce.pDest = &gcd; - if ( m_useServer && !m_hideServerWindow ) - CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); - else - CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); - bChatInstalled = TRUE; - } - else { - if ( IDYES == MessageBox(0,TranslateT("The IRC protocol depends on another plugin called \'Chat\'\n\nDo you want to download it from the Miranda NG web site now?"),TranslateT("Information"),MB_YESNO|MB_ICONINFORMATION )) - CallService( MS_UTILS_OPENURL, 1, (LPARAM) "http://miranda-ng.org/"); - } - - TCHAR szTemp[MAX_PATH]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_perform.ini"), m_szModuleName); - TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); - char* pszPerformData = IrcLoadFile( szLoadFileName ); - if ( pszPerformData != NULL ) { - char *p1 = pszPerformData, *p2 = pszPerformData; - while (( p1 = strstr( p2, "NETWORK: " )) != NULL ) { - p1 += 9; - p2 = strchr(p1, '\n'); - String sNetwork( p1, int( p2-p1-1 )); - sNetwork.MakeUpper(); - p1 = p2; - p2 = strstr( ++p1, "\nNETWORK: " ); - if ( !p2 ) - p2 = p1 + lstrlenA( p1 )-1; - if ( p1 == p2 ) - break; - - *p2++ = 0; - setString(("PERFORM:" + sNetwork).c_str(), rtrim( p1 )); - } - delete[] pszPerformData; - ::_tremove( szLoadFileName ); - } - mir_free( szLoadFileName ); - - if ( !getByte( "PerformConversionDone", 0 )) { - OBJLIST performToConvert( 10 ); - DBCONTACTENUMSETTINGS dbces; - dbces.pfnEnumProc = sttCheckPerform; - dbces.lParam = ( LPARAM )&performToConvert; - dbces.szModule = m_szModuleName; - CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); - - for ( int i = 0; i < performToConvert.getCount(); i++ ) { - String s = performToConvert[i]; - DBVARIANT dbv; - if ( !getTString( s, &dbv )) { - DBDeleteContactSetting( NULL, m_szModuleName, s ); - s.MakeUpper(); - setTString( s, dbv.ptszVal ); - DBFreeVariant( &dbv ); - } } - - setByte( "PerformConversionDone", 1 ); - } - - InitIgnore(); - - IrcHookEvent( ME_USERINFO_INITIALISE, &CIrcProto::OnInitUserInfo ); - IrcHookEvent( ME_OPT_INITIALISE, &CIrcProto::OnInitOptionsPages ); - - if ( m_nick[0] ) { - TCHAR szBuf[ 40 ]; - if ( lstrlen( m_alternativeNick ) == 0 ) { - mir_sntprintf( szBuf, SIZEOF(szBuf), _T("%s%u"), m_nick, rand()%9999); - setTString("AlernativeNick", szBuf); - lstrcpyn(m_alternativeNick, szBuf, 30); - } - - if ( lstrlen( m_name ) == 0 ) { - mir_sntprintf( szBuf, SIZEOF(szBuf), _T("Miranda%u"), rand()%9999); - setTString("Name", szBuf); - lstrcpyn( m_name, szBuf, 200 ); - } } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// AddToList - adds a contact to the contact list - -HANDLE __cdecl CIrcProto::AddToList( int, PROTOSEARCHRESULT* psr ) -{ - if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) - return 0; - - TCHAR *id = psr->id ? psr->id : psr->nick; - id = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)id) : mir_a2t((char*)id); - - CONTACT user = { id, NULL, NULL, true, false, false }; - HANDLE hContact = CList_AddContact( &user, true, false ); - - if ( hContact ) { - DBVARIANT dbv1; - CMString S = _T("S"); - - if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) { - S += user.name; - DoUserhostWithReason( 1, S, true, user.name ); - } - else { - if ( !getTString(hContact, "UWildcard", &dbv1 )) { - S += dbv1.ptszVal; - DoUserhostWithReason(2, S, true, dbv1.ptszVal); - DBFreeVariant( &dbv1 ); - } - else { - S += user.name; - DoUserhostWithReason( 2, S, true, user.name ); - } - } - if (getByte( "MirVerAutoRequest", 1)) - PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user.name); - } - - mir_free(id); - return hContact; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// AddToList - adds a contact to the contact list - -HANDLE __cdecl CIrcProto::AddToListByEvent( int, int, HANDLE ) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// AuthAllow - processes the successful authorization - -int __cdecl CIrcProto::Authorize( HANDLE ) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// AuthDeny - handles the unsuccessful authorization - -int __cdecl CIrcProto::AuthDeny( HANDLE, const TCHAR* ) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AUTH - -int __cdecl CIrcProto::AuthRecv( HANDLE, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AUTHREQUEST - -int __cdecl CIrcProto::AuthRequest( HANDLE, const TCHAR* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// ChangeInfo - -HANDLE __cdecl CIrcProto::ChangeInfo( int, void* ) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// FileAllow - starts a file transfer - -HANDLE __cdecl CIrcProto::FileAllow( HANDLE, HANDLE hTransfer, const TCHAR* szPath ) -{ - DCCINFO* di = ( DCCINFO* )hTransfer; - - if ( !IsConnected()) { - delete di; - return (HANDLE)szPath; - } - - di->sPath = szPath; - di->sFileAndPath = di->sPath + di->sFile; - - CDccSession* dcc = new CDccSession( this, di ); - AddDCCSession( di, dcc ); - dcc->Connect(); - return di; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// FileCancel - cancels a file transfer - -int __cdecl CIrcProto::FileCancel( HANDLE, HANDLE hTransfer ) -{ - DCCINFO* di = ( DCCINFO* )hTransfer; - - CDccSession* dcc = FindDCCSession(di); - if (dcc) { - InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_CANCEL); - SetEvent(dcc->hEvent); - dcc->Disconnect(); - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// FileDeny - denies a file transfer - -int __cdecl CIrcProto::FileDeny( HANDLE, HANDLE hTransfer, const TCHAR* ) -{ - DCCINFO* di = ( DCCINFO* )hTransfer; - delete di; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// FileResume - processes file renaming etc - -int __cdecl CIrcProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) -{ - DCCINFO* di = ( DCCINFO* )hTransfer; - - long i = (long)*action; - - CDccSession* dcc = FindDCCSession(di); - if (dcc) { - InterlockedExchange(&dcc->dwWhatNeedsDoing, i); - if (*action == FILERESUME_RENAME) { - TCHAR* szTemp = _tcsdup(*szFilename); - InterlockedExchangePointer((PVOID*)&dcc->NewFileName, szTemp); - } - - if (*action == FILERESUME_RESUME) { - unsigned __int64 dwPos = 0; - - struct _stati64 statbuf; - if (_tstati64(di->sFileAndPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) - dwPos = statbuf.st_size; - - CMString sFileWithQuotes = di->sFile; - - // if spaces in the filename surround witrh quotes - if (sFileWithQuotes.Find( ' ', 0 ) != -1 ) { - sFileWithQuotes.Insert( 0, _T("\"")); - sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); - } - - if (di->bReverse) - PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s 0 %I64u %s\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), dwPos, dcc->di->sToken.c_str()); - else - PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s %u %I64u\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), di->iPort, dwPos); - - return 0; - } - - SetEvent(dcc->hEvent); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetCaps - return protocol capabilities bits - -DWORD_PTR __cdecl CIrcProto::GetCaps( int type, HANDLE ) -{ - switch( type ) { - case PFLAGNUM_1: - return PF1_BASICSEARCH | PF1_MODEMSG | PF1_FILE | PF1_CHAT | PF1_CANRENAMEFILE | PF1_PEER2PEER | PF1_IM; - - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY; - - case PFLAGNUM_3: - return PF2_SHORTAWAY; - - case PFLAGNUM_4: - return PF4_NOAUTHDENYREASON | PF4_NOCUSTOMAUTH | PF4_IMSENDUTF; - - case PFLAG_UNIQUEIDTEXT: - return (DWORD_PTR) Translate("Nickname"); - - case PFLAG_MAXLENOFMESSAGE: - return 400; - - case PFLAG_UNIQUEIDSETTING: - return (DWORD_PTR) "Nick"; - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetIcon - loads an icon for the contact list - -HICON __cdecl CIrcProto::GetIcon( int iconIndex ) -{ - if (LOWORD(iconIndex) == PLI_PROTOCOL) - { - if (iconIndex & PLIF_ICOLIBHANDLE) - return (HICON)GetIconHandle(IDI_MAIN); - - bool big = (iconIndex & PLIF_SMALL) == 0; - HICON hIcon = LoadIconEx(IDI_MAIN, big); - - if (iconIndex & PLIF_ICOLIB) - return hIcon; - - HICON hIcon2 = CopyIcon(hIcon); - ReleaseIconEx(hIcon); - return hIcon2; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetInfo - retrieves a contact info - -int __cdecl CIrcProto::GetInfo( HANDLE, int ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchBasic - searches the contact by JID - -struct AckBasicSearchParam -{ - PROTOCHAR buf[ 50 ]; -}; - -void __cdecl CIrcProto::AckBasicSearch( void* param ) -{ - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_TCHAR; - psr.id = (( AckBasicSearchParam* )param )->buf; - psr.nick = (( AckBasicSearchParam* )param )->buf; - ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr); - ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0); - delete param; -} - -HANDLE __cdecl CIrcProto::SearchBasic( const PROTOCHAR* szId ) -{ - if ( szId ) { - if (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && - szId && szId[0] && !IsChannel(szId)) { - AckBasicSearchParam* param = new AckBasicSearchParam; - lstrcpyn( param->buf, szId, 50 ); - ircFork( &CIrcProto::AckBasicSearch, param ); - return ( HANDLE )1; - } } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchByEmail - searches the contact by its e-mail - -HANDLE __cdecl CIrcProto::SearchByEmail( const PROTOCHAR* ) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// upsupported search functions - -HANDLE __cdecl CIrcProto::SearchByName( const PROTOCHAR*, const PROTOCHAR*, const PROTOCHAR* ) -{ - return NULL; -} - -HWND __cdecl CIrcProto::CreateExtendedSearchUI( HWND ) -{ - return NULL; -} - -HWND __cdecl CIrcProto::SearchAdvanced( HWND ) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvContacts - -int __cdecl CIrcProto::RecvContacts( HANDLE, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvFile - -int __cdecl CIrcProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) -{ - return Proto_RecvFile(hContact, evt); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvMsg - -int __cdecl CIrcProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* evt ) -{ - return Proto_RecvMessage(hContact, evt); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvUrl - -int __cdecl CIrcProto::RecvUrl( HANDLE, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendContacts - -int __cdecl CIrcProto::SendContacts( HANDLE, int, int, HANDLE* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendFile - sends a file - -HANDLE __cdecl CIrcProto::SendFile( HANDLE hContact, const TCHAR*, TCHAR** ppszFiles ) -{ - DCCINFO* dci = NULL; - int iPort = 0; - int index= 0; - unsigned __int64 size = 0; - - // do not send to channels :-P - if ( getByte(hContact, "ChatRoom", 0) != 0) - return 0; - - // stop if it is an active type filetransfer and the user's IP is not known - unsigned long ulAdr = 0; - if (m_manualHost) - ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); - else - ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); - - if (!m_DCCPassive && !ulAdr) { - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: Unable to automatically resolve external IP"), NULL, NULL, NULL, true, false); - return 0; - } - - if ( ppszFiles[index] ) { - - //get file size - while (ppszFiles[index]) { - struct _stati64 statbuf; - if (_tstati64(ppszFiles[index], &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) { - size = statbuf.st_size; - break; - } - index++; - } - - if (size == 0) { - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: No valid files specified"), NULL, NULL, NULL, true, false); - return 0; - } - - DBVARIANT dbv; - if ( !getTString( hContact, "Nick", &dbv )) { - // set up a basic DCCINFO struct and pass it to a DCC object - dci = new DCCINFO; - dci->sFileAndPath = ppszFiles[index]; - - int i = dci->sFileAndPath.ReverseFind( '\\' ); - if (i != -1) { - dci->sPath = dci->sFileAndPath.Mid(0, i+1); - dci->sFile = dci->sFileAndPath.Mid(i+1, dci->sFileAndPath.GetLength()); - } - - CMString sFileWithQuotes = dci->sFile; - - // if spaces in the filename surround witrh quotes - if ( sFileWithQuotes.Find( ' ', 0 ) != -1) { - sFileWithQuotes.Insert( 0, _T("\"")); - sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); - } - - dci->hContact = hContact; - dci->sContactName = dbv.ptszVal; - dci->iType = DCC_SEND; - dci->bReverse = m_DCCPassive?true:false; - dci->bSender = true; - dci->dwSize = size; - - // create new dcc object - CDccSession* dcc = new CDccSession(this,dci); - - // keep track of all objects created - AddDCCSession(dci, dcc); - - // need to make sure that %'s are doubled to avoid having chat interpret as color codes - CMString sFileCorrect = dci->sFile; - ReplaceString(sFileCorrect, _T("%"), _T("%%")); - - // is it an reverse filetransfer (receiver acts as server) - if (dci->bReverse) { - TCHAR szTemp[256]; - PostIrcMessage( _T("/CTCP %s DCC SEND %s 200 0 %I64u %u"), - dci->sContactName.c_str(), sFileWithQuotes.c_str(), dci->dwSize, dcc->iToken); - - mir_sntprintf(szTemp, SIZEOF(szTemp), - TranslateT("DCC reversed file transfer request sent to %s [%s]"), - dci->sContactName.c_str(), sFileCorrect.c_str()); - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - - if (m_sendNotice) { - mir_sntprintf(szTemp, SIZEOF(szTemp), - _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [Reverse transfer]"), - dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024); - PostIrcMessage(szTemp); - } - } - else { // ... normal filetransfer. - iPort = dcc->Connect(); - if ( iPort ) { - TCHAR szTemp[256]; - PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u"), - dci->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, iPort, dci->dwSize); - - mir_sntprintf(szTemp, SIZEOF(szTemp), - TranslateT("DCC file transfer request sent to %s [%s]"), - dci->sContactName.c_str(), sFileCorrect.c_str()); - DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); - - if ( m_sendNotice ) { - mir_sntprintf(szTemp, SIZEOF(szTemp), - _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [IP: %s]"), - dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024, (TCHAR*)_A2T(ConvertIntegerToIP(ulAdr))); - PostIrcMessage(szTemp); - } - } - else DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), - TranslateT("DCC ERROR: Unable to bind local port"), NULL, NULL, NULL, true, false); - } - - // fix for sending multiple files - index++; - while( ppszFiles[index] ) { - if ( _taccess(ppszFiles[index], 0) == 0 ) { - PostIrcMessage( _T("/DCC SEND %s ") _T(TCHAR_STR_PARAM), dci->sContactName.c_str(), ppszFiles[index]); - } - index++; - } - - DBFreeVariant( &dbv ); - } } - - if (dci) - return dci; - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendMessage - sends a message - -void __cdecl CIrcProto::AckMessageFail( void* info ) -{ - ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The protocol is not online")); -} - -void __cdecl CIrcProto::AckMessageFailDcc( void* info ) -{ - ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The dcc chat connection is not active")); -} - -void __cdecl CIrcProto::AckMessageSuccess( void* info ) -{ - ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0); -} - -int __cdecl CIrcProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) -{ - BYTE bDcc = getByte( hContact, "DCC", 0) ; - WORD wStatus = getWord( hContact, "Status", ID_STATUS_OFFLINE) ; - if ( m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && !bDcc || bDcc && wStatus == ID_STATUS_ONLINE ) { - int codepage = getCodepage(); - - TCHAR* result; - if ( flags & PREF_UNICODE ) { - const char* p = strchr( pszSrc, '\0' ); - if ( p != pszSrc ) { - while ( *(++p) == '\0' ) - ; - result = mir_u2t_cp(( wchar_t* )p, codepage ); - } - else result = mir_a2t_cp( pszSrc, codepage ); - } - else if ( flags & PREF_UTF ) { - mir_utf8decode( NEWSTR_ALLOCA(pszSrc), &result ); - } - else result = mir_a2t_cp( pszSrc, codepage ); - - PostIrcMessageWnd(NULL, hContact, result ); - mir_free( result ); - ircFork( &CIrcProto::AckMessageSuccess, hContact ); - } - else { - if ( bDcc ) - ircFork( &CIrcProto::AckMessageFailDcc, hContact ); - else - ircFork( &CIrcProto::AckMessageFail, hContact ); - } - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendUrl - -int __cdecl CIrcProto::SendUrl( HANDLE, int, const char* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SetApparentMode - sets the visibility status - -int __cdecl CIrcProto::SetApparentMode( HANDLE, int ) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SetStatus - sets the protocol status - -int __cdecl CIrcProto::SetStatus( int iNewStatus ) -{ - return SetStatusInternal( iNewStatus, false ); -} - -int CIrcProto::SetStatusInternal( int iNewStatus, bool bIsInternal ) -{ - if ( !bChatInstalled ) - return 0; - - if ( iNewStatus != ID_STATUS_OFFLINE && !m_network[0] ) { - if (m_nick[0] && !m_disableDefaultServer) { - CQuickDlg* dlg = new CQuickDlg( this ); - dlg->GetProto()->m_quickComboSelection = dlg->GetProto()->m_serverComboSelection + 1; - dlg->Show(); - HWND hwnd = dlg->GetHwnd(); - SetWindowTextA(hwnd, "Miranda IRC"); - SetWindowText(GetDlgItem(hwnd, IDC_TEXT), TranslateT("Please choose an IRC-network to go online. This network will be the default.")); - SetWindowText(GetDlgItem(hwnd, IDC_CAPTION), TranslateT("Default network")); - WindowSetIcon(hwnd, IDI_MAIN); - ShowWindow(hwnd, SW_SHOW); - SetActiveWindow(hwnd); - } - return 0; - } - - if ( iNewStatus != ID_STATUS_OFFLINE && !m_nick[0] || !m_userID[0] || !m_name[0]) { - MIRANDASYSTRAYNOTIFY msn; - msn.cbSize = sizeof( MIRANDASYSTRAYNOTIFY ); - msn.szProto = m_szModuleName; - msn.tszInfoTitle = TranslateT( "IRC error" ); - msn.tszInfo = TranslateT( "Connection can not be established! You have not completed all necessary fields (Nickname, User ID and m_name)." ); - msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; - msn.uTimeout = 15000; - CallService( MS_CLIST_SYSTRAY_NOTIFY, (WPARAM)NULL,(LPARAM) &msn); - return 0; - } - - if ( !bIsInternal ) - m_iDesiredStatus = iNewStatus; - - if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_AWAY || iNewStatus == ID_STATUS_FREECHAT) && !IsConnected()) //go from offline to online - { - if (!m_bConnectThreadRunning) - ConnectToServer(); - } - else if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_FREECHAT) && IsConnected() && m_iStatus == ID_STATUS_AWAY) //go to online while connected - { - m_statusMessage = _T(""); - PostIrcMessage( _T("/AWAY")); - return 0; - } - else if ( iNewStatus == ID_STATUS_OFFLINE && IsConnected()) //go from online/away to offline - DisconnectFromServer(); - else if ( iNewStatus == ID_STATUS_OFFLINE && !IsConnected()) //offline to offline - { - KillChatTimer( RetryTimer); - return 0; - } - else if ( iNewStatus == ID_STATUS_AWAY && IsConnected()) //go to away while connected - { - PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); - return 0; - } - else if ( iNewStatus == ID_STATUS_ONLINE && IsConnected()) //already online - return 0; - else - SetStatusInternal(ID_STATUS_AWAY, true); - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetAwayMsg - returns a contact's away message - -HANDLE __cdecl CIrcProto::GetAwayMsg( HANDLE hContact ) -{ - WhoisAwayReply = _T(""); - DBVARIANT dbv; - - // bypass chat contacts. - if ( getByte( hContact, "ChatRoom", 0 ) == 0) { - if ( hContact && !getTString( hContact, "Nick", &dbv)) { - int i = getWord( hContact, "Status", ID_STATUS_OFFLINE ); - if ( i != ID_STATUS_AWAY) { - DBFreeVariant( &dbv); - return 0; - } - CMString S = _T("WHOIS "); - S += dbv.ptszVal; - if (IsConnected()) - SendIrcMessage( S.c_str(), false); - DBFreeVariant( &dbv); - } } - - return (HANDLE)1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AWAYMSG - -int __cdecl CIrcProto::RecvAwayMsg( HANDLE, int, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AWAYMSG - -int __cdecl CIrcProto::SendAwayMsg( HANDLE, HANDLE, const char* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SetAwayMsg - sets the away status message - -int __cdecl CIrcProto::SetAwayMsg( int status, const TCHAR* msg ) -{ - switch( status ) { - case ID_STATUS_ONLINE: case ID_STATUS_INVISIBLE: case ID_STATUS_FREECHAT: - case ID_STATUS_CONNECTING: case ID_STATUS_OFFLINE: - break; - - default: - CMString newStatus = msg; - ReplaceString( newStatus, _T("\r\n"), _T(" ")); - if ( m_statusMessage.IsEmpty() || msg == NULL || m_statusMessage != newStatus ) { - if ( msg == NULL || *msg == 0 ) - m_statusMessage = _T(STR_AWAYMESSAGE); - else - m_statusMessage = newStatus; - - if ( m_iStatus == ID_STATUS_AWAY ) - PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); - } } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// UserIsTyping - sends a UTN notification - -int __cdecl CIrcProto::UserIsTyping( HANDLE, int ) -{ - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnEvent - maintain protocol events - -int __cdecl CIrcProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ) -{ - switch( eventType ) { - case EV_PROTO_ONLOAD: return OnModulesLoaded( 0, 0 ); - case EV_PROTO_ONEXIT: return OnPreShutdown( 0, 0 ); - case EV_PROTO_ONOPTIONS: return OnInitOptionsPages( wParam, lParam ); - - case EV_PROTO_ONMENU: - InitMainMenus(); - break; - - case EV_PROTO_ONRENAME: - if ( hMenuRoot ) { - CLISTMENUITEM clmi = { 0 }; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - clmi.ptszName = m_tszUserName; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuRoot, ( LPARAM )&clmi ); - } - break; - - case EV_PROTO_ONCONTACTDELETED: - return OnContactDeleted(wParam, lParam); - - case EV_PROTO_DBSETTINGSCHANGED: - return OnDbSettingChanged(wParam, lParam); - } - return 1; -} diff --git a/protocols/IRCG/main.cpp b/protocols/IRCG/main.cpp deleted file mode 100644 index ea802d43cd..0000000000 --- a/protocols/IRCG/main.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" -#include "version.h" - -HINSTANCE hInst = NULL; - -int hLangpack; - -static int CompareServers( const SERVER_INFO* p1, const SERVER_INFO* p2 ) -{ - return lstrcmpA( p1->m_name, p2->m_name ); -} - -OBJLIST g_servers( 20, CompareServers ); - -static int sttCompareProtocols(const CIrcProto *p1, const CIrcProto *p2) -{ - return strcmp(p1->m_szModuleName, p2->m_szModuleName); -} - -LIST g_Instances(1, sttCompareProtocols); - -void InitTimers( void ); -void UninitTimers( void ); - -// Information about the plugin -PLUGININFOEX pluginInfo = -{ - sizeof( PLUGININFOEX ), - __PLUGIN_NAME, - __VERSION_DWORD, - __DESC, - __AUTHOR, - __AUTHOREMAIL, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - {0x92382b4d, 0x5572, 0x48a0, {0xb0, 0xb9, 0x13, 0x36, 0xa6, 0x1, 0xd6, 0x89}} // {92382B4D-5572-48a0-B0B9-1336A601D689} -}; - -extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD, LPVOID) -{ - hInst = hinstDLL; - return TRUE; -} - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) -{ - return &pluginInfo; -} - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static CIrcProto* ircProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) -{ - CIrcProto* ppro = new CIrcProto( pszProtoName, tszUserName ); - g_Instances.insert( ppro ); - return ppro; -} - -static int ircProtoUninit( CIrcProto* ppro ) -{ - g_Instances.remove(( CIrcProto* )ppro); - delete ppro; - return 0; -} - -extern "C" int __declspec(dllexport) Load( ) -{ - - mir_getLP( &pluginInfo ); - - AddIcons(); - InitTimers(); - InitServers(); - InitContactMenus(); - - // register protocol - PROTOCOLDESCRIPTOR pd = { 0 }; - pd.cbSize = sizeof( pd ); - pd.szName = "IRC"; - pd.type = PROTOTYPE_PROTOCOL; - pd.fnInit = ( pfnInitProto )ircProtoInit; - pd.fnUninit = ( pfnUninitProto )ircProtoUninit; - CallService( MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd ); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -extern "C" int __declspec(dllexport) Unload(void) -{ - UninitContactMenus(); - UninitIcons(); - UninitTimers(); - - g_Instances.destroy(); - - return 0; -} diff --git a/protocols/IRCG/options.cpp b/protocols/IRCG/options.cpp deleted file mode 100644 index 69a991374b..0000000000 --- a/protocols/IRCG/options.cpp +++ /dev/null @@ -1,1962 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" -#include - -#include "ui_utils.h" - -static WNDPROC OldProc; -static WNDPROC OldListViewProc; - -static HANDLE* hIconLibItems; - -static const CIrcProto* pZero = NULL; - -void CIrcProto::ReadSettings( TDbSetting* sets, int count ) -{ - BYTE* base = ( BYTE* )this; - - DBVARIANT dbv; - for ( int i=0; i < count; i++ ) { - TDbSetting* p = &sets[i]; - BYTE* ptr = base + p->offset; - switch( p->type ) { - case DBVT_BYTE: - *( BYTE* )ptr = getByte( p->name, p->defValue ); - break; - case DBVT_WORD: - *( WORD* )ptr = getWord( p->name, p->defValue ); - break; - case DBVT_DWORD: - *( DWORD* )ptr = getDword( p->name, p->defValue ); - break; - case DBVT_ASCIIZ: - if ( !getString( p->name, &dbv )) { - if ( p->size != -1 ) { - size_t len = min( p->size-1, strlen( dbv.pszVal )); - memcpy( ptr, dbv.pszVal, len ); - ptr[len] = 0; - } - else *( char** )ptr = mir_strdup( dbv.pszVal ); - DBFreeVariant( &dbv ); - } - else { - if ( p->size != -1 ) - *ptr = 0; - else - *( char** )ptr = NULL; - } - break; - case DBVT_TCHAR: - if ( !getTString( p->name, &dbv )) { - if ( p->size != -1 ) { - size_t len = min( p->size-1, _tcslen( dbv.ptszVal )); - memcpy( ptr, dbv.pszVal, len*sizeof(TCHAR)); - *( TCHAR* )&ptr[len*sizeof(TCHAR)] = 0; - } - else *( TCHAR** )ptr = mir_tstrdup( dbv.ptszVal ); - DBFreeVariant( &dbv ); - } - else { - if ( p->size != -1 ) { - if ( p->defStr == NULL ) - *ptr = 0; - else - lstrcpyn(( TCHAR* )ptr, p->defStr, (int)p->size ); - } - else *( TCHAR** )ptr = mir_tstrdup( p->defStr ); - } - break; -} } } - -void CIrcProto::WriteSettings( TDbSetting* sets, int count ) -{ - BYTE* base = ( BYTE* )this; - - for ( int i=0; i < count; i++ ) { - TDbSetting* p = &sets[i]; - BYTE* ptr = base + p->offset; - switch( p->type ) { - case DBVT_BYTE: setByte( p->name, *( BYTE* )ptr ); break; - case DBVT_WORD: setWord( p->name, *( WORD* )ptr ); break; - case DBVT_DWORD: setDword( p->name, *( DWORD* )ptr ); break; - - case DBVT_ASCIIZ: - if ( p->size == -1 ) - setString( p->name, *(char**)ptr ); - else - setString( p->name, (char*)ptr ); - break; - - case DBVT_TCHAR: - if ( p->size == -1 ) - setTString( p->name, *(TCHAR**)ptr ); - else - setTString( p->name, (TCHAR*)ptr ); - break; -} } } - -///////////////////////////////////////////////////////////////////////////////////////// - -static int sttServerEnum( const char* szSetting, LPARAM ) -{ - DBVARIANT dbv; - if ( DBGetContactSettingString( NULL, SERVERSMODULE, szSetting, &dbv )) - return 0; - - SERVER_INFO* pData = new SERVER_INFO; - pData->m_name = mir_strdup( szSetting ); - - char* p1 = strchr( dbv.pszVal, ':' )+1; - pData->m_iSSL = 0; - if ( !_strnicmp( p1, "SSL", 3 )) { - p1 +=3; - if ( *p1 == '1' ) - pData->m_iSSL = 1; - else if ( *p1 == '2' ) - pData->m_iSSL = 2; - p1++; - } - char* p2 = strchr(p1, ':'); - pData->m_address = ( char* )mir_alloc( p2-p1+1 ); - lstrcpynA( pData->m_address, p1, p2-p1+1 ); - - p1 = p2+1; - while (*p2 !='G' && *p2 != '-') - p2++; - - char* buf = ( char* )alloca( p2-p1+1 ); - lstrcpynA( buf, p1, p2-p1+1 ); - pData->m_portStart = atoi( buf ); - - if ( *p2 == 'G' ) - pData->m_portEnd = pData->m_portStart; - else { - p1 = p2+1; - p2 = strchr(p1, 'G'); - buf = ( char* )alloca( p2-p1+1 ); - lstrcpynA( buf, p1, p2-p1+1 ); - pData->m_portEnd = atoi( buf ); - } - - p1 = strchr(p2, ':')+1; - p2 = strchr(p1, '\0'); - pData->m_group = ( char* )mir_alloc( p2-p1+1 ); - lstrcpynA( pData->m_group, p1, p2-p1+1 ); - - g_servers.insert( pData ); - DBFreeVariant( &dbv ); - return 0; -} - -void RereadServers() -{ - g_servers.destroy(); - - DBCONTACTENUMSETTINGS dbces; - dbces.pfnEnumProc = sttServerEnum; - dbces.szModule = SERVERSMODULE; - CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void removeSpaces( TCHAR* p ) -{ - while ( *p ) { - if ( *p == ' ' ) - memmove( p, p+1, sizeof(TCHAR)*lstrlen(p)); - p++; -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// add icons to the skinning module - -struct -{ - char* szDescr; - char* szName; - int iSize; - int defIconID; -} -static iconList[] = -{ - { LPGEN("Main"), "main", 0, IDI_MAIN }, - { LPGEN("Add"), "add", 0, IDI_ADD }, - { LPGEN("Apply"), "apply", 0, IDI_APPLY }, - { LPGEN("Rename"), "rename", 0, IDI_RENAME }, - { LPGEN("Edit"), "edit", 0, IDI_EDIT }, - { LPGEN("Cancel"), "delete", 0, IDI_DELETE }, - { LPGEN("Ignore"), "block", 0, IDI_BLOCK }, - { LPGEN("Channel list"), "list", 0, IDI_LIST }, - { LPGEN("Channel manager"), "manager", 0, IDI_MANAGER }, - { LPGEN("Quick connect"), "quick", 0, IDI_QUICK }, - { LPGEN("Server window"), "server", 0, IDI_SERVER }, - { LPGEN("Show channel"), "show", 0, IDI_SHOW }, - { LPGEN("Question"), "question", 0, IDI_IRCQUESTION}, - { LPGEN("WhoIs"), "whois", 0, IDI_WHOIS }, - { LPGEN("Incoming DCC Chat"), "dcc", 0, IDI_DCC }, - { LPGEN("Logo (48x48)"), "logo", 48, IDI_LOGO } -}; - -void AddIcons(void) -{ - TCHAR szFile[MAX_PATH]; - GetModuleFileName(hInst, szFile, MAX_PATH); - - SKINICONDESC sid = {0}; - sid.cbSize = sizeof(SKINICONDESC); - sid.pszSection = "Protocols/IRC"; - sid.ptszDefaultFile = szFile; - sid.flags = SIDF_PATH_TCHAR; - hIconLibItems = new HANDLE[ SIZEOF(iconList) ]; - - // add them one by one - for ( int i=0; i < SIZEOF(iconList); i++ ) { - char szTemp[255]; - mir_snprintf(szTemp, sizeof(szTemp), "IRC_%s", iconList[i].szName ); - sid.pszName = szTemp; - sid.pszDescription = iconList[i].szDescr; - sid.iDefaultIndex = -iconList[i].defIconID; - sid.cx = sid.cy = iconList[i].iSize; - hIconLibItems[i] = Skin_AddIcon(&sid ); - } -} - -void UninitIcons(void) -{ - delete[] hIconLibItems; -} - -HICON LoadIconEx( int iconId, bool big ) -{ - for ( int i=0; i < SIZEOF(iconList); i++ ) - if ( iconList[i].defIconID == iconId ) - return ( HICON )CallService( MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)hIconLibItems[i] ); - - return NULL; -} - -HANDLE GetIconHandle( int iconId ) -{ - for ( int i=0; i < SIZEOF(iconList); i++ ) - if ( iconList[i].defIconID == iconId ) - return hIconLibItems[i]; - - return NULL; -} - -void ReleaseIconEx( HICON hIcon ) -{ - if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); -} - -void WindowSetIcon( HWND hWnd, int iconId ) -{ - SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadIconEx( iconId, true )); - SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadIconEx( iconId )); -} - -void WindowFreeIcon( HWND hWnd ) -{ - ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0)); - ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0)); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// code page handler - -struct { UINT cpId; TCHAR *cpName; } static cpTable[] = -{ - { 874, LPGENT("Thai") }, - { 932, LPGENT("Japanese") }, - { 936, LPGENT("Simplified Chinese") }, - { 949, LPGENT("Korean") }, - { 950, LPGENT("Traditional Chinese") }, - { 1250, LPGENT("Central European") }, - { 1251, LPGENT("Cyrillic (Windows)") }, - { 20866, LPGENT("Cyrillic (KOI8R)") }, - { 1252, LPGENT("Latin I") }, - { 1253, LPGENT("Greek") }, - { 1254, LPGENT("Turkish") }, - { 1255, LPGENT("Hebrew") }, - { 1256, LPGENT("Arabic") }, - { 1257, LPGENT("Baltic") }, - { 1258, LPGENT("Vietnamese") }, - { 1361, LPGENT("Korean (Johab)") } -}; - -static CCtrlCombo* sttCombo; - -typedef BOOL ( WINAPI *pfnGetCPInfoEx )( UINT, DWORD, LPCPINFOEX ); -static pfnGetCPInfoEx fnGetCPInfoEx = NULL; - -static BOOL CALLBACK sttLangAddCallback( CHAR* str ) -{ - UINT cp = atoi(str); - if ( fnGetCPInfoEx == NULL ) { - int i; - for ( i=0; i < SIZEOF(cpTable) && cpTable[i].cpId != cp; i++ ); - if ( i < SIZEOF(cpTable)) - sttCombo->AddString( TranslateTS( cpTable[i].cpName ), cp ); - } - else { - CPINFOEX cpinfo; - if ( fnGetCPInfoEx( cp, 0, &cpinfo )) { - TCHAR* b = _tcschr( cpinfo.CodePageName, '(' ); - if ( b ) { - TCHAR* e = _tcsrchr( cpinfo.CodePageName, ')' ); - if ( e ) { - *e = 0; - sttCombo->AddString( b+1, cp ); - } - else sttCombo->AddString( cpinfo.CodePageName, cp ); - } - else sttCombo->AddString( cpinfo.CodePageName, cp ); - } } - - return TRUE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Add server' dialog - -static int sttRequiredFields[] = { IDC_ADD_SERVER, IDC_ADD_ADDRESS, IDC_ADD_PORT, IDC_ADD_PORT2, IDC_ADD_COMBO }; - -struct CServerDlg : public CProtoDlgBase -{ - CConnectPrefsDlg* m_owner; - int m_action; - - CCtrlButton m_OK; - CCtrlEdit m_server, m_address, m_port, m_port2; - CCtrlCombo m_groupCombo; - - CServerDlg( CIrcProto* _pro, CConnectPrefsDlg* _owner, int _action ) : - CProtoDlgBase( _pro, IDD_ADDSERVER, _owner->GetHwnd()), - m_owner( _owner ), - m_action( _action ), - m_OK( this, IDOK ), - m_groupCombo( this, IDC_ADD_COMBO ), - m_address( this, IDC_ADD_ADDRESS ), - m_server( this, IDC_ADD_SERVER ), - m_port( this, IDC_ADD_PORT ), - m_port2( this, IDC_ADD_PORT2 ) - { - m_OK.OnClick = Callback( this, &CServerDlg::OnOk ); - m_autoClose = CLOSE_ON_CANCEL; - } - - virtual void OnInitDialog() - { - int i = m_owner->m_serverCombo.GetCount(); - for ( int index = 0; index < i; index++ ) { - SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( index ); - if ( m_groupCombo.FindStringA( pData->m_group, -1, true ) == CB_ERR ) - m_groupCombo.AddStringA( pData->m_group ); - } - - if ( m_action == 2 ) { - int j = m_owner->m_serverCombo.GetCurSel(); - SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( j ); - m_address.SetTextA( pData->m_address ); - m_groupCombo.SetTextA( pData->m_group ); - m_port.SetInt( pData->m_portStart ); - m_port2.SetInt( pData->m_portEnd ); - - char* p = strstr( pData->m_name, ": "); - if ( p ) - m_server.SetTextA( p+2 ); - - if ( pData->m_iSSL == 0 ) - CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED ); - if ( pData->m_iSSL == 1 ) - CheckDlgButton( m_hwnd, IDC_AUTO, BST_CHECKED ); - if ( pData->m_iSSL == 2 ) - CheckDlgButton( m_hwnd, IDC_ON, BST_CHECKED ); - } - else { - CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED); - m_port.SetInt( 6667 ); - m_port2.SetInt( 6667 ); - } - - int bEnableSsl = TRUE; - EnableWindow(GetDlgItem( m_hwnd, IDC_ON), bEnableSsl ); - EnableWindow(GetDlgItem( m_hwnd, IDC_OFF), bEnableSsl ); - EnableWindow(GetDlgItem( m_hwnd, IDC_AUTO), bEnableSsl ); - - SetFocus( m_groupCombo.GetHwnd()); - } - - virtual void OnClose() - { - m_owner->m_serverCombo.Enable(); - m_owner->m_add.Enable(); - m_owner->m_edit.Enable(); - m_owner->m_del.Enable(); - } - - void OnOk( CCtrlButton* ) - { - for ( int k = 0; k < SIZEOF(sttRequiredFields); k++ ) - if ( !GetWindowTextLength( GetDlgItem( m_hwnd, sttRequiredFields[k] ))) { - MessageBox( m_hwnd, TranslateT("Please complete all fields"), TranslateT("IRC error"), MB_OK | MB_ICONERROR ); - return; - } - - if ( m_action == 2 ) { - int i = m_owner->m_serverCombo.GetCurSel(); - m_owner->m_serverCombo.DeleteString( i ); - } - - SERVER_INFO* pData = new SERVER_INFO; - pData->m_iSSL = 0; - if(IsDlgButtonChecked( m_hwnd, IDC_ON)) - pData->m_iSSL = 2; - if(IsDlgButtonChecked( m_hwnd, IDC_AUTO)) - pData->m_iSSL = 1; - - pData->m_portStart = m_port.GetInt(); - pData->m_portEnd = m_port2.GetInt(); - pData->m_address = rtrim(m_address.GetTextA()); - pData->m_group = m_groupCombo.GetTextA(); - pData->m_name = m_server.GetTextA(); - - char temp[255]; - mir_snprintf( temp, sizeof(temp), "%s: %s", pData->m_group, pData->m_name ); - mir_free( pData->m_name ); - pData->m_name = mir_strdup( temp ); - - int iItem = m_owner->m_serverCombo.AddStringA( pData->m_name, ( LPARAM )pData ); - m_owner->m_serverCombo.SetCurSel( iItem ); - m_owner->OnServerCombo( NULL ); - - m_owner->m_serverlistModified = true; - Close(); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Connect preferences' dialog - -static TDbSetting ConnectSettings[] = -{ - { FIELD_OFFSET(CIrcProto, m_userID), "UserID", DBVT_TCHAR, SIZEOF(pZero->m_userID) }, - { FIELD_OFFSET(CIrcProto, m_identSystem), "IdentSystem", DBVT_TCHAR, SIZEOF(pZero->m_identSystem) }, - { FIELD_OFFSET(CIrcProto, m_identPort), "IdentPort", DBVT_TCHAR, SIZEOF(pZero->m_identPort) }, - { FIELD_OFFSET(CIrcProto, m_retryWait), "RetryWait", DBVT_TCHAR, SIZEOF(pZero->m_retryWait) }, - { FIELD_OFFSET(CIrcProto, m_retryCount), "RetryCount", DBVT_TCHAR, SIZEOF(pZero->m_retryCount) }, - - { FIELD_OFFSET(CIrcProto, m_serverName ), "ServerName", DBVT_ASCIIZ, SIZEOF(pZero->m_serverName) }, - { FIELD_OFFSET(CIrcProto, m_portStart ), "PortStart", DBVT_ASCIIZ, SIZEOF(pZero->m_portStart) }, - { FIELD_OFFSET(CIrcProto, m_portEnd ), "PortEnd", DBVT_ASCIIZ, SIZEOF(pZero->m_portEnd ) }, - { FIELD_OFFSET(CIrcProto, m_password ), "Password", DBVT_ASCIIZ, SIZEOF(pZero->m_password ) }, - { FIELD_OFFSET(CIrcProto, m_joinOnInvite ), "JoinOnInvite", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_network ), "Network", DBVT_ASCIIZ, SIZEOF(pZero->m_network ) }, - { FIELD_OFFSET(CIrcProto, m_iSSL ), "UseSSL", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_onlineNotificationTime) , "OnlineNotificationTime", DBVT_WORD, 0, 30 }, - { FIELD_OFFSET(CIrcProto, m_onlineNotificationLimit) , "OnlineNotificationLimit", DBVT_WORD, 0, 50 }, - { FIELD_OFFSET(CIrcProto, m_channelAwayNotification), "ChannelAwayNotification", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_nick), "Nick", DBVT_TCHAR, SIZEOF(pZero->m_nick) }, - { FIELD_OFFSET(CIrcProto, m_pNick), "PNick", DBVT_TCHAR, SIZEOF(pZero->m_pNick) }, - { FIELD_OFFSET(CIrcProto, m_alternativeNick), "AlernativeNick", DBVT_TCHAR, SIZEOF(pZero->m_alternativeNick) }, - { FIELD_OFFSET(CIrcProto, m_name), "Name", DBVT_TCHAR, SIZEOF(pZero->m_name) }, - { FIELD_OFFSET(CIrcProto, m_disableDefaultServer), "DisableDefaultServer", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_ident), "Ident", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_identTimer), "IdentTimer", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_forceVisible), "ForceVisible", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_disableErrorPopups), "DisableErrorPopups", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_rejoinChannels), "RejoinChannels", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_rejoinIfKicked), "RejoinIfKicked", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_retry), "Retry", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_showAddresses), "ShowAddresses", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_oldStyleModes), "OldStyleModes", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_useServer), "UseServer", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_hideServerWindow), "HideServerWindow", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_serverComboSelection), "ServerComboSelection", DBVT_DWORD, 0 }, - { FIELD_OFFSET(CIrcProto, m_sendKeepAlive), "SendKeepAlive", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_autoOnlineNotification), "AutoOnlineNotification", DBVT_BYTE }, -}; - -CConnectPrefsDlg::CConnectPrefsDlg( CIrcProto* _pro ) : - CProtoDlgBase( _pro, IDD_PREFS_CONNECT, NULL ), - m_serverCombo( this, IDC_SERVERCOMBO ), - m_server( this, IDC_SERVER ), - m_port( this, IDC_PORT ), - m_port2( this, IDC_PORT2 ), - m_pass( this, IDC_PASS ), - m_add( this, IDC_ADDSERVER, LoadIconEx(IDI_ADD), LPGEN("Add a new network")), - m_edit( this, IDC_EDITSERVER, LoadIconEx(IDI_EDIT), LPGEN("Edit this network")), - m_del( this, IDC_DELETESERVER, LoadIconEx(IDI_DELETE), LPGEN("Delete this network")), - m_nick( this, IDC_NICK ), - m_nick2( this, IDC_NICK2 ), - m_name( this, IDC_NAME ), - m_userID( this, IDC_USERID ), - m_ident( this, IDC_IDENT ), - m_identSystem( this, IDC_IDENTSYSTEM ), - m_identPort( this, IDC_IDENTPORT ), - m_identTimer( this, IDC_IDENT_TIMED ), - m_retry( this, IDC_RETRY ), - m_retryWait( this, IDC_RETRYWAIT ), - m_retryCount( this, IDC_RETRYCOUNT ), - m_forceVisible( this, IDC_FORCEVISIBLE ), - m_rejoinOnKick( this, IDC_REJOINONKICK ), - m_rejoinChannels( this, IDC_REJOINCHANNELS ), - m_disableError( this, IDC_DISABLEERROR ), - m_address( this, IDC_ADDRESS ), - m_useServer( this, IDC_USESERVER ), - m_showServer( this, IDC_SHOWSERVER ), - m_keepAlive( this, IDC_KEEPALIVE ), - m_autoJoin( this, IDC_AUTOJOIN ), - m_oldStyle( this, IDC_OLDSTYLE ), - m_onlineNotif( this, IDC_ONLINENOTIF ), - m_channelAway( this, IDC_CHANNELAWAY ), - m_enableServer( this, IDC_STARTUP ), - m_onlineTimer( this, IDC_ONLINETIMER ), - m_limit( this, IDC_LIMIT ), - m_spin1( this, IDC_SPIN1 ), - m_spin2( this, IDC_SPIN2 ), - m_ssl( this, IDC_SSL ), - m_serverlistModified( false ) -{ - m_serverCombo.OnChange = Callback( this, &CConnectPrefsDlg::OnServerCombo ); - m_add.OnClick = Callback( this, &CConnectPrefsDlg::OnAddServer ); - m_del.OnClick = Callback( this, &CConnectPrefsDlg::OnDeleteServer ); - m_edit.OnClick = Callback( this, &CConnectPrefsDlg::OnEditServer ); - m_enableServer.OnChange = Callback( this, &CConnectPrefsDlg::OnStartup ); - m_ident.OnChange = Callback( this, &CConnectPrefsDlg::OnIdent ); - m_useServer.OnChange = Callback( this, &CConnectPrefsDlg::OnUseServer ); - m_onlineNotif.OnChange = Callback( this, &CConnectPrefsDlg::OnOnlineNotif ); - m_channelAway.OnChange = Callback( this, &CConnectPrefsDlg::OnChannelAway ); - m_retry.OnChange = Callback( this, &CConnectPrefsDlg::OnRetry ); -} - -void CConnectPrefsDlg::OnInitDialog() -{ - m_proto->m_hwndConnect = m_hwnd; - - // Fill the servers combo box and create SERVER_INFO structures - for ( int i=0; i < g_servers.getCount(); i++ ) { - SERVER_INFO& si = g_servers[i]; - m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); - } - - m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); - m_server.SetTextA( m_proto->m_serverName ); - m_port.SetTextA( m_proto->m_portStart ); - m_port2.SetTextA( m_proto->m_portEnd ); - - if ( m_proto->m_iSSL == 0 ) - m_ssl.SetText( TranslateT( "Off" )); - if ( m_proto->m_iSSL == 1 ) - m_ssl.SetText( TranslateT( "Auto" )); - if ( m_proto->m_iSSL == 2 ) - m_ssl.SetText( TranslateT( "On" )); - - if ( m_proto->m_serverComboSelection != -1 ) { - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( m_proto->m_serverComboSelection ); - if ((INT_PTR)pData != CB_ERR) { - m_server.SetTextA( pData->m_address ); - m_port.SetInt( pData->m_portStart ); - m_port2.SetInt( pData->m_portEnd ); - } } - - m_spin1.SendMsg( UDM_SETRANGE,0,MAKELONG(999,20)); - m_spin1.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationTime,0)); - m_spin2.SendMsg( UDM_SETRANGE,0,MAKELONG(200,0)); - m_spin2.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationLimit,0)); - m_nick.SetText( m_proto->m_nick); - m_nick2.SetText( m_proto->m_alternativeNick ); - m_userID.SetText( m_proto->m_userID); - m_name.SetText( m_proto->m_name); - m_pass.SetTextA( m_proto->m_password); - m_identSystem.SetText( m_proto->m_identSystem ); - m_identPort.SetText( m_proto->m_identPort ); - m_retryWait.SetText( m_proto->m_retryWait); - m_retryCount.SetText( m_proto->m_retryCount); - m_address.SetState( m_proto->m_showAddresses ); - m_oldStyle.SetState( m_proto->m_oldStyleModes ); - m_channelAway.SetState( m_proto->m_channelAwayNotification ); - m_onlineNotif.SetState( m_proto->m_autoOnlineNotification ); - m_onlineTimer.Enable( m_proto->m_autoOnlineNotification); - m_channelAway.Enable( m_proto->m_autoOnlineNotification); - m_spin1.Enable( m_proto->m_autoOnlineNotification ); - m_spin2.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); - m_limit.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); - m_ident.SetState( m_proto->m_ident ); - m_identSystem.Enable( m_proto->m_ident ); - m_identPort.Enable( m_proto->m_ident ); - m_identTimer.Enable( m_proto->m_ident ); - m_identTimer.SetState( m_proto->m_identTimer ); - m_disableError.SetState( m_proto->m_disableErrorPopups ); - m_forceVisible.SetState( m_proto->m_forceVisible ); - m_rejoinChannels.SetState( m_proto->m_rejoinChannels ); - m_rejoinOnKick.SetState( m_proto->m_rejoinIfKicked ); - m_retry.SetState( m_proto->m_retry ); - m_retryWait.Enable( m_proto->m_retry ); - m_retryCount.Enable( m_proto->m_retry ); - m_enableServer.SetState( !m_proto->m_disableDefaultServer ); - m_keepAlive.SetState( m_proto->m_sendKeepAlive ); - m_useServer.SetState( m_proto->m_useServer ); - m_showServer.SetState( !m_proto->m_hideServerWindow ); - m_showServer.Enable( m_proto->m_useServer ); - m_autoJoin.SetState( m_proto->m_joinOnInvite ); - - m_serverCombo.Enable( !m_proto->m_disableDefaultServer ); - m_add.Enable( !m_proto->m_disableDefaultServer ); - m_edit.Enable( !m_proto->m_disableDefaultServer ); - m_del.Enable( !m_proto->m_disableDefaultServer ); - m_server.Enable( !m_proto->m_disableDefaultServer ); - m_port.Enable( !m_proto->m_disableDefaultServer ); - m_port2.Enable( !m_proto->m_disableDefaultServer ); - m_pass.Enable( !m_proto->m_disableDefaultServer ); -} - -void CConnectPrefsDlg::OnServerCombo( CCtrlData* ) -{ - int i = m_serverCombo.GetCurSel(); - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - if ( pData && (INT_PTR)pData != CB_ERR ) { - m_server.SetTextA( pData->m_address ); - m_port.SetInt( pData->m_portStart ); - m_port2.SetInt( pData->m_portEnd ); - m_pass.SetTextA( "" ); - - if ( pData->m_iSSL == 0 ) - m_ssl.SetText( TranslateT( "Off" )); - if ( pData->m_iSSL == 1 ) - m_ssl.SetText( TranslateT( "Auto" )); - if ( pData->m_iSSL == 2 ) - m_ssl.SetText( TranslateT( "On" )); - - SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); -} } - -void CConnectPrefsDlg::OnAddServer( CCtrlButton* ) -{ - m_serverCombo.Disable(); - m_add.Disable(); - m_edit.Disable(); - m_del.Disable(); - CServerDlg* dlg = new CServerDlg( m_proto, this, 1 ); - dlg->Show(); -} - -void CConnectPrefsDlg::OnDeleteServer( CCtrlButton* ) -{ - int i = m_serverCombo.GetCurSel(); - if ( i == CB_ERR) - return; - - m_serverCombo.Disable(); - m_add.Disable(); - m_edit.Disable(); - m_del.Disable(); - - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - TCHAR temp[200]; - mir_sntprintf( temp, SIZEOF(temp), TranslateT("Do you want to delete\r\n%s"), (TCHAR*)_A2T(pData->m_name)); - if ( MessageBox( m_hwnd, temp, TranslateT("Delete server"), MB_YESNO | MB_ICONQUESTION ) == IDYES ) { - g_servers.remove( pData ); - - m_serverCombo.DeleteString( i ); - if ( i >= m_serverCombo.GetCount()) - i--; - m_serverCombo.SetCurSel( i ); - OnServerCombo( NULL ); - SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); - m_serverlistModified = true; - } - - m_serverCombo.Enable(); - m_add.Enable(); - m_edit.Enable(); - m_del.Enable(); -} - -void CConnectPrefsDlg::OnEditServer( CCtrlButton* ) -{ - int i = m_serverCombo.GetCurSel(); - if ( i == CB_ERR ) - return; - - m_serverCombo.Disable(); - m_add.Disable(); - m_edit.Disable(); - m_del.Disable(); - CServerDlg* dlg = new CServerDlg( m_proto, this, 2 ); - dlg->Show(); - SetWindowText( dlg->GetHwnd(), TranslateT( "Edit server" )); -} - -void CConnectPrefsDlg::OnStartup( CCtrlData* ) -{ - m_serverCombo.Enable( m_enableServer.GetState()); - m_add.Enable( m_enableServer.GetState()); - m_edit.Enable( m_enableServer.GetState()); - m_del.Enable( m_enableServer.GetState()); - m_server.Enable( m_enableServer.GetState()); - m_port.Enable( m_enableServer.GetState()); - m_port2.Enable( m_enableServer.GetState()); - m_pass.Enable( m_enableServer.GetState()); - m_ssl.Enable( m_enableServer.GetState()); -} - -void CConnectPrefsDlg::OnIdent( CCtrlData* ) -{ - m_identSystem.Enable( m_ident.GetState()); - m_identPort.Enable( m_ident.GetState()); - m_identTimer.Enable( m_ident.GetState()); -} - -void CConnectPrefsDlg::OnUseServer( CCtrlData* ) -{ - EnableWindow(GetDlgItem( m_hwnd, IDC_SHOWSERVER), m_useServer.GetState()); -} - -void CConnectPrefsDlg::OnOnlineNotif( CCtrlData* ) -{ - m_channelAway.Enable( m_onlineNotif.GetState()); - m_onlineTimer.Enable( m_onlineNotif.GetState()); - m_spin1.Enable( m_onlineNotif.GetState()); - m_spin2.Enable( m_onlineNotif.GetState()); - m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); -} - -void CConnectPrefsDlg::OnChannelAway( CCtrlData* ) -{ - m_spin2.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); - m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); -} - -void CConnectPrefsDlg::OnRetry( CCtrlData* ) -{ - m_retryWait.Enable( m_retry.GetState()); - m_retryCount.Enable( m_retry.GetState()); -} - -void CConnectPrefsDlg::OnApply() -{ - //Save the setting in the CONNECT dialog - if(m_enableServer.GetState()) { - m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); - m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); - m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); - m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); - CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); - } - else m_proto->m_serverName[0] = m_proto->m_portStart[0] = m_proto->m_portEnd[0] = m_proto->m_password[0] = 0; - - m_proto->m_onlineNotificationTime = SendDlgItemMessage( m_hwnd,IDC_SPIN1,UDM_GETPOS,0,0); - m_proto->m_onlineNotificationLimit = SendDlgItemMessage( m_hwnd,IDC_SPIN2,UDM_GETPOS,0,0); - m_proto->m_channelAwayNotification = m_channelAway.GetState(); - - m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); - removeSpaces(m_proto->m_nick); - mir_sntprintf(m_proto->m_pNick, SIZEOF(m_proto->m_pNick), _T("%s"), m_proto->m_nick); - m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); - removeSpaces(m_proto->m_alternativeNick); - m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); - removeSpaces(m_proto->m_userID); - m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); - m_identSystem.GetText( m_proto->m_identSystem, SIZEOF(m_proto->m_identSystem)); - m_identPort.GetText( m_proto->m_identPort, SIZEOF(m_proto->m_identPort)); - m_retryWait.GetText( m_proto->m_retryWait, SIZEOF(m_proto->m_retryWait)); - m_retryCount.GetText( m_proto->m_retryCount, SIZEOF(m_proto->m_retryCount)); - m_proto->m_disableDefaultServer = !m_enableServer.GetState(); - m_proto->m_ident = m_ident.GetState(); - m_proto->m_identTimer = m_identTimer.GetState(); - m_proto->m_forceVisible = m_forceVisible.GetState(); - m_proto->m_disableErrorPopups = m_disableError.GetState(); - m_proto->m_rejoinChannels = m_rejoinChannels.GetState(); - m_proto->m_rejoinIfKicked = m_rejoinOnKick.GetState(); - m_proto->m_retry = m_retry.GetState(); - m_proto->m_showAddresses = m_address.GetState(); - m_proto->m_oldStyleModes = m_oldStyle.GetState(); - m_proto->m_useServer = m_useServer.GetState(); - - CLISTMENUITEM clmi; - memset( &clmi, 0, sizeof( clmi )); - clmi.cbSize = sizeof( clmi ); - clmi.flags = CMIM_FLAGS; - if ( !m_proto->m_useServer ) - clmi.flags |= CMIF_GRAYED; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_proto->hMenuServer, ( LPARAM )&clmi ); - - m_proto->m_joinOnInvite = m_autoJoin.GetState(); - m_proto->m_hideServerWindow = !m_showServer.GetState(); - m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); - if ( m_proto->m_sendKeepAlive = m_keepAlive.GetState()) - m_proto->SetChatTimer(m_proto->KeepAliveTimer, 60*1000, KeepAliveTimerProc); - else - m_proto->KillChatTimer(m_proto->KeepAliveTimer); - - m_proto->m_autoOnlineNotification = m_onlineNotif.GetState(); - if ( m_proto->m_autoOnlineNotification ) { - if ( !m_proto->bTempDisableCheck ) { - m_proto->SetChatTimer(m_proto->OnlineNotifTimer, 500, OnlineNotifTimerProc ); - if ( m_proto->m_channelAwayNotification ) - m_proto->SetChatTimer( m_proto->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); - } - } - else if ( !m_proto->bTempForceCheck ) { - m_proto->KillChatTimer( m_proto->OnlineNotifTimer ); - m_proto->KillChatTimer( m_proto->OnlineNotifTimer3 ); - } - - int i = m_serverCombo.GetCurSel(); - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - if ( pData && (INT_PTR)pData != CB_ERR ) { - if ( m_enableServer.GetState()) - lstrcpyA(m_proto->m_network, pData->m_group); - else - lstrcpyA(m_proto->m_network, ""); - m_proto->m_iSSL = pData->m_iSSL; - } - - if ( m_serverlistModified ) { - m_serverlistModified = false; - CallService( MS_DB_MODULE_DELETE, 0, (LPARAM)SERVERSMODULE ); - - int j = m_serverCombo.GetCount(); - if (j != CB_ERR && j != 0) { - for (int index2 = 0; index2 < j; index2++) { - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( index2 ); - if ( pData == NULL || (INT_PTR)pData == CB_ERR ) - continue; - - char TextLine[512]; - if ( pData->m_iSSL > 0 ) - mir_snprintf(TextLine, sizeof(TextLine), "SERVER:SSL%u%s:%d-%dGROUP:%s", pData->m_iSSL, pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); - else - mir_snprintf(TextLine, sizeof(TextLine), "SERVER:%s:%d-%dGROUP:%s", pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); - DBWriteContactSettingString( NULL, SERVERSMODULE, pData->m_name, TextLine ); - - // combobox might contain new items - if ( g_servers.find( pData ) == NULL ) - g_servers.insert( pData ); - } } } - - m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); - - CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'CTCP preferences' dialog - -static TDbSetting CtcpSettings[] = -{ - { FIELD_OFFSET(CIrcProto, m_userInfo ), "UserInfo", DBVT_TCHAR, SIZEOF(pZero->m_userInfo) }, - { FIELD_OFFSET(CIrcProto, m_DCCPacketSize ), "DccPacketSize", DBVT_WORD, 0, 4096 }, - { FIELD_OFFSET(CIrcProto, m_DCCPassive ), "DccPassive", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_DCCMode ), "DCCMode", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_manualHost ), "ManualHost", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_IPFromServer ), "IPFromServer", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_disconnectDCCChats ), "DisconnectDCCChats", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_mySpecifiedHost ), "SpecHost", DBVT_ASCIIZ, SIZEOF(pZero->m_mySpecifiedHost) }, - { FIELD_OFFSET(CIrcProto, m_DCCChatAccept ), "CtcpChatAccept", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_sendNotice ), "SendNotice", DBVT_BYTE, 0, 1 } -}; - -CCtcpPrefsDlg::CCtcpPrefsDlg( CIrcProto* _pro ) : - CProtoDlgBase( _pro, IDD_PREFS_CTCP, NULL ), - m_enableIP( this, IDC_ENABLEIP ), - m_fromServer( this, IDC_FROMSERVER ), - m_combo( this, IDC_COMBO ), - m_slow( this, IDC_SLOW ), - m_fast( this, IDC_FAST ), - m_disc( this, IDC_DISC ), - m_passive( this, IDC_PASSIVE ), - m_sendNotice( this, IDC_SENDNOTICE ), - m_ip( this, IDC_IP ), - m_userInfo( this, IDC_USERINFO), - m_radio1( this, IDC_RADIO1 ), - m_radio2( this, IDC_RADIO2 ), - m_radio3( this, IDC_RADIO3 ) -{ - m_enableIP.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); - m_fromServer.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); -} - -void CCtcpPrefsDlg::OnInitDialog() -{ - m_userInfo.SetText(m_proto->m_userInfo); - - m_slow.SetState( m_proto->m_DCCMode == 0 ); - m_fast.SetState( m_proto->m_DCCMode == 1 ); - m_disc.SetState( m_proto->m_disconnectDCCChats ); - m_passive.SetState( m_proto->m_DCCPassive ); - m_sendNotice.SetState( m_proto->m_sendNotice ); - - m_combo.AddStringA( "256" ); - m_combo.AddStringA( "512" ); - m_combo.AddStringA( "1024" ); - m_combo.AddStringA( "2048" ); - m_combo.AddStringA( "4096" ); - m_combo.AddStringA( "8192" ); - - TCHAR szTemp[10]; - mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u"), m_proto->m_DCCPacketSize ); - int i = m_combo.SelectString( szTemp ); - if ( i == CB_ERR ) - m_combo.SelectString( _T("4096")); - - if ( m_proto->m_DCCChatAccept == 1 ) - m_radio1.SetState( true ); - if ( m_proto->m_DCCChatAccept == 2 ) - m_radio2.SetState( true ); - if ( m_proto->m_DCCChatAccept == 3 ) - m_radio3.SetState( true ); - - m_fromServer.SetState( m_proto->m_IPFromServer ); - m_enableIP.SetState( m_proto->m_manualHost ); - m_ip.Enable( m_proto->m_manualHost ); - m_fromServer.Enable( !m_proto->m_manualHost ); - if (m_proto->m_manualHost) - m_ip.SetTextA( m_proto->m_mySpecifiedHost ); - else { - if ( m_proto->m_IPFromServer ) { - if ( m_proto->m_myHost[0] ) { - CMString s = (CMString)TranslateT("m_myHost) + _T(">"); - m_ip.SetText( s.c_str()); - } - else m_ip.SetText( TranslateT( "" )); - } - else { - if ( m_proto->m_myLocalHost[0] ) { - CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); - m_ip.SetText( s.c_str()); - } - else m_ip.SetText( TranslateT( "" )); -} } } - -void CCtcpPrefsDlg::OnClicked( CCtrlData* ) -{ - m_ip.Enable( m_enableIP.GetState()); - m_fromServer.Enable( !m_enableIP.GetState()); - - if ( m_enableIP.GetState()) - m_ip.SetTextA( m_proto->m_mySpecifiedHost ); - else { - if ( m_fromServer.GetState()) { - if ( m_proto->m_myHost[0] ) { - CMString s = (CMString)TranslateT( "m_myHost) + _T(">"); - m_ip.SetText( s.c_str()); - } - else m_ip.SetText( TranslateT( "" )); - } - else { - if ( m_proto->m_myLocalHost[0] ) { - CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); - m_ip.SetText( s.c_str()); - } - else m_ip.SetText( TranslateT( "" )); -} } } - -void CCtcpPrefsDlg::OnApply() -{ - m_userInfo.GetText( m_proto->m_userInfo, SIZEOF( m_proto->m_userInfo )); - - m_proto->m_DCCPacketSize = m_combo.GetInt(); - m_proto->m_DCCPassive = m_passive.GetState(); - m_proto->m_sendNotice = m_sendNotice.GetState(); - m_proto->m_DCCMode = m_fast.GetState(); - m_proto->m_manualHost = m_enableIP.GetState(); - m_proto->m_IPFromServer = m_fromServer.GetState(); - m_proto->m_disconnectDCCChats = m_disc.GetState(); - - if ( m_enableIP.GetState()) { - char szTemp[500]; - m_ip.GetTextA( szTemp, sizeof( szTemp )); - lstrcpynA(m_proto->m_mySpecifiedHost, GetWord(szTemp, 0).c_str(), 499); - if ( lstrlenA( m_proto->m_mySpecifiedHost )) - m_proto->ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_proto->m_mySpecifiedHost, IP_MANUAL )); - } - else m_proto->m_mySpecifiedHost[0] = 0; - - if ( m_radio1.GetState()) - m_proto->m_DCCChatAccept = 1; - if ( m_radio2.GetState()) - m_proto->m_DCCChatAccept = 2; - if ( m_radio3.GetState()) - m_proto->m_DCCChatAccept = 3; - - m_proto->WriteSettings( CtcpSettings, SIZEOF( CtcpSettings )); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Advanced preferences' dialog - -static TDbSetting OtherSettings[] = -{ - { FIELD_OFFSET(CIrcProto, m_quitMessage ), "QuitMessage", DBVT_TCHAR, SIZEOF(pZero->m_quitMessage) }, - { FIELD_OFFSET(CIrcProto, m_alias ), "Alias", DBVT_TCHAR, -1 }, - { FIELD_OFFSET(CIrcProto, m_codepage ), "Codepage", DBVT_DWORD, 0, CP_ACP }, - { FIELD_OFFSET(CIrcProto, m_utfAutodetect ), "UtfAutodetect", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_perform ), "Perform", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_scriptingEnabled ), "ScriptingEnabled", DBVT_BYTE } -}; - -static char* sttPerformEvents[] = { - "Event: Available", - "Event: Away", - "Event: N/A", - "Event: Occupied", - "Event: DND", - "Event: Free for chat", - "Event: On the phone", - "Event: Out for lunch", - "Event: Disconnect", - "ALL NETWORKS" -}; - -static LRESULT CALLBACK EditSubclassProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch(msg) { - case WM_CHAR : - if (wParam == 21 || wParam == 11 || wParam == 2) { - char w[2]; - w[1] = '\0'; - if (wParam == 11) - w[0] = 3; - if (wParam == 2) - w[0] = 2; - if (wParam == 21) - w[0] = 31; - SendMessage( hwndDlg, EM_REPLACESEL, false, (LPARAM) w); - SendMessage( hwndDlg, EM_SCROLLCARET, 0,0); - return 0; - } - break; - } - - return CallWindowProc(OldProc, hwndDlg, msg, wParam, lParam); -} - -COtherPrefsDlg::COtherPrefsDlg( CIrcProto* _pro ) : - CProtoDlgBase( _pro, IDD_PREFS_OTHER, NULL ), - m_url( this, IDC_CUSTOM ), - m_performCombo( this, IDC_PERFORMCOMBO ), - m_codepage( this, IDC_CODEPAGE ), - m_pertormEdit( this, IDC_PERFORMEDIT ), - m_perform( this, IDC_PERFORM ), - m_scripting( this, IDC_SCRIPT ), - m_autodetect( this, IDC_UTF_AUTODETECT ), - m_quitMessage( this, IDC_QUITMESSAGE ), - m_alias( this, IDC_ALIASEDIT ), - m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Click to set commands that will be performed for this event")), - m_delete( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Click to delete the commands for this event")), - m_performlistModified( false ) -{ - m_url.OnClick = Callback( this, &COtherPrefsDlg::OnUrl ); - m_performCombo.OnChange = Callback( this, &COtherPrefsDlg::OnPerformCombo ); - m_codepage.OnChange = Callback( this, &COtherPrefsDlg::OnCodePage ); - m_pertormEdit.OnChange = Callback( this, &COtherPrefsDlg::OnPerformEdit ); - m_perform.OnChange = Callback( this, &COtherPrefsDlg::OnPerform ); - m_add.OnClick = Callback( this, &COtherPrefsDlg::OnAdd ); - m_delete.OnClick = Callback( this, &COtherPrefsDlg::OnDelete ); -} - -void COtherPrefsDlg::OnInitDialog() -{ - OldProc = (WNDPROC)SetWindowLongPtr( m_alias.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); - SetWindowLongPtr( m_quitMessage.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); - SetWindowLongPtr( m_pertormEdit.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); - - m_alias.SetText( m_proto->m_alias ); - m_quitMessage.SetText( m_proto->m_quitMessage ); - m_perform.SetState( m_proto->m_perform ); - m_scripting.SetState( m_proto->m_scriptingEnabled ); - m_scripting.Enable( m_bMbotInstalled ); - m_performCombo.Enable( m_proto->m_perform ); - m_pertormEdit.Enable( m_proto->m_perform ); - m_add.Enable( m_proto->m_perform ); - m_delete.Enable( m_proto->m_perform ); - - fnGetCPInfoEx = ( pfnGetCPInfoEx )GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetCPInfoExW" ); - - m_codepage.AddString( TranslateT("Default ANSI codepage"), CP_ACP ); - if ( fnGetCPInfoEx == NULL ) - m_codepage.AddString( TranslateT("UTF-8"), CP_UTF8 ); - - sttCombo = &m_codepage; - EnumSystemCodePagesA(sttLangAddCallback, CP_INSTALLED); - - int i; - for ( i = m_codepage.GetCount(); i >= 0; i-- ) { - if ( m_codepage.GetItemData( i ) == m_proto->getCodepage()) { - m_codepage.SetCurSel( i ); - break; - } } - - - if ( m_proto->m_codepage == CP_UTF8 ) - m_autodetect.Disable(); - - for ( i=0; i < g_servers.getCount(); i++ ) { - SERVER_INFO& si = g_servers[i]; - int idx = m_performCombo.FindStringA( si.m_group, -1, true ); - if ( idx == CB_ERR ) { - idx = m_performCombo.AddStringA( si.m_group ); - addPerformComboValue( idx, si.m_group ); - } } - - for ( i=0; i < SIZEOF(sttPerformEvents); i++ ) { - int idx = m_performCombo.InsertString( _A2T( sttPerformEvents[i] ), i ); - addPerformComboValue( idx, sttPerformEvents[i] ); - } - - m_performCombo.SetCurSel( 0 ); - OnPerformCombo( NULL ); - m_autodetect.SetState( m_proto->m_utfAutodetect ); -} - -void COtherPrefsDlg::OnUrl( CCtrlButton* ) -{ - CallService( MS_UTILS_OPENURL,0,(LPARAM) "http://members.chello.se/matrix/index.html" ); -} - -void COtherPrefsDlg::OnPerformCombo( CCtrlData* ) -{ - int i = m_performCombo.GetCurSel(); - PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); - if (pPerf == 0) - m_pertormEdit.SetTextA( "" ); - else - m_pertormEdit.SetText( pPerf->mText.c_str()); - m_add.Disable(); - if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) - m_delete.Enable(); - else - m_delete.Disable(); -} - -void COtherPrefsDlg::OnCodePage( CCtrlData* ) -{ - int curSel = m_codepage.GetCurSel(); - m_autodetect.Enable( m_codepage.GetItemData(curSel) != CP_UTF8 ); -} - -void COtherPrefsDlg::OnPerformEdit( CCtrlData* ) -{ - m_add.Enable(); - - if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) - m_delete.Enable(); - else - m_delete.Disable(); -} - -void COtherPrefsDlg::OnPerform( CCtrlData* ) -{ - m_performCombo.Enable( m_perform.GetState()); - m_pertormEdit.Enable( m_perform.GetState()); - m_add.Enable( m_perform.GetState()); - m_delete.Enable( m_perform.GetState()); -} - -void COtherPrefsDlg::OnAdd( CCtrlButton* ) -{ - TCHAR* temp = m_pertormEdit.GetText(); - - if ( my_strstri( temp, _T("/away"))) - MessageBox( NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); - else { - int i = m_performCombo.GetCurSel(); - if ( i != CB_ERR ) { - PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); - if ( pPerf != NULL ) - pPerf->mText = temp; - - m_add.Disable(); - m_performlistModified = true; - } } - mir_free( temp ); -} - -void COtherPrefsDlg::OnDelete( CCtrlButton* ) -{ - int i = m_performCombo.GetCurSel(); - if ( i != CB_ERR ) { - PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); - if ( pPerf != NULL ) { - pPerf->mText = _T(""); - m_pertormEdit.SetTextA( "" ); - m_delete.Disable(); - m_add.Disable(); - } - - m_performlistModified = true; -} } - -void COtherPrefsDlg::OnDestroy() -{ - int i = m_performCombo.GetCount(); - if ( i != CB_ERR && i != 0 ) { - for (int index = 0; index < i; index++) { - PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( index ); - if (( INT_PTR )pPerf != CB_ERR && pPerf != NULL ) - delete pPerf; -} } } - -void COtherPrefsDlg::OnApply() -{ - mir_free( m_proto->m_alias ); - m_proto->m_alias = m_alias.GetText(); - m_quitMessage.GetText( m_proto->m_quitMessage, SIZEOF( m_proto->m_quitMessage )); - - int curSel = m_codepage.GetCurSel(); - m_proto->m_codepage = m_codepage.GetItemData( curSel ); - if ( m_proto->IsConnected()) - m_proto->setCodepage( m_proto->m_codepage ); - - m_proto->m_utfAutodetect = m_autodetect.GetState(); - m_proto->m_perform = m_perform.GetState(); - m_proto->m_scriptingEnabled = m_scripting.GetState(); - if ( m_add.Enabled()) - OnAdd( NULL ); - - if ( m_performlistModified ) { - int count = m_performCombo.GetCount(); - for ( int i = 0; i < count; i++ ) { - PERFORM_INFO* pPerf = ( PERFORM_INFO* )m_performCombo.GetItemData( i ); - if (( INT_PTR )pPerf == CB_ERR ) - continue; - - if ( !pPerf->mText.IsEmpty()) - m_proto->setTString( pPerf->mSetting.c_str(), pPerf->mText.c_str()); - else - DBDeleteContactSetting( NULL, m_proto->m_szModuleName, pPerf->mSetting.c_str()); - } } - m_proto->WriteSettings( OtherSettings, SIZEOF( OtherSettings )); -} - -void COtherPrefsDlg::addPerformComboValue( int idx, const char* szValueName ) -{ - String sSetting = String("PERFORM:") + szValueName; - sSetting.MakeUpper(); - - PERFORM_INFO* pPref; - DBVARIANT dbv; - if ( !m_proto->getTString( sSetting.c_str(), &dbv )) { - pPref = new PERFORM_INFO( sSetting.c_str(), dbv.ptszVal ); - DBFreeVariant( &dbv ); - } - else pPref = new PERFORM_INFO( sSetting.c_str(), _T("")); - m_performCombo.SetItemData( idx, ( LPARAM )pPref ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'add ignore' preferences dialog - -CAddIgnoreDlg::CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* _owner ) : - CProtoDlgBase( _pro, IDD_ADDIGNORE, _owner->GetHwnd()), - m_Ok( this, IDOK ), - m_owner( _owner ) -{ - if ( mask == NULL ) - szOldMask[0] = 0; - else - _tcsncpy( szOldMask, mask, SIZEOF(szOldMask)); - - m_Ok.OnClick = Callback( this, &CAddIgnoreDlg::OnOk ); -} - -void CAddIgnoreDlg::OnInitDialog() -{ - if ( szOldMask[0] == 0 ) { - if ( m_proto->IsConnected()) - SetWindowText(GetDlgItem( m_hwnd, IDC_NETWORK), m_proto->m_info.sNetwork.c_str()); - CheckDlgButton( m_hwnd, IDC_Q, BST_CHECKED); - CheckDlgButton( m_hwnd, IDC_N, BST_CHECKED); - CheckDlgButton( m_hwnd, IDC_I, BST_CHECKED); - CheckDlgButton( m_hwnd, IDC_D, BST_CHECKED); - CheckDlgButton( m_hwnd, IDC_C, BST_CHECKED); -} } - -void CAddIgnoreDlg::OnOk( CCtrlButton* ) -{ - TCHAR szMask[500]; - TCHAR szNetwork[500]; - CMString flags; - if ( IsDlgButtonChecked( m_hwnd, IDC_Q ) == BST_CHECKED ) flags += 'q'; - if ( IsDlgButtonChecked( m_hwnd, IDC_N ) == BST_CHECKED ) flags += 'n'; - if ( IsDlgButtonChecked( m_hwnd, IDC_I ) == BST_CHECKED ) flags += 'i'; - if ( IsDlgButtonChecked( m_hwnd, IDC_D ) == BST_CHECKED ) flags += 'd'; - if ( IsDlgButtonChecked( m_hwnd, IDC_C ) == BST_CHECKED ) flags += 'c'; - if ( IsDlgButtonChecked( m_hwnd, IDC_M ) == BST_CHECKED ) flags += 'm'; - - GetWindowText( GetDlgItem( m_hwnd, IDC_MASK), szMask, SIZEOF(szMask)); - GetWindowText( GetDlgItem( m_hwnd, IDC_NETWORK), szNetwork, SIZEOF(szNetwork)); - - CMString Mask = GetWord(szMask, 0); - if ( Mask.GetLength() != 0 ) { - if ( !_tcschr(Mask.c_str(), '!') && !_tcschr(Mask.c_str(), '@')) - Mask += _T("!*@*"); - - if ( !flags.IsEmpty()) { - if ( *szOldMask ) - m_proto->RemoveIgnore( szOldMask ); - m_proto->AddIgnore(Mask.c_str(), flags.c_str(), szNetwork); -} } } - -void CAddIgnoreDlg::OnClose() -{ - m_owner->FixButtons(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Ignore' preferences dialog - -static TDbSetting IgnoreSettings[] = -{ - { FIELD_OFFSET(CIrcProto, m_DCCFileEnabled ), "EnableCtcpFile", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_DCCChatEnabled ), "EnableCtcpChat", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_DCCChatIgnore), "CtcpChatIgnore", DBVT_BYTE, 0, 1 }, - { FIELD_OFFSET(CIrcProto, m_ignore ), "Ignore", DBVT_BYTE }, - { FIELD_OFFSET(CIrcProto, m_ignoreChannelDefault ), "IgnoreChannelDefault", DBVT_BYTE }, -}; - -static int CALLBACK IgnoreListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - CIgnorePrefsDlg* hwndDlg = ( CIgnorePrefsDlg* )lParamSort; - if ( !hwndDlg->GetHwnd()) - return 1; - - TCHAR temp1[512]; - TCHAR temp2[512]; - - LVITEM lvm; - lvm.mask = LVIF_TEXT; - lvm.iSubItem = 0; - lvm.cchTextMax = SIZEOF(temp1); - - lvm.iItem = lParam1; - lvm.pszText = temp1; - hwndDlg->m_list.GetItem( &lvm ); - - lvm.iItem = lParam2; - lvm.pszText = temp2; - hwndDlg->m_list.GetItem( &lvm ); - - if ( temp1[0] && temp2[0] ) - return lstrcmpi( temp1, temp2 ); - - return ( temp1[0] == 0 ) ? 1 : -1; -} - -static LRESULT CALLBACK ListviewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_KEYUP : - if ( ListView_GetSelectionMark(GetDlgItem(GetParent(hwnd), IDC_LIST)) != -1) { - EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), true); - EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), true); - } - else { - EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), false); - EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), false); - } - - if (wParam == VK_DELETE) - SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_DELETE, BN_CLICKED), 0); - - if (wParam == VK_SPACE) - SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_EDIT, BN_CLICKED), 0); - break; - } - - return CallWindowProc(OldListViewProc, hwnd, msg, wParam, lParam); -} - -// Callback for the 'Add ignore' dialog - -void CIrcProto::InitIgnore( void ) -{ - TCHAR szTemp[ MAX_PATH ]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_ignore.ini"), m_szModuleName); - TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); - char* pszIgnoreData = IrcLoadFile(szLoadFileName); - if ( pszIgnoreData != NULL ) { - char *p1 = pszIgnoreData; - while ( *p1 != '\0' ) { - while ( *p1 == '\r' || *p1 == '\n' ) - p1++; - if ( *p1 == '\0' ) - break; - - char* p2 = strstr( p1, "\r\n" ); - if ( !p2 ) - p2 = strchr( p1, '\0' ); - - char* pTemp = p2; - while ( pTemp > p1 && (*pTemp == '\r' || *pTemp == '\n' ||*pTemp == '\0' || *pTemp == ' ' )) - pTemp--; - *++pTemp = 0; - - String mask = GetWord(p1, 0); - String flags = GetWord(p1, 1); - String network = GetWord(p1, 2); - if ( !mask.IsEmpty()) - m_ignoreItems.insert( new CIrcIgnoreItem( getCodepage(), mask.c_str(), flags.c_str(), network.c_str())); - - p1 = p2; - } - - RewriteIgnoreSettings(); - delete[] pszIgnoreData; - ::_tremove( szLoadFileName ); - } - mir_free( szLoadFileName ); - - int idx = 0; - char settingName[40]; - for ( ;; ) { - mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", idx++ ); - - DBVARIANT dbv; - if ( getTString( settingName, &dbv )) - break; - - CMString mask = GetWord( dbv.ptszVal, 0 ); - CMString flags = GetWord( dbv.ptszVal, 1 ); - CMString network = GetWord( dbv.ptszVal, 2 ); - m_ignoreItems.insert( new CIrcIgnoreItem( mask.c_str(), flags.c_str(), network.c_str())); - DBFreeVariant( &dbv ); -} } - -void CIrcProto::RewriteIgnoreSettings( void ) -{ - char settingName[ 40 ]; - - int i=0; - for ( ;; ) { - mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i++ ); - if ( DBDeleteContactSetting( NULL, m_szModuleName, settingName )) - break; - } - - for ( i=0; i < m_ignoreItems.getCount(); i++ ) { - mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i ); - - CIrcIgnoreItem& C = m_ignoreItems[i]; - setTString( settingName, ( C.mask + _T(" ") + C.flags + _T(" ") + C.network ).c_str()); -} } - -CIgnorePrefsDlg::CIgnorePrefsDlg( CIrcProto* _pro ) : - CProtoDlgBase( _pro, IDD_PREFS_IGNORE, NULL ), - m_list( this, IDC_LIST ), - m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add new ignore")), - m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit this ignore")), - m_del( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Delete this ignore")), - m_enable( this, IDC_ENABLEIGNORE ), - m_ignoreChat( this, IDC_IGNORECHAT ), - m_ignoreFile( this, IDC_IGNOREFILE ), - m_ignoreChannel( this, IDC_IGNORECHANNEL ), - m_ignoreUnknown( this, IDC_IGNOREUNKNOWN ) -{ - m_enable.OnChange = Callback( this, &CIgnorePrefsDlg::OnEnableIgnore ); - m_ignoreChat.OnChange = Callback( this, &CIgnorePrefsDlg::OnIgnoreChat ); - m_add.OnClick = Callback( this, &CIgnorePrefsDlg::OnAdd ); - m_list.OnDoubleClick = m_edit.OnClick = Callback( this, &CIgnorePrefsDlg::OnEdit ); - m_del.OnClick = Callback( this, &CIgnorePrefsDlg::OnDelete ); - m_list.OnColumnClick = Callback( this, &CIgnorePrefsDlg::List_OnColumnClick ); -} - -void CIgnorePrefsDlg::OnInitDialog() -{ - m_proto->m_ignoreDlg = this; - OldListViewProc = (WNDPROC)SetWindowLongPtr( m_list.GetHwnd(),GWLP_WNDPROC, (LONG_PTR)ListviewSubclassProc ); - - m_enable.SetState( m_proto->m_ignore ); - m_ignoreFile.SetState( !m_proto->m_DCCFileEnabled ); - m_ignoreChat.SetState( !m_proto->m_DCCChatEnabled ); - m_ignoreChannel.SetState( m_proto->m_ignoreChannelDefault ); - if ( m_proto->m_DCCChatIgnore == 2 ) - m_ignoreUnknown.SetState( BST_CHECKED ); - - m_ignoreUnknown.Enable( m_proto->m_DCCChatEnabled ); - m_list.Enable( m_proto->m_ignore ); - m_ignoreChannel.Enable( m_proto->m_ignore); - m_add.Enable( m_proto->m_ignore ); - - static int COLUMNS_SIZES[3] = {195, 60, 80}; - LV_COLUMN lvC; - lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - lvC.fmt = LVCFMT_LEFT; - for ( int index=0; index < 3; index++ ) { - lvC.iSubItem = index; - lvC.cx = COLUMNS_SIZES[index]; - - TCHAR* text = NULL; - switch (index) { - case 0: text = TranslateT("Ignore mask"); break; - case 1: text = TranslateT("Flags"); break; - case 2: text = TranslateT("Network"); break; - } - lvC.pszText = text; - ListView_InsertColumn(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW),index,&lvC); - } - - ListView_SetExtendedListViewStyle(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW), LVS_EX_FULLROWSELECT); - RebuildList(); -} - -INT_PTR CIgnorePrefsDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch( msg ) { - case WM_NOTIFY: - switch(((LPNMHDR)lParam)->idFrom) { - case IDC_LIST: - switch (((NMHDR*)lParam)->code) { - case NM_CLICK: - case NM_RCLICK: - if ( m_list.GetSelectionMark() != -1 ) - FixButtons(); - break; - } } - break; - } - return CDlgBase::DlgProc(msg, wParam, lParam); -} - -void CIgnorePrefsDlg::OnEnableIgnore( CCtrlData* ) -{ - m_ignoreChannel.Enable( m_enable.GetState()); - m_list.Enable( m_enable.GetState()); - m_add.Enable( m_enable.GetState()); -} - -void CIgnorePrefsDlg::OnIgnoreChat( CCtrlData* ) -{ - m_ignoreUnknown.Enable( m_ignoreChat.GetState() == BST_UNCHECKED ); -} - -void CIgnorePrefsDlg::OnAdd( CCtrlButton* ) -{ - CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, NULL, this ); - dlg->Show(); - SetWindowText( dlg->GetHwnd(), TranslateT( "Add ignore" )); - m_add.Disable(); - m_edit.Disable(); - m_del.Disable(); -} - -void CIgnorePrefsDlg::OnEdit( CCtrlButton* ) -{ - if ( !m_add.Enabled()) - return; - - TCHAR szMask[512]; - TCHAR szFlags[512]; - TCHAR szNetwork[512]; - int i = m_list.GetSelectionMark(); - m_list.GetItemText( i, 0, szMask, 511 ); - m_list.GetItemText( i, 1, szFlags, 511 ); - m_list.GetItemText( i, 2, szNetwork, 511 ); - CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, szMask, this ); - dlg->Show(); - HWND hWnd = dlg->GetHwnd(); - SetWindowText(hWnd, TranslateT("Edit ignore")); - if ( szFlags[0] ) { - if ( _tcschr(szFlags, 'q')) - CheckDlgButton(hWnd, IDC_Q, BST_CHECKED); - if ( _tcschr(szFlags, 'n')) - CheckDlgButton(hWnd, IDC_N, BST_CHECKED); - if ( _tcschr(szFlags, 'i')) - CheckDlgButton(hWnd, IDC_I, BST_CHECKED); - if ( _tcschr(szFlags, 'd')) - CheckDlgButton(hWnd, IDC_D, BST_CHECKED); - if ( _tcschr(szFlags, 'c')) - CheckDlgButton(hWnd, IDC_C, BST_CHECKED); - if ( _tcschr(szFlags, 'm')) - CheckDlgButton(hWnd, IDC_M, BST_CHECKED); - } - SetWindowText(GetDlgItem(hWnd, IDC_MASK), szMask); - SetWindowText(GetDlgItem(hWnd, IDC_NETWORK), szNetwork); - m_add.Disable(); - m_edit.Disable(); - m_del.Disable(); -} - -void CIgnorePrefsDlg::OnDelete( CCtrlButton* ) -{ - if ( !m_del.Enabled()) - return; - - TCHAR szMask[512]; - int i = m_list.GetSelectionMark(); - m_list.GetItemText( i, 0, szMask, SIZEOF(szMask)); - m_proto->RemoveIgnore( szMask ); -} - -void CIgnorePrefsDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ) -{ - m_list.SortItems( IgnoreListSort, (LPARAM)this ); - UpdateList(); -} - -void CIgnorePrefsDlg::OnApply() -{ - m_proto->m_DCCFileEnabled = !m_ignoreFile.GetState(); - m_proto->m_DCCChatEnabled = !m_ignoreChat.GetState(); - m_proto->m_ignore = m_enable.GetState(); - m_proto->m_ignoreChannelDefault = m_ignoreChannel.GetState(); - m_proto->m_DCCChatIgnore = m_ignoreUnknown.GetState() ? 2 : 1; - m_proto->WriteSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); -} - -void CIgnorePrefsDlg::OnDestroy() -{ - m_proto->m_ignoreDlg = NULL; - m_proto->m_ignoreItems.destroy(); - - int i = m_list.GetItemCount(); - for ( int j = 0; j < i; j++ ) { - TCHAR szMask[512], szFlags[40], szNetwork[100]; - m_list.GetItemText( j, 0, szMask, SIZEOF(szMask)); - m_list.GetItemText( j, 1, szFlags, SIZEOF(szFlags)); - m_list.GetItemText( j, 2, szNetwork, SIZEOF(szNetwork)); - m_proto->m_ignoreItems.insert( new CIrcIgnoreItem( szMask, szFlags, szNetwork )); - } - - m_proto->RewriteIgnoreSettings(); - SetWindowLongPtr( m_list.GetHwnd(), GWLP_WNDPROC, (LONG_PTR)OldListViewProc ); -} - -void CIgnorePrefsDlg::FixButtons() -{ - m_add.Enable( m_enable.GetState()); - if ( m_list.GetSelectionMark() != -1 ) { - m_edit.Enable(); - m_del.Enable(); - } - else { - m_edit.Disable(); - m_del.Disable(); -} } - -void CIgnorePrefsDlg::RebuildList() -{ - m_list.DeleteAllItems(); - - for ( int i=0; i < m_proto->m_ignoreItems.getCount(); i++ ) { - CIrcIgnoreItem& C = m_proto->m_ignoreItems[i]; - if ( C.mask.IsEmpty() || C.flags[0] != '+' ) - continue; - - LVITEM lvItem; - lvItem.iItem = m_list.GetItemCount(); - lvItem.mask = LVIF_TEXT|LVIF_PARAM ; - lvItem.iSubItem = 0; - lvItem.lParam = lvItem.iItem; - lvItem.pszText = (TCHAR*)C.mask.c_str(); - lvItem.iItem = m_list.InsertItem( &lvItem ); - - lvItem.mask = LVIF_TEXT; - lvItem.iSubItem = 1; - lvItem.pszText = (TCHAR*)C.flags.c_str(); - m_list.SetItem( &lvItem ); - - lvItem.mask = LVIF_TEXT; - lvItem.iSubItem =2; - lvItem.pszText = (TCHAR*)C.network.c_str(); - m_list.SetItem( &lvItem ); - } - - UpdateList(); - m_list.SortItems( IgnoreListSort, ( LPARAM )this ); - UpdateList(); - - FixButtons(); -} - -void CIgnorePrefsDlg::UpdateList() -{ - int j = m_list.GetItemCount(); - if (j > 0 ) { - LVITEM lvm; - lvm.mask= LVIF_PARAM; - lvm.iSubItem = 0; - for ( int i =0; i < j; i++) { - lvm.iItem = i; - lvm.lParam = i; - m_list.SetItem( &lvm ); -} } } - -///////////////////////////////////////////////////////////////////////////////////////// - -int CIrcProto::OnInitOptionsPages(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = { 0 }; - - odp.cbSize = sizeof(odp); - odp.hInstance = hInst; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CONNECT); - odp.ptszTitle = m_tszUserName; - odp.ptszGroup = LPGENT("Network"); - odp.ptszTab = LPGENT("Account"); - odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; - odp.pfnDlgProc = CDlgBase::DynamicDlgProc; - odp.dwInitParam = (LPARAM)&OptCreateAccount; - OptCreateAccount.create = CConnectPrefsDlg::Create; - OptCreateAccount.param = this; - Options_AddPage(wParam, &odp); - - odp.flags |= ODPF_EXPERTONLY; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CTCP); - odp.ptszTab = LPGENT("DCC'n CTCP"); - odp.dwInitParam = (LPARAM)&OptCreateConn; - OptCreateConn.create = CCtcpPrefsDlg::Create; - OptCreateConn.param = this; - Options_AddPage(wParam, &odp); - - odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_OTHER); - odp.ptszTab = LPGENT("Advanced"); - odp.dwInitParam = (LPARAM)&OptCreateOther; - OptCreateOther.create = COtherPrefsDlg::Create; - OptCreateOther.param = this; - Options_AddPage(wParam, &odp); - - odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_IGNORE); - odp.ptszTab = LPGENT("Ignore"); - odp.dwInitParam = (LPARAM)&OptCreateIgnore; - OptCreateIgnore.create = CIgnorePrefsDlg::Create; - OptCreateIgnore.param = this; - Options_AddPage(wParam, &odp); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CIrcProto::InitPrefs(void) -{ - ConnectSettings[0].defStr = _T("Miranda"); - ConnectSettings[1].defStr = _T("UNIX"); - ConnectSettings[2].defStr = _T("113"); - ConnectSettings[3].defStr = _T("30"); - ConnectSettings[4].defStr = _T("10"); - - CtcpSettings[0].defStr = _T(STR_USERINFO); - - OtherSettings[0].defStr = _T(STR_QUITMESSAGE); - - ReadSettings( ConnectSettings, SIZEOF( ConnectSettings )); - ReadSettings( CtcpSettings, SIZEOF( CtcpSettings )); - ReadSettings( OtherSettings, SIZEOF( OtherSettings )); - ReadSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); - - CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_password); - - int x = getDword( "SizeOfListBottom", -1 ); - if ( x != -1 ) { - DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListBottom" ); - setDword( "channelList_height", x ); - } - if (( x = getDword( "SizeOfListWidth", -1 )) != -1 ) { - DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListWidth" ); - setDword( "channelList_width", x ); - } - - if ( m_pNick[0] == 0 ) { - if ( m_nick[0] != 0 ) { - memcpy( m_pNick, m_nick, sizeof( m_pNick )); - setTString("PNick", m_nick); - } - } - else { - memcpy( m_nick, m_pNick, sizeof( m_nick )); - setTString("Nick", m_nick); - } - - m_mySpecifiedHostIP[0] = 0; - - if ( m_alias == NULL ) - m_alias = mir_tstrdup( _T("/op /mode ## +ooo $1 $2 $3\r\n/dop /mode ## -ooo $1 $2 $3\r\n/voice /mode ## +vvv $1 $2 $3\r\n/dvoice /mode ## -vvv $1 $2 $3\r\n/j /join #$1 $2-\r\n/p /part ## $1-\r\n/w /whois $1\r\n/k /kick ## $1 $2-\r\n/q /query $1\r\n/logon /log on ##\r\n/logoff /log off ##\r\n/save /log buffer $1\r\n/slap /me slaps $1 around a bit with a large trout" )); - - m_quickComboSelection = getDword( "QuickComboSelection", m_serverComboSelection + 1); - m_myHost[0] = '\0'; - - colors[0] = RGB(255,255,255); - colors[1] = RGB(0,0,0); - colors[2] = RGB(0,0,127); - colors[3] = RGB(0,147,0); - colors[4] = RGB(255,0,0); - colors[5] = RGB(127,0,0); - colors[6] = RGB(156,0,156); - colors[7] = RGB(252,127,0); - colors[8] = RGB(255,255,0); - colors[9] = RGB(0,252,0); - colors[10] = RGB(0,147,147); - colors[11] = RGB(0,255,255); - colors[12] = RGB(0,0,252); - colors[13] = RGB(255,0,255); - colors[14] = RGB(127,127,127); - colors[15] = RGB(210,210,210); -} - -/////////////////////////////////////////////////////////////////////////////// -// Account manager UI - -struct CDlgAccMgrUI : public CProtoDlgBase -{ - CCtrlCombo m_serverCombo; - CCtrlEdit m_server, m_port, m_port2, m_pass, m_nick, m_nick2, m_name, m_userID, m_ssl; - - CDlgAccMgrUI( CIrcProto* _pro, HWND _owner ) : - CProtoDlgBase( _pro, IDD_ACCMGRUI, _owner ), - m_serverCombo( this, IDC_SERVERCOMBO ), - m_server( this, IDC_SERVER ), - m_port( this, IDC_PORT ), - m_port2( this, IDC_PORT2 ), - m_pass( this, IDC_PASS ), - m_nick( this, IDC_NICK ), - m_nick2( this, IDC_NICK2 ), - m_name( this, IDC_NAME ), - m_ssl( this, IDC_SSL ), - m_userID( this, IDC_USERID ) - { - m_serverCombo.OnChange = Callback( this, &CDlgAccMgrUI::OnChangeCombo ); - } - - virtual void OnInitDialog() - { - for ( int i=0; i < g_servers.getCount(); i++ ) { - SERVER_INFO& si = g_servers[i]; - m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); - } - m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); - m_server.SetTextA( m_proto->m_serverName ); - m_port.SetTextA( m_proto->m_portStart ); - m_port2.SetTextA( m_proto->m_portEnd ); - m_pass.SetTextA( m_proto->m_password); - switch ( m_proto->m_iSSL ) { - case 0: m_ssl.SetTextA( "Off" ); break; - case 1: m_ssl.SetTextA( "Auto" ); break; - case 2: m_ssl.SetTextA( "On" ); break; - } - - m_nick.SetText( m_proto->m_nick); - m_nick2.SetText( m_proto->m_alternativeNick ); - m_userID.SetText( m_proto->m_userID); - m_name.SetText( m_proto->m_name); - } - - virtual void OnApply() - { - m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); - m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); - m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); - m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); - m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); - CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); - - m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); - removeSpaces(m_proto->m_nick); - mir_sntprintf(m_proto->m_pNick, 30, _T("%s"), m_proto->m_nick); - m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); - removeSpaces(m_proto->m_alternativeNick); - m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); - removeSpaces(m_proto->m_userID); - m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); - m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); - CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); - } - - void OnChangeCombo( CCtrlCombo* ) - { - int i = m_serverCombo.GetCurSel(); - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - if ( pData && (INT_PTR)pData != CB_ERR ) { - m_server.SetTextA( pData->m_address ); - m_port.SetInt( pData->m_portStart ); - m_port2.SetInt( pData->m_portEnd ); - m_pass.SetTextA( "" ); - switch ( pData->m_iSSL ) { - case 0: m_ssl.SetTextA( "Off" ); break; - case 1: m_ssl.SetTextA( "Auto" ); break; - case 2: m_ssl.SetTextA( "On" ); break; - } } } -}; - -INT_PTR CIrcProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) -{ - CDlgAccMgrUI *dlg = new CDlgAccMgrUI(this, (HWND)lParam); - dlg->Show(); - return (INT_PTR)dlg->GetHwnd(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Initialize servers list - -static void sttImportIni( const TCHAR* szIniFile ) -{ - FILE* serverFile = _tfopen( szIniFile, _T("r")); - if ( serverFile == NULL ) - return; - - char buf1[ 500 ], buf2[ 200 ]; - while ( fgets( buf1, sizeof( buf1 ), serverFile )) { - char* p = strchr( buf1, '=' ); - if ( !p ) - continue; - - p++; - rtrim( p ); - char* p1 = strstr( p, "SERVER:" ); - if ( !p1 ) - continue; - - memcpy( buf2, p, int(p1-p)); - buf2[ int(p1-p) ] = 0; - DBWriteContactSettingString( NULL, SERVERSMODULE, buf2, p1 ); - } - fclose( serverFile ); - ::_tremove( szIniFile ); -} - -void InitServers() -{ - TCHAR *szTemp = Utils_ReplaceVarsT(_T("%miranda_path%\\Plugins\\IRC_servers.ini")); - sttImportIni( szTemp ); - mir_free( szTemp ); - - RereadServers(); - - if ( g_servers.getCount() == 0 ) { - TCHAR *szIniFile = Utils_ReplaceVarsT(_T("%temp%\\default_servers.ini")); - FILE *serverFile = _tfopen( szIniFile, _T("a")); - if (serverFile) { - char* pszSvrs = ( char* )LockResource(LoadResource(hInst,FindResource(hInst,MAKEINTRESOURCE(IDR_SERVERS),_T("TEXT")))); - if (pszSvrs) - fwrite(pszSvrs , 1 , lstrlenA(pszSvrs) + 1 , serverFile ); - fclose(serverFile); - - sttImportIni( szIniFile ); - RereadServers(); - } - mir_free(szIniFile); - } -} diff --git a/protocols/IRCG/output.cpp b/protocols/IRCG/output.cpp deleted file mode 100644 index 6a97f45baf..0000000000 --- a/protocols/IRCG/output.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -static CMString FormatOutput (const CIrcMessage* pmsg) -{ - CMString sMessage; - - if ( pmsg->m_bIncoming ) { // Is it an incoming message? - if ( pmsg->sCommand == _T("WALLOPS") && pmsg->parameters.getCount() > 0 ) { - TCHAR temp[200]; *temp = '\0'; - mir_sntprintf(temp, SIZEOF(temp), TranslateT("WallOps from %s: "), pmsg->prefix.sNick.c_str()); - sMessage = temp; - for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) { - sMessage += pmsg->parameters[i]; - if (i != pmsg->parameters.getCount()-1) - sMessage += _T(" "); - } - goto THE_END; - } - - if ( pmsg->sCommand == _T("INVITE") && pmsg->parameters.getCount() > 1 ) { - TCHAR temp[256]; *temp = '\0'; - mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s invites you to %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); - sMessage = temp; - for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { - sMessage += _T(": ") + pmsg->parameters[i]; - if ( i != pmsg->parameters.getCount()-1 ) - sMessage += _T(" "); - } - goto THE_END; - } - - int index = StrToInt( pmsg->sCommand.c_str()); - if ( index == 301 && pmsg->parameters.getCount() > 0 ) { - TCHAR temp[500]; *temp = '\0'; - mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is away"), pmsg->parameters[1].c_str()); - sMessage = temp; - for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { - sMessage += _T(": ") + pmsg->parameters[i]; - if ( i != pmsg->parameters.getCount()-1 ) - sMessage += _T(" "); - } - goto THE_END; - } - - if (( index == 443 || index == 441 ) && pmsg->parameters.getCount() > 3 ) - return pmsg->parameters[1] + _T(" ") + pmsg->parameters[3] + _T(": ") + pmsg->parameters[2]; - - if ( index == 303 ) { // ISON command - sMessage = TranslateT("These are online: "); - for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { - sMessage += pmsg->parameters[i]; - if (i != pmsg->parameters.getCount()-1) - sMessage += _T(", "); - } - goto THE_END; - } - - if (( index > 400 || index < 500) && pmsg->parameters.getCount() > 2 && pmsg->sCommand[0] == '4' ) //all error messages - return pmsg->parameters[2] + _T(": ") + pmsg->parameters[1]; - } - else if ( pmsg->sCommand == _T("NOTICE") && pmsg->parameters.getCount() > 1 ) { - TCHAR temp[500]; *temp = '\0'; - - int l = pmsg->parameters[1].GetLength(); - if ( l > 3 && pmsg->parameters[1][0] == 1 && pmsg->parameters[1][ l-1 ] == 1 ) { - // CTCP reply - CMString tempstr = pmsg->parameters[1]; - tempstr.Delete(0,1); - tempstr.Delete(tempstr.GetLength()-1,1); - CMString type = GetWord(tempstr.c_str(), 0); - if ( lstrcmpi(type.c_str(), _T("ping")) == 0) - mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s"), type.c_str(), pmsg->parameters[0].c_str()); - else - mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s: %s"), type.c_str(), pmsg->parameters[0].c_str(), GetWordAddress(tempstr.c_str(), 1)); - sMessage = temp; - } - else { - mir_sntprintf(temp, SIZEOF(temp), TranslateT("Notice to %s: "), pmsg->parameters[0].c_str()); - sMessage = temp; - for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { - sMessage += pmsg->parameters[i]; - if (i != pmsg->parameters.getCount()-1) - sMessage += _T(" "); - } } - goto THE_END; - } - - // Default Message handler. - - if ( pmsg->m_bIncoming ) { - if ( pmsg->parameters.getCount() < 2 && pmsg->parameters.getCount() > 0 ) - return pmsg->sCommand + _T(" : ") + pmsg->parameters[0]; - - if ( pmsg->parameters.getCount() > 1 ) - for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) - sMessage += pmsg->parameters[i] + _T(" "); - } - else { - if ( pmsg->prefix.sNick.GetLength()) - sMessage = pmsg->prefix.sNick + _T(" "); - sMessage += pmsg->sCommand + _T(" "); - for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) - sMessage += pmsg->parameters[i] + _T(" "); - } - -THE_END: - return sMessage; -} - -BOOL CIrcProto::ShowMessage (const CIrcMessage* pmsg) -{ - CMString mess = FormatOutput(pmsg); - - if ( !pmsg->m_bIncoming ) - ReplaceString( mess, _T("%%"), _T("%")); - - int iTemp = StrToInt( pmsg->sCommand.c_str()); - - //To active window - if (( iTemp > 400 || iTemp < 500 ) && pmsg->sCommand[0] == '4' //all error messages - || pmsg->sCommand == _T("303") //ISON command - || pmsg->sCommand == _T("INVITE") - || ( (pmsg->sCommand == _T("NOTICE")) && ( (pmsg->parameters.getCount() > 2) ? (_tcsstr(pmsg->parameters[1].c_str(), _T("\001"))==NULL) : false)) // CTCP answers should go to m_network Log window! - || pmsg->sCommand == _T("515")) //chanserv error - { - DoEvent(GC_EVENT_INFORMATION, NULL, pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); - return TRUE; - } - - if ( m_useServer ) { - DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, - ( pmsg->m_bIncoming ) ? pmsg->prefix.sNick.c_str() : m_info.sNick.c_str(), - mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming ? false : true ); - return true; - } - return false; -} diff --git a/protocols/IRCG/proto_irc/Proto_IRC.rc b/protocols/IRCG/proto_irc/Proto_IRC.rc deleted file mode 100644 index 09bc0ad668..0000000000 Binary files a/protocols/IRCG/proto_irc/Proto_IRC.rc and /dev/null differ diff --git a/protocols/IRCG/proto_irc/Proto_IRC.vcxproj b/protocols/IRCG/proto_irc/Proto_IRC.vcxproj index 84ec6a3d9a..62b71b47a5 100644 --- a/protocols/IRCG/proto_irc/Proto_IRC.vcxproj +++ b/protocols/IRCG/proto_irc/Proto_IRC.vcxproj @@ -119,10 +119,10 @@ - + - + diff --git a/protocols/IRCG/proto_irc/Proto_IRC.vcxproj.filters b/protocols/IRCG/proto_irc/Proto_IRC.vcxproj.filters index 0232af997d..025928f5f9 100644 --- a/protocols/IRCG/proto_irc/Proto_IRC.vcxproj.filters +++ b/protocols/IRCG/proto_irc/Proto_IRC.vcxproj.filters @@ -11,12 +11,12 @@ - + Header Files - + Resource Files diff --git a/protocols/IRCG/proto_irc/ico/Away.ico b/protocols/IRCG/proto_irc/ico/Away.ico deleted file mode 100644 index 48059b577a..0000000000 Binary files a/protocols/IRCG/proto_irc/ico/Away.ico and /dev/null differ diff --git a/protocols/IRCG/proto_irc/ico/Offline.ico b/protocols/IRCG/proto_irc/ico/Offline.ico deleted file mode 100644 index 4882899757..0000000000 Binary files a/protocols/IRCG/proto_irc/ico/Offline.ico and /dev/null differ diff --git a/protocols/IRCG/proto_irc/ico/Online.ico b/protocols/IRCG/proto_irc/ico/Online.ico deleted file mode 100644 index e816afd6ee..0000000000 Binary files a/protocols/IRCG/proto_irc/ico/Online.ico and /dev/null differ diff --git a/protocols/IRCG/proto_irc/res/Away.ico b/protocols/IRCG/proto_irc/res/Away.ico new file mode 100644 index 0000000000..48059b577a Binary files /dev/null and b/protocols/IRCG/proto_irc/res/Away.ico differ diff --git a/protocols/IRCG/proto_irc/res/Offline.ico b/protocols/IRCG/proto_irc/res/Offline.ico new file mode 100644 index 0000000000..4882899757 Binary files /dev/null and b/protocols/IRCG/proto_irc/res/Offline.ico differ diff --git a/protocols/IRCG/proto_irc/res/Online.ico b/protocols/IRCG/proto_irc/res/Online.ico new file mode 100644 index 0000000000..e816afd6ee Binary files /dev/null and b/protocols/IRCG/proto_irc/res/Online.ico differ diff --git a/protocols/IRCG/proto_irc/res/Proto_IRC.rc b/protocols/IRCG/proto_irc/res/Proto_IRC.rc new file mode 100644 index 0000000000..3e087d3e03 Binary files /dev/null and b/protocols/IRCG/proto_irc/res/Proto_IRC.rc differ diff --git a/protocols/IRCG/proto_irc/resource.h b/protocols/IRCG/proto_irc/resource.h deleted file mode 100644 index bf3cbb6839..0000000000 Binary files a/protocols/IRCG/proto_irc/resource.h and /dev/null differ diff --git a/protocols/IRCG/proto_irc/src/resource.h b/protocols/IRCG/proto_irc/src/resource.h new file mode 100644 index 0000000000..bf3cbb6839 Binary files /dev/null and b/protocols/IRCG/proto_irc/src/resource.h differ diff --git a/protocols/IRCG/res/IRC.rc b/protocols/IRCG/res/IRC.rc new file mode 100644 index 0000000000..9e22fe99a4 --- /dev/null +++ b/protocols/IRCG/res/IRC.rc @@ -0,0 +1,744 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAIN ICON "irc.ico" +IDI_ADD ICON "add.ico" +IDI_BLOCK ICON "block.ico" +IDI_DELETE ICON "delete.ico" +IDI_APPLY ICON "apply.ico" +IDI_WHOIS ICON "whois.ico" +IDI_LIST ICON "list.ico" +IDI_MANAGER ICON "manager.ico" +IDI_QUICK ICON "quick.ico" +IDI_RENAME ICON "rename.ico" +IDI_SHOW ICON "show.ico" +IDI_LOGO ICON "world.ico" +IDI_DCC ICON "dcc.ico" +IDI_SERVER ICON "server.ico" +IDI_EDIT ICON "edit.ico" +IDI_IRCQUESTION ICON "question.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PREFS_CONNECT DIALOGEX 0, 0, 304, 230 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_SERVERCOMBO,10,30,125,90,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_SERVER,10,53,88,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP | NOT WS_TABSTOP + EDITTEXT IDC_PORT,10,75,50,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT + EDITTEXT IDC_PORT2,85,75,50,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT + EDITTEXT IDC_PASS,10,100,125,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "&Add",IDC_ADDSERVER,"MButtonClass",WS_DISABLED | WS_TABSTOP,16,116,27,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Edit",IDC_EDITSERVER,"MButtonClass",WS_DISABLED | WS_TABSTOP,59,116,27,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Del",IDC_DELETESERVER,"MButtonClass",WS_DISABLED | WS_TABSTOP,102,116,27,14,WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_NICK,158,16,63,13,ES_AUTOHSCROLL + EDITTEXT IDC_NICK2,231,16,63,13,ES_AUTOHSCROLL + EDITTEXT IDC_NAME,158,40,63,13,ES_AUTOHSCROLL + EDITTEXT IDC_USERID,231,40,63,13,ES_AUTOHSCROLL + CONTROL "Enable",IDC_IDENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,73,46,15 + EDITTEXT IDC_IDENTSYSTEM,210,73,39,12,ES_AUTOHSCROLL + EDITTEXT IDC_IDENTPORT,256,73,39,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "only while connecting",IDC_IDENT_TIMED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,171,87,124,11 + CONTROL "Enable",IDC_RETRY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,118,42,10 + EDITTEXT IDC_RETRYWAIT,210,116,39,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + EDITTEXT IDC_RETRYCOUNT,256,116,39,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + CONTROL "Force visible (-i)",IDC_FORCEVISIBLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,145,134,10 + CONTROL "Rejoin channel if kicked",IDC_REJOINONKICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,156,134,10 + CONTROL "Rejoin channels on reconnect",IDC_REJOINCHANNELS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,167,134,10 + CONTROL "Disable tray balloon on error",IDC_DISABLEERROR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,178,134,10 + CONTROL "Show addresses",IDC_ADDRESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,189,134,10 + CONTROL "Use server window",IDC_USESERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,200,134,10 + CONTROL "Show server window on startup",IDC_SHOWSERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,211,129,10 + CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,145,154,10 + CONTROL "Automatically join on invite",IDC_AUTOJOIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,156,154,10 + CONTROL "'Old style' mode changes",IDC_OLDSTYLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,167,153,10 + CONTROL "Update online statuses for users",IDC_ONLINENOTIF, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,178,132,10 + EDITTEXT IDC_ONLINETIMER,267,188,29,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,284,188,12,14 + CONTROL "Update statuses in channel nicklist",IDC_CHANNELAWAY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,200,131,10 + EDITTEXT IDC_LIMIT,267,210,29,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,284,209,11,14 + CONTROL "Enable",IDC_STARTUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,11,73,10 + CONTROL "Internet address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,10,45,81,8,WS_EX_TRANSPARENT + LTEXT "Port range",IDC_STATIC,10,67,69,8,0,WS_EX_TRANSPARENT + LTEXT "Nick",IDC_STATIC,158,8,68,8,0,WS_EX_TRANSPARENT + LTEXT "User ID (Ident)",IDC_STATIC,231,31,68,9,0,WS_EX_TRANSPARENT + LTEXT "Full name (e-mail)",IDC_STATIC,158,31,68,9,0,WS_EX_TRANSPARENT + LTEXT "Password",IDC_STATIC,10,90,125,8,0,WS_EX_TRANSPARENT + LTEXT "Server name",IDC_STATIC,10,22,125,8,0,WS_EX_TRANSPARENT + LTEXT "->",IDC_STATIC,71,75,8,8 + LTEXT "Alternative nick",IDC_STATIC,231,8,68,8,0,WS_EX_TRANSPARENT + GROUPBOX "Ident",IDC_STATIC,150,59,154,42 + LTEXT "System",IDC_STATIC,210,65,39,8,0,WS_EX_TRANSPARENT + LTEXT "Port",IDC_STATIC,256,65,35,8,0,WS_EX_TRANSPARENT + GROUPBOX "Default network",IDC_STATIC,2,0,142,134 + GROUPBOX "User info - Required",IDC_STATIC,150,0,154,59 + GROUPBOX "Other",IDC_STATIC,2,134,302,92 + GROUPBOX "Reconnect",IDC_STATIC,150,101,154,33 + LTEXT "Wait (s)",IDC_STATIC,210,108,45,8,0,WS_EX_TRANSPARENT + LTEXT "Retry count",IDC_STATIC,256,108,43,8,0,WS_EX_TRANSPARENT + LTEXT "Fear the monkeys!!!",IDC_STATIC,72,4,63,8,NOT WS_VISIBLE + LTEXT "Check every (s):",IDC_STATIC,158,190,108,8 + EDITTEXT IDC_SSL,107,53,28,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT + LTEXT "SSL",IDC_STATIC,107,45,28,8,0,WS_EX_TRANSPARENT + CONTROL "Don't check if more than (users):",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,158,212,108,8 +END + +IDD_INFO DIALOGEX 0, 0, 267, 214 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "User information" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_INFO_NICK,6,63,60,97,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Ping",IDC_PING,12,142,50,14 + PUSHBUTTON "Version",IDC_VERSION,76,142,50,14 + PUSHBUTTON "Time",IDC_TIME,140,142,50,14 + PUSHBUTTON "Userinfo",IDC_USERINFO,204,142,50,14 + DEFPUSHBUTTON "&Refresh",ID_INFO_GO,93,194,50,14 + PUSHBUTTON "&Query",ID_INFO_QUERY,152,194,50,14,WS_GROUP + DEFPUSHBUTTON "&Close",IDOK,211,194,50,14,WS_GROUP + EDITTEXT IDC_INFO_NAME,71,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_ADDRESS,136,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_ID,201,63,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_AUTH,6,85,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_SERVER,71,85,60,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_AWAY2,136,85,125,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + EDITTEXT IDC_INFO_CHANNELS,136,108,125,20,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP + EDITTEXT IDC_INFO_OTHER,6,108,125,20,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP + LTEXT "Nick",IDC_STATIC,6,55,60,8 + LTEXT "Name",IDC_STATIC,71,55,59,8 + LTEXT "Address",IDC_STATIC,136,55,59,8,SS_NOTIFY + LTEXT "Channels",IDC_STATIC,136,100,119,8 + LTEXT "Auth",IDC_STATIC,6,77,59,8 + LTEXT "Server",IDC_STATIC,71,77,59,8 + LTEXT "User",IDC_STATIC,201,55,60,8 + LTEXT "Away Info",IDC_STATIC,136,77,125,8 + LTEXT "Other",IDC_STATIC,6,100,124,8 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,52,268,1 + LTEXT "",IDC_WHITERECT,0,0,267,52 + ICON "",IDC_LOGO,228,16,20,20,SS_REALSIZEIMAGE + LTEXT "The server returned the following information. Please note that this information might be misleading and/or falsified",IDC_TEXT,12,30,204,18 + LTEXT "",IDC_CAPTION,8,5,201,21 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,190,268,1 + GROUPBOX "CTCP information",IDC_STATIC,6,132,255,54 + EDITTEXT IDC_REPLY,12,160,243,20,ES_MULTILINE | ES_READONLY | NOT WS_TABSTOP + LTEXT "-",IDC_AWAYTIME,8,19,205,8 +END + +IDD_NICK DIALOGEX 0, 0, 180, 90 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Question" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_ENICK,5,47,170,71,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "&OK",IDOK,65,71,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,125,71,50,14,WS_GROUP + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,180,1 + LTEXT "",IDC_WHITERECT,0,0,179,38 + ICON "",IDC_LOGO,141,5,20,20,SS_REALSIZEIMAGE + LTEXT "",IDC_TEXT,13,16,121,18 + LTEXT "",IDC_CAPTION,5,5,125,11 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,65,180,1 +END + +IDD_PREFS_OTHER DIALOGEX 0, 0, 304, 225 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Perform",IDC_STATIC,4,4,136,152 + CONTROL "Enable",IDC_PERFORM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,18,107,10 + COMBOBOX IDC_PERFORMCOMBO,9,40,125,99,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_PERFORMEDIT,9,60,125,68,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | WS_GROUP + CONTROL "&Set",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,35,134,30,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Del",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,84,134,30,14,WS_EX_NOACTIVATE | 0x10000000L + GROUPBOX "Alias",IDC_STATIC,144,4,157,122 + EDITTEXT IDC_ALIASEDIT,152,18,142,102,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL + LTEXT "Perform on event:",IDC_STATIC,16,32,110,8,0,WS_EX_TRANSPARENT + GROUPBOX "Scripting support",IDC_STATIC,145,128,156,28 + CONTROL "Enable",IDC_SCRIPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,153,140,126,10 + GROUPBOX "Other",IDC_STATIC,4,156,297,66 + LTEXT "Quit message:",IDC_STATIC,12,168,136,8 + EDITTEXT IDC_QUITMESSAGE,12,176,282,12,ES_AUTOHSCROLL + COMBOBOX IDC_CODEPAGE,148,192,146,79,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Server code page:",IDC_STATIC,12,194,130,8 + CONTROL "Enable UTF8 autodetection",IDC_UTF_AUTODETECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,208,282,10 +END + +IDD_ADDSERVER DIALOGEX 0, 0, 182, 136 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT +CAPTION "Add server" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_ADD_COMBO,7,20,168,90,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_ADD_SERVER,7,44,120,12,ES_AUTOHSCROLL + EDITTEXT IDC_ADD_ADDRESS,7,68,120,12,ES_AUTOHSCROLL | WS_GROUP + EDITTEXT IDC_ADD_PORT,7,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + EDITTEXT IDC_ADD_PORT2,80,92,47,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + CONTROL "On",IDC_ON,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,143,52,25,10 + CONTROL "Auto",IDC_AUTO,"Button",BS_AUTORADIOBUTTON,143,69,30,10 + CONTROL "Off",IDC_OFF,"Button",BS_AUTORADIOBUTTON,143,86,25,10 + DEFPUSHBUTTON "&OK",IDOK,63,115,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,125,115,50,14 + CONTROL "Host address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,7,60,120,8,WS_EX_TRANSPARENT + LTEXT "->",IDC_STATIC,64,94,8,8 + LTEXT "Port range",IDC_STATIC,7,84,87,8,0,WS_EX_TRANSPARENT + LTEXT "Server description",IDC_STATIC,7,36,120,8,0,WS_EX_TRANSPARENT + LTEXT "Network",IDC_STATIC,7,12,107,8,0,WS_EX_TRANSPARENT + GROUPBOX "SSL",IDC_STATIC,136,38,39,67 +END + +IDD_LIST DIALOGEX 0, 0, 360, 212 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Channels on server" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + PUSHBUTTON "&Close",IDOK,306,183,50,14 + DEFPUSHBUTTON "&Join",IDC_JOIN,251,183,50,14,WS_DISABLED + CONTROL "List1",IDC_INFO_LISTVIEW,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,4,7,352,172 + EDITTEXT IDC_FILTER_STRING,68,183,143,13,ES_AUTOHSCROLL + CONTROL "List1",IDC_INFO_LISTVIEW2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,4,7,352,172 + LTEXT "Filter by",IDC_FILTER_BTN,7,185,56,8 + EDITTEXT IDC_TEXT,4,200,351,10,ES_AUTOHSCROLL | WS_DISABLED | NOT WS_BORDER,WS_EX_STATICEDGE +END + +IDD_QUICKCONN DIALOGEX 0, 0, 201, 165 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_SERVERCOMBO,12,54,177,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_SERVER,12,78,177,12,ES_AUTOHSCROLL + GROUPBOX "SSL",IDC_GRBOX_SSL,12,94,177,21,WS_GROUP | WS_TABSTOP + CONTROL "Off",IDC_SSL_OFF,"Button",BS_AUTORADIOBUTTON,36,102,42,10 + CONTROL "Auto",IDC_SSL_AUTO,"Button",BS_AUTORADIOBUTTON,87,102,42,10 + CONTROL "On",IDC_SSL_ON,"Button",BS_AUTORADIOBUTTON,138,102,44,10 + EDITTEXT IDC_PORT,12,124,36,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + EDITTEXT IDC_PORT2,63,124,36,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT + EDITTEXT IDC_PASS,116,124,73,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "C&onnect",IDOK,83,146,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,139,146,50,14 + CONTROL "Internet address",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP,12,70,130,8,WS_EX_TRANSPARENT + LTEXT "Port range",IDC_STATIC,12,116,63,8,0,WS_EX_TRANSPARENT + LTEXT "Password",IDC_STATIC,116,116,73,8,0,WS_EX_TRANSPARENT + LTEXT "Server name",IDC_STATIC,12,46,177,8,0,WS_EX_TRANSPARENT + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,140,201,1 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,201,1 + LTEXT "",IDC_WHITERECT,0,0,201,38 + ICON "",IDC_LOGO,159,5,20,20,SS_REALSIZEIMAGE + LTEXT "",IDC_TEXT,18,16,138,18 + LTEXT "",IDC_CAPTION,12,5,143,11 + LTEXT "->",IDC_STATIC,51,126,8,8,0,WS_EX_TRANSPARENT +END + +IDD_USERINFO DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_WILDCARD,12,91,40,12,ES_AUTOHSCROLL + EDITTEXT IDC_USER,66,91,40,12,ES_AUTOHSCROLL + EDITTEXT IDC_HOST,120,91,89,12,ES_AUTOHSCROLL + PUSHBUTTON "&Save",IDC_BUTTON,159,107,50,14,WS_DISABLED + LTEXT "Nick",IDC_STATIC,12,83,40,8 + LTEXT "User",IDC_STATIC,66,83,40,8 + LTEXT "Address",IDC_STATIC,120,83,89,8 + LTEXT "@",IDC_STATIC,109,90,8,8 + GROUPBOX "Hostmask",IDC_STATIC,6,73,209,52 + LTEXT "",IDC_DEFAULT,12,30,197,37 + LTEXT "!",IDC_STATIC,57,90,8,8 + PUSHBUTTON "&Clear all",IDC_BUTTON2,96,107,50,14 + GROUPBOX "Online detection mode",IDC_STATIC,6,7,209,66 + CONTROL "Basic",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,23,17,33,10 + CONTROL "Wildcard enabled network search",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,69,17,122,10 +END + +IDD_CHANMANAGER DIALOGEX 0, 0, 271, 303 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Channel manager" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_TOPIC,13,56,192,103,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + CONTROL "&Set",IDC_APPLYTOPIC,"MButtonClass",WS_DISABLED | WS_TABSTOP,226,54,28,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "Bans",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP | WS_TABSTOP,16,87,69,10 + CONTROL "Invites",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,90,87,74,10 + CONTROL "Excepts",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,166,87,86,10 + LISTBOX IDC_LIST,15,101,203,82,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_GROUP | WS_TABSTOP + CONTROL "&Add",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,100,28,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,116,28,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Del",IDC_REMOVE,"MButtonClass",WS_DISABLED | WS_TABSTOP,227,132,28,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "Only Ops set topic",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,211,111,10 + CONTROL "No external messages",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,224,109,10 + CONTROL "Invite only",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,237,106,10 + CONTROL "Moderated",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,250,106,10 + CONTROL "Key:",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,211,45,10 + EDITTEXT IDC_KEY,183,209,57,12,ES_AUTOHSCROLL | WS_DISABLED + CONTROL "User limit:",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,224,46,10 + EDITTEXT IDC_LIMIT,183,224,25,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + CONTROL "Private",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,237,73,10 + CONTROL "Secret",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,134,250,80,10 + CONTROL "&Set",IDC_APPLYMODES,"MButtonClass",WS_DISABLED | WS_TABSTOP,215,257,28,14,WS_EX_NOACTIVATE | 0x10000000L + DEFPUSHBUTTON "&Close",IDOK,212,284,50,14 + GROUPBOX "Topic",IDC_STATIC,6,45,256,28 + GROUPBOX "User modes",IDC_STATIC,6,73,256,118 + GROUPBOX "Channel modes",IDC_STATIC,6,197,256,82 + CONTROL "Hidden",IDC_NOTOP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE,217,73,45,10 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,271,1 + LTEXT "",IDC_WHITERECT,0,0,271,38 + ICON "",IDC_LOGO,236,5,21,20,SS_REALSIZEIMAGE + LTEXT "Use the options to set modes for this channel. You are usually required to be op. or higher to modify.",IDC_TEXT,18,16,219,18 + LTEXT "",IDC_CAPTION,12,5,210,11 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,279,255,1 + CONTROL "Strip colors",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,260,108,14 +END + +IDD_QUESTION DIALOGEX 0, 0, 230, 97 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Question" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_EDIT,5,48,220,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "&OK",IDOK,116,78,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,175,78,50,14,WS_GROUP + EDITTEXT IDC_HIDDENEDIT,5,78,40,14,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER | NOT WS_TABSTOP + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,38,230,1 + LTEXT "",IDC_WHITERECT,0,0,229,38 + ICON "",IDC_LOGO,193,5,20,20,SS_REALSIZEIMAGE + LTEXT "",IDC_TEXT,11,16,179,18 + LTEXT "",IDC_CAPTION,5,5,184,11 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,71,230,1 +END + +IDD_PREFS_CTCP DIALOGEX 0, 0, 304, 220 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_COMBO,104,40,52,85,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Normal",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,104,24,76,10 + CONTROL "Send-ahead",IDC_FAST,"Button",BS_AUTORADIOBUTTON,188,24,102,10 + CONTROL "Attempt reverse DCC (good if firewalled)",IDC_PASSIVE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,62,273,10 + CONTROL "none",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,104,94,162,10 + CONTROL "everyone on the contact list",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,104,105,186,10 + CONTROL "everyone",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,104,116,186,10 + CONTROL "Disconnect DCC chats when disconnecting from server",IDC_DISC, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,135,257,10 + CONTROL "Manually set external IP:",IDC_ENABLEIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,164,130,10 + EDITTEXT IDC_IP,146,162,144,14,ES_AUTOHSCROLL + EDITTEXT IDC_USERINFO,16,196,274,14,ES_AUTOHSCROLL + GROUPBOX "Client-to-Client File Transfers",IDC_STATIC,8,6,289,75 + LTEXT "User information",IDC_STATIC,16,188,144,8 + GROUPBOX "Client-to-Client Protocol",IDC_STATIC,8,151,289,67 + GROUPBOX "Client-to-Client Chats",IDC_STATIC,8,81,289,70 + LTEXT "Send mode:",IDC_STATIC,16,25,79,8 + LTEXT "Packet size (b):",IDC_STATIC,16,44,88,8 + CONTROL "Get IP address from server",IDC_FROMSERVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,176,227,10 + LTEXT "Auto-accept from:",IDC_STATIC,16,106,82,8 + CONTROL "Send notice",IDC_SENDNOTICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,43,101,10 +END + +IDD_MESSAGEBOX DIALOGEX 0, 0, 220, 68 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT +CAPTION "CTCP Chat Request" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + PUSHBUTTON "&Accept",IDOK,50,47,50,14 + DEFPUSHBUTTON "&Deny",IDCANCEL,120,47,50,14 + LTEXT "",IDC_TEXT,43,13,170,31,0,WS_EX_TRANSPARENT + ICON "",IDC_LOGO,7,13,21,20 +END + +IDD_PREFS_IGNORE DIALOGEX 0, 0, 304, 220 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Enable (*)",IDC_ENABLEIGNORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,78,10 + CONTROL "Ignore channel messages by default",IDC_IGNORECHANNEL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,108,18,180,10 + CONTROL "List1",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,16,33,240,104 + CONTROL "&Add",IDC_ADD,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,43,27,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,68,27,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "&Del",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,264,93,27,14,WS_EX_NOACTIVATE | 0x10000000L + CONTROL "Ignore filetransfer requests",IDC_IGNOREFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,170,240,10 + CONTROL "Ignore DCC Chat requests",IDC_IGNORECHAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,185,240,10 + CONTROL "Ignore DCC Chat requests from unknown contacts",IDC_IGNOREUNKNOWN, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,200,256,10 + GROUPBOX "Ignore users",-1,8,6,289,150 + GROUPBOX "Other",-1,8,156,289,62 + CONTROL "(*) Queries from users on your contactlist are never ignored",IDC_CUSTOM, + "Hyperlink",WS_TABSTOP | 0x1,16,142,274,9 +END + +IDD_ADDIGNORE DIALOGEX 0, 0, 220, 126 +STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_MASK,7,15,137,14,ES_AUTOHSCROLL + EDITTEXT IDC_NETWORK,150,15,63,14,ES_AUTOHSCROLL + CONTROL "Queries",IDC_Q,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,47,54,10 + CONTROL "Messages",IDC_M,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,47,64,10 + CONTROL "Notices",IDC_N,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,47,57,10 + CONTROL "Invites",IDC_I,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,66,54,10 + CONTROL "CTCP",IDC_C,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,66,64,10 + CONTROL "DCC",IDC_D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,66,57,10 + DEFPUSHBUTTON "&Accept",IDOK,93,105,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,163,105,50,14 + LTEXT "Ignore mask ( nick!user@host )",IDC_STATIC,7,7,136,8 + LTEXT "Network (*)",IDC_STATIC,150,7,63,8 + GROUPBOX "Ignore events",IDC_STATIC,7,36,206,46 + CTEXT "(*) blank to set this mask for all networks",IDC_STATIC,7,90,206,8 +END + +IDD_ACCMGRUI DIALOGEX 0, 0, 186, 134 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_SERVERCOMBO,55,5,125,90,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_SERVER,5,21,88,12,ES_AUTOHSCROLL | ES_READONLY | WS_GROUP | NOT WS_TABSTOP + EDITTEXT IDC_PORT,96,21,27,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT + EDITTEXT IDC_PORT2,126,21,27,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT + EDITTEXT IDC_PASS,54,38,125,12,ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT IDC_NICK,87,64,91,13,ES_AUTOHSCROLL + EDITTEXT IDC_NICK2,87,81,91,13,ES_AUTOHSCROLL + EDITTEXT IDC_NAME,87,98,91,13,ES_AUTOHSCROLL + EDITTEXT IDC_USERID,87,115,91,13,ES_AUTOHSCROLL + LTEXT "Server:",IDC_STATIC,5,7,45,8 + LTEXT "Password:",IDC_STATIC,6,41,43,8 + LTEXT "Nick",IDC_STATIC,8,66,77,8 + LTEXT "Alternate nick",IDC_STATIC,8,83,76,8 + LTEXT "Full name (e-mail)",IDC_STATIC,8,100,77,8 + LTEXT "User ID (Ident)",IDC_STATIC,8,117,74,8 + EDITTEXT IDC_SSL,155,21,23,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP,WS_EX_RIGHT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PREFS_CONNECT, DIALOG + BEGIN + LEFTMARGIN, 2 + VERTGUIDE, 10 + VERTGUIDE, 135 + VERTGUIDE, 144 + VERTGUIDE, 158 + VERTGUIDE, 210 + VERTGUIDE, 229 + HORZGUIDE, 16 + HORZGUIDE, 30 + HORZGUIDE, 39 + HORZGUIDE, 53 + HORZGUIDE, 61 + HORZGUIDE, 73 + HORZGUIDE, 75 + HORZGUIDE, 116 + HORZGUIDE, 134 + HORZGUIDE, 145 + END + + IDD_INFO, DIALOG + BEGIN + VERTGUIDE, 6 + VERTGUIDE, 10 + VERTGUIDE, 261 + BOTTOMMARGIN, 208 + HORZGUIDE, 38 + HORZGUIDE, 49 + HORZGUIDE, 71 + HORZGUIDE, 94 + HORZGUIDE, 118 + HORZGUIDE, 135 + HORZGUIDE, 146 + HORZGUIDE, 163 + HORZGUIDE, 180 + HORZGUIDE, 194 + END + + IDD_NICK, DIALOG + BEGIN + BOTTOMMARGIN, 85 + HORZGUIDE, 5 + HORZGUIDE, 65 + END + + IDD_PREFS_OTHER, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 291 + VERTGUIDE, 10 + VERTGUIDE, 128 + VERTGUIDE, 145 + VERTGUIDE, 220 + VERTGUIDE, 262 + VERTGUIDE, 283 + BOTTOMMARGIN, 217 + HORZGUIDE, 6 + HORZGUIDE, 28 + HORZGUIDE, 49 + HORZGUIDE, 117 + HORZGUIDE, 124 + HORZGUIDE, 131 + HORZGUIDE, 145 + HORZGUIDE, 174 + END + + IDD_ADDSERVER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + VERTGUIDE, 127 + VERTGUIDE, 136 + VERTGUIDE, 143 + TOPMARGIN, 7 + BOTTOMMARGIN, 129 + HORZGUIDE, 20 + HORZGUIDE, 44 + HORZGUIDE, 68 + HORZGUIDE, 92 + END + + IDD_LIST, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 356 + VERTGUIDE, 16 + VERTGUIDE, 70 + VERTGUIDE, 128 + VERTGUIDE, 182 + TOPMARGIN, 7 + BOTTOMMARGIN, 203 + HORZGUIDE, 19 + HORZGUIDE, 138 + HORZGUIDE, 179 + END + + IDD_QUICKCONN, DIALOG + BEGIN + VERTGUIDE, 12 + VERTGUIDE, 189 + BOTTOMMARGIN, 160 + HORZGUIDE, 5 + HORZGUIDE, 38 + HORZGUIDE, 54 + HORZGUIDE, 78 + HORZGUIDE, 124 + HORZGUIDE, 140 + END + + IDD_USERINFO, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 215 + VERTGUIDE, 62 + TOPMARGIN, 7 + BOTTOMMARGIN, 125 + HORZGUIDE, 22 + HORZGUIDE, 30 + HORZGUIDE, 73 + HORZGUIDE, 91 + HORZGUIDE, 114 + END + + IDD_CHANMANAGER, DIALOG + BEGIN + VERTGUIDE, 6 + VERTGUIDE, 15 + VERTGUIDE, 134 + VERTGUIDE, 262 + BOTTOMMARGIN, 298 + HORZGUIDE, 5 + HORZGUIDE, 22 + HORZGUIDE, 40 + HORZGUIDE, 45 + HORZGUIDE, 73 + HORZGUIDE, 191 + HORZGUIDE, 279 + END + + IDD_QUESTION, DIALOG + BEGIN + VERTGUIDE, 5 + BOTTOMMARGIN, 92 + HORZGUIDE, 5 + HORZGUIDE, 72 + END + + IDD_PREFS_CTCP, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 291 + VERTGUIDE, 10 + VERTGUIDE, 27 + VERTGUIDE, 37 + VERTGUIDE, 83 + VERTGUIDE, 98 + VERTGUIDE, 140 + VERTGUIDE, 154 + VERTGUIDE, 182 + VERTGUIDE, 199 + VERTGUIDE, 220 + VERTGUIDE, 260 + VERTGUIDE, 284 + BOTTOMMARGIN, 212 + HORZGUIDE, 23 + HORZGUIDE, 42 + HORZGUIDE, 61 + HORZGUIDE, 75 + HORZGUIDE, 104 + HORZGUIDE, 134 + HORZGUIDE, 145 + HORZGUIDE, 163 + HORZGUIDE, 190 + END + + IDD_MESSAGEBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + VERTGUIDE, 43 + VERTGUIDE, 75 + VERTGUIDE, 145 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + HORZGUIDE, 13 + END + + IDD_PREFS_IGNORE, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 291 + VERTGUIDE, 10 + VERTGUIDE, 250 + VERTGUIDE, 258 + BOTTOMMARGIN, 212 + HORZGUIDE, 17 + HORZGUIDE, 27 + HORZGUIDE, 140 + HORZGUIDE, 150 + END + + IDD_ADDIGNORE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + VERTGUIDE, 20 + VERTGUIDE, 80 + VERTGUIDE, 150 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + HORZGUIDE, 15 + HORZGUIDE, 36 + HORZGUIDE, 52 + HORZGUIDE, 71 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// TEXT +// + +IDR_SERVERS TEXT "..\\docs\\IRC_servers.ini" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/IRCG/res/add.ico b/protocols/IRCG/res/add.ico new file mode 100644 index 0000000000..a6a7e6f38c Binary files /dev/null and b/protocols/IRCG/res/add.ico differ diff --git a/protocols/IRCG/res/apply.ico b/protocols/IRCG/res/apply.ico new file mode 100644 index 0000000000..19957e4ac8 Binary files /dev/null and b/protocols/IRCG/res/apply.ico differ diff --git a/protocols/IRCG/res/block.ico b/protocols/IRCG/res/block.ico new file mode 100644 index 0000000000..073acb134f Binary files /dev/null and b/protocols/IRCG/res/block.ico differ diff --git a/protocols/IRCG/res/dcc.ico b/protocols/IRCG/res/dcc.ico new file mode 100644 index 0000000000..3d3b83d936 Binary files /dev/null and b/protocols/IRCG/res/dcc.ico differ diff --git a/protocols/IRCG/res/delete.ico b/protocols/IRCG/res/delete.ico new file mode 100644 index 0000000000..9108e38cfd Binary files /dev/null and b/protocols/IRCG/res/delete.ico differ diff --git a/protocols/IRCG/res/edit.ico b/protocols/IRCG/res/edit.ico new file mode 100644 index 0000000000..0c3764bec4 Binary files /dev/null and b/protocols/IRCG/res/edit.ico differ diff --git a/protocols/IRCG/res/irc.ico b/protocols/IRCG/res/irc.ico new file mode 100644 index 0000000000..27cc764c94 Binary files /dev/null and b/protocols/IRCG/res/irc.ico differ diff --git a/protocols/IRCG/res/list.ico b/protocols/IRCG/res/list.ico new file mode 100644 index 0000000000..a7004e37aa Binary files /dev/null and b/protocols/IRCG/res/list.ico differ diff --git a/protocols/IRCG/res/manager.ico b/protocols/IRCG/res/manager.ico new file mode 100644 index 0000000000..217534bc74 Binary files /dev/null and b/protocols/IRCG/res/manager.ico differ diff --git a/protocols/IRCG/res/question.ico b/protocols/IRCG/res/question.ico new file mode 100644 index 0000000000..0454d67afb Binary files /dev/null and b/protocols/IRCG/res/question.ico differ diff --git a/protocols/IRCG/res/quick.ico b/protocols/IRCG/res/quick.ico new file mode 100644 index 0000000000..078f7490c9 Binary files /dev/null and b/protocols/IRCG/res/quick.ico differ diff --git a/protocols/IRCG/res/rename.ico b/protocols/IRCG/res/rename.ico new file mode 100644 index 0000000000..0434c1bd02 Binary files /dev/null and b/protocols/IRCG/res/rename.ico differ diff --git a/protocols/IRCG/res/server.ico b/protocols/IRCG/res/server.ico new file mode 100644 index 0000000000..db008452f0 Binary files /dev/null and b/protocols/IRCG/res/server.ico differ diff --git a/protocols/IRCG/res/show.ico b/protocols/IRCG/res/show.ico new file mode 100644 index 0000000000..ce7136ae4a Binary files /dev/null and b/protocols/IRCG/res/show.ico differ diff --git a/protocols/IRCG/res/version.rc b/protocols/IRCG/res/version.rc new file mode 100644 index 0000000000..175296edb0 --- /dev/null +++ b/protocols/IRCG/res/version.rc @@ -0,0 +1,41 @@ +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include +#include "..\src\version.h" + +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#endif //_WIN32 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Author", __AUTHOR + VALUE "FileDescription", __DESC + VALUE "FileVersion", __VERSION_STRING + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/protocols/IRCG/res/whois.ico b/protocols/IRCG/res/whois.ico new file mode 100644 index 0000000000..e66f079830 Binary files /dev/null and b/protocols/IRCG/res/whois.ico differ diff --git a/protocols/IRCG/res/world.ico b/protocols/IRCG/res/world.ico new file mode 100644 index 0000000000..f462de9a04 Binary files /dev/null and b/protocols/IRCG/res/world.ico differ diff --git a/protocols/IRCG/resource.h b/protocols/IRCG/resource.h deleted file mode 100644 index 948b3a4085..0000000000 --- a/protocols/IRCG/resource.h +++ /dev/null @@ -1,253 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by IRC.rc -// -#define ID_INFO_QUERY 3 -#define IDD_PREFS_MAIN 101 -#define IDC_OPTIONSTAB 102 -#define IDD_PREFS_CONNECT 103 -#define IDD_INFO 106 -#define IDD_NICK 107 -#define IDD_PREFS_OTHER 113 -#define IDD_ADDSERVER 120 -#define IDD_LIST 123 -#define IDR_MENU 129 -#define IDD_QUICKCONN 133 -#define IDI_MAIN 136 -#define IDD_USERINFO 154 -#define IDD_CHANMANAGER 155 -#define IDD_QUESTION 156 -#define IDD_PREFS_CTCP 158 -#define IDD_MESSAGEBOX 159 -#define IDD_PREFS_IGNORE 160 -#define IDD_ADDIGNORE 161 -#define IDD_ACCMGRUI 162 -#define IDI_ADD 175 -#define IDI_BLOCK 176 -#define IDI_DELETE 177 -#define IDI_WHOIS 179 -#define IDI_LIST 181 -#define IDI_MANAGER 182 -#define IDI_QUICK 184 -#define IDI_GO 185 -#define IDI_APPLY 185 -#define IDI_SHOW 186 -#define IDI_LOGO 187 -#define IDI_RENAME 188 -#define IDI_SERVER 189 -#define IDI_DCC 196 -#define IDR_SERVERS 200 -#define IDI_EDIT 201 -#define IDI_IRCQUESTION 202 -#define IDC_ENICK 1000 -#define IDC_USERID 1001 -#define IDC_INFO_NAME 1001 -#define IDC_NICK 1002 -#define IDC_LIST 1002 -#define IDC_INFO_AUTH 1002 -#define IDC_INFO_LISTVIEW 1002 -#define IDC_PORT 1003 -#define IDC_INFO_CHANNELS 1003 -#define IDC_INFO_LISTVIEW2 1003 -#define IDC_NAME 1004 -#define IDC_INFO_ADDRESS 1004 -#define IDC_PASS 1005 -#define IDC_INFO_SERVER 1005 -#define IDC_SERVER 1006 -#define IDC_INFO_ID 1006 -#define IDC_PERFORMEDIT 1007 -#define IDC_PORT2 1008 -#define IDC_INFO_AWAY2 1008 -#define IDC_NICK2 1009 -#define IDC_REPLY 1009 -#define IDC_SSL 1010 -#define IDC_PORT3 1010 -#define IDC_INFO_OTHER 1011 -#define IDC_EDIT 1012 -#define IDC_RETRYCOUNT 1013 -#define IDC_INFO_NICK 1013 -#define IDC_EDIT2 1013 -#define ID_INFO_GO 1017 -#define IDC_SERVERCOMBO 1022 -#define IDC_IDENT 1023 -#define IDC_IDENT_TIMED 1024 -#define IDC_RETRY 1029 -#define IDC_ADDSERVER 1031 -#define IDC_EDITSERVER 1032 -#define IDC_RETRYWAIT 1035 -#define IDC_IDENTSYSTEM 1036 -#define IDC_IDENTPORT 1037 -#define IDC_ONLINETIMER 1038 -#define IDC_FORCEVISIBLE 1039 -#define IDC_REJOINCHANNELS 1041 -#define IDC_REJOINONKICK 1042 -#define IDC_PERFORM 1043 -#define IDC_PERFORMCOMBO 1044 -#define IDC_DISABLEERROR 1044 -#define IDC_KEEPALIVE 1045 -#define IDC_ENABLEIP 1045 -#define IDC_ONLINENOTIF 1046 -#define IDC_CHANNELAWAY 1047 -#define IDC_USESERVER 1048 -#define IDC_SHOWSERVER 1049 -#define IDC_ADDRESS 1050 -#define IDC_AUTOJOIN 1051 -#define IDC_OLDSTYLE 1052 -#define IDC_ADD 1090 -#define IDC_DELETE 1091 -#define IDC_ALIASEDIT 1094 -#define IDC_REMOVE 1094 -#define IDC_APPLYTOPIC 1095 -#define IDC_APPLYMODES 1096 -#define IDC_DELETESERVER 1097 -#define IDC_ADD_COMBO 1100 -#define IDC_ADD_SERVER 1101 -#define IDC_ADD_ADDRESS 1102 -#define IDC_ADD_PORT 1103 -#define IDC_ADD_PORT2 1104 -#define IDC_CLOSE 1108 -#define IDC_JOIN 1109 -#define ID_INFO_OK 1110 -#define IDC_STARTUP 1133 -#define IDC_TEXT 1134 -#define IDC_DEFAULT 1139 -#define IDC_WILDCARD 1140 -#define IDC_USER 1141 -#define IDC_HOST 1142 -#define IDC_BUTTON 1143 -#define IDC_BUTTON2 1144 -#define IDC_CHECK1 1147 -#define IDC_CHECK2 1148 -#define IDC_CHECK3 1149 -#define IDC_CHECK4 1150 -#define IDC_CHECK5 1151 -#define IDC_CHECK6 1152 -#define IDC_CHECK7 1153 -#define IDC_CHECK8 1154 -#define IDC_KEY 1159 -#define IDC_LIMIT 1160 -#define IDC_TOPIC 1161 -#define IDC_RADIO1 1170 -#define IDC_RADIO2 1171 -#define IDC_RADIO3 1172 -#define IDC_HIDDENEDIT 1175 -#define IDC_NOTOP 1176 -#define IDC_WHITERECT 1179 -#define IDC_LOGO 1180 -#define IDC_CAPTION 1181 -#define IDC_OFF 1184 -#define IDC_AUTO 1185 -#define IDC_ON 1186 -#define IDC_QUITMESSAGE 1187 -#define IDC_USERINFO 1189 -#define IDC_PING 1190 -#define IDC_IP 1190 -#define IDC_VERSION 1191 -#define IDN_YES 1191 -#define IDC_PASSIVE 1191 -#define IDC_TIME 1192 -#define IDN_NO 1192 -#define IDC_PASSIVE2 1192 -#define IDC_SENDNOTICE 1192 -#define IDC_SLOW 1193 -#define IDC_FAST 1194 -#define IDC_COMBO 1196 -#define IDC_DISC 1197 -#define IDC_FROMSERVER 1201 -#define IDC_SCRIPT 1202 -#define IDC_MASK 1204 -#define IDC_Q 1205 -#define IDC_M 1206 -#define IDC_N 1207 -#define IDC_I 1208 -#define IDC_C 1209 -#define IDC_D 1210 -#define IDC_NETWORK 1211 -#define IDC_IGNORECHANNEL 1212 -#define IDC_ENABLEIGNORE 1213 -#define IDC_IGNOREFILE 1214 -#define IDC_IGNORECHAT 1215 -#define IDC_IGNOREUNKNOWN 1216 -#define IDC_CUSTOM 1218 -#define IDC_SPIN1 1219 -#define IDC_SPIN2 1220 -#define IDC_CODEPAGE 1222 -#define IDC_COMBO1 1223 -#define IDC_CHECK9 1224 -#define IDC_UTF_AUTODETECT 1225 -#define IDC_AWAYTIME 1226 -#define IDC_SSL_ON 1227 -#define IDC_SSL_AUTO 1228 -#define IDC_SSL_OFF 1229 -#define IDC_GRBOX_SSL 1230 -#define IDC_LIST1 1231 -#define IDC_EDIT1 1232 -#define IDC_STATICTEXT1 1233 -#define IDC_STATICTEXT2 1234 -#define IDC_FILTER_STRING 1235 -#define IDC_BUTTON1 1236 -#define IDC_FILTER_BTN 1237 -#define ID_MENU1_OP 40013 -#define ID_MENU1_DEOP 40014 -#define ID_MENU1_VOICE 40015 -#define ID_MENU1_DEVOICE 40016 -#define ID_MENU1_KICK 40017 -#define ID_MENU1_QUERY 40018 -#define ID_MENU1_WHOIS 40019 -#define IDM_COPYALL 40020 -#define IDM_SELECTALL 40022 -#define IDM_CLEAR 40023 -#define IDM_OPENNEW 40024 -#define IDM_OPENEXISTING 40025 -#define IDM_COPYLINK 40026 -#define IDM_COPY 40027 -#define IDM_JOIN 40028 -#define IDM_CHANGENICK 40029 -#define IDM_SHOWSERVER 40030 -#define IDM_LEAVECHAN 40031 -#define ID_MENU1_ADDCONTACT 40032 -#define IDM_CHANMANAGER 40033 -#define ID_MENU1_KICKREASON 40034 -#define ID_MENU1_BAN 40035 -#define ID_MENU1_BANKICK 40036 -#define ID_MENU1_BANKICKREASON 40037 -#define ID_MENU1_IGNORE_ON 40038 -#define ID_MENU1_IGNORE_OFF 40039 -#define ID_MENU1_OWNER 40040 -#define ID_MENU1_DEOWNER 40041 -#define ID_MENU1_ADMIN 40042 -#define ID_MENU1_DEADMIN 40043 -#define ID_MENU1_SENDNOTICE 40044 -#define ID_MENU1_INVITETOCHANNEL 40045 -#define ID_MENU1_SLAP 40046 -#define ID_MENU1_NICKSERV 40047 -#define ID_NICKSERV_REGISTERNICK 40048 -#define ID_NICKSERV_AUTHNICK 40049 -#define ID_NICKSERV_DELETENICK 40050 -#define ID_NICKSERV_IDENTIFY 40051 -#define ID_NICKSERV_SENDPASSWORD 40052 -#define ID_NICKSERV_SETTINGS 40053 -#define ID_SETTINGS_LANGUAGE 40054 -#define ID_SETTINGS_E 40055 -#define ID_SETTINGS_INFO 40056 -#define ID_SETTINGS_KILL 40057 -#define ID_NICKSERV_KILL 40058 -#define ID_KILL_OFF 40059 -#define ID_KILL_ON 40060 -#define ID_KILL_QUICK 40061 -#define ID_NICKSERV_PRIVATE 40062 -#define ID_PRIVATE_ON 40063 -#define ID_PRIVATE_OFF 40064 -#define ID_NICKSERV_SETNEWPASSWORD 40065 -#define ID_NICKSERV_ 40066 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 203 -#define _APS_NEXT_COMMAND_VALUE 40067 -#define _APS_NEXT_CONTROL_VALUE 1238 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/protocols/IRCG/scripting.cpp b/protocols/IRCG/scripting.cpp deleted file mode 100644 index 26c6bc2a55..0000000000 --- a/protocols/IRCG/scripting.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -INT_PTR __cdecl CIrcProto::Scripting_InsertRawIn(WPARAM, LPARAM lParam) -{ - char* pszRaw = ( char* ) lParam; - - if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { - TCHAR* p = mir_a2t( pszRaw ); - InsertIncomingEvent( p ); - mir_free( p ); - return 0; - } - - return 1; -} - -INT_PTR __cdecl CIrcProto::Scripting_InsertRawOut( WPARAM, LPARAM lParam ) -{ - char* pszRaw = ( char* ) lParam; - if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { - String S = pszRaw; - ReplaceString( S, "%", "%%%%"); - NLSendNoScript((const unsigned char *)S.c_str(), lstrlenA(S.c_str())); - return 0; - } - - return 1; -} - -INT_PTR __cdecl CIrcProto::Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam) -{ - GCEVENT* gce = (GCEVENT *) lParam; - WPARAM_GUI_IN * wgi = (WPARAM_GUI_IN *) wParam; - - - if ( m_bMbotInstalled && m_scriptingEnabled && gce ) { - TCHAR* p1 = NULL; - CMString S; - if ( gce->pDest && gce->pDest->ptszID ) { - p1 = gce->pDest->ptszID; - S = MakeWndID(gce->pDest->ptszID); - gce->pDest->ptszID = ( TCHAR* )S.c_str(); - } - gce->cbSize = sizeof(GCEVENT); - - CallServiceSync( MS_GC_EVENT, wgi?wgi->wParam:0, (LPARAM)gce); - - if ( p1 ) - gce->pDest->ptszID = p1; - return 0; - } - - return 1; -} - -//helper functions -static void __stdcall OnHook(void * pi) -{ - GCHOOK* gch = ( GCHOOK* )pi; - - //Service_GCEventHook(1, (LPARAM) gch); - - if(gch->pszUID) - free(gch->pszUID); - if(gch->pszText) - free(gch->pszText); - if(gch->pDest->ptszID) - free(gch->pDest->ptszID); - if(gch->pDest->pszModule) - free(gch->pDest->pszModule); - delete gch->pDest; - delete gch; -} - -static void __cdecl GuiOutThread(LPVOID di) -{ - GCHOOK* gch = ( GCHOOK* )di; - CallFunctionAsync( OnHook, ( void* )gch ); -} - -INT_PTR __cdecl CIrcProto::Scripting_InsertGuiOut( WPARAM, LPARAM lParam ) -{ - GCHOOK* gch = ( GCHOOK* )lParam; - - if ( m_bMbotInstalled && m_scriptingEnabled && gch ) { - GCHOOK* gchook = new GCHOOK; - gchook->pDest = new GCDEST; - - gchook->dwData = gch->dwData; - gchook->pDest->iType = gch->pDest->iType; - if ( gch->ptszText ) - gchook->ptszText = _tcsdup( gch->ptszText ); - else gchook->pszText = NULL; - - if ( gch->ptszUID ) - gchook->ptszUID = _tcsdup( gch->ptszUID ); - else gchook->pszUID = NULL; - - if ( gch->pDest->ptszID ) { - CMString S = MakeWndID( gch->pDest->ptszID ); - gchook->pDest->ptszID = _tcsdup( S.c_str()); - } - else gchook->pDest->ptszID = NULL; - - if ( gch->pDest->pszModule ) - gchook->pDest->pszModule = _strdup(gch->pDest->pszModule); - else gchook->pDest->pszModule = NULL; - - mir_forkthread( GuiOutThread, gchook ); - return 0; - } - - return 1; -} - -BOOL CIrcProto::Scripting_TriggerMSPRawIn( char** pszRaw ) -{ - int iVal = CallService( MS_MBOT_IRC_RAW_IN, (WPARAM)m_szModuleName, (LPARAM)pszRaw); - if ( iVal == 0 ) - return TRUE; - - return iVal > 0 ? FALSE : TRUE; -} - -BOOL CIrcProto::Scripting_TriggerMSPRawOut(char ** pszRaw) -{ - int iVal = CallService( MS_MBOT_IRC_RAW_OUT, (WPARAM)m_szModuleName, (LPARAM)pszRaw); - if ( iVal == 0 ) - return TRUE; - - return iVal > 0 ? FALSE : TRUE; -} - -BOOL CIrcProto::Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce) -{ - WPARAM_GUI_IN wgi = {0}; - - wgi.pszModule = m_szModuleName; - wgi.wParam = *wparam; - if (gce->time == 0) - gce->time = time(0); - - int iVal = CallService( MS_MBOT_IRC_GUI_IN, (WPARAM)&wgi, (LPARAM)gce); - if ( iVal == 0 ) { - *wparam = wgi.wParam; - return TRUE; - } - - return iVal > 0 ? FALSE : TRUE; -} - -BOOL CIrcProto::Scripting_TriggerMSPGuiOut(GCHOOK* gch) -{ - int iVal = CallService( MS_MBOT_IRC_GUI_OUT, (WPARAM)m_szModuleName, (LPARAM)gch); - if ( iVal == 0 ) - return TRUE; - - return iVal > 0 ? FALSE : TRUE; -} - -INT_PTR __cdecl CIrcProto::Scripting_GetIrcData(WPARAM, LPARAM lparam) -{ - if ( m_bMbotInstalled && m_scriptingEnabled && lparam ) { - String sString = ( char* ) lparam, sRequest; - CMString sOutput, sChannel; - - int i = sString.Find("|"); - if ( i != -1 ) { - sRequest = sString.Mid(0, i); - TCHAR* p = mir_a2t(( char* )sString.Mid(i+1, sString.GetLength()).c_str()); - sChannel = p; - mir_free( p ); - } - else sRequest = sString; - - sRequest.MakeLower(); - - if (sRequest == "ownnick" && IsConnected()) - sOutput = m_info.sNick; - - else if (sRequest == "network" && IsConnected()) - sOutput = m_info.sNetwork; - - else if (sRequest == "primarynick") - sOutput = m_nick; - - else if (sRequest == "secondarynick") - sOutput = m_alternativeNick; - - else if (sRequest == "myip") - return ( INT_PTR )mir_strdup( m_manualHost ? m_mySpecifiedHostIP : - ( m_IPFromServer ) ? m_myHost : m_myLocalHost); - - else if (sRequest == "usercount" && !sChannel.IsEmpty()) { - CMString S = MakeWndID(sChannel.c_str()); - GC_INFO gci = {0}; - gci.Flags = BYID|COUNT; - gci.pszModule = m_szModuleName; - gci.pszID = (TCHAR*)S.c_str(); - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) { - TCHAR szTemp[40]; - _sntprintf( szTemp, 35, _T("%u"), gci.iCount); - sOutput = szTemp; - } - } - else if (sRequest == "userlist" && !sChannel.IsEmpty()) { - CMString S = MakeWndID(sChannel.c_str()); - GC_INFO gci = {0}; - gci.Flags = BYID|USERS; - gci.pszModule = m_szModuleName; - gci.pszID = ( TCHAR* )S.c_str(); - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) - return (INT_PTR)mir_strdup( gci.pszUsers ); - } - else if (sRequest == "channellist") { - CMString S = _T(""); - int i = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); - if ( i >= 0 ) { - int j = 0; - while (j < i) { - GC_INFO gci = {0}; - gci.Flags = BYINDEX|ID; - gci.pszModule = m_szModuleName; - gci.iItem = j; - if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) { - if ( lstrcmpi( gci.pszID, SERVERWINDOW)) { - CMString S1 = gci.pszID; - int k = S1.Find(_T(" ")); - if ( k != -1 ) - S1 = S1.Mid(0, k); - S += S1 + _T(" "); - } } - j++; - } } - - if ( !S.IsEmpty()) - sOutput = ( TCHAR* )S.c_str(); - } - // send it to mbot - if ( !sOutput.IsEmpty()) - return ( INT_PTR )mir_t2a( sOutput.c_str()); - } - return 0; -} diff --git a/protocols/IRCG/services.cpp b/protocols/IRCG/services.cpp deleted file mode 100644 index e3b363ac15..0000000000 --- a/protocols/IRCG/services.cpp +++ /dev/null @@ -1,1254 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -BOOL bChatInstalled = FALSE, m_bMbotInstalled = FALSE; - -void CIrcProto::InitMainMenus(void) -{ - char temp[ MAXMODULELABELLENGTH ]; - char *d = temp + sprintf( temp, m_szModuleName ); - - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof( mi ); - mi.pszService = temp; - - if ( bChatInstalled ) { - HGENMENU hRoot = MO_GetProtoRootMenu( m_szModuleName ); - if ( hRoot == NULL ) { - // Root popupmenuitem - mi.ptszName = m_tszUserName; - mi.position = -1999901010; - mi.hParentMenu = HGENMENU_ROOT; - mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - mi.icolibItem = GetIconHandle(IDI_MAIN); - hRoot = hMenuRoot = Menu_AddProtoMenuItem(&mi); - } - else { - if (hMenuRoot) - CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); - hMenuRoot = NULL; - } - - mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; - mi.pszName = LPGEN("&Quick connect"); - mi.icolibItem = GetIconHandle(IDI_QUICK); - strcpy( d, IRC_QUICKCONNECT ); - mi.position = 201001; - mi.hParentMenu = hRoot; - hMenuQuick = Menu_AddProtoMenuItem(&mi); - - if (m_iStatus != ID_STATUS_OFFLINE) mi.flags |= CMIF_GRAYED; - - mi.pszName = LPGEN("&Join channel"); - mi.icolibItem = LoadSkinnedIconHandle(SKINICON_CHAT_JOIN);//GetIconHandle(IDI_JOIN); - strcpy( d, IRC_JOINCHANNEL ); - mi.position = 201002; - hMenuJoin = Menu_AddProtoMenuItem(&mi); - - mi.pszName = LPGEN("&Change your nickname"); - mi.icolibItem = GetIconHandle(IDI_RENAME); - strcpy( d, IRC_CHANGENICK ); - mi.position = 201003; - hMenuNick = Menu_AddProtoMenuItem(&mi); - - mi.pszName = LPGEN("Show the &list of available channels"); - mi.icolibItem = GetIconHandle(IDI_LIST); - strcpy( d, IRC_SHOWLIST ); - mi.position = 201004; - hMenuList = Menu_AddProtoMenuItem(&mi); - - if (m_useServer) mi.flags &= ~CMIF_GRAYED; - mi.pszName = LPGEN("&Show the server window"); - mi.icolibItem = GetIconHandle(IDI_SERVER); - strcpy( d, IRC_SHOWSERVER ); - mi.position = 201005; - hMenuServer = Menu_AddProtoMenuItem(&mi); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static HGENMENU hUMenuChanSettings, hUMenuWhois, hUMenuDisconnect, hUMenuIgnore; -static HANDLE hPreBuildContactMenu, hMenuChanSettings, hMenuWhois, hMenuDisconnect, hMenuIgnore; - -static CIrcProto* IrcGetInstanceByHContact(HANDLE hContact) -{ - char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); - if (szProto == NULL) - return NULL; - - for (int i = 0; i < g_Instances.getCount(); i++) - if (!strcmp(szProto, g_Instances[i]->m_szModuleName)) - return g_Instances[i]; - - return NULL; -} - -static INT_PTR IrcMenuChanSettings(WPARAM wParam, LPARAM lParam) -{ - CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnMenuChanSettings(wParam, lParam) : 0; -} - -static INT_PTR IrcMenuWhois(WPARAM wParam, LPARAM lParam) -{ - CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnMenuWhois(wParam, lParam) : 0; -} - -static INT_PTR IrcMenuDisconnect(WPARAM wParam, LPARAM lParam) -{ - CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnMenuDisconnect(wParam, lParam) : 0; -} - -static INT_PTR IrcMenuIgnore(WPARAM wParam, LPARAM lParam) -{ - CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnMenuIgnore(wParam, lParam) : 0; -} - -int IrcPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) -{ - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); - - CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnMenuPreBuild(wParam, lParam) : 0; -} - -void InitContactMenus(void) -{ - char temp[MAXMODULELABELLENGTH]; - char *d = temp + sprintf(temp, "IRC"); - - CLISTMENUITEM mi = {0}; - mi.cbSize = sizeof(mi); - mi.pszService = temp; - mi.flags = CMIF_ICONFROMICOLIB; - - mi.pszName = LPGEN("Channel &settings"); - mi.icolibItem = GetIconHandle(IDI_MANAGER); - strcpy(d, IRC_UM_CHANSETTINGS); - mi.popupPosition = 500090002; - hUMenuChanSettings = Menu_AddContactMenuItem(&mi); - hMenuChanSettings = CreateServiceFunction(temp, IrcMenuChanSettings); - - mi.pszName = LPGEN("&WhoIs info"); - mi.icolibItem = GetIconHandle(IDI_WHOIS); - strcpy(d, IRC_UM_WHOIS); - mi.popupPosition = 500090001; - hUMenuWhois = Menu_AddContactMenuItem(&mi); - hMenuWhois = CreateServiceFunction(temp, IrcMenuWhois); - - mi.pszName = LPGEN("Di&sconnect"); - mi.icolibItem = GetIconHandle(IDI_DELETE); - strcpy(d, IRC_UM_DISCONNECT); - mi.popupPosition = 500090001; - hUMenuDisconnect = Menu_AddContactMenuItem(&mi); - hMenuDisconnect = CreateServiceFunction(temp, IrcMenuDisconnect); - - mi.pszName = LPGEN("&Add to ignore list"); - mi.icolibItem = GetIconHandle(IDI_BLOCK); - strcpy(d, IRC_UM_IGNORE); - mi.popupPosition = 500090002; - hUMenuIgnore = Menu_AddContactMenuItem(&mi); - hMenuIgnore = CreateServiceFunction( temp, IrcMenuIgnore ); - - hPreBuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, IrcPrebuildContactMenu); -} - -void UninitContactMenus(void) -{ - UnhookEvent(hPreBuildContactMenu); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuChanSettings, 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuWhois, 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuDisconnect, 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuIgnore, 0); - DestroyServiceFunction(hMenuChanSettings); - DestroyServiceFunction(hMenuWhois); - DestroyServiceFunction(hMenuDisconnect); - DestroyServiceFunction(hMenuIgnore); -} - -INT_PTR __cdecl CIrcProto::OnDoubleclicked(WPARAM, LPARAM lParam) -{ - if (!lParam) - return 0; - - CLISTEVENT* pcle = (CLISTEVENT*)lParam; - - if ( getByte((HANDLE) pcle->hContact, "DCC", 0) != 0) { - DCCINFO* pdci = ( DCCINFO* )pcle->lParam; - CMessageBoxDlg* dlg = new CMessageBoxDlg( this, pdci ); - dlg->Show(); - HWND hWnd = dlg->GetHwnd(); - TCHAR szTemp[500]; - mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("%s (%s) is requesting a client-to-client chat connection."), - pdci->sContactName.c_str(), pdci->sHostmask.c_str()); - SetDlgItemText( hWnd, IDC_TEXT, szTemp ); - ShowWindow( hWnd, SW_SHOW ); - return 1; - } - return 0; -} - -int __cdecl CIrcProto::OnContactDeleted(WPARAM wp, LPARAM) -{ - HANDLE hContact = ( HANDLE )wp; - if ( !hContact ) - return 0; - - DBVARIANT dbv; - if ( !getTString( hContact, "Nick", &dbv )) { - int type = getByte( hContact, "ChatRoom", 0 ); - if ( type != 0 ) { - GCEVENT gce = {0}; - GCDEST gcd = {0}; - CMString S = _T(""); - if (type == GCW_CHATROOM) - S = MakeWndID( dbv.ptszVal ); - if (type == GCW_SERVER) - S = SERVERWINDOW; - gce.cbSize = sizeof(GCEVENT); - gce.dwItemData = 0; - gcd.iType = GC_EVENT_CONTROL; - gcd.pszModule = m_szModuleName; - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - gcd.ptszID = ( TCHAR* )S.c_str(); - int i = CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); - if (i && type == GCW_CHATROOM) - PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); - } - else { - BYTE bDCC = getByte(( HANDLE )wp, "DCC", 0) ; - if ( bDCC ) { - CDccSession* dcc = FindDCCSession((HANDLE)wp); - if ( dcc ) - dcc->Disconnect(); - } } - - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnJoinChat(WPARAM wp, LPARAM) -{ - if (!wp ) - return 0; - - DBVARIANT dbv; - if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { - if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) - PostIrcMessage( _T("/JOIN %s"), dbv.ptszVal); - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnLeaveChat(WPARAM wp, LPARAM) -{ - if (!wp ) - return 0; - - DBVARIANT dbv; - if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { - if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) { - PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); - - GCEVENT gce = {0}; - GCDEST gcd = {0}; - CMString S = MakeWndID(dbv.ptszVal); - gce.cbSize = sizeof(GCEVENT); - gce.dwFlags = GC_TCHAR; - gcd.iType = GC_EVENT_CONTROL; - gcd.pszModule = m_szModuleName; - gce.pDest = &gcd; - gcd.ptszID = ( TCHAR* )S.c_str(); - CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); - } - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnMenuChanSettings(WPARAM wp, LPARAM) -{ - if (!wp ) - return 0; - - HANDLE hContact = (HANDLE) wp; - DBVARIANT dbv; - if ( !getTString( hContact, "Nick", &dbv )) { - PostIrcMessageWnd(dbv.ptszVal, NULL, _T("/CHANNELMANAGER")); - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnMenuWhois(WPARAM wp, LPARAM) -{ - if ( !wp ) - return 0; - - DBVARIANT dbv; - - if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { - PostIrcMessage( _T("/WHOIS %s %s"), dbv.ptszVal, dbv.ptszVal); - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnMenuDisconnect(WPARAM wp, LPARAM) -{ - CDccSession* dcc = FindDCCSession((HANDLE)wp); - if ( dcc ) - dcc->Disconnect(); - return 0; -} - -INT_PTR __cdecl CIrcProto::OnMenuIgnore(WPARAM wp, LPARAM) -{ - if ( !wp ) - return 0; - - HANDLE hContact = (HANDLE) wp; - DBVARIANT dbv; - if ( !getTString( hContact, "Nick", &dbv )) { - if ( getByte(( HANDLE )wp, "ChatRoom", 0) == 0 ) { - char* host = NULL; - DBVARIANT dbv1; - if ( !getString((HANDLE) wp, "Host", &dbv1)) - host = dbv1.pszVal; - - if ( host ) { - String S; - if (m_ignoreChannelDefault) - S = "+qnidcm"; - else - S = "+qnidc"; - PostIrcMessage( _T("/IGNORE %%question=\"%s\",\"%s\",\"*!*@") _T(TCHAR_STR_PARAM) _T("\" %s"), - TranslateT("Please enter the hostmask (nick!user@host) \nNOTE! Contacts on your contact list are never ignored"), - TranslateT("Ignore"), host, S.c_str()); - DBFreeVariant(&dbv1); - } - } - DBFreeVariant(&dbv); - } - return 0; -} - -INT_PTR __cdecl CIrcProto::OnJoinMenuCommand(WPARAM, LPARAM) -{ - if ( !m_joinDlg ) { - m_joinDlg = new CJoinDlg( this ); - m_joinDlg->Show(); - } - - SetDlgItemText( m_joinDlg->GetHwnd(), IDC_CAPTION, TranslateT("Join channel")); - SetWindowText( GetDlgItem( m_joinDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a channel to join")); - SendMessage( GetDlgItem( m_joinDlg->GetHwnd(), IDC_ENICK), EM_SETSEL, 0,MAKELPARAM(0,-1)); - ShowWindow( m_joinDlg->GetHwnd(), SW_SHOW); - SetActiveWindow( m_joinDlg->GetHwnd()); - return 0; -} - -INT_PTR __cdecl CIrcProto::OnQuickConnectMenuCommand(WPARAM, LPARAM) -{ - if ( !m_quickDlg ) { - m_quickDlg = new CQuickDlg( this ); - m_quickDlg->Show(); - - SetWindowText( m_quickDlg->GetHwnd(), TranslateT( "Quick connect" )); - SetDlgItemText( m_quickDlg->GetHwnd(), IDC_TEXT, TranslateT( "Please select IRC network and enter the password if needed" )); - SetDlgItemText( m_quickDlg->GetHwnd(), IDC_CAPTION, TranslateT( "Quick connect" )); - WindowSetIcon( m_quickDlg->GetHwnd(), IDI_QUICK ); - } - - ShowWindow( m_quickDlg->GetHwnd(), SW_SHOW ); - SetActiveWindow( m_quickDlg->GetHwnd()); - return 0; -} - -INT_PTR __cdecl CIrcProto::OnShowListMenuCommand(WPARAM, LPARAM) -{ - PostIrcMessage( _T("/LIST")); - return 0; -} - -INT_PTR __cdecl CIrcProto::OnShowServerMenuCommand(WPARAM, LPARAM) -{ - GCEVENT gce = {0}; - GCDEST gcd = {0}; - gcd.iType = GC_EVENT_CONTROL; - gcd.ptszID = SERVERWINDOW; - gce.dwFlags = GC_TCHAR; - gcd.pszModule = m_szModuleName; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); - return 0; -} - -INT_PTR __cdecl CIrcProto::OnChangeNickMenuCommand(WPARAM, LPARAM) -{ - if ( !m_nickDlg ) { - m_nickDlg = new CNickDlg( this ); - m_nickDlg->Show(); - } - - SetDlgItemText( m_nickDlg->GetHwnd(), IDC_CAPTION, TranslateT("Change nick name")); - SetWindowText( GetDlgItem( m_nickDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a unique nickname")); - m_nickDlg->m_Enick.SetText( m_info.sNick.c_str()); - m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); - ShowWindow( m_nickDlg->GetHwnd(), SW_SHOW); - SetActiveWindow( m_nickDlg->GetHwnd()); - return 0; -} - -static void DoChatFormatting( TCHAR* pszText ) -{ - TCHAR* p1 = pszText; - int iFG = -1; - int iRemoveChars; - TCHAR InsertThis[50]; - - while (*p1 != '\0') { - iRemoveChars = 0; - InsertThis[0] = 0; - - if ( *p1 == '%' ) { - switch ( p1[1] ) { - case 'B': - case 'b': - lstrcpy(InsertThis, _T("\002")); - iRemoveChars = 2; - break; - case 'I': - case 'i': - lstrcpy(InsertThis, _T("\026")); - iRemoveChars = 2; - break; - case 'U': - case 'u': - lstrcpy(InsertThis, _T("\037")); - iRemoveChars = 2; - break; - case 'c': - { - lstrcpy(InsertThis, _T("\003")); - iRemoveChars = 2; - - TCHAR szTemp[3]; - lstrcpyn(szTemp, p1 + 2, 3); - iFG = _ttoi(szTemp); - } - break; - case 'C': - if ( p1[2] == '%' && p1[3] == 'F') { - lstrcpy(InsertThis, _T("\00399,99")); - iRemoveChars = 4; - } - else { - lstrcpy(InsertThis, _T("\00399")); - iRemoveChars = 2; - } - iFG = -1; - break; - case 'f': - if (p1 - 3 >= pszText && p1[-3] == '\003') - lstrcpy(InsertThis, _T(",")); - else if ( iFG >= 0 ) - mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,"), iFG); - else - lstrcpy(InsertThis, _T("\00399,")); - - iRemoveChars = 2; - break; - - case 'F': - if (iFG >= 0) - mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,99"), iFG); - else - lstrcpy(InsertThis, _T("\00399,99")); - iRemoveChars = 2; - break; - - case '%': - lstrcpy(InsertThis, _T("%")); - iRemoveChars = 2; - break; - - default: - iRemoveChars = 2; - break; - } - - MoveMemory(p1 + lstrlen(InsertThis), p1 + iRemoveChars, sizeof(TCHAR)*(lstrlen(p1) - iRemoveChars + 1)); - CopyMemory(p1, InsertThis, sizeof(TCHAR)*lstrlen(InsertThis)); - if (iRemoveChars || lstrlen(InsertThis)) - p1 += lstrlen(InsertThis); - else - p1++; - } - else p1++; -} } - -int __cdecl CIrcProto::GCEventHook(WPARAM wParam,LPARAM lParam) -{ - GCHOOK *gchook= (GCHOOK*) lParam; - GCHOOK *gchtemp = NULL; - GCHOOK *gch = NULL; - CMString S = _T(""); - - EnterCriticalSection(&m_gchook); - - // handle the hook - if ( gchook ) { - if (!lstrcmpiA(gchook->pDest->pszModule, m_szModuleName)) { - - // first see if the scripting module should modify or stop this event - if (m_bMbotInstalled && m_scriptingEnabled && wParam == NULL) { - gchtemp = (GCHOOK *)mir_alloc(sizeof(GCHOOK)); - gchtemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); - gchtemp->pDest->iType = gchook->pDest->iType; - gchtemp->dwData = gchook->dwData; - - if ( gchook->pDest->ptszID ) { - gchtemp->pDest->ptszID = mir_tstrdup( gchook->pDest->ptszID ); - TCHAR* pTemp = _tcschr(gchtemp->pDest->ptszID, ' '); - if ( pTemp ) - *pTemp = '\0'; - } - else gchtemp->pDest->ptszID = NULL; - - //MBOT CORRECTIONS - gchook->pDest->pszModule = mir_strdup( gchook->pDest->pszModule ); - gchook->ptszText = mir_tstrdup( gchook->ptszText ); - gchook->ptszUID = mir_tstrdup( gchook->ptszUID ); - - if ( Scripting_TriggerMSPGuiOut(gchtemp) && gchtemp) - gch = gchtemp; - else - gch = NULL; - } - else gch = gchook; - - if ( gch ) { - TCHAR* p1 = mir_tstrdup( gch->pDest->ptszID ); - TCHAR* p2 = _tcsstr( p1, _T(" - ")); - if ( p2 ) - *p2 = '\0'; - - switch( gch->pDest->iType ) { - case GC_SESSION_TERMINATE: - FreeWindowItemData(p1, (CHANNELINFO*)gch->dwData); - break; - - case GC_USER_MESSAGE: - if (gch && gch->pszText && lstrlen(gch->ptszText) > 0 ) { - TCHAR* pszText = new TCHAR[lstrlen(gch->ptszText)+1000]; - lstrcpy(pszText, gch->ptszText); - DoChatFormatting(pszText); - PostIrcMessageWnd(p1, NULL, pszText); - delete []pszText; - } - break; - - case GC_USER_CHANMGR: - PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); - break; - - case GC_USER_PRIVMESS: - { - TCHAR szTemp[4000]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/QUERY %s"), gch->ptszUID ); - PostIrcMessageWnd(p1, NULL, szTemp); - } - break; - - case GC_USER_LOGMENU: - switch( gch->dwData ) { - case 1: - OnChangeNickMenuCommand(NULL, NULL); - break; - case 2: - PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); - break; - - case 3: - PostIrcMessage( _T("/PART %s %s"), p1, m_userInfo ); - { GCEVENT gce = {0}; - GCDEST gcd = {0}; - S = MakeWndID(p1); - gce.cbSize = sizeof(GCEVENT); - gcd.iType = GC_EVENT_CONTROL; - gcd.pszModule = m_szModuleName; - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - gcd.ptszID = ( TCHAR* )S.c_str(); - CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); - } - break; - case 4: // show server window - PostIrcMessageWnd(p1, NULL, _T("/SERVERSHOW")); - break; -/* case 5: // nickserv register nick - PostIrcMessage( _T("/nickserv REGISTER %%question=\"%s\",\"%s\""), - TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); - break; -*/ case 6: // nickserv Identify - PostIrcMessage( _T("/nickserv AUTH %%question=\"%s\",\"%s\""), - TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); - break; - case 7: // nickserv drop nick - if (MessageBox(0, TranslateT("Are you sure you want to unregister your current nick?"), TranslateT("Delete nick"), - MB_ICONERROR + MB_YESNO + MB_DEFBUTTON2) == IDYES) - PostIrcMessage( _T("/nickserv DROP")); - break; - case 8: // nickserv Identify - { - CQuestionDlg* dlg = new CQuestionDlg( this ); - dlg->Show(); - HWND question_hWnd = dlg->GetHwnd(); - HWND hEditCtrl = GetDlgItem( question_hWnd, IDC_EDIT); - SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Identify nick")); - SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter your password")); - SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, _T("/nickserv IDENTIFY %question=\"%s\",\"%s\"")); - SetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE, - (LONG)GetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE) | ES_PASSWORD); - SendMessage(hEditCtrl, EM_SETPASSWORDCHAR,(WPARAM)_T('*'),0 ); - SetFocus(hEditCtrl); - dlg->Activate(); - } - break; - case 9: // nickserv remind password - { - DBVARIANT dbv; - if ( !getTString( "Nick", &dbv )) { - PostIrcMessage( _T("/nickserv SENDPASS %s"), dbv.ptszVal); - DBFreeVariant( &dbv ); - } } - break; - case 10: // nickserv set new password - PostIrcMessage( _T("/nickserv SET PASSWORD %%question=\"%s\",\"%s\""), - TranslateT("Please enter your new password"), TranslateT("Set new password")); - break; - case 11: // nickserv set language - PostIrcMessage( _T("/nickserv SET LANGUAGE %%question=\"%s\",\"%s\""), - TranslateT("Please enter desired languageID (numeric value, depends on server)"), TranslateT("Change language of NickServ messages")); - break; - case 12: // nickserv set homepage - PostIrcMessage( _T("/nickserv SET URL %%question=\"%s\",\"%s\""), - TranslateT("Please enter URL that will be linked to your nick"), TranslateT("Set URL, linked to nick")); - break; - case 13: // nickserv set email - PostIrcMessage( _T("/nickserv SET EMAIL %%question=\"%s\",\"%s\""), - TranslateT("Please enter your e-mail, that will be linked to your nick"), TranslateT("Set e-mail, linked to nick")); - break; - case 14: // nickserv set info - PostIrcMessage( _T("/nickserv SET INFO %%question=\"%s\",\"%s\""), - TranslateT("Please enter some information about your nick"), TranslateT("Set information for nick")); - break; - case 15: // nickserv kill unauth off - PostIrcMessage( _T("/nickserv SET KILL OFF")); - break; - case 16: // nickserv kill unauth on - PostIrcMessage( _T("/nickserv SET KILL ON")); - break; - case 17: // nickserv kill unauth quick - PostIrcMessage( _T("/nickserv SET KILL QUICK")); - break; - case 18: // nickserv hide nick from /LIST - PostIrcMessage( _T("/nickserv SET PRIVATE ON")); - break; - case 19: // nickserv show nick to /LIST - PostIrcMessage( _T("/nickserv SET PRIVATE OFF")); - break; - case 20: // nickserv Hide e-mail from info - PostIrcMessage( _T("/nickserv SET HIDE EMAIL ON")); - break; - case 21: // nickserv Show e-mail in info - PostIrcMessage( _T("/nickserv SET HIDE EMAIL OFF")); - break; - case 22: // nickserv Set security for nick - PostIrcMessage( _T("/nickserv SET SECURE ON")); - break; - case 23: // nickserv Remove security for nick - PostIrcMessage( _T("/nickserv SET SECURE OFF")); - break; - case 24: // nickserv Link nick to current - PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), - TranslateT("Please enter nick you want to link to your current nick"), TranslateT("Link another nick to current nick")); - break; - case 25: // nickserv Unlink nick from current - PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), - TranslateT("Please enter nick you want to unlink from your current nick"), TranslateT("Unlink another nick from current nick")); - break; - case 26: // nickserv Set main nick - PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), - TranslateT("Please enter nick you want to set as your main nick"), TranslateT("Set main nick")); - break; - case 27: // nickserv list all linked nicks - PostIrcMessage( _T("/nickserv LISTLINKS")); - break; - case 28: // nickserv list all channels owned - PostIrcMessage( _T("/nickserv LISTCHANS")); - break; - } - break; - - case GC_USER_NICKLISTMENU: - switch(gch->dwData) { - case 1: - PostIrcMessage( _T("/MODE %s +o %s"), p1, gch->ptszUID ); - break; - case 2: - PostIrcMessage( _T("/MODE %s -o %s"), p1, gch->ptszUID ); - break; - case 3: - PostIrcMessage( _T("/MODE %s +v %s"), p1, gch->ptszUID ); - break; - case 4: - PostIrcMessage( _T("/MODE %s -v %s"), p1, gch->ptszUID ); - break; - case 5: - PostIrcMessage( _T("/KICK %s %s"), p1, gch->ptszUID ); - break; - case 6: - PostIrcMessage( _T("/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), - p1, gch->ptszUID, TranslateT("Please enter the reason"), TranslateT("Kick"), TranslateT("Jerk")); - break; - case 7: - DoUserhostWithReason(1, _T("B") + (CMString)p1, true, _T("%s"), gch->ptszUID ); - break; - case 8: - DoUserhostWithReason(1, _T("K") + (CMString)p1, true, _T("%s"), gch->ptszUID ); - break; - case 9: - DoUserhostWithReason(1, _T("L") + (CMString)p1, true, _T("%s"), gch->ptszUID ); - break; - case 10: - PostIrcMessage( _T("/WHOIS %s %s"), gch->ptszUID, gch->ptszUID ); - break; - // case 11: - // DoUserhostWithReason(1, "I", true, "%s", gch->ptszUID ); - // break; - // case 12: - // DoUserhostWithReason(1, "J", true, "%s", gch->ptszUID ); - // break; - case 13: - PostIrcMessage( _T("/DCC CHAT %s"), gch->ptszUID ); - break; - case 14: - PostIrcMessage( _T("/DCC SEND %s"), gch->ptszUID ); - break; - case 15: - DoUserhostWithReason(1, _T("I"), true, _T("%s"), gch->ptszUID ); - break; - case 16: - PostIrcMessage( _T("/MODE %s +h %s"), p1, gch->ptszUID ); - break; - case 17: - PostIrcMessage( _T("/MODE %s -h %s"), p1, gch->ptszUID ); - break; - case 18: - PostIrcMessage( _T("/MODE %s +q %s"), p1, gch->ptszUID ); - break; - case 19: - PostIrcMessage( _T("/MODE %s -q %s"), p1, gch->ptszUID ); - break; - case 20: - PostIrcMessage( _T("/MODE %s +a %s"), p1, gch->ptszUID ); - break; - case 21: - PostIrcMessage( _T("/MODE %s -a %s"), p1, gch->ptszUID ); - break; - case 22: - PostIrcMessage( _T("/NOTICE %s %%question=\"%s\",\"%s\""), - gch->ptszUID, TranslateT("Please enter the notice text"), TranslateT("Send notice")); - break; - case 23: - PostIrcMessage( _T("/INVITE %s %%question=\"%s\",\"%s\""), - gch->ptszUID, TranslateT("Please enter the channel name to invite to"), TranslateT("Invite to channel")); - break; - case 30: - { - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_TCHAR; - psr.id = gch->ptszUID; - psr.nick = gch->ptszUID; - - ADDCONTACTSTRUCT acs = { 0 }; - acs.handleType = HANDLE_SEARCHRESULT; - acs.szProto = m_szModuleName; - acs.psr = &psr; - CallService( MS_ADDCONTACT_SHOW, (WPARAM)NULL, (LPARAM)&acs); - } - break; - case 31: //slap - { - TCHAR tszTemp[4000]; - mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/slap %s"), gch->ptszUID); - PostIrcMessageWnd(p1, NULL, tszTemp); - } - break; - case 32: //nickserv info - { - TCHAR tszTemp[4000]; - mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv INFO %s ALL"), gch->ptszUID); - PostIrcMessageWnd(p1, NULL, tszTemp); - } - break; - case 33: //nickserv ghost - { - TCHAR tszTemp[4000]; - mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv GHOST %s"), gch->ptszUID); - PostIrcMessageWnd(p1, NULL, tszTemp); - } - break; - } - break; - } - mir_free( p1 ); - } } } - - if ( gchtemp ) { - mir_free(gchtemp->pszUID); - mir_free(gchtemp->pszText); - mir_free(gchtemp->pDest->ptszID); - mir_free(gchtemp->pDest->pszModule); - mir_free(gchtemp->pDest); - mir_free(gchtemp); - } - LeaveCriticalSection(&m_gchook); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static gc_item logItems[] = { - { LPGENT("&Change your nickname" ), 1, MENU_ITEM, FALSE }, - { LPGENT("Channel &settings" ), 2, MENU_ITEM, FALSE }, - { _T(""), 0, MENU_SEPARATOR, FALSE }, - { LPGENT("NickServ"), 0, MENU_NEWPOPUP, FALSE }, - { LPGENT("Register nick" ), 5, MENU_POPUPITEM, TRUE }, - { LPGENT("Auth nick" ), 6, MENU_POPUPITEM, FALSE }, - { LPGENT("Delete nick" ), 7, MENU_POPUPITEM, FALSE }, - { LPGENT("Identify nick" ), 8, MENU_POPUPITEM, FALSE }, - { LPGENT("Remind password " ), 9, MENU_POPUPITEM, FALSE }, - { LPGENT("Set new password" ), 10, MENU_POPUPITEM, TRUE }, - { LPGENT("Set language" ), 11, MENU_POPUPITEM, FALSE }, - { LPGENT("Set homepage" ), 12, MENU_POPUPITEM, FALSE }, - { LPGENT("Set e-mail" ), 13, MENU_POPUPITEM, FALSE }, - { LPGENT("Set info" ), 14, MENU_POPUPITEM, FALSE }, - { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("Hide e-mail from info" ), 20, MENU_POPUPITEM, FALSE }, - { LPGENT("Show e-mail in info" ), 21, MENU_POPUPITEM, FALSE }, - { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("Set security for nick" ), 22, MENU_POPUPITEM, FALSE }, - { LPGENT("Remove security for nick" ), 23, MENU_POPUPITEM, FALSE }, - { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("Link nick to current" ), 24, MENU_POPUPITEM, FALSE }, - { LPGENT("Unlink nick from current" ), 25, MENU_POPUPITEM, FALSE }, - { LPGENT("Set main nick" ), 26, MENU_POPUPITEM, FALSE }, - { LPGENT("List all your nicks" ), 27, MENU_POPUPITEM, FALSE }, - { LPGENT("List your channels" ), 28, MENU_POPUPITEM, FALSE }, - { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("Kill unauthorized: off" ), 15, MENU_POPUPITEM, FALSE }, - { LPGENT("Kill unauthorized: on" ), 16, MENU_POPUPITEM, FALSE }, - { LPGENT("Kill unauthorized: quick" ), 17, MENU_POPUPITEM, FALSE }, - { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("Hide nick from list" ), 18, MENU_POPUPITEM, FALSE }, - { LPGENT("Show nick to list" ), 19, MENU_POPUPITEM, FALSE }, - { LPGENT("Show the server &window" ), 4, MENU_ITEM, FALSE }, - { _T(""), 0, MENU_SEPARATOR, FALSE }, - { LPGENT("&Leave the channel" ), 3, MENU_ITEM, FALSE } -}; - -static gc_item nickItems[] = { - { LPGENT("&WhoIs info"), 10, MENU_ITEM, FALSE }, //0 - { LPGENT("&Invite to channel"), 23, MENU_ITEM, FALSE }, - { LPGENT("Send ¬ice"), 22, MENU_ITEM, FALSE }, - { LPGENT("&Slap"), 31, MENU_ITEM, FALSE }, - { LPGENT("Nickserv info"), 32, MENU_ITEM, FALSE }, - { LPGENT("Nickserv kill ghost"), 33, MENU_ITEM, FALSE }, //5 - { LPGENT("&Control"), 0, MENU_NEWPOPUP, FALSE }, - { LPGENT("Give Owner"), 18, MENU_POPUPITEM, FALSE }, //7 - { LPGENT("Take Owner"), 19, MENU_POPUPITEM, FALSE }, - { LPGENT("Give Admin"), 20, MENU_POPUPITEM, FALSE }, - { LPGENT("Take Admin"), 21, MENU_POPUPITEM, FALSE }, //10 - { LPGENT("Give &Op"), 1, MENU_POPUPITEM, FALSE }, - { LPGENT("Take O&p"), 2, MENU_POPUPITEM, FALSE }, - { LPGENT("Give &Halfop"), 16, MENU_POPUPITEM, FALSE }, - { LPGENT("Take H&alfop"), 17, MENU_POPUPITEM, FALSE }, - { LPGENT("Give &Voice"), 3, MENU_POPUPITEM, FALSE }, //15 - { LPGENT("Take V&oice"), 4, MENU_POPUPITEM, FALSE }, - { _T(""), 0, MENU_POPUPSEPARATOR, FALSE }, - { LPGENT("&Kick"), 5, MENU_POPUPITEM, FALSE }, - { LPGENT("Ki&ck (reason)"), 6, MENU_POPUPITEM, FALSE }, - { LPGENT("&Ban"), 7, MENU_POPUPITEM, FALSE }, //20 - { LPGENT("Ban'&n kick"), 8, MENU_POPUPITEM, FALSE }, - { LPGENT("Ban'n kick (&reason)"), 9, MENU_POPUPITEM, FALSE }, - { LPGENT("&Direct Connection"), 0, MENU_NEWPOPUP, FALSE }, - { LPGENT("Request &Chat"), 13, MENU_POPUPITEM, FALSE }, - { LPGENT("Send &File"), 14, MENU_POPUPITEM, FALSE }, //25 - { LPGENT("Add to &ignore list"), 15, MENU_ITEM, FALSE }, - { _T(""), 12, MENU_SEPARATOR, FALSE }, - { LPGENT("&Add User"), 30, MENU_ITEM, FALSE } -}; - -int __cdecl CIrcProto::GCMenuHook(WPARAM, LPARAM lParam) -{ - GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam; - if ( gcmi ) { - if ( !lstrcmpiA( gcmi->pszModule, m_szModuleName )) { - if ( gcmi->Type == MENU_ON_LOG ) { - if ( lstrcmpi( gcmi->pszID, SERVERWINDOW)) { - gcmi->nItems = SIZEOF(logItems); - gcmi->Item = logItems; - } - else gcmi->nItems = 0; - } - - if (gcmi->Type == MENU_ON_NICKLIST) { - CONTACT user ={ (TCHAR*)gcmi->pszUID, NULL, NULL, false, false, false}; - HANDLE hContact = CList_FindContact(&user); - - gcmi->nItems = SIZEOF(nickItems); - gcmi->Item = nickItems; - BOOL bIsInList = (hContact && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 0); - gcmi->Item[gcmi->nItems-1].bDisabled = bIsInList; - - unsigned long ulAdr = 0; - if (m_manualHost) - ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); - else - ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); - gcmi->Item[23].bDisabled = ulAdr == 0?TRUE:FALSE; //DCC submenu - - TCHAR stzChanName[100]; - const TCHAR* temp = _tcschr( gcmi->pszID, ' ' ); - int len = min((( temp == NULL ) ? lstrlen( gcmi->pszID ) : ( int )( temp - gcmi->pszID + 1 )), SIZEOF(stzChanName)-1 ); - lstrcpyn( stzChanName, gcmi->pszID, len ); - stzChanName[ len ] = 0; - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA,stzChanName, NULL, NULL, NULL, NULL, NULL, false, false, 0); - BOOL bServOwner = strchr(sUserModes.c_str(), 'q') == NULL?FALSE:TRUE; - BOOL bServAdmin = strchr(sUserModes.c_str(), 'a') == NULL?FALSE:TRUE; - BOOL bOwner = bServOwner?((wi->OwnMode>>4)&01):FALSE; - BOOL bAdmin = bServAdmin?((wi->OwnMode>>3)&01):FALSE; - BOOL bOp = strchr(sUserModes.c_str(), 'o') == NULL?FALSE:((wi->OwnMode>>2)&01); - BOOL bHalfop = strchr(sUserModes.c_str(), 'h') == NULL?FALSE:((wi->OwnMode>>1)&01); - - BOOL bForceEnable = GetAsyncKeyState(VK_CONTROL); - - gcmi->Item[6].bDisabled /* "Control" submenu */ = !(bForceEnable|| bHalfop || bOp || bAdmin || bOwner); - gcmi->Item[7].uType = gcmi->Item[8].uType = /* +/- Owner */ bServOwner?MENU_POPUPITEM:0; - gcmi->Item[9].uType = gcmi->Item[10].uType = /* +/- Admin */ bServAdmin?MENU_POPUPITEM:0; - gcmi->Item[7].bDisabled = gcmi->Item[8].bDisabled = gcmi->Item[9].bDisabled = gcmi->Item[10].bDisabled = /* +/- Owner/Admin */ - !(bForceEnable || bOwner); - gcmi->Item[11].bDisabled = gcmi->Item[12].bDisabled = gcmi->Item[13].bDisabled = gcmi->Item[14].bDisabled = /* +/- Op/hop */ - !(bForceEnable || bOp || bAdmin || bOwner); - } } } - - return 0; -} - -int __cdecl CIrcProto::OnPreShutdown(WPARAM, LPARAM) -{ - EnterCriticalSection(&cs); - - if ( m_perform && IsConnected()) - if ( DoPerform( "Event: Disconnect" )) - Sleep( 200 ); - - DisconnectAllDCCSessions( true ); - - if ( IsConnected()) - Disconnect(); - if ( m_listDlg ) - m_listDlg->Close(); - if ( m_nickDlg ) - m_nickDlg->Close(); - if ( m_joinDlg ) - m_joinDlg->Close(); - - LeaveCriticalSection(&cs); - return 0; -} - -int __cdecl CIrcProto::OnMenuPreBuild(WPARAM wParam, LPARAM) -{ - DBVARIANT dbv; - HANDLE hContact = ( HANDLE )wParam; - if ( !hContact ) - return 0; - - CLISTMENUITEM clmi = { 0 }; - clmi.cbSize = sizeof( clmi ); - clmi.flags = CMIM_FLAGS | CMIM_NAME | CMIM_ICON; - - char *szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) wParam, 0); - if ( szProto && !lstrcmpiA(szProto, m_szModuleName)) { - bool bIsOnline = getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE ? false : true; - if ( getByte(hContact, "ChatRoom", 0) == GCW_CHATROOM) { - // context menu for chatrooms - clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); - } - else if ( !getTString( hContact, "Default", &dbv )) { - // context menu for contact - BYTE bDcc = getByte( hContact, "DCC", 0) ; - - clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); - - clmi.flags = CMIM_FLAGS; - if ( bDcc ) { - // for DCC contact - clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); - } - else { - // for normal contact - clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; - if ( !IsConnected()) - clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); - - if (bIsOnline) { - DBVARIANT dbv3; - if ( !getString( hContact, "Host", &dbv3)) { - if (dbv3.pszVal[0] == 0) - clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; - DBFreeVariant( &dbv3 ); - } - } - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); - } - DBFreeVariant( &dbv ); - } } - - return 0; -} - -int __cdecl CIrcProto::OnDbSettingChanged(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = ( HANDLE ) wParam; - if ( hContact == NULL || !IsConnected()) - return 0; - - DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam; - if ( strcmp( cws->szModule, "CList" )) - return 0; - - if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 )) - return 0; - - if ( !strcmp( cws->szSetting, "NotOnList" )) { - DBVARIANT dbv; - if ( !getTString( hContact, "Nick", &dbv )) { - if ( getByte( "MirVerAutoRequest", 1)) - PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), dbv.ptszVal ); - DBFreeVariant( &dbv ); - } } - return 0; -} -void __cdecl CIrcProto::ConnectServerThread( void* ) -{ - InterlockedIncrement((long *) &m_bConnectThreadRunning); - InterlockedIncrement((long *) &m_bConnectRequested); - while ( !Miranda_Terminated() && m_bConnectRequested > 0 ) { - while(m_bConnectRequested > 0) - InterlockedDecrement((long *) &m_bConnectRequested); - if (IsConnected()) { - Sleep(200); - Disconnect(); - } - - m_info.bNickFlag = false; - int Temp = m_iStatus; - m_iStatus = ID_STATUS_CONNECTING; - nickflag = true; - ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_CONNECTING); - Sleep(100); - EnterCriticalSection(&cs); - Connect(si); - LeaveCriticalSection(&cs); - if (IsConnected()) { - KillChatTimer( RetryTimer ); - - if ( m_mySpecifiedHost[0] ) - ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_mySpecifiedHost, IP_MANUAL )); - - DoEvent(GC_EVENT_CHANGESESSIONAME, SERVERWINDOW, NULL, m_info.sNetwork.c_str(), NULL, NULL, NULL, FALSE, TRUE); - } - else { - Temp = m_iDesiredStatus; - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); - ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_OFFLINE); - Sleep(100); - } } - - InterlockedDecrement((long *) &m_bConnectThreadRunning); -} - -void __cdecl CIrcProto::DisconnectServerThread( void* ) -{ - EnterCriticalSection( &cs ); - KillChatTimer( RetryTimer ); - if ( IsConnected()) - Disconnect(); - LeaveCriticalSection( &cs ); - return; -} - -void CIrcProto::ConnectToServer(void) -{ - m_portCount = StrToIntA(m_portStart); - si.sServer = GetWord(m_serverName, 0); - si.iPort = m_portCount; - si.sNick = m_nick; - si.sUserID = m_userID; - si.sFullName = m_name; - si.sPassword = m_password; - si.bIdentServer = ((m_ident) ? (true) : (false)); - si.iIdentServerPort = StrToInt(m_identPort); - si.sIdentServerType = m_identSystem; - si.m_iSSL = m_iSSL; - { TCHAR* p = mir_a2t( m_network ); - si.sNetwork = p; - mir_free(p); - } - m_iRetryCount = 1; - KillChatTimer(RetryTimer); - if (m_retry) { - if (StrToInt(m_retryWait)<10) - lstrcpy(m_retryWait, _T("10")); - SetChatTimer(RetryTimer, StrToInt(m_retryWait)*1000, RetryTimerProc); - } - - bPerformDone = false; - bTempDisableCheck = false; - bTempForceCheck = false; - m_iTempCheckTime = 0; - sChannelPrefixes = _T("&#"); - sUserModes = "ov"; - sUserModePrefixes = _T("@+"); - sChannelModes = "btnimklps"; - - if (!m_bConnectThreadRunning) - ircFork( &CIrcProto::ConnectServerThread, 0 ); - else if (m_bConnectRequested < 1) - InterlockedIncrement((long *) &m_bConnectRequested); - - TCHAR szTemp[300]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)"), - TranslateT("Connecting to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); - DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); -} - -void CIrcProto::DisconnectFromServer(void) -{ - GCEVENT gce = {0}; - GCDEST gcd = {0}; - - if ( m_perform && IsConnected()) - DoPerform( "Event: Disconnect" ); - - gcd.iType = GC_EVENT_CONTROL; - gcd.ptszID = NULL; // all windows - gcd.pszModule = m_szModuleName; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - - CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); - ircFork( &CIrcProto::DisconnectServerThread, 0 ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// GetMyAwayMsg - obtain the current away message - -INT_PTR __cdecl CIrcProto::GetMyAwayMsg(WPARAM wParam,LPARAM lParam) -{ - if (( int )wParam != m_iStatus ) - return 0; - - const TCHAR* p = m_statusMessage.c_str(); - - return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_t2u(p) : (INT_PTR)mir_t2a(p); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Service function creation - -VOID CALLBACK RetryTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) -{ - CIrcProto* ppro = GetTimerOwner( idEvent ); - if ( !ppro ) - return; - - if ( ppro->m_iRetryCount <= StrToInt( ppro->m_retryCount) && ppro->m_retry ) { - ppro->m_portCount++; - if ( ppro->m_portCount > StrToIntA( ppro->m_portEnd ) || StrToIntA( ppro->m_portEnd ) == 0 ) - ppro->m_portCount = StrToIntA( ppro->m_portStart ); - ppro->si.iPort = ppro->m_portCount; - - TCHAR szTemp[300]; - mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u, try %u)"), - TranslateT("Reconnecting to"), ppro->si.sNetwork.c_str(), ppro->si.sServer.c_str(), ppro->si.iPort, ppro->m_iRetryCount); - - ppro->DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); - - if ( !ppro->m_bConnectThreadRunning ) - ppro->ircFork( &CIrcProto::ConnectServerThread, 0 ); - else - ppro->m_bConnectRequested = true; - - ppro->m_iRetryCount++; - } - else ppro->KillChatTimer( ppro->RetryTimer ); -} - -// logs text into NetLib (stolen from Jabber ;)) -void CIrcProto::DoNetlibLog( const char* fmt, ... ) -{ - va_list vararg; - va_start( vararg, fmt ); - char* str = ( char* )alloca( 32000 ); - mir_vsnprintf( str, 32000, fmt, vararg ); - va_end( vararg ); - - CallService( MS_NETLIB_LOG, ( WPARAM )hNetlib, ( LPARAM )str ); -} diff --git a/protocols/IRCG/src/MString.cpp b/protocols/IRCG/src/MString.cpp new file mode 100644 index 0000000000..70016e427e --- /dev/null +++ b/protocols/IRCG/src/MString.cpp @@ -0,0 +1,201 @@ +#include "irc.h" +#include "MString.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +CNilMStringData CMBaseString::m_nil; + +CMStringData* CMBaseString::Allocate( int nChars, int nCharSize ) +{ + CMStringData* pData; + nChars++; // nil char + size_t nDataBytes = nCharSize * nChars; + size_t nTotalSize = nDataBytes + sizeof(CMStringData); + + pData = static_cast(malloc(nTotalSize)); + if (pData == NULL) + return NULL; + + pData->nRefs = 1; + pData->nAllocLength = nChars - 1; + pData->nDataLength = 0; + return pData; +} + +void CMBaseString::Free(CMStringData* pData) +{ + free(pData); +} + +CMStringData* CMBaseString::Realloc(CMStringData* pData, int nChars, int nCharSize) +{ + CMStringData* pNewData; + nChars++; // nil char + ULONG nDataBytes = nCharSize * nChars; + ULONG nTotalSize = nDataBytes + sizeof(CMStringData); + + pNewData = static_cast(realloc(pData, nTotalSize)); + if (pNewData == NULL) + return NULL; + + pNewData->nAllocLength = nChars - 1; + return pNewData; +} + +CMStringData* CMBaseString::GetNilString() +{ + m_nil.AddRef(); + return &m_nil; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CMStringData + +void* CMStringData::data() +{ + return (this + 1); +} + +void CMStringData::AddRef() +{ + InterlockedIncrement(&nRefs); +} + +bool CMStringData::IsLocked() const +{ + return nRefs < 0; +} + +bool CMStringData::IsShared() const +{ + return (nRefs > 1); +} + +void CMStringData::Lock() +{ + nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary + if ( nRefs == 0 ) + nRefs = -1; +} + +void CMStringData::Release() +{ + if (InterlockedDecrement(&nRefs) <= 0) + CMBaseString::Free(this); +} + +void CMStringData::Unlock() +{ + if (IsLocked()) + { + nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary + if (nRefs == 0) + nRefs = 1; + } +} + +CNilMStringData::CNilMStringData() +{ + nRefs = 2; // Never gets freed + nDataLength = 0; + nAllocLength = 0; + achNil[0] = 0; + achNil[1] = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT + +#if _MSC_VER < 1400 +static HINSTANCE hCrt = NULL; + +typedef int ( __cdecl *_vscprintf_func )( LPCSTR pszFormat, va_list args ); +static _vscprintf_func _vscprintf_ptr = NULL; + +typedef int ( __cdecl *_vscwprintf_func )( LPCWSTR pszFormat, va_list args ); +static _vscwprintf_func _vscwprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnprintf_func )( char*, size_t, const char*, va_list ); +static _vsnprintf_func _vsnprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnwprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static _vsnwprintf_func _vsnwprintf_ptr = NULL; + +typedef int ( __cdecl *vswprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static vswprintf_func vswprintf_ptr = NULL; + +typedef int ( __cdecl *vsprintf_func )( char*, size_t, const char*, va_list ); +static vsprintf_func vsprintf_ptr = NULL; + +static void checkCrt( void ) +{ + if ( hCrt == NULL ) { + hCrt = GetModuleHandleA( "msvcrt.dll" ); + _vscprintf_ptr = (_vscprintf_func)GetProcAddress( hCrt, "_vscprintf" ); + _vscwprintf_ptr = (_vscwprintf_func)GetProcAddress( hCrt, "_vscwprintf" ); + _vsnprintf_ptr = (_vsnprintf_func)GetProcAddress( hCrt, "_vsnprintf" ); + _vsnwprintf_ptr = (_vsnwprintf_func)GetProcAddress( hCrt, "_vsnwprintf" ); + vswprintf_ptr = (vswprintf_func)GetProcAddress( hCrt, "vswprintf" ); + vsprintf_ptr = (vsprintf_func)GetProcAddress( hCrt, "vsprintf" ); +} } +#endif + +int __stdcall ChTraitsCRT::GetFormattedLength( LPCWSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscwprintf_ptr != NULL ) + return _vscwprintf_ptr( pszFormat, args ); + + WCHAR buf[ 4000 ]; + return vswprintf_ptr( buf, SIZEOF(buf), pszFormat, args ); + #else + return _vscwprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT::Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vsnwprintf_ptr != NULL ) + return _vsnwprintf_ptr( pszBuffer, nLength, pszFormat, args ); + + return vswprintf_ptr( pszBuffer, nLength, pszFormat, args ); + #else + return _vsnwprintf( pszBuffer, nLength, pszFormat, args ); + #endif +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT + +int __stdcall ChTraitsCRT::GetFormattedLength( LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscprintf_ptr != NULL ) + return _vscprintf_ptr( pszFormat, args ); + + char buf[4000]; + return vsprintf_ptr( buf, sizeof(buf), pszFormat, args ); + #else + return _vscprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT::Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + return _vsnprintf( pszBuffer, nlength, pszFormat, args ); + #else + return vsprintf_s( pszBuffer, nlength, pszFormat, args ); + #endif +} + diff --git a/protocols/IRCG/src/MString.h b/protocols/IRCG/src/MString.h new file mode 100644 index 0000000000..7cc16ff4a3 --- /dev/null +++ b/protocols/IRCG/src/MString.h @@ -0,0 +1,2300 @@ +#pragma once + +#include +#include +#include + +#ifdef __MINGW32__ +#include + +__inline size_t strnlen(const char *string, size_t maxlen) +{ + const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} +__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) +{ + const wchar_t *end = wmemchr (string, L'\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +/* FIXME: This may be wrong assumption about _AtlGetConversionACP */ +#define _AtlGetConversionACP() CP_THREAD_ACP +/* FIXME: This is unsafe */ +#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) +/* FIXME: This is quite silly implementation of _mbsstr */ +#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) +#define __max(x,y) (((x)<(y))?(y):(x)) +#endif /* __MINGW32__ */ + +struct CMStringData +{ + int nDataLength; // Length of currently used data in XCHARs (not including terminating null) + int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) + long nRefs; // Reference count: negative == locked + // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data + void* data(); + void AddRef(); + bool IsLocked() const; + bool IsShared() const; + void Lock(); + void Release(); + void Unlock(); +}; + +class CNilMStringData : public CMStringData +{ +public: + CNilMStringData(); + +public: + wchar_t achNil[2]; +}; + +template< typename BaseType = char > +class ChTraitsBase +{ +public: + typedef char XCHAR; + typedef LPSTR PXSTR; + typedef LPCSTR PCXSTR; + typedef wchar_t YCHAR; + typedef LPWSTR PYSTR; + typedef LPCWSTR PCYSTR; +}; + +template<> +class ChTraitsBase< wchar_t > +{ +public: + typedef wchar_t XCHAR; + typedef LPWSTR PXSTR; + typedef LPCWSTR PCXSTR; + typedef char YCHAR; + typedef LPSTR PYSTR; + typedef LPCSTR PCYSTR; +}; + +class CMBaseString +{ +public: + static CMStringData* Allocate(int nChars, int nCharSize); + static void Free(CMStringData* pData); + static CMStringData* Realloc(CMStringData* pData, int nChars, int nCharSize); + +protected: + static CMStringData* GetNilString(); + static CNilMStringData m_nil; +}; + +template< typename BaseType > +class CMSimpleStringT : public CMBaseString +{ +public: + typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; + typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; + typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; + typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; + typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; + typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; + +public: + explicit CMSimpleStringT() + { + CMStringData* pData = GetNilString(); + Attach(pData); + } + + CMSimpleStringT(const CMSimpleStringT& strSrc) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pNewData = CloneData( pSrcData ); + Attach( pNewData ); + } + + CMSimpleStringT(PCXSTR pszSrc) + { + int nLength = StringLength( pszSrc ); + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if (pData != NULL) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pszSrc, nLength ); + } + } + CMSimpleStringT(const XCHAR* pchSrc, int nLength) + { + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if ( pData != NULL ) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pchSrc, nLength ); + } + } + ~CMSimpleStringT() + { + CMStringData* pData = GetData(); + pData->Release(); + } + + operator CMSimpleStringT&() + { + return *(CMSimpleStringT*)this; + } + + CMSimpleStringT& operator=(const CMSimpleStringT& strSrc ) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pOldData = GetData(); + if ( pSrcData != pOldData) + { + if ( pOldData->IsLocked()) + SetString( strSrc.GetString(), strSrc.GetLength()); + else + { + CMStringData* pNewData = CloneData( pSrcData ); + pOldData->Release(); + Attach( pNewData ); + } + } + + return *this; + } + + CMSimpleStringT& operator=(PCXSTR pszSrc) + { + SetString( pszSrc ); + return *this; + } + + CMSimpleStringT& operator+=( const CMSimpleStringT& strSrc ) + { + Append( strSrc ); + + return *this; + } + + CMSimpleStringT& operator+=( PCXSTR pszSrc ) + { + Append( pszSrc ); + + return *this; + } + CMSimpleStringT& operator+=( char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( unsigned char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( wchar_t ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + + XCHAR operator[]( int iChar ) const + { + return m_pszData[iChar]; + } + + operator PCXSTR() const + { + return m_pszData; + } + + PCXSTR c_str() const + { + return m_pszData; + } + + void Append( PCXSTR pszSrc ) + { + Append( pszSrc, StringLength( pszSrc )); + } + void Append( PCXSTR pszSrc, int nLength ) + { + // See comment in SetString() about why we do this + UINT_PTR nOffset = pszSrc - GetString(); + + UINT nOldLength = GetLength(); + if (nOldLength < 0) + { + // protects from underflow + nOldLength = 0; + } + + //Make sure we don't read pass end of the terminating NULL + int nSrcLength = StringLength(pszSrc); + nLength = nLength > nSrcLength ? nSrcLength: nLength; + + int nNewLength = nOldLength+nLength; + PXSTR pszBuffer = GetBuffer( nNewLength ); + if ( nOffset <= nOldLength ) + { + pszSrc = pszBuffer+nOffset; + // No need to call CopyCharsOverlapped, since the destination is + // beyond the end of the original buffer + } + CopyChars( pszBuffer+nOldLength, nLength, pszSrc, nLength ); + ReleaseBufferSetLength( nNewLength ); + } + void AppendChar( XCHAR ch ) + { + UINT nOldLength = GetLength(); + int nNewLength = nOldLength+1; + PXSTR pszBuffer = GetBuffer( nNewLength ); + pszBuffer[nOldLength] = ch; + ReleaseBufferSetLength( nNewLength ); + } + void Append( const CMSimpleStringT& strSrc ) + { + Append( strSrc.GetString(), strSrc.GetLength()); + } + void Empty() + { + CMStringData* pOldData = GetData(); + if ( pOldData->nDataLength == 0 ) + return; + + if ( pOldData->IsLocked()) + { + // Don't reallocate a locked buffer that's shrinking + SetLength( 0 ); + } + else + { + pOldData->Release(); + CMStringData* pNewData = GetNilString(); + Attach( pNewData ); + } + } + void FreeExtra() + { + CMStringData* pOldData = GetData(); + int nLength = pOldData->nDataLength; + if ( pOldData->nAllocLength == nLength ) + return; + + if ( !pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking + { + CMStringData* pNewData = Allocate( nLength, sizeof( XCHAR )); + if ( pNewData == NULL ) { + SetLength( nLength ); + return; + } + + CopyChars( PXSTR( pNewData->data()), nLength, PCXSTR( pOldData->data()), nLength ); + + pOldData->Release(); + Attach( pNewData ); + SetLength( nLength ); + } + } + + int GetAllocLength() const + { + return GetData()->nAllocLength; + } + XCHAR GetAt( int iChar ) const + { + return m_pszData[iChar]; + } + PXSTR GetBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + Fork( pData->nDataLength ); + + return m_pszData; + } + PXSTR GetBuffer( int nMinBufferLength ) + { + return PrepareWrite( nMinBufferLength ); + } + PXSTR GetBufferSetLength( int nLength ) + { + PXSTR pszBuffer = GetBuffer( nLength ); + SetLength( nLength ); + + return pszBuffer; + } + int GetLength() const + { + return GetData()->nDataLength; + } + + PCXSTR GetString() const + { + return m_pszData; + } + bool IsEmpty() const + { + return GetLength() == 0; + } + PXSTR LockBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + { + Fork( pData->nDataLength ); + pData = GetData(); // Do it again, because the fork might have changed it + } + pData->Lock(); + + return m_pszData; + } + void UnlockBuffer() + { + CMStringData* pData = GetData(); + pData->Unlock(); + } + void Preallocate( int nLength ) + { + PrepareWrite( nLength ); + } + void ReleaseBuffer( int nNewLength = -1 ) + { + if ( nNewLength == -1 ) + { + int nAlloc = GetData()->nAllocLength; + nNewLength = StringLengthN( m_pszData, nAlloc); + } + SetLength( nNewLength ); + } + void ReleaseBufferSetLength( int nNewLength ) + { + SetLength( nNewLength ); + } + void Truncate( int nNewLength ) + { + GetBuffer( nNewLength ); + ReleaseBufferSetLength( nNewLength ); + } + void SetAt( int iChar, XCHAR ch ) + { + int nLength = GetLength(); + PXSTR pszBuffer = GetBuffer(); + pszBuffer[iChar] = ch; + ReleaseBufferSetLength( nLength ); + + } + void SetString( PCXSTR pszSrc ) + { + SetString( pszSrc, StringLength( pszSrc )); + } + void SetString( PCXSTR pszSrc, int nLength ) + { + if ( nLength == 0 ) + { + Empty(); + } + else + { + + UINT nOldLength = GetLength(); + UINT_PTR nOffset = pszSrc - GetString(); + + PXSTR pszBuffer = GetBuffer( nLength ); + if ( nOffset <= nOldLength ) + { + CopyCharsOverlapped( pszBuffer, GetAllocLength(), + pszBuffer+nOffset, nLength ); + } + else + { + CopyChars( pszBuffer, GetAllocLength(), pszSrc, nLength ); + } + ReleaseBufferSetLength( nLength ); + } + } +public: + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength()); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, PCXSTR psz2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(PCXSTR psz1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return s; + } + + static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars ) + { + #if _MSC_VER >= 1400 + memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memcpy(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) + { + #if _MSC_VER >= 1400 + memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memmove(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + static int __stdcall StringLength(const char* psz) + { + if (psz == NULL) + { + return(0); + } + return (int(strlen(psz))); + } + static int __stdcall StringLength(const wchar_t* psz) + { + if (psz == NULL) + return 0; + + return int(wcslen(psz)); + } + static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( strnlen( psz, sizeInXChar )); + } + static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( wcsnlen( psz, sizeInXChar )); + } +protected: + static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) + { + int nNewLength = nLength1+nLength2; + PXSTR pszBuffer = strResult.GetBuffer(nNewLength); + CopyChars(pszBuffer, nLength1, psz1, nLength1 ); + CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); + strResult.ReleaseBufferSetLength(nNewLength); + } + // Implementation +private: + void Attach(CMStringData* pData) + { + m_pszData = static_cast(pData->data()); + } + void Fork(int nLength) + { + CMStringData* pOldData = GetData(); + int nOldLength = pOldData->nDataLength; + CMStringData* pNewData = Allocate(nLength, sizeof(XCHAR)); + if (pNewData != NULL) + { + int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0' + CopyChars( PXSTR( pNewData->data()), nCharsToCopy, PCXSTR( pOldData->data()), nCharsToCopy ); + pNewData->nDataLength = nOldLength; + pOldData->Release(); + Attach(pNewData); + } + } + CMStringData* GetData() const + { + return (reinterpret_cast(m_pszData) - 1); + } + PXSTR PrepareWrite( int nLength ) + { + CMStringData* pOldData = GetData(); + int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false + int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false + if ((nShared | nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data + PrepareWrite2(nLength); + + return m_pszData; + } + void PrepareWrite2(int nLength) + { + CMStringData* pOldData = GetData(); + if (pOldData->nDataLength > nLength) + nLength = pOldData->nDataLength; + + if (pOldData->IsShared()) + { + Fork(nLength); + } + else if (pOldData->nAllocLength < nLength) + { + // Grow exponentially, until we hit 1K. + int nNewLength = pOldData->nAllocLength; + if ( nNewLength > 1024 ) + nNewLength += 1024; + else + nNewLength *= 2; + + if ( nNewLength < nLength ) + nNewLength = nLength; + + Reallocate( nNewLength ); + } + } + void Reallocate( int nLength ) + { + CMStringData* pOldData = GetData(); + if ( pOldData->nAllocLength >= nLength || nLength <= 0) + return; + + CMStringData* pNewData = Realloc( pOldData, nLength, sizeof( XCHAR )); + if ( pNewData != NULL ) + Attach( pNewData ); + } + + void SetLength( int nLength ) + { + GetData()->nDataLength = nLength; + m_pszData[nLength] = 0; + } + + static CMStringData* __stdcall CloneData(CMStringData* pData) + { + CMStringData* pNewData = NULL; + + if (!pData->IsLocked()) { + pNewData = pData; + pNewData->AddRef(); + } + + return pNewData; + } + +public : + // typedef CStrBufT CStrBuf; +private: + PXSTR m_pszData; +}; + + +template< typename _CharType = char > +class ChTraitsCRT : public ChTraitsBase< _CharType > +{ +public: + static char* __stdcall CharNext( const char* p ) + { + return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ))); + } + + static int __stdcall IsDigit( char ch ) + { + return _ismbcdigit( ch ); + } + + static int __stdcall IsSpace( char ch ) + { + return _ismbcspace( ch ); + } + + static int __stdcall StringCompare( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollate( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static LPCSTR __stdcall StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static LPSTR __stdcall StringFindString( LPSTR pszBlock, LPCSTR pszMatch ) + { + return const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch )); + } + + static LPCSTR __stdcall StringFindChar( LPCSTR pszBlock, char chMatch ) + { + return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch )); + } + + static LPCSTR __stdcall StringFindCharRev( LPCSTR psz, char ch ) + { + return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch )); + } + + static LPCSTR __stdcall StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static int __stdcall StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static int __stdcall StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static LPSTR __stdcall StringUppercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringLowercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringUppercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size); + #else + _mbsupr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringLowercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size ); + #else + _mbslwr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringReverse( LPSTR psz ) + { + return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz )) ); + } + + static int __stdcall GetFormattedLength( LPCSTR pszFormat, va_list args ); + + static int __stdcall Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vsprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + + } + + static int __stdcall Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer length in XCHARs + return int( strlen( pszSrc )); + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer length in XCHARs + return nLength; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource, int nLength ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL ); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in XCHARs + memcpy_s( pszDest, nDestLength*sizeof( char ), + pszSrc, nSrcLength*sizeof( char )); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) + { + // nLen is in XCHARs + ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL ); + } + + static void ConvertToOem( _CharType* pstrString) + { + BOOL fSuccess=::CharToOemA(pstrString, pstrString); + } + + static void ConvertToAnsi( _CharType* pstrString) + { + BOOL fSuccess=::OemToCharA(pstrString, pstrString); + } + + static void ConvertToOem( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + { + return; + } + DWORD dwSize=static_cast(size); + BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize); + } + + static void ConvertToAnsi( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + return; + + DWORD dwSize=static_cast(size); + BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize); + } + + static void __stdcall FloodCharacters( char ch, int nLength, char* pch ) + { + // nLength is in XCHARs + memset( pch, ch, nLength ); + } + + static BSTR __stdcall AllocSysString( const char* pchData, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BSTR bstr = ::SysAllocStringLen( NULL, nLen ); + if ( bstr != NULL ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, bstr, nLen ); + + return bstr; + } + + static BOOL __stdcall ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen ); + if ( bSuccess ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen ); + + return bSuccess; + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? int( strlen( psz )) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? int( wcslen( psz )) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return int( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize ) + { + return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize ); + } +}; + +// specialization for wchar_t +template<> +class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > +{ + static DWORD __stdcall _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) + { + return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize ); + } + +public: + static LPWSTR __stdcall CharNext( LPCWSTR psz ) + { + return const_cast< LPWSTR >( psz+1 ); + } + + static int __stdcall IsDigit( wchar_t ch ) + { + return iswdigit( static_cast(ch)); + } + + static int __stdcall IsSpace( wchar_t ch ) + { + return iswspace( static_cast(ch)); + } + + static int __stdcall StringCompare( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscmp( pszA, pszB ); + } + + static int __stdcall StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicmp( pszA, pszB ); + } + + static int __stdcall StringCollate( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscoll( pszA, pszB ); + } + + static int __stdcall StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicoll( pszA, pszB ); + } + + static LPCWSTR __stdcall StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcsstr( pszBlock, pszMatch ); + } + + static LPWSTR __stdcall StringFindString( LPWSTR pszBlock, LPCWSTR pszMatch ) + { + return const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch )); + } + + static LPCWSTR __stdcall StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) + { + return wcschr( pszBlock, chMatch ); + } + + static LPCWSTR __stdcall StringFindCharRev( LPCWSTR psz, wchar_t ch ) + { + return wcsrchr( psz, ch ); + } + + static LPCWSTR __stdcall StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcspbrk( pszBlock, pszMatch ); + } + + static int __stdcall StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcsspn( pszBlock, pszSet ); + } + + static int __stdcall StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcscspn( pszBlock, pszSet ); + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcsupr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcslwr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz, size_t ) + { + return _wcsupr( psz ); + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz, size_t ) + { + return _wcslwr( psz ); + } + + static LPWSTR __stdcall StringReverse( LPWSTR psz ) + { + return _wcsrev( psz ); + } + + static int __stdcall GetFormattedLength( LPCWSTR pszFormat, va_list args); + + static int __stdcall Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vswprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + } + + static int __stdcall Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, NULL, 0 )-1; + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nLength, NULL, 0 ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return (int)wcslen( pszSrc ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer size in wchar_ts + return nLength; + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) + { + // nLen is in wchar_ts + ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength ); + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in wchar_ts + #if _MSC_VER >= 1400 + wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); + #else + wmemcpy(pszDest, pszSrc, nDestLength); + #endif + } + + static void __stdcall FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) + { + // nLength is in XCHARs + for ( int i = 0; i < nLength; i++ ) + { + psz[i] = ch; + } + } + + static BSTR __stdcall AllocSysString( const wchar_t* pchData, int nDataLength ) + { + return ::SysAllocStringLen( pchData, nDataLength ); + } + + static BOOL __stdcall ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) + { + return ::SysReAllocStringLen( pbstr, pchData, nDataLength ); + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? (int)strlen( psz ) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? (int)wcslen( psz ) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + (void)pch; + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) + { + return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize ); + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/, size_t ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/, size_t ) + { + } +}; + +template< typename BaseType, class StringTraits > +class CMStringT : public CMSimpleStringT< BaseType > +{ +public: + typedef CMSimpleStringT< BaseType> CThisSimpleString; + typedef typename CThisSimpleString::XCHAR XCHAR; + typedef typename CThisSimpleString::PXSTR PXSTR; + typedef typename CThisSimpleString::PCXSTR PCXSTR; + typedef typename CThisSimpleString::YCHAR YCHAR; + typedef typename CThisSimpleString::PYSTR PYSTR; + typedef typename CThisSimpleString::PCYSTR PCYSTR; + +public: + CMStringT() : CThisSimpleString() + { + } + + static void __stdcall Construct( CMStringT* pString ) + { + new( pString ) CMStringT; + } + + // Copy constructor + CMStringT( const CMStringT& strSrc ) : + CThisSimpleString( strSrc ) + { + } + + CMStringT( const XCHAR* pszSrc ) : + CThisSimpleString() + { + // nDestLength is in XCHARs + *this = pszSrc; + } + + CMStringT( const YCHAR* pszSrc ) : + CThisSimpleString() + { + *this = pszSrc; + } + + + CMStringT( const unsigned char* pszSrc ) : + CThisSimpleString() + { + *this = reinterpret_cast< const char* >( pszSrc ); + } + + CMStringT( char ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + } + } + + CMStringT( wchar_t ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + //Convert ch to the BaseType + wchar_t pszCh[2] = { ch , 0 }; + int nBaseTypeCharLen = 1; + + if(ch != L'\0') + { + nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); + } + + XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; + StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 ); + //Allocate enough characters in String and flood (replicate) with the (converted character)*nLength + PXSTR pszBuffer = this->GetBuffer( nLength*nBaseTypeCharLen ); + if (nBaseTypeCharLen == 1) + { //Optimization for a common case - wide char translates to 1 ansi/wide char. + StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer ); + } else + { + XCHAR* p=pszBuffer; + for (int i=0 ; i < nLength ;++i) + { + for (int j=0 ; j < nBaseTypeCharLen ;++j) + { + *p=buffBaseTypeChar[j]; + ++p; + } + } + } + this->ReleaseBufferSetLength( nLength*nBaseTypeCharLen ); + delete [] buffBaseTypeChar; + } + } + + CMStringT( const XCHAR* pch, int nLength ) : + CThisSimpleString( pch, nLength ) + { + } + + CMStringT( const YCHAR* pch, int nLength ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength ); + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength ); + this->ReleaseBufferSetLength( nDestLength ); + } + } + + // Destructor + ~CMStringT() + { + } + + // Assignment operators + CMStringT& operator=( const CMStringT& strSrc ) + { + CThisSimpleString::operator=( strSrc ); + + return *this; + } + + CMStringT& operator=( PCXSTR pszSrc ) + { + CThisSimpleString::operator=( pszSrc ); + + return *this; + } + + CMStringT& operator=( PCYSTR pszSrc ) + { + // nDestLength is in XCHARs + int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0; + if ( nDestLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc); + this->ReleaseBufferSetLength( nDestLength ); + } + else + { + this->Empty(); + } + + return *this; + } + + CMStringT& operator=( const unsigned char* pszSrc ) + { + return operator=( reinterpret_cast< const char* >( pszSrc )); + } + + CMStringT& operator=( char ch ) + { + char ach[2] = { ch, 0 }; + + return operator=( ach ); + } + + CMStringT& operator=( wchar_t ch ) + { + wchar_t ach[2] = { ch, 0 }; + + return operator=( ach ); + } + +// CMStringT& operator=( const VARIANT& var ); + + CMStringT& operator+=( const CMStringT& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( const CThisSimpleString& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( PCXSTR pszSrc ) + { + CThisSimpleString::operator+=( pszSrc ); + return *this; + } +// template< int t_nSize > +// CMStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc ) +// { +// CThisSimpleString::operator+=( strSrc ); +// +// return *this; +// } + CMStringT& operator+=( PCYSTR pszSrc ) + { + CMStringT str( pszSrc ); + + return operator+=( str ); + } + + CMStringT& operator+=( char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( unsigned char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( wchar_t ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + // Comparison + + int Compare( PCXSTR psz ) const + { + return StringTraits::StringCompare( this->GetString(), psz ); + } + + int CompareNoCase( PCXSTR psz ) const + { + return StringTraits::StringCompareIgnore( this->GetString(), psz ); + } + + int Collate( PCXSTR psz ) const + { + return StringTraits::StringCollate( this->GetString(), psz ); + } + + int CollateNoCase( PCXSTR psz ) const + { + return StringTraits::StringCollateIgnore( this->GetString(), psz ); + } + + // Advanced manipulation + + // Delete 'nCount' characters, starting at index 'iIndex' + int Delete( int iIndex, int nCount = 1 ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( nCount < 0 ) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount + iIndex > nLength ) + { + nCount = nLength-iIndex; + } + if ( nCount > 0 ) + { + int nNewLength = nLength-nCount; + int nXCHARsToCopy = nLength-(iIndex+nCount)+1; + PXSTR pszBuffer = this->GetBuffer(); + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return this->GetLength(); + } + + // Insert character 'ch' before index 'iIndex' + int Insert( int iIndex, XCHAR ch ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + iIndex = this->GetLength(); + + int nNewLength = this->GetLength()+1; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #endif + pszBuffer[iIndex] = ch; + + this->ReleaseBufferSetLength( nNewLength ); + return nNewLength; + } + + // Insert string 'psz' before index 'iIndex' + int Insert( int iIndex, PCXSTR psz ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + { + iIndex = this->GetLength(); + } + + // nInsertLength and nNewLength are in XCHARs + int nInsertLength = StringTraits::SafeStringLen( psz ); + int nNewLength = this->GetLength(); + if ( nInsertLength > 0 ) + { + nNewLength += nInsertLength; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), psz, nInsertLength*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return nNewLength; + } + + // Replace all occurrences of character 'chOld' with character 'chNew' + int Replace( XCHAR chOld, XCHAR chNew ) + { + int nCount = 0; + + // short-circuit the nop case + if ( chOld != chNew ) + { + // otherwise modify each character that matches in the string + bool bCopied = false; + PXSTR pszBuffer = const_cast< PXSTR >( this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). + + int nLength = this->GetLength(); + int iChar = 0; + while( iChar < nLength ) + { + // replace instances of the specified character only + if ( pszBuffer[iChar] == chOld ) + { + if ( !bCopied ) + { + bCopied = true; + pszBuffer = this->GetBuffer( nLength ); + } + pszBuffer[iChar] = chNew; + nCount++; + } + iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer ); + } + if ( bCopied ) + { + this->ReleaseBufferSetLength( nLength ); + } + } + + return nCount; + } + + // Replace all occurrences of string 'pszOld' with string 'pszNew' + int Replace( PCXSTR pszOld, PCXSTR pszNew ) + { + // can't have empty or NULL lpszOld + + // nSourceLen is in XCHARs + int nSourceLen = StringTraits::SafeStringLen( pszOld ); + if ( nSourceLen == 0 ) + return 0; + // nReplacementLen is in XCHARs + int nReplacementLen = StringTraits::SafeStringLen( pszNew ); + + // loop once to figure out the size of the result string + int nCount = 0; + { + PCXSTR pszStart = this->GetString(); + PCXSTR pszEnd = pszStart+this->GetLength(); + while( pszStart < pszEnd ) + { + PCXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL) + { + nCount++; + pszStart = pszTarget+nSourceLen; + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + } + + // if any changes were made, make them + if ( nCount > 0 ) + { + // if the buffer is too small, just + // allocate a new buffer (slow but sure) + int nOldLength = this->GetLength(); + int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; + + PXSTR pszBuffer = this->GetBuffer( __max( nNewLength, nOldLength )); + + PXSTR pszStart = pszBuffer; + PXSTR pszEnd = pszStart+nOldLength; + + // loop again to actually do the work + while( pszStart < pszEnd ) + { + PXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL ) + { + int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); + memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), + pszTarget+nSourceLen, nBalance*sizeof( XCHAR )); + memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), + pszNew, nReplacementLen*sizeof( XCHAR )); + pszStart = pszTarget+nReplacementLen; + pszTarget[nReplacementLen+nBalance] = 0; + nOldLength += (nReplacementLen-nSourceLen); + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + this->ReleaseBufferSetLength( nNewLength ); + } + + return nCount; + } + + // Remove all occurrences of character 'chRemove' + int Remove( XCHAR chRemove ) + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + + PXSTR pszSource = pszBuffer; + PXSTR pszDest = pszBuffer; + PXSTR pszEnd = pszBuffer+nLength; + + while( pszSource < pszEnd ) + { + PXSTR pszNewSource = StringTraits::CharNext( pszSource ); + if ( *pszSource != chRemove ) + { + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + size_t NewSourceGap = (pszNewSource-pszSource); + PXSTR pszNewDest = pszDest + NewSourceGap; + size_t i = 0; + for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) + { + *pszDest = *pszSource; + pszSource++; + pszDest++; + } + } + pszSource = pszNewSource; + } + *pszDest = 0; + int nCount = int( pszSource-pszDest ); + this->ReleaseBufferSetLength( nLength-nCount ); + + return nCount; + } + + CMStringT Tokenize( PCXSTR pszTokens, int& iStart ) const + { + if ( (pszTokens == NULL) || (*pszTokens == (XCHAR)0)) + { + if (iStart < this->GetLength()) + return CMStringT( this->GetString()+iStart ); + } + else + { + PCXSTR pszPlace = this->GetString()+iStart; + PCXSTR pszEnd = this->GetString()+this->GetLength(); + if ( pszPlace < pszEnd ) + { + int nIncluding = StringTraits::StringSpanIncluding( pszPlace, pszTokens ); + + if ( (pszPlace+nIncluding) < pszEnd ) + { + pszPlace += nIncluding; + int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens ); + + int iFrom = iStart+nIncluding; + int nUntil = nExcluding; + iStart = iFrom+nUntil+1; + + return Mid( iFrom, nUntil ); + } + } + } + + // return empty string, done tokenizing + iStart = -1; + + return CMStringT(); + } + + // find routines + + // Find the first occurrence of character 'ch', starting at index 'iStart' + int Find( XCHAR ch, int iStart = 0 ) const + { + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart >= nLength) + return -1; + + // find first single character + PCXSTR psz = StringTraits::StringFindChar( this->GetString()+iStart, ch ); + + // return -1 if not found and index otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // look for a specific sub-string + + // Find the first occurrence of string 'pszSub', starting at index 'iStart' + int Find( PCXSTR pszSub, int iStart = 0 ) const + { + // iStart is in XCHARs + if(pszSub == NULL) + return -1; + + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart > nLength ) + return -1; + + // find first matching substring + PCXSTR psz = StringTraits::StringFindString( this->GetString()+iStart, pszSub ); + + // return -1 for not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the first occurrence of any of the characters in string 'pszCharSet' + int FindOneOf( PCXSTR pszCharSet ) const + { + PCXSTR psz = StringTraits::StringScanSet( this->GetString(), pszCharSet ); + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the last occurrence of character 'ch' + int ReverseFind( XCHAR ch ) const + { + // find last single character + PCXSTR psz = StringTraits::StringFindCharRev( this->GetString(), ch ); + + // return -1 if not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // manipulation + + // Convert the string to uppercase + CMStringT& MakeUpper() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringUppercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Convert the string to lowercase + CMStringT& MakeLower() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringLowercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Reverse the string + CMStringT& MakeReverse() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringReverse( pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // trimming + + // Remove all trailing whitespace + CMStringT& TrimRight() + { + // find beginning of trailing spaces by starting + // at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::IsSpace( *psz )) + { + if ( pszLast == NULL ) + pszLast = psz; + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at trailing space start + int iLast = int( pszLast-this->GetString()); + + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading whitespace + CMStringT& TrimLeft() + { + // find first non-space character + + PCXSTR psz = this->GetString(); + + while( StringTraits::IsSpace( *psz )) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading and trailing whitespace + CMStringT& Trim() + { + return TrimRight().TrimLeft(); + } + + // Remove all leading and trailing occurrences of character 'chTarget' + CMStringT& Trim( XCHAR chTarget ) + { + return TrimRight( chTarget ).TrimLeft( chTarget ); + } + + // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' + CMStringT& Trim( PCXSTR pszTargets ) + { + return TrimRight( pszTargets ).TrimLeft( pszTargets ); + } + + // trimming anything (either side) + + // Remove all trailing occurrences of character 'chTarget' + CMStringT& TrimRight( XCHAR chTarget ) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( *psz == chTarget ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all trailing occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimRight( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::StringFindChar( pszTargets, *psz ) != NULL ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading occurrences of character 'chTarget' + CMStringT& TrimLeft( XCHAR chTarget ) + { + // find first non-matching character + PCXSTR psz = this->GetString(); + + while( chTarget == *psz ) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimLeft( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + PCXSTR psz = this->GetString(); + while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL)) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Convert the string to the OEM character set + void AnsiToOem() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToOem( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Convert the string to the ANSI character set + void OemToAnsi() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToAnsi( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Very simple sub-string extraction + + // Return the substring starting at index 'iFirst' + CMStringT Mid( int iFirst ) const + { + return Mid( iFirst, this->GetLength()-iFirst ); + } + + // Return the substring starting at index 'iFirst', with length 'nCount' + CMStringT Mid( int iFirst, int nCount ) const + { + // nCount is in XCHARs + + // out-of-bounds requests return sensible things + if (iFirst < 0) + iFirst = 0; + if (nCount < 0) + nCount = 0; + + if ( (iFirst + nCount) > this->GetLength()) + nCount = this->GetLength()-iFirst; + + if ( iFirst > this->GetLength()) + nCount = 0; + + // optimize case of returning entire string + if ( (iFirst == 0) && ((iFirst+nCount) == this->GetLength())) + return *this; + + return CMStringT( this->GetString()+iFirst, nCount ); + } + + // Return the substring consisting of the rightmost 'nCount' characters + CMStringT Right( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + { + return *this; + } + + return CMStringT( this->GetString()+nLength-nCount, nCount ); + } + + // Return the substring consisting of the leftmost 'nCount' characters + CMStringT Left( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + return *this; + + return CMStringT( this->GetString(), nCount ); + } + + // Return the substring consisting of the leftmost characters in the set 'pszCharSet' + CMStringT SpanIncluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanIncluding( this->GetString(), pszCharSet )); + } + + // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' + CMStringT SpanExcluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanExcluding( this->GetString(), pszCharSet )); + } + + // Format data using format string 'pszFormat' + void Format( PCXSTR pszFormat, ... ); + + // Append formatted data using format string 'pszFormat' + void AppendFormat( PCXSTR pszFormat, ... ); + + void AppendFormatV( PCXSTR pszFormat, va_list args ) + { + int nCurrentLength = this->GetLength(); + int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nCurrentLength+nAppendLength ); + StringTraits::Format( pszBuffer+nCurrentLength, + nAppendLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nCurrentLength+nAppendLength ); + } + + void FormatV( PCXSTR pszFormat, va_list args ) + { + int nLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::Format( pszBuffer, nLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nLength ); + } + + // OLE BSTR support + + // Allocate a BSTR containing a copy of the string + BSTR AllocSysString() const + { + BSTR bstrResult = StringTraits::AllocSysString( this->GetString(), this->GetLength()); + return bstrResult; + } + + BSTR SetSysString( BSTR* pbstr ) const + { + StringTraits::ReAllocSysString( this->GetString(), pbstr, this->GetLength()); + return *pbstr; + } + + // Set the string to the value of environment variable 'pszVar' + BOOL GetEnvironmentVariable( PCXSTR pszVar ) + { + ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 ); + BOOL bRetVal = FALSE; + + if ( nLength == 0 ) + { + this->Empty(); + } + else + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength ); + this->ReleaseBuffer(); + bRetVal = TRUE; + } + + return bRetVal; + } + + // Load the string from resource 'nID' + BOOL LoadString( UINT nID ) + { + HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID ); + if ( hInst == NULL ) + return FALSE; + + return LoadString( hInst, nID ); + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, PCXSTR psz2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return strResult; + } + + friend CMStringT __stdcall operator+( PCXSTR psz1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, wchar_t ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, char ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( wchar_t ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( char ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend bool __stdcall operator==( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) == 0; + } + + friend bool __stdcall operator==( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 == str2; + } + + friend bool __stdcall operator==( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 == str2; + } + + friend bool __stdcall operator!=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) != 0; + } + + friend bool __stdcall operator!=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 != str2; + } + + friend bool __stdcall operator!=( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 != str2; + } + + friend bool __stdcall operator<( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) < 0; + } + + friend bool __stdcall operator<( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) < 0; + } + + friend bool __stdcall operator<( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) > 0; + } + + friend bool __stdcall operator>( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) < 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) <= 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) <= 0; + } + + friend bool __stdcall operator<=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) >= 0; + } + + friend bool __stdcall operator>=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) <= 0; + } + + friend bool __stdcall operator==( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() == 1) && (str2[0] == ch1); + } + + friend bool __stdcall operator==( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() == 1) && (str1[0] == ch2); + } + + friend bool __stdcall operator!=( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() != 1) || (str2[0] != ch1); + } + + friend bool __stdcall operator!=( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() != 1) || (str1[0] != ch2); + } +}; + +template< typename BaseType, class StringTraits > +inline void CMStringT::Format(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + FormatV( pszFormat, argList ); + va_end( argList ); +} + +template< typename BaseType, class StringTraits > +inline void CMStringT::AppendFormat(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + AppendFormatV( pszFormat, argList ); + va_end( argList ); +} + +typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; +typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; +typedef CMStringT< TCHAR, ChTraitsCRT< TCHAR > > CMString; diff --git a/protocols/IRCG/src/clist.cpp b/protocols/IRCG/src/clist.cpp new file mode 100644 index 0000000000..94bb460db9 --- /dev/null +++ b/protocols/IRCG/src/clist.cpp @@ -0,0 +1,247 @@ + +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +BOOL CIrcProto::CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) +{ + HANDLE hContact; + HANDLE hc; + TCHAR szNick[256]; + char szService[256]; + bool bFlag = false; + + CONTACT usertemp = { (TCHAR*)name.c_str(), NULL, NULL, false, false, true}; + hc = CList_FindContact( &usertemp ); + if ( hc && DBGetContactSettingByte( hc, "CList", "NotOnList", 0) == 0 + && DBGetContactSettingByte(hc,"CList", "Hidden", 0) == 0) + { + bFlag = true; + } + + CMString contactname = name; contactname += _T(DCCSTRING); + + CONTACT user = { (TCHAR*)contactname.c_str(), NULL, NULL, false, false, true}; + hContact = CList_AddContact(&user, false, false); + setByte(hContact, "DCC", 1); + + DCCINFO* pdci = new DCCINFO; + pdci->sHostmask = hostmask; + pdci->hContact = hContact; + pdci->dwAdr = (DWORD) adr; + pdci->iPort = port; + pdci->iType = DCC_CHAT; + pdci->bSender = false; + pdci->sContactName = name; + + if ( m_DCCChatAccept == 3 || m_DCCChatAccept == 2 && bFlag ) { + CDccSession* dcc = new CDccSession( this, pdci ); + + CDccSession* olddcc = FindDCCSession(hContact); + if ( olddcc ) + olddcc->Disconnect(); + + AddDCCSession(hContact, dcc); + dcc->Connect(); + if (getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), name.c_str()); + } + else { + CLISTEVENT cle = {0}; + cle.cbSize = sizeof(cle); + cle.hContact = (HANDLE)hContact; + cle.hDbEvent = (HANDLE)"dccchat"; + cle.flags = CLEF_TCHAR; + cle.hIcon = LoadIconEx(IDI_DCC); + mir_snprintf( szService, sizeof(szService),"%s/DblClickEvent", m_szModuleName); + cle.pszService = szService ; + mir_sntprintf( szNick, SIZEOF(szNick), TranslateT("CTCP chat request from %s"), name.c_str()); + cle.ptszTooltip = szNick; + cle.lParam = (LPARAM)pdci; + + if ( CallService( MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0)) + CallService( MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)"dccchat"); + CallService( MS_CLIST_ADDEVENT,(WPARAM) hContact,(LPARAM) &cle); + } + return TRUE; +} + +HANDLE CIrcProto::CList_AddContact(CONTACT * user, bool InList, bool SetOnline) +{ + if (user->name == NULL) + return 0; + + HANDLE hContact = CList_FindContact(user); + if ( hContact ) { + if ( InList ) + DBDeleteContactSetting( hContact, "CList", "NotOnList" ); + setTString(hContact, "Nick", user->name); + DBDeleteContactSetting(hContact, "CList", "Hidden"); + if (SetOnline && getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + return hContact; + } + + // here we create a new one since no one is to be found + hContact = (HANDLE) CallService( MS_DB_CONTACT_ADD, 0, 0); + if ( hContact ) { + CallService( MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM)m_szModuleName ); + + if ( InList ) + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + else + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + DBDeleteContactSetting(hContact, "CList", "Hidden"); + setTString(hContact, "Nick", user->name); + setTString(hContact, "Default", user->name); + setWord(hContact, "Status", SetOnline ? ID_STATUS_ONLINE:ID_STATUS_OFFLINE); + if ( !InList && getByte( "MirVerAutoRequestTemp", 0)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user->name); + return hContact; + } + return false; +} + +HANDLE CIrcProto::CList_SetOffline(struct CONTACT * user) +{ + DBVARIANT dbv; + HANDLE hContact = CList_FindContact(user); + if ( hContact ) { + if ( !getTString( hContact, "Default", &dbv )) { + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + setTString(hContact, "Nick", dbv.ptszVal); + setWord(hContact, "Status", ID_STATUS_OFFLINE); + DBFreeVariant(&dbv); + return hContact; + } } + + return 0; +} + +bool CIrcProto::CList_SetAllOffline(BYTE ChatsToo) +{ + DBVARIANT dbv; + + DisconnectAllDCCSessions(false); + + HANDLE hContact = db_find_first(); + while ( hContact ) { + char* szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0 ); + if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { + if ( getByte( hContact, "ChatRoom", 0 ) == 0 ) { + if ( getByte(hContact, "DCC", 0 ) != 0 ) { + if ( ChatsToo ) + setWord(hContact, "Status", ID_STATUS_OFFLINE); + } + else if ( !getTString( hContact, "Default", &dbv )) { + setTString( hContact, "Nick", dbv.ptszVal); + setWord( hContact, "Status", ID_STATUS_OFFLINE ); + DBFreeVariant( &dbv ); + } + DBDeleteContactSetting( hContact, m_szModuleName, "IP" ); + setString( hContact, "User", "" ); + setString( hContact, "Host", "" ); + } } + + hContact = db_find_next(hContact); + } + return true; +} + +HANDLE CIrcProto::CList_FindContact (CONTACT* user) +{ + if ( !user || !user->name ) + return 0; + + TCHAR* lowercasename = mir_tstrdup( user->name ); + CharLower(lowercasename); + + char *szProto; + DBVARIANT dbv1; + DBVARIANT dbv2; + DBVARIANT dbv3; + DBVARIANT dbv4; + DBVARIANT dbv5; + HANDLE hContact = db_find_first(); + while (hContact) { + szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { + if ( getByte( hContact, "ChatRoom", 0) == 0) { + HANDLE hContact_temp = NULL; + TCHAR* DBDefault = NULL; + TCHAR* DBNick = NULL; + TCHAR* DBWildcard = NULL; + TCHAR* DBUser = NULL; + TCHAR* DBHost = NULL; + if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; + if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; + if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; + if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; + if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; + + if ( DBWildcard ) + CharLower( DBWildcard ); + if ( IsChannel( user->name )) { + if ( DBDefault && !lstrcmpi( DBDefault, user->name )) + hContact_temp = (HANDLE)-1; + } + else if ( user->ExactNick && DBNick && !lstrcmpi( DBNick, user->name )) + hContact_temp = hContact; + + else if ( user->ExactOnly && DBDefault && !lstrcmpi( DBDefault, user->name )) + hContact_temp = hContact; + + else if ( user->ExactWCOnly ) { + if ( DBWildcard && !lstrcmpi( DBWildcard, lowercasename ) + || ( DBWildcard && !lstrcmpi( DBNick, lowercasename ) && !WCCmp( DBWildcard, lowercasename )) + || ( !DBWildcard && !lstrcmpi(DBNick, lowercasename))) + { + hContact_temp = hContact; + } + } + else if ( _tcschr(user->name, ' ' ) == 0 ) { + if (( DBDefault && !lstrcmpi(DBDefault, user->name) || DBNick && !lstrcmpi(DBNick, user->name) || + DBWildcard && WCCmp( DBWildcard, lowercasename )) + && ( WCCmp(DBUser, user->user) && WCCmp(DBHost, user->host))) + { + hContact_temp = hContact; + } } + + if ( DBDefault ) DBFreeVariant(&dbv1); + if ( DBNick ) DBFreeVariant(&dbv2); + if ( DBWildcard ) DBFreeVariant(&dbv3); + if ( DBUser ) DBFreeVariant(&dbv4); + if ( DBHost ) DBFreeVariant(&dbv5); + + if ( hContact_temp != NULL ) { + mir_free(lowercasename); + if ( hContact_temp != (HANDLE)-1 ) + return hContact_temp; + return 0; + } } } + + hContact = db_find_next(hContact); + } + mir_free(lowercasename); + return 0; +} diff --git a/protocols/IRCG/src/commandmonitor.cpp b/protocols/IRCG/src/commandmonitor.cpp new file mode 100644 index 0000000000..79d4579ae6 --- /dev/null +++ b/protocols/IRCG/src/commandmonitor.cpp @@ -0,0 +1,2508 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +// This file holds functions that are called upon receiving +// certain commands from the server. + +#include "irc.h" + +using namespace irc; + +VOID CALLBACK IdentTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + ppro->KillChatTimer( ppro->IdentTimer ); + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) + return; + + if ( ppro->IsConnected() && ppro->m_identTimer ) + ppro->KillIdent(); +} + +VOID CALLBACK TimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + ppro->KillChatTimer( ppro->InitTimer ); + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) + return; + + if ( ppro->m_forceVisible ) + ppro->PostIrcMessage( _T("/MODE %s -i"), ppro->m_info.sNick.c_str()); + + if ( lstrlenA( ppro->m_myHost ) == 0 && ppro->IsConnected()) + ppro->DoUserhostWithReason(2, (_T("S") + ppro->m_info.sNick).c_str(), true, _T("%s"), ppro->m_info.sNick.c_str()); +} + +VOID CALLBACK KeepAliveTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( !ppro->m_sendKeepAlive || ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING )) { + ppro->KillChatTimer( ppro->KeepAliveTimer ); + return; + } + + TCHAR temp2[270]; + if ( !ppro->m_info.sServerName.IsEmpty()) + mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %s"), ppro->m_info.sServerName.c_str()); + else + mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %u"), time(0)); + + if ( ppro->IsConnected()) + ppro->SendIrcMessage( temp2, false ); +} + +VOID CALLBACK OnlineNotifTimerProc3( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( !ppro->m_channelAwayNotification || + ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || + ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { + ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); + ppro->m_channelsToWho = _T(""); + return; + } + + CMString name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); + if ( name.IsEmpty()) { + ppro->m_channelsToWho = _T(""); + int count = (int)CallServiceSync(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)ppro->m_szModuleName); + for ( int i = 0; i < count; i++ ) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX | NAME | TYPE | COUNT; + gci.iItem = i; + gci.pszModule = ppro->m_szModuleName; + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) + if ( gci.iCount <= ppro->m_onlineNotificationLimit ) + ppro->m_channelsToWho += CMString(gci.pszName) + _T(" "); + } } + + if ( ppro->m_channelsToWho.IsEmpty()) { + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 60*1000, OnlineNotifTimerProc3 ); + return; + } + + name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); + ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); + CMString temp = GetWordAddress( ppro->m_channelsToWho.c_str(), 1 ); + ppro->m_channelsToWho = temp; + if ( ppro->m_iTempCheckTime ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc3 ); + else + ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc3 ); +} + +VOID CALLBACK OnlineNotifTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || + ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { + ppro->KillChatTimer( ppro->OnlineNotifTimer ); + ppro->m_namesToWho = _T(""); + return; + } + + CMString name = GetWord( ppro->m_namesToWho.c_str(), 0); + CMString name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); + + if ( name.IsEmpty() && name2.IsEmpty()) { + DBVARIANT dbv; + char* szProto; + + HANDLE hContact = db_find_first(); + while ( hContact ) { + szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto != NULL && !lstrcmpiA( szProto, ppro->m_szModuleName )) { + BYTE bRoom = ppro->getByte(hContact, "ChatRoom", 0); + if ( bRoom == 0 ) { + BYTE bDCC = ppro->getByte(hContact, "DCC", 0); + BYTE bHidden = DBGetContactSettingByte(hContact,"CList", "Hidden", 0); + if ( bDCC == 0 && bHidden == 0 ) { + if ( !ppro->getTString( hContact, "Default", &dbv )) { + BYTE bAdvanced = ppro->getByte(hContact, "AdvancedMode", 0) ; + if ( !bAdvanced ) { + DBFreeVariant( &dbv ); + if ( !ppro->getTString( hContact, "Nick", &dbv )) { + ppro->m_namesToUserhost += CMString(dbv.ptszVal) + _T(" "); + DBFreeVariant( &dbv ); + } + } + else { + DBFreeVariant( &dbv ); + DBVARIANT dbv2; + + TCHAR* DBNick = NULL; + TCHAR* DBWildcard = NULL; + if ( !ppro->getTString( hContact, "Nick", &dbv )) + DBNick = dbv.ptszVal; + if ( !ppro->getTString( hContact, "UWildcard", &dbv2 )) + DBWildcard = dbv2.ptszVal; + + if ( DBNick && ( !DBWildcard || !WCCmp(CharLower(DBWildcard), CharLower(DBNick)))) + ppro->m_namesToWho += CMString(DBNick) + _T(" "); + else if ( DBWildcard ) + ppro->m_namesToWho += CMString(DBWildcard) + _T(" "); + + if ( DBNick ) DBFreeVariant(&dbv); + if ( DBWildcard ) DBFreeVariant(&dbv2); + } } } } } + + hContact = db_find_next(hContact); + } } + + if ( ppro->m_namesToWho.IsEmpty() && ppro->m_namesToUserhost.IsEmpty()) { + ppro->SetChatTimer( ppro->OnlineNotifTimer, 60*1000, OnlineNotifTimerProc ); + return; + } + + name = GetWord( ppro->m_namesToWho.c_str(), 0); + name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); + CMString temp; + if ( !name.IsEmpty()) { + ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); + temp = GetWordAddress( ppro->m_namesToWho.c_str(), 1 ); + ppro->m_namesToWho = temp; + } + + if ( !name2.IsEmpty()) { + CMString params; + for ( int i = 0; i < 3; i++ ) { + params = _T(""); + for ( int j = 0; j < 5; j++ ) + params += GetWord( ppro->m_namesToUserhost, i *5 + j) + _T(" "); + + if ( params[0] != ' ' ) + ppro->DoUserhostWithReason(1, CMString(_T("S")) + params, true, params); + } + temp = GetWordAddress( ppro->m_namesToUserhost.c_str(), 15 ); + ppro->m_namesToUserhost = temp; + } + + if ( ppro->m_iTempCheckTime ) + ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc ); + else + ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc ); +} + +int CIrcProto::AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg) +{ + if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) + return 0; + + CMString S = DoColorCodes( msg, TRUE, FALSE ); + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.timestamp = (DWORD)time(NULL); + dbei.flags = DBEF_SENT + DBEF_UTF; + dbei.pBlob = ( PBYTE )mir_utf8encodeW( S.c_str()); + dbei.cbBlob = (DWORD)strlen(( char* )dbei.pBlob) + 1; + CallService( MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei); + mir_free( dbei.pBlob ); + return 1; +} + +void __cdecl CIrcProto::ResolveIPThread(LPVOID di) +{ + IPRESOLVE* ipr = (IPRESOLVE *) di; + + EnterCriticalSection( &m_resolve); + + if ( ipr != NULL && (ipr->iType == IP_AUTO && lstrlenA(m_myHost) == 0 || ipr->iType == IP_MANUAL )) { + hostent* myhost = gethostbyname( ipr->sAddr.c_str()); + if ( myhost ) { + IN_ADDR in; + memcpy( &in, myhost->h_addr, 4 ); + if ( ipr->iType == IP_AUTO ) + mir_snprintf( m_myHost, sizeof( m_myHost ), "%s", inet_ntoa( in )); + else + mir_snprintf( m_mySpecifiedHostIP, sizeof( m_mySpecifiedHostIP ), "%s", inet_ntoa( in )); + } } + + LeaveCriticalSection( &m_resolve ); + delete ipr; +} + +bool CIrcProto::OnIrc_PING(const CIrcMessage* pmsg) +{ + TCHAR szResponse[100]; + mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); + SendIrcMessage( szResponse ); + return false; +} + +bool CIrcProto::OnIrc_WELCOME( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters[0] != m_info.sNick ) + m_info.sNick = pmsg->parameters[0]; + + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + static TCHAR host[1024]; + int i = 0; + CMString word = GetWord( pmsg->parameters[1].c_str(), i ); + while ( !word.IsEmpty()) { + if ( _tcschr( word.c_str(), '!') && _tcschr( word.c_str(), '@' )) { + lstrcpyn( host, word.c_str(), SIZEOF(host)); + TCHAR* p1 = _tcschr( host, '@' ); + if ( p1 ) + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(p1+1), IP_AUTO )); + } + + word = GetWord(pmsg->parameters[1].c_str(), ++i); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOTOOLONG( const CIrcMessage* pmsg ) +{ + CMString command = GetNextUserhostReason(2); + if ( command[0] == 'U' ) + ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_BACKFROMAWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + int Temp = m_iStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_ONLINE; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_ONLINE); + + if ( m_perform ) + DoPerform( "Event: Available" ); + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_SETAWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + int Temp = m_iDesiredStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_AWAY; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_AWAY); + + if ( m_perform ) { + switch ( m_iStatus ) { + case ID_STATUS_AWAY: + DoPerform( "Event: Away" ); + break; + case ID_STATUS_NA: + DoPerform( "Event: N/A" ); + break; + case ID_STATUS_DND: + DoPerform( "Event: DND" ); + break; + case ID_STATUS_OCCUPIED: + DoPerform( "Event: Occupied" ); + break; + case ID_STATUS_OUTTOLUNCH: + DoPerform( "Event: Out for lunch" ); + break; + case ID_STATUS_ONTHEPHONE: + DoPerform( "Event: On the phone" ); + break; + default: + m_iStatus = ID_STATUS_AWAY; + DoPerform( "Event: Away" ); + break; + } } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_JOIN( const CIrcMessage* pmsg ) +{ + if (pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming && pmsg->prefix.sNick != m_info.sNick) { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_JOIN, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), NULL, _T("Normal"), host.c_str(), NULL, true, false); + DoEvent(GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[0].c_str(),pmsg->prefix.sNick.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_QUIT( const CIrcMessage* pmsg ) +{ + if (pmsg->m_bIncoming) + { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_QUIT, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>0?pmsg->parameters[0].c_str():NULL, NULL, host.c_str(), NULL, true, false); + struct CONTACT user = { (LPTSTR)pmsg->prefix.sNick.c_str(), (LPTSTR)pmsg->prefix.sUser.c_str(), (LPTSTR)pmsg->prefix.sHost.c_str(), false, false, false}; + CList_SetOffline( &user ); + if ( pmsg->prefix.sNick == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.cbSize = sizeof(GCEVENT); + gcd.pszID = NULL; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_PART( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming ) { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_PART, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>1?pmsg->parameters[1].c_str():NULL, NULL, host.c_str(), NULL, true, false); + if ( pmsg->prefix.sNick == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + CMString S = MakeWndID( pmsg->parameters[0].c_str()); + gce.cbSize = sizeof(GCEVENT); + gcd.ptszID = ( TCHAR* )S.c_str(); + gce.dwFlags = GC_TCHAR; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_KICK( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) + DoEvent( GC_EVENT_KICK, pmsg->parameters[0].c_str(), pmsg->parameters[1].c_str(), pmsg->parameters.getCount()>2?pmsg->parameters[2].c_str():NULL, pmsg->prefix.sNick.c_str(), NULL, NULL, true, false); + else + ShowMessage( pmsg ); + + if ( pmsg->parameters[1] == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + CMString S = MakeWndID( pmsg->parameters[0].c_str()); + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gcd.ptszID = ( TCHAR* )S.c_str(); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + + if ( m_rejoinIfKicked ) { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), pmsg->parameters[0].c_str(), wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[0].c_str()); + } } + + return true; +} + +bool CIrcProto::OnIrc_MODEQUERY( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 2 && pmsg->m_bIncoming && IsChannel( pmsg->parameters[1] )) { + CMString sPassword = _T(""); + CMString sLimit = _T(""); + bool bAdd = false; + int iParametercount = 3; + + LPCTSTR p1 = pmsg->parameters[2].c_str(); + while ( *p1 != '\0' ) { + if ( *p1 == '+' ) + bAdd = true; + if ( *p1 == '-' ) + bAdd = false; + if ( *p1 == 'l' && bAdd ) { + if (( int )pmsg->parameters.getCount() > iParametercount ) + sLimit = pmsg->parameters[ iParametercount ]; + iParametercount++; + } + if ( *p1 == 'k' && bAdd ) { + if (( int )pmsg->parameters.getCount() > iParametercount ) + sPassword = pmsg->parameters[ iParametercount ]; + iParametercount++; + } + + p1++; + } + + AddWindowItemData( pmsg->parameters[1].c_str(), sLimit.IsEmpty() ? 0 : sLimit.c_str(), pmsg->parameters[2].c_str(), sPassword.IsEmpty() ? 0 : sPassword.c_str(), 0 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_MODE( const CIrcMessage* pmsg ) +{ + bool flag = false; + bool bContainsValidModes = false; + CMString sModes = _T(""); + CMString sParams = _T(""); + + if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { + if ( IsChannel( pmsg->parameters[0] )) { + bool bAdd = false; + int iParametercount = 2; + LPCTSTR p1 = pmsg->parameters[1].c_str(); + + while ( *p1 != '\0' ) { + if ( *p1 == '+' ) { + bAdd = true; + sModes += _T("+"); + } + if ( *p1 == '-' ) { + bAdd = false; + sModes += _T("-"); + } + if ( *p1 == 'l' && bAdd && iParametercount < (int)pmsg->parameters.getCount()) { + bContainsValidModes = true; + sModes += _T("l"); + sParams += _T(" ") + pmsg->parameters[iParametercount]; + iParametercount++; + } + if ( *p1 == 'b' || *p1 == 'k' && iParametercount < (int)pmsg->parameters.getCount()) { + bContainsValidModes = true; + sModes += *p1; + sParams += _T(" ") + pmsg->parameters[iParametercount]; + iParametercount++; + } + if ( strchr( sUserModes.c_str(), (char)*p1 )) { + CMString sStatus = ModeToStatus( *p1 ); + if (( int )pmsg->parameters.getCount() > iParametercount ) { + if ( !_tcscmp(pmsg->parameters[2].c_str(), m_info.sNick.c_str())) { + char cModeBit = -1; + CHANNELINFO* wi = (CHANNELINFO *)DoEvent( GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, false, false, 0 ); + switch (*p1) { + case 'v': cModeBit = 0; break; + case 'h': cModeBit = 1; break; + case 'o': cModeBit = 2; break; + case 'a': cModeBit = 3; break; + case 'q': cModeBit = 4; break; + } + + // set bit for own mode on this channel (voice/hop/op/admin/owner) + if ( bAdd && cModeBit >= 0 ) + wi->OwnMode |= ( 1 << cModeBit ); + else + wi->OwnMode &= ~( 1 << cModeBit ); + + DoEvent( GC_EVENT_SETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0 ); + } + DoEvent( bAdd ? GC_EVENT_ADDSTATUS : GC_EVENT_REMOVESTATUS, pmsg->parameters[0].c_str(), pmsg->parameters[iParametercount].c_str(), pmsg->prefix.sNick.c_str(), sStatus.c_str(), NULL, NULL, m_oldStyleModes?false:true, false); + iParametercount++; + } + } + else if (*p1 != 'b' && *p1 != ' ' && *p1 != '+' && *p1 != '-' ) { + bContainsValidModes = true; + if (*p1 != 'l' && *p1 != 'k') + sModes += *p1; + flag = true; + } + + p1++; + } + + if ( m_oldStyleModes ) { + TCHAR temp[256]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), + pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + + CMString sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += _T(" ") + pmsg->parameters[i]; + + DoEvent( GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false ); + } + else if ( bContainsValidModes ) { + for ( int i = iParametercount; i < (int)pmsg->parameters.getCount(); i++ ) + sParams += _T(" ") + pmsg->parameters[i]; + + TCHAR temp[4000]; + mir_sntprintf( temp, 3999, TranslateT( "%s sets mode %s%s" ), pmsg->prefix.sNick.c_str(), sModes.c_str(), sParams.c_str()); + DoEvent(GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } + + if ( flag ) + PostIrcMessage( _T("/MODE %s"), pmsg->parameters[0].c_str()); + } + else { + TCHAR temp[256]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + + CMString sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += _T(" ") + pmsg->parameters[i]; + + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_NICK( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + bool bIsMe = pmsg->prefix.sNick.c_str() == m_info.sNick ? true : false; + + if ( m_info.sNick == pmsg->prefix.sNick && pmsg->parameters.getCount() > 0 ) { + m_info.sNick = pmsg->parameters[0]; + setTString("Nick", m_info.sNick.c_str()); + } + + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_NICK, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, host.c_str(), NULL, true, bIsMe); + DoEvent(GC_EVENT_CHUID, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, NULL, NULL, true, false); + + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + HANDLE hContact = CList_FindContact(&user); + if (hContact) { + if ( getWord(hContact, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + setTString(hContact, "Nick", pmsg->parameters[0].c_str()); + setTString(hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_NOTICE( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( IsCTCP( pmsg )) + return true; + + if ( !m_ignore || !IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'n' )) { + CMString S; + CMString S2; + CMString S3; + if ( pmsg->prefix.sNick.GetLength() > 0 ) + S = pmsg->prefix.sNick; + else + S = m_info.sNetwork; + S3 = m_info.sNetwork; + if ( IsChannel( pmsg->parameters[0] )) + S2 = pmsg->parameters[0].c_str(); + else { + GC_INFO gci = {0}; + gci.Flags = BYID | TYPE; + gci.pszModule = m_szModuleName; + + CMString S3 = GetWord( pmsg->parameters[1].c_str(), 0); + if ( S3[0] == '[' && S3[1] == '#' && S3[S3.GetLength()-1] == ']' ) { + S3.Delete(S3.GetLength()-1, 1); + S3.Delete(0,1); + CMString Wnd = MakeWndID( S3.c_str()); + gci.pszID = ( TCHAR* )Wnd.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) + S2 = GetWord( gci.pszID, 0 ); + else + S2 = _T(""); + } + else S2 = _T(""); + } + DoEvent(GC_EVENT_NOTICE, S2.IsEmpty() ? 0 : S2.c_str(), S.c_str(), pmsg->parameters[1].c_str(), NULL, S3.c_str(), NULL, true, false); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_YOURHOST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + static const TCHAR* lpszFmt = _T("Your host is %99[^ \x5b,], running version %99s"); + TCHAR szHostName[100], szVersion[100]; + if ( _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szHostName, &szVersion) > 0 ) + m_info.sServerName = szHostName; + if ( pmsg->parameters[0] != m_info.sNick) + m_info.sNick = pmsg->parameters[0]; + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INVITE( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && ( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'i' ))) + return true; + + if ( pmsg->m_bIncoming && m_joinOnInvite && pmsg->parameters.getCount() >1 && lstrcmpi(pmsg->parameters[0].c_str(), m_info.sNick.c_str()) == 0 ) + PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[1].c_str()); + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_PINGPONG( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->sCommand == _T("PING")) { + TCHAR szResponse[100]; + mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); + SendIrcMessage( szResponse ); + } + + return true; +} + +bool CIrcProto::OnIrc_PRIVMSG( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 1 ) { + if ( IsCTCP( pmsg )) + return true; + + CMString mess = pmsg->parameters[1]; + bool bIsChannel = IsChannel(pmsg->parameters[0]); + + if ( pmsg->m_bIncoming && !bIsChannel ) { + CCSDATA ccs = {0}; + PROTORECVEVENT pre; + + mess = DoColorCodes( mess.c_str(), TRUE, FALSE ); + ccs.szProtoService = PSR_MESSAGE; + + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + + if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_MESSAGE )) + if ( !CList_FindContact( &user )) + return true; + + if (( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' ))) { + HANDLE hContact = CList_FindContact( &user ); + if ( !hContact || ( hContact && DBGetContactSettingByte( hContact,"CList", "Hidden", 0) == 1 )) + return true; + } + + ccs.hContact = CList_AddContact( &user, false, true ); + ccs.lParam = (LPARAM)⪯ + pre.timestamp = (DWORD)time(NULL); + pre.flags = PREF_UTF; + pre.szMessage = mir_utf8encodeW( mess.c_str()); + setTString(ccs.hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(ccs.hContact, "Host", pmsg->prefix.sHost.c_str()); + CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); + mir_free( pre.szMessage ); + return true; + } + + if ( bIsChannel ) { + if ( !(pmsg->m_bIncoming && m_ignore && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm' ))) { + if ( !pmsg->m_bIncoming ) + ReplaceString( mess, _T("%%"), _T("%")); + DoEvent(GC_EVENT_MESSAGE, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + } + return true; + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::IsCTCP( const CIrcMessage* pmsg ) +{ + // is it a ctcp command, i e is the first and last characer of a PRIVMSG or NOTICE text ASCII 1 + CMString mess = pmsg->parameters[1]; + if ( !( mess.GetLength() > 3 && mess[0] == 1 && mess[ mess.GetLength()-1] == 1 )) + return false; + + // set mess to contain the ctcp command, excluding the leading and trailing ASCII 1 + mess.Delete(0,1); + mess.Delete(mess.GetLength()-1,1); + + // exploit??? + if ( mess.Find(1) != -1 || mess.Find( _T("%newl")) != -1 ) { + TCHAR temp[4096]; + mir_sntprintf(temp, SIZEOF(temp), TranslateT( "CTCP ERROR: Malformed CTCP command received from %s!%s@%s. Possible attempt to take control of your irc client registered"), pmsg->prefix.sNick.c_str(), pmsg->prefix.sUser.c_str(), pmsg->prefix.sHost.c_str()); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + return true; + } + + // extract the type of ctcp command + CMString ocommand = GetWord(mess.c_str(), 0); + CMString command = GetWord(mess.c_str(), 0); + command.MakeLower(); + + // should it be ignored? + if ( m_ignore ) { + if ( IsChannel( pmsg->parameters[0] )) { + if ( command == _T("action") && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm')) + return true; + } + else { + if ( command == _T("action")) { + if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' )) + return true; + } + else if ( command == _T("dcc")) { + if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'd' )) + return true; + } + else if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'c' )) + return true; + } } + + if ( pmsg->sCommand == _T("PRIVMSG")) { + // incoming ACTION + if ( command == _T("action")) { + mess.Delete(0,6); + + if ( IsChannel( pmsg->parameters[0] )) { + if ( mess.GetLength() > 1 ) { + mess.Delete(0,1); + if ( !pmsg->m_bIncoming ) + ReplaceString(mess, _T("%%"), _T("%")); + + DoEvent(GC_EVENT_ACTION, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + } + } + else if (pmsg->m_bIncoming) + { + mess.Insert(0, pmsg->prefix.sNick.c_str()); + mess.Insert(0, _T("* ")); + mess.Insert(mess.GetLength(), _T(" *")); + CIrcMessage msg = *pmsg; + msg.parameters[1] = mess; + OnIrc_PRIVMSG(&msg); + } + } + // incoming FINGER + else if (pmsg->m_bIncoming && command == _T("finger")) { + PostIrcMessage( _T("/NOTICE %s \001FINGER %s (%s)\001"), pmsg->prefix.sNick.c_str(), m_name, m_userID); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP FINGER requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming VERSION + else if (pmsg->m_bIncoming && command == _T("version")) { + PostIrcMessage( _T("/NOTICE %s \001VERSION Miranda NG %s (IRC v.%s%s), (c) 2003-09 J.Persson, G.Hazan\001"), + pmsg->prefix.sNick.c_str(), _T("%mirver"), _T("%version"), + _T(" Unicode")); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP VERSION requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming SOURCE + else if (pmsg->m_bIncoming && command == _T("source")) { + PostIrcMessage( _T("/NOTICE %s \001SOURCE Get Miranda IRC here: http://miranda-ng.org/ \001"), pmsg->prefix.sNick.c_str()); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP SOURCE requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming USERINFO + else if (pmsg->m_bIncoming && command == _T("userinfo")) { + PostIrcMessage( _T("/NOTICE %s \001USERINFO %s\001"), pmsg->prefix.sNick.c_str(), m_userInfo ); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP USERINFO requested by %s") , pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming PING + else if (pmsg->m_bIncoming && command == _T("ping")) { + PostIrcMessage( _T("/NOTICE %s \001%s\001"), pmsg->prefix.sNick.c_str(), mess.c_str()); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP PING requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming TIME + else if (pmsg->m_bIncoming && command == _T("time")) { + TCHAR temp[300]; + time_t tim = time(NULL); + lstrcpyn( temp, _tctime( &tim ), 25 ); + PostIrcMessage( _T("/NOTICE %s \001TIME %s\001"), pmsg->prefix.sNick.c_str(), temp); + + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP TIME requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming DCC request... lots of stuff happening here... + else if (pmsg->m_bIncoming && command == _T("dcc")) { + CMString type = GetWord(mess.c_str(), 1); + type.MakeLower(); + + // components of a dcc message + CMString sFile = _T(""); + DWORD dwAdr = 0; + int iPort = 0; + unsigned __int64 dwSize = 0; + CMString sToken = _T(""); + bool bIsChat = ( type == _T("chat")); + + // 1. separate the dcc command into the correct pieces + if ( bIsChat || type == _T("send")) { + // if the filename is surrounded by quotes, do this + if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { + int end = 0; + int begin = mess.Find('\"', 0); + if ( begin >= 0 ) { + end = mess.Find('\"', begin + 1); + if ( end >= 0 ) { + sFile = mess.Mid(begin+1, end-begin-1); + + begin = mess.Find(' ', end); + if ( begin >= 0 ) { + CMString rest = mess.Mid(begin, mess.GetLength()); + dwAdr = _tcstoul(GetWord(rest.c_str(), 0).c_str(), NULL, 10); + iPort = _ttoi(GetWord(rest.c_str(), 1).c_str()); + dwSize = _ttoi64(GetWord(rest.c_str(), 2).c_str()); + sToken = GetWord(rest.c_str(), 3); + } } } + } + // ... or try another method of separating the dcc command + else if ( !GetWord(mess.c_str(), (bIsChat) ? 4 : 5 ).IsEmpty()) { + int index = (bIsChat) ? 4 : 5; + bool bFlag = false; + + // look for the part of the ctcp command that contains adress, port and size + while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { + CMString sTemp; + + if ( type == _T("chat")) + sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + else + sTemp = GetWord(mess.c_str(), index-2) + GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + + // if all characters are number it indicates we have found the adress, port and size parameters + int ind = 0; + while ( sTemp[ind] != '\0' ) { + if ( !_istdigit( sTemp[ind] )) + break; + ind++; + } + + if ( sTemp[ind] == '\0' && GetWord( mess.c_str(), index + ((bIsChat) ? 1 : 2 )).IsEmpty()) + bFlag = true; + index++; + } + + if ( bFlag ) { + TCHAR* p1 = _tcsdup( GetWordAddress(mess.c_str(), 2 )); + TCHAR* p2 = ( TCHAR* )GetWordAddress( p1, index-5 ); + + if ( type == _T("send")) { + if ( p2 > p1 ) { + p2--; + while( p2 != p1 && *p2 == ' ' ) { + *p2 = '\0'; + p2--; + } + sFile = p1; + } + } + else sFile = _T("chat"); + + free( p1 ); + + dwAdr = _tcstoul(GetWord(mess.c_str(), index - (bIsChat?2:3)).c_str(), NULL, 10); + iPort = _ttoi(GetWord(mess.c_str(), index - (bIsChat?1:2)).c_str()); + dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); + sToken = GetWord(mess.c_str(), index); + } } + } + else if (type == _T("accept") || type == _T("resume")) { + // if the filename is surrounded by quotes, do this + if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { + int end = 0; + int begin = mess.Find('\"', 0); + if ( begin >= 0 ) { + end = mess.Find('\"', begin + 1); + if ( end >= 0 ) { + sFile = mess.Mid(begin+1, end); + + begin = mess.Find(' ', end); + if ( begin >= 0 ) { + CMString rest = mess.Mid(begin, mess.GetLength()); + iPort = _ttoi(GetWord(rest.c_str(), 0).c_str()); + dwSize = _ttoi(GetWord(rest.c_str(), 1).c_str()); + sToken = GetWord(rest.c_str(), 2); + } } } + } + // ... or try another method of separating the dcc command + else if ( !GetWord(mess.c_str(), 4).IsEmpty()) { + int index = 4; + bool bFlag = false; + + // look for the part of the ctcp command that contains adress, port and size + while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { + CMString sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + + // if all characters are number it indicates we have found the adress, port and size parameters + int ind = 0; + + while ( sTemp[ind] != '\0' ) { + if ( !_istdigit( sTemp[ind] )) + break; + ind++; + } + + if ( sTemp[ind] == '\0' && GetWord(mess.c_str(), index + 2).IsEmpty()) + bFlag = true; + index++; + } + if ( bFlag ) { + TCHAR* p1 = _tcsdup(GetWordAddress(mess.c_str(), 2)); + TCHAR* p2 = ( TCHAR* )GetWordAddress(p1, index-4); + + if ( p2 > p1 ) { + p2--; + while( p2 != p1 && *p2 == ' ' ) { + *p2 = '\0'; + p2--; + } + sFile = p1; + } + + free( p1 ); + + iPort = _ttoi(GetWord(mess.c_str(), index-2).c_str()); + dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); + sToken = GetWord(mess.c_str(), index); + } } } + // end separating dcc commands + + // 2. Check for malformed dcc commands or other errors + if ( bIsChat || type == _T("send")) { + TCHAR szTemp[256]; + szTemp[0] = '\0'; + + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( bIsChat && !m_DCCChatEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); + + else if(type == _T("send") && !m_DCCFileEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer request from %s denied"),pmsg->prefix.sNick.c_str()); + + else if(type == _T("send") && !iPort && ulAdr == 0) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Reverse file transfer request from %s denied [No local IP]"),pmsg->prefix.sNick.c_str()); + + if ( sFile.IsEmpty() || dwAdr == 0 || dwSize == 0 || iPort == 0 && sToken.IsEmpty()) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); + + if ( szTemp[0] ) { + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + // remove path from the filename if the remote client (stupidly) sent it + CMString sFileCorrected = sFile; + int i = sFile.ReverseFind( '\\' ); + if (i != -1 ) + sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); + sFile = sFileCorrected; + } + else if ( type == _T("accept") || type == _T("resume")) { + TCHAR szTemp[256]; + szTemp[0] = '\0'; + + if ( type == _T("resume") && !m_DCCFileEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer resume request from %s denied"),pmsg->prefix.sNick.c_str()); + + if ( sToken.IsEmpty() && iPort == 0 || sFile.IsEmpty()) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); + + if ( szTemp[0] ) { + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + // remove path from the filename if the remote client (stupidly) sent it + CMString sFileCorrected = sFile; + int i = sFile.ReverseFind( '\\' ); + if ( i != -1 ) + sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); + sFile = sFileCorrected; + } + + // 3. Take proper actions considering type of command + + // incoming chat request + if ( bIsChat ) { + CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), 0, 0, false, false, true}; + HANDLE hContact = CList_FindContact( &user ); + + // check if it should be ignored + if ( m_DCCChatIgnore == 1 || + m_DCCChatIgnore == 2 && hContact && + DBGetContactSettingByte(hContact,"CList", "NotOnList", 0) == 0 && + DBGetContactSettingByte(hContact,"CList", "Hidden", 0) == 0) + { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + CList_AddDCCChat(pmsg->prefix.sNick, host, dwAdr, iPort); // add a CHAT event to the clist + } + else { + TCHAR szTemp[512]; + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } } + + // remote requested that the file should be resumed + if ( type == _T("resume")) { + CDccSession* dcc; + if ( sToken.IsEmpty()) + dcc = FindDCCSendByPort( iPort ); + else + dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); // reverse ft + + if ( dcc ) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME); + dcc->dwResumePos = dwSize; // dwSize is the resume position + PostIrcMessage( _T("/PRIVMSG %s \001DCC ACCEPT %s\001"), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 2)); + } } + + // remote accepted your request for a file resume + if ( type == _T("accept")) { + CDccSession* dcc; + if ( sToken.IsEmpty()) + dcc = FindDCCRecvByPortAndName(iPort, pmsg->prefix.sNick.c_str()); + else + dcc = FindPassiveDCCRecv(pmsg->prefix.sNick, sToken); // reverse ft + + if ( dcc ) { + InterlockedExchange( &dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME ); + dcc->dwResumePos = dwSize; // dwSize is the resume position + SetEvent( dcc->hEvent ); + } } + + if ( type == _T("send")) { + CMString sTokenBackup = sToken; + bool bTurbo = false; // TDCC indicator + + if ( !sToken.IsEmpty() && sToken[sToken.GetLength()-1] == 'T' ) { + bTurbo = true; + sToken.Delete(sToken.GetLength()-1,1); + } + + // if a token exists and the port is non-zero it is the remote + // computer telling us that is has accepted to act as server for + // a reverse filetransfer. The plugin should connect to that computer + // and start sedning the file (if the token is valid). Compare to DCC RECV + if ( !sToken.IsEmpty() && iPort ) { + CDccSession* dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); + if ( dcc ) { + dcc->SetupPassive( dwAdr, iPort ); + dcc->Connect(); + } + } + else { + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_FILE )) + if ( !CList_FindContact( &user )) + return true; + + HANDLE hContact = CList_AddContact( &user, false, true ); + if ( hContact ) { + DCCINFO* di = new DCCINFO; + di->hContact = hContact; + di->sFile = sFile; + di->dwSize = dwSize; + di->sContactName = pmsg->prefix.sNick; + di->dwAdr = dwAdr; + di->iPort = iPort; + di->iType = DCC_SEND; + di->bSender = false; + di->bTurbo = bTurbo; + di->bSSL = false; + di->bReverse = (iPort == 0 && !sToken.IsEmpty()) ? true : false; + if ( di->bReverse ) + di->sToken = sTokenBackup; + + setTString(hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); + + TCHAR* tszTemp = ( TCHAR* )sFile.c_str(); + + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.timestamp = (DWORD)time(NULL); + pre.fileCount = 1; + pre.ptszFiles = &tszTemp; + pre.lParam = (LPARAM)di; + + CCSDATA ccs = {0}; + ccs.szProtoService = PSR_FILE; + ccs.hContact = hContact; + ccs.lParam = (LPARAM) & pre; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } } } + // end type == "send" + } + else if ( pmsg->m_bIncoming ) { + TCHAR temp[300]; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s requested by %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } } + + // handle incoming ctcp in notices. This technique is used for replying to CTCP queries + else if(pmsg->sCommand == _T("NOTICE")) { + TCHAR szTemp[300]; + szTemp[0] = '\0'; + + //if we got incoming CTCP Version for contact in CList - then write its as MirVer for that contact! + if (pmsg->m_bIncoming && command == _T("version")) + { + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + HANDLE hContact = CList_FindContact(&user); + if (hContact) + setTString( hContact, "MirVer", DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); + } + + // if the whois window is visible and the ctcp reply belongs to the user in it, then show the reply in the whois window + if ( m_whoisDlg && IsWindowVisible( m_whoisDlg->GetHwnd())) { + m_whoisDlg->m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + if ( lstrcmpi(szTemp, pmsg->prefix.sNick.c_str()) == 0 ) { + if ( pmsg->m_bIncoming && (command == _T("version") || command == _T("userinfo") || command == _T("time"))) { + SetActiveWindow( m_whoisDlg->GetHwnd()); + m_whoisDlg->m_Reply.SetText( DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); + return true; + } + if (pmsg->m_bIncoming && command == _T("ping")) { + SetActiveWindow( m_whoisDlg->GetHwnd()); + int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); + TCHAR szTemp[30]; + if ( s == 1 ) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u second"), s ); + else + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u seconds"), s ); + + m_whoisDlg->m_Reply.SetText( DoColorCodes( szTemp, TRUE, FALSE )); + return true; + } } } + + //... else show the reply in the current window + if ( pmsg->m_bIncoming && command == _T("ping")) { + int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP PING reply from %s: %u sec(s)"), pmsg->prefix.sNick.c_str(), s); + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s reply from %s: %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 1)); + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); + } } + + return true; +} + +bool CIrcProto::OnIrc_NAMES( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) + sNamesList += pmsg->parameters[3] + _T(" "); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ENDNAMES( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + CMString name = _T("a"); + int i = 0; + BOOL bFlag = false; + + // Is the user on the names list? + while ( !name.IsEmpty()) { + name = GetWord( sNamesList.c_str(), i ); + i++; + if ( !name.IsEmpty()) { + int index = 0; + while ( _tcschr( sUserModePrefixes.c_str(), name[index] )) + index++; + + if ( !lstrcmpi( name.Mid(index, name.GetLength()).c_str(), m_info.sNick.c_str())) { + bFlag = true; + break; + } } } + + if ( bFlag ) { + const TCHAR* sChanName = pmsg->parameters[1].c_str(); + if ( sChanName[0] == '@' || sChanName[0] == '*' || sChanName[0] == '=' ) + sChanName++; + + // Add a new chat window + GCSESSION gcw = {0}; + CMString sID = MakeWndID( sChanName ); + BYTE btOwnMode = 0; + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.dwFlags = GC_TCHAR; + gcw.ptszID = sID.c_str(); + gcw.pszModule = m_szModuleName; + gcw.ptszName = sChanName; + if ( !CallServiceSync( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw )) { + DBVARIANT dbv; + GCDEST gcd = {0}; + GCEVENT gce = {0}; + CMString sTemp; + int i = 0; + + PostIrcMessage( _T("/MODE %s"), sChanName ); + + gcd.ptszID = ( TCHAR* )sID.c_str(); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_ADDGROUP; + gce.time = 0; + gce.dwFlags = GC_TCHAR; + + //register the statuses + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + + gce.ptszStatus = _T("Owner"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Admin"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Op"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Halfop"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Voice"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Normal"); + CallChatEvent(0, (LPARAM)&gce); + + i = 0; + sTemp = GetWord(sNamesList.c_str(), i); + + // Fill the nicklist + while ( !sTemp.IsEmpty()) { + CMString sStat; + CMString sTemp2 = sTemp; + sStat = PrefixToStatus(sTemp[0]); + + // fix for networks like freshirc where they allow more than one prefix + while ( PrefixToStatus(sTemp[0]) != _T("Normal")) + sTemp.Delete(0,1); + + gcd.iType = GC_EVENT_JOIN; + gce.ptszUID = sTemp.c_str(); + gce.ptszNick = sTemp.c_str(); + gce.ptszStatus = sStat.c_str(); + BOOL bIsMe = ( !lstrcmpi( gce.ptszNick, m_info.sNick.c_str())) ? TRUE : FALSE; + if ( bIsMe ) { + char BitNr = -1; + switch ( sTemp2[0] ) { + case '+': BitNr = 0; break; + case '%': BitNr = 1; break; + case '@': BitNr = 2; break; + case '!': BitNr = 3; break; + case '*': BitNr = 4; break; + } + if (BitNr >=0) + btOwnMode = ( 1 << BitNr ); + else + btOwnMode = 0; + } + gce.dwFlags = GC_TCHAR; + gce.bIsMe = bIsMe; + gce.time = bIsMe?time(0):0; + CallChatEvent(0, (LPARAM)&gce); + DoEvent( GC_EVENT_SETCONTACTSTATUS, sChanName, sTemp.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE ); + // fix for networks like freshirc where they allow more than one prefix + if ( PrefixToStatus( sTemp2[0]) != _T("Normal")) { + sTemp2.Delete(0,1); + sStat = PrefixToStatus(sTemp2[0]); + while ( sStat != _T("Normal")) { + DoEvent( GC_EVENT_ADDSTATUS, sID.c_str(), sTemp.c_str(), _T("system"), sStat.c_str(), NULL, NULL, false, false, 0 ); + sTemp2.Delete(0,1); + sStat = PrefixToStatus(sTemp2[0]); + } } + + i++; + sTemp = GetWord(sNamesList.c_str(), i); + } + + //Set the item data for the window + { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, sChanName, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if (!wi) + wi = new CHANNELINFO; + wi->OwnMode = btOwnMode; + wi->pszLimit = 0; + wi->pszMode = 0; + wi->pszPassword = 0; + wi->pszTopic = 0; + wi->codepage = getCodepage(); + DoEvent(GC_EVENT_SETITEMDATA, sChanName, NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0); + + if ( !sTopic.IsEmpty() && !lstrcmpi(GetWord(sTopic.c_str(), 0).c_str(), sChanName )) { + DoEvent(GC_EVENT_TOPIC, sChanName, sTopicName.IsEmpty() ? NULL : sTopicName.c_str(), GetWordAddress(sTopic.c_str(), 1), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); + AddWindowItemData(sChanName, 0, 0, 0, GetWordAddress(sTopic.c_str(), 1)); + sTopic = _T(""); + sTopicName = _T(""); + sTopicTime = _T(""); + } } + + gcd.ptszID = (TCHAR*)sID.c_str(); + gcd.iType = GC_EVENT_CONTROL; + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.bIsMe = false; + gce.dwItemData = false; + gce.pszNick = NULL; + gce.pszStatus = NULL; + gce.pszText = NULL; + gce.pszUID = NULL; + gce.pszUserInfo = NULL; + gce.time = time(0); + gce.pDest = &gcd; + + if ( !getTString( "JTemp", &dbv )) { + CMString command = _T("a"); + CMString save = _T(""); + int i = 0; + + while ( !command.IsEmpty()) { + command = GetWord( dbv.ptszVal, i ); + i++; + if ( !command.IsEmpty()) { + CMString S = command.Mid(1, command.GetLength()); + if ( !lstrcmpi( sChanName, S.c_str())) + break; + + save += command + _T(" "); + } } + + if ( !command.IsEmpty()) { + save += GetWordAddress( dbv.ptszVal, i ); + switch ( command[0] ) { + case 'M': + CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); + break; + case 'X': + CallChatEvent( WINDOW_MAXIMIZE, (LPARAM)&gce); + break; + default: + CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + break; + } + } + else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + + if ( save.IsEmpty()) + DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); + else + setTString("JTemp", save.c_str()); + DBFreeVariant(&dbv); + } + else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + + { gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); + } } } } + + sNamesList = _T(""); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INITIALTOPIC( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { + AddWindowItemData( pmsg->parameters[1].c_str(), 0, 0, 0, pmsg->parameters[2].c_str()); + sTopic = pmsg->parameters[1] + _T(" ") + pmsg->parameters[2]; + sTopicName = _T(""); + sTopicTime = _T(""); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INITIALTOPICNAME( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) { + TCHAR tTimeBuf[128], *tStopStr; + time_t ttTopicTime; + sTopicName = pmsg->parameters[2]; + ttTopicTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); + _tcsftime(tTimeBuf, 128, _T("%#c"), localtime(&ttTopicTime)); + sTopicTime = tTimeBuf; + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_TOPIC( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { + DoEvent( GC_EVENT_TOPIC, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str(), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); + AddWindowItemData(pmsg->parameters[0].c_str(), 0, 0, 0, pmsg->parameters[1].c_str()); + } + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowDlgList( void* param ) +{ + CIrcProto* ppro = ( CIrcProto* )param; + if ( ppro->m_listDlg == NULL ) { + ppro->m_listDlg = new CListDlg( ppro ); + ppro->m_listDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); +} + +bool CIrcProto::OnIrc_LISTSTART( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + CallFunctionAsync( sttShowDlgList, this ); + WaitForSingleObject( m_evWndCreate, INFINITE ); + m_channelNumber = 0; + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_LIST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming == 1 && m_listDlg && pmsg->parameters.getCount() > 2 ) { + m_channelNumber++; + LVITEM lvItem; + HWND hListView = GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW ); + lvItem.iItem = ListView_GetItemCount( hListView ); + lvItem.mask = LVIF_TEXT | LVIF_PARAM; + lvItem.iSubItem = 0; + lvItem.pszText = (TCHAR*)pmsg->parameters[1].c_str(); + lvItem.lParam = lvItem.iItem; + lvItem.iItem = ListView_InsertItem( hListView, &lvItem ); + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem =1; + lvItem.pszText = (TCHAR*)pmsg->parameters[pmsg->parameters.getCount()-2].c_str(); + ListView_SetItem( hListView, &lvItem ); + + TCHAR* temp = mir_tstrdup( pmsg->parameters[pmsg->parameters.getCount()-1] ); + TCHAR* find = _tcsstr( temp , _T("[+")); + TCHAR* find2 = _tcsstr( temp , _T("]")); + TCHAR* save = temp; + if ( find == temp && find2 != NULL && find+8 >= find2 ) { + temp = _tcsstr( temp, _T("]")); + if ( lstrlen(temp) > 1 ) { + temp++; + temp[0] = '\0'; + lvItem.iSubItem =2; + lvItem.pszText = save; + ListView_SetItem(hListView,&lvItem); + temp[0] = ' '; + temp++; + } + else temp =save; + } + + lvItem.iSubItem =3; + CMString S = DoColorCodes(temp, TRUE, FALSE); + lvItem.pszText = ( TCHAR* )S.c_str(); + ListView_SetItem( hListView, &lvItem ); + temp = save; + mir_free( temp ); + + int percent = 100; + if ( m_noOfChannels > 0 ) + percent = (int)(m_channelNumber*100) / m_noOfChannels; + + TCHAR text[100]; + if ( percent < 100) + mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list (%u%%) - %u channels"), percent, m_channelNumber); + else + mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list - %u channels"), m_channelNumber); + m_listDlg->m_status.SetText( text ); + } + + return true; +} + +bool CIrcProto::OnIrc_LISTEND( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_listDlg ) { + EnableWindow(GetDlgItem(m_listDlg->GetHwnd(), IDC_JOIN), true); + ListView_SetSelectionMark(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 0); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 1, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 2, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 3, LVSCW_AUTOSIZE); + m_listDlg->UpdateList(); + + TCHAR text[100]; + mir_sntprintf( text, SIZEOF(text), TranslateT("Done: %u channels"), m_channelNumber ); + int percent = 100; + if ( m_noOfChannels > 0 ) + percent = (int)(m_channelNumber*100) / m_noOfChannels; + if ( percent < 70 ) { + lstrcat( text, _T(" ")); + lstrcat( text, TranslateT("(probably truncated by server)")); + } + SetDlgItemText( m_listDlg->GetHwnd(), IDC_TEXT, text ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_BANLIST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { + if ( m_managerDlg->GetHwnd() && ( + m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("367") || + m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("346") || + m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("348")) && + !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) + { + CMString S = pmsg->parameters[2]; + if ( pmsg->parameters.getCount() > 3 ) { + S += _T(" - "); + S += pmsg->parameters[3]; + if ( pmsg->parameters.getCount() > 4 ) { + S += _T(" - ( "); + time_t time = StrToInt( pmsg->parameters[4].c_str()); + S += _tctime( &time ); + ReplaceString( S, _T("\n"), _T(" ")); + S += _T(")"); + } } + + SendDlgItemMessage(m_managerDlg->GetHwnd(), IDC_LIST, LB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_BANLISTEND( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( m_managerDlg->GetHwnd() && + ( m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("368") + || m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("347") + || m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("349")) && + !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) + { + if ( strchr( sChannelModes.c_str(), 'b' )) + m_managerDlg->m_radio1.Enable(); + if ( strchr( sChannelModes.c_str(), 'I' )) + m_managerDlg->m_radio2.Enable(); + if ( strchr( sChannelModes.c_str(), 'e' )) + m_managerDlg->m_radio3.Enable(); + if ( !IsDlgButtonChecked(m_managerDlg->GetHwnd(), IDC_NOTOP)) + m_managerDlg->m_add.Enable(); + } } + + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowWhoisWnd( void* param ) +{ + CIrcMessage* pmsg = ( CIrcMessage* )param; + CIrcProto* ppro = ( CIrcProto* )pmsg->m_proto; + if ( ppro->m_whoisDlg == NULL ) { + ppro->m_whoisDlg = new CWhoisDlg( ppro ); + ppro->m_whoisDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); + + ppro->m_whoisDlg->ShowMessage( pmsg ); + delete pmsg; +} + +bool CIrcProto::OnIrc_WHOIS_NAME( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 5 && m_manualWhoisCount > 0 ) { + CallFunctionAsync( sttShowWhoisWnd, new CIrcMessage( *pmsg )); + WaitForSingleObject( m_evWndCreate, INFINITE ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_CHANNELS( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoChannels.SetText( pmsg->parameters[2].c_str()); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_AWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoAway2.SetText( pmsg->parameters[2].c_str()); + if ( m_manualWhoisCount < 1 && pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) + WhoisAwayReply = pmsg->parameters[2]; + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_OTHER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + TCHAR temp[1024], temp2[1024]; + m_whoisDlg->m_InfoOther.GetText( temp, 1000 ); + lstrcat( temp, _T("%s\r\n")); + mir_sntprintf( temp2, 1020, temp, pmsg->parameters[2].c_str()); + m_whoisDlg->m_InfoOther.SetText( temp2 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_END( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 && m_manualWhoisCount < 1 ) { + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, true}; + HANDLE hContact = CList_FindContact( &user ); + if ( hContact ) + ProtoBroadcastAck( m_szModuleName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM)WhoisAwayReply.c_str()); + } + + m_manualWhoisCount--; + if (m_manualWhoisCount < 0) + m_manualWhoisCount = 0; + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_IDLE( const CIrcMessage* pmsg ) +{ + int D = 0; + int H = 0; + int M = 0; + int S = 0; + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + S = StrToInt(pmsg->parameters[2].c_str()); + D = S/(60*60*24); + S -= (D * 60 * 60 *24); + H = S/(60*60); + S -= (H * 60 * 60); + M = S/60; + S -= (M * 60 ); + + TCHAR temp[100]; + if ( D ) + mir_sntprintf(temp, 99, _T("%ud, %uh, %um, %us"), D, H, M, S); + else if (H) + mir_sntprintf(temp, 99, _T("%uh, %um, %us"), H, M, S); + else if (M) + mir_sntprintf(temp, 99, _T("%um, %us"), M, S); + else if (S) + mir_sntprintf(temp, 99, _T("%us"), S); + else + temp[0] = 0; + + TCHAR temp3[256]; + TCHAR tTimeBuf[128], *tStopStr; + time_t ttTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); + _tcsftime(tTimeBuf, 128, _T("%c"), localtime(&ttTime)); + mir_sntprintf( temp3, SIZEOF(temp3), _T("online since %s, idle %s"), tTimeBuf, temp); + m_whoisDlg->m_AwayTime.SetText( temp3 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_SERVER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoServer.SetText( pmsg->parameters[2].c_str()); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_AUTH( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + if ( pmsg->sCommand == _T("330")) + m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); + else if ( pmsg->parameters[2] == _T("is an identified user") || pmsg->parameters[2] == _T("is a registered nick")) + m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); + else + OnIrc_WHOIS_OTHER( pmsg ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_NO_USER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 && !IsChannel( pmsg->parameters[1] )) { + if ( m_whoisDlg ) + m_whoisDlg->ShowMessageNoUser( pmsg ); + + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, false}; + HANDLE hContact = CList_FindContact( &user ); + if ( hContact ) { + AddOutgoingMessageToDB( hContact, (TCHAR*)((CMString)_T("> ") + pmsg->parameters[2] + (CMString)_T(": ") + pmsg->parameters[1]).c_str()); + + DBVARIANT dbv; + if ( !getTString( hContact, "Default", &dbv )) { + setTString( hContact, "Nick", dbv.ptszVal ); + + DBVARIANT dbv2; + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason(1, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); + else { + if ( !getTString( hContact, "UWildcard", &dbv2 )) { + DoUserhostWithReason(2, ((CMString)_T("S") + dbv2.ptszVal).c_str(), true, dbv2.ptszVal ); + DBFreeVariant(&dbv2); + } + else DoUserhostWithReason(2, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); + } + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + DBFreeVariant(&dbv); + } } } + + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowNickWnd( void* param ) +{ + CIrcMessage* pmsg = ( CIrcMessage* )param; + CIrcProto* ppro = pmsg->m_proto; + if ( ppro->m_nickDlg == NULL ) { + ppro->m_nickDlg = new CNickDlg( ppro ); + ppro->m_nickDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); + SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_CAPTION ), TranslateT("Change nickname")); + SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_TEXT ), pmsg->parameters.getCount() > 2 ? pmsg->parameters[2].c_str() : _T("")); + ppro->m_nickDlg->m_Enick.SetText( pmsg->parameters[1].c_str()); + ppro->m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); + delete pmsg; +} + +bool CIrcProto::OnIrc_NICK_ERR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + if ( nickflag && ((m_alternativeNick[0] != 0)) && (pmsg->parameters.getCount() > 2 && _tcscmp(pmsg->parameters[1].c_str(), m_alternativeNick))) { + TCHAR m[200]; + mir_sntprintf( m, SIZEOF(m), _T("NICK %s"), m_alternativeNick ); + if ( IsConnected()) + SendIrcMessage( m ); + } + else { + CallFunctionAsync( sttShowNickWnd, new CIrcMessage( *pmsg )); + WaitForSingleObject( m_evWndCreate, INFINITE ); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_JOINERROR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + DBVARIANT dbv; + if ( !getTString( "JTemp", &dbv )) { + CMString command = _T("a"); + CMString save = _T(""); + int i = 0; + + while ( !command.IsEmpty()) { + command = GetWord( dbv.ptszVal, i ); + i++; + + if ( !command.IsEmpty() && pmsg->parameters[0] == command.Mid(1, command.GetLength())) + save += command + _T(" "); + } + + DBFreeVariant(&dbv); + + if ( save.IsEmpty()) + DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); + else + setTString( "JTemp", save.c_str()); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_UNKNOWN( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + if ( pmsg->parameters[0] == _T("WHO") && GetNextUserhostReason(2) != _T("U")) + return true; + if ( pmsg->parameters[0] == _T("USERHOST") && GetNextUserhostReason(1) != _T("U")) + return true; + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ENDMOTD( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect( pmsg ); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_NOOFCHANNELS( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) + m_noOfChannels = StrToInt( pmsg->parameters[1].c_str()); + + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect( pmsg ); + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ERROR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && !m_disableErrorPopups && m_iDesiredStatus != ID_STATUS_OFFLINE) { + MIRANDASYSTRAYNOTIFY msn; + msn.cbSize = sizeof(MIRANDASYSTRAYNOTIFY); + msn.szProto = m_szModuleName; + msn.tszInfoTitle = TranslateT("IRC error"); + + CMString S; + if ( pmsg->parameters.getCount() > 0 ) + S = DoColorCodes( pmsg->parameters[0].c_str(), TRUE, FALSE ); + else + S = TranslateT( "Unknown" ); + + msn.tszInfo = ( TCHAR* )S.c_str(); + msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; + msn.uTimeout = 15000; + CallService( MS_CLIST_SYSTRAY_NOTIFY, 0, ( LPARAM )&msn ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHO_END( const CIrcMessage* pmsg ) +{ + CMString command = GetNextUserhostReason(2); + if ( command[0] == 'S' ) { + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + // is it a channel? + if ( IsChannel( pmsg->parameters[1] )) { + CMString S; + CMString User = GetWord( m_whoReply.c_str(), 0 ); + while ( !User.IsEmpty()) { + if ( GetWord( m_whoReply.c_str(), 3)[0] == 'G' ) { + S += User; + S += _T("\t"); + DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_AWAY, FALSE, FALSE); + } + else DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); + + CMString SS = GetWordAddress( m_whoReply.c_str(), 4 ); + if ( SS.IsEmpty()) + break; + m_whoReply = SS; + User = GetWord(m_whoReply.c_str(), 0); + } + + DoEvent( GC_EVENT_SETSTATUSEX, pmsg->parameters[1].c_str(), NULL, S.IsEmpty() ? NULL : S.c_str(), NULL, NULL, GC_SSE_TABDELIMITED, FALSE, FALSE); + return true; + } + + /// if it is not a channel + TCHAR* UserList = mir_tstrdup( m_whoReply.c_str()); + const TCHAR* p1= UserList; + m_whoReply = _T(""); + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, true, false}; + HANDLE hContact = CList_FindContact( &user ); + + if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 1 ) { + DBVARIANT dbv1, dbv2, dbv3, dbv4, dbv5, dbv6, dbv7; + TCHAR *DBDefault = NULL, *DBNick = NULL, *DBWildcard = NULL; + TCHAR *DBUser = NULL, *DBHost = NULL, *DBManUser = NULL, *DBManHost = NULL; + if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; + if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; + if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; + if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; + if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; + if ( !getTString(hContact, "User", &dbv6)) DBManUser = dbv6.ptszVal; + if ( !getTString(hContact, "Host", &dbv7)) DBManHost = dbv7.ptszVal; + if ( DBWildcard ) + CharLower( DBWildcard ); + + CMString nick; + CMString user; + CMString host; + CMString away = GetWord(p1, 3); + + while ( !away.IsEmpty()) { + nick = GetWord(p1, 0); + user = GetWord(p1, 1); + host = GetWord(p1, 2); + if (( DBWildcard && WCCmp( DBWildcard, nick.c_str()) || DBNick && !lstrcmpi(DBNick, nick.c_str()) || DBDefault && !lstrcmpi(DBDefault, nick.c_str())) + && (WCCmp(DBUser, user.c_str()) && WCCmp(DBHost, host.c_str()))) + { + if (away[0] == 'G' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_AWAY) + setWord(hContact, "Status", ID_STATUS_AWAY); + else if (away[0] == 'H' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_ONLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + + if (( DBNick && lstrcmpi( nick.c_str(), DBNick)) || !DBNick ) + setTString( hContact, "Nick", nick.c_str()); + if (( DBManUser && lstrcmpi( user.c_str(), DBManUser)) || !DBManUser ) + setTString( hContact, "User", user.c_str()); + if (( DBManHost && lstrcmpi(host.c_str(), DBManHost)) || !DBManHost ) + setTString(hContact, "Host", host.c_str()); + + goto LBL_Exit; + } + p1 = GetWordAddress(p1, 4); + away = GetWord(p1, 3); + } + + if ( DBWildcard && DBNick && !WCCmp( CharLower( DBWildcard ), CharLower( DBNick ))) { + setTString(hContact, "Nick", DBDefault); + + DoUserhostWithReason(2, ((CMString)_T("S") + DBWildcard).c_str(), true, DBWildcard); + + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + goto LBL_Exit; + } + + if ( getWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) { + setWord(hContact, "Status", ID_STATUS_OFFLINE); + setTString(hContact, "Nick", DBDefault); + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + } +LBL_Exit: + if ( DBDefault ) DBFreeVariant(&dbv1); + if ( DBNick ) DBFreeVariant(&dbv2); + if ( DBWildcard ) DBFreeVariant(&dbv3); + if ( DBUser ) DBFreeVariant(&dbv4); + if ( DBHost ) DBFreeVariant(&dbv5); + if ( DBManUser ) DBFreeVariant(&dbv6); + if ( DBManHost ) DBFreeVariant(&dbv7); + } + mir_free( UserList ); + } + } + else ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHO_REPLY( const CIrcMessage* pmsg ) +{ + CMString command = PeekAtReasons(2); + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 6 && command[0] == 'S' ) { + m_whoReply.AppendFormat( _T("%s %s %s %s "), pmsg->parameters[5].c_str(), pmsg->parameters[2].c_str(), pmsg->parameters[3].c_str(), pmsg->parameters[6].c_str()); + if ( lstrcmpi( pmsg->parameters[5].c_str(), m_info.sNick.c_str()) == 0 ) { + TCHAR host[1024]; + lstrcpyn( host, pmsg->parameters[3].c_str(), 1024 ); + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(host), IP_AUTO )); + } } + + if ( command[0] == 'U' ) + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_TRYAGAIN( const CIrcMessage* pmsg ) +{ + CMString command = _T(""); + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( pmsg->parameters[1] == _T("WHO")) + command = GetNextUserhostReason(2); + + if ( pmsg->parameters[1] == _T("USERHOST")) + command = GetNextUserhostReason(1); + } + if (command[0] == 'U') + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_USERHOST_REPLY( const CIrcMessage* pmsg ) +{ + CMString command = _T(""); + if ( pmsg->m_bIncoming ) { + command = GetNextUserhostReason(1); + if ( !command.IsEmpty() && command != _T("U") && pmsg->parameters.getCount() > 1 ) { + CONTACT finduser = {NULL, NULL, NULL, false, false, false}; + TCHAR* p1 = NULL; + TCHAR* p2 = NULL; + int awaystatus = 0; + CMString sTemp; + CMString host; + CMString user; + CMString nick; + CMString mask; + CMString mess; + CMString channel; + int i; + int j; + + // Status-check pre-processing: Setup check-list + OBJLIST checklist( 10 ); + if ( command[0] == 'S' ) { + j = 0; + sTemp = GetWord(command.c_str(), 0); + sTemp.Delete(0,1); + while ( !sTemp.IsEmpty()) { + checklist.insert( new CMString( sTemp )); + j++; + sTemp = GetWord(command.c_str(), j); + } } + + // Cycle through results + j = 0; + sTemp = GetWord( pmsg->parameters[1].c_str(), j ); + while ( !sTemp.IsEmpty()) { + p1 = mir_tstrdup( sTemp.c_str()); + p2 = p1; + + // Pull out host, user and nick + p2 = _tcschr(p1, '@'); + if ( p2 ) { + *p2 = '\0'; + p2++; + host = p2; + } + p2 = _tcschr(p1, '='); + if ( p2 ) { + if (*(p2-1) == '*') + *(p2-1) = '\0'; // remove special char for IRCOps + *p2 = '\0'; + p2++; + awaystatus = *p2; + p2++; + user = p2; + nick = p1; + } + mess = _T(""); + mask = nick + _T("!") + user + _T("@") + host; + if ( host.IsEmpty() || user.IsEmpty() || nick.IsEmpty()) { + mir_free( p1 ); + continue; + } + + // Do command + switch ( command[0] ) { + case 'S': // Status check + { + finduser.name = (TCHAR*)nick.c_str(); + finduser.host = (TCHAR*)host.c_str(); + finduser.user = (TCHAR*)user.c_str(); + + HANDLE hContact = CList_FindContact(&finduser); + if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 0 ) { + setWord(hContact, "Status", awaystatus == '-'? ID_STATUS_AWAY : ID_STATUS_ONLINE); + setTString(hContact, "User", user.c_str()); + setTString(hContact, "Host", host.c_str()); + setTString(hContact, "Nick", nick.c_str()); + + // If user found, remove from checklist + for ( i = 0; i < checklist.getCount(); i++ ) + if ( !lstrcmpi(checklist[i].c_str(), nick.c_str())) + checklist.remove( i ); + } + break; + } + case 'I': // m_ignore + mess = _T("/IGNORE %question=\""); + mess += TranslateT("Please enter the hostmask (nick!user@host)\nNOTE! Contacts on your contact list are never ignored"); + mess += (CMString)_T("\",\"") + TranslateT("Ignore") + _T("\",\"*!*@") + host + _T("\""); + if ( m_ignoreChannelDefault ) + mess += _T(" +qnidcm"); + else + mess += _T(" +qnidc"); + break; + + case 'J': // Unignore + mess = _T("/UNIGNORE *!*@") + host; + break; + + case 'B': // Ban + channel = (command.c_str() + 1); + mess = _T("/MODE ") + channel + _T(" +b *!*@") + host; + break; + + case 'K': // Ban & Kick + channel = (command.c_str() + 1); + mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s"), channel.c_str(), host.c_str(), channel.c_str(), nick.c_str()); + break; + + case 'L': // Ban & Kick with reason + channel = (command.c_str() + 1); + mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), + channel.c_str(), host.c_str(), channel.c_str(), nick.c_str(), + TranslateT("Please enter the reason"), TranslateT("Ban'n Kick"), TranslateT("Jerk")); + break; + } + + mir_free( p1 ); + + // Post message + if ( !mess.IsEmpty()) + PostIrcMessageWnd( NULL, NULL, mess.c_str()); + j++; + sTemp = GetWord(pmsg->parameters[1].c_str(), j); + } + + // Status-check post-processing: make buddies in ckeck-list offline + if ( command[0] == 'S' ) { + for ( i = 0; i < checklist.getCount(); i++ ) { + finduser.name = (TCHAR*)checklist[i].c_str(); + finduser.ExactNick = true; + CList_SetOffline( &finduser ); + } } + + return true; + } } + + if ( !pmsg->m_bIncoming || command == _T("U")) + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_SUPPORT( const CIrcMessage* pmsg ) +{ + static const TCHAR* lpszFmt = _T("Try server %99[^ ,], port %19s"); + TCHAR szAltServer[100]; + TCHAR szAltPort[20]; + if ( pmsg->parameters.getCount() > 1 && _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szAltServer, &szAltPort) == 2 ) { + ShowMessage( pmsg ); + lstrcpynA( m_serverName, _T2A(szAltServer), 99 ); + lstrcpynA( m_portStart, _T2A(szAltPort), 9 ); + + m_noOfChannels = 0; + ConnectToServer(); + return true; + } + + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect(pmsg); + + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + CMString S; + for ( int i = 0; i < pmsg->parameters.getCount(); i++ ) { + TCHAR* temp = mir_tstrdup( pmsg->parameters[i].c_str()); + if ( _tcsstr( temp, _T("CHANTYPES="))) { + TCHAR* p1 = _tcschr( temp, '=' ); + p1++; + if ( lstrlen( p1 ) > 0 ) + sChannelPrefixes = p1; + } + if ( _tcsstr(temp, _T("CHANMODES="))) { + TCHAR* p1 = _tcschr( temp, '=' ); + p1++; + if ( lstrlen( p1 ) > 0) + sChannelModes = ( char* )_T2A( p1 ); + } + if ( _tcsstr( temp, _T("PREFIX="))) { + TCHAR* p1 = _tcschr( temp, '(' ); + TCHAR* p2 = _tcschr( temp, ')' ); + if ( p1 && p2 ) { + p1++; + if ( p1 != p2 ) + sUserModes = ( char* )_T2A( p1 ); + sUserModes = sUserModes.Mid(0, p2-p1); + p2++; + if ( *p2 != '\0' ) + sUserModePrefixes = p2; + } + else { + p1 = _tcschr( temp, '=' ); + p1++; + sUserModePrefixes = p1; + for ( int i =0; i < sUserModePrefixes.GetLength()+1; i++ ) { + if ( sUserModePrefixes[i] == '@' ) + sUserModes.SetAt( i, 'o' ); + else if ( sUserModePrefixes[i] == '+' ) + sUserModes.SetAt( i, 'v' ); + else if ( sUserModePrefixes[i] == '-' ) + sUserModes.SetAt( i, 'u' ); + else if ( sUserModePrefixes[i] == '%' ) + sUserModes.SetAt( i, 'h' ); + else if ( sUserModePrefixes[i] == '!' ) + sUserModes.SetAt( i, 'a' ); + else if ( sUserModePrefixes[i] == '*' ) + sUserModes.SetAt( i, 'q' ); + else if ( sUserModePrefixes[i] == '\0' ) + sUserModes.SetAt( i, '\0' ); + else + sUserModes.SetAt( i, '_' ); + } } } + + mir_free( temp ); + } } + + ShowMessage( pmsg ); + return true; +} + +void CIrcProto::OnIrcDefault( const CIrcMessage* pmsg ) +{ + ShowMessage( pmsg ); +} + +void CIrcProto::OnIrcDisconnected() +{ + m_statusMessage = _T(""); + DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); + bTempDisableCheck = false; + bTempForceCheck = false; + m_iTempCheckTime = 0; + + m_myHost[0] = '\0'; + + int Temp = m_iStatus; + KillIdent(); + KillChatTimer( OnlineNotifTimer ); + KillChatTimer( OnlineNotifTimer3 ); + KillChatTimer( KeepAliveTimer ); + KillChatTimer( InitTimer ); + KillChatTimer( IdentTimer ); + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_OFFLINE); + + CMString sDisconn = _T("\0035\002"); + sDisconn += TranslateT("*Disconnected*"); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, sDisconn.c_str(), NULL, NULL, NULL, true, false); + + { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.cbSize = sizeof(GCEVENT); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + + if ( !Miranda_Terminated()) + CList_SetAllOffline( m_disconnectDCCChats ); + + // restore the original nick, cause it might be changed + memcpy( m_nick, m_pNick, sizeof( m_nick )); + setTString( "Nick", m_pNick ); + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnConnect + +static void __stdcall sttMainThrdOnConnect( void* param ) +{ + CIrcProto* ppro = ( CIrcProto* )param; + + ppro->SetChatTimer( ppro->InitTimer, 1*1000, TimerProc ); + if ( ppro->m_identTimer ) + ppro->SetChatTimer( ppro->IdentTimer, 60*1000, IdentTimerProc ); + if ( ppro->m_sendKeepAlive ) + ppro->SetChatTimer( ppro->KeepAliveTimer, 60*1000, KeepAliveTimerProc ); + if ( ppro->m_autoOnlineNotification && !ppro->bTempDisableCheck || ppro->bTempForceCheck ) { + ppro->SetChatTimer( ppro->OnlineNotifTimer, 1000, OnlineNotifTimerProc ); + if ( ppro->m_channelAwayNotification ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 3000, OnlineNotifTimerProc3); +} } + +bool CIrcProto::DoOnConnect( const CIrcMessage* ) +{ + bPerformDone = true; + nickflag = true; + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); + + int Temp = m_iStatus; + m_iStatus = ID_STATUS_ONLINE; + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE )Temp, m_iStatus ); + + if ( m_iDesiredStatus == ID_STATUS_AWAY ) + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + + if ( m_perform ) { + DoPerform( "ALL NETWORKS" ); + if ( IsConnected()) { + DoPerform( _T2A( m_info.sNetwork.c_str())); + switch( m_iStatus ) { + case ID_STATUS_FREECHAT: DoPerform( "Event: Free for chat" ); break; + case ID_STATUS_ONLINE: DoPerform( "Event: Available" ); break; + } } } + + if ( m_rejoinChannels ) { + int count = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); + for ( int i = 0; i < count ; i++ ) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX | DATA | NAME | TYPE; + gci.iItem = i; + gci.pszModule = m_szModuleName; + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci) && gci.iType == GCW_CHATROOM ) { + CHANNELINFO* wi = ( CHANNELINFO* )gci.dwItemData; + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), gci.pszName, wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), gci.pszName); + } } } + + DoEvent( GC_EVENT_ADDGROUP, SERVERWINDOW, NULL, NULL, _T("Normal"), NULL, NULL, FALSE, TRUE); + { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.dwFlags = GC_TCHAR; + gce.cbSize = sizeof(GCEVENT); + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); + } + + CallFunctionAsync( sttMainThrdOnConnect, this ); + nickflag = false; + return 0; +} + +static void __cdecl AwayWarningThread(LPVOID) +{ + MessageBox(NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); +} + +int CIrcProto::DoPerform( const char* event ) +{ + String sSetting = String("PERFORM:") + event; + sSetting.MakeUpper(); + + DBVARIANT dbv; + if ( !getTString( sSetting.c_str(), &dbv )) { + if ( !my_strstri( dbv.ptszVal, _T("/away"))) + PostIrcMessageWnd( NULL, NULL, dbv.ptszVal ); + else + mir_forkthread( AwayWarningThread, NULL ); + DBFreeVariant( &dbv ); + return 1; + } + return 0; +} + +int CIrcProto::IsIgnored( const CMString& nick, const CMString& address, const CMString& host, char type) +{ + return IsIgnored( nick + _T("!") + address + _T("@") + host, type ); +} + +int CIrcProto::IsIgnored( CMString user, char type ) +{ + for ( int i=0; i < m_ignoreItems.getCount(); i++ ) { + const CIrcIgnoreItem& C = m_ignoreItems[i]; + + if ( type == '\0' ) + if ( !lstrcmpi( user.c_str(), C.mask.c_str())) + return i+1; + + bool bUserContainsWild = ( _tcschr( user.c_str(), '*') != NULL || _tcschr( user.c_str(), '?' ) != NULL ); + if ( !bUserContainsWild && WCCmp( C.mask.c_str(), user.c_str()) || + bUserContainsWild && !lstrcmpi( user.c_str(), C.mask.c_str())) + { + if ( C.flags.IsEmpty() || C.flags[0] != '+' ) + continue; + + if ( !_tcschr( C.flags.c_str(), type )) + continue; + + if ( C.network.IsEmpty()) + return i+1; + + if ( IsConnected() && !lstrcmpi( C.network.c_str(), m_info.sNetwork.c_str())) + return i+1; + } } + + return 0; +} + +bool CIrcProto::AddIgnore( const TCHAR* mask, const TCHAR* flags, const TCHAR* network ) +{ + RemoveIgnore( mask ); + m_ignoreItems.insert( new CIrcIgnoreItem( mask, (_T("+") + CMString(flags)).c_str(), network )); + RewriteIgnoreSettings(); + + if ( m_ignoreDlg ) + m_ignoreDlg->RebuildList(); + return true; +} + +bool CIrcProto::RemoveIgnore( const TCHAR* mask ) +{ + int idx; + while (( idx = IsIgnored( mask, '\0')) != 0 ) + m_ignoreItems.remove( idx-1 ); + + RewriteIgnoreSettings(); + + if ( m_ignoreDlg ) + m_ignoreDlg->RebuildList(); + return true; +} diff --git a/protocols/IRCG/src/commandmonitor.h b/protocols/IRCG/src/commandmonitor.h new file mode 100644 index 0000000000..940cb9cc02 --- /dev/null +++ b/protocols/IRCG/src/commandmonitor.h @@ -0,0 +1,22 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +using namespace irc; diff --git a/protocols/IRCG/src/input.cpp b/protocols/IRCG/src/input.cpp new file mode 100644 index 0000000000..c564b7844c --- /dev/null +++ b/protocols/IRCG/src/input.cpp @@ -0,0 +1,936 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" +#include "version.h" + +#define NICKSUBSTITUTE _T("!_nick_!") + +void CIrcProto::FormatMsg(CMString& text) +{ + TCHAR temp[30]; + lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29); + CharLower(temp); + CMString command = temp; + CMString S = _T(""); + if (command == _T("/quit") || command == _T("/away")) + S = GetWord(text.c_str(), 0) + _T(" :") + GetWordAddress(text.c_str(), 1); + else if (command == _T("/privmsg") || command == _T("/part") || command == _T("/topic") || command == _T("/notice")) { + S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" :"); + if (!GetWord(text.c_str(), 2).IsEmpty()) + S += CMString(GetWordAddress(text.c_str(), 2)); + } + else if (command == _T("/kick")) { + S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" ") + GetWord(text.c_str(), 2) + _T(" :") + GetWordAddress(text.c_str(), 3); + } + else if (command == _T("/nick")) { + if ( !_tcsstr(GetWord(text.c_str(), 1).c_str(), NICKSUBSTITUTE )) { + sNick4Perform = GetWord(text.c_str(), 1); + S = GetWordAddress(text.c_str(), 0); + } + else { + CMString sNewNick = GetWord(text.c_str(), 1); + if ( sNick4Perform == _T("")) { + DBVARIANT dbv; + if ( !getTString( "PNick", &dbv )) { + sNick4Perform = dbv.ptszVal; + DBFreeVariant(&dbv); + } } + + ReplaceString( sNewNick, NICKSUBSTITUTE, sNick4Perform.c_str()); + S = GetWord(text.c_str(), 0) + _T(" ") + sNewNick; + } + } + else S = GetWordAddress(text.c_str(), 0); + + S.Delete(0,1); + text = S; +} + +static void AddCR( CMString& text ) +{ + ReplaceString( text, _T("\n"), _T("\r\n")); + ReplaceString( text, _T("\r\r"), _T("\r")); +} + +CMString CIrcProto::DoAlias( const TCHAR *text, TCHAR *window) +{ + CMString Messageout = _T(""); + const TCHAR* p1 = text; + const TCHAR* p2 = text; + bool LinebreakFlag = false, hasAlias = false; + p2 = _tcsstr(p1, _T("\r\n")); + if ( !p2 ) + p2 = _tcschr(p1, '\0'); + if ( p1 == p2 ) + return (CMString)text; + + do { + if ( LinebreakFlag ) + Messageout += _T("\r\n"); + + TCHAR* line = new TCHAR[p2-p1 +1]; + lstrcpyn(line, p1, p2-p1+1); + TCHAR* test = line; + while ( *test == ' ' ) + test++; + if ( *test == '/' ) { + lstrcpyn(line, GetWordAddress(line, 0), p2-p1+1); + CMString S = line; + delete [] line; + line = new TCHAR[S.GetLength()+2]; + lstrcpyn(line, S.c_str(), S.GetLength()+1); + CMString alias( m_alias ); + const TCHAR* p3 = _tcsstr( alias.c_str(), (GetWord(line, 0)+ _T(" ")).c_str()); + if ( p3 != alias.c_str()) { + CMString S = _T("\r\n"); + S += GetWord(line, 0) + _T(" "); + p3 = _tcsstr( alias.c_str(), S.c_str()); + if ( p3 ) + p3 += 2; + } + if ( p3 != NULL ) { + hasAlias = true; + const TCHAR* p4 = _tcsstr( p3, _T("\r\n")); + if ( !p4 ) + p4 = _tcschr( p3, '\0' ); + + *( TCHAR* )p4 = 0; + CMString S = p3; + ReplaceString( S, _T("##"), window ); + ReplaceString( S, _T("$?"), _T("%question")); + + for ( int index = 1; index < 8; index++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("#$%u"), index ); + if ( !GetWord(line, index).IsEmpty() && IsChannel( GetWord( line, index ))) + ReplaceString( S, str, GetWord(line, index).c_str()); + else { + CMString S1 = _T("#"); + S1 += GetWord( line, index ); + ReplaceString( S, str, S1.c_str()); + } + } + for ( int index2 = 1; index2 <8; index2++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("$%u-"), index2 ); + ReplaceString( S, str, GetWordAddress( line, index2 )); + } + for ( int index3 = 1; index3 <8; index3++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("$%u"), index3 ); + ReplaceString( S, str, GetWord(line, index3).c_str()); + } + Messageout += GetWordAddress(S.c_str(), 1); + } + else Messageout += line; + } + else Messageout += line; + + p1 = p2; + if ( *p1 == '\r' ) + p1 += 2; + p2 = _tcsstr( p1, _T("\r\n")); + if ( !p2 ) + p2 = _tcschr( p1, '\0' ); + delete [] line; + LinebreakFlag = true; + } + while ( *p1 != '\0'); + + return hasAlias ? DoIdentifiers(Messageout, window) : Messageout; +} + +CMString CIrcProto::DoIdentifiers( CMString text, const TCHAR* ) +{ + SYSTEMTIME time; + TCHAR str[2]; + + GetLocalTime( &time ); + ReplaceString( text, _T("%mnick"), m_nick); + ReplaceString( text, _T("%anick"), m_alternativeNick); + ReplaceString( text, _T("%awaymsg"), m_statusMessage.c_str()); + ReplaceString( text, _T("%module"), _A2T(m_szModuleName)); + ReplaceString( text, _T("%name"), m_name); + ReplaceString( text, _T("%newl"), _T("\r\n")); + ReplaceString( text, _T("%network"), m_info.sNetwork.c_str()); + ReplaceString( text, _T("%me"), m_info.sNick.c_str()); + + char mirver[100]; + CallService(MS_SYSTEM_GETVERSIONTEXT, SIZEOF(mirver), LPARAM(mirver)); + ReplaceString(text, _T("%mirver"), _A2T(mirver)); + + ReplaceString(text, _T("%version"), _T(__VERSION_STRING)); + + str[0] = 3; str[1] = '\0'; + ReplaceString(text, _T("%color"), str); + + str[0] = 2; + ReplaceString(text, _T("%bold"), str); + + str[0] = 31; + ReplaceString(text, _T("%underline"), str); + + str[0] = 22; + ReplaceString(text, _T("%italics"), str); + return text; +} + +static void __stdcall sttSetTimerOn( void* _pro ) +{ + CIrcProto* ppro = ( CIrcProto* )_pro; + ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT( "The buddy check function is enabled"), NULL, NULL, NULL, true, false); + ppro->SetChatTimer( ppro->OnlineNotifTimer, 500, OnlineNotifTimerProc ); + if ( ppro->m_channelAwayNotification ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); +} + +static void __stdcall sttSetTimerOff( void* _pro ) +{ + CIrcProto* ppro = ( CIrcProto* )_pro; + ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); + ppro->KillChatTimer( ppro->OnlineNotifTimer ); + ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); +} + +BOOL CIrcProto::DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ) +{ + TCHAR temp[30]; + lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29 ); + CharLower(temp); + CMString command = temp; + CMString one = GetWord(text.c_str(), 1); + CMString two = GetWord(text.c_str(), 2); + CMString three = GetWord(text.c_str(), 3); + CMString therest = GetWordAddress(text.c_str(), 4); + + if ( command == _T("/servershow") || command == _T("/serverhide")) { + if ( m_useServer ) { + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gce.dwFlags = GC_TCHAR; + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + CallChatEvent( command == _T("/servershow") ? WINDOW_VISIBLE : WINDOW_HIDDEN, (LPARAM)&gce); + } + return true; + } + + else if (command == _T("/sleep") || command == _T("/wait")) { + if (!one.IsEmpty()) { + int ms; + if (_stscanf(one.c_str(), _T("%d"), &ms) == 1 && ms > 0 && ms <= 4000) + Sleep(ms); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Incorrect parameters. Usage: /sleep [ms], ms should be greater than 0 and less than 4000."), NULL, NULL, NULL, true, false); + } + return true; + } + + if (command == _T("/clear")) { + CMString S; + if ( !one.IsEmpty()) { + if ( one == _T("server")) + S = SERVERWINDOW; + else + S = MakeWndID( one.c_str()); + } + else if ( lstrcmpi( window, SERVERWINDOW) == 0 ) + S = window; + else + S = MakeWndID( window ); + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gce.cbSize = sizeof(GCEVENT); + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + gcd.ptszID = (TCHAR*)S.c_str(); + CallChatEvent( WINDOW_CLEARLOG, (LPARAM)&gce); + return true; + } + + if ( command == _T("/ignore")) { + if ( IsConnected()) { + CMString IgnoreFlags; + TCHAR temp[500]; + if ( one.IsEmpty()) { + if ( m_ignore ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("on"))) { + m_ignore = 1; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("off"))) { + m_ignore = 0; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !_tcschr( one.c_str(), '!' ) && !_tcschr( one.c_str(), '@' )) + one += _T("!*@*"); + + if ( !two.IsEmpty() && two[0] == '+' ) { + if ( _tcschr( two.c_str(), 'q')) + IgnoreFlags += 'q'; + if ( _tcschr( two.c_str(), 'n')) + IgnoreFlags += 'n'; + if ( _tcschr( two.c_str(), 'i')) + IgnoreFlags += 'i'; + if ( _tcschr( two.c_str(), 'd')) + IgnoreFlags += 'd'; + if ( _tcschr( two.c_str(), 'c')) + IgnoreFlags += 'c'; + if ( _tcschr( two.c_str(), 'm')) + IgnoreFlags += 'm'; + } + else IgnoreFlags = _T("qnidc"); + + CMString m_network; + if ( three.IsEmpty()) + m_network = m_info.sNetwork; + else + m_network = three; + + AddIgnore( one.c_str(), IgnoreFlags.c_str(), m_network.c_str()); + + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s on %s is now ignored (+%s)"), one.c_str(), m_network.c_str(), IgnoreFlags.c_str()); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } + return true; + } + + if (command == _T("/unignore")) { + if ( !_tcschr( one.c_str(), '!' ) && !_tcschr(one.c_str(), '@')) + one += _T("!*@*"); + + TCHAR temp[500]; + if ( RemoveIgnore( one.c_str())) + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is not ignored now"), one.c_str()); + else + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s was not ignored"), one.c_str()); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + return true; + } + + if ( command == _T("/userhost")) { + if ( one.IsEmpty()) + return true; + + DoUserhostWithReason( 1, _T("U"), false, temp ); + return false; + } + + if ( command == _T("/joinx")) { + if ( !one.IsEmpty()) { + for ( int i=1; ; i++ ) { + CMString tmp = GetWord( text.c_str(), i ); + if ( tmp.IsEmpty()) + break; + + AddToJTemp( 'X', tmp ); + } + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + } + return true; + } + + if ( command == _T("/joinm")) { + if ( !one.IsEmpty()) { + for ( int i=1; ; i++ ) { + CMString tmp = GetWord( text.c_str(), i ); + if ( tmp.IsEmpty()) + break; + + AddToJTemp( 'M', tmp ); + } + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + } + return true; + } + + if (command == _T("/nusers")) { + TCHAR szTemp[40]; + CMString S = MakeWndID(window); + GC_INFO gci = {0}; + gci.Flags = BYID|NAME|COUNT; + gci.pszModule = m_szModuleName; + gci.pszID = (TCHAR*)S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("users: %u"), gci.iCount); + + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + if (command == _T("/echo")) { + if ( one.IsEmpty()) + return true; + + if ( !lstrcmpi( one.c_str(), _T("on"))) { + bEcho = TRUE; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are shown"), NULL, NULL, NULL, true, false); + } + + if ( !lstrcmpi( one.c_str(), _T("off"))) { + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are not shown"), NULL, NULL, NULL, true, false); + bEcho = FALSE; + } + + return true; + } + + if (command == _T("/buddycheck")) { + if ( one.IsEmpty()) { + if (( m_autoOnlineNotification && !bTempDisableCheck) || bTempForceCheck ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is enabled"), NULL, NULL, NULL, true, false); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("on"))) { + bTempForceCheck = true; + bTempDisableCheck = false; + CallFunctionAsync( sttSetTimerOn, this ); + } + if ( !lstrcmpi( one.c_str(), _T("off"))) { + bTempForceCheck = false; + bTempDisableCheck = true; + CallFunctionAsync( sttSetTimerOff, this ); + } + if ( !lstrcmpi( one.c_str(), _T("time")) && !two.IsEmpty()) { + m_iTempCheckTime = StrToInt( two.c_str()); + if ( m_iTempCheckTime < 10 && m_iTempCheckTime != 0 ) + m_iTempCheckTime = 10; + + if ( m_iTempCheckTime == 0 ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The time interval for the buddy check function is now at default setting"), NULL, NULL, NULL, true, false); + else { + TCHAR temp[200]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("The time interval for the buddy check function is now %u seconds"), m_iTempCheckTime); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } } + return true; + } + + if (command == _T("/whois")) { + if ( one.IsEmpty()) + return false; + m_manualWhoisCount++; + return false; + } + + if ( command == _T("/channelmanager")) { + if ( window && !hContact && IsChannel( window )) { + if ( IsConnected()) { + if ( m_managerDlg != NULL ) { + SetActiveWindow( m_managerDlg->GetHwnd()); + m_managerDlg->Close(); + } + else { + m_managerDlg = new CManagerDlg( this ); + m_managerDlg->Show(); + m_managerDlg->InitManager( 1, window ); + } } } + + return true; + } + + if ( command == _T("/who")) { + if ( one.IsEmpty()) + return true; + + DoUserhostWithReason( 2, _T("U"), false, _T("%s"), one.c_str()); + return false; + } + + if (command == _T("/hop")) { + if ( !IsChannel( window )) + return true; + + PostIrcMessage( _T("/PART %s"), window ); + + if (( one.IsEmpty() || !IsChannel( one ))) { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), window, wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), window); + return true; + } + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gcd.iType = GC_EVENT_CONTROL; + CMString S = MakeWndID(window); + gcd.ptszID = (TCHAR*)S.c_str(); + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + return true; + } + + if (command == _T("/list" )) { + if ( m_listDlg == NULL ) { + m_listDlg = new CListDlg( this ); + m_listDlg->Show(); + } + SetActiveWindow( m_listDlg->GetHwnd()); + int minutes = ( int )m_noOfChannels/4000; + int minutes2 = ( int )m_noOfChannels/9000; + + TCHAR text[256]; + mir_sntprintf( text, SIZEOF(text), TranslateT("This command is not recommended on a network of this size!\r\nIt will probably cause high CPU usage and/or high bandwidth\r\nusage for around %u to %u minute(s).\r\n\r\nDo you want to continue?"), minutes2, minutes); + if ( m_noOfChannels < 4000 || ( m_noOfChannels >= 4000 && MessageBox( NULL, text, TranslateT("IRC warning") , MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES)) { + ListView_DeleteAllItems( GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW )); + PostIrcMessage( _T("/lusers" )); + return false; + } + m_listDlg->m_status.SetText( TranslateT("Aborted")); + return true; + } + + if (command == _T("/me")) { + if ( one.IsEmpty()) + return true; + + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\001ACTION %s\001"), GetWordAddress(text.c_str(), 1)); + PostIrcMessageWnd( window, hContact, szTemp ); + return true; + } + + if (command == _T("/ame")) { + if ( one.IsEmpty()) + return true; + + CMString S = _T("/ME ") + DoIdentifiers(GetWordAddress(text.c_str(), 1), window); + ReplaceString( S, _T("%"), _T("%%")); + DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); + return true; + } + + if (command == _T("/amsg")) { + if ( one.IsEmpty()) + return true; + + CMString S = DoIdentifiers( GetWordAddress(text.c_str(), 1), window ); + ReplaceString( S, _T("%"), _T("%%")); + DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); + return true; + } + + if (command == _T("/msg")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); + + PostIrcMessageWnd(window, hContact, szTemp); + return true; + } + + if (command == _T("/query")) { + if ( one.IsEmpty() || IsChannel(one.c_str())) + return true; + + CONTACT user = { (TCHAR*)one.c_str(), NULL, NULL, false, false, false}; + HANDLE hContact2 = CList_AddContact(&user, false, false); + if ( hContact2 ) { + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason(1, (_T("S") + one).c_str(), true, one.c_str()); + else { + DBVARIANT dbv1; + if ( !getTString( hContact, "UWildcard", &dbv1 )) { + CMString S = _T("S"); + S += dbv1.ptszVal; + DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal); + DBFreeVariant(&dbv1); + } + else { + CMString S = _T("S"); + S += one; + DoUserhostWithReason(2, S.c_str(), true, one.c_str()); + } } + + CallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact2, 0 ); + } + + if ( !two.IsEmpty()) { + TCHAR szTemp[4000]; + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); + PostIrcMessageWnd( window, hContact, szTemp ); + } + return true; + } + + if (command == _T("/ctcp")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + TCHAR szTemp[1000]; + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + // if it is not dcc or if it is dcc and a local ip exist + if ( lstrcmpi( two.c_str(), _T("dcc")) != 0 || ulAdr ) { + if ( lstrcmpi( two.c_str(), _T("ping")) == 0 ) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s %u\001"), one.c_str(), two.c_str(), time(0)); + else + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s\001"), one.c_str(), GetWordAddress(text.c_str(), 2)); + PostIrcMessageWnd( window, hContact, szTemp ); + } + + if ( lstrcmpi(two.c_str(), _T("dcc")) != 0 ) { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s request sent to %s"), two.c_str(), one.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + + return true; + } + + if (command == _T("/dcc")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + if ( lstrcmpi( one.c_str(), _T("send")) == 0 ) { + TCHAR szTemp[1000]; + unsigned long ulAdr = 0; + + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( ulAdr ) { + CONTACT user = { (TCHAR*)two.c_str(), NULL, NULL, false, false, true }; + HANDLE hContact = CList_AddContact( &user, false, false ); + if ( hContact ) { + CMString s; + + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason( 1, (_T("S") + two).c_str(), true, two.c_str()); + else { + DBVARIANT dbv1; + CMString S = _T("S"); + if ( !getTString( hContact, "UWildcard", &dbv1 )) { + S += dbv1.ptszVal; + DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal ); + DBFreeVariant( &dbv1 ); + } + else { + S += two; + DoUserhostWithReason( 2, S.c_str(), true, two.c_str()); + } } + + if ( three.IsEmpty()) + CallService( MS_FILE_SENDFILE, ( WPARAM )hContact, 0 ); + else { + CMString temp = GetWordAddress(text.c_str(), 3); + TCHAR* pp[2]; + TCHAR* p = ( TCHAR* )temp.c_str(); + pp[0] = p; + pp[1] = NULL; + CallService( MS_FILE_SENDSPECIFICFILES, (WPARAM)hContact, (LPARAM)pp ); + } } + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + return true; + } + + if ( lstrcmpi( one.c_str(), _T("chat")) == 0 ) { + TCHAR szTemp[1000]; + + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( ulAdr ) { + CMString contact = two; contact += _T(DCCSTRING); + CONTACT user = { (TCHAR*)contact.c_str(), NULL, NULL, false, false, true}; + HANDLE hContact = CList_AddContact( &user, false, false ); + setByte(hContact, "DCC", 1); + + int iPort = 0; + if ( hContact ) { + DCCINFO* dci = new DCCINFO; + dci->hContact = hContact; + dci->sContactName = two; + dci->iType = DCC_CHAT; + dci->bSender = true; + + CDccSession* dcc = new CDccSession(this, dci); + CDccSession* olddcc = FindDCCSession(hContact); + if ( olddcc ) + olddcc->Disconnect(); + AddDCCSession(hContact, dcc); + iPort = dcc->Connect(); + } + + if ( iPort != 0 ) { + PostIrcMessage( _T("/CTCP %s DCC CHAT chat %u %u"), two.c_str(), ulAdr, iPort ); + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC CHAT request sent to %s"), two.c_str(), one.c_str()); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to bind port")); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } } + return true; + } + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct DoInputRequestParam +{ + DoInputRequestParam( CIrcProto* _pro, const TCHAR* _str ) : + ppro( _pro ), + str( mir_tstrdup( _str )) + {} + + CIrcProto* ppro; + TCHAR* str; +}; + +static void __stdcall DoInputRequestAliasApcStub( void* _par ) +{ + DoInputRequestParam* param = ( DoInputRequestParam* )_par; + CIrcProto* ppro = param->ppro; + TCHAR* str = param->str; + + TCHAR* infotext = NULL; + TCHAR* title = NULL; + TCHAR* defaulttext = NULL; + CMString command = ( TCHAR* )str; + TCHAR* p = _tcsstr(( TCHAR* )str, _T("%question")); + if ( p[9] == '=' && p[10] == '\"' ) { + infotext = &p[11]; + p = _tcschr( infotext, '\"' ); + if ( p ) { + *p = '\0'; + p++; + if ( *p == ',' && p[1] == '\"' ) { + p++; p++; + title = p; + p = _tcschr( title, '\"' ); + if ( p ) { + *p = '\0'; + p++; + if ( *p == ',' && p[1] == '\"' ) { + p++; p++; + defaulttext = p; + p = _tcschr( defaulttext, '\"' ); + if ( p ) + *p = '\0'; + } } } } } + + CQuestionDlg* dlg = new CQuestionDlg( ppro ); + dlg->Show(); + HWND question_hWnd = dlg->GetHwnd(); + + if ( title ) + SetDlgItemText( question_hWnd, IDC_CAPTION, title); + else + SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Input command")); + + if ( infotext ) + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), infotext ); + else + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter the reply")); + + if ( defaulttext ) + SetWindowText( GetDlgItem( question_hWnd, IDC_EDIT), defaulttext ); + + SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, command.c_str()); + dlg->Activate(); + + mir_free( str ); + delete param; +} + +bool CIrcProto::PostIrcMessage( const TCHAR* fmt, ... ) +{ + if ( !fmt || lstrlen(fmt) < 1 || lstrlen(fmt) > 4000 ) + return 0; + + va_list marker; + va_start( marker, fmt ); + static TCHAR szBuf[4*1024]; + mir_vsntprintf( szBuf, SIZEOF(szBuf), fmt, marker ); + va_end( marker ); + + return PostIrcMessageWnd(NULL, NULL, szBuf); +} + +bool CIrcProto::PostIrcMessageWnd( TCHAR* window, HANDLE hContact, const TCHAR* szBuf ) +{ + DBVARIANT dbv; + TCHAR windowname[256]; + BYTE bDCC = 0; + + if ( hContact ) + bDCC = getByte( hContact, "DCC", 0 ); + + if ( !IsConnected() && !bDCC || !szBuf || lstrlen(szBuf) < 1 ) + return 0; + + if ( hContact && !getTString( hContact, "Nick", &dbv )) { + lstrcpyn( windowname, dbv.ptszVal, 255); + DBFreeVariant(&dbv); + } + else if ( window ) + lstrcpyn( windowname, window, 255 ); + else + lstrcpyn( windowname, SERVERWINDOW, 255 ); + + if ( lstrcmpi( window, SERVERWINDOW) != 0 ) { + TCHAR* p1 = _tcschr( windowname, ' ' ); + if ( p1 ) + *p1 = '\0'; + } + + // remove unecessary linebreaks, and do the aliases + CMString Message = szBuf; + AddCR( Message ); + RemoveLinebreaks( Message ); + if ( !hContact && IsConnected()) { + Message = DoAlias( Message.c_str(), windowname ); + + if ( Message.Find( _T("%question")) != -1 ) { + CallFunctionAsync( DoInputRequestAliasApcStub, new DoInputRequestParam( this, Message )); + return 1; + } + + ReplaceString( Message, _T("%newl"), _T("\r\n")); + RemoveLinebreaks( Message ); + } + + if ( Message.IsEmpty()) + return 0; + + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, windowname, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + int codepage = ( wi ) ? wi->codepage : getCodepage(); + + // process the message + while ( !Message.IsEmpty()) { + // split the text into lines, and do an automatic textsplit on long lies as well + bool flag = false; + CMString DoThis = _T(""); + int index = Message.Find( _T("\r\n"), 0 ); + if ( index == -1 ) + index = Message.GetLength(); + + if ( index > 464 ) + index = 432; + DoThis = Message.Mid(0, index); + Message.Delete(0, index); + if ( Message.Find( _T("\r\n"), 0 ) == 0 ) + Message.Delete( 0, 2 ); + + //do this if it's a /raw + if ( IsConnected() && ( GetWord(DoThis.c_str(), 0) == _T("/raw") || GetWord(DoThis.c_str(), 0) == _T("/quote"))) { + if ( GetWord( DoThis.c_str(), 1 ).IsEmpty()) + continue; + + CMString S = GetWordAddress( DoThis.c_str(), 1 ); + SendIrcMessage( S.c_str(), true, codepage ); + continue; + } + + // Do this if the message is not a command + if ( (GetWord( DoThis.c_str(), 0)[0] != '/') || // not a command + ( (GetWord( DoThis.c_str(), 0)[0] == '/') && (GetWord( DoThis.c_str(), 0)[1] == '/')) || // or double backslash at the beginning + hContact ) { + CMString S = _T("/PRIVMSG "); + if ( lstrcmpi(window, SERVERWINDOW) == 0 && !m_info.sServerName.IsEmpty()) + S += m_info.sServerName + _T(" ") + DoThis; + else + S += CMString(windowname) + _T(" ") + DoThis; + + DoThis = S; + flag = true; + } + + // and here we send it unless the command was a hardcoded one that should not be sent + if ( DoHardcodedCommand( DoThis, windowname, hContact )) + continue; + + if ( !IsConnected() && !bDCC ) + continue; + + if ( !flag && IsConnected()) + DoThis = DoIdentifiers(DoThis, windowname); + + if ( hContact ) { + if ( flag && bDCC ) { + CDccSession* dcc = FindDCCSession( hContact ); + if ( dcc ) { + FormatMsg( DoThis ); + CMString mess = GetWordAddress(DoThis.c_str(), 2); + if ( mess[0] == ':' ) + mess.Delete(0,1); + mess += '\n'; + dcc->SendStuff( mess.c_str()); + } + } + else if ( IsConnected()) { + FormatMsg( DoThis ); + SendIrcMessage( DoThis.c_str(), false, codepage ); + } + } + else { + FormatMsg( DoThis ); + SendIrcMessage( DoThis.c_str(), true, codepage ); + } } + + return 1; +} diff --git a/protocols/IRCG/src/irc.h b/protocols/IRCG/src/irc.h new file mode 100644 index 0000000000..9fe6584d87 --- /dev/null +++ b/protocols/IRCG/src/irc.h @@ -0,0 +1,725 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _IRCWIN_H_ +#define _IRCWIN_H_ + +#define MIRANDA_VER 0x0A00 +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#include "m_stdhdr.h" + +#define _CRT_SECURE_NO_WARNINGS + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "newpluginapi.h" +#include "m_system.h" +#include "m_system_cpp.h" +#include "m_protocols.h" +#include "m_protomod.h" +#include "m_protosvc.h" +#include "m_protoint.h" +#include "m_clist.h" +#include "m_options.h" +#include "m_database.h" +#include "m_utils.h" +#include "m_skin.h" +#include "m_netlib.h" +#include "m_clui.h" +#include "m_langpack.h" +#include "m_message.h" +#include "m_userinfo.h" +#include "m_addcontact.h" +#include "m_button.h" +#include "m_genmenu.h" +#include "m_file.h" +#include "m_ignore.h" +#include "m_chat.h" +#include "m_icolib.h" +#include "m_ircscript.h" +#include "win2k.h" + +#include "resource.h" + +#define IRC_QUICKCONNECT "/QuickConnectMenu" +#define IRC_JOINCHANNEL "/JoinChannelMenu" +#define IRC_CHANGENICK "/ChangeNickMenu" +#define IRC_SHOWLIST "/ShowListMenu" +#define IRC_SHOWSERVER "/ShowServerMenu" +#define IRC_UM_CHANSETTINGS "/UMenuChanSettings" +#define IRC_UM_WHOIS "/UMenuWhois" +#define IRC_UM_DISCONNECT "/UMenuDisconnect" +#define IRC_UM_IGNORE "/UMenuIgnore" + +#define STR_QUITMESSAGE "\002Miranda NG!\002 Smaller, Faster, Easier. http://miranda-ng.org/" +#define STR_USERINFO "I'm a happy Miranda NG user! Get it here: http://miranda-ng.org/" +#define STR_AWAYMESSAGE "I'm away from the computer." // Default away +#define DCCSTRING " (DCC)" +#define SERVERSMODULE "IRC Servers" +#define SERVERWINDOW _T("Network log") + +#define DCC_CHAT 1 +#define DCC_SEND 2 + +#define FILERESUME_CANCEL 11 + +struct CIrcProto; + +#include "mstring.h" +typedef CMStringA String; + +// special service for tweaking performance, implemented in chat.dll +#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr" +typedef int (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam); +typedef struct { + GETEVENTFUNC pfnAddEvent; +} + GCPTRS; + +#define IP_AUTO 1 +#define IP_MANUAL 2 + +struct IPRESOLVE // Contains info about the channels +{ + IPRESOLVE( const char* _addr, int _type ) : + sAddr( _addr ), + iType( _type ) + {} + + ~IPRESOLVE() + {} + + String sAddr; + int iType; +}; + +struct CHANNELINFO // Contains info about the channels +{ + TCHAR* pszTopic; + TCHAR* pszMode; + TCHAR* pszPassword; + TCHAR* pszLimit; + BYTE OwnMode; /* own mode on the channel. Bitmask: + 0: voice + 1: halfop + 2: op + 3: admin + 4: owner */ + int codepage; +}; + +struct SERVER_INFO // Contains info about different servers +{ + ~SERVER_INFO(); + + char *m_name, *m_address, *m_group; + int m_portStart, m_portEnd, m_iSSL; +}; + +struct PERFORM_INFO // Contains 'm_perform buffer' for different networks +{ + PERFORM_INFO( const char* szSetting, const TCHAR* value ) : + mSetting( szSetting ), + mText( value ) + {} + + ~PERFORM_INFO() + {} + + String mSetting; + CMString mText; +}; + +struct CONTACT // Contains info about users +{ + TCHAR* name; + TCHAR* user; + TCHAR* host; + bool ExactOnly; + bool ExactWCOnly; + bool ExactNick; +}; + +struct TDbSetting +{ + int offset; + char* name; + int type; + size_t size; + union + { + int defValue; + TCHAR* defStr; + }; +}; + +#include "irclib.h" +using namespace irc; + +#include "irc_dlg.h" + +///////////////////////////////////////////////////////////////////////////////////////// + +struct CIrcProto; +typedef void ( __cdecl CIrcProto::*IrcThreadFunc )( void* param ); +typedef int ( __cdecl CIrcProto::*IrcEventFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFuncParam )( WPARAM, LPARAM, LPARAM ); + +typedef bool (CIrcProto::*PfnIrcMessageHandler)(const CIrcMessage* pmsg); + +struct CIrcHandler +{ + CIrcHandler( const TCHAR* _name, PfnIrcMessageHandler _handler ) : + m_name( _name ), + m_handler( _handler ) + {} + + const TCHAR* m_name; + PfnIrcMessageHandler m_handler; +}; + +struct CIrcProto : public PROTO_INTERFACE, public MZeroedObject +{ + CIrcProto( const char*, const TCHAR* ); + ~CIrcProto(); + + // Protocol interface + + virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); + virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); + + virtual int __cdecl Authorize( HANDLE hContact ); + virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); + virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); + + virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); + + virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); + virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); + virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); + virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); + + virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); + virtual HICON __cdecl GetIcon( int iconIndex ); + virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); + + virtual HANDLE __cdecl SearchBasic( const PROTOCHAR* id ); + virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR* email ); + virtual HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName ); + virtual HWND __cdecl SearchAdvanced( HWND owner ); + virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); + + virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); + virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); + + virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); + virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); + virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); + virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); + + virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); + virtual int __cdecl SetStatus( int iNewStatus ); + + virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); + virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); + virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); + virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); + + virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); + + virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); + + // Services + INT_PTR __cdecl SvcCreateAccMgrUI( WPARAM, LPARAM ); + INT_PTR __cdecl GetMyAwayMsg( WPARAM, LPARAM ); + + INT_PTR __cdecl OnChangeNickMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnDoubleclicked( WPARAM, LPARAM ); + INT_PTR __cdecl OnJoinChat( WPARAM, LPARAM ); + INT_PTR __cdecl OnJoinMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnLeaveChat( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuChanSettings( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuDisconnect( WPARAM , LPARAM ); + INT_PTR __cdecl OnMenuIgnore( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuWhois( WPARAM, LPARAM ); + INT_PTR __cdecl OnQuickConnectMenuCommand(WPARAM, LPARAM ); + INT_PTR __cdecl OnShowListMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnShowServerMenuCommand( WPARAM, LPARAM ); + + // Events + int __cdecl OnContactDeleted( WPARAM, LPARAM ); + int __cdecl OnInitOptionsPages( WPARAM, LPARAM ); + int __cdecl OnInitUserInfo( WPARAM, LPARAM ); + int __cdecl OnModulesLoaded( WPARAM, LPARAM ); + int __cdecl OnMenuPreBuild( WPARAM, LPARAM ); + int __cdecl OnPreShutdown( WPARAM, LPARAM ); + int __cdecl OnDbSettingChanged( WPARAM, LPARAM ); + + int __cdecl GCEventHook( WPARAM, LPARAM ); + int __cdecl GCMenuHook( WPARAM, LPARAM ); + + // Data + + char m_serverName[100]; + char m_password [500]; + TCHAR m_identSystem[10]; + char m_network[30]; + char m_portStart[10]; + char m_portEnd[10]; + int m_iSSL; + TCHAR m_identPort[10]; + TCHAR m_retryWait[10]; + TCHAR m_retryCount[10]; + TCHAR m_nick[30], m_pNick[30]; + TCHAR m_alternativeNick[30]; + TCHAR m_name[200]; + TCHAR m_userID[200]; + TCHAR m_quitMessage[400]; + TCHAR m_userInfo[500]; + char m_myHost[50]; + char m_mySpecifiedHost[500]; + char m_mySpecifiedHostIP[50]; + char m_myLocalHost[50]; + WORD m_myLocalPort; + TCHAR* m_alias; + int m_serverComboSelection; + int m_quickComboSelection; + int m_onlineNotificationTime; + int m_onlineNotificationLimit; + BYTE m_scriptingEnabled; + BYTE m_IPFromServer; + BYTE m_showAddresses; + BYTE m_disconnectDCCChats; + BYTE m_disableErrorPopups; + BYTE m_rejoinChannels; + BYTE m_rejoinIfKicked; + BYTE m_hideServerWindow; + BYTE m_ident; + BYTE m_identTimer; + BYTE m_retry; + BYTE m_disableDefaultServer; + BYTE m_autoOnlineNotification; + BYTE m_sendKeepAlive; + BYTE m_joinOnInvite; + BYTE m_perform; + BYTE m_forceVisible; + BYTE m_ignore; + BYTE m_ignoreChannelDefault; + BYTE m_useServer; + BYTE m_DCCFileEnabled; + BYTE m_DCCChatEnabled; + BYTE m_DCCChatAccept; + BYTE m_DCCChatIgnore; + BYTE m_DCCPassive; + BYTE m_DCCMode; + WORD m_DCCPacketSize; + BYTE m_manualHost; + BYTE m_oldStyleModes; + BYTE m_channelAwayNotification; + BYTE m_sendNotice; + BYTE m_utfAutodetect; + int m_codepage; + COLORREF colors[16]; + HICON hIcon[13]; + + OBJLIST vUserhostReasons; + OBJLIST vWhoInProgress; + + CRITICAL_SECTION cs; + CRITICAL_SECTION m_gchook; + CRITICAL_SECTION m_resolve; + HANDLE m_evWndCreate; + + CMString m_statusMessage; + bool m_bMbotInstalled; + int m_iTempCheckTime; + + CIrcSessionInfo si; + + int m_iRetryCount; + int m_portCount; + DWORD m_bConnectRequested; + DWORD m_bConnectThreadRunning; + + HGENMENU hMenuRoot, hMenuQuick, hMenuServer, hMenuJoin, hMenuNick, hMenuList; + HANDLE hNetlib, hNetlibDCC; + + bool bTempDisableCheck, bTempForceCheck, bEcho; + bool nickflag; + + bool bPerformDone; + + CJoinDlg* m_joinDlg; + CListDlg* m_listDlg; + CManagerDlg* m_managerDlg; + CNickDlg* m_nickDlg; + CWhoisDlg* m_whoisDlg; + CQuickDlg* m_quickDlg; + CIgnorePrefsDlg* m_ignoreDlg; + + int m_noOfChannels, m_manualWhoisCount; + String sChannelModes, sUserModes; + CMString sChannelPrefixes, sUserModePrefixes, WhoisAwayReply; + + CDlgBase::CreateParam OptCreateAccount, OptCreateConn, OptCreateIgnore, OptCreateOther; + + //clist.cpp + HANDLE CList_AddContact(struct CONTACT * user, bool InList, bool SetOnline); + bool CList_SetAllOffline(BYTE ChatsToo); + HANDLE CList_SetOffline(struct CONTACT * user); + + bool CList_AddEvent(struct CONTACT * user, HICON Icon, HANDLE event, const char * tooltip, int type ) ; + HANDLE CList_FindContact (struct CONTACT * user); + BOOL CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) ; + + //commandmonitor.cpp + UINT_PTR IdentTimer, InitTimer, KeepAliveTimer, OnlineNotifTimer, OnlineNotifTimer3; + + int AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg); + bool DoOnConnect(const CIrcMessage *pmsg); + int DoPerform(const char* event); + void __cdecl ResolveIPThread( void* di ); + + bool AddIgnore(const TCHAR* mask, const TCHAR* mode, const TCHAR* network) ; + int IsIgnored(const CMString& nick, const CMString& address, const CMString& host, char type) ; + int IsIgnored(CMString user, char type); + bool RemoveIgnore(const TCHAR* mask) ; + + //input.cpp + CMString DoAlias( const TCHAR *text, TCHAR *window); + BOOL DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ); + CMString DoIdentifiers( CMString text, const TCHAR* window ); + void FormatMsg(CMString& text); + bool PostIrcMessageWnd(TCHAR* pszWindow, HANDLE hContact,const TCHAR* szBuf); + bool PostIrcMessage( const TCHAR* fmt, ...); + + // irclib.cpp + UINT_PTR DCCTimer; + void SendIrcMessage( const TCHAR*, bool bNotify = true, int codepage = -1 ); + + // ircproto.cpp + void __cdecl AckBasicSearch( void* param ); + void __cdecl AckMessageFail( void* info ); + void __cdecl AckMessageFailDcc( void* info ); + void __cdecl AckMessageSuccess( void* info ); + + int SetStatusInternal( int iNewStatus, bool bIsInternal ); + + //options.cpp + HWND m_hwndConnect; + + OBJLIST m_ignoreItems; + + int m_channelNumber; + CMString m_whoReply; + CMString sNamesList; + CMString sTopic; + CMString sTopicName; + CMString sTopicTime; + CMString m_namesToWho; + CMString m_channelsToWho; + CMString m_namesToUserhost; + + void InitPrefs(void); + void InitIgnore(void); + + void ReadSettings( TDbSetting* sets, int count ); + void RewriteIgnoreSettings( void ); + void WriteSettings( TDbSetting* sets, int count ); + + //output + BOOL ShowMessage (const CIrcMessage* pmsg); + + //scripting.cpp + INT_PTR __cdecl Scripting_InsertRawIn(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertRawOut(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertGuiOut(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_GetIrcData(WPARAM wparam, LPARAM lparam); + BOOL Scripting_TriggerMSPRawIn(char ** pszRaw); + BOOL Scripting_TriggerMSPRawOut(char ** pszRaw); + BOOL Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce); + BOOL Scripting_TriggerMSPGuiOut(GCHOOK * gch); + + // services.cpp + void ConnectToServer(void); + void DisconnectFromServer(void); + void DoNetlibLog( const char* fmt, ... ); + void IrcHookEvent( const char*, IrcEventFunc ); + void InitMainMenus(void); + + void ircFork( IrcThreadFunc, void* arg ); + HANDLE ircForkEx( IrcThreadFunc, void* arg ); + + UINT_PTR RetryTimer; + + void __cdecl ConnectServerThread( void* ); + void __cdecl DisconnectServerThread( void* ); + + //tools.cpp + void AddToJTemp(TCHAR op, CMString& sCommand); + bool AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic); + INT_PTR CallChatEvent(WPARAM wParam, LPARAM lParam); + void CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ); + INT_PTR DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe,time_t timestamp = 1); + void FindLocalIP(HANDLE con); + bool FreeWindowItemData(CMString window, CHANNELINFO* wis); + bool IsChannel(const char* sName); + bool IsChannel(const TCHAR* sName); + void KillChatTimer(UINT_PTR &nIDEvent); + CMString MakeWndID(const TCHAR* sWindow); + CMString ModeToStatus(int sMode); + CMString PrefixToStatus(int cPrefix); + int SetChannelSBText(CMString sWindow, CHANNELINFO * wi); + void SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc); + + void ClearUserhostReasons(int type); + void DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...); + CMString GetNextUserhostReason(int type); + CMString PeekAtReasons(int type); + + int getByte( const char* name, BYTE defaultValue ); + int getByte( HANDLE hContact, const char* name, BYTE defaultValue ); + int getDword( const char* name, DWORD defaultValue ); + int getDword( HANDLE hContact, const char* name, DWORD defaultValue ); + int getString( const char* name, DBVARIANT* ); + int getString( HANDLE hContact, const char* name, DBVARIANT* ); + int getTString( const char* name, DBVARIANT* ); + int getTString( HANDLE hContact, const char* name, DBVARIANT* ); + int getWord( const char* name, WORD defaultValue ); + int getWord( HANDLE hContact, const char* name, WORD defaultValue ); + + void setByte( const char* name, BYTE value ); + void setByte( HANDLE hContact, const char* name, BYTE value ); + void setDword( const char* name, DWORD value ); + void setDword( HANDLE hContact, const char* name, DWORD value ); + void setString( const char* name, const char* value ); + void setString( HANDLE hContact, const char* name, const char* value ); + void setTString( const char* name, const TCHAR* value ); + void setTString( HANDLE hContact, const char* name, const TCHAR* value ); + void setWord( const char* name, int value ); + void setWord( HANDLE hContact, const char* name, int value ); + + // userinfo.cpp + void __cdecl AckUserInfoSearch( void* hContact ); + + //////////////////////////////////////////////////////////////////////////////////////// + // former CIrcSession class + + void AddDCCSession(HANDLE hContact, CDccSession* dcc); + void AddDCCSession(DCCINFO* pdci, CDccSession* dcc); + void RemoveDCCSession(HANDLE hContact); + void RemoveDCCSession(DCCINFO* pdci); + + CDccSession* FindDCCSession(HANDLE hContact); + CDccSession* FindDCCSession(DCCINFO* pdci); + CDccSession* FindDCCSendByPort(int iPort); + CDccSession* FindDCCRecvByPortAndName(int iPort, const TCHAR* szName); + CDccSession* FindPassiveDCCSend(int iToken); + CDccSession* FindPassiveDCCRecv(CMString sName, CMString sToken); + + void DisconnectAllDCCSessions(bool Shutdown); + void CheckDCCTimeout(void); + + bool Connect(const CIrcSessionInfo& info); + void Disconnect(void); + void KillIdent(void); + + int NLSend(const TCHAR* fmt, ...); + int NLSend(const char* fmt, ...); + int NLSend(const unsigned char* buf, int cbBuf); + int NLSendNoScript( const unsigned char* buf, int cbBuf); + int NLReceive(unsigned char* buf, int cbBuf); + void InsertIncomingEvent(TCHAR* pszRaw); + + __inline bool IsConnected() const { return con != NULL; } + + // send-to-stream operators + int getCodepage() const; + __inline void setCodepage( int aPage ) { codepage = aPage; } + + CIrcSessionInfo m_info; + +protected : + int codepage; + HANDLE con; + HANDLE hBindPort; + void DoReceive(); + LIST m_dcc_chats; + LIST m_dcc_xfers; + +private : + CRITICAL_SECTION m_dcc; // protect the dcc objects + + void createMessageFromPchar( const char* p ); + void Notify(const CIrcMessage* pmsg); + void __cdecl ThreadProc( void *pparam ); + + //////////////////////////////////////////////////////////////////////////////////////// + // former CIrcMonitor class + + bool OnIrc_PING(const CIrcMessage* pmsg); + bool OnIrc_WELCOME(const CIrcMessage* pmsg); + bool OnIrc_YOURHOST(const CIrcMessage* pmsg); + bool OnIrc_NICK(const CIrcMessage* pmsg); + bool OnIrc_PRIVMSG(const CIrcMessage* pmsg); + bool OnIrc_JOIN(const CIrcMessage* pmsg); + bool OnIrc_QUIT(const CIrcMessage* pmsg); + bool OnIrc_PART(const CIrcMessage* pmsg); + bool OnIrc_KICK(const CIrcMessage* pmsg); + bool OnIrc_MODE(const CIrcMessage* pmsg); + bool OnIrc_USERHOST_REPLY(const CIrcMessage* pmsg); + bool OnIrc_MODEQUERY(const CIrcMessage* pmsg); + bool OnIrc_NAMES(const CIrcMessage* pmsg); + bool OnIrc_ENDNAMES(const CIrcMessage* pmsg); + bool OnIrc_INITIALTOPIC(const CIrcMessage* pmsg); + bool OnIrc_INITIALTOPICNAME(const CIrcMessage* pmsg); + bool OnIrc_TOPIC(const CIrcMessage* pmsg); + bool OnIrc_TRYAGAIN(const CIrcMessage* pmsg); + bool OnIrc_NOTICE(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_NAME(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_CHANNELS(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_SERVER(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_AWAY(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_IDLE(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_END(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_OTHER(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_AUTH(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_NO_USER(const CIrcMessage* pmsg); + bool OnIrc_NICK_ERR(const CIrcMessage* pmsg); + bool OnIrc_ENDMOTD(const CIrcMessage* pmsg); + bool OnIrc_LISTSTART(const CIrcMessage* pmsg); + bool OnIrc_LIST(const CIrcMessage* pmsg); + bool OnIrc_LISTEND(const CIrcMessage* pmsg); + bool OnIrc_BANLIST(const CIrcMessage* pmsg); + bool OnIrc_BANLISTEND(const CIrcMessage* pmsg); + bool OnIrc_SUPPORT(const CIrcMessage* pmsg); + bool OnIrc_BACKFROMAWAY(const CIrcMessage* pmsg); + bool OnIrc_SETAWAY(const CIrcMessage* pmsg); + bool OnIrc_JOINERROR(const CIrcMessage* pmsg); + bool OnIrc_UNKNOWN(const CIrcMessage* pmsg); + bool OnIrc_ERROR(const CIrcMessage* pmsg); + bool OnIrc_NOOFCHANNELS(const CIrcMessage* pmsg); + bool OnIrc_PINGPONG(const CIrcMessage* pmsg); + bool OnIrc_INVITE(const CIrcMessage* pmsg); + bool OnIrc_WHO_END(const CIrcMessage* pmsg); + bool OnIrc_WHO_REPLY(const CIrcMessage* pmsg); + bool OnIrc_WHOTOOLONG(const CIrcMessage* pmsg); + + bool IsCTCP(const CIrcMessage* pmsg); + + void OnIrcDefault(const CIrcMessage* pmsg); + void OnIrcDisconnected(); + + static OBJLIST m_handlers; + + PfnIrcMessageHandler FindMethod(const TCHAR* lpszName); + + void OnIrcMessage(const CIrcMessage* pmsg); + CMString sNick4Perform; +}; + +// map actual member functions to their associated IRC command. +// put any number of this macro in the class's constructor. +#define IRC_MAP_ENTRY(name, member) \ + m_handlers.insert( new CIrcHandler( _T(name), &CIrcProto::OnIrc_##member )); + +///////////////////////////////////////////////////////////////////////////////////////// +// Functions + +//main.cpp +extern HINSTANCE hInst; + +extern LIST g_Instances; + +extern OBJLIST g_servers; + +void UpgradeCheck(void); + +CIrcProto* GetTimerOwner( UINT_PTR eventId ); + +VOID CALLBACK IdentTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK KeepAliveTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK OnlineNotifTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK OnlineNotifTimerProc3( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK DCCTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK RetryTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); + +// options.cpp + +void InitServers(void); +void RereadServers(void); + +void InitContactMenus(void); +void UninitContactMenus(void); + +void WindowSetIcon(HWND hWnd, int iconId); +void WindowFreeIcon(HWND hWnd); + +void AddIcons(void); +void UninitIcons(void); +HICON LoadIconEx(int iIndex, bool big = false); +HANDLE GetIconHandle(int iconId); +void ReleaseIconEx(HICON hIcon); + +// services.cpp + +extern BOOL bChatInstalled, m_bMbotInstalled; + +//tools.cpp +int __stdcall WCCmp(const TCHAR* wild, const TCHAR* string); +char* __stdcall IrcLoadFile(TCHAR * szPath); +CMString __stdcall GetWord(const TCHAR* text, int index); +CMString& __stdcall ReplaceString (CMString& text, const TCHAR* replaceme, const TCHAR* newword); +const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index); +void __stdcall RemoveLinebreaks( CMString& Message ); +TCHAR* __stdcall my_strstri(const TCHAR *s1, const TCHAR *s2) ; +TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent); + +String& __stdcall ReplaceString (String& text, const char* replaceme, const char* newword); +String __stdcall GetWord(const char* text, int index); + +#pragma comment(lib,"comctl32.lib") + +#endif diff --git a/protocols/IRCG/src/irc_dlg.h b/protocols/IRCG/src/irc_dlg.h new file mode 100644 index 0000000000..887e9f0d0c --- /dev/null +++ b/protocols/IRCG/src/irc_dlg.h @@ -0,0 +1,329 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "ui_utils.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Dialogs + +struct CMessageBoxDlg : public CProtoDlgBase +{ + DCCINFO* pdci; + + CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + + virtual void OnInitDialog(); +}; + +struct CCoolIrcDlg : public CProtoDlgBase +{ + CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent = NULL ); + + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + virtual void OnInitDialog(); + virtual void OnDestroy(); +}; + +struct CWhoisDlg : public CCoolIrcDlg +{ + CWhoisDlg( CIrcProto* _pro ); + + CCtrlCombo m_InfoNick; + CCtrlEdit m_Reply; + CCtrlBase m_Caption, m_AwayTime; + CCtrlBase m_InfoName, m_InfoId, m_InfoAddress, m_InfoChannels, m_InfoAuth, + m_InfoServer, m_InfoAway2, m_InfoOther; + CCtrlButton m_Ping, m_Version, m_Time, m_userInfo, m_Refresh, m_Query; + + void ShowMessage( const CIrcMessage* ); + void ShowMessageNoUser( const CIrcMessage* ); + + void OnGo( CCtrlButton* ); + void OnQuery( CCtrlButton* ); + void OnPing( CCtrlButton* ); + void OnUserInfo( CCtrlButton* ); + void OnTime( CCtrlButton* ); + void OnVersion( CCtrlButton* ); + + virtual void OnInitDialog(); + virtual void OnClose(); + virtual void OnDestroy(); +}; + +struct CNickDlg : public CCoolIrcDlg +{ + CNickDlg( CIrcProto* _pro ); + + CCtrlCombo m_Enick; + CCtrlButton m_Ok; + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + void OnOk( CCtrlButton* ); +}; + +struct CListDlg : public CProtoDlgBase +{ + CListDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnChange( CCtrlBase* ctrl ); + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + virtual void OnDestroy(); + virtual int Resizer(UTILRESIZECONTROL *urc); + + TCHAR m_title[255]; + CCtrlListView m_list, m_list2; + CCtrlEdit m_filter, m_status; + UINT_PTR m_timer; + + CCtrlButton m_Join; + void OnJoin( CCtrlButton* ); + + void List_OnColumnClick( CCtrlListView::TEventInfo* ev ); + + void UpdateList( void ); +}; + +struct CJoinDlg : public CCoolIrcDlg +{ + CJoinDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); +}; + +struct CQuickDlg : public CCoolIrcDlg +{ + CQuickDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + CCtrlCombo m_serverCombo; + void OnServerCombo( CCtrlData* ); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + +private: + struct SERVER_INFO* m_si; +}; + +struct CManagerDlg : public CCoolIrcDlg +{ + CManagerDlg( CIrcProto* _pro ); + + CCtrlCheck m_check1, m_check2, m_check3, m_check4, m_check5, m_check6, m_check7, m_check8, m_check9; + CCtrlEdit m_key, m_limit; + CCtrlCombo m_topic; + CCtrlCheck m_radio1, m_radio2, m_radio3; + CCtrlMButton m_add, m_edit, m_remove, m_applyTopic, m_applyModes; + CCtrlListBox m_list; + + virtual void OnInitDialog(); + virtual void OnClose(); + virtual void OnDestroy(); + + void OnCheck( CCtrlData* ); + void OnCheck5( CCtrlData* ); + void OnCheck6( CCtrlData* ); + void OnRadio( CCtrlData* ); + + void OnAdd( CCtrlButton* ); + void OnEdit( CCtrlButton* ); + void OnRemove( CCtrlButton* ); + + void OnListDblClick( CCtrlListBox* ); + void OnChangeList( CCtrlListBox* ); + void OnChangeModes( CCtrlData* ); + void OnChangeTopic( CCtrlData* ); + + void OnApplyModes( CCtrlButton* ); + void OnApplyTopic( CCtrlButton* ); + + void ApplyQuestion(); + void CloseQuestion(); + void InitManager( int mode, const TCHAR* window ); +}; + +struct CQuestionDlg : public CCoolIrcDlg +{ + CQuestionDlg( CIrcProto* _pro, CManagerDlg* owner = NULL ); + + virtual void OnInitDialog(); + virtual void OnClose(); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + + void Activate(); + +private: + CManagerDlg* m_owner; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// options + +//---- the first property page: Account ------------------------------------------------- + +struct CConnectPrefsDlg : public CProtoDlgBase +{ + bool m_serverlistModified; + + CCtrlCombo m_serverCombo; + CCtrlEdit m_server, m_port, m_port2, m_pass; + CCtrlMButton m_add, m_edit, m_del; + CCtrlEdit m_nick, m_nick2, m_name, m_userID; + + CCtrlCheck m_ident, m_identTimer; + CCtrlEdit m_identSystem, m_identPort; + + CCtrlCheck m_retry; + CCtrlEdit m_retryCount, m_retryWait; + + CCtrlCheck m_forceVisible, m_rejoinOnKick, m_rejoinChannels, m_disableError, + m_address, m_useServer, m_showServer, m_keepAlive, m_autoJoin, + m_oldStyle, m_onlineNotif, m_channelAway, m_enableServer; + CCtrlEdit m_onlineTimer, m_limit, m_spin1, m_spin2, m_ssl; + + CConnectPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CConnectPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + + void OnServerCombo( CCtrlData* ); + void OnAddServer( CCtrlButton* ); + void OnDeleteServer( CCtrlButton* ); + void OnEditServer( CCtrlButton* ); + void OnStartup( CCtrlData* ); + void OnIdent( CCtrlData* ); + void OnUseServer( CCtrlData* ); + void OnOnlineNotif( CCtrlData* ); + void OnChannelAway( CCtrlData* ); + void OnRetry( CCtrlData* ); +}; + +//---- the second property page: DCC/CTCP ----------------------------------------------- + +struct CCtcpPrefsDlg : public CProtoDlgBase +{ + CCtrlCombo m_combo; + CCtrlCheck m_slow, m_fast, m_disc, m_passive, m_sendNotice, m_enableIP, m_fromServer; + CCtrlEdit m_ip, m_userInfo; + CCtrlCheck m_radio1, m_radio2, m_radio3; + + CCtcpPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CCtcpPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + + void OnClicked( CCtrlData* ); +}; + +//---- the third property page: Other --------------------------------------------------- + +struct COtherPrefsDlg : public CProtoDlgBase +{ + bool m_performlistModified; + + CCtrlButton m_url; + CCtrlMButton m_add, m_delete; + CCtrlCombo m_performCombo, m_codepage; + CCtrlEdit m_pertormEdit, m_quitMessage, m_alias; + CCtrlCheck m_perform, m_scripting, m_autodetect; + + COtherPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new COtherPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + virtual void OnDestroy(); + + void OnUrl( CCtrlButton* ); + void OnPerformCombo( CCtrlData* ); + void OnCodePage( CCtrlData* ); + void OnPerformEdit( CCtrlData* ); + void OnPerform( CCtrlData* ); + void OnAdd( CCtrlButton* ); + void OnDelete( CCtrlButton* ); + + void addPerformComboValue( int idx, const char* szValueName ); +}; + +//---- the fourth property page: Ignore ------------------------------------------------- + +struct CIgnorePrefsDlg : public CProtoDlgBase +{ + CCtrlMButton m_add, m_edit, m_del; + CCtrlCheck m_enable, m_ignoreChat, m_ignoreFile, m_ignoreChannel, m_ignoreUnknown; + CCtrlListView m_list; + + CIgnorePrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CIgnorePrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnDestroy(); + virtual void OnApply(); + + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + void List_OnColumnClick( CCtrlListView::TEventInfo* ); + void OnEnableIgnore( CCtrlData* ); + void OnIgnoreChat( CCtrlData* ); + void OnAdd( CCtrlButton* ); + void OnEdit( CCtrlButton* ); + void OnDelete( CCtrlButton* ); + + void FixButtons( void ); + void RebuildList( void ); + void UpdateList( void ); +}; + +struct CAddIgnoreDlg : public CProtoDlgBase +{ + CCtrlButton m_Ok; + CIgnorePrefsDlg* m_owner; + + TCHAR szOldMask[500]; + + CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* parent ); + + virtual void OnInitDialog(); + virtual void OnClose(); + + void OnOk( CCtrlButton* ); +}; diff --git a/protocols/IRCG/src/irclib.cpp b/protocols/IRCG/src/irclib.cpp new file mode 100644 index 0000000000..c018b57a02 --- /dev/null +++ b/protocols/IRCG/src/irclib.cpp @@ -0,0 +1,1505 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "irc.h" + +#define DCCCHATTIMEOUT 300 +#define DCCSENDTIMEOUT 120 + +using namespace irc; + +int CDccSession::nDcc = 0; + +static int CompareHandlers( const CIrcHandler* p1, const CIrcHandler* p2 ) +{ + return lstrcmp( p1->m_name, p2->m_name ); +} + +OBJLIST CIrcProto::m_handlers( 30, CompareHandlers ); + +//////////////////////////////////////////////////////////////////// + +CIrcMessage::CIrcMessage( CIrcProto* _pro, const TCHAR* lpszCmdLine, int codepage, bool bIncoming, bool bNotify ) : + m_proto( _pro ), + m_bIncoming( bIncoming ), + m_bNotify( bNotify ), + m_codePage( codepage ), + parameters( 10 ) +{ + ParseIrcCommand(lpszCmdLine); +} + +CIrcMessage::CIrcMessage(const CIrcMessage& m) : + sCommand( m.sCommand ), + m_bIncoming( m.m_bIncoming ), + m_bNotify( m.m_bNotify ), + m_codePage( m.m_codePage ), + m_proto( m.m_proto ), + parameters( m.parameters.getCount()) +{ + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; + + for ( int i=0; i < m.parameters.getCount(); i++ ) + parameters.insert( new CMString( m.parameters[i] )); +} + +CIrcMessage::~CIrcMessage() +{ +} + +void CIrcMessage::Reset() +{ + prefix.sNick = prefix.sUser = prefix.sHost = sCommand = _T(""); + m_bIncoming = false; + m_bNotify = true; + + parameters.destroy(); +} + +CIrcMessage& CIrcMessage::operator = (const CIrcMessage& m) +{ + if ( &m != this ) { + sCommand = m.sCommand; + parameters = m.parameters; + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; + m_bIncoming = m.m_bIncoming; + m_bNotify = m.m_bNotify; + } + return *this; +} + +CIrcMessage& CIrcMessage::operator = (const TCHAR* lpszCmdLine) +{ + Reset(); + ParseIrcCommand(lpszCmdLine); + return *this; +} + +void CIrcMessage::ParseIrcCommand(const TCHAR* lpszCmdLine) +{ + const TCHAR* p1 = lpszCmdLine; + const TCHAR* p2 = lpszCmdLine; + + // prefix exists ? + if ( *p1 == ':' ) { + // break prefix into its components (nick!user@host) + p2 = ++p1; + while( *p2 && !_tcschr( _T(" !"), *p2 )) + ++p2; + prefix.sNick.SetString(p1, p2 - p1); + if ( *p2 != '!' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && !_tcschr( _T(" @"), *p2 )) + ++p2; + prefix.sUser.SetString(p1, p2 - p1); + if ( *p2 != '@' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && *p2 != ' ' ) + ++p2; + prefix.sHost.SetString(p1, p2 - p1); +end_of_prefix : + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; + } + + // get command + p2 = p1; + while( *p2 && *p2 != ' ' ) + ++p2; + + sCommand.SetString(p1, p2 - p1); + sCommand.MakeUpper(); + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; + + // get parameters + while( *p1 ) { + if ( *p1 == ':' ) { + ++p1; + + // seek end-of-message + while( *p2 ) + ++p2; + parameters.insert( new CMString(p1, p2 - p1)); + break; + } + else { + // seek end of parameter + while( *p2 && *p2 != ' ' ) + ++p2; + parameters.insert( new CMString(p1, p2 - p1)); + // see next parameter + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; +} } } + +//////////////////////////////////////////////////////////////////// + +int CIrcProto::getCodepage() const +{ + return ( con != NULL ) ? codepage : CP_ACP; +} + +void CIrcProto::SendIrcMessage( const TCHAR* msg, bool bNotify, int codepage ) +{ + if ( codepage == -1 ) + codepage = getCodepage(); + + if ( this ) { + char* str = mir_t2a_cp( msg, codepage ); + rtrim( str ); + int cbLen = (int)strlen( str ); + str = ( char* )mir_realloc( str, cbLen+3 ); + strcat( str, "\r\n" ); + NLSend(( const BYTE* )str, cbLen+2 ); + mir_free( str ); + + if ( bNotify ) { + CIrcMessage ircMsg( this, msg, codepage ); + if ( !ircMsg.sCommand.IsEmpty() && ircMsg.sCommand != _T("QUIT")) + Notify( &ircMsg ); +} } } + +bool CIrcProto::Connect(const CIrcSessionInfo& info) +{ + codepage = m_codepage; + + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = info.sServer.c_str(); + ncon.wPort = info.iPort; + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM) hNetlib, (LPARAM) & ncon); + if (con == NULL) { + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0035%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)."), + TranslateT("Failed to connect to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); + return false; + } + + FindLocalIP(con); // get the local ip used for filetransfers etc + + if ( info.m_iSSL > 0 ) { + if ( !CallService( MS_NETLIB_STARTSSL, ( WPARAM ) con, 0 ) && info.m_iSSL == 2 ) { + Netlib_CloseHandle( con ); + con = NULL; + m_info.Reset(); + return false; + } } + + if ( Miranda_Terminated()) { + Disconnect(); + return false; + } + + m_info = info; + + // start receiving messages from host + ircFork( &CIrcProto::ThreadProc, NULL ); + Sleep( 100 ); + if ( info.sPassword.GetLength()) + NLSend( "PASS %s\r\n", info.sPassword.c_str()); + NLSend( _T("NICK %s\r\n"), info.sNick.c_str()); + + CMString m_userID = GetWord(info.sUserID.c_str(), 0); + TCHAR szHostName[MAX_PATH]; + DWORD cbHostName = SIZEOF( szHostName ); + GetComputerName(szHostName, &cbHostName); + CMString HostName = GetWord(szHostName, 0); + if ( m_userID.IsEmpty()) + m_userID = _T("Miranda"); + if ( HostName.IsEmpty()) + HostName= _T("host"); + NLSend( _T("USER %s %s %s :%s\r\n"), m_userID.c_str(), HostName.c_str(), _T("server"), info.sFullName.c_str()); + + return con != NULL; +} + +void CIrcProto::Disconnect(void) +{ + static const DWORD dwServerTimeout = 5 * 1000; + + if ( con == NULL ) + return; + + KillIdent(); + + if ( m_quitMessage && m_quitMessage[0] ) + NLSend( _T("QUIT :%s\r\n"), m_quitMessage); + else + NLSend( "QUIT \r\n" ); + + Sleep(50); + + if ( con ) + Netlib_Shutdown(con); + + m_info.Reset(); + return; +} + +void CIrcProto::Notify(const CIrcMessage* pmsg) +{ + OnIrcMessage(pmsg); +} + +int CIrcProto::NLSend( const unsigned char* buf, int cbBuf) +{ + if ( m_bMbotInstalled && m_scriptingEnabled ) { + int iVal = NULL; + char * pszTemp = 0; + pszTemp = ( char* ) mir_alloc( lstrlenA((const char *) buf ) + 1); + lstrcpynA(pszTemp, (const char *)buf, lstrlenA ((const char *)buf) + 1); + + if ( Scripting_TriggerMSPRawOut(&pszTemp) && pszTemp ) { + if (con) + iVal = Netlib_Send(con, (const char*)pszTemp, lstrlenA(pszTemp), MSG_DUMPASTEXT); + } + if ( pszTemp ) + mir_free( pszTemp ); + + return iVal; + } + + if (con) + return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); + + return 0; +} + +int CIrcProto::NLSend( const TCHAR* fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + + TCHAR szBuf[1024*4]; + mir_vsntprintf(szBuf, SIZEOF(szBuf), fmt, marker); + va_end(marker); + + char* buf = mir_t2a_cp( szBuf, getCodepage()); + int result = NLSend((unsigned char*)buf, (int)strlen(buf)); + mir_free( buf ); + return result; +} + +int CIrcProto::NLSend( const char* fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + + char szBuf[1024*4]; + int cbLen = mir_vsnprintf(szBuf, SIZEOF(szBuf), fmt, marker); + va_end(marker); + + return NLSend((unsigned char*)szBuf, cbLen ); +} + +int CIrcProto::NLSendNoScript( const unsigned char* buf, int cbBuf) +{ + if ( con ) + return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); + + return 0; +} + +int CIrcProto::NLReceive(unsigned char* buf, int cbBuf) +{ + return Netlib_Recv( con, (char*)buf, cbBuf, MSG_DUMPASTEXT ); +} + +void CIrcProto::KillIdent() +{ + if ( hBindPort ) { + HANDLE hPort = hBindPort; + hBindPort = NULL; + Netlib_CloseHandle( hPort ); + } +} + +void CIrcProto::InsertIncomingEvent(TCHAR* pszRaw) +{ + CIrcMessage msg( this, pszRaw, true); + Notify( &msg ); + return; +} + +void CIrcProto::createMessageFromPchar( const char* p ) +{ + TCHAR* ptszMsg; + if ( codepage != CP_UTF8 && m_utfAutodetect ) { + if ( mir_utf8decodecp( NEWSTR_ALLOCA(p), codepage, &ptszMsg ) == NULL ) + ptszMsg = mir_a2t_cp( p, codepage ); + } + else ptszMsg = mir_a2t_cp( p, codepage ); + CIrcMessage msg( this, ptszMsg, codepage, true ); + Notify( &msg ); + mir_free( ptszMsg ); +} + +void CIrcProto::DoReceive() +{ + char chBuf[1024*4+1]; + int cbInBuf = 0; + + if ( m_info.bIdentServer && m_info.iIdentServerPort != NULL ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIdent; + nb.pExtra = this; + nb.wPort = m_info.iIdentServerPort; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)hNetlib,(LPARAM) &nb); + if ( !hBindPort || nb.wPort != m_info.iIdentServerPort ) { + DoNetlibLog("Error: unable to bind local port %u", m_info.iIdentServerPort); + KillIdent(); + } } + + while( con ) { + int nLinesProcessed = 0; + + int cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); + if ( cbRead <= 0 ) + break; + + cbInBuf += cbRead; + chBuf[cbInBuf] = '\0'; + + char* pStart = chBuf; + while( *pStart ) { + char* pEnd; + + // seek end-of-line + for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) + ; + if ( *pEnd == '\0' ) + break; // uncomplete message. stop parsing. + + ++nLinesProcessed; + + // replace end-of-line with NULLs and skip + while( *pEnd == '\r' || *pEnd == '\n' ) + *pEnd++ = '\0'; + + // process single message by monitor objects + if ( *pStart ) { + if ( m_bMbotInstalled && m_scriptingEnabled ) { + char* pszTemp = mir_strdup( pStart ); + + if ( Scripting_TriggerMSPRawIn( &pszTemp ) && pszTemp ) { + char* p1 = pszTemp; + // replace end-of-line with NULLs + while( *p1 != '\0' ) { + if ( *p1 == '\r' || *p1 == '\n') + *p1 = '\0'; + p1++; + } + + createMessageFromPchar( pszTemp ); + } + + mir_free( pszTemp ); + } + else createMessageFromPchar( pStart ); + } + + cbInBuf -= pEnd - pStart; + pStart = pEnd; + } + + // discard processed messages + if ( nLinesProcessed != 0 ) + memmove(chBuf, pStart, cbInBuf+1); + } + + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + + // notify monitor objects that the connection has been closed + Notify(NULL); +} + +void __cdecl CIrcProto::ThreadProc( void* ) +{ + DoReceive(); + m_info.Reset(); +} + +void CIrcProto::AddDCCSession(HANDLE, CDccSession* dcc) +{ + EnterCriticalSection(&m_dcc); + + CDccSession* p = m_dcc_chats.find(dcc); + if ( p ) + m_dcc_chats.remove( p ); + + m_dcc_chats.insert( dcc ); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::AddDCCSession(DCCINFO*, CDccSession* dcc) +{ + EnterCriticalSection(&m_dcc); + + m_dcc_xfers.insert( dcc ); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::RemoveDCCSession(HANDLE hContact) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_dcc_chats[i]->di->hContact == hContact ) { + m_dcc_chats.remove( i ); + break; + } + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::RemoveDCCSession(DCCINFO* pdci) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) + if ( m_dcc_xfers[i]->di == pdci ) { + m_dcc_xfers.remove( i ); + break; + } + + LeaveCriticalSection(&m_dcc); +} + +CDccSession* CIrcProto::FindDCCSession(HANDLE hContact) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_dcc_chats[i]->di->hContact == hContact ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_chats[ i ]; + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCSession(DCCINFO* pdci) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) + if ( m_dcc_xfers[i]->di == pdci ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_xfers[ i ]; + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCSendByPort(int iPort) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + if ( p->di->iType == DCC_SEND && p->di->bSender && iPort == p->di->iPort ) { + LeaveCriticalSection(&m_dcc); + return p; + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCRecvByPortAndName(int iPort, const TCHAR* szName) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + DBVARIANT dbv; + if ( !getTString(p->di->hContact, "Nick", &dbv)) { + if ( p->di->iType == DCC_SEND && !p->di->bSender && !lstrcmpi( szName, dbv.ptszVal) && iPort == p->di->iPort ) { + DBFreeVariant(&dbv); + LeaveCriticalSection(&m_dcc); + return p; + } + DBFreeVariant(&dbv); + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindPassiveDCCSend(int iToken) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + if ( m_dcc_xfers[ i ]->iToken == iToken ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_xfers[ i ]; + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindPassiveDCCRecv(CMString sName, CMString sToken) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + if ( sToken == p->di->sToken && sName == p->di->sContactName ) { + LeaveCriticalSection(&m_dcc); + return p; + } + } + LeaveCriticalSection(&m_dcc); + return 0; +} + +void CIrcProto::DisconnectAllDCCSessions(bool Shutdown) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_disconnectDCCChats || Shutdown ) + m_dcc_chats[i]->Disconnect(); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::CheckDCCTimeout(void) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) { + CDccSession* p = m_dcc_chats[i]; + if ( time(0) > p->tLastActivity + DCCCHATTIMEOUT ) + p->Disconnect(); + } + + for ( int j=0; j < m_dcc_xfers.getCount(); j++ ) { + CDccSession* p = m_dcc_xfers[j]; + if ( time(0) > p->tLastActivity + DCCSENDTIMEOUT ) + p->Disconnect(); + } + + LeaveCriticalSection(&m_dcc); +} + +//////////////////////////////////////////////////////////////////// + +CIrcIgnoreItem::CIrcIgnoreItem( const TCHAR* _mask, const TCHAR* _flags, const TCHAR* _network ) : + mask( _mask ), + flags( _flags ), + network( _network ) +{ +} + +CIrcIgnoreItem::CIrcIgnoreItem( int codepage, const char* _mask, const char* _flags, const char* _network ) : + mask( (TCHAR *)_A2T( _mask, codepage )), + flags( (TCHAR *)_A2T( _flags, codepage )), + network( (TCHAR *)_A2T( _network, codepage )) +{ +} + +CIrcIgnoreItem::~CIrcIgnoreItem() +{ +} + +//////////////////////////////////////////////////////////////////// + +CIrcSessionInfo::CIrcSessionInfo() : + iPort(0), + bIdentServer(false), + iIdentServerPort(0) +{ +} + +CIrcSessionInfo::CIrcSessionInfo(const CIrcSessionInfo& si) : + sServer(si.sServer), + sServerName(si.sServerName), + iPort(si.iPort), + sNick(si.sNick), + sUserID(si.sUserID), + sFullName(si.sFullName), + sPassword(si.sPassword), + bIdentServer(si.bIdentServer), + m_iSSL(si.m_iSSL), + sIdentServerType(si.sIdentServerType), + sNetwork(si.sNetwork), + iIdentServerPort(si.iIdentServerPort) +{ +} + +void CIrcSessionInfo::Reset() +{ + sServer = ""; + sServerName = _T(""); + iPort = 0; + sNick = _T(""); + sUserID = _T(""); + sFullName = _T(""); + sPassword = ""; + bIdentServer = false; + bNickFlag = false; + m_iSSL = 0; + sIdentServerType = _T(""); + iIdentServerPort = 0; + sNetwork = _T(""); +} + +//////////////////////////////////////////////////////////////////// + +void CIrcProto::OnIrcMessage(const CIrcMessage* pmsg) +{ + if ( pmsg != NULL ) { + PfnIrcMessageHandler pfn = FindMethod( pmsg->sCommand.c_str()); + if ( pfn ) { + // call member function. if it returns 'false', + // call the default handling + __try + { + if ( !(this->*pfn)( pmsg )) + OnIrcDefault( pmsg ); + } + __except( EXCEPTION_EXECUTE_HANDLER ) // dedicated to Sava :) + { + DoNetlibLog( "IRC handler feels sick: %S", pmsg->sCommand.c_str()); + } + } + else // handler not found. call default handler + OnIrcDefault( pmsg ); + } + else OnIrcDisconnected(); +} + +PfnIrcMessageHandler CIrcProto::FindMethod(const TCHAR* lpszName) +{ + CIrcHandler temp( lpszName, NULL ); + CIrcHandler* p = m_handlers.find( &temp ); + return ( p == NULL ) ? NULL : p->m_handler; +} + +//////////////////////////////////////////////////////////////////// + +#define IPC_ADDR_SIZE 4 /* Size of IP address, change for IPv6. */ + +char* ConvertIntegerToIP(unsigned long int_ip_addr) +{ + IN_ADDR intemp; + IN_ADDR in; + intemp.S_un.S_addr = int_ip_addr; + + in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; + in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; + in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; + in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; + + return inet_ntoa( in ); +} + +unsigned long ConvertIPToInteger( char* IP ) +{ + IN_ADDR in; + IN_ADDR intemp; + + if ( IP == 0 || lstrlenA(IP) == 0) + return 0; + + intemp.S_un.S_addr = inet_addr(IP); + + in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; + in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; + in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; + in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; + return in.S_un.S_addr; +} + +//////////////////////////////////////////////////////////////////// + +// initialize basic stuff needed for the dcc objects, also start a timer for checking the status of connections (timeouts) +CDccSession::CDccSession( CIrcProto* _pro, DCCINFO* pdci ) : + m_proto( _pro ), + NewFileName(0), + dwWhatNeedsDoing(0), + tLastPercentageUpdate(0), + dwTotal(0), + iGlobalToken(), + dwResumePos(0), + hEvent(0), + con(0), + hBindPort(0) +{ + tLastActivity = time(0); + + di = pdci; // Setup values passed to the constructor + + ZeroMemory(&pfts, sizeof(PROTOFILETRANSFERSTATUS)); + pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); + + if(di->iType == DCC_SEND && di->bSender == false) + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if(nDcc == 0) + m_proto->SetChatTimer(m_proto->DCCTimer, 20*1000, DCCTimerProc); + + nDcc++; // increase the count of existing objects + + iGlobalToken++; + if(iGlobalToken == 1000) + iGlobalToken = 1; + iToken = iGlobalToken; + + iPacketSize = m_proto->getWord( "PacketSize", 4096 ); + + if ( di->dwAdr ) + m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff +} + +CDccSession::~CDccSession() // destroy all that needs destroying +{ + if ( di->iType == DCC_SEND ) { + // ack SUCCESS or FAILURE + if (dwTotal == di->dwSize ) + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (void *)di, 0); + else + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + } + + if ( di->iType == DCC_CHAT ) { + CDccSession* dcc = m_proto->FindDCCSession(di->hContact); + if ( dcc && this == dcc ) { + m_proto->RemoveDCCSession(di->hContact); // objects automatically remove themselves from the list of objects + m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); + } } + + if ( di->iType == DCC_SEND ) + m_proto->RemoveDCCSession( di ); + + if ( hEvent != NULL ) { + SetEvent( hEvent ); + CloseHandle( hEvent ); + hEvent = NULL; + } + + delete di; + nDcc--; + + if ( nDcc < 0 ) + nDcc = 0; + + if ( nDcc == 0 ) + m_proto->KillChatTimer( m_proto->DCCTimer ); // destroy the timer when no dcc objects remain +} + +int CDccSession::NLSend(const unsigned char* buf, int cbBuf) +{ + tLastActivity = time(0); + + if (con) + return Netlib_Send(con, (const char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); + + return 0; +} + +int CDccSession::NLReceive(const unsigned char* buf, int cbBuf) +{ + int n = 0; + + if(con) + n = Netlib_Recv(con, (char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); + + tLastActivity = time(0); + return n; +} + +int CDccSession::SendStuff(const TCHAR* fmt) +{ + String buf = _T2A( fmt, m_proto->getCodepage()); + return NLSend(( const unsigned char* )buf.c_str(), buf.GetLength()); +} + +// called when the user wants to connect/create a new connection given the parameters in the constructor. +int CDccSession::Connect() +{ + if ( !di->bSender || di->bReverse ) { + if ( !con ) + mir_forkthread( ConnectProc, this ); // spawn a new thread for time consuming activities, ie when connecting to a remote computer + return true; + } + + if ( !con ) + return SetupConnection(); // no need to spawn thread for setting up a listening port locally + + return false; +} + +void __cdecl CDccSession::ConnectProc( void *pparam ) +{ + CDccSession* pThis = (CDccSession*)pparam; + if ( !pThis->con ) + pThis->SetupConnection(); +} + +// small function to setup the address and port of the remote computer fror passive filetransfers +void CDccSession::SetupPassive(DWORD adress, DWORD port) +{ + di->dwAdr = adress; + di->iPort = (int)port; + + m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff +} + +int CDccSession::SetupConnection() +{ + // if it is a dcc chat connection make sure it is "offline" to begin with, since no connection exists still + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); + + // Set up stuff needed for the filetransfer dialog (if it is a filetransfer) + if ( di->iType == DCC_SEND ) { + file[0] = ( TCHAR* )di->sFileAndPath.c_str(); + file[1] = 0; + + pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); + pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); + pfts.hContact = di->hContact; + pfts.flags = PFTS_TCHAR + ((di->bSender) ? PFTS_SENDING : PFTS_RECEIVING); + pfts.totalFiles = 1; + pfts.currentFileNumber = 0; + pfts.totalBytes = di->dwSize; + pfts.currentFileSize = pfts.totalBytes; + pfts.ptszFiles = file; + pfts.totalProgress = 0; + pfts.currentFileProgress = 0; + pfts.currentFileTime = (unsigned long)time(0); + } + + // create a listening socket for outgoing chat/send requests. The remote computer connects to this computer. Used for both chat and filetransfer. + if ( di->bSender && !di->bReverse ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() + nb.pExtra = (void *)this; + nb.wPort = 0; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); + + if ( hBindPort == NULL ) { + delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. + return 0; + } + + di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) + return nb.wPort; // return the created port so it can be sent to the remote computer in a ctcp/dcc command + } + + // If a remote computer initiates a chat session this is used to connect to the remote computer (user already accepted at this point). + // also used for connecting to a remote computer for remote file transfers + if ( di->iType == DCC_CHAT && !di->bSender || di->iType == DCC_SEND && di->bSender && di->bReverse ) { + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = ConvertIntegerToIP(di->dwAdr); + ncon.wPort = (WORD) di->iPort; + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); + } + + + // If a remote computer initiates a filetransfer this is used to connect to that computer (the user has chosen to accept but it is possible the file exists/needs to be resumed etc still) + if ( di->iType == DCC_SEND && !di->bSender ) { + + // this following code is for miranda to be able to show the resume/overwrite etc dialog if the file that we are receiving already exists. + // It must be done before we create the connection or else the other party will begin sending packets while the user is still deciding if + // s/he wants to resume/cancel or whatever. Just the way dcc is... + + // if the file exists (dialog is shown) WaitForSingleObject() till the dialog is closed and PS_FILERESUME has been processed. + // dwWhatNeedsDoing will be set using InterlockedExchange() (from other parts of the code depending on action) before SetEvent() is called. + // If the user has chosen rename then InterlockedExchange() will be used for setting NewFileName to a string containing the new name. + // Furthermore dwResumePos will be set using InterlockedExchange() to indicate what the file position to start from is. + if ( ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (void *)di, (LPARAM)&pfts)) { + WaitForSingleObject( hEvent, INFINITE ); + switch( dwWhatNeedsDoing ) { + case FILERESUME_RENAME: + // If the user has chosen to rename the file we need to change variables accordingly. NewFileName has been set using + // InterlockedExchange() + if ( NewFileName) { // the user has chosen to rename the new incoming file. + di->sFileAndPath = NewFileName; + + int i = di->sFileAndPath.ReverseFind( '\\' ); + if ( i != -1 ) { + di->sPath = di->sFileAndPath.Mid(0, i+1); + di->sFile = di->sFileAndPath.Mid(i+1, di->sFileAndPath.GetLength()); + } + + pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); + pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); + pfts.totalBytes = di->dwSize; + pfts.currentFileSize = pfts.totalBytes; + + delete[] NewFileName; + NewFileName = NULL; + } + break; + + case FILERESUME_OVERWRITE: + case FILERESUME_RESUME : + // no action needed at this point, just break out of the switch statement + break; + + case FILERESUME_CANCEL : + return FALSE; + + case FILERESUME_SKIP : + default: + delete this; // per usual dcc objects destroy themselves when they fail or when connection is closed + return FALSE; + } } + + // hack for passive filetransfers + if ( di->iType == DCC_SEND && !di->bSender && di->bReverse ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() + nb.pExtra = (void *)this; + nb.wPort = 0; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); + + if ( hBindPort == NULL ) { + m_proto->DoEvent(GC_EVENT_INFORMATION, 0, m_proto->m_info.sNick.c_str(), LPGENT("DCC ERROR: Unable to bind local port for passive filetransfer"), NULL, NULL, NULL, true, false); + delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. + return 0; + } + + di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) + + CMString sFileWithQuotes = di->sFile; + + // if spaces in the filename surround with quotes + if ( sFileWithQuotes.Find( ' ', 0 ) != -1 ) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + // send out DCC RECV command for passive filetransfers + unsigned long ulAdr = 0; + if ( m_proto->m_manualHost ) + ulAdr = ConvertIPToInteger( m_proto->m_mySpecifiedHostIP ); + else + ulAdr = m_proto->m_IPFromServer ? ConvertIPToInteger( m_proto->m_myHost ) : nb.dwExternalIP; + + if ( di->iPort && ulAdr ) + m_proto->PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u %s"), di->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, di->iPort, di->dwSize, di->sToken.c_str()); + + return TRUE; + } + + // connect to the remote computer from which you are receiving the file (now all actions to take (resume/overwrite etc) have been decided + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = ConvertIntegerToIP(di->dwAdr); + ncon.wPort = (WORD) di->iPort; + + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); + } + + // if for some reason the plugin has failed to connect to the remote computer the object is destroyed. + if ( con == NULL ) { + delete this; + return FALSE; // failed to connect + } + + // if it is a chat connection set the user to online now since we now know there is a connection + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); + + // spawn a new thread to handle receiving/sending of data for the new chat/filetransfer connection to the remote computer + mir_forkthread( ThreadProc, this ); + + return con != NULL; +} + +// called by netlib for incoming connections on a listening socket (chat/filetransfer) +int CDccSession::IncomingConnection(HANDLE hConnection, DWORD dwIP) +{ + con = hConnection; + if ( con == NULL ) { + delete this; + return false; // failed to connect + } + + m_proto->setDword(di->hContact, "IP", dwIP); // mToolTip stuff + + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); // set chat to online + + // same as above, spawn a new thread to handle receiving/sending of data for the new incoming chat/filetransfer connection + mir_forkthread(ThreadProc, this ); + return true; +} + +// here we decide which function to use for communicating with the remote computer, depending on connection type +void __cdecl CDccSession::ThreadProc(void *pparam) +{ + CDccSession* pThis = (CDccSession*)pparam; + + // if it is an incoming connection on a listening port, then we should close the listenting port so only one can connect (the one you offered + // the connection to) can connect and not evil IRCopers with haxxored IRCDs + if ( pThis->hBindPort ) { + Netlib_CloseHandle(pThis->hBindPort); + pThis->hBindPort = NULL; + } + + if ( pThis->di->iType == DCC_CHAT ) + pThis->DoChatReceive(); // dcc chat + + else if ( !pThis->di->bSender ) + pThis->DoReceiveFile(); // receive a file + + else if ( pThis->di->bSender ) + pThis->DoSendFile(); // send a file +} + +// this is done when the user is initiating a filetransfer to a remote computer +void CDccSession::DoSendFile() +{ + // initialize the filetransfer dialog + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); + + WORD wPacketSize = m_proto->getWord( "DCCPacketSize", 1024*4); + + if ( wPacketSize < 256 ) + wPacketSize = 256; + + if ( wPacketSize > 32 * 1024 ) + wPacketSize = 32 * 1024; + + BYTE* chBuf = new BYTE[wPacketSize+1]; + + // is there a connection? + if ( con ) { + // open the file for reading + int hFile = _topen( di->sFileAndPath.c_str(), _O_RDONLY | _O_BINARY, _S_IREAD); + if (hFile >= 0) { + unsigned __int64 dwLastAck = 0; + + // if the user has chosen to resume a file, dwResumePos will contain a value (set using InterlockedExchange()) + // and then the variables and the file pointer are changed accordingly. + if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { + _lseeki64(hFile, dwResumePos, SEEK_SET); + dwTotal = dwResumePos; + dwLastAck = dwResumePos; + pfts.totalProgress = dwResumePos; + pfts.currentFileProgress = dwResumePos; + } + + // initial ack to set the 'percentage-ready meter' to the correct value + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + tLastActivity = time(0); + + // create a packet receiver to handle receiving ack's from the remote computer. + HANDLE hPackrcver = (HANDLE)CallService( MS_NETLIB_CREATEPACKETRECVER, (WPARAM)con, (LPARAM)sizeof(DWORD)); + NETLIBPACKETRECVER npr; + npr.cbSize = sizeof(NETLIBPACKETRECVER); + npr.dwTimeout = 60*1000; + npr.bufferSize = sizeof(DWORD); + npr.bytesUsed = 0; + + // until the connection is dropped it will spin around in this while() loop + while ( con ) { + // read a packet + int iRead = _read(hFile, chBuf, wPacketSize); + if ( iRead <= 0 ) + break; // break out if everything has already been read + + // send the package + int cbSent = NLSend((unsigned char*)chBuf, iRead); + if ( cbSent <= 0 ) + break; // break out if connection is lost or a transmission error has occured + + if ( !con ) + break; + + dwTotal += cbSent; + + // block connection and receive ack's from remote computer (if applicable) + if ( m_proto->m_DCCMode == 0 ) { + DWORD dwRead = 0; + DWORD dwPacket = NULL; + + do { + dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); + npr.bytesUsed = sizeof(DWORD); + + if ( dwRead <= 0) + break; // connection closed, or a timeout occurred. + + dwPacket = *(DWORD*)npr.buffer; + dwLastAck = ntohl(dwPacket); + + } + while(con && dwTotal != dwLastAck); + + if ( !con || dwRead <= 0 ) + goto DCC_STOP; + } + + if ( m_proto->m_DCCMode == 1 ) { + DWORD dwRead = 0; + DWORD dwPacket = 0; + + do { + dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); + npr.bytesUsed = sizeof(DWORD); + if ( dwRead <= 0) + break; // connection closed, or a timeout occurred. + + dwPacket = *(DWORD*)npr.buffer; + dwLastAck = ntohl(dwPacket); + } + while(con && (di->dwSize != dwTotal + && dwTotal - dwLastAck >= 100*1024 + || di->dwSize == dwTotal // get the last packets when the whole file has been sent + && dwTotal != dwLastAck)); + + if ( !con || dwRead <= 0 ) + goto DCC_STOP; + } + + // update the filetransfer dialog's 'percentage-ready meter' once per second only to save cpu + if ( tLastPercentageUpdate < time(0)) { + tLastPercentageUpdate = time(0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + } + + // close the connection once the whole file has been sent an completely ack'ed + if ( dwLastAck >= di->dwSize ) { + Netlib_CloseHandle(con); + con = NULL; + } } + +DCC_STOP: + // need to close the connection if it isn't allready + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + + // ack the progress one final time + tLastActivity = time(0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + _close(hFile); + } + else // file was not possible to open for reading + { + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } } } + + delete []chBuf; + delete this; // ... and hopefully all went right, cuz here the object is deleted in any case +} + +// This is called when receiving a file from a remote computer. +void CDccSession::DoReceiveFile() +{ + // initialize the filetransfer dialog + ProtoBroadcastAck( m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); + + BYTE chBuf[1024*32+1]; + + // do some stupid thing so the filetransfer dialog shows the right thing + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); + + // open the file for writing (and reading in case it is a resume) + int hFile = _topen( di->sFileAndPath.c_str(), + (dwWhatNeedsDoing == FILERESUME_RESUME ? _O_APPEND : _O_TRUNC | _O_CREAT) | _O_RDWR | _O_BINARY, + _S_IREAD | _S_IWRITE); + if ( hFile >= 0 ) { + unsigned __int64 dwLastAck = 0; + + // dwResumePos and dwWhatNeedsDoing has possibly been set using InterlockedExchange() + // if set it is a resume and we adjust variables and the file pointer accordingly. + if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { + _lseeki64(hFile, dwResumePos, SEEK_SET); + dwTotal = dwResumePos; + dwLastAck = dwResumePos; + pfts.totalProgress = dwResumePos; + pfts.currentFileProgress = dwResumePos; + } + + // send an initial ack for the percentage-ready meter + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + // the while loop will spin around till the connection is dropped, locally or by the remote computer. + while ( con ) { + // read + int cbRead = NLReceive((unsigned char*)chBuf, sizeof(chBuf)); + if ( cbRead <= 0 ) + break; + + // write it to the file + _write(hFile, chBuf, cbRead); + + dwTotal += cbRead; + + // this snippet sends out an ack for every 4 kb received in send ahead + // or every packet for normal mode + if ( !di->bTurbo ) { + DWORD no = dwTotal; + no = htonl(no); + NLSend((unsigned char *)&no, sizeof(DWORD)); + dwLastAck = dwTotal; + } + else dwLastAck = dwTotal; + + // sets the 'last update time' to check for timed out connections, and also make sure we only + // ack the 'percentage-ready meter' only once a second to save CPU. + if ( tLastPercentageUpdate < time( 0 )) { + tLastPercentageUpdate = time (0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + } + + // if file size is known and everything is received then disconnect + if ( di->dwSize && di->dwSize == dwTotal ) { + Netlib_CloseHandle(con); + con = NULL; + } } + // receiving loop broken locally or by remote computer, just some cleaning up left.... + + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + _close(hFile); + } + else { + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + if ( con ) { // file not possible to open for writing so we ack FAILURE and close the handle + Netlib_CloseHandle(con); + con = NULL; + } } + + delete this; // and finally the object is deleted +} + +// this function handles receiving text in dcc chats and then send it in the protochain. very uncomplicated... +// For sending text the SendStuff() function is called (with the help of some function in CIrcProto to find the right +// Dcc object). See CIrcProto for info on how the dcc objects are stored, retreived and deleted. + +void CDccSession::DoChatReceive() +{ + char chBuf[1024*4+1]; + int cbInBuf = 0; + + // loop to spin around while there is a connection + while( con ) { + int cbRead; + int nLinesProcessed = 0; + + cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); + if ( cbRead <= 0 ) + break; + + cbInBuf += cbRead; + chBuf[cbInBuf] = '\0'; + + char* pStart = chBuf; + while( *pStart ) { + char* pEnd; + + // seek end-of-line + for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) + ; + if ( *pEnd == '\0' ) + break; // uncomplete message. stop parsing. + + ++nLinesProcessed; + + // replace end-of-line with NULLs and skip + while( *pEnd == '\r' || *pEnd == '\n' ) + *pEnd++ = '\0'; + + if ( *pStart ) { + // send it off to some messaging module + + PROTORECVEVENT pre = {0}; + pre.timestamp = (DWORD)time(NULL); +// pre.szMessage = (char*)DoColorCodes((TCHAR*)pStart, true, false); //!!!! // remove color codes + pre.szMessage = pStart; + + CCSDATA ccs = {0}; + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = di->hContact; + ccs.lParam = (LPARAM) ⪯ + + CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); + } + + cbInBuf -= pEnd - pStart; + pStart = pEnd; + } + + // discard processed messages + if ( nLinesProcessed != 0 ) + memmove(chBuf, pStart, cbInBuf+1); + } + + delete this; // delete the object when the connection is dropped +} + +// disconnect the stuff +int CDccSession::Disconnect() +{ + if ( hBindPort ) { + Netlib_CloseHandle(hBindPort); + hBindPort = NULL; + } + + // if 'con' exists it is cuz a connection exists. + // Terminating 'con' will cause any spawned threads to die and then the object will destroy itself. + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + else delete this; // if 'con' do not exist (no connection made so far from the object) the object is destroyed + + return TRUE; +} + +//////////////////////////////////////////////////////////////////// +// check if the dcc chats should disconnect ( default 5 minute timeout ) + +VOID CALLBACK DCCTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( ppro ) + ppro->CheckDCCTimeout(); +} + +// helper function for incoming dcc connections. +void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void * p1) +{ + CDccSession* dcc = (CDccSession*)p1; + dcc->IncomingConnection(hConnection, dwRemoteIP); +} + +// ident server + +void strdel( char* parBuffer, int len ) +{ + char* p; + for ( p = parBuffer+len; *p != 0; p++ ) + p[ -len ] = *p; + + p[ -len ] = '\0'; +} + +void DoIdent(HANDLE hConnection, DWORD, void* extra ) +{ + CIrcProto* ppro = ( CIrcProto* )extra; + + char szBuf[1024]; + int cbTotal = 0; + + for (;;) { + int cbRead = Netlib_Recv(hConnection, szBuf+cbTotal, sizeof(szBuf)-1-cbTotal, 0); + if ( cbRead == SOCKET_ERROR || cbRead == 0) + break; + + cbTotal += cbRead; + szBuf[cbTotal] = '\0'; + +LBL_Parse: + char* EOLPos = strstr(szBuf, "\r\n"); + if (EOLPos == NULL) + continue; + + EOLPos[0] = EOLPos[1] = '\0'; + rtrim( szBuf ); + ppro->DoNetlibLog("Got Ident request: %s", szBuf); + + unsigned int PeerPortNrRcvd = 0, LocalPortNrRcvd = 0; + int iParamCnt = sscanf( szBuf, "%d , %d", &LocalPortNrRcvd, &PeerPortNrRcvd ); + + int cbLen = 0; + char buf[1024*4]; + + if (iParamCnt != 2) + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : UNKNOWN-ERROR\r\n", szBuf); + else + { + for (int i = 0; i < g_Instances.getCount(); i++) + { + if (PeerPortNrRcvd == g_Instances[i]->m_info.iPort && LocalPortNrRcvd == g_Instances[i]->m_myLocalPort) + { + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : USERID : " TCHAR_STR_PARAM " : " TCHAR_STR_PARAM "\r\n", + szBuf, g_Instances[i]->m_info.sIdentServerType.c_str() , g_Instances[i]->m_info.sUserID.c_str()); + break; + } + } + + if (cbLen == 0) + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : INVALID-PORT\r\n", szBuf); + } + + if ( Netlib_Send(hConnection, (const char*)buf, cbLen, 0) > 0) + ppro->DoNetlibLog("Sent Ident answer: %s", buf); + else + ppro->DoNetlibLog("Sending Ident answer failed."); + + if ( ppro->m_identTimer ) + break; + + cbTotal -= EOLPos + 2 - szBuf; + strdel(szBuf, int(EOLPos + 2 - szBuf)); + goto LBL_Parse; + } + Netlib_CloseHandle(hConnection); +} diff --git a/protocols/IRCG/src/irclib.h b/protocols/IRCG/src/irclib.h new file mode 100644 index 0000000000..7dcb5a4c01 --- /dev/null +++ b/protocols/IRCG/src/irclib.h @@ -0,0 +1,175 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _IRC_H_ +#define _IRC_H_ + +#pragma warning (disable: 4786) + +void DoIdent(HANDLE hConnection, DWORD dwRemoteIP, void* extra); +void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void* extra); +unsigned long ConvertIPToInteger(char * IP); +char* ConvertIntegerToIP(unsigned long int_ip_addr); + +//////////////////////////////////////////////////////////////////// +namespace irc { +//////////////////////////////////////////////////////////////////// + +struct DCCINFO : public MZeroedObject +{ + DWORD dwAdr; + unsigned __int64 dwSize; + DWORD iType; + CMString sToken; + int iPort; + BOOL bTurbo; + BOOL bSSL; + BOOL bSender; + BOOL bReverse; + CMString sPath; + CMString sFile; + CMString sFileAndPath; + CMString sHostmask; + HANDLE hContact; + CMString sContactName; +}; + +class CIrcMessage +{ +public : + struct Prefix + { + CMString sNick, sUser, sHost; + } + prefix; + + CIrcProto* m_proto; + CMString sCommand; + OBJLIST parameters; + bool m_bIncoming; + bool m_bNotify; + int m_codePage; + + //CIrcMessage( CIrcProto* ); // default constructor + CIrcMessage( CIrcProto*, const TCHAR* lpszCmdLine, int codepage, bool bIncoming=false, bool bNotify = true); // parser constructor + CIrcMessage( const CIrcMessage& m ); // copy constructor + ~CIrcMessage(); + + void Reset(); + + CIrcMessage& operator = (const CIrcMessage& m); + CIrcMessage& operator = (const TCHAR* lpszCmdLine); + +private : + void ParseIrcCommand(const TCHAR* lpszCmdLine); +}; + +//////////////////////////////////////////////////////////////////// + +struct CIrcSessionInfo +{ + String sServer; + CMString sServerName; + CMString sNick; + CMString sUserID; + CMString sFullName; + String sPassword; + CMString sIdentServerType; + CMString sNetwork; + bool bIdentServer; + bool bNickFlag; + int m_iSSL; + unsigned int iIdentServerPort; + unsigned int iPort; + + CIrcSessionInfo(); + CIrcSessionInfo(const CIrcSessionInfo& si); + + void Reset(); +}; + +//////////////////////////////////////////////////////////////////// + +struct CIrcIgnoreItem +{ + CIrcIgnoreItem( const TCHAR*, const TCHAR*, const TCHAR* ); + CIrcIgnoreItem( int codepage, const char*, const char*, const char* ); + ~CIrcIgnoreItem(); + + CMString mask, flags, network; +}; + +//////////////////////////////////////////////////////////////////// + +class CDccSession +{ +protected: + CIrcProto* m_proto; + HANDLE con; // connection handle + HANDLE hBindPort; // handle for listening port + static int nDcc; // number of dcc objects + unsigned __int64 dwTotal; // total bytes sent/received + + int iPacketSize; // size of outgoing packets + int iGlobalToken; + + PROTOFILETRANSFERSTATUS pfts; // structure used to setup and update the filetransfer dialogs of miranda + TCHAR* file[2]; + + int SetupConnection(); + void DoSendFile(); + void DoReceiveFile(); + void DoChatReceive(); + int NLSend( const unsigned char* buf, int cbBuf); + int NLReceive(const unsigned char* buf, int cbBuf); + static void __cdecl ThreadProc(void *pparam); + static void __cdecl ConnectProc(void *pparam); + +public: + + CDccSession(CIrcProto*, DCCINFO* pdci); // constructor + ~CDccSession(); // destructor, ÷òî õàðàêòåðíî + + time_t tLastPercentageUpdate; // time of last update of the filetransfer dialog + time_t tLastActivity; // time of last in/out activity of the object + time_t tLastAck; // last acked filesize + + HANDLE hEvent; // Manual object + long dwWhatNeedsDoing; // Set to indicate what FILERESUME_ action is chosen by the user + TCHAR* NewFileName; // contains new file name if FILERESUME_RENAME chosen + unsigned __int64 dwResumePos; // position to resume from if FILERESUME_RESUME + + int iToken; // used to identify (find) objects in reverse dcc filetransfers + + DCCINFO* di; // details regarding the filetrasnfer + + int Connect(); + void SetupPassive( DWORD adr, DWORD port ); + int SendStuff(const TCHAR* fmt); + int IncomingConnection(HANDLE hConnection, DWORD dwIP); + int Disconnect(); +}; + +//////////////////////////////////////////////////////////////////// +}; // end of namespace irc +//////////////////////////////////////////////////////////////////// + +#endif // _IRC_H_ diff --git a/protocols/IRCG/src/ircproto.cpp b/protocols/IRCG/src/ircproto.cpp new file mode 100644 index 0000000000..9ff2a1c851 --- /dev/null +++ b/protocols/IRCG/src/ircproto.cpp @@ -0,0 +1,1076 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" +#include "version.h" + +#include + +static int CompareSessions( const CDccSession* p1, const CDccSession* p2 ) +{ + return INT_PTR( p1->di->hContact ) - INT_PTR( p2->di->hContact ); +} + +CIrcProto::CIrcProto( const char* szModuleName, const TCHAR* tszUserName ) : + m_dcc_chats( 10, CompareSessions ), + m_dcc_xfers( 10, CompareSessions ), + m_ignoreItems( 10 ), + vUserhostReasons( 10 ), + vWhoInProgress( 10 ) +{ + m_iVersion = 2; + m_tszUserName = mir_tstrdup( tszUserName ); + m_szModuleName = mir_strdup( szModuleName ); + + InitializeCriticalSection(&cs); + InitializeCriticalSection(&m_gchook); + m_evWndCreate = ::CreateEvent( NULL, FALSE, FALSE, NULL ); + + CreateProtoService( PS_GETMYAWAYMSG, &CIrcProto::GetMyAwayMsg ); + + CreateProtoService( PS_CREATEACCMGRUI, &CIrcProto::SvcCreateAccMgrUI ); + CreateProtoService( PS_JOINCHAT, &CIrcProto::OnJoinChat ); + CreateProtoService( PS_LEAVECHAT, &CIrcProto::OnLeaveChat ); + + CreateProtoService( IRC_JOINCHANNEL, &CIrcProto::OnJoinMenuCommand ); + CreateProtoService( IRC_QUICKCONNECT, &CIrcProto::OnQuickConnectMenuCommand); + CreateProtoService( IRC_CHANGENICK, &CIrcProto::OnChangeNickMenuCommand ); + CreateProtoService( IRC_SHOWLIST, &CIrcProto::OnShowListMenuCommand ); + CreateProtoService( IRC_SHOWSERVER, &CIrcProto::OnShowServerMenuCommand ); + CreateProtoService( IRC_UM_CHANSETTINGS, &CIrcProto::OnMenuChanSettings ); + CreateProtoService( IRC_UM_WHOIS, &CIrcProto::OnMenuWhois ); + CreateProtoService( IRC_UM_DISCONNECT, &CIrcProto::OnMenuDisconnect ); + CreateProtoService( IRC_UM_IGNORE, &CIrcProto::OnMenuIgnore ); + + CreateProtoService( "/DblClickEvent", &CIrcProto::OnDoubleclicked ); + CreateProtoService( "/InsertRawIn", &CIrcProto::Scripting_InsertRawIn ); + CreateProtoService( "/InsertRawOut", &CIrcProto::Scripting_InsertRawOut ); + CreateProtoService( "/InsertGuiIn", &CIrcProto::Scripting_InsertGuiIn ); + CreateProtoService( "/InsertGuiOut", &CIrcProto::Scripting_InsertGuiOut); + CreateProtoService( "/GetIrcData", &CIrcProto::Scripting_GetIrcData); + + codepage = CP_ACP; + InitializeCriticalSection(&m_resolve); + InitializeCriticalSection(&m_dcc); + + InitPrefs(); + + char text[ MAX_PATH ]; + mir_snprintf( text, sizeof( text ), "%s/Status", m_szProtoName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + + CList_SetAllOffline(true); + AddIcons(); + + IRC_MAP_ENTRY("PING", PING) + IRC_MAP_ENTRY("JOIN", JOIN) + IRC_MAP_ENTRY("QUIT", QUIT) + IRC_MAP_ENTRY("KICK", KICK) + IRC_MAP_ENTRY("MODE", MODE) + IRC_MAP_ENTRY("NICK", NICK) + IRC_MAP_ENTRY("PART", PART) + IRC_MAP_ENTRY("PRIVMSG", PRIVMSG) + IRC_MAP_ENTRY("TOPIC", TOPIC) + IRC_MAP_ENTRY("NOTICE", NOTICE) + IRC_MAP_ENTRY("PING", PINGPONG) + IRC_MAP_ENTRY("PONG", PINGPONG) + IRC_MAP_ENTRY("INVITE", INVITE) + IRC_MAP_ENTRY("ERROR", ERROR) + IRC_MAP_ENTRY("001", WELCOME) + IRC_MAP_ENTRY("002", YOURHOST) + IRC_MAP_ENTRY("005", SUPPORT) + IRC_MAP_ENTRY("223", WHOIS_OTHER) //CodePage info + IRC_MAP_ENTRY("254", NOOFCHANNELS) + IRC_MAP_ENTRY("263", TRYAGAIN) + IRC_MAP_ENTRY("264", WHOIS_OTHER) //Encryption info (SSL connect) + IRC_MAP_ENTRY("301", WHOIS_AWAY) + IRC_MAP_ENTRY("302", USERHOST_REPLY) + IRC_MAP_ENTRY("305", BACKFROMAWAY) + IRC_MAP_ENTRY("306", SETAWAY) + IRC_MAP_ENTRY("307", WHOIS_AUTH) + IRC_MAP_ENTRY("310", WHOIS_OTHER) + IRC_MAP_ENTRY("311", WHOIS_NAME) + IRC_MAP_ENTRY("312", WHOIS_SERVER) + IRC_MAP_ENTRY("313", WHOIS_OTHER) + IRC_MAP_ENTRY("315", WHO_END) + IRC_MAP_ENTRY("317", WHOIS_IDLE) + IRC_MAP_ENTRY("318", WHOIS_END) + IRC_MAP_ENTRY("319", WHOIS_CHANNELS) + IRC_MAP_ENTRY("320", WHOIS_AUTH) + IRC_MAP_ENTRY("321", LISTSTART) + IRC_MAP_ENTRY("322", LIST) + IRC_MAP_ENTRY("323", LISTEND) + IRC_MAP_ENTRY("324", MODEQUERY) + IRC_MAP_ENTRY("330", WHOIS_AUTH) + IRC_MAP_ENTRY("332", INITIALTOPIC) + IRC_MAP_ENTRY("333", INITIALTOPICNAME) + IRC_MAP_ENTRY("352", WHO_REPLY) + IRC_MAP_ENTRY("353", NAMES) + IRC_MAP_ENTRY("366", ENDNAMES) + IRC_MAP_ENTRY("367", BANLIST) + IRC_MAP_ENTRY("368", BANLISTEND) + IRC_MAP_ENTRY("346", BANLIST) + IRC_MAP_ENTRY("347", BANLISTEND) + IRC_MAP_ENTRY("348", BANLIST) + IRC_MAP_ENTRY("349", BANLISTEND) + IRC_MAP_ENTRY("371", WHOIS_OTHER) + IRC_MAP_ENTRY("376", ENDMOTD) + IRC_MAP_ENTRY("401", WHOIS_NO_USER) + IRC_MAP_ENTRY("403", JOINERROR) + IRC_MAP_ENTRY("416", WHOTOOLONG) + IRC_MAP_ENTRY("421", UNKNOWN) + IRC_MAP_ENTRY("422", ENDMOTD) + IRC_MAP_ENTRY("433", NICK_ERR) + IRC_MAP_ENTRY("471", JOINERROR) + IRC_MAP_ENTRY("473", JOINERROR) + IRC_MAP_ENTRY("474", JOINERROR) + IRC_MAP_ENTRY("475", JOINERROR) + IRC_MAP_ENTRY("671", WHOIS_OTHER) //Encryption info (SSL connect) +} + +CIrcProto::~CIrcProto() +{ + if ( con ) { + Netlib_CloseHandle( con ); + con = NULL; + } + + Netlib_CloseHandle(hNetlib); hNetlib = NULL; + Netlib_CloseHandle(hNetlibDCC); hNetlibDCC = NULL; + + m_dcc_chats.destroy(); + m_dcc_xfers.destroy(); + + DeleteCriticalSection( &cs ); + DeleteCriticalSection( &m_gchook ); + + if (hMenuRoot) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); + + mir_free( m_alias ); + mir_free( m_szModuleName ); + mir_free( m_tszUserName ); + + CloseHandle( m_evWndCreate ); + DeleteCriticalSection(&m_resolve); + DeleteCriticalSection(&m_dcc); + KillChatTimer(OnlineNotifTimer); + KillChatTimer(OnlineNotifTimer3); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoaded - performs hook registration + +static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + +static int sttCheckPerform( const char *szSetting, LPARAM lParam ) +{ + if ( !_strnicmp( szSetting, "PERFORM:", 8 )) { + String s = szSetting; + s.MakeUpper(); + if ( s != szSetting ) { + OBJLIST* p = ( OBJLIST* )lParam; + p->insert( new String( szSetting )); + } } + return 0; +} + +int CIrcProto::OnModulesLoaded( WPARAM, LPARAM ) +{ + char szTemp3[256]; + NETLIBUSER nlu = {0}; + TCHAR name[128]; + + DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); + + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; + nlu.szSettingsModule = m_szModuleName; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s server connection"), m_tszUserName); + nlu.ptszDescriptiveName = name; + hNetlib=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; + char szTemp2[256]; + mir_snprintf(szTemp2, sizeof(szTemp2), "%s DCC", m_szModuleName); + nlu.szSettingsModule = szTemp2; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s client-to-client connections"), m_tszUserName); + nlu.ptszDescriptiveName = name; + hNetlibDCC=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + //add as a known module in DB Editor ++ + CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)m_szModuleName,0); + mir_snprintf(szTemp3, sizeof(szTemp3), "%s DCC", m_szModuleName); + CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)szTemp3,0); + + if ( ServiceExists("MBot/GetFcnTable")) { + CallService( MS_MBOT_REGISTERIRC, 0, (LPARAM)m_szModuleName); + m_bMbotInstalled = TRUE; + } + + if ( ServiceExists( MS_GC_REGISTER )) { + GCREGISTER gcr = {0}; + gcr.cbSize = sizeof(GCREGISTER); + gcr.dwFlags = GC_CHANMGR | GC_BOLD | GC_ITALICS | GC_UNDERLINE | GC_COLOR | GC_BKGCOLOR | GC_TCHAR; + gcr.iMaxText = 0; + gcr.nColors = 16; + gcr.pColors = colors; + gcr.ptszModuleDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + CallServiceSync( MS_GC_REGISTER, NULL, (LPARAM)&gcr ); + IrcHookEvent( ME_GC_EVENT, &CIrcProto::GCEventHook ); + IrcHookEvent( ME_GC_BUILDMENU, &CIrcProto::GCMenuHook ); + + GCSESSION gcw = {0}; + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gcw.cbSize = sizeof(GCSESSION); + gcw.dwFlags = GC_TCHAR; + gcw.iType = GCW_SERVER; + gcw.ptszID = SERVERWINDOW; + gcw.pszModule = m_szModuleName; + gcw.ptszName = NEWTSTR_ALLOCA(( TCHAR* )_A2T( m_network )); + CallServiceSync( MS_GC_NEWSESSION, 0, (LPARAM)&gcw ); + + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + + gce.pDest = &gcd; + if ( m_useServer && !m_hideServerWindow ) + CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); + else + CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); + bChatInstalled = TRUE; + } + else { + if ( IDYES == MessageBox(0,TranslateT("The IRC protocol depends on another plugin called \'Chat\'\n\nDo you want to download it from the Miranda NG web site now?"),TranslateT("Information"),MB_YESNO|MB_ICONINFORMATION )) + CallService( MS_UTILS_OPENURL, 1, (LPARAM) "http://miranda-ng.org/"); + } + + TCHAR szTemp[MAX_PATH]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_perform.ini"), m_szModuleName); + TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); + char* pszPerformData = IrcLoadFile( szLoadFileName ); + if ( pszPerformData != NULL ) { + char *p1 = pszPerformData, *p2 = pszPerformData; + while (( p1 = strstr( p2, "NETWORK: " )) != NULL ) { + p1 += 9; + p2 = strchr(p1, '\n'); + String sNetwork( p1, int( p2-p1-1 )); + sNetwork.MakeUpper(); + p1 = p2; + p2 = strstr( ++p1, "\nNETWORK: " ); + if ( !p2 ) + p2 = p1 + lstrlenA( p1 )-1; + if ( p1 == p2 ) + break; + + *p2++ = 0; + setString(("PERFORM:" + sNetwork).c_str(), rtrim( p1 )); + } + delete[] pszPerformData; + ::_tremove( szLoadFileName ); + } + mir_free( szLoadFileName ); + + if ( !getByte( "PerformConversionDone", 0 )) { + OBJLIST performToConvert( 10 ); + DBCONTACTENUMSETTINGS dbces; + dbces.pfnEnumProc = sttCheckPerform; + dbces.lParam = ( LPARAM )&performToConvert; + dbces.szModule = m_szModuleName; + CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); + + for ( int i = 0; i < performToConvert.getCount(); i++ ) { + String s = performToConvert[i]; + DBVARIANT dbv; + if ( !getTString( s, &dbv )) { + DBDeleteContactSetting( NULL, m_szModuleName, s ); + s.MakeUpper(); + setTString( s, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } } + + setByte( "PerformConversionDone", 1 ); + } + + InitIgnore(); + + IrcHookEvent( ME_USERINFO_INITIALISE, &CIrcProto::OnInitUserInfo ); + IrcHookEvent( ME_OPT_INITIALISE, &CIrcProto::OnInitOptionsPages ); + + if ( m_nick[0] ) { + TCHAR szBuf[ 40 ]; + if ( lstrlen( m_alternativeNick ) == 0 ) { + mir_sntprintf( szBuf, SIZEOF(szBuf), _T("%s%u"), m_nick, rand()%9999); + setTString("AlernativeNick", szBuf); + lstrcpyn(m_alternativeNick, szBuf, 30); + } + + if ( lstrlen( m_name ) == 0 ) { + mir_sntprintf( szBuf, SIZEOF(szBuf), _T("Miranda%u"), rand()%9999); + setTString("Name", szBuf); + lstrcpyn( m_name, szBuf, 200 ); + } } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AddToList - adds a contact to the contact list + +HANDLE __cdecl CIrcProto::AddToList( int, PROTOSEARCHRESULT* psr ) +{ + if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) + return 0; + + TCHAR *id = psr->id ? psr->id : psr->nick; + id = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)id) : mir_a2t((char*)id); + + CONTACT user = { id, NULL, NULL, true, false, false }; + HANDLE hContact = CList_AddContact( &user, true, false ); + + if ( hContact ) { + DBVARIANT dbv1; + CMString S = _T("S"); + + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) { + S += user.name; + DoUserhostWithReason( 1, S, true, user.name ); + } + else { + if ( !getTString(hContact, "UWildcard", &dbv1 )) { + S += dbv1.ptszVal; + DoUserhostWithReason(2, S, true, dbv1.ptszVal); + DBFreeVariant( &dbv1 ); + } + else { + S += user.name; + DoUserhostWithReason( 2, S, true, user.name ); + } + } + if (getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user.name); + } + + mir_free(id); + return hContact; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AddToList - adds a contact to the contact list + +HANDLE __cdecl CIrcProto::AddToListByEvent( int, int, HANDLE ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthAllow - processes the successful authorization + +int __cdecl CIrcProto::Authorize( HANDLE ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthDeny - handles the unsuccessful authorization + +int __cdecl CIrcProto::AuthDeny( HANDLE, const TCHAR* ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int __cdecl CIrcProto::AuthRecv( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int __cdecl CIrcProto::AuthRequest( HANDLE, const TCHAR* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// ChangeInfo + +HANDLE __cdecl CIrcProto::ChangeInfo( int, void* ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileAllow - starts a file transfer + +HANDLE __cdecl CIrcProto::FileAllow( HANDLE, HANDLE hTransfer, const TCHAR* szPath ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + if ( !IsConnected()) { + delete di; + return (HANDLE)szPath; + } + + di->sPath = szPath; + di->sFileAndPath = di->sPath + di->sFile; + + CDccSession* dcc = new CDccSession( this, di ); + AddDCCSession( di, dcc ); + dcc->Connect(); + return di; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileCancel - cancels a file transfer + +int __cdecl CIrcProto::FileCancel( HANDLE, HANDLE hTransfer ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + CDccSession* dcc = FindDCCSession(di); + if (dcc) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_CANCEL); + SetEvent(dcc->hEvent); + dcc->Disconnect(); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileDeny - denies a file transfer + +int __cdecl CIrcProto::FileDeny( HANDLE, HANDLE hTransfer, const TCHAR* ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + delete di; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileResume - processes file renaming etc + +int __cdecl CIrcProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + long i = (long)*action; + + CDccSession* dcc = FindDCCSession(di); + if (dcc) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, i); + if (*action == FILERESUME_RENAME) { + TCHAR* szTemp = _tcsdup(*szFilename); + InterlockedExchangePointer((PVOID*)&dcc->NewFileName, szTemp); + } + + if (*action == FILERESUME_RESUME) { + unsigned __int64 dwPos = 0; + + struct _stati64 statbuf; + if (_tstati64(di->sFileAndPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) + dwPos = statbuf.st_size; + + CMString sFileWithQuotes = di->sFile; + + // if spaces in the filename surround witrh quotes + if (sFileWithQuotes.Find( ' ', 0 ) != -1 ) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + if (di->bReverse) + PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s 0 %I64u %s\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), dwPos, dcc->di->sToken.c_str()); + else + PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s %u %I64u\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), di->iPort, dwPos); + + return 0; + } + + SetEvent(dcc->hEvent); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +DWORD_PTR __cdecl CIrcProto::GetCaps( int type, HANDLE ) +{ + switch( type ) { + case PFLAGNUM_1: + return PF1_BASICSEARCH | PF1_MODEMSG | PF1_FILE | PF1_CHAT | PF1_CANRENAMEFILE | PF1_PEER2PEER | PF1_IM; + + case PFLAGNUM_2: + return PF2_ONLINE | PF2_SHORTAWAY; + + case PFLAGNUM_3: + return PF2_SHORTAWAY; + + case PFLAGNUM_4: + return PF4_NOAUTHDENYREASON | PF4_NOCUSTOMAUTH | PF4_IMSENDUTF; + + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR) Translate("Nickname"); + + case PFLAG_MAXLENOFMESSAGE: + return 400; + + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR) "Nick"; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetIcon - loads an icon for the contact list + +HICON __cdecl CIrcProto::GetIcon( int iconIndex ) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)GetIconHandle(IDI_MAIN); + + bool big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = LoadIconEx(IDI_MAIN, big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + HICON hIcon2 = CopyIcon(hIcon); + ReleaseIconEx(hIcon); + return hIcon2; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int __cdecl CIrcProto::GetInfo( HANDLE, int ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by JID + +struct AckBasicSearchParam +{ + PROTOCHAR buf[ 50 ]; +}; + +void __cdecl CIrcProto::AckBasicSearch( void* param ) +{ + PROTOSEARCHRESULT psr = { 0 }; + psr.cbSize = sizeof(psr); + psr.flags = PSR_TCHAR; + psr.id = (( AckBasicSearchParam* )param )->buf; + psr.nick = (( AckBasicSearchParam* )param )->buf; + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr); + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + delete param; +} + +HANDLE __cdecl CIrcProto::SearchBasic( const PROTOCHAR* szId ) +{ + if ( szId ) { + if (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && + szId && szId[0] && !IsChannel(szId)) { + AckBasicSearchParam* param = new AckBasicSearchParam; + lstrcpyn( param->buf, szId, 50 ); + ircFork( &CIrcProto::AckBasicSearch, param ); + return ( HANDLE )1; + } } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE __cdecl CIrcProto::SearchByEmail( const PROTOCHAR* ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// upsupported search functions + +HANDLE __cdecl CIrcProto::SearchByName( const PROTOCHAR*, const PROTOCHAR*, const PROTOCHAR* ) +{ + return NULL; +} + +HWND __cdecl CIrcProto::CreateExtendedSearchUI( HWND ) +{ + return NULL; +} + +HWND __cdecl CIrcProto::SearchAdvanced( HWND ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int __cdecl CIrcProto::RecvContacts( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvFile + +int __cdecl CIrcProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) +{ + return Proto_RecvFile(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +int __cdecl CIrcProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* evt ) +{ + return Proto_RecvMessage(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvUrl + +int __cdecl CIrcProto::RecvUrl( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int __cdecl CIrcProto::SendContacts( HANDLE, int, int, HANDLE* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE __cdecl CIrcProto::SendFile( HANDLE hContact, const TCHAR*, TCHAR** ppszFiles ) +{ + DCCINFO* dci = NULL; + int iPort = 0; + int index= 0; + unsigned __int64 size = 0; + + // do not send to channels :-P + if ( getByte(hContact, "ChatRoom", 0) != 0) + return 0; + + // stop if it is an active type filetransfer and the user's IP is not known + unsigned long ulAdr = 0; + if (m_manualHost) + ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); + else + ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); + + if (!m_DCCPassive && !ulAdr) { + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: Unable to automatically resolve external IP"), NULL, NULL, NULL, true, false); + return 0; + } + + if ( ppszFiles[index] ) { + + //get file size + while (ppszFiles[index]) { + struct _stati64 statbuf; + if (_tstati64(ppszFiles[index], &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) { + size = statbuf.st_size; + break; + } + index++; + } + + if (size == 0) { + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: No valid files specified"), NULL, NULL, NULL, true, false); + return 0; + } + + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + // set up a basic DCCINFO struct and pass it to a DCC object + dci = new DCCINFO; + dci->sFileAndPath = ppszFiles[index]; + + int i = dci->sFileAndPath.ReverseFind( '\\' ); + if (i != -1) { + dci->sPath = dci->sFileAndPath.Mid(0, i+1); + dci->sFile = dci->sFileAndPath.Mid(i+1, dci->sFileAndPath.GetLength()); + } + + CMString sFileWithQuotes = dci->sFile; + + // if spaces in the filename surround witrh quotes + if ( sFileWithQuotes.Find( ' ', 0 ) != -1) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + dci->hContact = hContact; + dci->sContactName = dbv.ptszVal; + dci->iType = DCC_SEND; + dci->bReverse = m_DCCPassive?true:false; + dci->bSender = true; + dci->dwSize = size; + + // create new dcc object + CDccSession* dcc = new CDccSession(this,dci); + + // keep track of all objects created + AddDCCSession(dci, dcc); + + // need to make sure that %'s are doubled to avoid having chat interpret as color codes + CMString sFileCorrect = dci->sFile; + ReplaceString(sFileCorrect, _T("%"), _T("%%")); + + // is it an reverse filetransfer (receiver acts as server) + if (dci->bReverse) { + TCHAR szTemp[256]; + PostIrcMessage( _T("/CTCP %s DCC SEND %s 200 0 %I64u %u"), + dci->sContactName.c_str(), sFileWithQuotes.c_str(), dci->dwSize, dcc->iToken); + + mir_sntprintf(szTemp, SIZEOF(szTemp), + TranslateT("DCC reversed file transfer request sent to %s [%s]"), + dci->sContactName.c_str(), sFileCorrect.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + + if (m_sendNotice) { + mir_sntprintf(szTemp, SIZEOF(szTemp), + _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [Reverse transfer]"), + dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024); + PostIrcMessage(szTemp); + } + } + else { // ... normal filetransfer. + iPort = dcc->Connect(); + if ( iPort ) { + TCHAR szTemp[256]; + PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u"), + dci->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, iPort, dci->dwSize); + + mir_sntprintf(szTemp, SIZEOF(szTemp), + TranslateT("DCC file transfer request sent to %s [%s]"), + dci->sContactName.c_str(), sFileCorrect.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + + if ( m_sendNotice ) { + mir_sntprintf(szTemp, SIZEOF(szTemp), + _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [IP: %s]"), + dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024, (TCHAR*)_A2T(ConvertIntegerToIP(ulAdr))); + PostIrcMessage(szTemp); + } + } + else DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), + TranslateT("DCC ERROR: Unable to bind local port"), NULL, NULL, NULL, true, false); + } + + // fix for sending multiple files + index++; + while( ppszFiles[index] ) { + if ( _taccess(ppszFiles[index], 0) == 0 ) { + PostIrcMessage( _T("/DCC SEND %s ") _T(TCHAR_STR_PARAM), dci->sContactName.c_str(), ppszFiles[index]); + } + index++; + } + + DBFreeVariant( &dbv ); + } } + + if (dci) + return dci; + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendMessage - sends a message + +void __cdecl CIrcProto::AckMessageFail( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The protocol is not online")); +} + +void __cdecl CIrcProto::AckMessageFailDcc( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The dcc chat connection is not active")); +} + +void __cdecl CIrcProto::AckMessageSuccess( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0); +} + +int __cdecl CIrcProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) +{ + BYTE bDcc = getByte( hContact, "DCC", 0) ; + WORD wStatus = getWord( hContact, "Status", ID_STATUS_OFFLINE) ; + if ( m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && !bDcc || bDcc && wStatus == ID_STATUS_ONLINE ) { + int codepage = getCodepage(); + + TCHAR* result; + if ( flags & PREF_UNICODE ) { + const char* p = strchr( pszSrc, '\0' ); + if ( p != pszSrc ) { + while ( *(++p) == '\0' ) + ; + result = mir_u2t_cp(( wchar_t* )p, codepage ); + } + else result = mir_a2t_cp( pszSrc, codepage ); + } + else if ( flags & PREF_UTF ) { + mir_utf8decode( NEWSTR_ALLOCA(pszSrc), &result ); + } + else result = mir_a2t_cp( pszSrc, codepage ); + + PostIrcMessageWnd(NULL, hContact, result ); + mir_free( result ); + ircFork( &CIrcProto::AckMessageSuccess, hContact ); + } + else { + if ( bDcc ) + ircFork( &CIrcProto::AckMessageFailDcc, hContact ); + else + ircFork( &CIrcProto::AckMessageFail, hContact ); + } + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int __cdecl CIrcProto::SendUrl( HANDLE, int, const char* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetApparentMode - sets the visibility status + +int __cdecl CIrcProto::SetApparentMode( HANDLE, int ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetStatus - sets the protocol status + +int __cdecl CIrcProto::SetStatus( int iNewStatus ) +{ + return SetStatusInternal( iNewStatus, false ); +} + +int CIrcProto::SetStatusInternal( int iNewStatus, bool bIsInternal ) +{ + if ( !bChatInstalled ) + return 0; + + if ( iNewStatus != ID_STATUS_OFFLINE && !m_network[0] ) { + if (m_nick[0] && !m_disableDefaultServer) { + CQuickDlg* dlg = new CQuickDlg( this ); + dlg->GetProto()->m_quickComboSelection = dlg->GetProto()->m_serverComboSelection + 1; + dlg->Show(); + HWND hwnd = dlg->GetHwnd(); + SetWindowTextA(hwnd, "Miranda IRC"); + SetWindowText(GetDlgItem(hwnd, IDC_TEXT), TranslateT("Please choose an IRC-network to go online. This network will be the default.")); + SetWindowText(GetDlgItem(hwnd, IDC_CAPTION), TranslateT("Default network")); + WindowSetIcon(hwnd, IDI_MAIN); + ShowWindow(hwnd, SW_SHOW); + SetActiveWindow(hwnd); + } + return 0; + } + + if ( iNewStatus != ID_STATUS_OFFLINE && !m_nick[0] || !m_userID[0] || !m_name[0]) { + MIRANDASYSTRAYNOTIFY msn; + msn.cbSize = sizeof( MIRANDASYSTRAYNOTIFY ); + msn.szProto = m_szModuleName; + msn.tszInfoTitle = TranslateT( "IRC error" ); + msn.tszInfo = TranslateT( "Connection can not be established! You have not completed all necessary fields (Nickname, User ID and m_name)." ); + msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; + msn.uTimeout = 15000; + CallService( MS_CLIST_SYSTRAY_NOTIFY, (WPARAM)NULL,(LPARAM) &msn); + return 0; + } + + if ( !bIsInternal ) + m_iDesiredStatus = iNewStatus; + + if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_AWAY || iNewStatus == ID_STATUS_FREECHAT) && !IsConnected()) //go from offline to online + { + if (!m_bConnectThreadRunning) + ConnectToServer(); + } + else if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_FREECHAT) && IsConnected() && m_iStatus == ID_STATUS_AWAY) //go to online while connected + { + m_statusMessage = _T(""); + PostIrcMessage( _T("/AWAY")); + return 0; + } + else if ( iNewStatus == ID_STATUS_OFFLINE && IsConnected()) //go from online/away to offline + DisconnectFromServer(); + else if ( iNewStatus == ID_STATUS_OFFLINE && !IsConnected()) //offline to offline + { + KillChatTimer( RetryTimer); + return 0; + } + else if ( iNewStatus == ID_STATUS_AWAY && IsConnected()) //go to away while connected + { + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + return 0; + } + else if ( iNewStatus == ID_STATUS_ONLINE && IsConnected()) //already online + return 0; + else + SetStatusInternal(ID_STATUS_AWAY, true); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetAwayMsg - returns a contact's away message + +HANDLE __cdecl CIrcProto::GetAwayMsg( HANDLE hContact ) +{ + WhoisAwayReply = _T(""); + DBVARIANT dbv; + + // bypass chat contacts. + if ( getByte( hContact, "ChatRoom", 0 ) == 0) { + if ( hContact && !getTString( hContact, "Nick", &dbv)) { + int i = getWord( hContact, "Status", ID_STATUS_OFFLINE ); + if ( i != ID_STATUS_AWAY) { + DBFreeVariant( &dbv); + return 0; + } + CMString S = _T("WHOIS "); + S += dbv.ptszVal; + if (IsConnected()) + SendIrcMessage( S.c_str(), false); + DBFreeVariant( &dbv); + } } + + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG + +int __cdecl CIrcProto::RecvAwayMsg( HANDLE, int, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AWAYMSG + +int __cdecl CIrcProto::SendAwayMsg( HANDLE, HANDLE, const char* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetAwayMsg - sets the away status message + +int __cdecl CIrcProto::SetAwayMsg( int status, const TCHAR* msg ) +{ + switch( status ) { + case ID_STATUS_ONLINE: case ID_STATUS_INVISIBLE: case ID_STATUS_FREECHAT: + case ID_STATUS_CONNECTING: case ID_STATUS_OFFLINE: + break; + + default: + CMString newStatus = msg; + ReplaceString( newStatus, _T("\r\n"), _T(" ")); + if ( m_statusMessage.IsEmpty() || msg == NULL || m_statusMessage != newStatus ) { + if ( msg == NULL || *msg == 0 ) + m_statusMessage = _T(STR_AWAYMESSAGE); + else + m_statusMessage = newStatus; + + if ( m_iStatus == ID_STATUS_AWAY ) + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + } } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// UserIsTyping - sends a UTN notification + +int __cdecl CIrcProto::UserIsTyping( HANDLE, int ) +{ + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnEvent - maintain protocol events + +int __cdecl CIrcProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ) +{ + switch( eventType ) { + case EV_PROTO_ONLOAD: return OnModulesLoaded( 0, 0 ); + case EV_PROTO_ONEXIT: return OnPreShutdown( 0, 0 ); + case EV_PROTO_ONOPTIONS: return OnInitOptionsPages( wParam, lParam ); + + case EV_PROTO_ONMENU: + InitMainMenus(); + break; + + case EV_PROTO_ONRENAME: + if ( hMenuRoot ) { + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + clmi.ptszName = m_tszUserName; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuRoot, ( LPARAM )&clmi ); + } + break; + + case EV_PROTO_ONCONTACTDELETED: + return OnContactDeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return OnDbSettingChanged(wParam, lParam); + } + return 1; +} diff --git a/protocols/IRCG/src/main.cpp b/protocols/IRCG/src/main.cpp new file mode 100644 index 0000000000..ea802d43cd --- /dev/null +++ b/protocols/IRCG/src/main.cpp @@ -0,0 +1,122 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" +#include "version.h" + +HINSTANCE hInst = NULL; + +int hLangpack; + +static int CompareServers( const SERVER_INFO* p1, const SERVER_INFO* p2 ) +{ + return lstrcmpA( p1->m_name, p2->m_name ); +} + +OBJLIST g_servers( 20, CompareServers ); + +static int sttCompareProtocols(const CIrcProto *p1, const CIrcProto *p2) +{ + return strcmp(p1->m_szModuleName, p2->m_szModuleName); +} + +LIST g_Instances(1, sttCompareProtocols); + +void InitTimers( void ); +void UninitTimers( void ); + +// Information about the plugin +PLUGININFOEX pluginInfo = +{ + sizeof( PLUGININFOEX ), + __PLUGIN_NAME, + __VERSION_DWORD, + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + {0x92382b4d, 0x5572, 0x48a0, {0xb0, 0xb9, 0x13, 0x36, 0xa6, 0x1, 0xd6, 0x89}} // {92382B4D-5572-48a0-B0B9-1336A601D689} +}; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD, LPVOID) +{ + hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static CIrcProto* ircProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) +{ + CIrcProto* ppro = new CIrcProto( pszProtoName, tszUserName ); + g_Instances.insert( ppro ); + return ppro; +} + +static int ircProtoUninit( CIrcProto* ppro ) +{ + g_Instances.remove(( CIrcProto* )ppro); + delete ppro; + return 0; +} + +extern "C" int __declspec(dllexport) Load( ) +{ + + mir_getLP( &pluginInfo ); + + AddIcons(); + InitTimers(); + InitServers(); + InitContactMenus(); + + // register protocol + PROTOCOLDESCRIPTOR pd = { 0 }; + pd.cbSize = sizeof( pd ); + pd.szName = "IRC"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = ( pfnInitProto )ircProtoInit; + pd.fnUninit = ( pfnUninitProto )ircProtoUninit; + CallService( MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd ); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" int __declspec(dllexport) Unload(void) +{ + UninitContactMenus(); + UninitIcons(); + UninitTimers(); + + g_Instances.destroy(); + + return 0; +} diff --git a/protocols/IRCG/src/options.cpp b/protocols/IRCG/src/options.cpp new file mode 100644 index 0000000000..69a991374b --- /dev/null +++ b/protocols/IRCG/src/options.cpp @@ -0,0 +1,1962 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" +#include + +#include "ui_utils.h" + +static WNDPROC OldProc; +static WNDPROC OldListViewProc; + +static HANDLE* hIconLibItems; + +static const CIrcProto* pZero = NULL; + +void CIrcProto::ReadSettings( TDbSetting* sets, int count ) +{ + BYTE* base = ( BYTE* )this; + + DBVARIANT dbv; + for ( int i=0; i < count; i++ ) { + TDbSetting* p = &sets[i]; + BYTE* ptr = base + p->offset; + switch( p->type ) { + case DBVT_BYTE: + *( BYTE* )ptr = getByte( p->name, p->defValue ); + break; + case DBVT_WORD: + *( WORD* )ptr = getWord( p->name, p->defValue ); + break; + case DBVT_DWORD: + *( DWORD* )ptr = getDword( p->name, p->defValue ); + break; + case DBVT_ASCIIZ: + if ( !getString( p->name, &dbv )) { + if ( p->size != -1 ) { + size_t len = min( p->size-1, strlen( dbv.pszVal )); + memcpy( ptr, dbv.pszVal, len ); + ptr[len] = 0; + } + else *( char** )ptr = mir_strdup( dbv.pszVal ); + DBFreeVariant( &dbv ); + } + else { + if ( p->size != -1 ) + *ptr = 0; + else + *( char** )ptr = NULL; + } + break; + case DBVT_TCHAR: + if ( !getTString( p->name, &dbv )) { + if ( p->size != -1 ) { + size_t len = min( p->size-1, _tcslen( dbv.ptszVal )); + memcpy( ptr, dbv.pszVal, len*sizeof(TCHAR)); + *( TCHAR* )&ptr[len*sizeof(TCHAR)] = 0; + } + else *( TCHAR** )ptr = mir_tstrdup( dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + else { + if ( p->size != -1 ) { + if ( p->defStr == NULL ) + *ptr = 0; + else + lstrcpyn(( TCHAR* )ptr, p->defStr, (int)p->size ); + } + else *( TCHAR** )ptr = mir_tstrdup( p->defStr ); + } + break; +} } } + +void CIrcProto::WriteSettings( TDbSetting* sets, int count ) +{ + BYTE* base = ( BYTE* )this; + + for ( int i=0; i < count; i++ ) { + TDbSetting* p = &sets[i]; + BYTE* ptr = base + p->offset; + switch( p->type ) { + case DBVT_BYTE: setByte( p->name, *( BYTE* )ptr ); break; + case DBVT_WORD: setWord( p->name, *( WORD* )ptr ); break; + case DBVT_DWORD: setDword( p->name, *( DWORD* )ptr ); break; + + case DBVT_ASCIIZ: + if ( p->size == -1 ) + setString( p->name, *(char**)ptr ); + else + setString( p->name, (char*)ptr ); + break; + + case DBVT_TCHAR: + if ( p->size == -1 ) + setTString( p->name, *(TCHAR**)ptr ); + else + setTString( p->name, (TCHAR*)ptr ); + break; +} } } + +///////////////////////////////////////////////////////////////////////////////////////// + +static int sttServerEnum( const char* szSetting, LPARAM ) +{ + DBVARIANT dbv; + if ( DBGetContactSettingString( NULL, SERVERSMODULE, szSetting, &dbv )) + return 0; + + SERVER_INFO* pData = new SERVER_INFO; + pData->m_name = mir_strdup( szSetting ); + + char* p1 = strchr( dbv.pszVal, ':' )+1; + pData->m_iSSL = 0; + if ( !_strnicmp( p1, "SSL", 3 )) { + p1 +=3; + if ( *p1 == '1' ) + pData->m_iSSL = 1; + else if ( *p1 == '2' ) + pData->m_iSSL = 2; + p1++; + } + char* p2 = strchr(p1, ':'); + pData->m_address = ( char* )mir_alloc( p2-p1+1 ); + lstrcpynA( pData->m_address, p1, p2-p1+1 ); + + p1 = p2+1; + while (*p2 !='G' && *p2 != '-') + p2++; + + char* buf = ( char* )alloca( p2-p1+1 ); + lstrcpynA( buf, p1, p2-p1+1 ); + pData->m_portStart = atoi( buf ); + + if ( *p2 == 'G' ) + pData->m_portEnd = pData->m_portStart; + else { + p1 = p2+1; + p2 = strchr(p1, 'G'); + buf = ( char* )alloca( p2-p1+1 ); + lstrcpynA( buf, p1, p2-p1+1 ); + pData->m_portEnd = atoi( buf ); + } + + p1 = strchr(p2, ':')+1; + p2 = strchr(p1, '\0'); + pData->m_group = ( char* )mir_alloc( p2-p1+1 ); + lstrcpynA( pData->m_group, p1, p2-p1+1 ); + + g_servers.insert( pData ); + DBFreeVariant( &dbv ); + return 0; +} + +void RereadServers() +{ + g_servers.destroy(); + + DBCONTACTENUMSETTINGS dbces; + dbces.pfnEnumProc = sttServerEnum; + dbces.szModule = SERVERSMODULE; + CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void removeSpaces( TCHAR* p ) +{ + while ( *p ) { + if ( *p == ' ' ) + memmove( p, p+1, sizeof(TCHAR)*lstrlen(p)); + p++; +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// add icons to the skinning module + +struct +{ + char* szDescr; + char* szName; + int iSize; + int defIconID; +} +static iconList[] = +{ + { LPGEN("Main"), "main", 0, IDI_MAIN }, + { LPGEN("Add"), "add", 0, IDI_ADD }, + { LPGEN("Apply"), "apply", 0, IDI_APPLY }, + { LPGEN("Rename"), "rename", 0, IDI_RENAME }, + { LPGEN("Edit"), "edit", 0, IDI_EDIT }, + { LPGEN("Cancel"), "delete", 0, IDI_DELETE }, + { LPGEN("Ignore"), "block", 0, IDI_BLOCK }, + { LPGEN("Channel list"), "list", 0, IDI_LIST }, + { LPGEN("Channel manager"), "manager", 0, IDI_MANAGER }, + { LPGEN("Quick connect"), "quick", 0, IDI_QUICK }, + { LPGEN("Server window"), "server", 0, IDI_SERVER }, + { LPGEN("Show channel"), "show", 0, IDI_SHOW }, + { LPGEN("Question"), "question", 0, IDI_IRCQUESTION}, + { LPGEN("WhoIs"), "whois", 0, IDI_WHOIS }, + { LPGEN("Incoming DCC Chat"), "dcc", 0, IDI_DCC }, + { LPGEN("Logo (48x48)"), "logo", 48, IDI_LOGO } +}; + +void AddIcons(void) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(hInst, szFile, MAX_PATH); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.pszSection = "Protocols/IRC"; + sid.ptszDefaultFile = szFile; + sid.flags = SIDF_PATH_TCHAR; + hIconLibItems = new HANDLE[ SIZEOF(iconList) ]; + + // add them one by one + for ( int i=0; i < SIZEOF(iconList); i++ ) { + char szTemp[255]; + mir_snprintf(szTemp, sizeof(szTemp), "IRC_%s", iconList[i].szName ); + sid.pszName = szTemp; + sid.pszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + sid.cx = sid.cy = iconList[i].iSize; + hIconLibItems[i] = Skin_AddIcon(&sid ); + } +} + +void UninitIcons(void) +{ + delete[] hIconLibItems; +} + +HICON LoadIconEx( int iconId, bool big ) +{ + for ( int i=0; i < SIZEOF(iconList); i++ ) + if ( iconList[i].defIconID == iconId ) + return ( HICON )CallService( MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)hIconLibItems[i] ); + + return NULL; +} + +HANDLE GetIconHandle( int iconId ) +{ + for ( int i=0; i < SIZEOF(iconList); i++ ) + if ( iconList[i].defIconID == iconId ) + return hIconLibItems[i]; + + return NULL; +} + +void ReleaseIconEx( HICON hIcon ) +{ + if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +void WindowSetIcon( HWND hWnd, int iconId ) +{ + SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadIconEx( iconId, true )); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadIconEx( iconId )); +} + +void WindowFreeIcon( HWND hWnd ) +{ + ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0)); + ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0)); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// code page handler + +struct { UINT cpId; TCHAR *cpName; } static cpTable[] = +{ + { 874, LPGENT("Thai") }, + { 932, LPGENT("Japanese") }, + { 936, LPGENT("Simplified Chinese") }, + { 949, LPGENT("Korean") }, + { 950, LPGENT("Traditional Chinese") }, + { 1250, LPGENT("Central European") }, + { 1251, LPGENT("Cyrillic (Windows)") }, + { 20866, LPGENT("Cyrillic (KOI8R)") }, + { 1252, LPGENT("Latin I") }, + { 1253, LPGENT("Greek") }, + { 1254, LPGENT("Turkish") }, + { 1255, LPGENT("Hebrew") }, + { 1256, LPGENT("Arabic") }, + { 1257, LPGENT("Baltic") }, + { 1258, LPGENT("Vietnamese") }, + { 1361, LPGENT("Korean (Johab)") } +}; + +static CCtrlCombo* sttCombo; + +typedef BOOL ( WINAPI *pfnGetCPInfoEx )( UINT, DWORD, LPCPINFOEX ); +static pfnGetCPInfoEx fnGetCPInfoEx = NULL; + +static BOOL CALLBACK sttLangAddCallback( CHAR* str ) +{ + UINT cp = atoi(str); + if ( fnGetCPInfoEx == NULL ) { + int i; + for ( i=0; i < SIZEOF(cpTable) && cpTable[i].cpId != cp; i++ ); + if ( i < SIZEOF(cpTable)) + sttCombo->AddString( TranslateTS( cpTable[i].cpName ), cp ); + } + else { + CPINFOEX cpinfo; + if ( fnGetCPInfoEx( cp, 0, &cpinfo )) { + TCHAR* b = _tcschr( cpinfo.CodePageName, '(' ); + if ( b ) { + TCHAR* e = _tcsrchr( cpinfo.CodePageName, ')' ); + if ( e ) { + *e = 0; + sttCombo->AddString( b+1, cp ); + } + else sttCombo->AddString( cpinfo.CodePageName, cp ); + } + else sttCombo->AddString( cpinfo.CodePageName, cp ); + } } + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Add server' dialog + +static int sttRequiredFields[] = { IDC_ADD_SERVER, IDC_ADD_ADDRESS, IDC_ADD_PORT, IDC_ADD_PORT2, IDC_ADD_COMBO }; + +struct CServerDlg : public CProtoDlgBase +{ + CConnectPrefsDlg* m_owner; + int m_action; + + CCtrlButton m_OK; + CCtrlEdit m_server, m_address, m_port, m_port2; + CCtrlCombo m_groupCombo; + + CServerDlg( CIrcProto* _pro, CConnectPrefsDlg* _owner, int _action ) : + CProtoDlgBase( _pro, IDD_ADDSERVER, _owner->GetHwnd()), + m_owner( _owner ), + m_action( _action ), + m_OK( this, IDOK ), + m_groupCombo( this, IDC_ADD_COMBO ), + m_address( this, IDC_ADD_ADDRESS ), + m_server( this, IDC_ADD_SERVER ), + m_port( this, IDC_ADD_PORT ), + m_port2( this, IDC_ADD_PORT2 ) + { + m_OK.OnClick = Callback( this, &CServerDlg::OnOk ); + m_autoClose = CLOSE_ON_CANCEL; + } + + virtual void OnInitDialog() + { + int i = m_owner->m_serverCombo.GetCount(); + for ( int index = 0; index < i; index++ ) { + SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( index ); + if ( m_groupCombo.FindStringA( pData->m_group, -1, true ) == CB_ERR ) + m_groupCombo.AddStringA( pData->m_group ); + } + + if ( m_action == 2 ) { + int j = m_owner->m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( j ); + m_address.SetTextA( pData->m_address ); + m_groupCombo.SetTextA( pData->m_group ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + + char* p = strstr( pData->m_name, ": "); + if ( p ) + m_server.SetTextA( p+2 ); + + if ( pData->m_iSSL == 0 ) + CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED ); + if ( pData->m_iSSL == 1 ) + CheckDlgButton( m_hwnd, IDC_AUTO, BST_CHECKED ); + if ( pData->m_iSSL == 2 ) + CheckDlgButton( m_hwnd, IDC_ON, BST_CHECKED ); + } + else { + CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED); + m_port.SetInt( 6667 ); + m_port2.SetInt( 6667 ); + } + + int bEnableSsl = TRUE; + EnableWindow(GetDlgItem( m_hwnd, IDC_ON), bEnableSsl ); + EnableWindow(GetDlgItem( m_hwnd, IDC_OFF), bEnableSsl ); + EnableWindow(GetDlgItem( m_hwnd, IDC_AUTO), bEnableSsl ); + + SetFocus( m_groupCombo.GetHwnd()); + } + + virtual void OnClose() + { + m_owner->m_serverCombo.Enable(); + m_owner->m_add.Enable(); + m_owner->m_edit.Enable(); + m_owner->m_del.Enable(); + } + + void OnOk( CCtrlButton* ) + { + for ( int k = 0; k < SIZEOF(sttRequiredFields); k++ ) + if ( !GetWindowTextLength( GetDlgItem( m_hwnd, sttRequiredFields[k] ))) { + MessageBox( m_hwnd, TranslateT("Please complete all fields"), TranslateT("IRC error"), MB_OK | MB_ICONERROR ); + return; + } + + if ( m_action == 2 ) { + int i = m_owner->m_serverCombo.GetCurSel(); + m_owner->m_serverCombo.DeleteString( i ); + } + + SERVER_INFO* pData = new SERVER_INFO; + pData->m_iSSL = 0; + if(IsDlgButtonChecked( m_hwnd, IDC_ON)) + pData->m_iSSL = 2; + if(IsDlgButtonChecked( m_hwnd, IDC_AUTO)) + pData->m_iSSL = 1; + + pData->m_portStart = m_port.GetInt(); + pData->m_portEnd = m_port2.GetInt(); + pData->m_address = rtrim(m_address.GetTextA()); + pData->m_group = m_groupCombo.GetTextA(); + pData->m_name = m_server.GetTextA(); + + char temp[255]; + mir_snprintf( temp, sizeof(temp), "%s: %s", pData->m_group, pData->m_name ); + mir_free( pData->m_name ); + pData->m_name = mir_strdup( temp ); + + int iItem = m_owner->m_serverCombo.AddStringA( pData->m_name, ( LPARAM )pData ); + m_owner->m_serverCombo.SetCurSel( iItem ); + m_owner->OnServerCombo( NULL ); + + m_owner->m_serverlistModified = true; + Close(); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Connect preferences' dialog + +static TDbSetting ConnectSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_userID), "UserID", DBVT_TCHAR, SIZEOF(pZero->m_userID) }, + { FIELD_OFFSET(CIrcProto, m_identSystem), "IdentSystem", DBVT_TCHAR, SIZEOF(pZero->m_identSystem) }, + { FIELD_OFFSET(CIrcProto, m_identPort), "IdentPort", DBVT_TCHAR, SIZEOF(pZero->m_identPort) }, + { FIELD_OFFSET(CIrcProto, m_retryWait), "RetryWait", DBVT_TCHAR, SIZEOF(pZero->m_retryWait) }, + { FIELD_OFFSET(CIrcProto, m_retryCount), "RetryCount", DBVT_TCHAR, SIZEOF(pZero->m_retryCount) }, + + { FIELD_OFFSET(CIrcProto, m_serverName ), "ServerName", DBVT_ASCIIZ, SIZEOF(pZero->m_serverName) }, + { FIELD_OFFSET(CIrcProto, m_portStart ), "PortStart", DBVT_ASCIIZ, SIZEOF(pZero->m_portStart) }, + { FIELD_OFFSET(CIrcProto, m_portEnd ), "PortEnd", DBVT_ASCIIZ, SIZEOF(pZero->m_portEnd ) }, + { FIELD_OFFSET(CIrcProto, m_password ), "Password", DBVT_ASCIIZ, SIZEOF(pZero->m_password ) }, + { FIELD_OFFSET(CIrcProto, m_joinOnInvite ), "JoinOnInvite", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_network ), "Network", DBVT_ASCIIZ, SIZEOF(pZero->m_network ) }, + { FIELD_OFFSET(CIrcProto, m_iSSL ), "UseSSL", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_onlineNotificationTime) , "OnlineNotificationTime", DBVT_WORD, 0, 30 }, + { FIELD_OFFSET(CIrcProto, m_onlineNotificationLimit) , "OnlineNotificationLimit", DBVT_WORD, 0, 50 }, + { FIELD_OFFSET(CIrcProto, m_channelAwayNotification), "ChannelAwayNotification", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_nick), "Nick", DBVT_TCHAR, SIZEOF(pZero->m_nick) }, + { FIELD_OFFSET(CIrcProto, m_pNick), "PNick", DBVT_TCHAR, SIZEOF(pZero->m_pNick) }, + { FIELD_OFFSET(CIrcProto, m_alternativeNick), "AlernativeNick", DBVT_TCHAR, SIZEOF(pZero->m_alternativeNick) }, + { FIELD_OFFSET(CIrcProto, m_name), "Name", DBVT_TCHAR, SIZEOF(pZero->m_name) }, + { FIELD_OFFSET(CIrcProto, m_disableDefaultServer), "DisableDefaultServer", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_ident), "Ident", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_identTimer), "IdentTimer", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_forceVisible), "ForceVisible", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_disableErrorPopups), "DisableErrorPopups", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_rejoinChannels), "RejoinChannels", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_rejoinIfKicked), "RejoinIfKicked", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_retry), "Retry", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_showAddresses), "ShowAddresses", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_oldStyleModes), "OldStyleModes", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_useServer), "UseServer", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_hideServerWindow), "HideServerWindow", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_serverComboSelection), "ServerComboSelection", DBVT_DWORD, 0 }, + { FIELD_OFFSET(CIrcProto, m_sendKeepAlive), "SendKeepAlive", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_autoOnlineNotification), "AutoOnlineNotification", DBVT_BYTE }, +}; + +CConnectPrefsDlg::CConnectPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_CONNECT, NULL ), + m_serverCombo( this, IDC_SERVERCOMBO ), + m_server( this, IDC_SERVER ), + m_port( this, IDC_PORT ), + m_port2( this, IDC_PORT2 ), + m_pass( this, IDC_PASS ), + m_add( this, IDC_ADDSERVER, LoadIconEx(IDI_ADD), LPGEN("Add a new network")), + m_edit( this, IDC_EDITSERVER, LoadIconEx(IDI_EDIT), LPGEN("Edit this network")), + m_del( this, IDC_DELETESERVER, LoadIconEx(IDI_DELETE), LPGEN("Delete this network")), + m_nick( this, IDC_NICK ), + m_nick2( this, IDC_NICK2 ), + m_name( this, IDC_NAME ), + m_userID( this, IDC_USERID ), + m_ident( this, IDC_IDENT ), + m_identSystem( this, IDC_IDENTSYSTEM ), + m_identPort( this, IDC_IDENTPORT ), + m_identTimer( this, IDC_IDENT_TIMED ), + m_retry( this, IDC_RETRY ), + m_retryWait( this, IDC_RETRYWAIT ), + m_retryCount( this, IDC_RETRYCOUNT ), + m_forceVisible( this, IDC_FORCEVISIBLE ), + m_rejoinOnKick( this, IDC_REJOINONKICK ), + m_rejoinChannels( this, IDC_REJOINCHANNELS ), + m_disableError( this, IDC_DISABLEERROR ), + m_address( this, IDC_ADDRESS ), + m_useServer( this, IDC_USESERVER ), + m_showServer( this, IDC_SHOWSERVER ), + m_keepAlive( this, IDC_KEEPALIVE ), + m_autoJoin( this, IDC_AUTOJOIN ), + m_oldStyle( this, IDC_OLDSTYLE ), + m_onlineNotif( this, IDC_ONLINENOTIF ), + m_channelAway( this, IDC_CHANNELAWAY ), + m_enableServer( this, IDC_STARTUP ), + m_onlineTimer( this, IDC_ONLINETIMER ), + m_limit( this, IDC_LIMIT ), + m_spin1( this, IDC_SPIN1 ), + m_spin2( this, IDC_SPIN2 ), + m_ssl( this, IDC_SSL ), + m_serverlistModified( false ) +{ + m_serverCombo.OnChange = Callback( this, &CConnectPrefsDlg::OnServerCombo ); + m_add.OnClick = Callback( this, &CConnectPrefsDlg::OnAddServer ); + m_del.OnClick = Callback( this, &CConnectPrefsDlg::OnDeleteServer ); + m_edit.OnClick = Callback( this, &CConnectPrefsDlg::OnEditServer ); + m_enableServer.OnChange = Callback( this, &CConnectPrefsDlg::OnStartup ); + m_ident.OnChange = Callback( this, &CConnectPrefsDlg::OnIdent ); + m_useServer.OnChange = Callback( this, &CConnectPrefsDlg::OnUseServer ); + m_onlineNotif.OnChange = Callback( this, &CConnectPrefsDlg::OnOnlineNotif ); + m_channelAway.OnChange = Callback( this, &CConnectPrefsDlg::OnChannelAway ); + m_retry.OnChange = Callback( this, &CConnectPrefsDlg::OnRetry ); +} + +void CConnectPrefsDlg::OnInitDialog() +{ + m_proto->m_hwndConnect = m_hwnd; + + // Fill the servers combo box and create SERVER_INFO structures + for ( int i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); + } + + m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); + m_server.SetTextA( m_proto->m_serverName ); + m_port.SetTextA( m_proto->m_portStart ); + m_port2.SetTextA( m_proto->m_portEnd ); + + if ( m_proto->m_iSSL == 0 ) + m_ssl.SetText( TranslateT( "Off" )); + if ( m_proto->m_iSSL == 1 ) + m_ssl.SetText( TranslateT( "Auto" )); + if ( m_proto->m_iSSL == 2 ) + m_ssl.SetText( TranslateT( "On" )); + + if ( m_proto->m_serverComboSelection != -1 ) { + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( m_proto->m_serverComboSelection ); + if ((INT_PTR)pData != CB_ERR) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + } } + + m_spin1.SendMsg( UDM_SETRANGE,0,MAKELONG(999,20)); + m_spin1.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationTime,0)); + m_spin2.SendMsg( UDM_SETRANGE,0,MAKELONG(200,0)); + m_spin2.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationLimit,0)); + m_nick.SetText( m_proto->m_nick); + m_nick2.SetText( m_proto->m_alternativeNick ); + m_userID.SetText( m_proto->m_userID); + m_name.SetText( m_proto->m_name); + m_pass.SetTextA( m_proto->m_password); + m_identSystem.SetText( m_proto->m_identSystem ); + m_identPort.SetText( m_proto->m_identPort ); + m_retryWait.SetText( m_proto->m_retryWait); + m_retryCount.SetText( m_proto->m_retryCount); + m_address.SetState( m_proto->m_showAddresses ); + m_oldStyle.SetState( m_proto->m_oldStyleModes ); + m_channelAway.SetState( m_proto->m_channelAwayNotification ); + m_onlineNotif.SetState( m_proto->m_autoOnlineNotification ); + m_onlineTimer.Enable( m_proto->m_autoOnlineNotification); + m_channelAway.Enable( m_proto->m_autoOnlineNotification); + m_spin1.Enable( m_proto->m_autoOnlineNotification ); + m_spin2.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); + m_limit.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); + m_ident.SetState( m_proto->m_ident ); + m_identSystem.Enable( m_proto->m_ident ); + m_identPort.Enable( m_proto->m_ident ); + m_identTimer.Enable( m_proto->m_ident ); + m_identTimer.SetState( m_proto->m_identTimer ); + m_disableError.SetState( m_proto->m_disableErrorPopups ); + m_forceVisible.SetState( m_proto->m_forceVisible ); + m_rejoinChannels.SetState( m_proto->m_rejoinChannels ); + m_rejoinOnKick.SetState( m_proto->m_rejoinIfKicked ); + m_retry.SetState( m_proto->m_retry ); + m_retryWait.Enable( m_proto->m_retry ); + m_retryCount.Enable( m_proto->m_retry ); + m_enableServer.SetState( !m_proto->m_disableDefaultServer ); + m_keepAlive.SetState( m_proto->m_sendKeepAlive ); + m_useServer.SetState( m_proto->m_useServer ); + m_showServer.SetState( !m_proto->m_hideServerWindow ); + m_showServer.Enable( m_proto->m_useServer ); + m_autoJoin.SetState( m_proto->m_joinOnInvite ); + + m_serverCombo.Enable( !m_proto->m_disableDefaultServer ); + m_add.Enable( !m_proto->m_disableDefaultServer ); + m_edit.Enable( !m_proto->m_disableDefaultServer ); + m_del.Enable( !m_proto->m_disableDefaultServer ); + m_server.Enable( !m_proto->m_disableDefaultServer ); + m_port.Enable( !m_proto->m_disableDefaultServer ); + m_port2.Enable( !m_proto->m_disableDefaultServer ); + m_pass.Enable( !m_proto->m_disableDefaultServer ); +} + +void CConnectPrefsDlg::OnServerCombo( CCtrlData* ) +{ + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + m_pass.SetTextA( "" ); + + if ( pData->m_iSSL == 0 ) + m_ssl.SetText( TranslateT( "Off" )); + if ( pData->m_iSSL == 1 ) + m_ssl.SetText( TranslateT( "Auto" )); + if ( pData->m_iSSL == 2 ) + m_ssl.SetText( TranslateT( "On" )); + + SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); +} } + +void CConnectPrefsDlg::OnAddServer( CCtrlButton* ) +{ + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + CServerDlg* dlg = new CServerDlg( m_proto, this, 1 ); + dlg->Show(); +} + +void CConnectPrefsDlg::OnDeleteServer( CCtrlButton* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR) + return; + + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + TCHAR temp[200]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("Do you want to delete\r\n%s"), (TCHAR*)_A2T(pData->m_name)); + if ( MessageBox( m_hwnd, temp, TranslateT("Delete server"), MB_YESNO | MB_ICONQUESTION ) == IDYES ) { + g_servers.remove( pData ); + + m_serverCombo.DeleteString( i ); + if ( i >= m_serverCombo.GetCount()) + i--; + m_serverCombo.SetCurSel( i ); + OnServerCombo( NULL ); + SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); + m_serverlistModified = true; + } + + m_serverCombo.Enable(); + m_add.Enable(); + m_edit.Enable(); + m_del.Enable(); +} + +void CConnectPrefsDlg::OnEditServer( CCtrlButton* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR ) + return; + + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + CServerDlg* dlg = new CServerDlg( m_proto, this, 2 ); + dlg->Show(); + SetWindowText( dlg->GetHwnd(), TranslateT( "Edit server" )); +} + +void CConnectPrefsDlg::OnStartup( CCtrlData* ) +{ + m_serverCombo.Enable( m_enableServer.GetState()); + m_add.Enable( m_enableServer.GetState()); + m_edit.Enable( m_enableServer.GetState()); + m_del.Enable( m_enableServer.GetState()); + m_server.Enable( m_enableServer.GetState()); + m_port.Enable( m_enableServer.GetState()); + m_port2.Enable( m_enableServer.GetState()); + m_pass.Enable( m_enableServer.GetState()); + m_ssl.Enable( m_enableServer.GetState()); +} + +void CConnectPrefsDlg::OnIdent( CCtrlData* ) +{ + m_identSystem.Enable( m_ident.GetState()); + m_identPort.Enable( m_ident.GetState()); + m_identTimer.Enable( m_ident.GetState()); +} + +void CConnectPrefsDlg::OnUseServer( CCtrlData* ) +{ + EnableWindow(GetDlgItem( m_hwnd, IDC_SHOWSERVER), m_useServer.GetState()); +} + +void CConnectPrefsDlg::OnOnlineNotif( CCtrlData* ) +{ + m_channelAway.Enable( m_onlineNotif.GetState()); + m_onlineTimer.Enable( m_onlineNotif.GetState()); + m_spin1.Enable( m_onlineNotif.GetState()); + m_spin2.Enable( m_onlineNotif.GetState()); + m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); +} + +void CConnectPrefsDlg::OnChannelAway( CCtrlData* ) +{ + m_spin2.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); + m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); +} + +void CConnectPrefsDlg::OnRetry( CCtrlData* ) +{ + m_retryWait.Enable( m_retry.GetState()); + m_retryCount.Enable( m_retry.GetState()); +} + +void CConnectPrefsDlg::OnApply() +{ + //Save the setting in the CONNECT dialog + if(m_enableServer.GetState()) { + m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); + CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + } + else m_proto->m_serverName[0] = m_proto->m_portStart[0] = m_proto->m_portEnd[0] = m_proto->m_password[0] = 0; + + m_proto->m_onlineNotificationTime = SendDlgItemMessage( m_hwnd,IDC_SPIN1,UDM_GETPOS,0,0); + m_proto->m_onlineNotificationLimit = SendDlgItemMessage( m_hwnd,IDC_SPIN2,UDM_GETPOS,0,0); + m_proto->m_channelAwayNotification = m_channelAway.GetState(); + + m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); + removeSpaces(m_proto->m_nick); + mir_sntprintf(m_proto->m_pNick, SIZEOF(m_proto->m_pNick), _T("%s"), m_proto->m_nick); + m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); + removeSpaces(m_proto->m_alternativeNick); + m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); + removeSpaces(m_proto->m_userID); + m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); + m_identSystem.GetText( m_proto->m_identSystem, SIZEOF(m_proto->m_identSystem)); + m_identPort.GetText( m_proto->m_identPort, SIZEOF(m_proto->m_identPort)); + m_retryWait.GetText( m_proto->m_retryWait, SIZEOF(m_proto->m_retryWait)); + m_retryCount.GetText( m_proto->m_retryCount, SIZEOF(m_proto->m_retryCount)); + m_proto->m_disableDefaultServer = !m_enableServer.GetState(); + m_proto->m_ident = m_ident.GetState(); + m_proto->m_identTimer = m_identTimer.GetState(); + m_proto->m_forceVisible = m_forceVisible.GetState(); + m_proto->m_disableErrorPopups = m_disableError.GetState(); + m_proto->m_rejoinChannels = m_rejoinChannels.GetState(); + m_proto->m_rejoinIfKicked = m_rejoinOnKick.GetState(); + m_proto->m_retry = m_retry.GetState(); + m_proto->m_showAddresses = m_address.GetState(); + m_proto->m_oldStyleModes = m_oldStyle.GetState(); + m_proto->m_useServer = m_useServer.GetState(); + + CLISTMENUITEM clmi; + memset( &clmi, 0, sizeof( clmi )); + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS; + if ( !m_proto->m_useServer ) + clmi.flags |= CMIF_GRAYED; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_proto->hMenuServer, ( LPARAM )&clmi ); + + m_proto->m_joinOnInvite = m_autoJoin.GetState(); + m_proto->m_hideServerWindow = !m_showServer.GetState(); + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); + if ( m_proto->m_sendKeepAlive = m_keepAlive.GetState()) + m_proto->SetChatTimer(m_proto->KeepAliveTimer, 60*1000, KeepAliveTimerProc); + else + m_proto->KillChatTimer(m_proto->KeepAliveTimer); + + m_proto->m_autoOnlineNotification = m_onlineNotif.GetState(); + if ( m_proto->m_autoOnlineNotification ) { + if ( !m_proto->bTempDisableCheck ) { + m_proto->SetChatTimer(m_proto->OnlineNotifTimer, 500, OnlineNotifTimerProc ); + if ( m_proto->m_channelAwayNotification ) + m_proto->SetChatTimer( m_proto->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); + } + } + else if ( !m_proto->bTempForceCheck ) { + m_proto->KillChatTimer( m_proto->OnlineNotifTimer ); + m_proto->KillChatTimer( m_proto->OnlineNotifTimer3 ); + } + + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + if ( m_enableServer.GetState()) + lstrcpyA(m_proto->m_network, pData->m_group); + else + lstrcpyA(m_proto->m_network, ""); + m_proto->m_iSSL = pData->m_iSSL; + } + + if ( m_serverlistModified ) { + m_serverlistModified = false; + CallService( MS_DB_MODULE_DELETE, 0, (LPARAM)SERVERSMODULE ); + + int j = m_serverCombo.GetCount(); + if (j != CB_ERR && j != 0) { + for (int index2 = 0; index2 < j; index2++) { + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( index2 ); + if ( pData == NULL || (INT_PTR)pData == CB_ERR ) + continue; + + char TextLine[512]; + if ( pData->m_iSSL > 0 ) + mir_snprintf(TextLine, sizeof(TextLine), "SERVER:SSL%u%s:%d-%dGROUP:%s", pData->m_iSSL, pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); + else + mir_snprintf(TextLine, sizeof(TextLine), "SERVER:%s:%d-%dGROUP:%s", pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); + DBWriteContactSettingString( NULL, SERVERSMODULE, pData->m_name, TextLine ); + + // combobox might contain new items + if ( g_servers.find( pData ) == NULL ) + g_servers.insert( pData ); + } } } + + m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); + + CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'CTCP preferences' dialog + +static TDbSetting CtcpSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_userInfo ), "UserInfo", DBVT_TCHAR, SIZEOF(pZero->m_userInfo) }, + { FIELD_OFFSET(CIrcProto, m_DCCPacketSize ), "DccPacketSize", DBVT_WORD, 0, 4096 }, + { FIELD_OFFSET(CIrcProto, m_DCCPassive ), "DccPassive", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_DCCMode ), "DCCMode", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_manualHost ), "ManualHost", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_IPFromServer ), "IPFromServer", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_disconnectDCCChats ), "DisconnectDCCChats", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_mySpecifiedHost ), "SpecHost", DBVT_ASCIIZ, SIZEOF(pZero->m_mySpecifiedHost) }, + { FIELD_OFFSET(CIrcProto, m_DCCChatAccept ), "CtcpChatAccept", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_sendNotice ), "SendNotice", DBVT_BYTE, 0, 1 } +}; + +CCtcpPrefsDlg::CCtcpPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_CTCP, NULL ), + m_enableIP( this, IDC_ENABLEIP ), + m_fromServer( this, IDC_FROMSERVER ), + m_combo( this, IDC_COMBO ), + m_slow( this, IDC_SLOW ), + m_fast( this, IDC_FAST ), + m_disc( this, IDC_DISC ), + m_passive( this, IDC_PASSIVE ), + m_sendNotice( this, IDC_SENDNOTICE ), + m_ip( this, IDC_IP ), + m_userInfo( this, IDC_USERINFO), + m_radio1( this, IDC_RADIO1 ), + m_radio2( this, IDC_RADIO2 ), + m_radio3( this, IDC_RADIO3 ) +{ + m_enableIP.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); + m_fromServer.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); +} + +void CCtcpPrefsDlg::OnInitDialog() +{ + m_userInfo.SetText(m_proto->m_userInfo); + + m_slow.SetState( m_proto->m_DCCMode == 0 ); + m_fast.SetState( m_proto->m_DCCMode == 1 ); + m_disc.SetState( m_proto->m_disconnectDCCChats ); + m_passive.SetState( m_proto->m_DCCPassive ); + m_sendNotice.SetState( m_proto->m_sendNotice ); + + m_combo.AddStringA( "256" ); + m_combo.AddStringA( "512" ); + m_combo.AddStringA( "1024" ); + m_combo.AddStringA( "2048" ); + m_combo.AddStringA( "4096" ); + m_combo.AddStringA( "8192" ); + + TCHAR szTemp[10]; + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u"), m_proto->m_DCCPacketSize ); + int i = m_combo.SelectString( szTemp ); + if ( i == CB_ERR ) + m_combo.SelectString( _T("4096")); + + if ( m_proto->m_DCCChatAccept == 1 ) + m_radio1.SetState( true ); + if ( m_proto->m_DCCChatAccept == 2 ) + m_radio2.SetState( true ); + if ( m_proto->m_DCCChatAccept == 3 ) + m_radio3.SetState( true ); + + m_fromServer.SetState( m_proto->m_IPFromServer ); + m_enableIP.SetState( m_proto->m_manualHost ); + m_ip.Enable( m_proto->m_manualHost ); + m_fromServer.Enable( !m_proto->m_manualHost ); + if (m_proto->m_manualHost) + m_ip.SetTextA( m_proto->m_mySpecifiedHost ); + else { + if ( m_proto->m_IPFromServer ) { + if ( m_proto->m_myHost[0] ) { + CMString s = (CMString)TranslateT("m_myHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); + } + else { + if ( m_proto->m_myLocalHost[0] ) { + CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); +} } } + +void CCtcpPrefsDlg::OnClicked( CCtrlData* ) +{ + m_ip.Enable( m_enableIP.GetState()); + m_fromServer.Enable( !m_enableIP.GetState()); + + if ( m_enableIP.GetState()) + m_ip.SetTextA( m_proto->m_mySpecifiedHost ); + else { + if ( m_fromServer.GetState()) { + if ( m_proto->m_myHost[0] ) { + CMString s = (CMString)TranslateT( "m_myHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); + } + else { + if ( m_proto->m_myLocalHost[0] ) { + CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); +} } } + +void CCtcpPrefsDlg::OnApply() +{ + m_userInfo.GetText( m_proto->m_userInfo, SIZEOF( m_proto->m_userInfo )); + + m_proto->m_DCCPacketSize = m_combo.GetInt(); + m_proto->m_DCCPassive = m_passive.GetState(); + m_proto->m_sendNotice = m_sendNotice.GetState(); + m_proto->m_DCCMode = m_fast.GetState(); + m_proto->m_manualHost = m_enableIP.GetState(); + m_proto->m_IPFromServer = m_fromServer.GetState(); + m_proto->m_disconnectDCCChats = m_disc.GetState(); + + if ( m_enableIP.GetState()) { + char szTemp[500]; + m_ip.GetTextA( szTemp, sizeof( szTemp )); + lstrcpynA(m_proto->m_mySpecifiedHost, GetWord(szTemp, 0).c_str(), 499); + if ( lstrlenA( m_proto->m_mySpecifiedHost )) + m_proto->ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_proto->m_mySpecifiedHost, IP_MANUAL )); + } + else m_proto->m_mySpecifiedHost[0] = 0; + + if ( m_radio1.GetState()) + m_proto->m_DCCChatAccept = 1; + if ( m_radio2.GetState()) + m_proto->m_DCCChatAccept = 2; + if ( m_radio3.GetState()) + m_proto->m_DCCChatAccept = 3; + + m_proto->WriteSettings( CtcpSettings, SIZEOF( CtcpSettings )); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Advanced preferences' dialog + +static TDbSetting OtherSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_quitMessage ), "QuitMessage", DBVT_TCHAR, SIZEOF(pZero->m_quitMessage) }, + { FIELD_OFFSET(CIrcProto, m_alias ), "Alias", DBVT_TCHAR, -1 }, + { FIELD_OFFSET(CIrcProto, m_codepage ), "Codepage", DBVT_DWORD, 0, CP_ACP }, + { FIELD_OFFSET(CIrcProto, m_utfAutodetect ), "UtfAutodetect", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_perform ), "Perform", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_scriptingEnabled ), "ScriptingEnabled", DBVT_BYTE } +}; + +static char* sttPerformEvents[] = { + "Event: Available", + "Event: Away", + "Event: N/A", + "Event: Occupied", + "Event: DND", + "Event: Free for chat", + "Event: On the phone", + "Event: Out for lunch", + "Event: Disconnect", + "ALL NETWORKS" +}; + +static LRESULT CALLBACK EditSubclassProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_CHAR : + if (wParam == 21 || wParam == 11 || wParam == 2) { + char w[2]; + w[1] = '\0'; + if (wParam == 11) + w[0] = 3; + if (wParam == 2) + w[0] = 2; + if (wParam == 21) + w[0] = 31; + SendMessage( hwndDlg, EM_REPLACESEL, false, (LPARAM) w); + SendMessage( hwndDlg, EM_SCROLLCARET, 0,0); + return 0; + } + break; + } + + return CallWindowProc(OldProc, hwndDlg, msg, wParam, lParam); +} + +COtherPrefsDlg::COtherPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_OTHER, NULL ), + m_url( this, IDC_CUSTOM ), + m_performCombo( this, IDC_PERFORMCOMBO ), + m_codepage( this, IDC_CODEPAGE ), + m_pertormEdit( this, IDC_PERFORMEDIT ), + m_perform( this, IDC_PERFORM ), + m_scripting( this, IDC_SCRIPT ), + m_autodetect( this, IDC_UTF_AUTODETECT ), + m_quitMessage( this, IDC_QUITMESSAGE ), + m_alias( this, IDC_ALIASEDIT ), + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Click to set commands that will be performed for this event")), + m_delete( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Click to delete the commands for this event")), + m_performlistModified( false ) +{ + m_url.OnClick = Callback( this, &COtherPrefsDlg::OnUrl ); + m_performCombo.OnChange = Callback( this, &COtherPrefsDlg::OnPerformCombo ); + m_codepage.OnChange = Callback( this, &COtherPrefsDlg::OnCodePage ); + m_pertormEdit.OnChange = Callback( this, &COtherPrefsDlg::OnPerformEdit ); + m_perform.OnChange = Callback( this, &COtherPrefsDlg::OnPerform ); + m_add.OnClick = Callback( this, &COtherPrefsDlg::OnAdd ); + m_delete.OnClick = Callback( this, &COtherPrefsDlg::OnDelete ); +} + +void COtherPrefsDlg::OnInitDialog() +{ + OldProc = (WNDPROC)SetWindowLongPtr( m_alias.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + SetWindowLongPtr( m_quitMessage.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + SetWindowLongPtr( m_pertormEdit.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + + m_alias.SetText( m_proto->m_alias ); + m_quitMessage.SetText( m_proto->m_quitMessage ); + m_perform.SetState( m_proto->m_perform ); + m_scripting.SetState( m_proto->m_scriptingEnabled ); + m_scripting.Enable( m_bMbotInstalled ); + m_performCombo.Enable( m_proto->m_perform ); + m_pertormEdit.Enable( m_proto->m_perform ); + m_add.Enable( m_proto->m_perform ); + m_delete.Enable( m_proto->m_perform ); + + fnGetCPInfoEx = ( pfnGetCPInfoEx )GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetCPInfoExW" ); + + m_codepage.AddString( TranslateT("Default ANSI codepage"), CP_ACP ); + if ( fnGetCPInfoEx == NULL ) + m_codepage.AddString( TranslateT("UTF-8"), CP_UTF8 ); + + sttCombo = &m_codepage; + EnumSystemCodePagesA(sttLangAddCallback, CP_INSTALLED); + + int i; + for ( i = m_codepage.GetCount(); i >= 0; i-- ) { + if ( m_codepage.GetItemData( i ) == m_proto->getCodepage()) { + m_codepage.SetCurSel( i ); + break; + } } + + + if ( m_proto->m_codepage == CP_UTF8 ) + m_autodetect.Disable(); + + for ( i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + int idx = m_performCombo.FindStringA( si.m_group, -1, true ); + if ( idx == CB_ERR ) { + idx = m_performCombo.AddStringA( si.m_group ); + addPerformComboValue( idx, si.m_group ); + } } + + for ( i=0; i < SIZEOF(sttPerformEvents); i++ ) { + int idx = m_performCombo.InsertString( _A2T( sttPerformEvents[i] ), i ); + addPerformComboValue( idx, sttPerformEvents[i] ); + } + + m_performCombo.SetCurSel( 0 ); + OnPerformCombo( NULL ); + m_autodetect.SetState( m_proto->m_utfAutodetect ); +} + +void COtherPrefsDlg::OnUrl( CCtrlButton* ) +{ + CallService( MS_UTILS_OPENURL,0,(LPARAM) "http://members.chello.se/matrix/index.html" ); +} + +void COtherPrefsDlg::OnPerformCombo( CCtrlData* ) +{ + int i = m_performCombo.GetCurSel(); + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if (pPerf == 0) + m_pertormEdit.SetTextA( "" ); + else + m_pertormEdit.SetText( pPerf->mText.c_str()); + m_add.Disable(); + if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) + m_delete.Enable(); + else + m_delete.Disable(); +} + +void COtherPrefsDlg::OnCodePage( CCtrlData* ) +{ + int curSel = m_codepage.GetCurSel(); + m_autodetect.Enable( m_codepage.GetItemData(curSel) != CP_UTF8 ); +} + +void COtherPrefsDlg::OnPerformEdit( CCtrlData* ) +{ + m_add.Enable(); + + if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) + m_delete.Enable(); + else + m_delete.Disable(); +} + +void COtherPrefsDlg::OnPerform( CCtrlData* ) +{ + m_performCombo.Enable( m_perform.GetState()); + m_pertormEdit.Enable( m_perform.GetState()); + m_add.Enable( m_perform.GetState()); + m_delete.Enable( m_perform.GetState()); +} + +void COtherPrefsDlg::OnAdd( CCtrlButton* ) +{ + TCHAR* temp = m_pertormEdit.GetText(); + + if ( my_strstri( temp, _T("/away"))) + MessageBox( NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); + else { + int i = m_performCombo.GetCurSel(); + if ( i != CB_ERR ) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if ( pPerf != NULL ) + pPerf->mText = temp; + + m_add.Disable(); + m_performlistModified = true; + } } + mir_free( temp ); +} + +void COtherPrefsDlg::OnDelete( CCtrlButton* ) +{ + int i = m_performCombo.GetCurSel(); + if ( i != CB_ERR ) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if ( pPerf != NULL ) { + pPerf->mText = _T(""); + m_pertormEdit.SetTextA( "" ); + m_delete.Disable(); + m_add.Disable(); + } + + m_performlistModified = true; +} } + +void COtherPrefsDlg::OnDestroy() +{ + int i = m_performCombo.GetCount(); + if ( i != CB_ERR && i != 0 ) { + for (int index = 0; index < i; index++) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( index ); + if (( INT_PTR )pPerf != CB_ERR && pPerf != NULL ) + delete pPerf; +} } } + +void COtherPrefsDlg::OnApply() +{ + mir_free( m_proto->m_alias ); + m_proto->m_alias = m_alias.GetText(); + m_quitMessage.GetText( m_proto->m_quitMessage, SIZEOF( m_proto->m_quitMessage )); + + int curSel = m_codepage.GetCurSel(); + m_proto->m_codepage = m_codepage.GetItemData( curSel ); + if ( m_proto->IsConnected()) + m_proto->setCodepage( m_proto->m_codepage ); + + m_proto->m_utfAutodetect = m_autodetect.GetState(); + m_proto->m_perform = m_perform.GetState(); + m_proto->m_scriptingEnabled = m_scripting.GetState(); + if ( m_add.Enabled()) + OnAdd( NULL ); + + if ( m_performlistModified ) { + int count = m_performCombo.GetCount(); + for ( int i = 0; i < count; i++ ) { + PERFORM_INFO* pPerf = ( PERFORM_INFO* )m_performCombo.GetItemData( i ); + if (( INT_PTR )pPerf == CB_ERR ) + continue; + + if ( !pPerf->mText.IsEmpty()) + m_proto->setTString( pPerf->mSetting.c_str(), pPerf->mText.c_str()); + else + DBDeleteContactSetting( NULL, m_proto->m_szModuleName, pPerf->mSetting.c_str()); + } } + m_proto->WriteSettings( OtherSettings, SIZEOF( OtherSettings )); +} + +void COtherPrefsDlg::addPerformComboValue( int idx, const char* szValueName ) +{ + String sSetting = String("PERFORM:") + szValueName; + sSetting.MakeUpper(); + + PERFORM_INFO* pPref; + DBVARIANT dbv; + if ( !m_proto->getTString( sSetting.c_str(), &dbv )) { + pPref = new PERFORM_INFO( sSetting.c_str(), dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + else pPref = new PERFORM_INFO( sSetting.c_str(), _T("")); + m_performCombo.SetItemData( idx, ( LPARAM )pPref ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'add ignore' preferences dialog + +CAddIgnoreDlg::CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* _owner ) : + CProtoDlgBase( _pro, IDD_ADDIGNORE, _owner->GetHwnd()), + m_Ok( this, IDOK ), + m_owner( _owner ) +{ + if ( mask == NULL ) + szOldMask[0] = 0; + else + _tcsncpy( szOldMask, mask, SIZEOF(szOldMask)); + + m_Ok.OnClick = Callback( this, &CAddIgnoreDlg::OnOk ); +} + +void CAddIgnoreDlg::OnInitDialog() +{ + if ( szOldMask[0] == 0 ) { + if ( m_proto->IsConnected()) + SetWindowText(GetDlgItem( m_hwnd, IDC_NETWORK), m_proto->m_info.sNetwork.c_str()); + CheckDlgButton( m_hwnd, IDC_Q, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_N, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_I, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_D, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_C, BST_CHECKED); +} } + +void CAddIgnoreDlg::OnOk( CCtrlButton* ) +{ + TCHAR szMask[500]; + TCHAR szNetwork[500]; + CMString flags; + if ( IsDlgButtonChecked( m_hwnd, IDC_Q ) == BST_CHECKED ) flags += 'q'; + if ( IsDlgButtonChecked( m_hwnd, IDC_N ) == BST_CHECKED ) flags += 'n'; + if ( IsDlgButtonChecked( m_hwnd, IDC_I ) == BST_CHECKED ) flags += 'i'; + if ( IsDlgButtonChecked( m_hwnd, IDC_D ) == BST_CHECKED ) flags += 'd'; + if ( IsDlgButtonChecked( m_hwnd, IDC_C ) == BST_CHECKED ) flags += 'c'; + if ( IsDlgButtonChecked( m_hwnd, IDC_M ) == BST_CHECKED ) flags += 'm'; + + GetWindowText( GetDlgItem( m_hwnd, IDC_MASK), szMask, SIZEOF(szMask)); + GetWindowText( GetDlgItem( m_hwnd, IDC_NETWORK), szNetwork, SIZEOF(szNetwork)); + + CMString Mask = GetWord(szMask, 0); + if ( Mask.GetLength() != 0 ) { + if ( !_tcschr(Mask.c_str(), '!') && !_tcschr(Mask.c_str(), '@')) + Mask += _T("!*@*"); + + if ( !flags.IsEmpty()) { + if ( *szOldMask ) + m_proto->RemoveIgnore( szOldMask ); + m_proto->AddIgnore(Mask.c_str(), flags.c_str(), szNetwork); +} } } + +void CAddIgnoreDlg::OnClose() +{ + m_owner->FixButtons(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Ignore' preferences dialog + +static TDbSetting IgnoreSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_DCCFileEnabled ), "EnableCtcpFile", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_DCCChatEnabled ), "EnableCtcpChat", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_DCCChatIgnore), "CtcpChatIgnore", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_ignore ), "Ignore", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_ignoreChannelDefault ), "IgnoreChannelDefault", DBVT_BYTE }, +}; + +static int CALLBACK IgnoreListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + CIgnorePrefsDlg* hwndDlg = ( CIgnorePrefsDlg* )lParamSort; + if ( !hwndDlg->GetHwnd()) + return 1; + + TCHAR temp1[512]; + TCHAR temp2[512]; + + LVITEM lvm; + lvm.mask = LVIF_TEXT; + lvm.iSubItem = 0; + lvm.cchTextMax = SIZEOF(temp1); + + lvm.iItem = lParam1; + lvm.pszText = temp1; + hwndDlg->m_list.GetItem( &lvm ); + + lvm.iItem = lParam2; + lvm.pszText = temp2; + hwndDlg->m_list.GetItem( &lvm ); + + if ( temp1[0] && temp2[0] ) + return lstrcmpi( temp1, temp2 ); + + return ( temp1[0] == 0 ) ? 1 : -1; +} + +static LRESULT CALLBACK ListviewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_KEYUP : + if ( ListView_GetSelectionMark(GetDlgItem(GetParent(hwnd), IDC_LIST)) != -1) { + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), true); + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), true); + } + else { + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), false); + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), false); + } + + if (wParam == VK_DELETE) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_DELETE, BN_CLICKED), 0); + + if (wParam == VK_SPACE) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_EDIT, BN_CLICKED), 0); + break; + } + + return CallWindowProc(OldListViewProc, hwnd, msg, wParam, lParam); +} + +// Callback for the 'Add ignore' dialog + +void CIrcProto::InitIgnore( void ) +{ + TCHAR szTemp[ MAX_PATH ]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_ignore.ini"), m_szModuleName); + TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); + char* pszIgnoreData = IrcLoadFile(szLoadFileName); + if ( pszIgnoreData != NULL ) { + char *p1 = pszIgnoreData; + while ( *p1 != '\0' ) { + while ( *p1 == '\r' || *p1 == '\n' ) + p1++; + if ( *p1 == '\0' ) + break; + + char* p2 = strstr( p1, "\r\n" ); + if ( !p2 ) + p2 = strchr( p1, '\0' ); + + char* pTemp = p2; + while ( pTemp > p1 && (*pTemp == '\r' || *pTemp == '\n' ||*pTemp == '\0' || *pTemp == ' ' )) + pTemp--; + *++pTemp = 0; + + String mask = GetWord(p1, 0); + String flags = GetWord(p1, 1); + String network = GetWord(p1, 2); + if ( !mask.IsEmpty()) + m_ignoreItems.insert( new CIrcIgnoreItem( getCodepage(), mask.c_str(), flags.c_str(), network.c_str())); + + p1 = p2; + } + + RewriteIgnoreSettings(); + delete[] pszIgnoreData; + ::_tremove( szLoadFileName ); + } + mir_free( szLoadFileName ); + + int idx = 0; + char settingName[40]; + for ( ;; ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", idx++ ); + + DBVARIANT dbv; + if ( getTString( settingName, &dbv )) + break; + + CMString mask = GetWord( dbv.ptszVal, 0 ); + CMString flags = GetWord( dbv.ptszVal, 1 ); + CMString network = GetWord( dbv.ptszVal, 2 ); + m_ignoreItems.insert( new CIrcIgnoreItem( mask.c_str(), flags.c_str(), network.c_str())); + DBFreeVariant( &dbv ); +} } + +void CIrcProto::RewriteIgnoreSettings( void ) +{ + char settingName[ 40 ]; + + int i=0; + for ( ;; ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i++ ); + if ( DBDeleteContactSetting( NULL, m_szModuleName, settingName )) + break; + } + + for ( i=0; i < m_ignoreItems.getCount(); i++ ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i ); + + CIrcIgnoreItem& C = m_ignoreItems[i]; + setTString( settingName, ( C.mask + _T(" ") + C.flags + _T(" ") + C.network ).c_str()); +} } + +CIgnorePrefsDlg::CIgnorePrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_IGNORE, NULL ), + m_list( this, IDC_LIST ), + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add new ignore")), + m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit this ignore")), + m_del( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Delete this ignore")), + m_enable( this, IDC_ENABLEIGNORE ), + m_ignoreChat( this, IDC_IGNORECHAT ), + m_ignoreFile( this, IDC_IGNOREFILE ), + m_ignoreChannel( this, IDC_IGNORECHANNEL ), + m_ignoreUnknown( this, IDC_IGNOREUNKNOWN ) +{ + m_enable.OnChange = Callback( this, &CIgnorePrefsDlg::OnEnableIgnore ); + m_ignoreChat.OnChange = Callback( this, &CIgnorePrefsDlg::OnIgnoreChat ); + m_add.OnClick = Callback( this, &CIgnorePrefsDlg::OnAdd ); + m_list.OnDoubleClick = m_edit.OnClick = Callback( this, &CIgnorePrefsDlg::OnEdit ); + m_del.OnClick = Callback( this, &CIgnorePrefsDlg::OnDelete ); + m_list.OnColumnClick = Callback( this, &CIgnorePrefsDlg::List_OnColumnClick ); +} + +void CIgnorePrefsDlg::OnInitDialog() +{ + m_proto->m_ignoreDlg = this; + OldListViewProc = (WNDPROC)SetWindowLongPtr( m_list.GetHwnd(),GWLP_WNDPROC, (LONG_PTR)ListviewSubclassProc ); + + m_enable.SetState( m_proto->m_ignore ); + m_ignoreFile.SetState( !m_proto->m_DCCFileEnabled ); + m_ignoreChat.SetState( !m_proto->m_DCCChatEnabled ); + m_ignoreChannel.SetState( m_proto->m_ignoreChannelDefault ); + if ( m_proto->m_DCCChatIgnore == 2 ) + m_ignoreUnknown.SetState( BST_CHECKED ); + + m_ignoreUnknown.Enable( m_proto->m_DCCChatEnabled ); + m_list.Enable( m_proto->m_ignore ); + m_ignoreChannel.Enable( m_proto->m_ignore); + m_add.Enable( m_proto->m_ignore ); + + static int COLUMNS_SIZES[3] = {195, 60, 80}; + LV_COLUMN lvC; + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; + for ( int index=0; index < 3; index++ ) { + lvC.iSubItem = index; + lvC.cx = COLUMNS_SIZES[index]; + + TCHAR* text = NULL; + switch (index) { + case 0: text = TranslateT("Ignore mask"); break; + case 1: text = TranslateT("Flags"); break; + case 2: text = TranslateT("Network"); break; + } + lvC.pszText = text; + ListView_InsertColumn(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW),index,&lvC); + } + + ListView_SetExtendedListViewStyle(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW), LVS_EX_FULLROWSELECT); + RebuildList(); +} + +INT_PTR CIgnorePrefsDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch( msg ) { + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case IDC_LIST: + switch (((NMHDR*)lParam)->code) { + case NM_CLICK: + case NM_RCLICK: + if ( m_list.GetSelectionMark() != -1 ) + FixButtons(); + break; + } } + break; + } + return CDlgBase::DlgProc(msg, wParam, lParam); +} + +void CIgnorePrefsDlg::OnEnableIgnore( CCtrlData* ) +{ + m_ignoreChannel.Enable( m_enable.GetState()); + m_list.Enable( m_enable.GetState()); + m_add.Enable( m_enable.GetState()); +} + +void CIgnorePrefsDlg::OnIgnoreChat( CCtrlData* ) +{ + m_ignoreUnknown.Enable( m_ignoreChat.GetState() == BST_UNCHECKED ); +} + +void CIgnorePrefsDlg::OnAdd( CCtrlButton* ) +{ + CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, NULL, this ); + dlg->Show(); + SetWindowText( dlg->GetHwnd(), TranslateT( "Add ignore" )); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); +} + +void CIgnorePrefsDlg::OnEdit( CCtrlButton* ) +{ + if ( !m_add.Enabled()) + return; + + TCHAR szMask[512]; + TCHAR szFlags[512]; + TCHAR szNetwork[512]; + int i = m_list.GetSelectionMark(); + m_list.GetItemText( i, 0, szMask, 511 ); + m_list.GetItemText( i, 1, szFlags, 511 ); + m_list.GetItemText( i, 2, szNetwork, 511 ); + CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, szMask, this ); + dlg->Show(); + HWND hWnd = dlg->GetHwnd(); + SetWindowText(hWnd, TranslateT("Edit ignore")); + if ( szFlags[0] ) { + if ( _tcschr(szFlags, 'q')) + CheckDlgButton(hWnd, IDC_Q, BST_CHECKED); + if ( _tcschr(szFlags, 'n')) + CheckDlgButton(hWnd, IDC_N, BST_CHECKED); + if ( _tcschr(szFlags, 'i')) + CheckDlgButton(hWnd, IDC_I, BST_CHECKED); + if ( _tcschr(szFlags, 'd')) + CheckDlgButton(hWnd, IDC_D, BST_CHECKED); + if ( _tcschr(szFlags, 'c')) + CheckDlgButton(hWnd, IDC_C, BST_CHECKED); + if ( _tcschr(szFlags, 'm')) + CheckDlgButton(hWnd, IDC_M, BST_CHECKED); + } + SetWindowText(GetDlgItem(hWnd, IDC_MASK), szMask); + SetWindowText(GetDlgItem(hWnd, IDC_NETWORK), szNetwork); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); +} + +void CIgnorePrefsDlg::OnDelete( CCtrlButton* ) +{ + if ( !m_del.Enabled()) + return; + + TCHAR szMask[512]; + int i = m_list.GetSelectionMark(); + m_list.GetItemText( i, 0, szMask, SIZEOF(szMask)); + m_proto->RemoveIgnore( szMask ); +} + +void CIgnorePrefsDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ) +{ + m_list.SortItems( IgnoreListSort, (LPARAM)this ); + UpdateList(); +} + +void CIgnorePrefsDlg::OnApply() +{ + m_proto->m_DCCFileEnabled = !m_ignoreFile.GetState(); + m_proto->m_DCCChatEnabled = !m_ignoreChat.GetState(); + m_proto->m_ignore = m_enable.GetState(); + m_proto->m_ignoreChannelDefault = m_ignoreChannel.GetState(); + m_proto->m_DCCChatIgnore = m_ignoreUnknown.GetState() ? 2 : 1; + m_proto->WriteSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); +} + +void CIgnorePrefsDlg::OnDestroy() +{ + m_proto->m_ignoreDlg = NULL; + m_proto->m_ignoreItems.destroy(); + + int i = m_list.GetItemCount(); + for ( int j = 0; j < i; j++ ) { + TCHAR szMask[512], szFlags[40], szNetwork[100]; + m_list.GetItemText( j, 0, szMask, SIZEOF(szMask)); + m_list.GetItemText( j, 1, szFlags, SIZEOF(szFlags)); + m_list.GetItemText( j, 2, szNetwork, SIZEOF(szNetwork)); + m_proto->m_ignoreItems.insert( new CIrcIgnoreItem( szMask, szFlags, szNetwork )); + } + + m_proto->RewriteIgnoreSettings(); + SetWindowLongPtr( m_list.GetHwnd(), GWLP_WNDPROC, (LONG_PTR)OldListViewProc ); +} + +void CIgnorePrefsDlg::FixButtons() +{ + m_add.Enable( m_enable.GetState()); + if ( m_list.GetSelectionMark() != -1 ) { + m_edit.Enable(); + m_del.Enable(); + } + else { + m_edit.Disable(); + m_del.Disable(); +} } + +void CIgnorePrefsDlg::RebuildList() +{ + m_list.DeleteAllItems(); + + for ( int i=0; i < m_proto->m_ignoreItems.getCount(); i++ ) { + CIrcIgnoreItem& C = m_proto->m_ignoreItems[i]; + if ( C.mask.IsEmpty() || C.flags[0] != '+' ) + continue; + + LVITEM lvItem; + lvItem.iItem = m_list.GetItemCount(); + lvItem.mask = LVIF_TEXT|LVIF_PARAM ; + lvItem.iSubItem = 0; + lvItem.lParam = lvItem.iItem; + lvItem.pszText = (TCHAR*)C.mask.c_str(); + lvItem.iItem = m_list.InsertItem( &lvItem ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem = 1; + lvItem.pszText = (TCHAR*)C.flags.c_str(); + m_list.SetItem( &lvItem ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem =2; + lvItem.pszText = (TCHAR*)C.network.c_str(); + m_list.SetItem( &lvItem ); + } + + UpdateList(); + m_list.SortItems( IgnoreListSort, ( LPARAM )this ); + UpdateList(); + + FixButtons(); +} + +void CIgnorePrefsDlg::UpdateList() +{ + int j = m_list.GetItemCount(); + if (j > 0 ) { + LVITEM lvm; + lvm.mask= LVIF_PARAM; + lvm.iSubItem = 0; + for ( int i =0; i < j; i++) { + lvm.iItem = i; + lvm.lParam = i; + m_list.SetItem( &lvm ); +} } } + +///////////////////////////////////////////////////////////////////////////////////////// + +int CIrcProto::OnInitOptionsPages(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CONNECT); + odp.ptszTitle = m_tszUserName; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTab = LPGENT("Account"); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; + odp.pfnDlgProc = CDlgBase::DynamicDlgProc; + odp.dwInitParam = (LPARAM)&OptCreateAccount; + OptCreateAccount.create = CConnectPrefsDlg::Create; + OptCreateAccount.param = this; + Options_AddPage(wParam, &odp); + + odp.flags |= ODPF_EXPERTONLY; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CTCP); + odp.ptszTab = LPGENT("DCC'n CTCP"); + odp.dwInitParam = (LPARAM)&OptCreateConn; + OptCreateConn.create = CCtcpPrefsDlg::Create; + OptCreateConn.param = this; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_OTHER); + odp.ptszTab = LPGENT("Advanced"); + odp.dwInitParam = (LPARAM)&OptCreateOther; + OptCreateOther.create = COtherPrefsDlg::Create; + OptCreateOther.param = this; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_IGNORE); + odp.ptszTab = LPGENT("Ignore"); + odp.dwInitParam = (LPARAM)&OptCreateIgnore; + OptCreateIgnore.create = CIgnorePrefsDlg::Create; + OptCreateIgnore.param = this; + Options_AddPage(wParam, &odp); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIrcProto::InitPrefs(void) +{ + ConnectSettings[0].defStr = _T("Miranda"); + ConnectSettings[1].defStr = _T("UNIX"); + ConnectSettings[2].defStr = _T("113"); + ConnectSettings[3].defStr = _T("30"); + ConnectSettings[4].defStr = _T("10"); + + CtcpSettings[0].defStr = _T(STR_USERINFO); + + OtherSettings[0].defStr = _T(STR_QUITMESSAGE); + + ReadSettings( ConnectSettings, SIZEOF( ConnectSettings )); + ReadSettings( CtcpSettings, SIZEOF( CtcpSettings )); + ReadSettings( OtherSettings, SIZEOF( OtherSettings )); + ReadSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); + + CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_password); + + int x = getDword( "SizeOfListBottom", -1 ); + if ( x != -1 ) { + DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListBottom" ); + setDword( "channelList_height", x ); + } + if (( x = getDword( "SizeOfListWidth", -1 )) != -1 ) { + DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListWidth" ); + setDword( "channelList_width", x ); + } + + if ( m_pNick[0] == 0 ) { + if ( m_nick[0] != 0 ) { + memcpy( m_pNick, m_nick, sizeof( m_pNick )); + setTString("PNick", m_nick); + } + } + else { + memcpy( m_nick, m_pNick, sizeof( m_nick )); + setTString("Nick", m_nick); + } + + m_mySpecifiedHostIP[0] = 0; + + if ( m_alias == NULL ) + m_alias = mir_tstrdup( _T("/op /mode ## +ooo $1 $2 $3\r\n/dop /mode ## -ooo $1 $2 $3\r\n/voice /mode ## +vvv $1 $2 $3\r\n/dvoice /mode ## -vvv $1 $2 $3\r\n/j /join #$1 $2-\r\n/p /part ## $1-\r\n/w /whois $1\r\n/k /kick ## $1 $2-\r\n/q /query $1\r\n/logon /log on ##\r\n/logoff /log off ##\r\n/save /log buffer $1\r\n/slap /me slaps $1 around a bit with a large trout" )); + + m_quickComboSelection = getDword( "QuickComboSelection", m_serverComboSelection + 1); + m_myHost[0] = '\0'; + + colors[0] = RGB(255,255,255); + colors[1] = RGB(0,0,0); + colors[2] = RGB(0,0,127); + colors[3] = RGB(0,147,0); + colors[4] = RGB(255,0,0); + colors[5] = RGB(127,0,0); + colors[6] = RGB(156,0,156); + colors[7] = RGB(252,127,0); + colors[8] = RGB(255,255,0); + colors[9] = RGB(0,252,0); + colors[10] = RGB(0,147,147); + colors[11] = RGB(0,255,255); + colors[12] = RGB(0,0,252); + colors[13] = RGB(255,0,255); + colors[14] = RGB(127,127,127); + colors[15] = RGB(210,210,210); +} + +/////////////////////////////////////////////////////////////////////////////// +// Account manager UI + +struct CDlgAccMgrUI : public CProtoDlgBase +{ + CCtrlCombo m_serverCombo; + CCtrlEdit m_server, m_port, m_port2, m_pass, m_nick, m_nick2, m_name, m_userID, m_ssl; + + CDlgAccMgrUI( CIrcProto* _pro, HWND _owner ) : + CProtoDlgBase( _pro, IDD_ACCMGRUI, _owner ), + m_serverCombo( this, IDC_SERVERCOMBO ), + m_server( this, IDC_SERVER ), + m_port( this, IDC_PORT ), + m_port2( this, IDC_PORT2 ), + m_pass( this, IDC_PASS ), + m_nick( this, IDC_NICK ), + m_nick2( this, IDC_NICK2 ), + m_name( this, IDC_NAME ), + m_ssl( this, IDC_SSL ), + m_userID( this, IDC_USERID ) + { + m_serverCombo.OnChange = Callback( this, &CDlgAccMgrUI::OnChangeCombo ); + } + + virtual void OnInitDialog() + { + for ( int i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); + } + m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); + m_server.SetTextA( m_proto->m_serverName ); + m_port.SetTextA( m_proto->m_portStart ); + m_port2.SetTextA( m_proto->m_portEnd ); + m_pass.SetTextA( m_proto->m_password); + switch ( m_proto->m_iSSL ) { + case 0: m_ssl.SetTextA( "Off" ); break; + case 1: m_ssl.SetTextA( "Auto" ); break; + case 2: m_ssl.SetTextA( "On" ); break; + } + + m_nick.SetText( m_proto->m_nick); + m_nick2.SetText( m_proto->m_alternativeNick ); + m_userID.SetText( m_proto->m_userID); + m_name.SetText( m_proto->m_name); + } + + virtual void OnApply() + { + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); + m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); + CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + + m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); + removeSpaces(m_proto->m_nick); + mir_sntprintf(m_proto->m_pNick, 30, _T("%s"), m_proto->m_nick); + m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); + removeSpaces(m_proto->m_alternativeNick); + m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); + removeSpaces(m_proto->m_userID); + m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); + m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); + CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + } + + void OnChangeCombo( CCtrlCombo* ) + { + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + m_pass.SetTextA( "" ); + switch ( pData->m_iSSL ) { + case 0: m_ssl.SetTextA( "Off" ); break; + case 1: m_ssl.SetTextA( "Auto" ); break; + case 2: m_ssl.SetTextA( "On" ); break; + } } } +}; + +INT_PTR CIrcProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) +{ + CDlgAccMgrUI *dlg = new CDlgAccMgrUI(this, (HWND)lParam); + dlg->Show(); + return (INT_PTR)dlg->GetHwnd(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Initialize servers list + +static void sttImportIni( const TCHAR* szIniFile ) +{ + FILE* serverFile = _tfopen( szIniFile, _T("r")); + if ( serverFile == NULL ) + return; + + char buf1[ 500 ], buf2[ 200 ]; + while ( fgets( buf1, sizeof( buf1 ), serverFile )) { + char* p = strchr( buf1, '=' ); + if ( !p ) + continue; + + p++; + rtrim( p ); + char* p1 = strstr( p, "SERVER:" ); + if ( !p1 ) + continue; + + memcpy( buf2, p, int(p1-p)); + buf2[ int(p1-p) ] = 0; + DBWriteContactSettingString( NULL, SERVERSMODULE, buf2, p1 ); + } + fclose( serverFile ); + ::_tremove( szIniFile ); +} + +void InitServers() +{ + TCHAR *szTemp = Utils_ReplaceVarsT(_T("%miranda_path%\\Plugins\\IRC_servers.ini")); + sttImportIni( szTemp ); + mir_free( szTemp ); + + RereadServers(); + + if ( g_servers.getCount() == 0 ) { + TCHAR *szIniFile = Utils_ReplaceVarsT(_T("%temp%\\default_servers.ini")); + FILE *serverFile = _tfopen( szIniFile, _T("a")); + if (serverFile) { + char* pszSvrs = ( char* )LockResource(LoadResource(hInst,FindResource(hInst,MAKEINTRESOURCE(IDR_SERVERS),_T("TEXT")))); + if (pszSvrs) + fwrite(pszSvrs , 1 , lstrlenA(pszSvrs) + 1 , serverFile ); + fclose(serverFile); + + sttImportIni( szIniFile ); + RereadServers(); + } + mir_free(szIniFile); + } +} diff --git a/protocols/IRCG/src/output.cpp b/protocols/IRCG/src/output.cpp new file mode 100644 index 0000000000..6a97f45baf --- /dev/null +++ b/protocols/IRCG/src/output.cpp @@ -0,0 +1,158 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +static CMString FormatOutput (const CIrcMessage* pmsg) +{ + CMString sMessage; + + if ( pmsg->m_bIncoming ) { // Is it an incoming message? + if ( pmsg->sCommand == _T("WALLOPS") && pmsg->parameters.getCount() > 0 ) { + TCHAR temp[200]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("WallOps from %s: "), pmsg->prefix.sNick.c_str()); + sMessage = temp; + for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(" "); + } + goto THE_END; + } + + if ( pmsg->sCommand == _T("INVITE") && pmsg->parameters.getCount() > 1 ) { + TCHAR temp[256]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s invites you to %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += _T(": ") + pmsg->parameters[i]; + if ( i != pmsg->parameters.getCount()-1 ) + sMessage += _T(" "); + } + goto THE_END; + } + + int index = StrToInt( pmsg->sCommand.c_str()); + if ( index == 301 && pmsg->parameters.getCount() > 0 ) { + TCHAR temp[500]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is away"), pmsg->parameters[1].c_str()); + sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += _T(": ") + pmsg->parameters[i]; + if ( i != pmsg->parameters.getCount()-1 ) + sMessage += _T(" "); + } + goto THE_END; + } + + if (( index == 443 || index == 441 ) && pmsg->parameters.getCount() > 3 ) + return pmsg->parameters[1] + _T(" ") + pmsg->parameters[3] + _T(": ") + pmsg->parameters[2]; + + if ( index == 303 ) { // ISON command + sMessage = TranslateT("These are online: "); + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(", "); + } + goto THE_END; + } + + if (( index > 400 || index < 500) && pmsg->parameters.getCount() > 2 && pmsg->sCommand[0] == '4' ) //all error messages + return pmsg->parameters[2] + _T(": ") + pmsg->parameters[1]; + } + else if ( pmsg->sCommand == _T("NOTICE") && pmsg->parameters.getCount() > 1 ) { + TCHAR temp[500]; *temp = '\0'; + + int l = pmsg->parameters[1].GetLength(); + if ( l > 3 && pmsg->parameters[1][0] == 1 && pmsg->parameters[1][ l-1 ] == 1 ) { + // CTCP reply + CMString tempstr = pmsg->parameters[1]; + tempstr.Delete(0,1); + tempstr.Delete(tempstr.GetLength()-1,1); + CMString type = GetWord(tempstr.c_str(), 0); + if ( lstrcmpi(type.c_str(), _T("ping")) == 0) + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s"), type.c_str(), pmsg->parameters[0].c_str()); + else + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s: %s"), type.c_str(), pmsg->parameters[0].c_str(), GetWordAddress(tempstr.c_str(), 1)); + sMessage = temp; + } + else { + mir_sntprintf(temp, SIZEOF(temp), TranslateT("Notice to %s: "), pmsg->parameters[0].c_str()); + sMessage = temp; + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(" "); + } } + goto THE_END; + } + + // Default Message handler. + + if ( pmsg->m_bIncoming ) { + if ( pmsg->parameters.getCount() < 2 && pmsg->parameters.getCount() > 0 ) + return pmsg->sCommand + _T(" : ") + pmsg->parameters[0]; + + if ( pmsg->parameters.getCount() > 1 ) + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += pmsg->parameters[i] + _T(" "); + } + else { + if ( pmsg->prefix.sNick.GetLength()) + sMessage = pmsg->prefix.sNick + _T(" "); + sMessage += pmsg->sCommand + _T(" "); + for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += pmsg->parameters[i] + _T(" "); + } + +THE_END: + return sMessage; +} + +BOOL CIrcProto::ShowMessage (const CIrcMessage* pmsg) +{ + CMString mess = FormatOutput(pmsg); + + if ( !pmsg->m_bIncoming ) + ReplaceString( mess, _T("%%"), _T("%")); + + int iTemp = StrToInt( pmsg->sCommand.c_str()); + + //To active window + if (( iTemp > 400 || iTemp < 500 ) && pmsg->sCommand[0] == '4' //all error messages + || pmsg->sCommand == _T("303") //ISON command + || pmsg->sCommand == _T("INVITE") + || ( (pmsg->sCommand == _T("NOTICE")) && ( (pmsg->parameters.getCount() > 2) ? (_tcsstr(pmsg->parameters[1].c_str(), _T("\001"))==NULL) : false)) // CTCP answers should go to m_network Log window! + || pmsg->sCommand == _T("515")) //chanserv error + { + DoEvent(GC_EVENT_INFORMATION, NULL, pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + return TRUE; + } + + if ( m_useServer ) { + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, + ( pmsg->m_bIncoming ) ? pmsg->prefix.sNick.c_str() : m_info.sNick.c_str(), + mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming ? false : true ); + return true; + } + return false; +} diff --git a/protocols/IRCG/src/resource.h b/protocols/IRCG/src/resource.h new file mode 100644 index 0000000000..948b3a4085 --- /dev/null +++ b/protocols/IRCG/src/resource.h @@ -0,0 +1,253 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by IRC.rc +// +#define ID_INFO_QUERY 3 +#define IDD_PREFS_MAIN 101 +#define IDC_OPTIONSTAB 102 +#define IDD_PREFS_CONNECT 103 +#define IDD_INFO 106 +#define IDD_NICK 107 +#define IDD_PREFS_OTHER 113 +#define IDD_ADDSERVER 120 +#define IDD_LIST 123 +#define IDR_MENU 129 +#define IDD_QUICKCONN 133 +#define IDI_MAIN 136 +#define IDD_USERINFO 154 +#define IDD_CHANMANAGER 155 +#define IDD_QUESTION 156 +#define IDD_PREFS_CTCP 158 +#define IDD_MESSAGEBOX 159 +#define IDD_PREFS_IGNORE 160 +#define IDD_ADDIGNORE 161 +#define IDD_ACCMGRUI 162 +#define IDI_ADD 175 +#define IDI_BLOCK 176 +#define IDI_DELETE 177 +#define IDI_WHOIS 179 +#define IDI_LIST 181 +#define IDI_MANAGER 182 +#define IDI_QUICK 184 +#define IDI_GO 185 +#define IDI_APPLY 185 +#define IDI_SHOW 186 +#define IDI_LOGO 187 +#define IDI_RENAME 188 +#define IDI_SERVER 189 +#define IDI_DCC 196 +#define IDR_SERVERS 200 +#define IDI_EDIT 201 +#define IDI_IRCQUESTION 202 +#define IDC_ENICK 1000 +#define IDC_USERID 1001 +#define IDC_INFO_NAME 1001 +#define IDC_NICK 1002 +#define IDC_LIST 1002 +#define IDC_INFO_AUTH 1002 +#define IDC_INFO_LISTVIEW 1002 +#define IDC_PORT 1003 +#define IDC_INFO_CHANNELS 1003 +#define IDC_INFO_LISTVIEW2 1003 +#define IDC_NAME 1004 +#define IDC_INFO_ADDRESS 1004 +#define IDC_PASS 1005 +#define IDC_INFO_SERVER 1005 +#define IDC_SERVER 1006 +#define IDC_INFO_ID 1006 +#define IDC_PERFORMEDIT 1007 +#define IDC_PORT2 1008 +#define IDC_INFO_AWAY2 1008 +#define IDC_NICK2 1009 +#define IDC_REPLY 1009 +#define IDC_SSL 1010 +#define IDC_PORT3 1010 +#define IDC_INFO_OTHER 1011 +#define IDC_EDIT 1012 +#define IDC_RETRYCOUNT 1013 +#define IDC_INFO_NICK 1013 +#define IDC_EDIT2 1013 +#define ID_INFO_GO 1017 +#define IDC_SERVERCOMBO 1022 +#define IDC_IDENT 1023 +#define IDC_IDENT_TIMED 1024 +#define IDC_RETRY 1029 +#define IDC_ADDSERVER 1031 +#define IDC_EDITSERVER 1032 +#define IDC_RETRYWAIT 1035 +#define IDC_IDENTSYSTEM 1036 +#define IDC_IDENTPORT 1037 +#define IDC_ONLINETIMER 1038 +#define IDC_FORCEVISIBLE 1039 +#define IDC_REJOINCHANNELS 1041 +#define IDC_REJOINONKICK 1042 +#define IDC_PERFORM 1043 +#define IDC_PERFORMCOMBO 1044 +#define IDC_DISABLEERROR 1044 +#define IDC_KEEPALIVE 1045 +#define IDC_ENABLEIP 1045 +#define IDC_ONLINENOTIF 1046 +#define IDC_CHANNELAWAY 1047 +#define IDC_USESERVER 1048 +#define IDC_SHOWSERVER 1049 +#define IDC_ADDRESS 1050 +#define IDC_AUTOJOIN 1051 +#define IDC_OLDSTYLE 1052 +#define IDC_ADD 1090 +#define IDC_DELETE 1091 +#define IDC_ALIASEDIT 1094 +#define IDC_REMOVE 1094 +#define IDC_APPLYTOPIC 1095 +#define IDC_APPLYMODES 1096 +#define IDC_DELETESERVER 1097 +#define IDC_ADD_COMBO 1100 +#define IDC_ADD_SERVER 1101 +#define IDC_ADD_ADDRESS 1102 +#define IDC_ADD_PORT 1103 +#define IDC_ADD_PORT2 1104 +#define IDC_CLOSE 1108 +#define IDC_JOIN 1109 +#define ID_INFO_OK 1110 +#define IDC_STARTUP 1133 +#define IDC_TEXT 1134 +#define IDC_DEFAULT 1139 +#define IDC_WILDCARD 1140 +#define IDC_USER 1141 +#define IDC_HOST 1142 +#define IDC_BUTTON 1143 +#define IDC_BUTTON2 1144 +#define IDC_CHECK1 1147 +#define IDC_CHECK2 1148 +#define IDC_CHECK3 1149 +#define IDC_CHECK4 1150 +#define IDC_CHECK5 1151 +#define IDC_CHECK6 1152 +#define IDC_CHECK7 1153 +#define IDC_CHECK8 1154 +#define IDC_KEY 1159 +#define IDC_LIMIT 1160 +#define IDC_TOPIC 1161 +#define IDC_RADIO1 1170 +#define IDC_RADIO2 1171 +#define IDC_RADIO3 1172 +#define IDC_HIDDENEDIT 1175 +#define IDC_NOTOP 1176 +#define IDC_WHITERECT 1179 +#define IDC_LOGO 1180 +#define IDC_CAPTION 1181 +#define IDC_OFF 1184 +#define IDC_AUTO 1185 +#define IDC_ON 1186 +#define IDC_QUITMESSAGE 1187 +#define IDC_USERINFO 1189 +#define IDC_PING 1190 +#define IDC_IP 1190 +#define IDC_VERSION 1191 +#define IDN_YES 1191 +#define IDC_PASSIVE 1191 +#define IDC_TIME 1192 +#define IDN_NO 1192 +#define IDC_PASSIVE2 1192 +#define IDC_SENDNOTICE 1192 +#define IDC_SLOW 1193 +#define IDC_FAST 1194 +#define IDC_COMBO 1196 +#define IDC_DISC 1197 +#define IDC_FROMSERVER 1201 +#define IDC_SCRIPT 1202 +#define IDC_MASK 1204 +#define IDC_Q 1205 +#define IDC_M 1206 +#define IDC_N 1207 +#define IDC_I 1208 +#define IDC_C 1209 +#define IDC_D 1210 +#define IDC_NETWORK 1211 +#define IDC_IGNORECHANNEL 1212 +#define IDC_ENABLEIGNORE 1213 +#define IDC_IGNOREFILE 1214 +#define IDC_IGNORECHAT 1215 +#define IDC_IGNOREUNKNOWN 1216 +#define IDC_CUSTOM 1218 +#define IDC_SPIN1 1219 +#define IDC_SPIN2 1220 +#define IDC_CODEPAGE 1222 +#define IDC_COMBO1 1223 +#define IDC_CHECK9 1224 +#define IDC_UTF_AUTODETECT 1225 +#define IDC_AWAYTIME 1226 +#define IDC_SSL_ON 1227 +#define IDC_SSL_AUTO 1228 +#define IDC_SSL_OFF 1229 +#define IDC_GRBOX_SSL 1230 +#define IDC_LIST1 1231 +#define IDC_EDIT1 1232 +#define IDC_STATICTEXT1 1233 +#define IDC_STATICTEXT2 1234 +#define IDC_FILTER_STRING 1235 +#define IDC_BUTTON1 1236 +#define IDC_FILTER_BTN 1237 +#define ID_MENU1_OP 40013 +#define ID_MENU1_DEOP 40014 +#define ID_MENU1_VOICE 40015 +#define ID_MENU1_DEVOICE 40016 +#define ID_MENU1_KICK 40017 +#define ID_MENU1_QUERY 40018 +#define ID_MENU1_WHOIS 40019 +#define IDM_COPYALL 40020 +#define IDM_SELECTALL 40022 +#define IDM_CLEAR 40023 +#define IDM_OPENNEW 40024 +#define IDM_OPENEXISTING 40025 +#define IDM_COPYLINK 40026 +#define IDM_COPY 40027 +#define IDM_JOIN 40028 +#define IDM_CHANGENICK 40029 +#define IDM_SHOWSERVER 40030 +#define IDM_LEAVECHAN 40031 +#define ID_MENU1_ADDCONTACT 40032 +#define IDM_CHANMANAGER 40033 +#define ID_MENU1_KICKREASON 40034 +#define ID_MENU1_BAN 40035 +#define ID_MENU1_BANKICK 40036 +#define ID_MENU1_BANKICKREASON 40037 +#define ID_MENU1_IGNORE_ON 40038 +#define ID_MENU1_IGNORE_OFF 40039 +#define ID_MENU1_OWNER 40040 +#define ID_MENU1_DEOWNER 40041 +#define ID_MENU1_ADMIN 40042 +#define ID_MENU1_DEADMIN 40043 +#define ID_MENU1_SENDNOTICE 40044 +#define ID_MENU1_INVITETOCHANNEL 40045 +#define ID_MENU1_SLAP 40046 +#define ID_MENU1_NICKSERV 40047 +#define ID_NICKSERV_REGISTERNICK 40048 +#define ID_NICKSERV_AUTHNICK 40049 +#define ID_NICKSERV_DELETENICK 40050 +#define ID_NICKSERV_IDENTIFY 40051 +#define ID_NICKSERV_SENDPASSWORD 40052 +#define ID_NICKSERV_SETTINGS 40053 +#define ID_SETTINGS_LANGUAGE 40054 +#define ID_SETTINGS_E 40055 +#define ID_SETTINGS_INFO 40056 +#define ID_SETTINGS_KILL 40057 +#define ID_NICKSERV_KILL 40058 +#define ID_KILL_OFF 40059 +#define ID_KILL_ON 40060 +#define ID_KILL_QUICK 40061 +#define ID_NICKSERV_PRIVATE 40062 +#define ID_PRIVATE_ON 40063 +#define ID_PRIVATE_OFF 40064 +#define ID_NICKSERV_SETNEWPASSWORD 40065 +#define ID_NICKSERV_ 40066 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 203 +#define _APS_NEXT_COMMAND_VALUE 40067 +#define _APS_NEXT_CONTROL_VALUE 1238 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/IRCG/src/scripting.cpp b/protocols/IRCG/src/scripting.cpp new file mode 100644 index 0000000000..26c6bc2a55 --- /dev/null +++ b/protocols/IRCG/src/scripting.cpp @@ -0,0 +1,265 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +INT_PTR __cdecl CIrcProto::Scripting_InsertRawIn(WPARAM, LPARAM lParam) +{ + char* pszRaw = ( char* ) lParam; + + if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { + TCHAR* p = mir_a2t( pszRaw ); + InsertIncomingEvent( p ); + mir_free( p ); + return 0; + } + + return 1; +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertRawOut( WPARAM, LPARAM lParam ) +{ + char* pszRaw = ( char* ) lParam; + if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { + String S = pszRaw; + ReplaceString( S, "%", "%%%%"); + NLSendNoScript((const unsigned char *)S.c_str(), lstrlenA(S.c_str())); + return 0; + } + + return 1; +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam) +{ + GCEVENT* gce = (GCEVENT *) lParam; + WPARAM_GUI_IN * wgi = (WPARAM_GUI_IN *) wParam; + + + if ( m_bMbotInstalled && m_scriptingEnabled && gce ) { + TCHAR* p1 = NULL; + CMString S; + if ( gce->pDest && gce->pDest->ptszID ) { + p1 = gce->pDest->ptszID; + S = MakeWndID(gce->pDest->ptszID); + gce->pDest->ptszID = ( TCHAR* )S.c_str(); + } + gce->cbSize = sizeof(GCEVENT); + + CallServiceSync( MS_GC_EVENT, wgi?wgi->wParam:0, (LPARAM)gce); + + if ( p1 ) + gce->pDest->ptszID = p1; + return 0; + } + + return 1; +} + +//helper functions +static void __stdcall OnHook(void * pi) +{ + GCHOOK* gch = ( GCHOOK* )pi; + + //Service_GCEventHook(1, (LPARAM) gch); + + if(gch->pszUID) + free(gch->pszUID); + if(gch->pszText) + free(gch->pszText); + if(gch->pDest->ptszID) + free(gch->pDest->ptszID); + if(gch->pDest->pszModule) + free(gch->pDest->pszModule); + delete gch->pDest; + delete gch; +} + +static void __cdecl GuiOutThread(LPVOID di) +{ + GCHOOK* gch = ( GCHOOK* )di; + CallFunctionAsync( OnHook, ( void* )gch ); +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertGuiOut( WPARAM, LPARAM lParam ) +{ + GCHOOK* gch = ( GCHOOK* )lParam; + + if ( m_bMbotInstalled && m_scriptingEnabled && gch ) { + GCHOOK* gchook = new GCHOOK; + gchook->pDest = new GCDEST; + + gchook->dwData = gch->dwData; + gchook->pDest->iType = gch->pDest->iType; + if ( gch->ptszText ) + gchook->ptszText = _tcsdup( gch->ptszText ); + else gchook->pszText = NULL; + + if ( gch->ptszUID ) + gchook->ptszUID = _tcsdup( gch->ptszUID ); + else gchook->pszUID = NULL; + + if ( gch->pDest->ptszID ) { + CMString S = MakeWndID( gch->pDest->ptszID ); + gchook->pDest->ptszID = _tcsdup( S.c_str()); + } + else gchook->pDest->ptszID = NULL; + + if ( gch->pDest->pszModule ) + gchook->pDest->pszModule = _strdup(gch->pDest->pszModule); + else gchook->pDest->pszModule = NULL; + + mir_forkthread( GuiOutThread, gchook ); + return 0; + } + + return 1; +} + +BOOL CIrcProto::Scripting_TriggerMSPRawIn( char** pszRaw ) +{ + int iVal = CallService( MS_MBOT_IRC_RAW_IN, (WPARAM)m_szModuleName, (LPARAM)pszRaw); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPRawOut(char ** pszRaw) +{ + int iVal = CallService( MS_MBOT_IRC_RAW_OUT, (WPARAM)m_szModuleName, (LPARAM)pszRaw); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce) +{ + WPARAM_GUI_IN wgi = {0}; + + wgi.pszModule = m_szModuleName; + wgi.wParam = *wparam; + if (gce->time == 0) + gce->time = time(0); + + int iVal = CallService( MS_MBOT_IRC_GUI_IN, (WPARAM)&wgi, (LPARAM)gce); + if ( iVal == 0 ) { + *wparam = wgi.wParam; + return TRUE; + } + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPGuiOut(GCHOOK* gch) +{ + int iVal = CallService( MS_MBOT_IRC_GUI_OUT, (WPARAM)m_szModuleName, (LPARAM)gch); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +INT_PTR __cdecl CIrcProto::Scripting_GetIrcData(WPARAM, LPARAM lparam) +{ + if ( m_bMbotInstalled && m_scriptingEnabled && lparam ) { + String sString = ( char* ) lparam, sRequest; + CMString sOutput, sChannel; + + int i = sString.Find("|"); + if ( i != -1 ) { + sRequest = sString.Mid(0, i); + TCHAR* p = mir_a2t(( char* )sString.Mid(i+1, sString.GetLength()).c_str()); + sChannel = p; + mir_free( p ); + } + else sRequest = sString; + + sRequest.MakeLower(); + + if (sRequest == "ownnick" && IsConnected()) + sOutput = m_info.sNick; + + else if (sRequest == "network" && IsConnected()) + sOutput = m_info.sNetwork; + + else if (sRequest == "primarynick") + sOutput = m_nick; + + else if (sRequest == "secondarynick") + sOutput = m_alternativeNick; + + else if (sRequest == "myip") + return ( INT_PTR )mir_strdup( m_manualHost ? m_mySpecifiedHostIP : + ( m_IPFromServer ) ? m_myHost : m_myLocalHost); + + else if (sRequest == "usercount" && !sChannel.IsEmpty()) { + CMString S = MakeWndID(sChannel.c_str()); + GC_INFO gci = {0}; + gci.Flags = BYID|COUNT; + gci.pszModule = m_szModuleName; + gci.pszID = (TCHAR*)S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) { + TCHAR szTemp[40]; + _sntprintf( szTemp, 35, _T("%u"), gci.iCount); + sOutput = szTemp; + } + } + else if (sRequest == "userlist" && !sChannel.IsEmpty()) { + CMString S = MakeWndID(sChannel.c_str()); + GC_INFO gci = {0}; + gci.Flags = BYID|USERS; + gci.pszModule = m_szModuleName; + gci.pszID = ( TCHAR* )S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) + return (INT_PTR)mir_strdup( gci.pszUsers ); + } + else if (sRequest == "channellist") { + CMString S = _T(""); + int i = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); + if ( i >= 0 ) { + int j = 0; + while (j < i) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX|ID; + gci.pszModule = m_szModuleName; + gci.iItem = j; + if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) { + if ( lstrcmpi( gci.pszID, SERVERWINDOW)) { + CMString S1 = gci.pszID; + int k = S1.Find(_T(" ")); + if ( k != -1 ) + S1 = S1.Mid(0, k); + S += S1 + _T(" "); + } } + j++; + } } + + if ( !S.IsEmpty()) + sOutput = ( TCHAR* )S.c_str(); + } + // send it to mbot + if ( !sOutput.IsEmpty()) + return ( INT_PTR )mir_t2a( sOutput.c_str()); + } + return 0; +} diff --git a/protocols/IRCG/src/services.cpp b/protocols/IRCG/src/services.cpp new file mode 100644 index 0000000000..e3b363ac15 --- /dev/null +++ b/protocols/IRCG/src/services.cpp @@ -0,0 +1,1254 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +BOOL bChatInstalled = FALSE, m_bMbotInstalled = FALSE; + +void CIrcProto::InitMainMenus(void) +{ + char temp[ MAXMODULELABELLENGTH ]; + char *d = temp + sprintf( temp, m_szModuleName ); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof( mi ); + mi.pszService = temp; + + if ( bChatInstalled ) { + HGENMENU hRoot = MO_GetProtoRootMenu( m_szModuleName ); + if ( hRoot == NULL ) { + // Root popupmenuitem + mi.ptszName = m_tszUserName; + mi.position = -1999901010; + mi.hParentMenu = HGENMENU_ROOT; + mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.icolibItem = GetIconHandle(IDI_MAIN); + hRoot = hMenuRoot = Menu_AddProtoMenuItem(&mi); + } + else { + if (hMenuRoot) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); + hMenuRoot = NULL; + } + + mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; + mi.pszName = LPGEN("&Quick connect"); + mi.icolibItem = GetIconHandle(IDI_QUICK); + strcpy( d, IRC_QUICKCONNECT ); + mi.position = 201001; + mi.hParentMenu = hRoot; + hMenuQuick = Menu_AddProtoMenuItem(&mi); + + if (m_iStatus != ID_STATUS_OFFLINE) mi.flags |= CMIF_GRAYED; + + mi.pszName = LPGEN("&Join channel"); + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_CHAT_JOIN);//GetIconHandle(IDI_JOIN); + strcpy( d, IRC_JOINCHANNEL ); + mi.position = 201002; + hMenuJoin = Menu_AddProtoMenuItem(&mi); + + mi.pszName = LPGEN("&Change your nickname"); + mi.icolibItem = GetIconHandle(IDI_RENAME); + strcpy( d, IRC_CHANGENICK ); + mi.position = 201003; + hMenuNick = Menu_AddProtoMenuItem(&mi); + + mi.pszName = LPGEN("Show the &list of available channels"); + mi.icolibItem = GetIconHandle(IDI_LIST); + strcpy( d, IRC_SHOWLIST ); + mi.position = 201004; + hMenuList = Menu_AddProtoMenuItem(&mi); + + if (m_useServer) mi.flags &= ~CMIF_GRAYED; + mi.pszName = LPGEN("&Show the server window"); + mi.icolibItem = GetIconHandle(IDI_SERVER); + strcpy( d, IRC_SHOWSERVER ); + mi.position = 201005; + hMenuServer = Menu_AddProtoMenuItem(&mi); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static HGENMENU hUMenuChanSettings, hUMenuWhois, hUMenuDisconnect, hUMenuIgnore; +static HANDLE hPreBuildContactMenu, hMenuChanSettings, hMenuWhois, hMenuDisconnect, hMenuIgnore; + +static CIrcProto* IrcGetInstanceByHContact(HANDLE hContact) +{ + char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return NULL; + + for (int i = 0; i < g_Instances.getCount(); i++) + if (!strcmp(szProto, g_Instances[i]->m_szModuleName)) + return g_Instances[i]; + + return NULL; +} + +static INT_PTR IrcMenuChanSettings(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuChanSettings(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuWhois(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuWhois(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuDisconnect(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuDisconnect(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuIgnore(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuIgnore(wParam, lParam) : 0; +} + +int IrcPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) +{ + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); + + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuPreBuild(wParam, lParam) : 0; +} + +void InitContactMenus(void) +{ + char temp[MAXMODULELABELLENGTH]; + char *d = temp + sprintf(temp, "IRC"); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.pszService = temp; + mi.flags = CMIF_ICONFROMICOLIB; + + mi.pszName = LPGEN("Channel &settings"); + mi.icolibItem = GetIconHandle(IDI_MANAGER); + strcpy(d, IRC_UM_CHANSETTINGS); + mi.popupPosition = 500090002; + hUMenuChanSettings = Menu_AddContactMenuItem(&mi); + hMenuChanSettings = CreateServiceFunction(temp, IrcMenuChanSettings); + + mi.pszName = LPGEN("&WhoIs info"); + mi.icolibItem = GetIconHandle(IDI_WHOIS); + strcpy(d, IRC_UM_WHOIS); + mi.popupPosition = 500090001; + hUMenuWhois = Menu_AddContactMenuItem(&mi); + hMenuWhois = CreateServiceFunction(temp, IrcMenuWhois); + + mi.pszName = LPGEN("Di&sconnect"); + mi.icolibItem = GetIconHandle(IDI_DELETE); + strcpy(d, IRC_UM_DISCONNECT); + mi.popupPosition = 500090001; + hUMenuDisconnect = Menu_AddContactMenuItem(&mi); + hMenuDisconnect = CreateServiceFunction(temp, IrcMenuDisconnect); + + mi.pszName = LPGEN("&Add to ignore list"); + mi.icolibItem = GetIconHandle(IDI_BLOCK); + strcpy(d, IRC_UM_IGNORE); + mi.popupPosition = 500090002; + hUMenuIgnore = Menu_AddContactMenuItem(&mi); + hMenuIgnore = CreateServiceFunction( temp, IrcMenuIgnore ); + + hPreBuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, IrcPrebuildContactMenu); +} + +void UninitContactMenus(void) +{ + UnhookEvent(hPreBuildContactMenu); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuChanSettings, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuWhois, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuDisconnect, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuIgnore, 0); + DestroyServiceFunction(hMenuChanSettings); + DestroyServiceFunction(hMenuWhois); + DestroyServiceFunction(hMenuDisconnect); + DestroyServiceFunction(hMenuIgnore); +} + +INT_PTR __cdecl CIrcProto::OnDoubleclicked(WPARAM, LPARAM lParam) +{ + if (!lParam) + return 0; + + CLISTEVENT* pcle = (CLISTEVENT*)lParam; + + if ( getByte((HANDLE) pcle->hContact, "DCC", 0) != 0) { + DCCINFO* pdci = ( DCCINFO* )pcle->lParam; + CMessageBoxDlg* dlg = new CMessageBoxDlg( this, pdci ); + dlg->Show(); + HWND hWnd = dlg->GetHwnd(); + TCHAR szTemp[500]; + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("%s (%s) is requesting a client-to-client chat connection."), + pdci->sContactName.c_str(), pdci->sHostmask.c_str()); + SetDlgItemText( hWnd, IDC_TEXT, szTemp ); + ShowWindow( hWnd, SW_SHOW ); + return 1; + } + return 0; +} + +int __cdecl CIrcProto::OnContactDeleted(WPARAM wp, LPARAM) +{ + HANDLE hContact = ( HANDLE )wp; + if ( !hContact ) + return 0; + + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + int type = getByte( hContact, "ChatRoom", 0 ); + if ( type != 0 ) { + GCEVENT gce = {0}; + GCDEST gcd = {0}; + CMString S = _T(""); + if (type == GCW_CHATROOM) + S = MakeWndID( dbv.ptszVal ); + if (type == GCW_SERVER) + S = SERVERWINDOW; + gce.cbSize = sizeof(GCEVENT); + gce.dwItemData = 0; + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + int i = CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + if (i && type == GCW_CHATROOM) + PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); + } + else { + BYTE bDCC = getByte(( HANDLE )wp, "DCC", 0) ; + if ( bDCC ) { + CDccSession* dcc = FindDCCSession((HANDLE)wp); + if ( dcc ) + dcc->Disconnect(); + } } + + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnJoinChat(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + DBVARIANT dbv; + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) + PostIrcMessage( _T("/JOIN %s"), dbv.ptszVal); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnLeaveChat(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + DBVARIANT dbv; + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) { + PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + CMString S = MakeWndID(dbv.ptszVal); + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + } + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuChanSettings(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + HANDLE hContact = (HANDLE) wp; + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + PostIrcMessageWnd(dbv.ptszVal, NULL, _T("/CHANNELMANAGER")); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuWhois(WPARAM wp, LPARAM) +{ + if ( !wp ) + return 0; + + DBVARIANT dbv; + + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + PostIrcMessage( _T("/WHOIS %s %s"), dbv.ptszVal, dbv.ptszVal); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuDisconnect(WPARAM wp, LPARAM) +{ + CDccSession* dcc = FindDCCSession((HANDLE)wp); + if ( dcc ) + dcc->Disconnect(); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuIgnore(WPARAM wp, LPARAM) +{ + if ( !wp ) + return 0; + + HANDLE hContact = (HANDLE) wp; + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == 0 ) { + char* host = NULL; + DBVARIANT dbv1; + if ( !getString((HANDLE) wp, "Host", &dbv1)) + host = dbv1.pszVal; + + if ( host ) { + String S; + if (m_ignoreChannelDefault) + S = "+qnidcm"; + else + S = "+qnidc"; + PostIrcMessage( _T("/IGNORE %%question=\"%s\",\"%s\",\"*!*@") _T(TCHAR_STR_PARAM) _T("\" %s"), + TranslateT("Please enter the hostmask (nick!user@host) \nNOTE! Contacts on your contact list are never ignored"), + TranslateT("Ignore"), host, S.c_str()); + DBFreeVariant(&dbv1); + } + } + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnJoinMenuCommand(WPARAM, LPARAM) +{ + if ( !m_joinDlg ) { + m_joinDlg = new CJoinDlg( this ); + m_joinDlg->Show(); + } + + SetDlgItemText( m_joinDlg->GetHwnd(), IDC_CAPTION, TranslateT("Join channel")); + SetWindowText( GetDlgItem( m_joinDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a channel to join")); + SendMessage( GetDlgItem( m_joinDlg->GetHwnd(), IDC_ENICK), EM_SETSEL, 0,MAKELPARAM(0,-1)); + ShowWindow( m_joinDlg->GetHwnd(), SW_SHOW); + SetActiveWindow( m_joinDlg->GetHwnd()); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnQuickConnectMenuCommand(WPARAM, LPARAM) +{ + if ( !m_quickDlg ) { + m_quickDlg = new CQuickDlg( this ); + m_quickDlg->Show(); + + SetWindowText( m_quickDlg->GetHwnd(), TranslateT( "Quick connect" )); + SetDlgItemText( m_quickDlg->GetHwnd(), IDC_TEXT, TranslateT( "Please select IRC network and enter the password if needed" )); + SetDlgItemText( m_quickDlg->GetHwnd(), IDC_CAPTION, TranslateT( "Quick connect" )); + WindowSetIcon( m_quickDlg->GetHwnd(), IDI_QUICK ); + } + + ShowWindow( m_quickDlg->GetHwnd(), SW_SHOW ); + SetActiveWindow( m_quickDlg->GetHwnd()); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnShowListMenuCommand(WPARAM, LPARAM) +{ + PostIrcMessage( _T("/LIST")); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnShowServerMenuCommand(WPARAM, LPARAM) +{ + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = SERVERWINDOW; + gce.dwFlags = GC_TCHAR; + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnChangeNickMenuCommand(WPARAM, LPARAM) +{ + if ( !m_nickDlg ) { + m_nickDlg = new CNickDlg( this ); + m_nickDlg->Show(); + } + + SetDlgItemText( m_nickDlg->GetHwnd(), IDC_CAPTION, TranslateT("Change nick name")); + SetWindowText( GetDlgItem( m_nickDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a unique nickname")); + m_nickDlg->m_Enick.SetText( m_info.sNick.c_str()); + m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); + ShowWindow( m_nickDlg->GetHwnd(), SW_SHOW); + SetActiveWindow( m_nickDlg->GetHwnd()); + return 0; +} + +static void DoChatFormatting( TCHAR* pszText ) +{ + TCHAR* p1 = pszText; + int iFG = -1; + int iRemoveChars; + TCHAR InsertThis[50]; + + while (*p1 != '\0') { + iRemoveChars = 0; + InsertThis[0] = 0; + + if ( *p1 == '%' ) { + switch ( p1[1] ) { + case 'B': + case 'b': + lstrcpy(InsertThis, _T("\002")); + iRemoveChars = 2; + break; + case 'I': + case 'i': + lstrcpy(InsertThis, _T("\026")); + iRemoveChars = 2; + break; + case 'U': + case 'u': + lstrcpy(InsertThis, _T("\037")); + iRemoveChars = 2; + break; + case 'c': + { + lstrcpy(InsertThis, _T("\003")); + iRemoveChars = 2; + + TCHAR szTemp[3]; + lstrcpyn(szTemp, p1 + 2, 3); + iFG = _ttoi(szTemp); + } + break; + case 'C': + if ( p1[2] == '%' && p1[3] == 'F') { + lstrcpy(InsertThis, _T("\00399,99")); + iRemoveChars = 4; + } + else { + lstrcpy(InsertThis, _T("\00399")); + iRemoveChars = 2; + } + iFG = -1; + break; + case 'f': + if (p1 - 3 >= pszText && p1[-3] == '\003') + lstrcpy(InsertThis, _T(",")); + else if ( iFG >= 0 ) + mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,"), iFG); + else + lstrcpy(InsertThis, _T("\00399,")); + + iRemoveChars = 2; + break; + + case 'F': + if (iFG >= 0) + mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,99"), iFG); + else + lstrcpy(InsertThis, _T("\00399,99")); + iRemoveChars = 2; + break; + + case '%': + lstrcpy(InsertThis, _T("%")); + iRemoveChars = 2; + break; + + default: + iRemoveChars = 2; + break; + } + + MoveMemory(p1 + lstrlen(InsertThis), p1 + iRemoveChars, sizeof(TCHAR)*(lstrlen(p1) - iRemoveChars + 1)); + CopyMemory(p1, InsertThis, sizeof(TCHAR)*lstrlen(InsertThis)); + if (iRemoveChars || lstrlen(InsertThis)) + p1 += lstrlen(InsertThis); + else + p1++; + } + else p1++; +} } + +int __cdecl CIrcProto::GCEventHook(WPARAM wParam,LPARAM lParam) +{ + GCHOOK *gchook= (GCHOOK*) lParam; + GCHOOK *gchtemp = NULL; + GCHOOK *gch = NULL; + CMString S = _T(""); + + EnterCriticalSection(&m_gchook); + + // handle the hook + if ( gchook ) { + if (!lstrcmpiA(gchook->pDest->pszModule, m_szModuleName)) { + + // first see if the scripting module should modify or stop this event + if (m_bMbotInstalled && m_scriptingEnabled && wParam == NULL) { + gchtemp = (GCHOOK *)mir_alloc(sizeof(GCHOOK)); + gchtemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); + gchtemp->pDest->iType = gchook->pDest->iType; + gchtemp->dwData = gchook->dwData; + + if ( gchook->pDest->ptszID ) { + gchtemp->pDest->ptszID = mir_tstrdup( gchook->pDest->ptszID ); + TCHAR* pTemp = _tcschr(gchtemp->pDest->ptszID, ' '); + if ( pTemp ) + *pTemp = '\0'; + } + else gchtemp->pDest->ptszID = NULL; + + //MBOT CORRECTIONS + gchook->pDest->pszModule = mir_strdup( gchook->pDest->pszModule ); + gchook->ptszText = mir_tstrdup( gchook->ptszText ); + gchook->ptszUID = mir_tstrdup( gchook->ptszUID ); + + if ( Scripting_TriggerMSPGuiOut(gchtemp) && gchtemp) + gch = gchtemp; + else + gch = NULL; + } + else gch = gchook; + + if ( gch ) { + TCHAR* p1 = mir_tstrdup( gch->pDest->ptszID ); + TCHAR* p2 = _tcsstr( p1, _T(" - ")); + if ( p2 ) + *p2 = '\0'; + + switch( gch->pDest->iType ) { + case GC_SESSION_TERMINATE: + FreeWindowItemData(p1, (CHANNELINFO*)gch->dwData); + break; + + case GC_USER_MESSAGE: + if (gch && gch->pszText && lstrlen(gch->ptszText) > 0 ) { + TCHAR* pszText = new TCHAR[lstrlen(gch->ptszText)+1000]; + lstrcpy(pszText, gch->ptszText); + DoChatFormatting(pszText); + PostIrcMessageWnd(p1, NULL, pszText); + delete []pszText; + } + break; + + case GC_USER_CHANMGR: + PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); + break; + + case GC_USER_PRIVMESS: + { + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/QUERY %s"), gch->ptszUID ); + PostIrcMessageWnd(p1, NULL, szTemp); + } + break; + + case GC_USER_LOGMENU: + switch( gch->dwData ) { + case 1: + OnChangeNickMenuCommand(NULL, NULL); + break; + case 2: + PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); + break; + + case 3: + PostIrcMessage( _T("/PART %s %s"), p1, m_userInfo ); + { GCEVENT gce = {0}; + GCDEST gcd = {0}; + S = MakeWndID(p1); + gce.cbSize = sizeof(GCEVENT); + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + } + break; + case 4: // show server window + PostIrcMessageWnd(p1, NULL, _T("/SERVERSHOW")); + break; +/* case 5: // nickserv register nick + PostIrcMessage( _T("/nickserv REGISTER %%question=\"%s\",\"%s\""), + TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); + break; +*/ case 6: // nickserv Identify + PostIrcMessage( _T("/nickserv AUTH %%question=\"%s\",\"%s\""), + TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); + break; + case 7: // nickserv drop nick + if (MessageBox(0, TranslateT("Are you sure you want to unregister your current nick?"), TranslateT("Delete nick"), + MB_ICONERROR + MB_YESNO + MB_DEFBUTTON2) == IDYES) + PostIrcMessage( _T("/nickserv DROP")); + break; + case 8: // nickserv Identify + { + CQuestionDlg* dlg = new CQuestionDlg( this ); + dlg->Show(); + HWND question_hWnd = dlg->GetHwnd(); + HWND hEditCtrl = GetDlgItem( question_hWnd, IDC_EDIT); + SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Identify nick")); + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter your password")); + SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, _T("/nickserv IDENTIFY %question=\"%s\",\"%s\"")); + SetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE, + (LONG)GetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE) | ES_PASSWORD); + SendMessage(hEditCtrl, EM_SETPASSWORDCHAR,(WPARAM)_T('*'),0 ); + SetFocus(hEditCtrl); + dlg->Activate(); + } + break; + case 9: // nickserv remind password + { + DBVARIANT dbv; + if ( !getTString( "Nick", &dbv )) { + PostIrcMessage( _T("/nickserv SENDPASS %s"), dbv.ptszVal); + DBFreeVariant( &dbv ); + } } + break; + case 10: // nickserv set new password + PostIrcMessage( _T("/nickserv SET PASSWORD %%question=\"%s\",\"%s\""), + TranslateT("Please enter your new password"), TranslateT("Set new password")); + break; + case 11: // nickserv set language + PostIrcMessage( _T("/nickserv SET LANGUAGE %%question=\"%s\",\"%s\""), + TranslateT("Please enter desired languageID (numeric value, depends on server)"), TranslateT("Change language of NickServ messages")); + break; + case 12: // nickserv set homepage + PostIrcMessage( _T("/nickserv SET URL %%question=\"%s\",\"%s\""), + TranslateT("Please enter URL that will be linked to your nick"), TranslateT("Set URL, linked to nick")); + break; + case 13: // nickserv set email + PostIrcMessage( _T("/nickserv SET EMAIL %%question=\"%s\",\"%s\""), + TranslateT("Please enter your e-mail, that will be linked to your nick"), TranslateT("Set e-mail, linked to nick")); + break; + case 14: // nickserv set info + PostIrcMessage( _T("/nickserv SET INFO %%question=\"%s\",\"%s\""), + TranslateT("Please enter some information about your nick"), TranslateT("Set information for nick")); + break; + case 15: // nickserv kill unauth off + PostIrcMessage( _T("/nickserv SET KILL OFF")); + break; + case 16: // nickserv kill unauth on + PostIrcMessage( _T("/nickserv SET KILL ON")); + break; + case 17: // nickserv kill unauth quick + PostIrcMessage( _T("/nickserv SET KILL QUICK")); + break; + case 18: // nickserv hide nick from /LIST + PostIrcMessage( _T("/nickserv SET PRIVATE ON")); + break; + case 19: // nickserv show nick to /LIST + PostIrcMessage( _T("/nickserv SET PRIVATE OFF")); + break; + case 20: // nickserv Hide e-mail from info + PostIrcMessage( _T("/nickserv SET HIDE EMAIL ON")); + break; + case 21: // nickserv Show e-mail in info + PostIrcMessage( _T("/nickserv SET HIDE EMAIL OFF")); + break; + case 22: // nickserv Set security for nick + PostIrcMessage( _T("/nickserv SET SECURE ON")); + break; + case 23: // nickserv Remove security for nick + PostIrcMessage( _T("/nickserv SET SECURE OFF")); + break; + case 24: // nickserv Link nick to current + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to link to your current nick"), TranslateT("Link another nick to current nick")); + break; + case 25: // nickserv Unlink nick from current + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to unlink from your current nick"), TranslateT("Unlink another nick from current nick")); + break; + case 26: // nickserv Set main nick + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to set as your main nick"), TranslateT("Set main nick")); + break; + case 27: // nickserv list all linked nicks + PostIrcMessage( _T("/nickserv LISTLINKS")); + break; + case 28: // nickserv list all channels owned + PostIrcMessage( _T("/nickserv LISTCHANS")); + break; + } + break; + + case GC_USER_NICKLISTMENU: + switch(gch->dwData) { + case 1: + PostIrcMessage( _T("/MODE %s +o %s"), p1, gch->ptszUID ); + break; + case 2: + PostIrcMessage( _T("/MODE %s -o %s"), p1, gch->ptszUID ); + break; + case 3: + PostIrcMessage( _T("/MODE %s +v %s"), p1, gch->ptszUID ); + break; + case 4: + PostIrcMessage( _T("/MODE %s -v %s"), p1, gch->ptszUID ); + break; + case 5: + PostIrcMessage( _T("/KICK %s %s"), p1, gch->ptszUID ); + break; + case 6: + PostIrcMessage( _T("/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), + p1, gch->ptszUID, TranslateT("Please enter the reason"), TranslateT("Kick"), TranslateT("Jerk")); + break; + case 7: + DoUserhostWithReason(1, _T("B") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 8: + DoUserhostWithReason(1, _T("K") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 9: + DoUserhostWithReason(1, _T("L") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 10: + PostIrcMessage( _T("/WHOIS %s %s"), gch->ptszUID, gch->ptszUID ); + break; + // case 11: + // DoUserhostWithReason(1, "I", true, "%s", gch->ptszUID ); + // break; + // case 12: + // DoUserhostWithReason(1, "J", true, "%s", gch->ptszUID ); + // break; + case 13: + PostIrcMessage( _T("/DCC CHAT %s"), gch->ptszUID ); + break; + case 14: + PostIrcMessage( _T("/DCC SEND %s"), gch->ptszUID ); + break; + case 15: + DoUserhostWithReason(1, _T("I"), true, _T("%s"), gch->ptszUID ); + break; + case 16: + PostIrcMessage( _T("/MODE %s +h %s"), p1, gch->ptszUID ); + break; + case 17: + PostIrcMessage( _T("/MODE %s -h %s"), p1, gch->ptszUID ); + break; + case 18: + PostIrcMessage( _T("/MODE %s +q %s"), p1, gch->ptszUID ); + break; + case 19: + PostIrcMessage( _T("/MODE %s -q %s"), p1, gch->ptszUID ); + break; + case 20: + PostIrcMessage( _T("/MODE %s +a %s"), p1, gch->ptszUID ); + break; + case 21: + PostIrcMessage( _T("/MODE %s -a %s"), p1, gch->ptszUID ); + break; + case 22: + PostIrcMessage( _T("/NOTICE %s %%question=\"%s\",\"%s\""), + gch->ptszUID, TranslateT("Please enter the notice text"), TranslateT("Send notice")); + break; + case 23: + PostIrcMessage( _T("/INVITE %s %%question=\"%s\",\"%s\""), + gch->ptszUID, TranslateT("Please enter the channel name to invite to"), TranslateT("Invite to channel")); + break; + case 30: + { + PROTOSEARCHRESULT psr = { 0 }; + psr.cbSize = sizeof(psr); + psr.flags = PSR_TCHAR; + psr.id = gch->ptszUID; + psr.nick = gch->ptszUID; + + ADDCONTACTSTRUCT acs = { 0 }; + acs.handleType = HANDLE_SEARCHRESULT; + acs.szProto = m_szModuleName; + acs.psr = &psr; + CallService( MS_ADDCONTACT_SHOW, (WPARAM)NULL, (LPARAM)&acs); + } + break; + case 31: //slap + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/slap %s"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + case 32: //nickserv info + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv INFO %s ALL"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + case 33: //nickserv ghost + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv GHOST %s"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + } + break; + } + mir_free( p1 ); + } } } + + if ( gchtemp ) { + mir_free(gchtemp->pszUID); + mir_free(gchtemp->pszText); + mir_free(gchtemp->pDest->ptszID); + mir_free(gchtemp->pDest->pszModule); + mir_free(gchtemp->pDest); + mir_free(gchtemp); + } + LeaveCriticalSection(&m_gchook); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static gc_item logItems[] = { + { LPGENT("&Change your nickname" ), 1, MENU_ITEM, FALSE }, + { LPGENT("Channel &settings" ), 2, MENU_ITEM, FALSE }, + { _T(""), 0, MENU_SEPARATOR, FALSE }, + { LPGENT("NickServ"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Register nick" ), 5, MENU_POPUPITEM, TRUE }, + { LPGENT("Auth nick" ), 6, MENU_POPUPITEM, FALSE }, + { LPGENT("Delete nick" ), 7, MENU_POPUPITEM, FALSE }, + { LPGENT("Identify nick" ), 8, MENU_POPUPITEM, FALSE }, + { LPGENT("Remind password " ), 9, MENU_POPUPITEM, FALSE }, + { LPGENT("Set new password" ), 10, MENU_POPUPITEM, TRUE }, + { LPGENT("Set language" ), 11, MENU_POPUPITEM, FALSE }, + { LPGENT("Set homepage" ), 12, MENU_POPUPITEM, FALSE }, + { LPGENT("Set e-mail" ), 13, MENU_POPUPITEM, FALSE }, + { LPGENT("Set info" ), 14, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Hide e-mail from info" ), 20, MENU_POPUPITEM, FALSE }, + { LPGENT("Show e-mail in info" ), 21, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Set security for nick" ), 22, MENU_POPUPITEM, FALSE }, + { LPGENT("Remove security for nick" ), 23, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Link nick to current" ), 24, MENU_POPUPITEM, FALSE }, + { LPGENT("Unlink nick from current" ), 25, MENU_POPUPITEM, FALSE }, + { LPGENT("Set main nick" ), 26, MENU_POPUPITEM, FALSE }, + { LPGENT("List all your nicks" ), 27, MENU_POPUPITEM, FALSE }, + { LPGENT("List your channels" ), 28, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Kill unauthorized: off" ), 15, MENU_POPUPITEM, FALSE }, + { LPGENT("Kill unauthorized: on" ), 16, MENU_POPUPITEM, FALSE }, + { LPGENT("Kill unauthorized: quick" ), 17, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Hide nick from list" ), 18, MENU_POPUPITEM, FALSE }, + { LPGENT("Show nick to list" ), 19, MENU_POPUPITEM, FALSE }, + { LPGENT("Show the server &window" ), 4, MENU_ITEM, FALSE }, + { _T(""), 0, MENU_SEPARATOR, FALSE }, + { LPGENT("&Leave the channel" ), 3, MENU_ITEM, FALSE } +}; + +static gc_item nickItems[] = { + { LPGENT("&WhoIs info"), 10, MENU_ITEM, FALSE }, //0 + { LPGENT("&Invite to channel"), 23, MENU_ITEM, FALSE }, + { LPGENT("Send ¬ice"), 22, MENU_ITEM, FALSE }, + { LPGENT("&Slap"), 31, MENU_ITEM, FALSE }, + { LPGENT("Nickserv info"), 32, MENU_ITEM, FALSE }, + { LPGENT("Nickserv kill ghost"), 33, MENU_ITEM, FALSE }, //5 + { LPGENT("&Control"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Give Owner"), 18, MENU_POPUPITEM, FALSE }, //7 + { LPGENT("Take Owner"), 19, MENU_POPUPITEM, FALSE }, + { LPGENT("Give Admin"), 20, MENU_POPUPITEM, FALSE }, + { LPGENT("Take Admin"), 21, MENU_POPUPITEM, FALSE }, //10 + { LPGENT("Give &Op"), 1, MENU_POPUPITEM, FALSE }, + { LPGENT("Take O&p"), 2, MENU_POPUPITEM, FALSE }, + { LPGENT("Give &Halfop"), 16, MENU_POPUPITEM, FALSE }, + { LPGENT("Take H&alfop"), 17, MENU_POPUPITEM, FALSE }, + { LPGENT("Give &Voice"), 3, MENU_POPUPITEM, FALSE }, //15 + { LPGENT("Take V&oice"), 4, MENU_POPUPITEM, FALSE }, + { _T(""), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("&Kick"), 5, MENU_POPUPITEM, FALSE }, + { LPGENT("Ki&ck (reason)"), 6, MENU_POPUPITEM, FALSE }, + { LPGENT("&Ban"), 7, MENU_POPUPITEM, FALSE }, //20 + { LPGENT("Ban'&n kick"), 8, MENU_POPUPITEM, FALSE }, + { LPGENT("Ban'n kick (&reason)"), 9, MENU_POPUPITEM, FALSE }, + { LPGENT("&Direct Connection"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Request &Chat"), 13, MENU_POPUPITEM, FALSE }, + { LPGENT("Send &File"), 14, MENU_POPUPITEM, FALSE }, //25 + { LPGENT("Add to &ignore list"), 15, MENU_ITEM, FALSE }, + { _T(""), 12, MENU_SEPARATOR, FALSE }, + { LPGENT("&Add User"), 30, MENU_ITEM, FALSE } +}; + +int __cdecl CIrcProto::GCMenuHook(WPARAM, LPARAM lParam) +{ + GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam; + if ( gcmi ) { + if ( !lstrcmpiA( gcmi->pszModule, m_szModuleName )) { + if ( gcmi->Type == MENU_ON_LOG ) { + if ( lstrcmpi( gcmi->pszID, SERVERWINDOW)) { + gcmi->nItems = SIZEOF(logItems); + gcmi->Item = logItems; + } + else gcmi->nItems = 0; + } + + if (gcmi->Type == MENU_ON_NICKLIST) { + CONTACT user ={ (TCHAR*)gcmi->pszUID, NULL, NULL, false, false, false}; + HANDLE hContact = CList_FindContact(&user); + + gcmi->nItems = SIZEOF(nickItems); + gcmi->Item = nickItems; + BOOL bIsInList = (hContact && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 0); + gcmi->Item[gcmi->nItems-1].bDisabled = bIsInList; + + unsigned long ulAdr = 0; + if (m_manualHost) + ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); + else + ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); + gcmi->Item[23].bDisabled = ulAdr == 0?TRUE:FALSE; //DCC submenu + + TCHAR stzChanName[100]; + const TCHAR* temp = _tcschr( gcmi->pszID, ' ' ); + int len = min((( temp == NULL ) ? lstrlen( gcmi->pszID ) : ( int )( temp - gcmi->pszID + 1 )), SIZEOF(stzChanName)-1 ); + lstrcpyn( stzChanName, gcmi->pszID, len ); + stzChanName[ len ] = 0; + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA,stzChanName, NULL, NULL, NULL, NULL, NULL, false, false, 0); + BOOL bServOwner = strchr(sUserModes.c_str(), 'q') == NULL?FALSE:TRUE; + BOOL bServAdmin = strchr(sUserModes.c_str(), 'a') == NULL?FALSE:TRUE; + BOOL bOwner = bServOwner?((wi->OwnMode>>4)&01):FALSE; + BOOL bAdmin = bServAdmin?((wi->OwnMode>>3)&01):FALSE; + BOOL bOp = strchr(sUserModes.c_str(), 'o') == NULL?FALSE:((wi->OwnMode>>2)&01); + BOOL bHalfop = strchr(sUserModes.c_str(), 'h') == NULL?FALSE:((wi->OwnMode>>1)&01); + + BOOL bForceEnable = GetAsyncKeyState(VK_CONTROL); + + gcmi->Item[6].bDisabled /* "Control" submenu */ = !(bForceEnable|| bHalfop || bOp || bAdmin || bOwner); + gcmi->Item[7].uType = gcmi->Item[8].uType = /* +/- Owner */ bServOwner?MENU_POPUPITEM:0; + gcmi->Item[9].uType = gcmi->Item[10].uType = /* +/- Admin */ bServAdmin?MENU_POPUPITEM:0; + gcmi->Item[7].bDisabled = gcmi->Item[8].bDisabled = gcmi->Item[9].bDisabled = gcmi->Item[10].bDisabled = /* +/- Owner/Admin */ + !(bForceEnable || bOwner); + gcmi->Item[11].bDisabled = gcmi->Item[12].bDisabled = gcmi->Item[13].bDisabled = gcmi->Item[14].bDisabled = /* +/- Op/hop */ + !(bForceEnable || bOp || bAdmin || bOwner); + } } } + + return 0; +} + +int __cdecl CIrcProto::OnPreShutdown(WPARAM, LPARAM) +{ + EnterCriticalSection(&cs); + + if ( m_perform && IsConnected()) + if ( DoPerform( "Event: Disconnect" )) + Sleep( 200 ); + + DisconnectAllDCCSessions( true ); + + if ( IsConnected()) + Disconnect(); + if ( m_listDlg ) + m_listDlg->Close(); + if ( m_nickDlg ) + m_nickDlg->Close(); + if ( m_joinDlg ) + m_joinDlg->Close(); + + LeaveCriticalSection(&cs); + return 0; +} + +int __cdecl CIrcProto::OnMenuPreBuild(WPARAM wParam, LPARAM) +{ + DBVARIANT dbv; + HANDLE hContact = ( HANDLE )wParam; + if ( !hContact ) + return 0; + + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS | CMIM_NAME | CMIM_ICON; + + char *szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) wParam, 0); + if ( szProto && !lstrcmpiA(szProto, m_szModuleName)) { + bool bIsOnline = getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE ? false : true; + if ( getByte(hContact, "ChatRoom", 0) == GCW_CHATROOM) { + // context menu for chatrooms + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + } + else if ( !getTString( hContact, "Default", &dbv )) { + // context menu for contact + BYTE bDcc = getByte( hContact, "DCC", 0) ; + + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + + clmi.flags = CMIM_FLAGS; + if ( bDcc ) { + // for DCC contact + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); + } + else { + // for normal contact + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + if ( !IsConnected()) + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); + + if (bIsOnline) { + DBVARIANT dbv3; + if ( !getString( hContact, "Host", &dbv3)) { + if (dbv3.pszVal[0] == 0) + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + DBFreeVariant( &dbv3 ); + } + } + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); + } + DBFreeVariant( &dbv ); + } } + + return 0; +} + +int __cdecl CIrcProto::OnDbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = ( HANDLE ) wParam; + if ( hContact == NULL || !IsConnected()) + return 0; + + DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam; + if ( strcmp( cws->szModule, "CList" )) + return 0; + + if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 )) + return 0; + + if ( !strcmp( cws->szSetting, "NotOnList" )) { + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + if ( getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), dbv.ptszVal ); + DBFreeVariant( &dbv ); + } } + return 0; +} +void __cdecl CIrcProto::ConnectServerThread( void* ) +{ + InterlockedIncrement((long *) &m_bConnectThreadRunning); + InterlockedIncrement((long *) &m_bConnectRequested); + while ( !Miranda_Terminated() && m_bConnectRequested > 0 ) { + while(m_bConnectRequested > 0) + InterlockedDecrement((long *) &m_bConnectRequested); + if (IsConnected()) { + Sleep(200); + Disconnect(); + } + + m_info.bNickFlag = false; + int Temp = m_iStatus; + m_iStatus = ID_STATUS_CONNECTING; + nickflag = true; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_CONNECTING); + Sleep(100); + EnterCriticalSection(&cs); + Connect(si); + LeaveCriticalSection(&cs); + if (IsConnected()) { + KillChatTimer( RetryTimer ); + + if ( m_mySpecifiedHost[0] ) + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_mySpecifiedHost, IP_MANUAL )); + + DoEvent(GC_EVENT_CHANGESESSIONAME, SERVERWINDOW, NULL, m_info.sNetwork.c_str(), NULL, NULL, NULL, FALSE, TRUE); + } + else { + Temp = m_iDesiredStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_OFFLINE); + Sleep(100); + } } + + InterlockedDecrement((long *) &m_bConnectThreadRunning); +} + +void __cdecl CIrcProto::DisconnectServerThread( void* ) +{ + EnterCriticalSection( &cs ); + KillChatTimer( RetryTimer ); + if ( IsConnected()) + Disconnect(); + LeaveCriticalSection( &cs ); + return; +} + +void CIrcProto::ConnectToServer(void) +{ + m_portCount = StrToIntA(m_portStart); + si.sServer = GetWord(m_serverName, 0); + si.iPort = m_portCount; + si.sNick = m_nick; + si.sUserID = m_userID; + si.sFullName = m_name; + si.sPassword = m_password; + si.bIdentServer = ((m_ident) ? (true) : (false)); + si.iIdentServerPort = StrToInt(m_identPort); + si.sIdentServerType = m_identSystem; + si.m_iSSL = m_iSSL; + { TCHAR* p = mir_a2t( m_network ); + si.sNetwork = p; + mir_free(p); + } + m_iRetryCount = 1; + KillChatTimer(RetryTimer); + if (m_retry) { + if (StrToInt(m_retryWait)<10) + lstrcpy(m_retryWait, _T("10")); + SetChatTimer(RetryTimer, StrToInt(m_retryWait)*1000, RetryTimerProc); + } + + bPerformDone = false; + bTempDisableCheck = false; + bTempForceCheck = false; + m_iTempCheckTime = 0; + sChannelPrefixes = _T("&#"); + sUserModes = "ov"; + sUserModePrefixes = _T("@+"); + sChannelModes = "btnimklps"; + + if (!m_bConnectThreadRunning) + ircFork( &CIrcProto::ConnectServerThread, 0 ); + else if (m_bConnectRequested < 1) + InterlockedIncrement((long *) &m_bConnectRequested); + + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)"), + TranslateT("Connecting to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); +} + +void CIrcProto::DisconnectFromServer(void) +{ + GCEVENT gce = {0}; + GCDEST gcd = {0}; + + if ( m_perform && IsConnected()) + DoPerform( "Event: Disconnect" ); + + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = NULL; // all windows + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + ircFork( &CIrcProto::DisconnectServerThread, 0 ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// GetMyAwayMsg - obtain the current away message + +INT_PTR __cdecl CIrcProto::GetMyAwayMsg(WPARAM wParam,LPARAM lParam) +{ + if (( int )wParam != m_iStatus ) + return 0; + + const TCHAR* p = m_statusMessage.c_str(); + + return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_t2u(p) : (INT_PTR)mir_t2a(p); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Service function creation + +VOID CALLBACK RetryTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( ppro->m_iRetryCount <= StrToInt( ppro->m_retryCount) && ppro->m_retry ) { + ppro->m_portCount++; + if ( ppro->m_portCount > StrToIntA( ppro->m_portEnd ) || StrToIntA( ppro->m_portEnd ) == 0 ) + ppro->m_portCount = StrToIntA( ppro->m_portStart ); + ppro->si.iPort = ppro->m_portCount; + + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u, try %u)"), + TranslateT("Reconnecting to"), ppro->si.sNetwork.c_str(), ppro->si.sServer.c_str(), ppro->si.iPort, ppro->m_iRetryCount); + + ppro->DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); + + if ( !ppro->m_bConnectThreadRunning ) + ppro->ircFork( &CIrcProto::ConnectServerThread, 0 ); + else + ppro->m_bConnectRequested = true; + + ppro->m_iRetryCount++; + } + else ppro->KillChatTimer( ppro->RetryTimer ); +} + +// logs text into NetLib (stolen from Jabber ;)) +void CIrcProto::DoNetlibLog( const char* fmt, ... ) +{ + va_list vararg; + va_start( vararg, fmt ); + char* str = ( char* )alloca( 32000 ); + mir_vsnprintf( str, 32000, fmt, vararg ); + va_end( vararg ); + + CallService( MS_NETLIB_LOG, ( WPARAM )hNetlib, ( LPARAM )str ); +} diff --git a/protocols/IRCG/src/tools.cpp b/protocols/IRCG/src/tools.cpp new file mode 100644 index 0000000000..83ac7ae60f --- /dev/null +++ b/protocols/IRCG/src/tools.cpp @@ -0,0 +1,905 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Standard functions + +int CIrcProto::getByte( const char* name, BYTE defaultValue ) +{ return DBGetContactSettingByte( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getByte( HANDLE hContact, const char* name, BYTE defaultValue ) +{ return DBGetContactSettingByte(hContact, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getDword( const char* name, DWORD defaultValue ) +{ return DBGetContactSettingDword( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getDword( HANDLE hContact, const char* name, DWORD defaultValue ) +{ return DBGetContactSettingDword(hContact, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getString( const char* name, DBVARIANT* result ) +{ return DBGetContactSettingString( NULL, m_szModuleName, name, result ); +} + +int CIrcProto::getString( HANDLE hContact, const char* name, DBVARIANT* result ) +{ return DBGetContactSettingString( hContact, m_szModuleName, name, result ); +} + +int CIrcProto::getTString( const char* name, DBVARIANT* result ) +{ return DBGetContactSettingTString( NULL, m_szModuleName, name, result ); +} + +int CIrcProto::getTString( HANDLE hContact, const char* name, DBVARIANT* result ) +{ return DBGetContactSettingTString( hContact, m_szModuleName, name, result ); +} + +int CIrcProto::getWord( const char* name, WORD defaultValue ) +{ return DBGetContactSettingWord( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getWord( HANDLE hContact, const char* name, WORD defaultValue ) +{ return DBGetContactSettingWord(hContact, m_szModuleName, name, defaultValue ); +} + +void CIrcProto::setByte( const char* name, BYTE value ) +{ DBWriteContactSettingByte(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setByte( HANDLE hContact, const char* name, BYTE value ) +{ DBWriteContactSettingByte(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setDword( const char* name, DWORD value ) +{ DBWriteContactSettingDword(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setDword( HANDLE hContact, const char* name, DWORD value ) +{ DBWriteContactSettingDword(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setString( const char* name, const char* value ) +{ DBWriteContactSettingString(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setString( HANDLE hContact, const char* name, const char* value ) +{ DBWriteContactSettingString(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setTString( const char* name, const TCHAR* value ) +{ DBWriteContactSettingTString(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setTString( HANDLE hContact, const char* name, const TCHAR* value ) +{ DBWriteContactSettingTString(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setWord( const char* name, int value ) +{ DBWriteContactSettingWord(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setWord( HANDLE hContact, const char* name, int value ) +{ DBWriteContactSettingWord(hContact, m_szModuleName, name, value ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIrcProto::AddToJTemp(TCHAR op, CMString& sCommand) +{ + CMString res; + + int pos = 0; + for ( ;; ) { + CMString tmp = sCommand.Tokenize( _T(","), pos ); + if ( pos == -1 ) + break; + + tmp = op + tmp; + if ( res.IsEmpty()) + res = tmp; + else + res += _T(" ") + tmp; + } + + DBVARIANT dbv; + if ( !getTString( "JTemp", &dbv )) { + res = CMString(dbv.ptszVal) + _T(" ") + res; + DBFreeVariant( &dbv ); + } + + setTString("JTemp", res.c_str()); +} + +void CIrcProto::ircFork( IrcThreadFunc pFunc, void* arg ) +{ + unsigned threadID; + CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID )); +} + +HANDLE CIrcProto::ircForkEx( IrcThreadFunc pFunc, void* arg ) +{ + unsigned threadID; + return (HANDLE)::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID ); +} + +void CIrcProto::IrcHookEvent( const char* szEvent, IrcEventFunc pFunc ) +{ + ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&pFunc, this ); +} + +CMString __stdcall GetWord(const TCHAR* text, int index) +{ + if ( text && *text ) { + TCHAR* p1 = (TCHAR*)text; + TCHAR* p2 = NULL; + + while (*p1 == ' ') + p1++; + + if (*p1 != '\0') { + for (int i =0; i < index; i++) { + p2 = _tcschr( p1, ' ' ); + if ( !p2 ) + p2 = _tcschr( p1, '\0' ); + else + while ( *p2 == ' ' ) + p2++; + + p1 = p2; + } + + p2 = _tcschr(p1, ' '); + if ( !p2 ) + p2 = _tcschr(p1, '\0'); + + if (p1 != p2) + return CMString( p1, p2-p1 ); + } } + + return CMString(); +} + +const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index) +{ + if ( !text || !lstrlen(text)) + return text; + + const TCHAR* temp = text; + + while (*temp == ' ') + temp++; + + if (index == 0) + return temp; + + for (int i = 0; i < index; i++) { + temp = _tcschr(temp, ' '); + if ( !temp ) + temp = ( TCHAR* )_tcschr(text, '\0'); + else + while (*temp == ' ') + temp++; + text = temp; + } + + return temp; +} + +void __stdcall RemoveLinebreaks( CMString& Message ) +{ + while ( Message.Find( _T("\r\n\r\n"), 0) != -1 ) + ReplaceString( Message, _T("\r\n\r\n"), _T("\r\n")); + + if (Message.Find( _T("\r\n"), 0) == 0) + Message.Delete(0,2); + + if ( (Message.GetLength() > 1) && (Message.Find(_T("\r\n"), Message.GetLength()-2) == 0)) + Message.Delete(Message.GetLength()-2, 2); +} + +String& __stdcall ReplaceString ( String& text, const char* replaceme, const char* newword ) +{ + if ( !text.IsEmpty() && replaceme != NULL) { + int i = 0; + while (( i = text.Find(replaceme, i)) != -1 ) { + text.Delete(i,lstrlenA(replaceme)); + text.Insert(i, newword); + i = i + lstrlenA(newword); + } } + + return text; +} + +CMString& __stdcall ReplaceString ( CMString& text, const TCHAR* replaceme, const TCHAR* newword) +{ + if ( !text.IsEmpty() && replaceme != NULL) { + int i = 0; + while (( i = text.Find(replaceme, i)) != -1 ) { + text.Delete(i,lstrlen(replaceme)); + text.Insert(i, newword); + i = i + lstrlen(newword); + } } + + return text; +} + +char* __stdcall IrcLoadFile( TCHAR* szPath) +{ + char * szContainer = NULL; + DWORD dwSiz = 0; + FILE *hFile = _tfopen(szPath, _T("rb")); + if ( hFile != NULL ) + { + fseek(hFile,0,SEEK_END); // seek to end + dwSiz = ftell(hFile); // size + fseek(hFile,0,SEEK_SET); // seek back to original pos + szContainer = new char [dwSiz+1]; + fread(szContainer, 1, dwSiz, hFile); + szContainer[dwSiz] = '\0'; + fclose(hFile); + return szContainer; + } + + return 0; +} + +int __stdcall WCCmp( const TCHAR* wild, const TCHAR* string ) +{ + if ( wild == NULL || !lstrlen(wild) || string == NULL || !lstrlen(string)) + return 1; + + const TCHAR *cp = NULL, *mp = NULL; + while ((*string) && (*wild != '*')) { + if ((*wild != *string) && (*wild != '?')) + return 0; + + wild++; + string++; + } + + while (*string) { + if (*wild == '*') { + if (!*++wild) + return 1; + + mp = wild; + cp = string+1; + } + else if ((*wild == *string) || (*wild == '?')) { + wild++; + string++; + } + else { + wild = mp; + string = cp++; + } } + + while (*wild == '*') + wild++; + + return !*wild; +} + +bool CIrcProto::IsChannel(const TCHAR* sName) +{ + return ( sChannelPrefixes.Find( sName[0] ) != -1 ); +} + +String __stdcall GetWord(const char* text, int index) +{ + if ( text && text[0] ) { + char* p1 = (char*)text; + char* p2 = NULL; + + while (*p1 == ' ') + p1++; + + if (*p1 != '\0') { + for (int i =0; i < index; i++) { + p2 = strchr( p1, ' ' ); + if ( !p2 ) + p2 = strchr( p1, '\0' ); + else + while ( *p2 == ' ' ) + p2++; + + p1 = p2; + } + + p2 = strchr(p1, ' '); + if (!p2) + p2 = strchr(p1, '\0'); + + if (p1 != p2) + return String( p1, p2-p1+1 ); + } } + + return String(); +} + +bool CIrcProto::IsChannel(const char* sName) +{ + return ( sChannelPrefixes.Find( sName[0] ) != -1 ); +} + +TCHAR* __stdcall my_strstri(const TCHAR* s1, const TCHAR* s2) +{ + int i,j,k; + for(i=0;s1[i];i++) + for(j=i,k=0; _totlower(s1[j]) == _totlower(s2[k]);j++,k++) + if (!s2[k+1]) + return ( TCHAR* )(s1+i); + + return NULL; +} + +TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent) +{ + static TCHAR szTemp[4000]; szTemp[0] = '\0'; + TCHAR* p = szTemp; + bool bBold = false; + bool bUnderline = false; + bool bItalics = false; + + if ( !text ) + return szTemp; + + while ( *text != '\0' ) { + int iFG = -1; + int iBG = -1; + + switch( *text ) { + case '%': //escape + *p++ = '%'; + if ( bReplacePercent ) + *p++ = '%'; + text++; + break; + + case 2: //bold + if ( !bStrip ) { + *p++ = '%'; + *p++ = bBold ? 'B' : 'b'; + } + bBold = !bBold; + text++; + break; + + case 15: //reset + if ( !bStrip ) { + *p++ = '%'; + *p++ = 'r'; + } + bUnderline = false; + bBold = false; + text++; + break; + + case 22: //italics + if ( !bStrip ) { + *p++ = '%'; + *p++ = bItalics ? 'I' : 'i'; + } + bItalics = !bItalics; + text++; + break; + + case 31: //underlined + if ( !bStrip ) { + *p++ = '%'; + *p++ = bUnderline ? 'U' : 'u'; + } + bUnderline = !bUnderline; + text++; + break; + + case 3: //colors + text++; + + // do this if the colors should be reset to default + if ( *text <= 47 || *text >= 58 || *text == '\0' ) { + if ( !bStrip ) { + *p++ = '%'; + *p++ = 'C'; + *p++ = '%'; + *p++ = 'F'; + } + break; + } + else { // some colors should be set... need to find out who + TCHAR buf[3]; + + // fix foreground index + if ( text[1] > 47 && text[1] < 58 && text[1] != '\0') + lstrcpyn( buf, text, 3 ); + else + lstrcpyn( buf, text, 2 ); + text += lstrlen( buf ); + iFG = _ttoi( buf ); + + // fix background color + if ( *text == ',' && text[1] > 47 && text[1] < 58 && text[1] != '\0' ) { + text++; + + if ( text[1] > 47 && text[1] < 58 && text[1] != '\0' ) + lstrcpyn( buf, text, 3 ); + else + lstrcpyn( buf, text, 2 ); + text += lstrlen( buf ); + iBG = _ttoi( buf ); + } } + + if ( iFG >= 0 && iFG != 99 ) + while( iFG > 15 ) + iFG -= 16; + if ( iBG >= 0 && iBG != 99 ) + while( iBG > 15 ) + iBG -= 16; + + // create tag for chat.dll + if ( !bStrip ) { + TCHAR buf[10]; + if ( iFG >= 0 && iFG != 99 ) { + *p++ = '%'; + *p++ = 'c'; + + mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iFG ); + for (int i = 0; i<2; i++) + *p++ = buf[i]; + } + else if (iFG == 99) { + *p++ = '%'; + *p++ = 'C'; + } + + if ( iBG >= 0 && iBG != 99 ) { + *p++ = '%'; + *p++ = 'f'; + + mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iBG ); + for ( int i = 0; i<2; i++ ) + *p++ = buf[i]; + } + else if ( iBG == 99 ) { + *p++ = '%'; + *p++ = 'F'; + } } + break; + + default: + *p++ = *text++; + break; + } } + + *p = '\0'; + return szTemp; +} + +INT_PTR CIrcProto::CallChatEvent(WPARAM wParam, LPARAM lParam) +{ + GCEVENT * gce = (GCEVENT *)lParam; + INT_PTR iVal = 0; + + // first see if the scripting module should modify or stop this event + if ( m_bMbotInstalled && m_scriptingEnabled && gce + && gce->time != 0 && (gce->pDest->pszID == NULL + || lstrlen(gce->pDest->ptszID) != 0 && lstrcmpi(gce->pDest->ptszID , SERVERWINDOW))) + { + GCEVENT *gcevent= (GCEVENT*) lParam; + GCEVENT *gcetemp = NULL; + WPARAM wp = wParam; + gcetemp = (GCEVENT *)mir_alloc(sizeof(GCEVENT)); + gcetemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); + gcetemp->pDest->iType = gcevent->pDest->iType; + gcetemp->dwFlags = gcevent->dwFlags; + gcetemp->bIsMe = gcevent->bIsMe; + gcetemp->cbSize = sizeof(GCEVENT); + gcetemp->dwItemData = gcevent->dwItemData; + gcetemp->time = gcevent->time; + gcetemp->pDest->ptszID = mir_tstrdup( gcevent->pDest->ptszID ); + gcetemp->pDest->pszModule = mir_strdup( gcevent->pDest->pszModule ); + gcetemp->ptszText = mir_tstrdup( gcevent->ptszText ); + gcetemp->ptszUID = mir_tstrdup( gcevent->ptszUID ); + gcetemp->ptszNick = mir_tstrdup( gcevent->ptszNick ); + gcetemp->ptszStatus = mir_tstrdup( gcevent->ptszStatus ); + gcetemp->ptszUserInfo = mir_tstrdup( gcevent->ptszUserInfo ); + + if ( Scripting_TriggerMSPGuiIn( &wp, gcetemp ) && gcetemp ) { + //MBOT CORRECTIONS + //if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID ) { + if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID && + !my_strstri(gcetemp->pDest->ptszID, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline"))) { + + CMString sTempId = MakeWndID( gcetemp->pDest->ptszID ); + mir_realloc( gcetemp->pDest->ptszID, sizeof(TCHAR)*(sTempId.GetLength() + 1)); + lstrcpyn(gcetemp->pDest->ptszID, sTempId.c_str(), sTempId.GetLength()+1); + } + iVal = CallServiceSync(MS_GC_EVENT, wp, (LPARAM) gcetemp); + } + + if ( gcetemp ) { + mir_free(( void* )gcetemp->pszNick); + mir_free(( void* )gcetemp->pszUID); + mir_free(( void* )gcetemp->pszStatus); + mir_free(( void* )gcetemp->pszUserInfo); + mir_free(( void* )gcetemp->pszText); + mir_free(( void* )gcetemp->pDest->pszID); + mir_free(( void* )gcetemp->pDest->pszModule); + mir_free(( void* )gcetemp->pDest); + mir_free(( void* )gcetemp); + } + + return iVal; + } + + return CallServiceSync( MS_GC_EVENT, wParam, ( LPARAM )gce ); +} + +INT_PTR CIrcProto::DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, + const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, + DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe, time_t timestamp) +{ + GCDEST gcd = {0}; + GCEVENT gce = {0}; + CMString sID; + CMString sText = _T(""); + + if ( iEvent == GC_EVENT_INFORMATION && bIsMe && !bEcho ) + return false; + + if ( pszText ) { + if (iEvent != GC_EVENT_SENDMESSAGE) + sText = DoColorCodes(pszText, FALSE, TRUE); + else + sText = pszText; + } + + if ( pszWindow ) { + if ( lstrcmpi( pszWindow, SERVERWINDOW)) + sID = pszWindow + (CMString)_T(" - ") + m_info.sNetwork; + else + sID = pszWindow; + gcd.ptszID = (TCHAR*)sID.c_str(); + } + else gcd.ptszID = NULL; + + gcd.pszModule = m_szModuleName; + gcd.iType = iEvent; + + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.ptszStatus = pszStatus; + gce.dwFlags = GC_TCHAR + ((bAddToLog) ? GCEF_ADDTOLOG : 0); + gce.ptszNick = pszNick; + gce.ptszUID = pszNick; + if (iEvent == GC_EVENT_TOPIC) + gce.ptszUserInfo = pszUserInfo; + else + gce.ptszUserInfo = m_showAddresses ? pszUserInfo : NULL; + + if ( !sText.IsEmpty()) + gce.ptszText = sText.c_str(); + + gce.dwItemData = dwItemData; + if(timestamp == 1) + gce.time = time(NULL); + else + gce.time = timestamp; + gce.bIsMe = bIsMe; + return CallChatEvent((WPARAM)0, (LPARAM)&gce); +} + +CMString CIrcProto::ModeToStatus(int sMode) +{ + if ( sUserModes.Find( sMode ) != -1 ) { + switch( sMode ) { + case 'q': + return (CMString)_T("Owner"); + case 'o': + return (CMString)_T("Op"); + case 'v': + return (CMString)_T("Voice"); + case 'h': + return (CMString)_T("Halfop"); + case 'a': + return (CMString)_T("Admin"); + default: + return (CMString)_T("Unknown"); + } } + + return (CMString)_T("Normal"); +} + +CMString CIrcProto::PrefixToStatus(int cPrefix) +{ + const TCHAR* p = _tcschr( sUserModePrefixes.c_str(), cPrefix ); + if ( p ) { + int index = int( p - sUserModePrefixes.c_str()); + return ModeToStatus( sUserModes[index] ); + } + + return (CMString)_T("Normal"); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Timer functions + +struct TimerPair +{ + TimerPair( CIrcProto* _pro, UINT_PTR _id ) : + ppro( _pro ), + idEvent( _id ) + {} + + UINT_PTR idEvent; + CIrcProto* ppro; +}; + +static int CompareTimers( const TimerPair* p1, const TimerPair* p2 ) +{ + if ( p1->idEvent < p2->idEvent ) + return -1; + return ( p1->idEvent == p2->idEvent ) ? 0 : 1; +} + +static OBJLIST timers( 10, CompareTimers ); +static CRITICAL_SECTION timers_cs; + +void InitTimers( void ) +{ + InitializeCriticalSection( &timers_cs ); +} + +void UninitTimers( void ) +{ + EnterCriticalSection( &timers_cs ); + timers.destroy(); + LeaveCriticalSection( &timers_cs ); + DeleteCriticalSection( &timers_cs ); +} + +CIrcProto* GetTimerOwner( UINT_PTR nIDEvent ) +{ + CIrcProto* result; + + EnterCriticalSection( &timers_cs ); + TimerPair temp( NULL, nIDEvent ); + int idx = timers.getIndex( &temp ); + if ( idx == -1 ) + result = NULL; + else + result = timers[ idx ].ppro; + LeaveCriticalSection( &timers_cs ); + return result; +} + +void CIrcProto::SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc) +{ + if (nIDEvent) + KillChatTimer(nIDEvent); + + nIDEvent = SetTimer( NULL, NULL, uElapse, lpTimerFunc); + + EnterCriticalSection( &timers_cs ); + timers.insert( new TimerPair( this, nIDEvent )); + LeaveCriticalSection( &timers_cs ); +} + +void CIrcProto::KillChatTimer(UINT_PTR &nIDEvent) +{ + if ( nIDEvent ) { + EnterCriticalSection( &timers_cs ); + TimerPair temp( this, nIDEvent ); + int idx = timers.getIndex( &temp ); + if ( idx != -1 ) + timers.remove( idx ); + + LeaveCriticalSection( &timers_cs ); + + KillTimer(NULL, nIDEvent); + nIDEvent = NULL; +} } + +///////////////////////////////////////////////////////////////////////////////////////// + +int CIrcProto::SetChannelSBText(CMString sWindow, CHANNELINFO * wi) +{ + CMString sTemp = _T(""); + if(wi->pszMode) + { + sTemp += _T("["); + sTemp += wi->pszMode; + sTemp += _T("] "); + } + if(wi->pszTopic) + sTemp += wi->pszTopic; + sTemp = DoColorCodes(sTemp.c_str(), TRUE, FALSE); + return DoEvent(GC_EVENT_SETSBTEXT, sWindow.c_str(), NULL, sTemp.c_str(), NULL, NULL, NULL, FALSE, FALSE, 0); +} + +CMString CIrcProto::MakeWndID(const TCHAR* sWindow) +{ + TCHAR buf[200]; + mir_sntprintf( buf, SIZEOF(buf), _T("%s - %s"), sWindow, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline")); + return CMString(buf); +} + +bool CIrcProto::FreeWindowItemData(CMString window, CHANNELINFO* wis) +{ + CHANNELINFO* wi; + if ( !wis ) + wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + else + wi = wis; + if ( wi ) { + delete[] wi->pszLimit; + delete[]wi->pszMode; + delete[]wi->pszPassword; + delete[]wi->pszTopic; + delete wi; + return true; + } + return false; +} + +bool CIrcProto::AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic) +{ + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + if ( pszLimit ) { + wi->pszLimit = ( TCHAR* )realloc( wi->pszLimit, sizeof(TCHAR)*(lstrlen(pszLimit)+1)); + lstrcpy( wi->pszLimit, pszLimit ); + } + if ( pszMode ) { + wi->pszMode = ( TCHAR* )realloc( wi->pszMode, sizeof(TCHAR)*(lstrlen(pszMode)+1)); + lstrcpy( wi->pszMode, pszMode ); + } + if ( pszPassword ) { + wi->pszPassword = ( TCHAR* )realloc( wi->pszPassword, sizeof(TCHAR)*(lstrlen(pszPassword)+1)); + lstrcpy( wi->pszPassword, pszPassword ); + } + if ( pszTopic ) { + wi->pszTopic = ( TCHAR* )realloc( wi->pszTopic, sizeof(TCHAR)*(lstrlen(pszTopic)+1)); + lstrcpy( wi->pszTopic, pszTopic ); + } + + SetChannelSBText(window, wi); + return true; + } + return false; +} + +void CIrcProto::CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ) +{ + char temp[MAXMODULELABELLENGTH]; + mir_snprintf( temp, sizeof(temp), "%s%s", m_szModuleName, serviceName ); + CreateServiceFunctionObj( temp, ( MIRANDASERVICEOBJ )*( void** )&pFunc, this ); +} + +void CIrcProto::FindLocalIP(HANDLE con) // inspiration from jabber +{ + // Determine local IP + int socket = CallService( MS_NETLIB_GETSOCKET, (WPARAM) con, 0); + if ( socket != INVALID_SOCKET ) { + struct sockaddr_in saddr; + int len = sizeof(saddr); + getsockname(socket, (struct sockaddr *) &saddr, &len); + lstrcpynA(m_myLocalHost, inet_ntoa(saddr.sin_addr), 49); + m_myLocalPort = ntohs(saddr.sin_port ); +} } + +void CIrcProto::DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...) +{ + TCHAR temp[4096]; + CMString S = _T(""); + switch( type ) { + case 1: + S = _T("USERHOST"); + break; + case 2: + S = _T("WHO"); + break; + default: + S = _T("USERHOST"); + break; + } + + va_list ap; + va_start(ap, userhostparams); + mir_vsntprintf(temp, SIZEOF(temp), (S + _T(" ") + userhostparams).c_str(), ap); + va_end(ap); + + // Add reason + if ( type == 1 ) + vUserhostReasons.insert( new CMString( reason )); + else if ( type == 2 ) + vWhoInProgress.insert( new CMString( reason)); + + // Do command + if ( IsConnected() && bSendCommand ) + SendIrcMessage( temp, false ); +} + +CMString CIrcProto::GetNextUserhostReason(int type) +{ + CMString reason = _T(""); + switch( type ) { + case 1: + if ( !vUserhostReasons.getCount()) + return CMString(); + + // Get reason + reason = vUserhostReasons[0]; + vUserhostReasons.remove( 0 ); + break; + case 2: + if ( !vWhoInProgress.getCount()) + return CMString(); + + // Get reason + reason = vWhoInProgress[0]; + vWhoInProgress.remove( 0 ); + break; + } + + return reason; +} + +CMString CIrcProto::PeekAtReasons( int type ) +{ + switch ( type ) { + case 1: + if (!vUserhostReasons.getCount()) + return CMString(); + return vUserhostReasons[0]; + + case 2: + if (!vWhoInProgress.getCount()) + return CMString(); + return vWhoInProgress[0]; + + } + return CMString(); +} + +void CIrcProto::ClearUserhostReasons(int type) +{ + switch (type) { + case 1: + vUserhostReasons.destroy(); + break; + case 2: + vWhoInProgress.destroy(); + break; +} } + +//////////////////////////////////////////////////////////////////// + +SERVER_INFO::~SERVER_INFO() +{ + mir_free( m_name ); + mir_free( m_address ); + mir_free( m_group ); +} diff --git a/protocols/IRCG/src/ui_utils.cpp b/protocols/IRCG/src/ui_utils.cpp new file mode 100644 index 0000000000..d7c8e4b6b6 --- /dev/null +++ b/protocols/IRCG/src/ui_utils.cpp @@ -0,0 +1,1820 @@ +/* + +Object UI extensions +Copyright (C) 2008 Victor Pavlychko, George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.cpp $ +Revision : $Revision: 13133 $ +Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ +Last change by : $Author: george.hazan $ + +*/ + +#include "irc.h" +#include "ui_utils.h" + +extern HINSTANCE hInst; + +CDlgBase::CDlgBase(int idDialog, HWND hwndParent) : + m_controls(1, CCtrlBase::cmp) +{ + m_idDialog = idDialog; + m_hwndParent = hwndParent; + m_hwnd = NULL; + m_first = NULL; + m_isModal = false; + m_initialized = false; + m_autoClose = CLOSE_ON_OK|CLOSE_ON_CANCEL; + m_forceResizable = false; +} + +CDlgBase::~CDlgBase() +{ + // remove handlers + m_controls.destroy(); + + if (m_hwnd) + DestroyWindow(m_hwnd); +} + +void CDlgBase::Create() +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_HIDE); +} + +void CDlgBase::Show() +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_SHOW); +} + +int CDlgBase::DoModal() +{ + m_isModal = true; + return DialogBoxParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this); +} + +int CDlgBase::Resizer(UTILRESIZECONTROL*) +{ + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + m_initialized = false; + TranslateDialogDefault(m_hwnd); + + for ( CCtrlBase* p = m_first; p != NULL; p = p->m_next ) + AddControl( p ); + + NotifyControls(&CCtrlBase::OnInit); + OnInitDialog(); + + m_initialized = true; + return TRUE; + } + + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnMeasureItem(param); + return FALSE; + } + + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDrawItem(param); + return FALSE; + } + + case WM_DELETEITEM: + { + DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDeleteItem(param); + return FALSE; + } + + case WM_COMMAND: + { + HWND hwndCtrl = (HWND)lParam; + WORD idCtrl = LOWORD(wParam); + WORD idCode = HIWORD(wParam); + if (CCtrlBase *ctrl = FindControl(idCtrl)) { + BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode); + if ( result != FALSE ) + return result; + } + + if (idCode == BN_CLICKED && + ((idCtrl == IDOK) && (m_autoClose & CLOSE_ON_OK) || + (idCtrl == IDCANCEL) && (m_autoClose & CLOSE_ON_CANCEL))) + { + PostMessage( m_hwnd, WM_CLOSE, 0, 0 ); + } + return FALSE; + } + + case WM_NOTIFY: + { + int idCtrl = wParam; + NMHDR *pnmh = (NMHDR *)lParam; + + if (pnmh->idFrom == 0) + { + if (pnmh->code == PSN_APPLY) + { + NotifyControls(&CCtrlBase::OnApply); + OnApply(); + } + else if (pnmh->code == PSN_RESET) + { + NotifyControls(&CCtrlBase::OnReset); + OnReset(); + } + } + + if (CCtrlBase *ctrl = FindControl(pnmh->idFrom)) + return ctrl->OnNotify(idCtrl, pnmh); + return FALSE; + } + + case WM_SIZE: + { + if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_SIZEBOX)) + { + UTILRESIZEDIALOG urd; + urd.cbSize = sizeof(urd); + urd.hwndDlg = m_hwnd; + urd.hInstance = hInst; + urd.lpTemplate = MAKEINTRESOURCEA(m_idDialog); + urd.lParam = 0; + urd.pfnResizer = GlobalDlgResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + } + return TRUE; + } + + case WM_CLOSE: + { + m_lresult = FALSE; + OnClose(); + if ( !m_lresult ) + { + if (m_isModal) + EndDialog(m_hwnd, 0); + else + DestroyWindow(m_hwnd); + } + return TRUE; + } + + case WM_DESTROY: + { + OnDestroy(); + NotifyControls(&CCtrlBase::OnDestroy); + + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + m_hwnd = NULL; + if (m_isModal) + { + m_isModal = false; + } else + { // modeless dialogs MUST be allocated with 'new' + delete this; + } + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CDlgBase *wnd = NULL; + if (msg == WM_INITDIALOG) + { + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + wnd = (CDlgBase *)lParam; + wnd->m_hwnd = hwnd; + } else + { + wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + + if (!wnd) return FALSE; + + wnd->m_msg.hwnd = hwnd; + wnd->m_msg.message = msg; + wnd->m_msg.wParam = wParam; + wnd->m_msg.lParam = lParam; + return wnd->DlgProc(msg, wParam, lParam); +} + +int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) +{ + CDlgBase *wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!wnd) return 0; + + return wnd->Resizer(urc); +} + +void CDlgBase::AddControl(CCtrlBase *ctrl) +{ + m_controls.insert(ctrl); +} + +void CDlgBase::NotifyControls(void (CCtrlBase::*fn)()) +{ + for (int i = 0; i < m_controls.getCount(); ++i) + (m_controls[i]->*fn)(); +} + +CCtrlBase* CDlgBase::FindControl(int idCtrl) +{ + CCtrlBase search(NULL, idCtrl); + return m_controls.find(&search); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo class + +CCtrlCombo::CCtrlCombo( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCombo::AddString(const TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +int CCtrlCombo::AddStringA(const char *text, LPARAM data) +{ + int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::DeleteString(int index) +{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0); +} + +int CCtrlCombo::FindString(const TCHAR *str, int index, bool exact ) +{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::FindStringA(const char *str, int index, bool exact ) +{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::GetCount() +{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0); +} + +int CCtrlCombo::GetCurSel() +{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); +} + +bool CCtrlCombo::GetDroppedState() +{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false; +} + +LPARAM CCtrlCombo::GetItemData(int index) +{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlCombo::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlCombo::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +int CCtrlCombo::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::ResetContent() +{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0); +} + +int CCtrlCombo::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlCombo::SetCurSel(int index) +{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0); +} + +void CCtrlCombo::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data); +} + +void CCtrlCombo::ShowDropdown(bool show) +{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox class + +CCtrlListBox::CCtrlListBox( CDlgBase* dlg, int ctrlId ) : + CCtrlBase( dlg, ctrlId ) +{ +} + +BOOL CCtrlListBox::OnCommand(HWND, WORD, WORD idCode) +{ + switch (idCode) + { + case LBN_DBLCLK: OnDblClick(this); break; + case LBN_SELCANCEL: OnSelCancel(this); break; + case LBN_SELCHANGE: OnSelChange(this); break; + } + return TRUE; +} + +int CCtrlListBox::AddString(TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)text); + SendMessage(m_hwnd, LB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::DeleteString(int index) +{ SendMessage(m_hwnd, LB_DELETESTRING, index, 0); +} + +int CCtrlListBox::FindString( TCHAR *str, int index, bool exact) +{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlListBox::GetCount() +{ return SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); +} + +int CCtrlListBox::GetCurSel() +{ return SendMessage(m_hwnd, LB_GETCURSEL, 0, 0); +} + +LPARAM CCtrlListBox::GetItemData(int index) +{ return SendMessage(m_hwnd, LB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlListBox::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlListBox::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +bool CCtrlListBox::GetSel(int index) +{ return SendMessage(m_hwnd, LB_GETSEL, index, 0) ? true : false; +} + +int CCtrlListBox::GetSelCount() +{ return SendMessage(m_hwnd, LB_GETSELCOUNT, 0, 0); +} + +int* CCtrlListBox::GetSelItems(int *items, int count) +{ + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)items); + return items; +} + +int* CCtrlListBox::GetSelItems() +{ + int count = GetSelCount() + 1; + int *result = (int *)mir_alloc(sizeof(int) * count); + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)result); + result[count-1] = -1; + return result; +} + +int CCtrlListBox::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::ResetContent() +{ SendMessage(m_hwnd, LB_RESETCONTENT, 0, 0); +} + +int CCtrlListBox::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, LB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlListBox::SetCurSel(int index) +{ return SendMessage(m_hwnd, LB_SETCURSEL, index, 0); +} + +void CCtrlListBox::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, LB_SETITEMDATA, index, data); +} + +void CCtrlListBox::SetSel(int index, bool sel) +{ SendMessage(m_hwnd, LB_SETSEL, sel ? TRUE : FALSE, index); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck class + +CCtrlCheck::CCtrlCheck( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCheck::GetState() +{ + return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); +} + +void CCtrlCheck::SetState(int state) +{ + SendMessage(m_hwnd, BM_SETCHECK, state, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit class + +CCtrlEdit::CCtrlEdit( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData class + +CCtrlData::CCtrlData( CDlgBase *wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ), + m_dbLink( NULL ) +{ +} + +void CCtrlData::OnInit() +{ + CCtrlBase::OnInit(); + m_changed = false; +} + +void CCtrlData::NotifyChange() +{ + if (!m_parentWnd || m_parentWnd->IsInitialized()) m_changed = true; + if ( m_parentWnd ) { + m_parentWnd->OnChange(this); + if ( m_parentWnd->IsInitialized()) + ::SendMessage( ::GetParent( m_parentWnd->GetHwnd()), PSM_CHANGED, 0, 0 ); + } + + OnChange(this); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, type, iValue); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, DBVT_TCHAR, szValue ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +int CCtrlButton::GetState() +{ return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); +} + +void CCtrlButton::SetState(int state) +{ SendMessage(m_hwnd, BM_SETCHECK, state, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlMButton + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( hIcon ), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( LoadSkinnedIcon(iCoreIcon)), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::~CCtrlMButton() +{ + if ( m_hIcon ) CallService( MS_SKIN2_RELEASEICON, (WPARAM)m_hIcon, 0 ); +} + +void CCtrlMButton::OnInit() +{ + CCtrlButton::OnInit(); + + SendMessage( m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon ); + SendMessage( m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0); +} + +void CCtrlMButton::MakeFlat() +{ + SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0); +} + +void CCtrlMButton::MakePush() +{ + SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +CCtrlButton::CCtrlButton( CDlgBase* wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ) +{ +} + +BOOL CCtrlButton::OnCommand(HWND, WORD, WORD idCode) +{ + if ( idCode == BN_CLICKED || idCode == STN_CLICKED ) + OnClick(this); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlHyperlink + +CCtrlHyperlink::CCtrlHyperlink( CDlgBase* wnd, int idCtrl, const char* url ) : + CCtrlBase( wnd, idCtrl ), + m_url(url) +{ +} + +BOOL CCtrlHyperlink::OnCommand(HWND, WORD, WORD) +{ + ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +CCtrlClc::CCtrlClc( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh }; + switch (pnmh->code) + { + case CLN_EXPANDED: OnExpanded(&evt); break; + case CLN_LISTREBUILT: OnListRebuilt(&evt); break; + case CLN_ITEMCHECKED: OnItemChecked(&evt); break; + case CLN_DRAGGING: OnDragging(&evt); break; + case CLN_DROPPED: OnDropped(&evt); break; + case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break; + case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break; + case CLN_DRAGSTOP: OnDragStop(&evt); break; + case CLN_NEWCONTACT: OnNewContact(&evt); break; + case CLN_CONTACTMOVED: OnContactMoved(&evt); break; + case CLN_CHECKCHANGED: OnCheckChanged(&evt); break; + case NM_CLICK: OnClick(&evt); break; + } + return FALSE; +} + +void CCtrlClc::AddContact(HANDLE hContact) +{ SendMessage(m_hwnd, CLM_ADDCONTACT, (WPARAM)hContact, 0); +} + +void CCtrlClc::AddGroup(HANDLE hGroup) +{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0); +} + +void CCtrlClc::AutoRebuild() +{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0); +} + +void CCtrlClc::DeleteItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::EditLabel(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0); +} + +void CCtrlClc::EndEditLabel(bool save) +{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0); +} + +void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk) +{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE); +} + +void CCtrlClc::Expand(HANDLE hItem, DWORD flags) +{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags); +} + +HANDLE CCtrlClc::FindContact(HANDLE hContact) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, (WPARAM)hContact, 0); +} + +HANDLE CCtrlClc::FindGroup(HANDLE hGroup) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0); +} + +COLORREF CCtrlClc::GetBkColor() +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0); +} + +bool CCtrlClc::GetCheck(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false; +} + +int CCtrlClc::GetCount() +{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0); +} + +HWND CCtrlClc::GetEditControl() +{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0); +} + +DWORD CCtrlClc::GetExpand(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0); +} + +int CCtrlClc::GetExtraColumns() +{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0); +} + +BYTE CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) +{ return (BYTE)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFF); +} + +HIMAGELIST CCtrlClc::GetExtraImageList() +{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0); +} + +HFONT CCtrlClc::GetFont(int iFontId) +{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0); +} + +HANDLE CCtrlClc::GetSelection() +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0); +} + +HANDLE CCtrlClc::HitTest(int x, int y, DWORD *hitTest) +{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y)); +} + +void CCtrlClc::SelectItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::SetBkBitmap(DWORD mode, HBITMAP hBitmap) +{ SendMessage(m_hwnd, CLM_SETBKBITMAP, mode, (LPARAM)hBitmap); +} + +void CCtrlClc::SetBkColor(COLORREF clBack) +{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0); +} + +void CCtrlClc::SetCheck(HANDLE hItem, bool check) +{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0); +} + +void CCtrlClc::SetExtraColumns(int iColumns) +{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0); +} + +void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); +} + +void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList); +} + +void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw) +{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId)); +} + +void CCtrlClc::SetIndent(int iIndent) +{ SendMessage(m_hwnd, CLM_SETINDENT, (WPARAM)iIndent, 0); +} + +void CCtrlClc::SetItemText(HANDLE hItem, char *szText) +{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText); +} + +void CCtrlClc::SetHideEmptyGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetGreyoutFlags(DWORD flags) +{ SendMessage(m_hwnd, CLM_SETGREYOUTFLAGS, (WPARAM)flags, 0); +} + +bool CCtrlClc::GetHideOfflineRoot() +{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false; +} + +void CCtrlClc::SetHideOfflineRoot(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9); +} + +void CCtrlClc::SetUseGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetOfflineModes(DWORD modes) +{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0); +} + +DWORD CCtrlClc::GetExStyle() +{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0); +} + +void CCtrlClc::SetExStyle(DWORD exStyle) +{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0); +} + +int CCtrlClc::GetLefrMargin() +{ return SendMessage(m_hwnd, CLM_GETLEFTMARGIN, 0, 0); +} + +void CCtrlClc::SetLeftMargin(int iMargin) +{ SendMessage(m_hwnd, CLM_SETLEFTMARGIN, (WPARAM)iMargin, 0); +} + +HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii) +{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii); +} + +int CCtrlClc::GetItemType(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0); +} + +HANDLE CCtrlClc::GetNextItem(HANDLE hItem, DWORD flags) +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem); +} + +COLORREF CCtrlClc::GetTextColot(int iFontId) +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETTEXTCOLOR, (WPARAM)iFontId, 0); +} + +void CCtrlClc::SetTextColor(int iFontId, COLORREF clText) +{ SendMessage(m_hwnd, CLM_SETTEXTCOLOR, (WPARAM)iFontId, (LPARAM)clText); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +CCtrlListView::CCtrlListView( CDlgBase* dlg, int ctrlId ) : + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) { + case NM_DBLCLK: OnDoubleClick(&evt); return TRUE; + case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE; + case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE; + case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE; + case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE; + case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE; + //case LVN_INCREMENTALSEARCH: OnIncrementalSearch(&evt); return TRUE; + case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE; + case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE; + case LVN_ITEMCHANGED: OnItemChanged(&evt); return TRUE; + case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE; + case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE; + case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + } + + return FALSE; +} +DWORD CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount) +{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount); +} +void CCtrlListView::Arrange(UINT code) +{ ListView_Arrange(m_hwnd, code); +} +void CCtrlListView::CancelEditLabel() +{ ListView_CancelEditLabel(m_hwnd); +} +HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft) +{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft); +} +void CCtrlListView::DeleteAllItems() +{ ListView_DeleteAllItems(m_hwnd); +} +void CCtrlListView::DeleteColumn(int iCol) +{ ListView_DeleteColumn(m_hwnd, iCol); +} +void CCtrlListView::DeleteItem(int iItem) +{ ListView_DeleteItem(m_hwnd, iItem); +} +HWND CCtrlListView::EditLabel(int iItem) +{ return ListView_EditLabel(m_hwnd, iItem); +} +int CCtrlListView::EnableGroupView(BOOL fEnable) +{ return ListView_EnableGroupView(m_hwnd, fEnable); +} +BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK) +{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK); +} +int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi) +{ return ListView_FindItem(m_hwnd, iStart, plvfi); +} +COLORREF CCtrlListView::GetBkColor() +{ return ListView_GetBkColor(m_hwnd); +} +void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) +{ ListView_GetBkImage(m_hwnd, plvbki); +} +UINT CCtrlListView::GetCallbackMask() +{ return ListView_GetCallbackMask(m_hwnd); +} +BOOL CCtrlListView::GetCheckState(UINT iIndex) +{ return ListView_GetCheckState(m_hwnd, iIndex); +} +void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) +{ ListView_GetColumn(m_hwnd, iCol, pcol); +} +void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) +{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +int CCtrlListView::GetColumnWidth(int iCol) +{ return ListView_GetColumnWidth(m_hwnd, iCol); +} +int CCtrlListView::GetCountPerPage() +{ return ListView_GetCountPerPage(m_hwnd); +} +HWND CCtrlListView::GetEditControl() +{ return ListView_GetEditControl(m_hwnd); +} +//void CCtrlListView::GetEmptyText(PWSTR pszText, UINT cchText) +//{ ListView_GetEmptyText(m_hwnd, pszText, cchText); +//} +DWORD CCtrlListView::GetExtendedListViewStyle() +{ return ListView_GetExtendedListViewStyle(m_hwnd); +} +//INT CCtrlListView::GetFocusedGroup() +//{ return ListView_GetFocusedGroup(m_hwnd); +//} +//void CCtrlListView::GetFooterInfo(LPLVFOOTERINFO plvfi) +//{ ListView_GetFooterInfo(m_hwnd, plvfi); +//} +//void CCtrlListView::GetFooterItem(UINT iItem, LVFOOTERITEM *pfi) +//{ ListView_GetFooterItem(m_hwnd, iItem, pfi); +//} +//void CCtrlListView::GetFooterItemRect(UINT iItem, RECT *prc) +//{ ListView_GetFooterItemRect(m_hwnd, iItem, prc); +//} +//void CCtrlListView::GetFooterRect(RECT *prc) +//{ ListView_GetFooterRect(m_hwnd, prc); +//} +//int CCtrlListView::GetGroupCount() +//{ return ListView_GetGroupCount(m_hwnd); +//} +//HIMAGELIST CCtrlListView::GetGroupHeaderImageList() +//{ return ListView_GetGroupHeaderImageList(m_hwnd); +//} +//void CCtrlListView::GetGroupInfo(int iGroupId, PLVGROUP pgrp) +//{ ListView_GetGroupInfo(m_hwnd, iGroupId, pgrp); +//} +//void CCtrlListView::GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) +//{ ListView_GetGroupInfoByIndex(m_hwnd, iIndex, pgrp); +//} +void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) +{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics); +} +//BOOL CCtrlListView::GetGroupRect(int iGroupId, RECT *prc) +//{ return ListView_GetGroupRect(m_hwnd, iGroupId, prc); +//} +//UINT CCtrlListView::GetGroupState(UINT dwGroupId, UINT dwMask) +//{ return ListView_GetGroupState(m_hwnd, dwGroupId, dwMask); +//} +HWND CCtrlListView::GetHeader() +{ return ListView_GetHeader(m_hwnd); +} +HCURSOR CCtrlListView::GetHotCursor() +{ return ListView_GetHotCursor(m_hwnd); +} +INT CCtrlListView::GetHotItem() +{ return ListView_GetHotItem(m_hwnd); +} +DWORD CCtrlListView::GetHoverTime() +{ return ListView_GetHoverTime(m_hwnd); +} +HIMAGELIST CCtrlListView::GetImageList(int iImageList) +{ return ListView_GetImageList(m_hwnd, iImageList); +} +BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) +{ return ListView_GetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::GetInsertMarkColor() +{ return ListView_GetInsertMarkColor(m_hwnd); +} +int CCtrlListView::GetInsertMarkRect(LPRECT prc) +{ return ListView_GetInsertMarkRect(m_hwnd, prc); +} +BOOL CCtrlListView::GetISearchString(LPSTR lpsz) +{ return ListView_GetISearchString(m_hwnd, lpsz); +} +void CCtrlListView::GetItem(LPLVITEM pitem) +{ ListView_GetItem(m_hwnd, pitem); +} +int CCtrlListView::GetItemCount() +{ return ListView_GetItemCount(m_hwnd); +} +//void CCtrlListView::GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc) +//{ ListView_GetItemIndexRect(m_hwnd, plvii, iSubItem, code, prc); +//} +void CCtrlListView::GetItemPosition(int i, POINT *ppt) +{ ListView_GetItemPosition(m_hwnd, i, ppt); +} +void CCtrlListView::GetItemRect(int i, RECT *prc, int code) +{ ListView_GetItemRect(m_hwnd, i, prc, code); +} +DWORD CCtrlListView::GetItemSpacing(BOOL fSmall) +{ return ListView_GetItemSpacing(m_hwnd, fSmall); +} +UINT CCtrlListView::GetItemState(int i, UINT mask) +{ return ListView_GetItemState(m_hwnd, i, mask); +} +void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) +{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax); +} +int CCtrlListView::GetNextItem(int iStart, UINT flags) +{ return ListView_GetNextItem(m_hwnd, iStart, flags); +} +//BOOL CCtrlListView::GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags) +//{ return ListView_GetNextItemIndex(m_hwnd, plvii, flags); +//} +BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) +{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas); +} +BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) +{ return ListView_GetOrigin(m_hwnd, lpptOrg); +} +COLORREF CCtrlListView::GetOutlineColor() +{ return ListView_GetOutlineColor(m_hwnd); +} +UINT CCtrlListView::GetSelectedColumn() +{ return ListView_GetSelectedColumn(m_hwnd); +} +UINT CCtrlListView::GetSelectedCount() +{ return ListView_GetSelectedCount(m_hwnd); +} +INT CCtrlListView::GetSelectionMark() +{ return ListView_GetSelectionMark(m_hwnd); +} +int CCtrlListView::GetStringWidth(LPCSTR psz) +{ return ListView_GetStringWidth(m_hwnd, psz); +} +BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) +{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect); +} +COLORREF CCtrlListView::GetTextBkColor() +{ return ListView_GetTextBkColor(m_hwnd); +} +COLORREF CCtrlListView::GetTextColor() +{ return ListView_GetTextColor(m_hwnd); +} +void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) +{ ListView_GetTileInfo(m_hwnd, plvtinfo); +} +void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::GetToolTips() +{ return ListView_GetToolTips(m_hwnd); +} +int CCtrlListView::GetTopIndex() +{ return ListView_GetTopIndex(m_hwnd); +} +BOOL CCtrlListView::GetUnicodeFormat() +{ return ListView_GetUnicodeFormat(m_hwnd); +} +DWORD CCtrlListView::GetView() +{ return ListView_GetView(m_hwnd); +} +BOOL CCtrlListView::GetViewRect(RECT *prc) +{ return ListView_GetViewRect(m_hwnd, prc); +} +void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +BOOL CCtrlListView::HasGroup(int dwGroupId) +{ return ListView_HasGroup(m_hwnd, dwGroupId); +} +int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) +{ return ListView_HitTest(m_hwnd, pinfo); +} +//int CCtrlListView::HitTestEx(LPLVHITTESTINFO pinfo) +//{ return ListView_HitTestEx(m_hwnd, pinfo); +//} +int CCtrlListView::InsertColumn(int iCol, const LPLVCOLUMN pcol) +{ return ListView_InsertColumn(m_hwnd, iCol, pcol); +} +int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp) +{ return ListView_InsertGroup(m_hwnd, index, pgrp); +} +void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert) +{ ListView_InsertGroupSorted(m_hwnd, structInsert); +} +int CCtrlListView::InsertItem(const LPLVITEM pitem) +{ return ListView_InsertItem(m_hwnd, pitem); +} +BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim) +{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim); +} +BOOL CCtrlListView::IsGroupViewEnabled() +{ return ListView_IsGroupViewEnabled(m_hwnd); +} +//UINT CCtrlListView::IsItemVisible(UINT index) +//{ return ListView_IsItemVisible(m_hwnd, index); +//} +UINT CCtrlListView::MapIDToIndex(UINT id) +{ return ListView_MapIDToIndex(m_hwnd, id); +} +UINT CCtrlListView::MapIndexToID(UINT index) +{ return ListView_MapIndexToID(m_hwnd, index); +} +BOOL CCtrlListView::RedrawItems(int iFirst, int iLast) +{ return ListView_RedrawItems(m_hwnd, iFirst, iLast); +} +void CCtrlListView::RemoveAllGroups() +{ ListView_RemoveAllGroups(m_hwnd); +} +int CCtrlListView::RemoveGroup(int iGroupId) +{ return ListView_RemoveGroup(m_hwnd, iGroupId); +} +BOOL CCtrlListView::Scroll(int dx, int dy) +{ return ListView_Scroll(m_hwnd, dx, dy); +} +BOOL CCtrlListView::SetBkColor(COLORREF clrBk) +{ return ListView_SetBkColor(m_hwnd, clrBk); +} +BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki) +{ return ListView_SetBkImage(m_hwnd, plvbki); +} +BOOL CCtrlListView::SetCallbackMask(UINT mask) +{ return ListView_SetCallbackMask(m_hwnd, mask); +} +void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck) +{ ListView_SetCheckState(m_hwnd, iIndex, fCheck); +} +BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol) +{ return ListView_SetColumn(m_hwnd, iCol, pcol); +} +BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray) +{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +BOOL CCtrlListView::SetColumnWidth(int iCol, int cx) +{ return ListView_SetColumnWidth(m_hwnd, iCol, cx); +} +void CCtrlListView::SetExtendedListViewStyle(DWORD dwExStyle) +{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle); +} +void CCtrlListView::SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle) +{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle); +} +//HIMAGELIST CCtrlListView::SetGroupHeaderImageList(HIMAGELIST himl) +//{ return ListView_SetGroupHeaderImageList(m_hwnd, himl); +//} +int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp) +{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp); +} +void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) +{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics); +} +//void CCtrlListView::SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState) +//{ ListView_SetGroupState(m_hwnd, dwGroupId, dwMask, dwState); +//} +HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor) +{ return ListView_SetHotCursor(m_hwnd, hCursor); +} +INT CCtrlListView::SetHotItem(INT iIndex) +{ return ListView_SetHotItem(m_hwnd, iIndex); +} +void CCtrlListView::SetHoverTime(DWORD dwHoverTime) +{ ListView_SetHoverTime(m_hwnd, dwHoverTime); +} +DWORD CCtrlListView::SetIconSpacing(int cx, int cy) +{ return ListView_SetIconSpacing(m_hwnd, cx, cy); +} +HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList) +{ return ListView_SetImageList(m_hwnd, himl, iImageList); +} +BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip) +{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip); +} +BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim) +{ return ListView_SetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color) +{ return ListView_SetInsertMarkColor(m_hwnd, color); +} +BOOL CCtrlListView::SetItem(const LPLVITEM pitem) +{ return ListView_SetItem(m_hwnd, pitem); +} +void CCtrlListView::SetItemCount(int cItems) +{ ListView_SetItemCount(m_hwnd, cItems); +} +void CCtrlListView::SetItemCountEx(int cItems, DWORD dwFlags) +{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags); +} +//HRESULT CCtrlListView::SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask) +//{ return ListView_SetItemIndexState(m_hwnd, plvii, data, mask); +//} +BOOL CCtrlListView::SetItemPosition(int i, int x, int y) +{ return ListView_SetItemPosition(m_hwnd, i, x, y); +} +void CCtrlListView::SetItemPosition32(int iItem, int x, int y) +{ ListView_SetItemPosition32(m_hwnd, iItem, x, y); +} +void CCtrlListView::SetItemState(int i, UINT state, UINT mask) +{ ListView_SetItemState(m_hwnd, i, state, mask); +} +void CCtrlListView::SetItemText(int i, int iSubItem, TCHAR *pszText) +{ ListView_SetItemText(m_hwnd, i, iSubItem, pszText); +} +COLORREF CCtrlListView::SetOutlineColor(COLORREF color) +{ return ListView_SetOutlineColor(m_hwnd, color); +} +void CCtrlListView::SetSelectedColumn(int iCol) +{ ListView_SetSelectedColumn(m_hwnd, iCol); +} +INT CCtrlListView::SetSelectionMark(INT iIndex) +{ return ListView_SetSelectionMark(m_hwnd, iIndex); +} +BOOL CCtrlListView::SetTextBkColor(COLORREF clrText) +{ return ListView_SetTextBkColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTextColor(COLORREF clrText) +{ return ListView_SetTextColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo) +{ return ListView_SetTileInfo(m_hwnd, plvtinfo); +} +BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::SetToolTips(HWND ToolTip) +{ return ListView_SetToolTips(m_hwnd, ToolTip); +} +BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode) +{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode); +} +int CCtrlListView::SetView(DWORD iView) +{ return ListView_SetView(m_hwnd, iView); +} +void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv) +{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv); +} +BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort); +} +BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort); +} +INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) +{ return ListView_SubItemHitTest(m_hwnd, pInfo); +} +//INT CCtrlListView::SubItemHitTestEx(LPLVHITTESTINFO plvhti) +//{ return ListView_SubItemHitTestEx(m_hwnd, plvhti); +//} +BOOL CCtrlListView::Update(int iItem) +{ return ListView_Update(m_hwnd, iItem); +} +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +CCtrlTreeView::CCtrlTreeView( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) + { + case TVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; + case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; + case TVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; + case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; + case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; + } + + return FALSE; +} + +void CCtrlTreeView::TranslateItem(HTREEITEM hItem) +{ + TCHAR buf[128]; + TVITEMEX tvi; + + GetItem(hItem, &tvi, buf, SIZEOF(buf)); + tvi.pszText = TranslateTS(tvi.pszText); + tvi.cchTextMax = lstrlen(tvi.pszText); + SetItem(&tvi); +} + +void CCtrlTreeView::TranslateTree() +{ + HTREEITEM hItem = GetRoot(); + while (hItem) + { + TranslateItem(hItem); + + HTREEITEM hItemTmp = 0; + if (hItemTmp = GetChild(hItem)) + hItem = hItemTmp; + else if (hItemTmp = GetNextSibling(hItem)) + hItem = hItemTmp; + else + { + for (;;) + { + if (!(hItem = GetParent(hItem))) break; + if (hItemTmp = GetNextSibling(hItem)) + { + hItem = hItemTmp; + break; + } + } + } + } +} + +HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const TCHAR *name) +{ + TVITEMEX tvi = {0}; + TCHAR str[MAX_PATH]; + + if (hItem) + tvi.hItem = GetChild(hItem); + else + tvi.hItem = GetRoot(); + + if (!name) + return tvi.hItem; + + tvi.mask = TVIF_TEXT; + tvi.pszText = str; + tvi.cchTextMax = SIZEOF(str); + + while (tvi.hItem) + { + GetItem(&tvi); + + if (!lstrcmp(tvi.pszText, name)) + return tvi.hItem; + + tvi.hItem = GetNextSibling(tvi.hItem); + } + return NULL; +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE; + tvi->hItem = hItem; + GetItem(tvi); +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT; + tvi->hItem = hItem; + tvi->pszText = szText; + tvi->cchTextMax = iTextLength; + GetItem(tvi); +} + +HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) +{ return TreeView_CreateDragImage(m_hwnd, hItem); +} + +void CCtrlTreeView::DeleteAllItems() +{ TreeView_DeleteAllItems(m_hwnd); +} + +void CCtrlTreeView::DeleteItem(HTREEITEM hItem) +{ TreeView_DeleteItem(m_hwnd, hItem); +} + +HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) +{ return TreeView_EditLabel(m_hwnd, hItem); +} + +void CCtrlTreeView::EndEditLabelNow(BOOL cancel) +{ TreeView_EndEditLabelNow(m_hwnd, cancel); +} + +void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) +{ TreeView_EnsureVisible(m_hwnd, hItem); +} + +void CCtrlTreeView::Expand(HTREEITEM hItem, DWORD flag) +{ TreeView_Expand(m_hwnd, hItem, flag); +} + +COLORREF CCtrlTreeView::GetBkColor() +{ return TreeView_GetBkColor(m_hwnd); +} + +DWORD CCtrlTreeView::GetCheckState(HTREEITEM hItem) +{ return TreeView_GetCheckState(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) +{ return TreeView_GetChild(m_hwnd, hItem); +} + +int CCtrlTreeView::GetCount() +{ return TreeView_GetCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetDropHilight() +{ return TreeView_GetDropHilight(m_hwnd); +} + +HWND CCtrlTreeView::GetEditControl() +{ return TreeView_GetEditControl(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetFirstVisible() +{ return TreeView_GetFirstVisible(m_hwnd); +} + +HIMAGELIST CCtrlTreeView::GetImageList(int iImage) +{ return TreeView_GetImageList(m_hwnd, iImage); +} + +int CCtrlTreeView::GetIndent() +{ return TreeView_GetIndent(m_hwnd); +} + +COLORREF CCtrlTreeView::GetInsertMarkColor() +{ return TreeView_GetInsertMarkColor(m_hwnd); +} + +void CCtrlTreeView::GetItem(TVITEMEX *tvi) +{ TreeView_GetItem(m_hwnd, tvi); +} + +int CCtrlTreeView::GetItemHeight() +{ return TreeView_GetItemHeight(m_hwnd); +} + +void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) +{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); +} + +DWORD CCtrlTreeView::GetItemState(HTREEITEM hItem, DWORD stateMask) +{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); +} + +HTREEITEM CCtrlTreeView::GetLastVisible() +{ return TreeView_GetLastVisible(m_hwnd); +} + +COLORREF CCtrlTreeView::GetLineColor() +{ return TreeView_GetLineColor(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, DWORD flag) +{ return TreeView_GetNextItem(m_hwnd, hItem, flag); +} + +HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) +{ return TreeView_GetNextSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) +{ return TreeView_GetNextVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) +{ return TreeView_GetParent(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) +{ return TreeView_GetPrevSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) +{ return TreeView_GetPrevVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetRoot() +{ return TreeView_GetRoot(m_hwnd); +} + +DWORD CCtrlTreeView::GetScrollTime() +{ return TreeView_GetScrollTime(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetSelection() +{ return TreeView_GetSelection(m_hwnd); +} + +COLORREF CCtrlTreeView::GetTextColor() +{ return TreeView_GetTextColor(m_hwnd); +} + +HWND CCtrlTreeView::GetToolTips() +{ return TreeView_GetToolTips(m_hwnd); +} + +BOOL CCtrlTreeView::GetUnicodeFormat() +{ return TreeView_GetUnicodeFormat(m_hwnd); +} + +unsigned CCtrlTreeView::GetVisibleCount() +{ return TreeView_GetVisibleCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) +{ return TreeView_HitTest(m_hwnd, hti); +} + +HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) +{ return TreeView_InsertItem(m_hwnd, tvis); +} + +/* +HTREEITEM CCtrlTreeView::MapAccIDToHTREEITEM(UINT id) +{ return TreeView_MapAccIDToHTREEITEM(m_hwnd, id); +} + +UINT CCtrlTreeView::MapHTREEITEMtoAccID(HTREEITEM hItem) +{ return TreeView_MapHTREEITEMtoAccID(m_hwnd, hItem); +} + +*/ +void CCtrlTreeView::Select(HTREEITEM hItem, DWORD flag) +{ TreeView_Select(m_hwnd, hItem, flag); +} + +void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) +{ TreeView_SelectDropTarget(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectItem(HTREEITEM hItem) +{ TreeView_SelectItem(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) +{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); +} + +COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) +{ return TreeView_SetBkColor(m_hwnd, clBack); +} + +void CCtrlTreeView::SetCheckState(HTREEITEM hItem, DWORD state) +{ TreeView_SetCheckState(m_hwnd, hItem, state); +} + +void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) +{ TreeView_SetImageList(m_hwnd, hIml, iImage); +} + +void CCtrlTreeView::SetIndent(int iIndent) +{ TreeView_SetIndent(m_hwnd, iIndent); +} + +void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) +{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); +} + +COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) +{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); +} + +void CCtrlTreeView::SetItem(TVITEMEX *tvi) +{ TreeView_SetItem(m_hwnd, tvi); +} + +void CCtrlTreeView::SetItemHeight(short cyItem) +{ TreeView_SetItemHeight(m_hwnd, cyItem); +} + +void CCtrlTreeView::SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask) +{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); +} + +COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) +{ return TreeView_SetLineColor(m_hwnd, clLine); +} + +void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) +{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); +} + +COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) +{ return TreeView_SetTextColor(m_hwnd, clText); +} + +HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) +{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); +} + +BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) +{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); +} + +void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) +{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); +} + +void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) +{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) : + m_parentWnd( wnd ), + m_idCtrl( idCtrl ), + m_hwnd( NULL ), + m_wndproc( NULL ) +{ + if ( wnd ) { + m_next = wnd->m_first; + wnd->m_first = this; +} } + +void CCtrlBase::OnInit() +{ + m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : NULL; +} + +void CCtrlBase::OnDestroy() +{ + Unsubclass(); + m_hwnd = NULL; +} + +void CCtrlBase::Enable( int bIsEnable ) +{ + ::EnableWindow( m_hwnd, bIsEnable ); +} + +BOOL CCtrlBase::Enabled() const +{ + return ( m_hwnd ) ? IsWindowEnabled( m_hwnd ) : FALSE; +} + +LRESULT CCtrlBase::SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ) +{ + return ::SendMessage( m_hwnd, Msg, wParam, lParam ); +} + +void CCtrlBase::SetText(const TCHAR *text) +{ + ::SetWindowText( m_hwnd, text ); +} + +void CCtrlBase::SetTextA(const char *text) +{ + ::SetWindowTextA( m_hwnd, text ); +} + +void CCtrlBase::SetInt(int value) +{ + TCHAR buf[32] = {0}; + mir_sntprintf(buf, SIZEOF(buf), _T("%d"), value); + SetWindowText(m_hwnd, buf); +} + +TCHAR* CCtrlBase::GetText() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return result; +} + +char* CCtrlBase::GetTextA() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + char *result = (char *)mir_alloc(length * sizeof(char)); + GetWindowTextA(m_hwnd, result, length); + return result; +} + +TCHAR* CCtrlBase::GetText(TCHAR *buf, int size) +{ + GetWindowText(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +char* CCtrlBase::GetTextA(char *buf, int size) +{ + GetWindowTextA(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +int CCtrlBase::GetInt() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)_alloca(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return _ttoi(result); +} + +LRESULT CCtrlBase::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_DESTROY) Unsubclass(); + return CallWindowProc(m_wndproc, m_hwnd, msg, wParam, lParam); +} + +void CCtrlBase::Subclass() +{ + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + m_wndproc = (WNDPROC)SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassWndProc); +} + +void CCtrlBase::Unsubclass() +{ + if (m_wndproc) + { + SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + m_wndproc = 0; +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink class + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_type = type; + m_iDefault = iValue; + m_szDefault = 0; + dbv.type = DBVT_DELETED; +} + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_type = type; + m_szDefault = mir_tstrdup(szValue); + dbv.type = DBVT_DELETED; +} + +CDbLink::~CDbLink() +{ + mir_free(m_szModule); + mir_free(m_szSetting); + mir_free(m_szDefault); + if (dbv.type != DBVT_DELETED) + DBFreeVariant(&dbv); +} + +DWORD CDbLink::LoadInt() +{ + switch (m_type) { + case DBVT_BYTE: return DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_WORD: return DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_DWORD: return DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); + default: return m_iDefault; + } +} + +void CDbLink::SaveInt(DWORD value) +{ + switch (m_type) { + case DBVT_BYTE: DBWriteContactSettingByte(NULL, m_szModule, m_szSetting, (BYTE)value); break; + case DBVT_WORD: DBWriteContactSettingWord(NULL, m_szModule, m_szSetting, (WORD)value); break; + case DBVT_DWORD: DBWriteContactSettingDword(NULL, m_szModule, m_szSetting, value); break; + } +} + +TCHAR* CDbLink::LoadText() +{ + if (dbv.type != DBVT_DELETED) DBFreeVariant(&dbv); + if (!DBGetContactSettingTString(NULL, m_szModule, m_szSetting, &dbv)) + { + if (dbv.type == DBVT_TCHAR) + return dbv.ptszVal; + return m_szDefault; + } + + dbv.type = DBVT_DELETED; + return m_szDefault; +} + +void CDbLink::SaveText(TCHAR *value) +{ + DBWriteContactSettingTString(NULL, m_szModule, m_szSetting, value); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Misc utilities + +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) +{ + if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton))) + PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton)); + return 0; +} + +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow) +{ + for (; *idList; ++idList) + ShowWindow(GetDlgItem(hwndDlg, *idList), nCmdShow); +} diff --git a/protocols/IRCG/src/ui_utils.h b/protocols/IRCG/src/ui_utils.h new file mode 100644 index 0000000000..60566ce913 --- /dev/null +++ b/protocols/IRCG/src/ui_utils.h @@ -0,0 +1,1108 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007-08 Maxim Mluhov +Copyright ( C ) 2007-08 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.h $ +Revision : $Revision: 13133 $ +Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ +Last change by : $Author: george.hazan $ + +*/ + +#ifndef __jabber_ui_utils_h__ +#define __jabber_ui_utils_h__ + +#include "m_clc.h" + +#ifndef LPLVCOLUMN +typedef struct tagNMLVSCROLL +{ + NMHDR hdr; + int dx; + int dy; +} NMLVSCROLL; +typedef struct tagLVG +{ + UINT cbSize; + UINT mask; + LPWSTR pszHeader; + int cchHeader; + LPWSTR pszFooter; + int cchFooter; + int iGroupId; + UINT stateMask; + UINT state; + UINT uAlign; +} LVGROUP, *PLVGROUP; +typedef struct tagLVGROUPMETRICS +{ + UINT cbSize; + UINT mask; + UINT Left; + UINT Top; + UINT Right; + UINT Bottom; + COLORREF crLeft; + COLORREF crTop; + COLORREF crRight; + COLORREF crBottom; + COLORREF crHeader; + COLORREF crFooter; +} LVGROUPMETRICS, *PLVGROUPMETRICS; +typedef struct tagLVTILEVIEWINFO +{ + UINT cbSize; + DWORD dwMask; + DWORD dwFlags; + SIZE sizeTile; + int cLines; + RECT rcLabelMargin; +} LVTILEVIEWINFO, *PLVTILEVIEWINFO; +typedef struct tagLVTILEINFO +{ + UINT cbSize; + int iItem; + UINT cColumns; + PUINT puColumns; +} LVTILEINFO, *PLVTILEINFO; +typedef struct +{ + UINT cbSize; + DWORD dwFlags; + int iItem; + DWORD dwReserved; +} LVINSERTMARK, * LPLVINSERTMARK; +typedef int (CALLBACK *PFNLVGROUPCOMPARE)(int, int, void *); +typedef struct tagLVINSERTGROUPSORTED +{ + PFNLVGROUPCOMPARE pfnGroupCompare; + void *pvData; + LVGROUP lvGroup; +} LVINSERTGROUPSORTED, *PLVINSERTGROUPSORTED; +typedef struct tagLVSETINFOTIP +{ + UINT cbSize; + DWORD dwFlags; + LPWSTR pszText; + int iItem; + int iSubItem; +} LVSETINFOTIP, *PLVSETINFOTIP; +#define LPLVCOLUMN LPLVCOLUMNA +#define LPLVITEM LPLVITEMA +#define LVN_BEGINSCROLL (LVN_FIRST-80) +#define LVN_ENDSCROLL (LVN_FIRST-81) +#define LVN_HOTTRACK (LVN_FIRST-21) +#define LVN_MARQUEEBEGIN (LVN_FIRST-56) +#define LVM_MAPINDEXTOID (LVM_FIRST + 180) +#define ListView_MapIndexToID(hwnd, index) \ + (UINT)SendMessage((hwnd), LVM_MAPINDEXTOID, (WPARAM)index, (LPARAM)0) +#define TreeView_GetLineColor(hwnd) \ + (COLORREF)SendMessage((hwnd), TVM_GETLINECOLOR, 0, 0) +#define TreeView_SetLineColor(hwnd, clr) \ + (COLORREF)SendMessage((hwnd), TVM_SETLINECOLOR, 0, (LPARAM)(clr)) +#endif + + +#pragma warning(disable:4355) + +///////////////////////////////////////////////////////////////////////////////////////// +// Callbacks + +struct CCallbackImp +{ + struct CDummy + { int foo; + }; + +public: + __inline CCallbackImp(): m_object(NULL), m_func(NULL) {} + + __inline CCallbackImp(const CCallbackImp &other): m_object(other.m_object), m_func(other.m_func) {} + __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } + + __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } + __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } + + __inline operator bool() const { return m_object && m_func; } + + __inline bool CheckObject(void *object) const { return (object == m_object) ? true : false; } + +protected: + template + __inline CCallbackImp(TClass *object, void ( TClass::*func)(TArgument *argument)): m_object(( CDummy* )object), m_func((TFnCallback)func) {} + + __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } + +private: + typedef void ( CDummy::*TFnCallback)( void *argument ); + + CDummy* m_object; + TFnCallback m_func; +}; + +template +struct CCallback: public CCallbackImp +{ +public: + __inline CCallback() {} + + template + __inline CCallback(TClass *object, void ( TClass::*func)(TArgument *argument)): CCallbackImp(object, func) {} + + __inline CCallback& operator=( const CCallbackImp& x ) { CCallbackImp::operator =( x ); return *this; } + + __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } +}; + +template +__inline CCallback Callback(TClass *object, void (TClass::*func)(TArgument *argument)) + { return CCallback(object, func); } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDlgBase - base dialog class + +class CDlgBase +{ + friend class CCtrlBase; + friend class CCtrlData; + +public: + CDlgBase(int idDialog, HWND hwndParent); + virtual ~CDlgBase(); + + // general utilities + void Create(); + void Show(); + int DoModal(); + + __inline HWND GetHwnd() const { return m_hwnd; } + __inline bool IsInitialized() const { return m_initialized; } + __inline void Close() { SendMessage(m_hwnd, WM_CLOSE, 0, 0); } + __inline const MSG *ActiveMessage() const { return &m_msg; } + + // dynamic creation support (mainly to avoid leaks in options) + struct CreateParam + { + CDlgBase *(*create)(void *param); + void *param; + }; + static INT_PTR CALLBACK DynamicDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (msg == WM_INITDIALOG) + { + CreateParam *param = (CreateParam *)lParam; + CDlgBase *wnd = param->create(param->param); + SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)GlobalDlgProc); + return GlobalDlgProc(hwnd, msg, wParam, (LPARAM)wnd); + } + + return FALSE; + } + + LRESULT m_lresult; + +protected: + HWND m_hwnd; + HWND m_hwndParent; + int m_idDialog; + MSG m_msg; + bool m_isModal; + bool m_initialized; + bool m_forceResizable; + + enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; + BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL + + CCtrlBase* m_first; + + // override this handlers to provide custom functionality + // general messages + virtual void OnInitDialog() { } + virtual void OnClose() { } + virtual void OnDestroy() { } + + // miranda-related stuff + virtual int Resizer(UTILRESIZECONTROL *urc); + virtual void OnApply() {} + virtual void OnReset() {} + virtual void OnChange(CCtrlBase*) {} + + // main dialog procedure + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + // resister controls + void AddControl(CCtrlBase *ctrl); + +private: + LIST m_controls; + + void NotifyControls(void (CCtrlBase::*fn)()); + CCtrlBase *FindControl(int idCtrl); + + static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink + +class CDbLink +{ + char *m_szModule; + char *m_szSetting; + BYTE m_type; + + DWORD m_iDefault; + TCHAR *m_szDefault; + + DBVARIANT dbv; + +public: + CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue); + CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue); + ~CDbLink(); + + __inline BYTE GetDataType() { return m_type; } + + DWORD LoadInt(); + void SaveInt(DWORD value); + + TCHAR *LoadText(); + void SaveText(TCHAR *value); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +class CCtrlBase +{ + friend class CDlgBase; + +public: + CCtrlBase(CDlgBase *wnd, int idCtrl ); + virtual ~CCtrlBase() { Unsubclass(); } + + __inline int GetCtrlId() const { return m_idCtrl; } + __inline HWND GetHwnd() const { return m_hwnd; } + __inline CDlgBase *GetParent() { return m_parentWnd; } + + void Enable( int bIsEnable = true ); + __inline void Disable() { Enable( false ); } + BOOL Enabled( void ) const; + + LRESULT SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ); + + void SetText(const TCHAR *text); + void SetTextA(const char *text); + void SetInt(int value); + + TCHAR *GetText(); + char *GetTextA(); + + TCHAR *GetText(TCHAR *buf, int size); + char *GetTextA(char *buf, int size); + + int GetInt(); + + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } + virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } + + virtual void OnInit(); + virtual void OnDestroy(); + + virtual void OnApply() {} + virtual void OnReset() {} + + static int cmp(const CCtrlBase *c1, const CCtrlBase *c2) + { + if (c1->m_idCtrl < c2->m_idCtrl) return -1; + if (c1->m_idCtrl > c2->m_idCtrl) return +1; + return 0; + } + +protected: + HWND m_hwnd; + int m_idCtrl; + CCtrlBase* m_next; + CDlgBase* m_parentWnd; + + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + void Subclass(); + void Unsubclass(); + +private: + WNDPROC m_wndproc; + static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (CCtrlBase *ctrl = (CCtrlBase*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) + if (ctrl) + return ctrl->CustomWndProc(msg, wParam, lParam); + + return DefWindowProc(hwnd, msg, wParam, lParam); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +class CCtrlButton : public CCtrlBase +{ +public: + CCtrlButton( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + + CCallback OnClick; + + int GetState(); + void SetState(int state); +}; + +class CCtrlMButton : public CCtrlButton +{ +public: + CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ); + CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ); + ~CCtrlMButton(); + + void MakeFlat(); + void MakePush(); + + virtual void OnInit(); + +protected: + HICON m_hIcon; + const char* m_toolTip; +}; + +class CCtrlHyperlink : public CCtrlBase +{ +public: + CCtrlHyperlink( CDlgBase* dlg, int ctrlId, const char* url ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + +protected: + const char* m_url; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +class CCtrlClc: public CCtrlBase +{ +public: + CCtrlClc( CDlgBase* dlg, int ctrlId ); + + void AddContact(HANDLE hContact); + void AddGroup(HANDLE hGroup); + void AutoRebuild(); + void DeleteItem(HANDLE hItem); + void EditLabel(HANDLE hItem); + void EndEditLabel(bool save); + void EnsureVisible(HANDLE hItem, bool partialOk); + void Expand(HANDLE hItem, DWORD flags); + HANDLE FindContact(HANDLE hContact); + HANDLE FindGroup(HANDLE hGroup); + COLORREF GetBkColor(); + bool GetCheck(HANDLE hItem); + int GetCount(); + HWND GetEditControl(); + DWORD GetExpand(HANDLE hItem); + int GetExtraColumns(); + BYTE GetExtraImage(HANDLE hItem, int iColumn); + HIMAGELIST GetExtraImageList(); + HFONT GetFont(int iFontId); + HANDLE GetSelection(); + HANDLE HitTest(int x, int y, DWORD *hitTest); + void SelectItem(HANDLE hItem); + void SetBkBitmap(DWORD mode, HBITMAP hBitmap); + void SetBkColor(COLORREF clBack); + void SetCheck(HANDLE hItem, bool check); + void SetExtraColumns(int iColumns); + void SetExtraImage(HANDLE hItem, int iColumn, int iImage); + void SetExtraImageList(HIMAGELIST hImgList); + void SetFont(int iFontId, HANDLE hFont, bool bRedraw); + void SetIndent(int iIndent); + void SetItemText(HANDLE hItem, char *szText); + void SetHideEmptyGroups(bool state); + void SetGreyoutFlags(DWORD flags); + bool GetHideOfflineRoot(); + void SetHideOfflineRoot(bool state); + void SetUseGroups(bool state); + void SetOfflineModes(DWORD modes); + DWORD GetExStyle(); + void SetExStyle(DWORD exStyle); + int GetLefrMargin(); + void SetLeftMargin(int iMargin); + HANDLE AddInfoItem(CLCINFOITEM *cii); + int GetItemType(HANDLE hItem); + HANDLE GetNextItem(HANDLE hItem, DWORD flags); + COLORREF GetTextColot(int iFontId); + void SetTextColor(int iFontId, COLORREF clText); + + struct TEventInfo + { + CCtrlClc *ctrl; + NMCLISTCONTROL *info; + }; + + CCallback OnExpanded; + CCallback OnListRebuilt; + CCallback OnItemChecked; + CCallback OnDragging; + CCallback OnDropped; + CCallback OnListSizeChange; + CCallback OnOptionsChanged; + CCallback OnDragStop; + CCallback OnNewContact; + CCallback OnContactMoved; + CCallback OnCheckChanged; + CCallback OnClick; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData - data access controls base class + +class CCtrlData : public CCtrlBase +{ +public: + CCtrlData( CDlgBase* dlg, int ctrlId ); + + virtual ~CCtrlData() + { + if (m_dbLink) delete m_dbLink; + } + + __inline bool IsChanged() const { return m_changed; } + + void CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ); + void CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ); + + virtual void OnInit(); + + // Events + CCallback OnChange; + +protected: + CDbLink *m_dbLink; + bool m_changed; + + void NotifyChange(); + + __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } + __inline DWORD LoadInt() { return m_dbLink ? m_dbLink->LoadInt() : 0; } + __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } + __inline const TCHAR *LoadText() { return m_dbLink ? m_dbLink->LoadText() : _T(""); } + __inline void SaveText(TCHAR *value) { if (m_dbLink) m_dbLink->SaveText(value); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck + +class CCtrlCheck : public CCtrlData +{ +public: + CCtrlCheck( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND, WORD, WORD) { NotifyChange(); return TRUE; } + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + SaveInt(GetState()); + } + virtual void OnReset() + { + SetState(LoadInt()); + } + + int GetState(); + void SetState(int state); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit + +class CCtrlEdit : public CCtrlData +{ +public: + CCtrlEdit( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND, WORD, WORD idCode) + { + if (idCode == EN_CHANGE) + NotifyChange(); + return TRUE; + } + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(LoadInt()); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox + +class CCtrlListBox : public CCtrlBase +{ +public: + CCtrlListBox( CDlgBase* dlg, int ctrlId ); + + int AddString(TCHAR *text, LPARAM data=0); + void DeleteString(int index); + int FindString(TCHAR *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + bool GetSel(int index); + int GetSelCount(); + int* GetSelItems(int *items, int count); + int* GetSelItems(); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void SetSel(int index, bool sel=true); + + // Events + CCallback OnDblClick; + CCallback OnSelCancel; + CCallback OnSelChange; + +protected: + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo + +class CCtrlCombo : public CCtrlData +{ +public: + CCtrlCombo( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND, WORD, WORD idCode) + { + switch (idCode) + { + case CBN_CLOSEUP: OnCloseup(this); break; + case CBN_DROPDOWN: OnDropdown(this); break; + + case CBN_EDITCHANGE: + case CBN_EDITUPDATE: + case CBN_SELCHANGE: + case CBN_SELENDOK: + NotifyChange(); + break; + } + return TRUE; + } + + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(LoadInt()); + } + + // Control interface + int AddString(const TCHAR *text, LPARAM data = 0 ); + int AddStringA(const char *text, LPARAM data = 0 ); + void DeleteString(int index); + int FindString(const TCHAR *str, int index = -1, bool exact = false); + int FindStringA(const char *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + bool GetDroppedState(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void ShowDropdown(bool show = true); + + // Events + CCallback OnCloseup; + CCallback OnDropdown; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +class CCtrlListView : public CCtrlBase +{ +public: + CCtrlListView( CDlgBase* dlg, int ctrlId ); + + // Classic LV interface + DWORD ApproximateViewRect(int cx, int cy, int iCount); + void Arrange(UINT code); + void CancelEditLabel(); + HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); + void DeleteAllItems(); + void DeleteColumn(int iCol); + void DeleteItem(int iItem); + HWND EditLabel(int iItem); + int EnableGroupView(BOOL fEnable); + BOOL EnsureVisible(int i, BOOL fPartialOK); + int FindItem(int iStart, const LVFINDINFO *plvfi); + COLORREF GetBkColor(); + void GetBkImage(LPLVBKIMAGE plvbki); + UINT GetCallbackMask(); + BOOL GetCheckState(UINT iIndex); + void GetColumn(int iCol, LPLVCOLUMN pcol); + void GetColumnOrderArray(int iCount, int *lpiArray); + int GetColumnWidth(int iCol); + int GetCountPerPage(); + HWND GetEditControl(); + //void GetEmptyText(PWSTR pszText, UINT cchText); + DWORD GetExtendedListViewStyle(); + INT GetFocusedGroup(); + //void GetFooterInfo(LVFOOTERINFO *plvfi); + //void GetFooterItem(UINT iItem, LVFOOTERITEM *pfi); + //void GetFooterItemRect(UINT iItem, RECT *prc); + //void GetFooterRect(RECT *prc); + int GetGroupCount(); + //HIMAGELIST GetGroupHeaderImageList(); + void GetGroupInfo(int iGroupId, PLVGROUP pgrp); + void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp); + void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics); + //BOOL GetGroupRect(int iGroupId, RECT *prc); + UINT GetGroupState(UINT dwGroupId, UINT dwMask); + HWND GetHeader(); + HCURSOR GetHotCursor(); + INT GetHotItem(); + DWORD GetHoverTime(); + HIMAGELIST GetImageList(int iImageList); + BOOL GetInsertMark(LVINSERTMARK *plvim); + COLORREF GetInsertMarkColor(); + int GetInsertMarkRect(LPRECT prc); + BOOL GetISearchString(LPSTR lpsz); + void GetItem(LPLVITEM pitem); + int GetItemCount(); + //void GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc); + void GetItemPosition(int i, POINT *ppt); + void GetItemRect(int i, RECT *prc, int code); + DWORD GetItemSpacing(BOOL fSmall); + UINT GetItemState(int i, UINT mask); + void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax); + int GetNextItem(int iStart, UINT flags); + //BOOL GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags); + BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas); + BOOL GetOrigin(LPPOINT lpptOrg); + COLORREF GetOutlineColor(); + UINT GetSelectedColumn(); + UINT GetSelectedCount(); + INT GetSelectionMark(); + int GetStringWidth(LPCSTR psz); + BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect); + COLORREF GetTextBkColor(); + COLORREF GetTextColor(); + void GetTileInfo(PLVTILEINFO plvtinfo); + void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND GetToolTips(); + int GetTopIndex(); + BOOL GetUnicodeFormat(); + DWORD GetView(); + BOOL GetViewRect(RECT *prc); + void GetWorkAreas(INT nWorkAreas, LPRECT lprc); + BOOL HasGroup(int dwGroupId); + int HitTest(LPLVHITTESTINFO pinfo); + int HitTestEx(LPLVHITTESTINFO pinfo); + int InsertColumn(int iCol, const LPLVCOLUMN pcol); + int InsertGroup(int index, PLVGROUP pgrp); + void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); + int InsertItem(const LPLVITEM pitem); + BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); + BOOL IsGroupViewEnabled(); + UINT IsItemVisible(UINT index); + UINT MapIDToIndex(UINT id); + UINT MapIndexToID(UINT index); + BOOL RedrawItems(int iFirst, int iLast); + void RemoveAllGroups(); + int RemoveGroup(int iGroupId); + BOOL Scroll(int dx, int dy); + BOOL SetBkColor(COLORREF clrBk); + BOOL SetBkImage(LPLVBKIMAGE plvbki); + BOOL SetCallbackMask(UINT mask); + void SetCheckState(UINT iIndex, BOOL fCheck); + BOOL SetColumn(int iCol, LPLVCOLUMN pcol); + BOOL SetColumnOrderArray(int iCount, int *lpiArray); + BOOL SetColumnWidth(int iCol, int cx); + void SetExtendedListViewStyle(DWORD dwExStyle); + void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); + //HIMAGELIST SetGroupHeaderImageList(HIMAGELIST himl); + int SetGroupInfo(int iGroupId, PLVGROUP pgrp); + void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); + void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); + HCURSOR SetHotCursor(HCURSOR hCursor); + INT SetHotItem(INT iIndex); + void SetHoverTime(DWORD dwHoverTime); + DWORD SetIconSpacing(int cx, int cy); + HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); + BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); + BOOL SetInsertMark(LVINSERTMARK *plvim); + COLORREF SetInsertMarkColor(COLORREF color); + BOOL SetItem(const LPLVITEM pitem); + void SetItemCount(int cItems); + void SetItemCountEx(int cItems, DWORD dwFlags); + //HRESULT SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask); + BOOL SetItemPosition(int i, int x, int y); + void SetItemPosition32(int iItem, int x, int y); + void SetItemState(int i, UINT state, UINT mask); + void SetItemText(int i, int iSubItem, TCHAR *pszText); + COLORREF SetOutlineColor(COLORREF color); + void SetSelectedColumn(int iCol); + INT SetSelectionMark(INT iIndex); + BOOL SetTextBkColor(COLORREF clrText); + BOOL SetTextColor(COLORREF clrText); + BOOL SetTileInfo(PLVTILEINFO plvtinfo); + BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND SetToolTips(HWND ToolTip); + BOOL SetUnicodeFormat(BOOL fUnicode); + int SetView(DWORD iView); + void SetWorkAreas(INT nWorkAreas, LPRECT lprc); + int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + INT SubItemHitTest(LPLVHITTESTINFO pInfo); + INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); + BOOL Update(int iItem); + + // Events + struct TEventInfo { + CCtrlListView *treeviewctrl; + union { + NMHDR *nmhdr; + NMLISTVIEW *nmlv; + NMLVDISPINFO *nmlvdi; + NMLVSCROLL *nmlvscr; + NMLVGETINFOTIP *nmlvit; + NMLVFINDITEM *nmlvfi; + NMITEMACTIVATE *nmlvia; + NMLVKEYDOWN *nmlvkey; + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnBeginScroll; + CCallback OnColumnClick; + //CCallback OnColumnDropdown; + //CCallback OnColumnOverflowClick; + CCallback OnDeleteAllItems; + CCallback OnDeleteItem; + CCallback OnDoubleClick; + CCallback OnEndLabelEdit; + CCallback OnEndScroll; + CCallback OnGetDispInfo; + //CCallback OnGetEmptyMarkup; + CCallback OnGetInfoTip; + CCallback OnHotTrack; + CCallback OnIncrementalSearch; + CCallback OnInsertItem; + CCallback OnItemActivate; + CCallback OnItemChanged; + CCallback OnItemChanging; + CCallback OnKeyDown; + //CCallback OnLinkClick; + CCallback OnMarqueeBegin; + CCallback OnSetDispInfo; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +class CCtrlTreeView : public CCtrlBase +{ +public: + CCtrlTreeView( CDlgBase* dlg, int ctrlId ); + + // Classic TV interface + HIMAGELIST CreateDragImage(HTREEITEM hItem); + void DeleteAllItems(); + void DeleteItem(HTREEITEM hItem); + HWND EditLabel(HTREEITEM hItem); + void EndEditLabelNow(BOOL cancel); + void EnsureVisible(HTREEITEM hItem); + void Expand(HTREEITEM hItem, DWORD flag); + COLORREF GetBkColor(); + DWORD GetCheckState(HTREEITEM hItem); + HTREEITEM GetChild(HTREEITEM hItem); + int GetCount(); + HTREEITEM GetDropHilight(); + HWND GetEditControl(); + HTREEITEM GetFirstVisible(); + HIMAGELIST GetImageList(int iImage); + int GetIndent(); + COLORREF GetInsertMarkColor(); + void GetItem(TVITEMEX *tvi); + int GetItemHeight(); + void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect); + DWORD GetItemState(HTREEITEM hItem, DWORD stateMask); + HTREEITEM GetLastVisible(); + COLORREF GetLineColor(); + HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag); + HTREEITEM GetNextSibling(HTREEITEM hItem); + HTREEITEM GetNextVisible(HTREEITEM hItem); + HTREEITEM GetParent(HTREEITEM hItem); + HTREEITEM GetPrevSibling(HTREEITEM hItem); + HTREEITEM GetPrevVisible(HTREEITEM hItem); + HTREEITEM GetRoot(); + DWORD GetScrollTime(); + HTREEITEM GetSelection(); + COLORREF GetTextColor(); + HWND GetToolTips(); + BOOL GetUnicodeFormat(); + unsigned GetVisibleCount(); + HTREEITEM HitTest(TVHITTESTINFO *hti); + HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); + //HTREEITEM MapAccIDToHTREEITEM(UINT id); + //UINT MapHTREEITEMtoAccID(HTREEITEM hItem); + void Select(HTREEITEM hItem, DWORD flag); + void SelectDropTarget(HTREEITEM hItem); + void SelectItem(HTREEITEM hItem); + void SelectSetFirstVisible(HTREEITEM hItem); + COLORREF SetBkColor(COLORREF clBack); + void SetCheckState(HTREEITEM hItem, DWORD state); + void SetImageList(HIMAGELIST hIml, int iImage); + void SetIndent(int iIndent); + void SetInsertMark(HTREEITEM hItem, BOOL fAfter); + COLORREF SetInsertMarkColor(COLORREF clMark); + void SetItem(TVITEMEX *tvi); + void SetItemHeight(short cyItem); + void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); + COLORREF SetLineColor(COLORREF clLine); + void SetScrollTime(UINT uMaxScrollTime); + COLORREF SetTextColor(COLORREF clText); + HWND SetToolTips(HWND hwndToolTips); + BOOL SetUnicodeFormat(BOOL fUnicode); + void SortChildren(HTREEITEM hItem, BOOL fRecurse); + void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); + + // Additional stuff + void TranslateItem(HTREEITEM hItem); + void TranslateTree(); + HTREEITEM FindNamedItem(HTREEITEM hItem, const TCHAR *name); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength); + + // Events + struct TEventInfo { + CCtrlTreeView *treeviewctrl; + union { + NMHDR *nmhdr; + NMTREEVIEW *nmtv; + NMTVDISPINFO *nmtvdi; + NMTVGETINFOTIP *nmtvit; + NMTVKEYDOWN *nmtvkey; + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnDeleteItem; + CCallback OnEndLabelEdit; + CCallback OnGetDispInfo; + CCallback OnGetInfoTip; + CCallback OnItemExpanded; + CCallback OnItemExpanding; + CCallback OnKeyDown; + CCallback OnSelChanged; + CCallback OnSelChanging; + CCallback OnSetDispInfo; + CCallback OnSingleExpand; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCustom + +template +class CCtrlCustom : public CCtrlBase +{ +private: + void (TDlg::*m_pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode); + void (TDlg::*m_pfnOnNotify)(int idCtrl, NMHDR *pnmh); + void (TDlg::*m_pfnOnMeasureItem)(MEASUREITEMSTRUCT *param); + void (TDlg::*m_pfnOnDrawItem)(DRAWITEMSTRUCT *param); + void (TDlg::*m_pfnOnDeleteItem)(DELETEITEMSTRUCT *param); + +public: + CCtrlCustom(TDlg *wnd, int idCtrl, + void (TDlg::*pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode), + void (TDlg::*pfnOnNotify)(int idCtrl, NMHDR *pnmh), + void (TDlg::*pfnOnMeasureItem)(MEASUREITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDrawItem)(DRAWITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDeleteItem)(DELETEITEMSTRUCT *param) = NULL): CCtrlBase(wnd, idCtrl) + { + m_pfnOnCommand = pfnOnCommand; + m_pfnOnNotify = pfnOnNotify; + m_pfnOnMeasureItem = pfnOnMeasureItem; + m_pfnOnDrawItem = pfnOnDrawItem; + m_pfnOnDeleteItem = pfnOnDeleteItem; + } + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) + { + if (m_parentWnd && m_pfnOnCommand) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnCommand)(hwndCtrl, idCtrl, idCode); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnNotify(int idCtrl, NMHDR *pnmh) + { + if (m_parentWnd && m_pfnOnNotify) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnNotify)(idCtrl, pnmh); + return m_parentWnd->m_lresult; + } + return FALSE; + } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnMeasureItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnMeasureItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDrawItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDrawItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDeleteItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDeleteItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CProtoDlgBase + +template +class CProtoDlgBase : public CDlgBase +{ +public: + __inline CProtoDlgBase(TProto *proto, int idDialog, HWND parent ) : + CDlgBase( idDialog, parent ), + m_proto( proto ) + { + } + + __inline void CreateLink( CCtrlData& ctrl, char *szSetting, BYTE type, DWORD iValue) + { + ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, type, iValue ); + } + __inline void CreateLink( CCtrlData& ctrl, const char *szSetting, TCHAR *szValue) + { + ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, szValue ); + } + + __inline TProto *GetProto() { return m_proto; } + +protected: + TProto* m_proto; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton); +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow); + +#endif // __jabber_ui_utils_h__ diff --git a/protocols/IRCG/src/userinfo.cpp b/protocols/IRCG/src/userinfo.cpp new file mode 100644 index 0000000000..8f6378a3ce --- /dev/null +++ b/protocols/IRCG/src/userinfo.cpp @@ -0,0 +1,224 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// 'User details' dialog + +struct UserDetailsDlgProcParam +{ + UserDetailsDlgProcParam( CIrcProto* _pro, HANDLE _info ) : + ppro( _pro ), + hContact( _info ) + {} + + CIrcProto* ppro; + HANDLE hContact; +}; + +#define STR_BASIC "Faster! Searches the network for an exact match of the nickname only. The hostmask is optional and provides further security if used. Wildcards (? and *) are allowed." +#define STR_ADVANCED "Slower! Searches the network for nicknames matching a wildcard string. The hostmask is mandatory and a minimum of 4 characters is necessary in the \"Nick\" field. Wildcards (? and *) are allowed." +#define STR_ERROR "Settings could not be saved!\n\nThe \"Nick\" field must contain at least four characters including wildcards,\n and it must also match the default nickname for this contact." +#define STR_ERROR2 "Settings could not be saved!\n\nA full hostmask must be set for this online detection mode to work." + +INT_PTR CALLBACK UserDetailsDlgProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + UserDetailsDlgProcParam* p = ( UserDetailsDlgProcParam* )GetWindowLongPtr( m_hwnd, GWLP_USERDATA ); + switch (msg) { + case WM_INITDIALOG: + p = new UserDetailsDlgProcParam( NULL, ( HANDLE )lParam ); + SetWindowLongPtr( m_hwnd, GWLP_USERDATA, ( LPARAM )p ); + break; + + case WM_NOTIFY: + if ((( LPNMHDR )lParam )->idFrom == 0 && (( LPNMHDR )lParam )->code == PSN_PARAMCHANGED ) { + p->ppro = ( CIrcProto* )(( PSHNOTIFY* )lParam )->lParam; + + DBVARIANT dbv; + BYTE bAdvanced = p->ppro->getByte( p->hContact, "AdvancedMode", 0); + + TranslateDialogDefault( m_hwnd); + + CheckDlgButton( m_hwnd, IDC_RADIO1, bAdvanced?BST_UNCHECKED:BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_RADIO2, bAdvanced?BST_CHECKED:BST_UNCHECKED); + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), bAdvanced); + + if ( !bAdvanced ) { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); + if ( !p->ppro->getTString( p->hContact, "Default", &dbv)) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + else { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); + if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv)) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); + DBFreeVariant(&dbv); + } } + + if ( !p->ppro->getTString( p->hContact, "UUser", &dbv)) { + SetDlgItemText( m_hwnd, IDC_USER, dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if ( !p->ppro->getTString( p->hContact, "UHost", &dbv)) { + SetDlgItemText( m_hwnd, IDC_HOST, dbv.ptszVal); + DBFreeVariant(&dbv); + } + ProtoBroadcastAck(p->ppro->m_szModuleName, p->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + } + break; + + case WM_COMMAND: + if (( LOWORD(wParam) == IDC_WILDCARD || LOWORD(wParam) == IDC_USER || LOWORD(wParam) == IDC_HOST ) && + ( HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) + return true; + + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), true); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), true); + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON ) { + TCHAR temp[500]; + GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); + DBVARIANT dbv; + + BYTE bAdvanced = IsDlgButtonChecked( m_hwnd, IDC_RADIO1)?0:1; + if ( bAdvanced ) { + if ( GetWindowTextLength(GetDlgItem( m_hwnd, IDC_WILDCARD)) == 0 || + GetWindowTextLength(GetDlgItem( m_hwnd, IDC_USER)) == 0 || + GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HOST)) == 0) + { + MessageBox( NULL, TranslateT(STR_ERROR2), TranslateT("IRC error"), MB_OK|MB_ICONERROR); + return FALSE; + } + + if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { + CMString S = _T(STR_ERROR); + S += _T(" ("); + S += dbv.ptszVal; + S += _T(")"); + if (( lstrlen(temp) < 4 && lstrlen(temp)) || !WCCmp(CharLower(temp), CharLower(dbv.ptszVal))) { + MessageBox( NULL, TranslateTS( S.c_str()), TranslateT( "IRC error" ), MB_OK | MB_ICONERROR ); + DBFreeVariant( &dbv ); + return FALSE; + } + DBFreeVariant( &dbv ); + } + + GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); + if ( lstrlen( GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UWildcard", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); + } + + p->ppro->setByte( p->hContact, "AdvancedMode", bAdvanced); + + GetDlgItemText( m_hwnd, IDC_USER, temp, SIZEOF(temp)); + if (lstrlen(GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UUser", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); + + GetDlgItemText( m_hwnd, IDC_HOST, temp, SIZEOF(temp)); + if (lstrlen(GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UHost", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); + + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON2 ) { + if ( IsDlgButtonChecked( m_hwnd, IDC_RADIO2 )) + SetDlgItemTextA( m_hwnd, IDC_WILDCARD, ""); + SetDlgItemTextA( m_hwnd, IDC_HOST, "" ); + SetDlgItemTextA( m_hwnd, IDC_USER, "" ); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE ); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), FALSE ); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO1 ) { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); + + DBVARIANT dbv; + if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), FALSE ); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO2 ) { + DBVARIANT dbv; + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); + if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv )) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), true); + } + break; + } + return FALSE; +} + +int __cdecl CIrcProto::OnInitUserInfo(WPARAM wParam, LPARAM lParam) +{ + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, lParam, 0); + HANDLE hContact = (HANDLE) lParam; + if ( !hContact || !szProto || lstrcmpiA( szProto, m_szModuleName )) + return 0; + + if ( getByte( hContact, "ChatRoom", 0 ) != 0 ) + return 0; + + if ( getByte( hContact, "DCC", 0 ) != 0 ) + return 0; + + DBVARIANT dbv; + if ( !getTString( hContact, "Default", &dbv )) { + if ( IsChannel( dbv.ptszVal )) { + DBFreeVariant( &dbv ); + return 0; + } + DBFreeVariant(&dbv); + } + + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.flags = ODPF_DONTTRANSLATE; + odp.pszTitle = m_szModuleName; + odp.hIcon = NULL; + odp.dwInitParam = ( LPARAM )this; + odp.hInstance = hInst; + odp.position = -1900000000; + odp.pfnDlgProc = UserDetailsDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO); + odp.pszTitle = m_szModuleName; + UserInfo_AddPage(wParam, &odp); + return 0; +} diff --git a/protocols/IRCG/src/version.h b/protocols/IRCG/src/version.h new file mode 100644 index 0000000000..4def5ec467 --- /dev/null +++ b/protocols/IRCG/src/version.h @@ -0,0 +1,12 @@ +#define __FILEVERSION_STRING 0,11,0,1 +#define __VERSION_STRING "0.11.0.1" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 11, 0, 1) + +#define __DESC "IRC protocol for Miranda NG." +#define __AUTHOR "Miranda team" +#define __AUTHOREMAIL "ghazan@miranda-im.org" +#define __COPYRIGHT "c 2003-2011 Jurgen Persson, George Hazan" +#define __AUTHORWEB "http://miranda-ng.org/" + +#define __PLUGIN_NAME "IRC protocol" +#define __FILENAME "IRC.dll" diff --git a/protocols/IRCG/src/windows.cpp b/protocols/IRCG/src/windows.cpp new file mode 100644 index 0000000000..313e99353c --- /dev/null +++ b/protocols/IRCG/src/windows.cpp @@ -0,0 +1,1406 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "irc.h" + +static WNDPROC OldMgrEditProc; + +///////////////////////////////////////////////////////////////////////////////////////// +// Message Box + +CMessageBoxDlg::CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ) : + CProtoDlgBase( _pro, IDD_MESSAGEBOX, NULL ), + pdci( _dci ), + m_Ok( this, IDOK ) +{ + m_Ok.OnClick = Callback( this, &CMessageBoxDlg::OnOk ); +} + +void CMessageBoxDlg::OnInitDialog() +{ +} + +void CMessageBoxDlg::OnOk( CCtrlButton* ) +{ + CDccSession* dcc = new CDccSession(m_proto, pdci); + + CDccSession* olddcc = m_proto->FindDCCSession(pdci->hContact); + if (olddcc) + olddcc->Disconnect(); + m_proto->AddDCCSession(pdci->hContact, dcc); + + dcc->Connect(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Whois dialog + +CWhoisDlg::CWhoisDlg( CIrcProto* _pro ) : + CCoolIrcDlg( _pro, IDD_INFO ), + m_InfoNick( this, IDC_INFO_NICK ), + m_Reply( this, IDC_REPLY ), + m_Caption( this, IDC_CAPTION ), + m_AwayTime( this, IDC_AWAYTIME ), + m_InfoName( this, IDC_INFO_NAME ), + m_InfoId( this, IDC_INFO_ID ), + m_InfoAddress( this, IDC_INFO_ADDRESS ), + m_InfoChannels( this, IDC_INFO_CHANNELS ), + m_InfoAuth( this, IDC_INFO_AUTH ), + m_InfoServer( this, IDC_INFO_SERVER ), + m_InfoAway2( this, IDC_INFO_AWAY2 ), + m_InfoOther( this, IDC_INFO_OTHER ), + m_Ping( this, IDC_PING ), + m_Version( this, IDC_VERSION ), + m_Time( this, IDC_TIME ), + m_userInfo( this, IDC_USERINFO ), + m_Refresh( this, ID_INFO_GO ), + m_Query( this, ID_INFO_QUERY ) +{ + m_Ping.OnClick = Callback( this, &CWhoisDlg::OnPing ); + m_Version.OnClick = Callback( this, &CWhoisDlg::OnVersion ); + m_Time.OnClick = Callback( this, &CWhoisDlg::OnTime ); + m_userInfo.OnClick = Callback( this, &CWhoisDlg::OnUserInfo ); + m_Refresh.OnClick = Callback( this, &CWhoisDlg::OnGo ); + m_Query.OnClick = Callback( this, &CWhoisDlg::OnQuery ); +} + +void CWhoisDlg::OnInitDialog() +{ + LOGFONT lf; + HFONT hFont = ( HFONT )m_AwayTime.SendMsg( WM_GETFONT, 0, 0 ); + GetObject( hFont, sizeof( lf ), &lf ); + lf.lfWeight = FW_BOLD; + hFont = CreateFontIndirect( &lf ); + m_AwayTime.SendMsg( WM_SETFONT, ( WPARAM )hFont, 0 ); + + CCoolIrcDlg::OnInitDialog(); + + WindowSetIcon( m_hwnd, IDI_WHOIS ); +} + +void CWhoisDlg::OnClose() +{ + ShowWindow( m_hwnd, SW_HIDE); + SendMessage( m_hwnd, WM_SETREDRAW, FALSE, 0); +} + +void CWhoisDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + + HFONT hFont2=(HFONT)SendDlgItemMessage( m_hwnd,IDC_AWAYTIME,WM_GETFONT,0,0); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); + DeleteObject(hFont2); + + m_proto->m_whoisDlg = NULL; +} + +void CWhoisDlg::OnGo( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/WHOIS %s %s"), szTemp, szTemp ); +} + +void CWhoisDlg::OnQuery( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/QUERY %s"), szTemp ); +} + +void CWhoisDlg::OnPing( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001PING %u\001"), szTemp, time(0)); +} + +void CWhoisDlg::OnUserInfo( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001USERINFO\001"), szTemp); +} + +void CWhoisDlg::OnTime( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001TIME\001"), szTemp); +} + +void CWhoisDlg::OnVersion( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), szTemp); +} + +void CWhoisDlg::ShowMessage( const CIrcMessage* pmsg ) +{ + if ( m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()) == CB_ERR) + m_InfoNick.SendMsg( CB_ADDSTRING, 0, (LPARAM) pmsg->parameters[1].c_str()); + int i = m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()); + m_InfoNick.SendMsg( CB_SETCURSEL, i, 0); + m_Caption.SetText( pmsg->parameters[1].c_str()); + m_InfoName.SetText( pmsg->parameters[5].c_str()); + m_InfoAddress.SetText( pmsg->parameters[3].c_str()); + m_InfoId.SetText( pmsg->parameters[2].c_str()); + m_InfoChannels.SetText( _T("")); + m_InfoServer.SetText( _T("")); + m_InfoAway2.SetText( _T("")); + m_InfoAuth.SetText( _T("")); + m_InfoOther.SetText( _T("")); + m_Reply.SetText( _T("")); + SetWindowText( m_hwnd, TranslateT("User information")); + EnableWindow( GetDlgItem( m_hwnd, ID_INFO_QUERY), true ); + ShowWindow( m_hwnd, SW_SHOW); + if ( IsIconic( m_hwnd )) + ShowWindow( m_hwnd, SW_SHOWNORMAL ); + SendMessage( m_hwnd, WM_SETREDRAW, TRUE, 0); + InvalidateRect( m_hwnd, NULL, TRUE); +} + +void CWhoisDlg::ShowMessageNoUser( const CIrcMessage* pmsg ) +{ + m_InfoNick.SetText( pmsg->parameters[2].c_str()); + m_InfoNick.SendMsg( CB_SETEDITSEL, 0,MAKELPARAM(0,-1)); + m_Caption.SetText( pmsg->parameters[2].c_str()); + m_InfoName.SetText( _T("")); + m_InfoAddress.SetText( _T("")); + m_InfoId.SetText( _T("")); + m_InfoChannels.SetText( _T("")); + m_InfoServer.SetText( _T("")); + m_InfoAway2.SetText( _T("")); + m_InfoAuth.SetText( _T("")); + m_Reply.SetText( _T("")); + EnableWindow(GetDlgItem(m_hwnd, ID_INFO_QUERY), false); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Change nickname' dialog + +CNickDlg::CNickDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_NICK ), + m_Ok( this, IDOK ), + m_Enick( this, IDC_ENICK ) +{ + m_Ok.OnClick = Callback( this, &CNickDlg::OnOk ); +} + +void CNickDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + WindowSetIcon( m_hwnd, IDI_RENAME ); + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentNicks", &dbv)) { + for (int i = 0; i<10; i++) + if ( !GetWord( dbv.ptszVal, i).IsEmpty()) + SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)GetWord(dbv.ptszVal, i).c_str()); + + DBFreeVariant(&dbv); +} } + +void CNickDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_nickDlg = NULL; +} + +void CNickDlg::OnOk( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_Enick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/NICK %s"), szTemp); + + CMString S = szTemp; + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentNicks", &dbv )) { + for ( int i = 0; i<10; i++ ) { + CMString s = GetWord(dbv.ptszVal, i); + if ( !s.IsEmpty() && s != szTemp) + S += _T(" ") + s; + } + DBFreeVariant(&dbv); + } + m_proto->setTString( "RecentNicks", S.c_str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Change nickname' dialog + +#define LIST_TIMER 10 + +CListDlg::CListDlg(CIrcProto *_pro) : + CProtoDlgBase( _pro, IDD_LIST, NULL ), + m_Join( this, IDC_JOIN ), + m_list( this, IDC_INFO_LISTVIEW ), + m_list2( this, IDC_INFO_LISTVIEW2 ), + m_status( this, IDC_TEXT ), + m_filter( this, IDC_FILTER_STRING ) +{ + m_list2.OnDoubleClick = m_list.OnDoubleClick = m_Join.OnClick = Callback( this, &CListDlg::OnJoin ); + m_list.OnColumnClick = Callback( this, &CListDlg::List_OnColumnClick ); +} + +void CListDlg::OnInitDialog() +{ + RECT screen; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0); + LVCOLUMN lvC; + int COLUMNS_SIZES[4] ={200, 50,50,2000}; + TCHAR szBuffer[32]; + + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; + for ( int index = 0; index < 4; index++ ) { + lvC.iSubItem = index; + lvC.cx = COLUMNS_SIZES[index]; + + switch( index ) { + case 0: lstrcpy( szBuffer, TranslateT("Channel")); break; + case 1: lstrcpy( szBuffer, _T("#")); break; + case 2: lstrcpy( szBuffer, TranslateT("Mode")); break; + case 3: lstrcpy( szBuffer, TranslateT("Topic")); break; + } + lvC.pszText = szBuffer; + m_list.InsertColumn( index, &lvC ); + m_list2.InsertColumn( index, &lvC ); + } + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); + + m_list.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); + m_list2.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); + WindowSetIcon( m_hwnd, IDI_LIST ); + m_status.SetText( TranslateT( "Please wait..." )); +} + +INT_PTR CListDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_TIMER ) { + ::KillTimer( m_hwnd, m_timer ); m_timer = 0; + + // Retrieve the input text + TCHAR strFilterText[255]; + m_filter.GetText( strFilterText, SIZEOF(strFilterText)); + + if ( strFilterText[0] ) { + int itemCount = 0; + int j = m_list.GetItemCount(); + if ( j <= 0 ) + return FALSE; + + // Empty the filtered list + m_list2.DeleteAllItems(); + + LVITEM lvm; + TCHAR text[255]; + lvm.pszText = text; // Set buffer for texts + lvm.cchTextMax = 128; + lvm.mask = LVIF_TEXT; + for ( int i = 0; i < j; i++ ) { + lvm.iSubItem = 0; // First column + lvm.iItem = i; + m_list.GetItem( &lvm ); + + // Match the text? + TCHAR* t = _tcsstr( lvm.pszText, strFilterText); + if ( t == NULL ) // If no, then Check if in the topics + { + LVITEM lvm2; // To avoid to overwrite the external lvm + TCHAR text[300]; + lvm2.pszText = text; // Set buffer for texts + lvm2.cchTextMax = SIZEOF(text); + lvm2.mask = LVIF_TEXT; + lvm2.iSubItem = 3; // Topic column + lvm2.iItem = i; + m_list.GetItem( &lvm ); + + // Match the text? + t = _tcsstr( lvm.pszText, strFilterText); + } + if ( t ) { + ++itemCount; + + // Column 0 + LVITEM lvItem; + lvItem.iItem = m_list2.GetItemCount(); + lvItem.mask = LVIF_TEXT | LVIF_PARAM; + + lvItem.iSubItem = 0; + lvItem.pszText = lvm.pszText; + lvItem.lParam = lvItem.iItem; + lvItem.iItem = m_list2.InsertItem( &lvItem ); + + // Column 2 + lvm.mask = LVIF_TEXT; + lvm.iSubItem = 1; + lvm.iItem = i; + m_list.GetItem( &lvm ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem = 1; + lvItem.pszText = lvm.pszText; + m_list2.SetItem( &lvItem ); + + // Column 4 + lvm.mask= LVIF_TEXT; + lvm.iSubItem = 3; + lvm.iItem = i; + m_list.GetItem( &lvm ); + + lvItem.mask = LVIF_TEXT; + lvItem.pszText = lvm.pszText; + lvItem.iSubItem = 3; + m_list2.SetItem( &lvItem ); + } } + + // Show the list + SetWindowPos( m_list2.GetHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); + ShowWindow( m_list.GetHwnd(), SW_HIDE ); + + // New dialog title + TCHAR newTitle[255]; + wsprintf( newTitle, TranslateT("%s - Filtered - %d items"), m_title, itemCount ); + SetWindowText( m_hwnd, newTitle ); + } + else { + ShowWindow( m_list.GetHwnd(), SW_SHOW ); + ShowWindow( m_list2.GetHwnd(), SW_HIDE); + SetWindowText( m_hwnd, m_title ); + } } + + return CProtoDlgBase::DlgProc( msg, wParam, lParam ); +} + +void CListDlg::OnChange( CCtrlBase* ctrl ) +{ + if ( ctrl->GetCtrlId() == IDC_FILTER_STRING ) + m_timer = ::SetTimer( m_hwnd, LIST_TIMER, 200, NULL ); +} + +void CListDlg::OnDestroy() +{ + if ( m_timer ) + ::KillTimer( m_hwnd, m_timer ); + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); + m_proto->m_listDlg = NULL; +} + +struct ListViewSortParam +{ + CCtrlListView* pList; + int iSubItem; +}; + +static int CALLBACK ListViewSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + ListViewSortParam* param = ( ListViewSortParam* )lParamSort; + if ( !param->pList->GetHwnd()) + return 0; + + TCHAR temp1[512]; + TCHAR temp2[512]; + LVITEM lvm; + lvm.mask = LVIF_TEXT; + lvm.iItem = lParam1; + lvm.iSubItem = param->iSubItem; + lvm.pszText = temp1; + lvm.cchTextMax = 511; + param->pList->GetItem( &lvm ); + lvm.iItem = lParam2; + lvm.pszText = temp2; + param->pList->GetItem( &lvm ); + if (param->iSubItem != 1){ + if (lstrlen(temp1) != 0 && lstrlen(temp2) !=0) + return lstrcmpi(temp1, temp2); + + return ( *temp1 == 0 ) ? 1 : -1; + } + + return ( StrToInt(temp1) < StrToInt(temp2)) ? 1 : -1; +} + +int CListDlg::Resizer( UTILRESIZECONTROL *urc) +{ + switch( urc->wId ) { + case IDC_INFO_LISTVIEW: + case IDC_INFO_LISTVIEW2: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH; + case IDC_FILTER_STRING: + case IDC_FILTER_BTN: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + case IDC_TEXT: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM | RD_ANCHORX_WIDTH; + } + + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; +} + +void CListDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ev ) +{ + ListViewSortParam param = { &m_list, ev->nmlv->iSubItem }; + m_list.SortItems( ListViewSort, (LPARAM)¶m ); + UpdateList(); +} + +void CListDlg::OnJoin( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_filter.GetText( szTemp, SIZEOF(szTemp)); + + if ( szTemp[0] ) + m_list2.GetItemText( m_list2.GetSelectionMark(), 0, szTemp, 255 ); + else + m_list.GetItemText( m_list.GetSelectionMark(), 0, szTemp, 255 ); + m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); +} + +void CListDlg::UpdateList() +{ + GetWindowText( m_hwnd, m_title, 128); + + int j = m_list.GetItemCount(); + if ( j > 0 ) { + LVITEM lvm; + lvm.mask= LVIF_PARAM; + lvm.iSubItem = 0; + for ( int i = 0; i < j; i++ ) { + lvm.iItem = i; + lvm.lParam = i; + m_list.SetItem( &lvm ); +} } } + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Join' dialog + +CJoinDlg::CJoinDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_NICK, NULL ), + m_Ok( this, IDOK ) +{ + m_Ok.OnClick = Callback( this, &CJoinDlg::OnOk ); +} + +void CJoinDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentChannels", &dbv)) { + for ( int i = 0; i < 20; i++ ) { + if ( !GetWord( dbv.ptszVal, i).IsEmpty()) { + CMString S = GetWord(dbv.ptszVal, i); + ReplaceString( S, _T("%newl"), _T(" ")); + SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + DBFreeVariant(&dbv); +} } + +void CJoinDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_joinDlg = NULL; +} + +void CJoinDlg::OnOk( CCtrlButton* ) +{ + TCHAR szTemp[255]; + GetDlgItemText( m_hwnd, IDC_ENICK, szTemp, SIZEOF(szTemp)); + if ( m_proto->IsChannel( szTemp )) + m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); + else + m_proto->PostIrcMessage( _T("/JOIN #%s"), szTemp ); + + CMString S = szTemp; + ReplaceString( S, _T(" "), _T("%newl")); + CMString SL = S; + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentChannels", &dbv)) { + for (int i = 0; i < 20; i++ ) { + CMString W = GetWord(dbv.ptszVal, i); + if ( !W.IsEmpty() && W != SL) + S += _T(" ") + W; + } + DBFreeVariant(&dbv); + } + m_proto->setTString("RecentChannels", S.c_str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Quick' dialog + +CQuickDlg::CQuickDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_QUICKCONN ), + m_Ok( this, IDOK ), + m_serverCombo( this, IDC_SERVERCOMBO ) +{ + m_Ok.OnClick = Callback( this, &CQuickDlg::OnOk ); + m_serverCombo.OnChange = Callback( this, &CQuickDlg::OnServerCombo ); +} + +void CQuickDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + if ( g_servers.getCount() > 0 ) { + for ( int i=0; i < g_servers.getCount(); i++ ) { + const SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, ( LPARAM )&si ); + } + } + else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); + + m_si = new SERVER_INFO; + m_si->m_group = mir_strdup( "" ); + m_si->m_name = mir_strdup( Translate("---- Not listed server ----")); + + DBVARIANT dbv; + if ( !m_proto->getString( "ServerName", &dbv )) { + m_si->m_address = mir_strdup( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_address = mir_strdup( Translate("Type new server address here")); + + if ( !m_proto->getString( "PortStart", &dbv )) { + m_si->m_portStart = atoi( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_portStart = 6667; + + if ( !m_proto->getString( "PortEnd", &dbv )) { + m_si->m_portEnd = atoi( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_portEnd = 6667; + + m_si->m_iSSL = m_proto->getByte( "UseSSL", 0 ); + + m_serverCombo.AddStringA( m_si->m_name, ( LPARAM )m_si ); + + if ( m_proto->m_quickComboSelection != -1 ) { + m_serverCombo.SetCurSel( m_proto->m_quickComboSelection ); + OnServerCombo( NULL ); + } + else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); +} + +void CQuickDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + + delete m_si; + m_proto->m_quickDlg = NULL; +} + +void CQuickDlg::OnOk( CCtrlButton* ) +{ + GetDlgItemTextA( m_hwnd, IDC_SERVER, m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + GetDlgItemTextA( m_hwnd, IDC_PORT, m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + GetDlgItemTextA( m_hwnd, IDC_PORT2, m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + GetDlgItemTextA( m_hwnd, IDC_PASS, m_proto->m_password, SIZEOF(m_proto->m_password)); + + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + lstrcpyA( m_proto->m_network, pData->m_group ); + pData->m_iSSL = 0; + if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_ON )) + pData->m_iSSL = 2; + if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_AUTO )) + pData->m_iSSL = 1; + m_proto->m_iSSL = pData->m_iSSL; + } + + TCHAR windowname[20]; + GetWindowText( m_hwnd, windowname, 20); + if ( lstrcmpi(windowname, _T("Miranda IRC")) == 0 ) { + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel() - 1; + m_proto->setDword("ServerComboSelection",m_proto->m_serverComboSelection); + m_proto->setString("ServerName",m_proto->m_serverName); + m_proto->setString("PortStart",m_proto->m_portStart); + m_proto->setString("PortEnd",m_proto->m_portEnd); + CallService( MS_DB_CRYPT_ENCODESTRING, 499, (LPARAM)m_proto->m_password); + m_proto->setString("Password",m_proto->m_password); + CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_proto->m_password); + m_proto->setString("Network",m_proto->m_network); + m_proto->setByte("UseSSL",m_proto->m_iSSL); + } + m_proto->m_quickComboSelection = m_serverCombo.GetCurSel(); + m_proto->setDword("QuickComboSelection",m_proto->m_quickComboSelection); + m_proto->DisconnectFromServer(); + m_proto->ConnectToServer(); +} + +void CQuickDlg::OnServerCombo( CCtrlData* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR ) + return; + + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + SetDlgItemTextA( m_hwnd, IDC_SERVER, pData->m_address ); + SetDlgItemTextA( m_hwnd, IDC_PASS, "" ); + SetDlgItemInt( m_hwnd, IDC_PORT, pData->m_portStart, FALSE ); + SetDlgItemInt( m_hwnd, IDC_PORT2, pData->m_portEnd, FALSE ); + + if ( pData->m_iSSL == 0 ) { + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); + } + if ( pData->m_iSSL == 1 ) { + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); + } + if ( pData->m_iSSL == 2 ) { + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); + } + + if ( !strcmp( pData->m_name, Translate("---- Not listed server ----" ))) { + SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, false, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, false, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, false, 0); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), TRUE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),TRUE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), TRUE); + } + else { + SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, true, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, true, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, true, 0); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), FALSE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),FALSE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), FALSE); + } + + EnableWindow(GetDlgItem( m_hwnd, IDOK), true); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Question' dialog + +CQuestionDlg::CQuestionDlg(CIrcProto *_pro, CManagerDlg* owner ) : + CCoolIrcDlg( _pro, IDD_QUESTION, ( owner == NULL ) ? NULL : owner->GetHwnd()), + m_Ok( this, IDOK ), + m_owner( owner ) +{ + m_Ok.OnClick = Callback( this, &CQuestionDlg::OnOk ); +} + +void CQuestionDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + WindowSetIcon( m_hwnd, IDI_IRCQUESTION ); +} + +void CQuestionDlg::OnClose() +{ + if ( m_owner ) + m_owner->CloseQuestion(); +} + +void CQuestionDlg::OnOk( CCtrlButton* ) +{ + int i = GetWindowTextLength( GetDlgItem( m_hwnd, IDC_EDIT )); + if ( i > 0 ) { + TCHAR* l = new TCHAR[ i+2 ]; + GetDlgItemText( m_hwnd, IDC_EDIT, l, i+1 ); + + int j = GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HIDDENEDIT)); + TCHAR* m = new TCHAR[ j+2 ]; + GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, m, j+1 ); + + TCHAR* text = _tcsstr( m, _T("%question")); + TCHAR* p1 = text; + TCHAR* p2 = NULL; + if ( p1 ) { + p1 += 9; + if ( *p1 == '=' && p1[1] == '\"' ) { + p1 += 2; + for ( int k =0; k < 3; k++ ) { + p2 = _tcschr( p1, '\"' ); + if ( p2 ) { + p2++; + if ( k == 2 || (*p2 != ',' || (*p2 == ',' && p2[1] != '\"'))) + *p2 = '\0'; + else + p2 += 2; + p1 = p2; + } } + } + else *p1 = '\0'; + } + + TCHAR* n = ( TCHAR* )alloca( sizeof( TCHAR )*( j+2 )); + GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, n, j+1 ); + CMString S( n ); + ReplaceString( S, text, l ); + m_proto->PostIrcMessageWnd( NULL, NULL, (TCHAR*)S.c_str()); + + delete []m; + delete []l; + + if ( m_owner ) + m_owner->ApplyQuestion(); +} } + +void CQuestionDlg::Activate() +{ + ShowWindow( m_hwnd, SW_SHOW ); + SetActiveWindow( m_hwnd ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Channel Manager' dialog + +CManagerDlg::CManagerDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_CHANMANAGER ), + m_list( this, IDC_LIST ), + + m_check1( this, IDC_CHECK1 ), + m_check2( this, IDC_CHECK2 ), + m_check3( this, IDC_CHECK3 ), + m_check4( this, IDC_CHECK4 ), + m_check5( this, IDC_CHECK5 ), + m_check6( this, IDC_CHECK6 ), + m_check7( this, IDC_CHECK7 ), + m_check8( this, IDC_CHECK8 ), + m_check9( this, IDC_CHECK9 ), + + m_key( this, IDC_KEY ), + m_limit( this, IDC_LIMIT ), + m_topic( this, IDC_TOPIC ), + + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add ban/invite/exception")), + m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit selected ban/invite/exception")), + m_remove( this, IDC_REMOVE, LoadIconEx(IDI_DELETE), LPGEN("Delete selected ban/invite/exception")), + m_applyModes( this, IDC_APPLYMODES, LoadIconEx( IDI_APPLY ), LPGEN("Set these modes for the channel")), + m_applyTopic( this, IDC_APPLYTOPIC, LoadIconEx( IDI_APPLY ), LPGEN("Set this topic for the channel")), + + m_radio1( this, IDC_RADIO1 ), + m_radio2( this, IDC_RADIO2 ), + m_radio3( this, IDC_RADIO3 ) +{ + m_add.OnClick = Callback( this, &CManagerDlg::OnAdd ); + m_edit.OnClick = Callback( this, &CManagerDlg::OnEdit ); + m_remove.OnClick = Callback( this, &CManagerDlg::OnRemove ); + + m_applyModes.OnClick = Callback( this, &CManagerDlg::OnApplyModes ); + m_applyTopic.OnClick = Callback( this, &CManagerDlg::OnApplyTopic ); + + m_check1.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check2.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check3.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check4.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check5.OnChange = Callback( this, &CManagerDlg::OnCheck5 ); + m_check6.OnChange = Callback( this, &CManagerDlg::OnCheck6 ); + m_check7.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check8.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check9.OnChange = Callback( this, &CManagerDlg::OnCheck ); + + m_key.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); + m_limit.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); + m_topic.OnChange = Callback( this, &CManagerDlg::OnChangeTopic ); + + m_radio1.OnChange = Callback( this, &CManagerDlg::OnRadio ); + m_radio2.OnChange = Callback( this, &CManagerDlg::OnRadio ); + m_radio3.OnChange = Callback( this, &CManagerDlg::OnRadio ); + + m_list.OnDblClick = Callback( this, &CManagerDlg::OnListDblClick ); + m_list.OnSelChange = Callback( this, &CManagerDlg::OnChangeList ); +} + +LRESULT CALLBACK MgrEditSubclassProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch( msg ) { + case WM_CHAR : + if ( wParam == 21 || wParam == 11 || wParam == 2 ) { + char w[2]; + if ( wParam == 11 ) { + w[0] = 3; + w[1] = '\0'; + } + if ( wParam == 2 ) { + w[0] = 2; + w[1] = '\0'; + } + if ( wParam == 21 ) { + w[0] = 31; + w[1] = '\0'; + } + SendMessage( m_hwnd, EM_REPLACESEL, false, (LPARAM) w); + SendMessage( m_hwnd, EM_SCROLLCARET, 0, 0 ); + return 0; + } + break; + } + + return CallWindowProc(OldMgrEditProc, m_hwnd, msg, wParam, lParam); +} + +void CManagerDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + POINT pt; + pt.x = 3; + pt.y = 3; + HWND hwndEdit = ChildWindowFromPoint( m_topic.GetHwnd(), pt); + OldMgrEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit, GWLP_WNDPROC,(LONG_PTR)MgrEditSubclassProc); + + WindowSetIcon( m_hwnd, IDI_MANAGER ); + + m_list.SendMsg( LB_SETHORIZONTALEXTENT, 750, NULL ); + m_radio1.SetState( true ); + + const char* modes = m_proto->sChannelModes.c_str(); + if ( !strchr( modes, 't')) m_check1.Disable(); + if ( !strchr( modes, 'n')) m_check2.Disable(); + if ( !strchr( modes, 'i')) m_check3.Disable(); + if ( !strchr( modes, 'm')) m_check4.Disable(); + if ( !strchr( modes, 'k')) m_check5.Disable(); + if ( !strchr( modes, 'l')) m_check6.Disable(); + if ( !strchr( modes, 'p')) m_check7.Disable(); + if ( !strchr( modes, 's')) m_check8.Disable(); + if ( !strchr( modes, 'c')) m_check9.Disable(); +} + +void CManagerDlg::OnClose() +{ + if ( m_applyModes.Enabled() || m_applyTopic.Enabled()) { + int i = MessageBox( NULL, TranslateT("You have not applied all changes!\n\nApply before exiting?"), TranslateT("IRC warning"), MB_YESNOCANCEL|MB_ICONWARNING|MB_DEFBUTTON3); + if ( i == IDCANCEL ) { + m_lresult = TRUE; + return; + } + + if ( i == IDYES ) { + if ( m_applyModes.Enabled()) + OnApplyModes( NULL ); + if ( m_applyTopic.Enabled()) + OnApplyTopic( NULL ); + } } + + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255 ); + CMString S = _T(""); + TCHAR temp[1000]; + for ( int i = 0; i < 5; i++ ) { + if ( m_topic.SendMsg( CB_GETLBTEXT, i, (LPARAM)temp) != LB_ERR) { + CMString S1 = temp; +/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ +#if !defined(__GNUC__) || !defined(UNICODE) + ReplaceString( S1, _T(" "), _T("%¤")); +#endif + S += _T(" ") + S1; + } } + + if ( !S.IsEmpty() && m_proto->IsConnected()) { + mir_sntprintf( temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); + char* p = mir_t2a(temp); + m_proto->setTString(p, S.c_str()); + mir_free(p); + } + DestroyWindow( m_hwnd); +} + +void CManagerDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_managerDlg = NULL; +} + +void CManagerDlg::OnAdd( CCtrlButton* ) +{ + TCHAR temp[100]; + TCHAR mode[3]; + if ( m_radio1.GetState()) { + lstrcpy( mode, _T("+b")); + lstrcpyn( temp, TranslateT("Add ban"), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy( mode, _T("+I")); + lstrcpyn( temp, TranslateT("Add invite"), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy( mode, _T("+e")); + lstrcpyn( temp, TranslateT("Add exception"), 100); + } + + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); + dlg->Show(); + HWND addban_hWnd = dlg->GetHwnd(); + SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); + SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); + + TCHAR temp2[450]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + mir_sntprintf(temp2, 450, _T("/MODE %s %s %s"), window, mode, _T("%question")); + SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); + dlg->Activate(); +} + +void CManagerDlg::OnEdit( CCtrlButton* ) +{ + if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { + int i = m_list.GetCurSel(); + if ( i != LB_ERR ) { + TCHAR* m = m_list.GetItemText( i ); + CMString user = GetWord(m, 0); + mir_free( m ); + + TCHAR temp[100]; + TCHAR mode[3]; + if ( m_radio1.GetState()) { + lstrcpy( mode, _T("b")); + lstrcpyn( temp, TranslateT("Edit ban"), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy( mode, _T("I")); + lstrcpyn( temp, TranslateT("Edit invite?"), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy( mode, _T("e")); + lstrcpyn( temp, TranslateT("Edit exception?"), 100 ); + } + + CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); + dlg->Show(); + HWND addban_hWnd = dlg->GetHwnd(); + SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); + SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); + SetWindowText(GetDlgItem(addban_hWnd, IDC_EDIT), user.c_str()); + + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + TCHAR temp2[450]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + mir_sntprintf(temp2, 450, _T("/MODE %s -%s %s%s/MODE %s +%s %s"), window, mode, user.c_str(), _T("%newl"), window, mode, _T("%question")); + SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); + dlg->Activate(); +} } } + +void CManagerDlg::OnRemove( CCtrlButton* ) +{ + int i = m_list.GetCurSel(); + if ( i != LB_ERR ) { + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + TCHAR temp[100], mode[3]; + TCHAR* m = m_list.GetItemText( i, temp, SIZEOF( temp )); + CMString user = GetWord(m, 0); + + if ( m_radio1.GetState()) { + lstrcpy(mode, _T("-b")); + lstrcpyn(temp, TranslateT( "Remove ban?" ), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy(mode, _T("-I")); + lstrcpyn(temp, TranslateT( "Remove invite?" ), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy(mode, _T("-e")); + lstrcpyn(temp, TranslateT( "Remove exception?" ), 100 ); + } + + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + if ( MessageBox( m_hwnd, user.c_str(), temp, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 ) == IDYES ) { + m_proto->PostIrcMessage( _T("/MODE %s %s %s"), window, mode, user.c_str()); + ApplyQuestion(); + } + CloseQuestion(); +} } + +void CManagerDlg::OnListDblClick( CCtrlListBox* ) +{ + OnEdit( NULL ); +} + +void CManagerDlg::OnChangeList( CCtrlListBox* ) +{ + if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { + m_edit.Enable(); + m_remove.Enable(); +} } + +void CManagerDlg::OnChangeModes( CCtrlData* ) +{ + m_applyModes.Enable(); +} + +void CManagerDlg::OnChangeTopic( CCtrlData* ) +{ + m_applyTopic.Enable(); +} + +void CManagerDlg::OnApplyModes( CCtrlButton* ) +{ + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + TCHAR toadd[10]; *toadd = '\0'; + TCHAR toremove[10]; *toremove = '\0'; + CMString appendixadd = _T(""); + CMString appendixremove = _T(""); + if ( wi->pszMode && _tcschr( wi->pszMode, 't' )) { + if ( !m_check1.GetState()) + lstrcat( toremove, _T("t")); + } + else if ( m_check1.GetState()) + lstrcat( toadd, _T("t")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'n' )) { + if ( !m_check2.GetState()) + lstrcat( toremove, _T("n")); + } + else if ( m_check2.GetState()) + lstrcat( toadd, _T("n")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'i' )) { + if ( !m_check3.GetState()) + lstrcat( toremove, _T("i")); + } + else if ( m_check3.GetState()) + lstrcat( toadd, _T("i")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'm' )) { + if ( !m_check4.GetState()) + lstrcat( toremove, _T("m")); + } + else if ( m_check4.GetState()) + lstrcat( toadd, _T("m")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'p' )) { + if ( !m_check7.GetState()) + lstrcat( toremove, _T("p")); + } + else if ( m_check7.GetState()) + lstrcat( toadd, _T("p")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 's' )) { + if ( !m_check8.GetState()) + lstrcat( toremove, _T("s")); + } + else if ( m_check8.GetState()) + lstrcat( toadd, _T("s")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'c' )) { + if ( !m_check9.GetState()) + lstrcat( toremove, _T("c")); + } + else if ( m_check9.GetState()) + lstrcat( toadd, _T("c")); + + CMString Key = _T(""); + CMString Limit = _T(""); + if ( wi->pszMode && wi->pszPassword && _tcschr( wi->pszMode, 'k' )) { + if ( !m_check5.GetState()) { + lstrcat( toremove, _T("k")); + appendixremove += _T(" ") + CMString(wi->pszPassword); + } + else if ( GetWindowTextLength( m_key.GetHwnd())) { + TCHAR temp[400]; + m_key.GetText( temp, 14); + + if ( Key != temp ) { + lstrcat( toremove, _T("k")); + lstrcat( toadd, _T("k")); + appendixadd += _T(" ") + CMString(temp); + appendixremove += _T(" ") + CMString(wi->pszPassword); + } } + } + else if ( m_check5.GetState() && GetWindowTextLength( m_key.GetHwnd())) { + lstrcat( toadd, _T("k")); + appendixadd += _T(" "); + + TCHAR temp[400]; + m_key.GetText( temp, SIZEOF(temp)); + appendixadd += temp; + } + + if ( _tcschr( wi->pszMode, 'l' )) { + if ( !m_check6.GetState()) + lstrcat( toremove, _T("l")); + else if ( GetWindowTextLength( GetDlgItem( m_hwnd, IDC_LIMIT ))) { + TCHAR temp[15]; + GetDlgItemText( m_hwnd, IDC_LIMIT, temp, SIZEOF(temp)); + if ( wi->pszLimit && lstrcmpi( wi->pszLimit, temp )) { + lstrcat( toadd, _T("l")); + appendixadd += _T(" ") + CMString(temp); + } } + } + else if ( m_check6.GetState() && GetWindowTextLength( m_limit.GetHwnd())) { + lstrcat( toadd, _T("l")); + appendixadd += _T(" "); + + TCHAR temp[15]; + m_limit.GetText( temp, SIZEOF(temp)); + appendixadd += temp; + } + + if ( lstrlen(toadd) || lstrlen( toremove )) { + TCHAR temp[500]; + lstrcpy(temp, _T("/mode ")); + lstrcat(temp, window); + lstrcat(temp, _T(" ")); + if ( lstrlen( toremove )) + mir_sntprintf( temp, 499, _T("%s-%s"), temp, toremove ); + if ( lstrlen( toadd )) + mir_sntprintf( temp, 499, _T("%s+%s"), temp, toadd ); + if (!appendixremove.IsEmpty()) + lstrcat(temp, appendixremove.c_str()); + if (!appendixadd.IsEmpty()) + lstrcat(temp, appendixadd.c_str()); + m_proto->PostIrcMessage( temp); + } } + + m_applyModes.Disable(); +} + +void CManagerDlg::OnApplyTopic( CCtrlButton* ) +{ + TCHAR temp[470]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + m_topic.GetText( temp, SIZEOF(temp)); + m_proto->PostIrcMessage( _T("/TOPIC %s %s"), window, temp); + int i = m_topic.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM)temp); + if ( i != LB_ERR ) + m_topic.SendMsg( CB_DELETESTRING, i, 0); + m_topic.SendMsg( CB_INSERTSTRING, 0, (LPARAM)temp); + m_topic.SetText( temp ); + m_applyTopic.Disable(); +} + +void CManagerDlg::OnCheck( CCtrlData* ) +{ + m_applyModes.Enable(); +} + +void CManagerDlg::OnCheck5( CCtrlData* ) +{ + m_key.Enable( m_check5.GetState()); + m_applyModes.Enable(); +} + +void CManagerDlg::OnCheck6( CCtrlData* ) +{ + m_limit.Enable( m_check6.GetState()); + m_applyModes.Enable(); +} + +void CManagerDlg::OnRadio( CCtrlData* ) +{ + ApplyQuestion(); +} + +void CManagerDlg::ApplyQuestion() +{ + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255); + + TCHAR mode[3]; + lstrcpy( mode, _T("+b")); + if ( m_radio2.GetState()) + lstrcpy( mode, _T("+I")); + if ( m_radio3.GetState()) + lstrcpy( mode, _T("+e")); + m_list.ResetContent(); + m_radio1.Disable(); + m_radio2.Disable(); + m_radio3.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + m_proto->PostIrcMessage( _T("%s %s %s"), _T("/MODE"), window, mode); //wrong overloaded operator if three args +} + +void CManagerDlg::CloseQuestion() +{ + m_add.Enable(); + if ( m_list.GetCurSel() != LB_ERR) { + m_edit.Enable(); + m_remove.Enable(); +} } + +void CManagerDlg::InitManager( int mode, const TCHAR* window ) +{ + SetWindowText( GetDlgItem( m_hwnd, IDC_CAPTION ), window ); + + CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + if ( m_proto->IsConnected()) { + TCHAR temp[1000]; + mir_sntprintf(temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); + + char* p = mir_t2a(temp); + + DBVARIANT dbv; + if ( !m_proto->getTString( p, &dbv )) { + for ( int i = 0; i<5; i++ ) { + CMString S = GetWord(dbv.ptszVal, i); + if ( !S.IsEmpty()) { +/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ +#if !defined(__GNUC__) || !defined(UNICODE) + ReplaceString( S, _T("%¤"), _T(" ")); +#endif + m_topic.SendMsg( CB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + DBFreeVariant(&dbv); + } + mir_free(p); + } + + if ( wi->pszTopic ) + m_topic.SetText( wi->pszTopic ); + + if ( !IsDlgButtonChecked( m_proto->m_managerDlg->GetHwnd(), IDC_NOTOP )) + m_add.Enable(); + + bool add = false; + TCHAR* p1= wi->pszMode; + if ( p1 ) { + while ( *p1 != '\0' && *p1 != ' ' ) { + if (*p1 == '+') + add = true; + if (*p1 == '-') + add = false; + if (*p1 == 't') + m_check1.SetState( add ); + if (*p1 == 'n') + m_check2.SetState( add ); + if (*p1 == 'i') + m_check3.SetState( add ); + if (*p1 == 'm') + m_check4.SetState( add ); + if (*p1 == 'p') + m_check7.SetState( add ); + if (*p1 == 's') + m_check8.SetState( add ); + if (*p1 == 'c') + m_check9.SetState( add ); + if (*p1 == 'k' && add) { + m_check5.SetState( add ); + m_key.Enable( add ); + if ( wi->pszPassword ) + m_key.SetText( wi->pszPassword ); + } + if (*p1 == 'l' && add) { + m_check6.SetState( add ); + m_limit.Enable( add ); + if ( wi->pszLimit ) + m_limit.SetText( wi->pszLimit ); + } + p1++; + if ( mode == 0 ) { + m_limit.Disable(); + m_key.Disable(); + m_check1.Disable(); + m_check2.Disable(); + m_check3.Disable(); + m_check4.Disable(); + m_check5.Disable(); + m_check6.Disable(); + m_check7.Disable(); + m_check8.Disable(); + m_check9.Disable(); + m_add.Disable(); + if ( m_check1.GetState()) + m_topic.Disable(); + CheckDlgButton( m_hwnd, IDC_NOTOP, BST_CHECKED); + } + ShowWindow( m_hwnd, SW_SHOW ); + } } } + + if ( strchr( m_proto->sChannelModes.c_str(), 'b' )) { + m_radio1.SetState( true ); + m_proto->PostIrcMessage( _T("/MODE %s +b"), window); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// 'cool' dialog + +CCoolIrcDlg::CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent ) : + CProtoDlgBase( _pro, dlgId, parent ) +{ +} + +void CCoolIrcDlg::OnInitDialog() +{ + HFONT hFont; + LOGFONT lf; + hFont=(HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); + GetObject(hFont,sizeof(lf),&lf); + lf.lfHeight=(int)(lf.lfHeight*1.2); + lf.lfWeight=FW_BOLD; + hFont=CreateFontIndirect(&lf); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,(WPARAM)hFont,0); + + SendDlgItemMessage( m_hwnd, IDC_LOGO, STM_SETICON,(LPARAM)(HICON)LoadIconEx(IDI_LOGO), 0); +} + +void CCoolIrcDlg::OnDestroy() +{ + HFONT hFont = (HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); + DeleteObject(hFont); + + ReleaseIconEx((HICON)SendDlgItemMessage(m_hwnd, IDC_LOGO, STM_SETICON, 0, 0)); + WindowFreeIcon(m_hwnd); +} + +INT_PTR CCoolIrcDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_CTLCOLOREDIT || msg == WM_CTLCOLORSTATIC ) { + switch( GetDlgCtrlID(( HWND )lParam )) { + case IDC_WHITERECT: case IDC_TEXT: case IDC_CAPTION: case IDC_AWAYTIME: case IDC_LOGO: + SetTextColor((HDC)wParam,RGB(0,0,0)); + SetBkColor((HDC)wParam,RGB(255,255,255)); + return (INT_PTR)GetStockObject(WHITE_BRUSH); + } } + + return CDlgBase::DlgProc(msg, wParam, lParam); +} diff --git a/protocols/IRCG/tools.cpp b/protocols/IRCG/tools.cpp deleted file mode 100644 index 83ac7ae60f..0000000000 --- a/protocols/IRCG/tools.cpp +++ /dev/null @@ -1,905 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// Standard functions - -int CIrcProto::getByte( const char* name, BYTE defaultValue ) -{ return DBGetContactSettingByte( NULL, m_szModuleName, name, defaultValue ); -} - -int CIrcProto::getByte( HANDLE hContact, const char* name, BYTE defaultValue ) -{ return DBGetContactSettingByte(hContact, m_szModuleName, name, defaultValue ); -} - -int CIrcProto::getDword( const char* name, DWORD defaultValue ) -{ return DBGetContactSettingDword( NULL, m_szModuleName, name, defaultValue ); -} - -int CIrcProto::getDword( HANDLE hContact, const char* name, DWORD defaultValue ) -{ return DBGetContactSettingDword(hContact, m_szModuleName, name, defaultValue ); -} - -int CIrcProto::getString( const char* name, DBVARIANT* result ) -{ return DBGetContactSettingString( NULL, m_szModuleName, name, result ); -} - -int CIrcProto::getString( HANDLE hContact, const char* name, DBVARIANT* result ) -{ return DBGetContactSettingString( hContact, m_szModuleName, name, result ); -} - -int CIrcProto::getTString( const char* name, DBVARIANT* result ) -{ return DBGetContactSettingTString( NULL, m_szModuleName, name, result ); -} - -int CIrcProto::getTString( HANDLE hContact, const char* name, DBVARIANT* result ) -{ return DBGetContactSettingTString( hContact, m_szModuleName, name, result ); -} - -int CIrcProto::getWord( const char* name, WORD defaultValue ) -{ return DBGetContactSettingWord( NULL, m_szModuleName, name, defaultValue ); -} - -int CIrcProto::getWord( HANDLE hContact, const char* name, WORD defaultValue ) -{ return DBGetContactSettingWord(hContact, m_szModuleName, name, defaultValue ); -} - -void CIrcProto::setByte( const char* name, BYTE value ) -{ DBWriteContactSettingByte(NULL, m_szModuleName, name, value ); -} - -void CIrcProto::setByte( HANDLE hContact, const char* name, BYTE value ) -{ DBWriteContactSettingByte(hContact, m_szModuleName, name, value ); -} - -void CIrcProto::setDword( const char* name, DWORD value ) -{ DBWriteContactSettingDword(NULL, m_szModuleName, name, value ); -} - -void CIrcProto::setDword( HANDLE hContact, const char* name, DWORD value ) -{ DBWriteContactSettingDword(hContact, m_szModuleName, name, value ); -} - -void CIrcProto::setString( const char* name, const char* value ) -{ DBWriteContactSettingString(NULL, m_szModuleName, name, value ); -} - -void CIrcProto::setString( HANDLE hContact, const char* name, const char* value ) -{ DBWriteContactSettingString(hContact, m_szModuleName, name, value ); -} - -void CIrcProto::setTString( const char* name, const TCHAR* value ) -{ DBWriteContactSettingTString(NULL, m_szModuleName, name, value ); -} - -void CIrcProto::setTString( HANDLE hContact, const char* name, const TCHAR* value ) -{ DBWriteContactSettingTString(hContact, m_szModuleName, name, value ); -} - -void CIrcProto::setWord( const char* name, int value ) -{ DBWriteContactSettingWord(NULL, m_szModuleName, name, value ); -} - -void CIrcProto::setWord( HANDLE hContact, const char* name, int value ) -{ DBWriteContactSettingWord(hContact, m_szModuleName, name, value ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CIrcProto::AddToJTemp(TCHAR op, CMString& sCommand) -{ - CMString res; - - int pos = 0; - for ( ;; ) { - CMString tmp = sCommand.Tokenize( _T(","), pos ); - if ( pos == -1 ) - break; - - tmp = op + tmp; - if ( res.IsEmpty()) - res = tmp; - else - res += _T(" ") + tmp; - } - - DBVARIANT dbv; - if ( !getTString( "JTemp", &dbv )) { - res = CMString(dbv.ptszVal) + _T(" ") + res; - DBFreeVariant( &dbv ); - } - - setTString("JTemp", res.c_str()); -} - -void CIrcProto::ircFork( IrcThreadFunc pFunc, void* arg ) -{ - unsigned threadID; - CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID )); -} - -HANDLE CIrcProto::ircForkEx( IrcThreadFunc pFunc, void* arg ) -{ - unsigned threadID; - return (HANDLE)::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID ); -} - -void CIrcProto::IrcHookEvent( const char* szEvent, IrcEventFunc pFunc ) -{ - ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&pFunc, this ); -} - -CMString __stdcall GetWord(const TCHAR* text, int index) -{ - if ( text && *text ) { - TCHAR* p1 = (TCHAR*)text; - TCHAR* p2 = NULL; - - while (*p1 == ' ') - p1++; - - if (*p1 != '\0') { - for (int i =0; i < index; i++) { - p2 = _tcschr( p1, ' ' ); - if ( !p2 ) - p2 = _tcschr( p1, '\0' ); - else - while ( *p2 == ' ' ) - p2++; - - p1 = p2; - } - - p2 = _tcschr(p1, ' '); - if ( !p2 ) - p2 = _tcschr(p1, '\0'); - - if (p1 != p2) - return CMString( p1, p2-p1 ); - } } - - return CMString(); -} - -const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index) -{ - if ( !text || !lstrlen(text)) - return text; - - const TCHAR* temp = text; - - while (*temp == ' ') - temp++; - - if (index == 0) - return temp; - - for (int i = 0; i < index; i++) { - temp = _tcschr(temp, ' '); - if ( !temp ) - temp = ( TCHAR* )_tcschr(text, '\0'); - else - while (*temp == ' ') - temp++; - text = temp; - } - - return temp; -} - -void __stdcall RemoveLinebreaks( CMString& Message ) -{ - while ( Message.Find( _T("\r\n\r\n"), 0) != -1 ) - ReplaceString( Message, _T("\r\n\r\n"), _T("\r\n")); - - if (Message.Find( _T("\r\n"), 0) == 0) - Message.Delete(0,2); - - if ( (Message.GetLength() > 1) && (Message.Find(_T("\r\n"), Message.GetLength()-2) == 0)) - Message.Delete(Message.GetLength()-2, 2); -} - -String& __stdcall ReplaceString ( String& text, const char* replaceme, const char* newword ) -{ - if ( !text.IsEmpty() && replaceme != NULL) { - int i = 0; - while (( i = text.Find(replaceme, i)) != -1 ) { - text.Delete(i,lstrlenA(replaceme)); - text.Insert(i, newword); - i = i + lstrlenA(newword); - } } - - return text; -} - -CMString& __stdcall ReplaceString ( CMString& text, const TCHAR* replaceme, const TCHAR* newword) -{ - if ( !text.IsEmpty() && replaceme != NULL) { - int i = 0; - while (( i = text.Find(replaceme, i)) != -1 ) { - text.Delete(i,lstrlen(replaceme)); - text.Insert(i, newword); - i = i + lstrlen(newword); - } } - - return text; -} - -char* __stdcall IrcLoadFile( TCHAR* szPath) -{ - char * szContainer = NULL; - DWORD dwSiz = 0; - FILE *hFile = _tfopen(szPath, _T("rb")); - if ( hFile != NULL ) - { - fseek(hFile,0,SEEK_END); // seek to end - dwSiz = ftell(hFile); // size - fseek(hFile,0,SEEK_SET); // seek back to original pos - szContainer = new char [dwSiz+1]; - fread(szContainer, 1, dwSiz, hFile); - szContainer[dwSiz] = '\0'; - fclose(hFile); - return szContainer; - } - - return 0; -} - -int __stdcall WCCmp( const TCHAR* wild, const TCHAR* string ) -{ - if ( wild == NULL || !lstrlen(wild) || string == NULL || !lstrlen(string)) - return 1; - - const TCHAR *cp = NULL, *mp = NULL; - while ((*string) && (*wild != '*')) { - if ((*wild != *string) && (*wild != '?')) - return 0; - - wild++; - string++; - } - - while (*string) { - if (*wild == '*') { - if (!*++wild) - return 1; - - mp = wild; - cp = string+1; - } - else if ((*wild == *string) || (*wild == '?')) { - wild++; - string++; - } - else { - wild = mp; - string = cp++; - } } - - while (*wild == '*') - wild++; - - return !*wild; -} - -bool CIrcProto::IsChannel(const TCHAR* sName) -{ - return ( sChannelPrefixes.Find( sName[0] ) != -1 ); -} - -String __stdcall GetWord(const char* text, int index) -{ - if ( text && text[0] ) { - char* p1 = (char*)text; - char* p2 = NULL; - - while (*p1 == ' ') - p1++; - - if (*p1 != '\0') { - for (int i =0; i < index; i++) { - p2 = strchr( p1, ' ' ); - if ( !p2 ) - p2 = strchr( p1, '\0' ); - else - while ( *p2 == ' ' ) - p2++; - - p1 = p2; - } - - p2 = strchr(p1, ' '); - if (!p2) - p2 = strchr(p1, '\0'); - - if (p1 != p2) - return String( p1, p2-p1+1 ); - } } - - return String(); -} - -bool CIrcProto::IsChannel(const char* sName) -{ - return ( sChannelPrefixes.Find( sName[0] ) != -1 ); -} - -TCHAR* __stdcall my_strstri(const TCHAR* s1, const TCHAR* s2) -{ - int i,j,k; - for(i=0;s1[i];i++) - for(j=i,k=0; _totlower(s1[j]) == _totlower(s2[k]);j++,k++) - if (!s2[k+1]) - return ( TCHAR* )(s1+i); - - return NULL; -} - -TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent) -{ - static TCHAR szTemp[4000]; szTemp[0] = '\0'; - TCHAR* p = szTemp; - bool bBold = false; - bool bUnderline = false; - bool bItalics = false; - - if ( !text ) - return szTemp; - - while ( *text != '\0' ) { - int iFG = -1; - int iBG = -1; - - switch( *text ) { - case '%': //escape - *p++ = '%'; - if ( bReplacePercent ) - *p++ = '%'; - text++; - break; - - case 2: //bold - if ( !bStrip ) { - *p++ = '%'; - *p++ = bBold ? 'B' : 'b'; - } - bBold = !bBold; - text++; - break; - - case 15: //reset - if ( !bStrip ) { - *p++ = '%'; - *p++ = 'r'; - } - bUnderline = false; - bBold = false; - text++; - break; - - case 22: //italics - if ( !bStrip ) { - *p++ = '%'; - *p++ = bItalics ? 'I' : 'i'; - } - bItalics = !bItalics; - text++; - break; - - case 31: //underlined - if ( !bStrip ) { - *p++ = '%'; - *p++ = bUnderline ? 'U' : 'u'; - } - bUnderline = !bUnderline; - text++; - break; - - case 3: //colors - text++; - - // do this if the colors should be reset to default - if ( *text <= 47 || *text >= 58 || *text == '\0' ) { - if ( !bStrip ) { - *p++ = '%'; - *p++ = 'C'; - *p++ = '%'; - *p++ = 'F'; - } - break; - } - else { // some colors should be set... need to find out who - TCHAR buf[3]; - - // fix foreground index - if ( text[1] > 47 && text[1] < 58 && text[1] != '\0') - lstrcpyn( buf, text, 3 ); - else - lstrcpyn( buf, text, 2 ); - text += lstrlen( buf ); - iFG = _ttoi( buf ); - - // fix background color - if ( *text == ',' && text[1] > 47 && text[1] < 58 && text[1] != '\0' ) { - text++; - - if ( text[1] > 47 && text[1] < 58 && text[1] != '\0' ) - lstrcpyn( buf, text, 3 ); - else - lstrcpyn( buf, text, 2 ); - text += lstrlen( buf ); - iBG = _ttoi( buf ); - } } - - if ( iFG >= 0 && iFG != 99 ) - while( iFG > 15 ) - iFG -= 16; - if ( iBG >= 0 && iBG != 99 ) - while( iBG > 15 ) - iBG -= 16; - - // create tag for chat.dll - if ( !bStrip ) { - TCHAR buf[10]; - if ( iFG >= 0 && iFG != 99 ) { - *p++ = '%'; - *p++ = 'c'; - - mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iFG ); - for (int i = 0; i<2; i++) - *p++ = buf[i]; - } - else if (iFG == 99) { - *p++ = '%'; - *p++ = 'C'; - } - - if ( iBG >= 0 && iBG != 99 ) { - *p++ = '%'; - *p++ = 'f'; - - mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iBG ); - for ( int i = 0; i<2; i++ ) - *p++ = buf[i]; - } - else if ( iBG == 99 ) { - *p++ = '%'; - *p++ = 'F'; - } } - break; - - default: - *p++ = *text++; - break; - } } - - *p = '\0'; - return szTemp; -} - -INT_PTR CIrcProto::CallChatEvent(WPARAM wParam, LPARAM lParam) -{ - GCEVENT * gce = (GCEVENT *)lParam; - INT_PTR iVal = 0; - - // first see if the scripting module should modify or stop this event - if ( m_bMbotInstalled && m_scriptingEnabled && gce - && gce->time != 0 && (gce->pDest->pszID == NULL - || lstrlen(gce->pDest->ptszID) != 0 && lstrcmpi(gce->pDest->ptszID , SERVERWINDOW))) - { - GCEVENT *gcevent= (GCEVENT*) lParam; - GCEVENT *gcetemp = NULL; - WPARAM wp = wParam; - gcetemp = (GCEVENT *)mir_alloc(sizeof(GCEVENT)); - gcetemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); - gcetemp->pDest->iType = gcevent->pDest->iType; - gcetemp->dwFlags = gcevent->dwFlags; - gcetemp->bIsMe = gcevent->bIsMe; - gcetemp->cbSize = sizeof(GCEVENT); - gcetemp->dwItemData = gcevent->dwItemData; - gcetemp->time = gcevent->time; - gcetemp->pDest->ptszID = mir_tstrdup( gcevent->pDest->ptszID ); - gcetemp->pDest->pszModule = mir_strdup( gcevent->pDest->pszModule ); - gcetemp->ptszText = mir_tstrdup( gcevent->ptszText ); - gcetemp->ptszUID = mir_tstrdup( gcevent->ptszUID ); - gcetemp->ptszNick = mir_tstrdup( gcevent->ptszNick ); - gcetemp->ptszStatus = mir_tstrdup( gcevent->ptszStatus ); - gcetemp->ptszUserInfo = mir_tstrdup( gcevent->ptszUserInfo ); - - if ( Scripting_TriggerMSPGuiIn( &wp, gcetemp ) && gcetemp ) { - //MBOT CORRECTIONS - //if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID ) { - if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID && - !my_strstri(gcetemp->pDest->ptszID, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline"))) { - - CMString sTempId = MakeWndID( gcetemp->pDest->ptszID ); - mir_realloc( gcetemp->pDest->ptszID, sizeof(TCHAR)*(sTempId.GetLength() + 1)); - lstrcpyn(gcetemp->pDest->ptszID, sTempId.c_str(), sTempId.GetLength()+1); - } - iVal = CallServiceSync(MS_GC_EVENT, wp, (LPARAM) gcetemp); - } - - if ( gcetemp ) { - mir_free(( void* )gcetemp->pszNick); - mir_free(( void* )gcetemp->pszUID); - mir_free(( void* )gcetemp->pszStatus); - mir_free(( void* )gcetemp->pszUserInfo); - mir_free(( void* )gcetemp->pszText); - mir_free(( void* )gcetemp->pDest->pszID); - mir_free(( void* )gcetemp->pDest->pszModule); - mir_free(( void* )gcetemp->pDest); - mir_free(( void* )gcetemp); - } - - return iVal; - } - - return CallServiceSync( MS_GC_EVENT, wParam, ( LPARAM )gce ); -} - -INT_PTR CIrcProto::DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, - const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, - DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe, time_t timestamp) -{ - GCDEST gcd = {0}; - GCEVENT gce = {0}; - CMString sID; - CMString sText = _T(""); - - if ( iEvent == GC_EVENT_INFORMATION && bIsMe && !bEcho ) - return false; - - if ( pszText ) { - if (iEvent != GC_EVENT_SENDMESSAGE) - sText = DoColorCodes(pszText, FALSE, TRUE); - else - sText = pszText; - } - - if ( pszWindow ) { - if ( lstrcmpi( pszWindow, SERVERWINDOW)) - sID = pszWindow + (CMString)_T(" - ") + m_info.sNetwork; - else - sID = pszWindow; - gcd.ptszID = (TCHAR*)sID.c_str(); - } - else gcd.ptszID = NULL; - - gcd.pszModule = m_szModuleName; - gcd.iType = iEvent; - - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - gce.ptszStatus = pszStatus; - gce.dwFlags = GC_TCHAR + ((bAddToLog) ? GCEF_ADDTOLOG : 0); - gce.ptszNick = pszNick; - gce.ptszUID = pszNick; - if (iEvent == GC_EVENT_TOPIC) - gce.ptszUserInfo = pszUserInfo; - else - gce.ptszUserInfo = m_showAddresses ? pszUserInfo : NULL; - - if ( !sText.IsEmpty()) - gce.ptszText = sText.c_str(); - - gce.dwItemData = dwItemData; - if(timestamp == 1) - gce.time = time(NULL); - else - gce.time = timestamp; - gce.bIsMe = bIsMe; - return CallChatEvent((WPARAM)0, (LPARAM)&gce); -} - -CMString CIrcProto::ModeToStatus(int sMode) -{ - if ( sUserModes.Find( sMode ) != -1 ) { - switch( sMode ) { - case 'q': - return (CMString)_T("Owner"); - case 'o': - return (CMString)_T("Op"); - case 'v': - return (CMString)_T("Voice"); - case 'h': - return (CMString)_T("Halfop"); - case 'a': - return (CMString)_T("Admin"); - default: - return (CMString)_T("Unknown"); - } } - - return (CMString)_T("Normal"); -} - -CMString CIrcProto::PrefixToStatus(int cPrefix) -{ - const TCHAR* p = _tcschr( sUserModePrefixes.c_str(), cPrefix ); - if ( p ) { - int index = int( p - sUserModePrefixes.c_str()); - return ModeToStatus( sUserModes[index] ); - } - - return (CMString)_T("Normal"); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Timer functions - -struct TimerPair -{ - TimerPair( CIrcProto* _pro, UINT_PTR _id ) : - ppro( _pro ), - idEvent( _id ) - {} - - UINT_PTR idEvent; - CIrcProto* ppro; -}; - -static int CompareTimers( const TimerPair* p1, const TimerPair* p2 ) -{ - if ( p1->idEvent < p2->idEvent ) - return -1; - return ( p1->idEvent == p2->idEvent ) ? 0 : 1; -} - -static OBJLIST timers( 10, CompareTimers ); -static CRITICAL_SECTION timers_cs; - -void InitTimers( void ) -{ - InitializeCriticalSection( &timers_cs ); -} - -void UninitTimers( void ) -{ - EnterCriticalSection( &timers_cs ); - timers.destroy(); - LeaveCriticalSection( &timers_cs ); - DeleteCriticalSection( &timers_cs ); -} - -CIrcProto* GetTimerOwner( UINT_PTR nIDEvent ) -{ - CIrcProto* result; - - EnterCriticalSection( &timers_cs ); - TimerPair temp( NULL, nIDEvent ); - int idx = timers.getIndex( &temp ); - if ( idx == -1 ) - result = NULL; - else - result = timers[ idx ].ppro; - LeaveCriticalSection( &timers_cs ); - return result; -} - -void CIrcProto::SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc) -{ - if (nIDEvent) - KillChatTimer(nIDEvent); - - nIDEvent = SetTimer( NULL, NULL, uElapse, lpTimerFunc); - - EnterCriticalSection( &timers_cs ); - timers.insert( new TimerPair( this, nIDEvent )); - LeaveCriticalSection( &timers_cs ); -} - -void CIrcProto::KillChatTimer(UINT_PTR &nIDEvent) -{ - if ( nIDEvent ) { - EnterCriticalSection( &timers_cs ); - TimerPair temp( this, nIDEvent ); - int idx = timers.getIndex( &temp ); - if ( idx != -1 ) - timers.remove( idx ); - - LeaveCriticalSection( &timers_cs ); - - KillTimer(NULL, nIDEvent); - nIDEvent = NULL; -} } - -///////////////////////////////////////////////////////////////////////////////////////// - -int CIrcProto::SetChannelSBText(CMString sWindow, CHANNELINFO * wi) -{ - CMString sTemp = _T(""); - if(wi->pszMode) - { - sTemp += _T("["); - sTemp += wi->pszMode; - sTemp += _T("] "); - } - if(wi->pszTopic) - sTemp += wi->pszTopic; - sTemp = DoColorCodes(sTemp.c_str(), TRUE, FALSE); - return DoEvent(GC_EVENT_SETSBTEXT, sWindow.c_str(), NULL, sTemp.c_str(), NULL, NULL, NULL, FALSE, FALSE, 0); -} - -CMString CIrcProto::MakeWndID(const TCHAR* sWindow) -{ - TCHAR buf[200]; - mir_sntprintf( buf, SIZEOF(buf), _T("%s - %s"), sWindow, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline")); - return CMString(buf); -} - -bool CIrcProto::FreeWindowItemData(CMString window, CHANNELINFO* wis) -{ - CHANNELINFO* wi; - if ( !wis ) - wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - else - wi = wis; - if ( wi ) { - delete[] wi->pszLimit; - delete[]wi->pszMode; - delete[]wi->pszPassword; - delete[]wi->pszTopic; - delete wi; - return true; - } - return false; -} - -bool CIrcProto::AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic) -{ - CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if ( wi ) { - if ( pszLimit ) { - wi->pszLimit = ( TCHAR* )realloc( wi->pszLimit, sizeof(TCHAR)*(lstrlen(pszLimit)+1)); - lstrcpy( wi->pszLimit, pszLimit ); - } - if ( pszMode ) { - wi->pszMode = ( TCHAR* )realloc( wi->pszMode, sizeof(TCHAR)*(lstrlen(pszMode)+1)); - lstrcpy( wi->pszMode, pszMode ); - } - if ( pszPassword ) { - wi->pszPassword = ( TCHAR* )realloc( wi->pszPassword, sizeof(TCHAR)*(lstrlen(pszPassword)+1)); - lstrcpy( wi->pszPassword, pszPassword ); - } - if ( pszTopic ) { - wi->pszTopic = ( TCHAR* )realloc( wi->pszTopic, sizeof(TCHAR)*(lstrlen(pszTopic)+1)); - lstrcpy( wi->pszTopic, pszTopic ); - } - - SetChannelSBText(window, wi); - return true; - } - return false; -} - -void CIrcProto::CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ) -{ - char temp[MAXMODULELABELLENGTH]; - mir_snprintf( temp, sizeof(temp), "%s%s", m_szModuleName, serviceName ); - CreateServiceFunctionObj( temp, ( MIRANDASERVICEOBJ )*( void** )&pFunc, this ); -} - -void CIrcProto::FindLocalIP(HANDLE con) // inspiration from jabber -{ - // Determine local IP - int socket = CallService( MS_NETLIB_GETSOCKET, (WPARAM) con, 0); - if ( socket != INVALID_SOCKET ) { - struct sockaddr_in saddr; - int len = sizeof(saddr); - getsockname(socket, (struct sockaddr *) &saddr, &len); - lstrcpynA(m_myLocalHost, inet_ntoa(saddr.sin_addr), 49); - m_myLocalPort = ntohs(saddr.sin_port ); -} } - -void CIrcProto::DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...) -{ - TCHAR temp[4096]; - CMString S = _T(""); - switch( type ) { - case 1: - S = _T("USERHOST"); - break; - case 2: - S = _T("WHO"); - break; - default: - S = _T("USERHOST"); - break; - } - - va_list ap; - va_start(ap, userhostparams); - mir_vsntprintf(temp, SIZEOF(temp), (S + _T(" ") + userhostparams).c_str(), ap); - va_end(ap); - - // Add reason - if ( type == 1 ) - vUserhostReasons.insert( new CMString( reason )); - else if ( type == 2 ) - vWhoInProgress.insert( new CMString( reason)); - - // Do command - if ( IsConnected() && bSendCommand ) - SendIrcMessage( temp, false ); -} - -CMString CIrcProto::GetNextUserhostReason(int type) -{ - CMString reason = _T(""); - switch( type ) { - case 1: - if ( !vUserhostReasons.getCount()) - return CMString(); - - // Get reason - reason = vUserhostReasons[0]; - vUserhostReasons.remove( 0 ); - break; - case 2: - if ( !vWhoInProgress.getCount()) - return CMString(); - - // Get reason - reason = vWhoInProgress[0]; - vWhoInProgress.remove( 0 ); - break; - } - - return reason; -} - -CMString CIrcProto::PeekAtReasons( int type ) -{ - switch ( type ) { - case 1: - if (!vUserhostReasons.getCount()) - return CMString(); - return vUserhostReasons[0]; - - case 2: - if (!vWhoInProgress.getCount()) - return CMString(); - return vWhoInProgress[0]; - - } - return CMString(); -} - -void CIrcProto::ClearUserhostReasons(int type) -{ - switch (type) { - case 1: - vUserhostReasons.destroy(); - break; - case 2: - vWhoInProgress.destroy(); - break; -} } - -//////////////////////////////////////////////////////////////////// - -SERVER_INFO::~SERVER_INFO() -{ - mir_free( m_name ); - mir_free( m_address ); - mir_free( m_group ); -} diff --git a/protocols/IRCG/ui_utils.cpp b/protocols/IRCG/ui_utils.cpp deleted file mode 100644 index d7c8e4b6b6..0000000000 --- a/protocols/IRCG/ui_utils.cpp +++ /dev/null @@ -1,1820 +0,0 @@ -/* - -Object UI extensions -Copyright (C) 2008 Victor Pavlychko, George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.cpp $ -Revision : $Revision: 13133 $ -Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ -Last change by : $Author: george.hazan $ - -*/ - -#include "irc.h" -#include "ui_utils.h" - -extern HINSTANCE hInst; - -CDlgBase::CDlgBase(int idDialog, HWND hwndParent) : - m_controls(1, CCtrlBase::cmp) -{ - m_idDialog = idDialog; - m_hwndParent = hwndParent; - m_hwnd = NULL; - m_first = NULL; - m_isModal = false; - m_initialized = false; - m_autoClose = CLOSE_ON_OK|CLOSE_ON_CANCEL; - m_forceResizable = false; -} - -CDlgBase::~CDlgBase() -{ - // remove handlers - m_controls.destroy(); - - if (m_hwnd) - DestroyWindow(m_hwnd); -} - -void CDlgBase::Create() -{ - ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_HIDE); -} - -void CDlgBase::Show() -{ - ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_SHOW); -} - -int CDlgBase::DoModal() -{ - m_isModal = true; - return DialogBoxParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this); -} - -int CDlgBase::Resizer(UTILRESIZECONTROL*) -{ - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; -} - -INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - { - m_initialized = false; - TranslateDialogDefault(m_hwnd); - - for ( CCtrlBase* p = m_first; p != NULL; p = p->m_next ) - AddControl( p ); - - NotifyControls(&CCtrlBase::OnInit); - OnInitDialog(); - - m_initialized = true; - return TRUE; - } - - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnMeasureItem(param); - return FALSE; - } - - case WM_DRAWITEM: - { - DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnDrawItem(param); - return FALSE; - } - - case WM_DELETEITEM: - { - DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnDeleteItem(param); - return FALSE; - } - - case WM_COMMAND: - { - HWND hwndCtrl = (HWND)lParam; - WORD idCtrl = LOWORD(wParam); - WORD idCode = HIWORD(wParam); - if (CCtrlBase *ctrl = FindControl(idCtrl)) { - BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode); - if ( result != FALSE ) - return result; - } - - if (idCode == BN_CLICKED && - ((idCtrl == IDOK) && (m_autoClose & CLOSE_ON_OK) || - (idCtrl == IDCANCEL) && (m_autoClose & CLOSE_ON_CANCEL))) - { - PostMessage( m_hwnd, WM_CLOSE, 0, 0 ); - } - return FALSE; - } - - case WM_NOTIFY: - { - int idCtrl = wParam; - NMHDR *pnmh = (NMHDR *)lParam; - - if (pnmh->idFrom == 0) - { - if (pnmh->code == PSN_APPLY) - { - NotifyControls(&CCtrlBase::OnApply); - OnApply(); - } - else if (pnmh->code == PSN_RESET) - { - NotifyControls(&CCtrlBase::OnReset); - OnReset(); - } - } - - if (CCtrlBase *ctrl = FindControl(pnmh->idFrom)) - return ctrl->OnNotify(idCtrl, pnmh); - return FALSE; - } - - case WM_SIZE: - { - if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_SIZEBOX)) - { - UTILRESIZEDIALOG urd; - urd.cbSize = sizeof(urd); - urd.hwndDlg = m_hwnd; - urd.hInstance = hInst; - urd.lpTemplate = MAKEINTRESOURCEA(m_idDialog); - urd.lParam = 0; - urd.pfnResizer = GlobalDlgResizer; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); - } - return TRUE; - } - - case WM_CLOSE: - { - m_lresult = FALSE; - OnClose(); - if ( !m_lresult ) - { - if (m_isModal) - EndDialog(m_hwnd, 0); - else - DestroyWindow(m_hwnd); - } - return TRUE; - } - - case WM_DESTROY: - { - OnDestroy(); - NotifyControls(&CCtrlBase::OnDestroy); - - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); - m_hwnd = NULL; - if (m_isModal) - { - m_isModal = false; - } else - { // modeless dialogs MUST be allocated with 'new' - delete this; - } - return TRUE; - } - } - - return FALSE; -} - -INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CDlgBase *wnd = NULL; - if (msg == WM_INITDIALOG) - { - SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); - wnd = (CDlgBase *)lParam; - wnd->m_hwnd = hwnd; - } else - { - wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - } - - if (!wnd) return FALSE; - - wnd->m_msg.hwnd = hwnd; - wnd->m_msg.message = msg; - wnd->m_msg.wParam = wParam; - wnd->m_msg.lParam = lParam; - return wnd->DlgProc(msg, wParam, lParam); -} - -int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) -{ - CDlgBase *wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!wnd) return 0; - - return wnd->Resizer(urc); -} - -void CDlgBase::AddControl(CCtrlBase *ctrl) -{ - m_controls.insert(ctrl); -} - -void CDlgBase::NotifyControls(void (CCtrlBase::*fn)()) -{ - for (int i = 0; i < m_controls.getCount(); ++i) - (m_controls[i]->*fn)(); -} - -CCtrlBase* CDlgBase::FindControl(int idCtrl) -{ - CCtrlBase search(NULL, idCtrl); - return m_controls.find(&search); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCombo class - -CCtrlCombo::CCtrlCombo( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -int CCtrlCombo::AddString(const TCHAR *text, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); - if ( data ) - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -int CCtrlCombo::AddStringA(const char *text, LPARAM data) -{ - int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); - if ( data ) - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlCombo::DeleteString(int index) -{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0); -} - -int CCtrlCombo::FindString(const TCHAR *str, int index, bool exact ) -{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlCombo::FindStringA(const char *str, int index, bool exact ) -{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlCombo::GetCount() -{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0); -} - -int CCtrlCombo::GetCurSel() -{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); -} - -bool CCtrlCombo::GetDroppedState() -{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false; -} - -LPARAM CCtrlCombo::GetItemData(int index) -{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0); -} - -TCHAR* CCtrlCombo::GetItemText(int index) -{ - TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); - return result; -} - -TCHAR* CCtrlCombo::GetItemText(int index, TCHAR *buf, int size) -{ - TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); - lstrcpyn(buf, result, size); - return buf; -} - -int CCtrlCombo::InsertString(TCHAR *text, int pos, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlCombo::ResetContent() -{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0); -} - -int CCtrlCombo::SelectString(TCHAR *str) -{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str); -} - -int CCtrlCombo::SetCurSel(int index) -{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0); -} - -void CCtrlCombo::SetItemData(int index, LPARAM data) -{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data); -} - -void CCtrlCombo::ShowDropdown(bool show) -{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListBox class - -CCtrlListBox::CCtrlListBox( CDlgBase* dlg, int ctrlId ) : - CCtrlBase( dlg, ctrlId ) -{ -} - -BOOL CCtrlListBox::OnCommand(HWND, WORD, WORD idCode) -{ - switch (idCode) - { - case LBN_DBLCLK: OnDblClick(this); break; - case LBN_SELCANCEL: OnSelCancel(this); break; - case LBN_SELCHANGE: OnSelChange(this); break; - } - return TRUE; -} - -int CCtrlListBox::AddString(TCHAR *text, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)text); - SendMessage(m_hwnd, LB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlListBox::DeleteString(int index) -{ SendMessage(m_hwnd, LB_DELETESTRING, index, 0); -} - -int CCtrlListBox::FindString( TCHAR *str, int index, bool exact) -{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlListBox::GetCount() -{ return SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); -} - -int CCtrlListBox::GetCurSel() -{ return SendMessage(m_hwnd, LB_GETCURSEL, 0, 0); -} - -LPARAM CCtrlListBox::GetItemData(int index) -{ return SendMessage(m_hwnd, LB_GETITEMDATA, index, 0); -} - -TCHAR* CCtrlListBox::GetItemText(int index) -{ - TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); - return result; -} - -TCHAR* CCtrlListBox::GetItemText(int index, TCHAR *buf, int size) -{ - TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); - lstrcpyn(buf, result, size); - return buf; -} - -bool CCtrlListBox::GetSel(int index) -{ return SendMessage(m_hwnd, LB_GETSEL, index, 0) ? true : false; -} - -int CCtrlListBox::GetSelCount() -{ return SendMessage(m_hwnd, LB_GETSELCOUNT, 0, 0); -} - -int* CCtrlListBox::GetSelItems(int *items, int count) -{ - SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)items); - return items; -} - -int* CCtrlListBox::GetSelItems() -{ - int count = GetSelCount() + 1; - int *result = (int *)mir_alloc(sizeof(int) * count); - SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)result); - result[count-1] = -1; - return result; -} - -int CCtrlListBox::InsertString(TCHAR *text, int pos, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlListBox::ResetContent() -{ SendMessage(m_hwnd, LB_RESETCONTENT, 0, 0); -} - -int CCtrlListBox::SelectString(TCHAR *str) -{ return SendMessage(m_hwnd, LB_SELECTSTRING, 0, (LPARAM)str); -} - -int CCtrlListBox::SetCurSel(int index) -{ return SendMessage(m_hwnd, LB_SETCURSEL, index, 0); -} - -void CCtrlListBox::SetItemData(int index, LPARAM data) -{ SendMessage(m_hwnd, LB_SETITEMDATA, index, data); -} - -void CCtrlListBox::SetSel(int index, bool sel) -{ SendMessage(m_hwnd, LB_SETSEL, sel ? TRUE : FALSE, index); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCheck class - -CCtrlCheck::CCtrlCheck( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -int CCtrlCheck::GetState() -{ - return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); -} - -void CCtrlCheck::SetState(int state) -{ - SendMessage(m_hwnd, BM_SETCHECK, state, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlEdit class - -CCtrlEdit::CCtrlEdit( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlData class - -CCtrlData::CCtrlData( CDlgBase *wnd, int idCtrl ) : - CCtrlBase( wnd, idCtrl ), - m_dbLink( NULL ) -{ -} - -void CCtrlData::OnInit() -{ - CCtrlBase::OnInit(); - m_changed = false; -} - -void CCtrlData::NotifyChange() -{ - if (!m_parentWnd || m_parentWnd->IsInitialized()) m_changed = true; - if ( m_parentWnd ) { - m_parentWnd->OnChange(this); - if ( m_parentWnd->IsInitialized()) - ::SendMessage( ::GetParent( m_parentWnd->GetHwnd()), PSM_CHANGED, 0, 0 ); - } - - OnChange(this); -} - -void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ) -{ - m_dbLink = new CDbLink( szModuleName, szSetting, type, iValue); -} - -void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ) -{ - m_dbLink = new CDbLink( szModuleName, szSetting, DBVT_TCHAR, szValue ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -int CCtrlButton::GetState() -{ return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); -} - -void CCtrlButton::SetState(int state) -{ SendMessage(m_hwnd, BM_SETCHECK, state, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlMButton - -CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ) : - CCtrlButton( dlg, ctrlId ), - m_hIcon( hIcon ), - m_toolTip( tooltip ) -{ -} - -CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ) : - CCtrlButton( dlg, ctrlId ), - m_hIcon( LoadSkinnedIcon(iCoreIcon)), - m_toolTip( tooltip ) -{ -} - -CCtrlMButton::~CCtrlMButton() -{ - if ( m_hIcon ) CallService( MS_SKIN2_RELEASEICON, (WPARAM)m_hIcon, 0 ); -} - -void CCtrlMButton::OnInit() -{ - CCtrlButton::OnInit(); - - SendMessage( m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon ); - SendMessage( m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0); -} - -void CCtrlMButton::MakeFlat() -{ - SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0); -} - -void CCtrlMButton::MakePush() -{ - SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -CCtrlButton::CCtrlButton( CDlgBase* wnd, int idCtrl ) : - CCtrlBase( wnd, idCtrl ) -{ -} - -BOOL CCtrlButton::OnCommand(HWND, WORD, WORD idCode) -{ - if ( idCode == BN_CLICKED || idCode == STN_CLICKED ) - OnClick(this); - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlHyperlink - -CCtrlHyperlink::CCtrlHyperlink( CDlgBase* wnd, int idCtrl, const char* url ) : - CCtrlBase( wnd, idCtrl ), - m_url(url) -{ -} - -BOOL CCtrlHyperlink::OnCommand(HWND, WORD, WORD) -{ - ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW); - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlClc -CCtrlClc::CCtrlClc( CDlgBase* dlg, int ctrlId ): - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh }; - switch (pnmh->code) - { - case CLN_EXPANDED: OnExpanded(&evt); break; - case CLN_LISTREBUILT: OnListRebuilt(&evt); break; - case CLN_ITEMCHECKED: OnItemChecked(&evt); break; - case CLN_DRAGGING: OnDragging(&evt); break; - case CLN_DROPPED: OnDropped(&evt); break; - case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break; - case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break; - case CLN_DRAGSTOP: OnDragStop(&evt); break; - case CLN_NEWCONTACT: OnNewContact(&evt); break; - case CLN_CONTACTMOVED: OnContactMoved(&evt); break; - case CLN_CHECKCHANGED: OnCheckChanged(&evt); break; - case NM_CLICK: OnClick(&evt); break; - } - return FALSE; -} - -void CCtrlClc::AddContact(HANDLE hContact) -{ SendMessage(m_hwnd, CLM_ADDCONTACT, (WPARAM)hContact, 0); -} - -void CCtrlClc::AddGroup(HANDLE hGroup) -{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0); -} - -void CCtrlClc::AutoRebuild() -{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0); -} - -void CCtrlClc::DeleteItem(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0); -} - -void CCtrlClc::EditLabel(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0); -} - -void CCtrlClc::EndEditLabel(bool save) -{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0); -} - -void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk) -{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE); -} - -void CCtrlClc::Expand(HANDLE hItem, DWORD flags) -{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags); -} - -HANDLE CCtrlClc::FindContact(HANDLE hContact) -{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, (WPARAM)hContact, 0); -} - -HANDLE CCtrlClc::FindGroup(HANDLE hGroup) -{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0); -} - -COLORREF CCtrlClc::GetBkColor() -{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0); -} - -bool CCtrlClc::GetCheck(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false; -} - -int CCtrlClc::GetCount() -{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0); -} - -HWND CCtrlClc::GetEditControl() -{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0); -} - -DWORD CCtrlClc::GetExpand(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0); -} - -int CCtrlClc::GetExtraColumns() -{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0); -} - -BYTE CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) -{ return (BYTE)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFF); -} - -HIMAGELIST CCtrlClc::GetExtraImageList() -{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0); -} - -HFONT CCtrlClc::GetFont(int iFontId) -{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0); -} - -HANDLE CCtrlClc::GetSelection() -{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0); -} - -HANDLE CCtrlClc::HitTest(int x, int y, DWORD *hitTest) -{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y)); -} - -void CCtrlClc::SelectItem(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0); -} - -void CCtrlClc::SetBkBitmap(DWORD mode, HBITMAP hBitmap) -{ SendMessage(m_hwnd, CLM_SETBKBITMAP, mode, (LPARAM)hBitmap); -} - -void CCtrlClc::SetBkColor(COLORREF clBack) -{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0); -} - -void CCtrlClc::SetCheck(HANDLE hItem, bool check) -{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0); -} - -void CCtrlClc::SetExtraColumns(int iColumns) -{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0); -} - -void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage) -{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); -} - -void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList) -{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList); -} - -void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw) -{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId)); -} - -void CCtrlClc::SetIndent(int iIndent) -{ SendMessage(m_hwnd, CLM_SETINDENT, (WPARAM)iIndent, 0); -} - -void CCtrlClc::SetItemText(HANDLE hItem, char *szText) -{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText); -} - -void CCtrlClc::SetHideEmptyGroups(bool state) -{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0); -} - -void CCtrlClc::SetGreyoutFlags(DWORD flags) -{ SendMessage(m_hwnd, CLM_SETGREYOUTFLAGS, (WPARAM)flags, 0); -} - -bool CCtrlClc::GetHideOfflineRoot() -{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false; -} - -void CCtrlClc::SetHideOfflineRoot(bool state) -{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9); -} - -void CCtrlClc::SetUseGroups(bool state) -{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0); -} - -void CCtrlClc::SetOfflineModes(DWORD modes) -{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0); -} - -DWORD CCtrlClc::GetExStyle() -{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0); -} - -void CCtrlClc::SetExStyle(DWORD exStyle) -{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0); -} - -int CCtrlClc::GetLefrMargin() -{ return SendMessage(m_hwnd, CLM_GETLEFTMARGIN, 0, 0); -} - -void CCtrlClc::SetLeftMargin(int iMargin) -{ SendMessage(m_hwnd, CLM_SETLEFTMARGIN, (WPARAM)iMargin, 0); -} - -HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii) -{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii); -} - -int CCtrlClc::GetItemType(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0); -} - -HANDLE CCtrlClc::GetNextItem(HANDLE hItem, DWORD flags) -{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem); -} - -COLORREF CCtrlClc::GetTextColot(int iFontId) -{ return (COLORREF)SendMessage(m_hwnd, CLM_GETTEXTCOLOR, (WPARAM)iFontId, 0); -} - -void CCtrlClc::SetTextColor(int iFontId, COLORREF clText) -{ SendMessage(m_hwnd, CLM_SETTEXTCOLOR, (WPARAM)iFontId, (LPARAM)clText); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListView - -CCtrlListView::CCtrlListView( CDlgBase* dlg, int ctrlId ) : - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, pnmh }; - - switch (pnmh->code) { - case NM_DBLCLK: OnDoubleClick(&evt); return TRUE; - case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; - case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; - case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; - case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE; - case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE; - case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE; - case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; - case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; - case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE; - case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; - case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; - case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE; - //case LVN_INCREMENTALSEARCH: OnIncrementalSearch(&evt); return TRUE; - case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE; - case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE; - case LVN_ITEMCHANGED: OnItemChanged(&evt); return TRUE; - case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE; - case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE; - case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE; - case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; - } - - return FALSE; -} -DWORD CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount) -{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount); -} -void CCtrlListView::Arrange(UINT code) -{ ListView_Arrange(m_hwnd, code); -} -void CCtrlListView::CancelEditLabel() -{ ListView_CancelEditLabel(m_hwnd); -} -HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft) -{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft); -} -void CCtrlListView::DeleteAllItems() -{ ListView_DeleteAllItems(m_hwnd); -} -void CCtrlListView::DeleteColumn(int iCol) -{ ListView_DeleteColumn(m_hwnd, iCol); -} -void CCtrlListView::DeleteItem(int iItem) -{ ListView_DeleteItem(m_hwnd, iItem); -} -HWND CCtrlListView::EditLabel(int iItem) -{ return ListView_EditLabel(m_hwnd, iItem); -} -int CCtrlListView::EnableGroupView(BOOL fEnable) -{ return ListView_EnableGroupView(m_hwnd, fEnable); -} -BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK) -{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK); -} -int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi) -{ return ListView_FindItem(m_hwnd, iStart, plvfi); -} -COLORREF CCtrlListView::GetBkColor() -{ return ListView_GetBkColor(m_hwnd); -} -void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) -{ ListView_GetBkImage(m_hwnd, plvbki); -} -UINT CCtrlListView::GetCallbackMask() -{ return ListView_GetCallbackMask(m_hwnd); -} -BOOL CCtrlListView::GetCheckState(UINT iIndex) -{ return ListView_GetCheckState(m_hwnd, iIndex); -} -void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) -{ ListView_GetColumn(m_hwnd, iCol, pcol); -} -void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) -{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray); -} -int CCtrlListView::GetColumnWidth(int iCol) -{ return ListView_GetColumnWidth(m_hwnd, iCol); -} -int CCtrlListView::GetCountPerPage() -{ return ListView_GetCountPerPage(m_hwnd); -} -HWND CCtrlListView::GetEditControl() -{ return ListView_GetEditControl(m_hwnd); -} -//void CCtrlListView::GetEmptyText(PWSTR pszText, UINT cchText) -//{ ListView_GetEmptyText(m_hwnd, pszText, cchText); -//} -DWORD CCtrlListView::GetExtendedListViewStyle() -{ return ListView_GetExtendedListViewStyle(m_hwnd); -} -//INT CCtrlListView::GetFocusedGroup() -//{ return ListView_GetFocusedGroup(m_hwnd); -//} -//void CCtrlListView::GetFooterInfo(LPLVFOOTERINFO plvfi) -//{ ListView_GetFooterInfo(m_hwnd, plvfi); -//} -//void CCtrlListView::GetFooterItem(UINT iItem, LVFOOTERITEM *pfi) -//{ ListView_GetFooterItem(m_hwnd, iItem, pfi); -//} -//void CCtrlListView::GetFooterItemRect(UINT iItem, RECT *prc) -//{ ListView_GetFooterItemRect(m_hwnd, iItem, prc); -//} -//void CCtrlListView::GetFooterRect(RECT *prc) -//{ ListView_GetFooterRect(m_hwnd, prc); -//} -//int CCtrlListView::GetGroupCount() -//{ return ListView_GetGroupCount(m_hwnd); -//} -//HIMAGELIST CCtrlListView::GetGroupHeaderImageList() -//{ return ListView_GetGroupHeaderImageList(m_hwnd); -//} -//void CCtrlListView::GetGroupInfo(int iGroupId, PLVGROUP pgrp) -//{ ListView_GetGroupInfo(m_hwnd, iGroupId, pgrp); -//} -//void CCtrlListView::GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) -//{ ListView_GetGroupInfoByIndex(m_hwnd, iIndex, pgrp); -//} -void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) -{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics); -} -//BOOL CCtrlListView::GetGroupRect(int iGroupId, RECT *prc) -//{ return ListView_GetGroupRect(m_hwnd, iGroupId, prc); -//} -//UINT CCtrlListView::GetGroupState(UINT dwGroupId, UINT dwMask) -//{ return ListView_GetGroupState(m_hwnd, dwGroupId, dwMask); -//} -HWND CCtrlListView::GetHeader() -{ return ListView_GetHeader(m_hwnd); -} -HCURSOR CCtrlListView::GetHotCursor() -{ return ListView_GetHotCursor(m_hwnd); -} -INT CCtrlListView::GetHotItem() -{ return ListView_GetHotItem(m_hwnd); -} -DWORD CCtrlListView::GetHoverTime() -{ return ListView_GetHoverTime(m_hwnd); -} -HIMAGELIST CCtrlListView::GetImageList(int iImageList) -{ return ListView_GetImageList(m_hwnd, iImageList); -} -BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) -{ return ListView_GetInsertMark(m_hwnd, plvim); -} -COLORREF CCtrlListView::GetInsertMarkColor() -{ return ListView_GetInsertMarkColor(m_hwnd); -} -int CCtrlListView::GetInsertMarkRect(LPRECT prc) -{ return ListView_GetInsertMarkRect(m_hwnd, prc); -} -BOOL CCtrlListView::GetISearchString(LPSTR lpsz) -{ return ListView_GetISearchString(m_hwnd, lpsz); -} -void CCtrlListView::GetItem(LPLVITEM pitem) -{ ListView_GetItem(m_hwnd, pitem); -} -int CCtrlListView::GetItemCount() -{ return ListView_GetItemCount(m_hwnd); -} -//void CCtrlListView::GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc) -//{ ListView_GetItemIndexRect(m_hwnd, plvii, iSubItem, code, prc); -//} -void CCtrlListView::GetItemPosition(int i, POINT *ppt) -{ ListView_GetItemPosition(m_hwnd, i, ppt); -} -void CCtrlListView::GetItemRect(int i, RECT *prc, int code) -{ ListView_GetItemRect(m_hwnd, i, prc, code); -} -DWORD CCtrlListView::GetItemSpacing(BOOL fSmall) -{ return ListView_GetItemSpacing(m_hwnd, fSmall); -} -UINT CCtrlListView::GetItemState(int i, UINT mask) -{ return ListView_GetItemState(m_hwnd, i, mask); -} -void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) -{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax); -} -int CCtrlListView::GetNextItem(int iStart, UINT flags) -{ return ListView_GetNextItem(m_hwnd, iStart, flags); -} -//BOOL CCtrlListView::GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags) -//{ return ListView_GetNextItemIndex(m_hwnd, plvii, flags); -//} -BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) -{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas); -} -BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) -{ return ListView_GetOrigin(m_hwnd, lpptOrg); -} -COLORREF CCtrlListView::GetOutlineColor() -{ return ListView_GetOutlineColor(m_hwnd); -} -UINT CCtrlListView::GetSelectedColumn() -{ return ListView_GetSelectedColumn(m_hwnd); -} -UINT CCtrlListView::GetSelectedCount() -{ return ListView_GetSelectedCount(m_hwnd); -} -INT CCtrlListView::GetSelectionMark() -{ return ListView_GetSelectionMark(m_hwnd); -} -int CCtrlListView::GetStringWidth(LPCSTR psz) -{ return ListView_GetStringWidth(m_hwnd, psz); -} -BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) -{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect); -} -COLORREF CCtrlListView::GetTextBkColor() -{ return ListView_GetTextBkColor(m_hwnd); -} -COLORREF CCtrlListView::GetTextColor() -{ return ListView_GetTextColor(m_hwnd); -} -void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) -{ ListView_GetTileInfo(m_hwnd, plvtinfo); -} -void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) -{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo); -} -HWND CCtrlListView::GetToolTips() -{ return ListView_GetToolTips(m_hwnd); -} -int CCtrlListView::GetTopIndex() -{ return ListView_GetTopIndex(m_hwnd); -} -BOOL CCtrlListView::GetUnicodeFormat() -{ return ListView_GetUnicodeFormat(m_hwnd); -} -DWORD CCtrlListView::GetView() -{ return ListView_GetView(m_hwnd); -} -BOOL CCtrlListView::GetViewRect(RECT *prc) -{ return ListView_GetViewRect(m_hwnd, prc); -} -void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) -{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc); -} -BOOL CCtrlListView::HasGroup(int dwGroupId) -{ return ListView_HasGroup(m_hwnd, dwGroupId); -} -int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) -{ return ListView_HitTest(m_hwnd, pinfo); -} -//int CCtrlListView::HitTestEx(LPLVHITTESTINFO pinfo) -//{ return ListView_HitTestEx(m_hwnd, pinfo); -//} -int CCtrlListView::InsertColumn(int iCol, const LPLVCOLUMN pcol) -{ return ListView_InsertColumn(m_hwnd, iCol, pcol); -} -int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp) -{ return ListView_InsertGroup(m_hwnd, index, pgrp); -} -void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert) -{ ListView_InsertGroupSorted(m_hwnd, structInsert); -} -int CCtrlListView::InsertItem(const LPLVITEM pitem) -{ return ListView_InsertItem(m_hwnd, pitem); -} -BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim) -{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim); -} -BOOL CCtrlListView::IsGroupViewEnabled() -{ return ListView_IsGroupViewEnabled(m_hwnd); -} -//UINT CCtrlListView::IsItemVisible(UINT index) -//{ return ListView_IsItemVisible(m_hwnd, index); -//} -UINT CCtrlListView::MapIDToIndex(UINT id) -{ return ListView_MapIDToIndex(m_hwnd, id); -} -UINT CCtrlListView::MapIndexToID(UINT index) -{ return ListView_MapIndexToID(m_hwnd, index); -} -BOOL CCtrlListView::RedrawItems(int iFirst, int iLast) -{ return ListView_RedrawItems(m_hwnd, iFirst, iLast); -} -void CCtrlListView::RemoveAllGroups() -{ ListView_RemoveAllGroups(m_hwnd); -} -int CCtrlListView::RemoveGroup(int iGroupId) -{ return ListView_RemoveGroup(m_hwnd, iGroupId); -} -BOOL CCtrlListView::Scroll(int dx, int dy) -{ return ListView_Scroll(m_hwnd, dx, dy); -} -BOOL CCtrlListView::SetBkColor(COLORREF clrBk) -{ return ListView_SetBkColor(m_hwnd, clrBk); -} -BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki) -{ return ListView_SetBkImage(m_hwnd, plvbki); -} -BOOL CCtrlListView::SetCallbackMask(UINT mask) -{ return ListView_SetCallbackMask(m_hwnd, mask); -} -void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck) -{ ListView_SetCheckState(m_hwnd, iIndex, fCheck); -} -BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol) -{ return ListView_SetColumn(m_hwnd, iCol, pcol); -} -BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray) -{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray); -} -BOOL CCtrlListView::SetColumnWidth(int iCol, int cx) -{ return ListView_SetColumnWidth(m_hwnd, iCol, cx); -} -void CCtrlListView::SetExtendedListViewStyle(DWORD dwExStyle) -{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle); -} -void CCtrlListView::SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle) -{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle); -} -//HIMAGELIST CCtrlListView::SetGroupHeaderImageList(HIMAGELIST himl) -//{ return ListView_SetGroupHeaderImageList(m_hwnd, himl); -//} -int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp) -{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp); -} -void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) -{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics); -} -//void CCtrlListView::SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState) -//{ ListView_SetGroupState(m_hwnd, dwGroupId, dwMask, dwState); -//} -HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor) -{ return ListView_SetHotCursor(m_hwnd, hCursor); -} -INT CCtrlListView::SetHotItem(INT iIndex) -{ return ListView_SetHotItem(m_hwnd, iIndex); -} -void CCtrlListView::SetHoverTime(DWORD dwHoverTime) -{ ListView_SetHoverTime(m_hwnd, dwHoverTime); -} -DWORD CCtrlListView::SetIconSpacing(int cx, int cy) -{ return ListView_SetIconSpacing(m_hwnd, cx, cy); -} -HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList) -{ return ListView_SetImageList(m_hwnd, himl, iImageList); -} -BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip) -{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip); -} -BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim) -{ return ListView_SetInsertMark(m_hwnd, plvim); -} -COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color) -{ return ListView_SetInsertMarkColor(m_hwnd, color); -} -BOOL CCtrlListView::SetItem(const LPLVITEM pitem) -{ return ListView_SetItem(m_hwnd, pitem); -} -void CCtrlListView::SetItemCount(int cItems) -{ ListView_SetItemCount(m_hwnd, cItems); -} -void CCtrlListView::SetItemCountEx(int cItems, DWORD dwFlags) -{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags); -} -//HRESULT CCtrlListView::SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask) -//{ return ListView_SetItemIndexState(m_hwnd, plvii, data, mask); -//} -BOOL CCtrlListView::SetItemPosition(int i, int x, int y) -{ return ListView_SetItemPosition(m_hwnd, i, x, y); -} -void CCtrlListView::SetItemPosition32(int iItem, int x, int y) -{ ListView_SetItemPosition32(m_hwnd, iItem, x, y); -} -void CCtrlListView::SetItemState(int i, UINT state, UINT mask) -{ ListView_SetItemState(m_hwnd, i, state, mask); -} -void CCtrlListView::SetItemText(int i, int iSubItem, TCHAR *pszText) -{ ListView_SetItemText(m_hwnd, i, iSubItem, pszText); -} -COLORREF CCtrlListView::SetOutlineColor(COLORREF color) -{ return ListView_SetOutlineColor(m_hwnd, color); -} -void CCtrlListView::SetSelectedColumn(int iCol) -{ ListView_SetSelectedColumn(m_hwnd, iCol); -} -INT CCtrlListView::SetSelectionMark(INT iIndex) -{ return ListView_SetSelectionMark(m_hwnd, iIndex); -} -BOOL CCtrlListView::SetTextBkColor(COLORREF clrText) -{ return ListView_SetTextBkColor(m_hwnd, clrText); -} -BOOL CCtrlListView::SetTextColor(COLORREF clrText) -{ return ListView_SetTextColor(m_hwnd, clrText); -} -BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo) -{ return ListView_SetTileInfo(m_hwnd, plvtinfo); -} -BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) -{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo); -} -HWND CCtrlListView::SetToolTips(HWND ToolTip) -{ return ListView_SetToolTips(m_hwnd, ToolTip); -} -BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode) -{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode); -} -int CCtrlListView::SetView(DWORD iView) -{ return ListView_SetView(m_hwnd, iView); -} -void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc) -{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc); -} -int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv) -{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv); -} -BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) -{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort); -} -BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) -{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort); -} -INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) -{ return ListView_SubItemHitTest(m_hwnd, pInfo); -} -//INT CCtrlListView::SubItemHitTestEx(LPLVHITTESTINFO plvhti) -//{ return ListView_SubItemHitTestEx(m_hwnd, plvhti); -//} -BOOL CCtrlListView::Update(int iItem) -{ return ListView_Update(m_hwnd, iItem); -} -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -CCtrlTreeView::CCtrlTreeView( CDlgBase* dlg, int ctrlId ): - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, pnmh }; - - switch (pnmh->code) - { - case TVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; - case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; - case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; - case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; - case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; - case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; - case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; - case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; - case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; - case TVN_KEYDOWN: OnKeyDown(&evt); return TRUE; - case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; - case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; - case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; - case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; - } - - return FALSE; -} - -void CCtrlTreeView::TranslateItem(HTREEITEM hItem) -{ - TCHAR buf[128]; - TVITEMEX tvi; - - GetItem(hItem, &tvi, buf, SIZEOF(buf)); - tvi.pszText = TranslateTS(tvi.pszText); - tvi.cchTextMax = lstrlen(tvi.pszText); - SetItem(&tvi); -} - -void CCtrlTreeView::TranslateTree() -{ - HTREEITEM hItem = GetRoot(); - while (hItem) - { - TranslateItem(hItem); - - HTREEITEM hItemTmp = 0; - if (hItemTmp = GetChild(hItem)) - hItem = hItemTmp; - else if (hItemTmp = GetNextSibling(hItem)) - hItem = hItemTmp; - else - { - for (;;) - { - if (!(hItem = GetParent(hItem))) break; - if (hItemTmp = GetNextSibling(hItem)) - { - hItem = hItemTmp; - break; - } - } - } - } -} - -HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const TCHAR *name) -{ - TVITEMEX tvi = {0}; - TCHAR str[MAX_PATH]; - - if (hItem) - tvi.hItem = GetChild(hItem); - else - tvi.hItem = GetRoot(); - - if (!name) - return tvi.hItem; - - tvi.mask = TVIF_TEXT; - tvi.pszText = str; - tvi.cchTextMax = SIZEOF(str); - - while (tvi.hItem) - { - GetItem(&tvi); - - if (!lstrcmp(tvi.pszText, name)) - return tvi.hItem; - - tvi.hItem = GetNextSibling(tvi.hItem); - } - return NULL; -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) -{ - ZeroMemory(tvi, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE; - tvi->hItem = hItem; - GetItem(tvi); -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength) -{ - ZeroMemory(tvi, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT; - tvi->hItem = hItem; - tvi->pszText = szText; - tvi->cchTextMax = iTextLength; - GetItem(tvi); -} - -HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) -{ return TreeView_CreateDragImage(m_hwnd, hItem); -} - -void CCtrlTreeView::DeleteAllItems() -{ TreeView_DeleteAllItems(m_hwnd); -} - -void CCtrlTreeView::DeleteItem(HTREEITEM hItem) -{ TreeView_DeleteItem(m_hwnd, hItem); -} - -HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) -{ return TreeView_EditLabel(m_hwnd, hItem); -} - -void CCtrlTreeView::EndEditLabelNow(BOOL cancel) -{ TreeView_EndEditLabelNow(m_hwnd, cancel); -} - -void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) -{ TreeView_EnsureVisible(m_hwnd, hItem); -} - -void CCtrlTreeView::Expand(HTREEITEM hItem, DWORD flag) -{ TreeView_Expand(m_hwnd, hItem, flag); -} - -COLORREF CCtrlTreeView::GetBkColor() -{ return TreeView_GetBkColor(m_hwnd); -} - -DWORD CCtrlTreeView::GetCheckState(HTREEITEM hItem) -{ return TreeView_GetCheckState(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) -{ return TreeView_GetChild(m_hwnd, hItem); -} - -int CCtrlTreeView::GetCount() -{ return TreeView_GetCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetDropHilight() -{ return TreeView_GetDropHilight(m_hwnd); -} - -HWND CCtrlTreeView::GetEditControl() -{ return TreeView_GetEditControl(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetFirstVisible() -{ return TreeView_GetFirstVisible(m_hwnd); -} - -HIMAGELIST CCtrlTreeView::GetImageList(int iImage) -{ return TreeView_GetImageList(m_hwnd, iImage); -} - -int CCtrlTreeView::GetIndent() -{ return TreeView_GetIndent(m_hwnd); -} - -COLORREF CCtrlTreeView::GetInsertMarkColor() -{ return TreeView_GetInsertMarkColor(m_hwnd); -} - -void CCtrlTreeView::GetItem(TVITEMEX *tvi) -{ TreeView_GetItem(m_hwnd, tvi); -} - -int CCtrlTreeView::GetItemHeight() -{ return TreeView_GetItemHeight(m_hwnd); -} - -void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) -{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); -} - -DWORD CCtrlTreeView::GetItemState(HTREEITEM hItem, DWORD stateMask) -{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); -} - -HTREEITEM CCtrlTreeView::GetLastVisible() -{ return TreeView_GetLastVisible(m_hwnd); -} - -COLORREF CCtrlTreeView::GetLineColor() -{ return TreeView_GetLineColor(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, DWORD flag) -{ return TreeView_GetNextItem(m_hwnd, hItem, flag); -} - -HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) -{ return TreeView_GetNextSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) -{ return TreeView_GetNextVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) -{ return TreeView_GetParent(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) -{ return TreeView_GetPrevSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) -{ return TreeView_GetPrevVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetRoot() -{ return TreeView_GetRoot(m_hwnd); -} - -DWORD CCtrlTreeView::GetScrollTime() -{ return TreeView_GetScrollTime(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetSelection() -{ return TreeView_GetSelection(m_hwnd); -} - -COLORREF CCtrlTreeView::GetTextColor() -{ return TreeView_GetTextColor(m_hwnd); -} - -HWND CCtrlTreeView::GetToolTips() -{ return TreeView_GetToolTips(m_hwnd); -} - -BOOL CCtrlTreeView::GetUnicodeFormat() -{ return TreeView_GetUnicodeFormat(m_hwnd); -} - -unsigned CCtrlTreeView::GetVisibleCount() -{ return TreeView_GetVisibleCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) -{ return TreeView_HitTest(m_hwnd, hti); -} - -HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) -{ return TreeView_InsertItem(m_hwnd, tvis); -} - -/* -HTREEITEM CCtrlTreeView::MapAccIDToHTREEITEM(UINT id) -{ return TreeView_MapAccIDToHTREEITEM(m_hwnd, id); -} - -UINT CCtrlTreeView::MapHTREEITEMtoAccID(HTREEITEM hItem) -{ return TreeView_MapHTREEITEMtoAccID(m_hwnd, hItem); -} - -*/ -void CCtrlTreeView::Select(HTREEITEM hItem, DWORD flag) -{ TreeView_Select(m_hwnd, hItem, flag); -} - -void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) -{ TreeView_SelectDropTarget(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectItem(HTREEITEM hItem) -{ TreeView_SelectItem(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) -{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); -} - -COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) -{ return TreeView_SetBkColor(m_hwnd, clBack); -} - -void CCtrlTreeView::SetCheckState(HTREEITEM hItem, DWORD state) -{ TreeView_SetCheckState(m_hwnd, hItem, state); -} - -void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) -{ TreeView_SetImageList(m_hwnd, hIml, iImage); -} - -void CCtrlTreeView::SetIndent(int iIndent) -{ TreeView_SetIndent(m_hwnd, iIndent); -} - -void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) -{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); -} - -COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) -{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); -} - -void CCtrlTreeView::SetItem(TVITEMEX *tvi) -{ TreeView_SetItem(m_hwnd, tvi); -} - -void CCtrlTreeView::SetItemHeight(short cyItem) -{ TreeView_SetItemHeight(m_hwnd, cyItem); -} - -void CCtrlTreeView::SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask) -{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); -} - -COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) -{ return TreeView_SetLineColor(m_hwnd, clLine); -} - -void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) -{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); -} - -COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) -{ return TreeView_SetTextColor(m_hwnd, clText); -} - -HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) -{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); -} - -BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) -{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); -} - -void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) -{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); -} - -void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) -{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlBase - -CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) : - m_parentWnd( wnd ), - m_idCtrl( idCtrl ), - m_hwnd( NULL ), - m_wndproc( NULL ) -{ - if ( wnd ) { - m_next = wnd->m_first; - wnd->m_first = this; -} } - -void CCtrlBase::OnInit() -{ - m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : NULL; -} - -void CCtrlBase::OnDestroy() -{ - Unsubclass(); - m_hwnd = NULL; -} - -void CCtrlBase::Enable( int bIsEnable ) -{ - ::EnableWindow( m_hwnd, bIsEnable ); -} - -BOOL CCtrlBase::Enabled() const -{ - return ( m_hwnd ) ? IsWindowEnabled( m_hwnd ) : FALSE; -} - -LRESULT CCtrlBase::SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ) -{ - return ::SendMessage( m_hwnd, Msg, wParam, lParam ); -} - -void CCtrlBase::SetText(const TCHAR *text) -{ - ::SetWindowText( m_hwnd, text ); -} - -void CCtrlBase::SetTextA(const char *text) -{ - ::SetWindowTextA( m_hwnd, text ); -} - -void CCtrlBase::SetInt(int value) -{ - TCHAR buf[32] = {0}; - mir_sntprintf(buf, SIZEOF(buf), _T("%d"), value); - SetWindowText(m_hwnd, buf); -} - -TCHAR* CCtrlBase::GetText() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - TCHAR *result = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); - GetWindowText(m_hwnd, result, length); - return result; -} - -char* CCtrlBase::GetTextA() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - char *result = (char *)mir_alloc(length * sizeof(char)); - GetWindowTextA(m_hwnd, result, length); - return result; -} - -TCHAR* CCtrlBase::GetText(TCHAR *buf, int size) -{ - GetWindowText(m_hwnd, buf, size); - buf[size-1] = 0; - return buf; -} - -char* CCtrlBase::GetTextA(char *buf, int size) -{ - GetWindowTextA(m_hwnd, buf, size); - buf[size-1] = 0; - return buf; -} - -int CCtrlBase::GetInt() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - TCHAR *result = (TCHAR *)_alloca(length * sizeof(TCHAR)); - GetWindowText(m_hwnd, result, length); - return _ttoi(result); -} - -LRESULT CCtrlBase::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_DESTROY) Unsubclass(); - return CallWindowProc(m_wndproc, m_hwnd, msg, wParam, lParam); -} - -void CCtrlBase::Subclass() -{ - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); - m_wndproc = (WNDPROC)SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassWndProc); -} - -void CCtrlBase::Unsubclass() -{ - if (m_wndproc) - { - SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); - m_wndproc = 0; -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// CDbLink class - -CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue) -{ - m_szModule = mir_strdup(szModule); - m_szSetting = mir_strdup(szSetting); - m_type = type; - m_iDefault = iValue; - m_szDefault = 0; - dbv.type = DBVT_DELETED; -} - -CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue) -{ - m_szModule = mir_strdup(szModule); - m_szSetting = mir_strdup(szSetting); - m_type = type; - m_szDefault = mir_tstrdup(szValue); - dbv.type = DBVT_DELETED; -} - -CDbLink::~CDbLink() -{ - mir_free(m_szModule); - mir_free(m_szSetting); - mir_free(m_szDefault); - if (dbv.type != DBVT_DELETED) - DBFreeVariant(&dbv); -} - -DWORD CDbLink::LoadInt() -{ - switch (m_type) { - case DBVT_BYTE: return DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_WORD: return DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_DWORD: return DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); - default: return m_iDefault; - } -} - -void CDbLink::SaveInt(DWORD value) -{ - switch (m_type) { - case DBVT_BYTE: DBWriteContactSettingByte(NULL, m_szModule, m_szSetting, (BYTE)value); break; - case DBVT_WORD: DBWriteContactSettingWord(NULL, m_szModule, m_szSetting, (WORD)value); break; - case DBVT_DWORD: DBWriteContactSettingDword(NULL, m_szModule, m_szSetting, value); break; - } -} - -TCHAR* CDbLink::LoadText() -{ - if (dbv.type != DBVT_DELETED) DBFreeVariant(&dbv); - if (!DBGetContactSettingTString(NULL, m_szModule, m_szSetting, &dbv)) - { - if (dbv.type == DBVT_TCHAR) - return dbv.ptszVal; - return m_szDefault; - } - - dbv.type = DBVT_DELETED; - return m_szDefault; -} - -void CDbLink::SaveText(TCHAR *value) -{ - DBWriteContactSettingTString(NULL, m_szModule, m_szSetting, value); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Misc utilities - -int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) -{ - if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton))) - PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton)); - return 0; -} - -void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow) -{ - for (; *idList; ++idList) - ShowWindow(GetDlgItem(hwndDlg, *idList), nCmdShow); -} diff --git a/protocols/IRCG/ui_utils.h b/protocols/IRCG/ui_utils.h deleted file mode 100644 index 60566ce913..0000000000 --- a/protocols/IRCG/ui_utils.h +++ /dev/null @@ -1,1108 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007-08 Maxim Mluhov -Copyright ( C ) 2007-08 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.h $ -Revision : $Revision: 13133 $ -Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ -Last change by : $Author: george.hazan $ - -*/ - -#ifndef __jabber_ui_utils_h__ -#define __jabber_ui_utils_h__ - -#include "m_clc.h" - -#ifndef LPLVCOLUMN -typedef struct tagNMLVSCROLL -{ - NMHDR hdr; - int dx; - int dy; -} NMLVSCROLL; -typedef struct tagLVG -{ - UINT cbSize; - UINT mask; - LPWSTR pszHeader; - int cchHeader; - LPWSTR pszFooter; - int cchFooter; - int iGroupId; - UINT stateMask; - UINT state; - UINT uAlign; -} LVGROUP, *PLVGROUP; -typedef struct tagLVGROUPMETRICS -{ - UINT cbSize; - UINT mask; - UINT Left; - UINT Top; - UINT Right; - UINT Bottom; - COLORREF crLeft; - COLORREF crTop; - COLORREF crRight; - COLORREF crBottom; - COLORREF crHeader; - COLORREF crFooter; -} LVGROUPMETRICS, *PLVGROUPMETRICS; -typedef struct tagLVTILEVIEWINFO -{ - UINT cbSize; - DWORD dwMask; - DWORD dwFlags; - SIZE sizeTile; - int cLines; - RECT rcLabelMargin; -} LVTILEVIEWINFO, *PLVTILEVIEWINFO; -typedef struct tagLVTILEINFO -{ - UINT cbSize; - int iItem; - UINT cColumns; - PUINT puColumns; -} LVTILEINFO, *PLVTILEINFO; -typedef struct -{ - UINT cbSize; - DWORD dwFlags; - int iItem; - DWORD dwReserved; -} LVINSERTMARK, * LPLVINSERTMARK; -typedef int (CALLBACK *PFNLVGROUPCOMPARE)(int, int, void *); -typedef struct tagLVINSERTGROUPSORTED -{ - PFNLVGROUPCOMPARE pfnGroupCompare; - void *pvData; - LVGROUP lvGroup; -} LVINSERTGROUPSORTED, *PLVINSERTGROUPSORTED; -typedef struct tagLVSETINFOTIP -{ - UINT cbSize; - DWORD dwFlags; - LPWSTR pszText; - int iItem; - int iSubItem; -} LVSETINFOTIP, *PLVSETINFOTIP; -#define LPLVCOLUMN LPLVCOLUMNA -#define LPLVITEM LPLVITEMA -#define LVN_BEGINSCROLL (LVN_FIRST-80) -#define LVN_ENDSCROLL (LVN_FIRST-81) -#define LVN_HOTTRACK (LVN_FIRST-21) -#define LVN_MARQUEEBEGIN (LVN_FIRST-56) -#define LVM_MAPINDEXTOID (LVM_FIRST + 180) -#define ListView_MapIndexToID(hwnd, index) \ - (UINT)SendMessage((hwnd), LVM_MAPINDEXTOID, (WPARAM)index, (LPARAM)0) -#define TreeView_GetLineColor(hwnd) \ - (COLORREF)SendMessage((hwnd), TVM_GETLINECOLOR, 0, 0) -#define TreeView_SetLineColor(hwnd, clr) \ - (COLORREF)SendMessage((hwnd), TVM_SETLINECOLOR, 0, (LPARAM)(clr)) -#endif - - -#pragma warning(disable:4355) - -///////////////////////////////////////////////////////////////////////////////////////// -// Callbacks - -struct CCallbackImp -{ - struct CDummy - { int foo; - }; - -public: - __inline CCallbackImp(): m_object(NULL), m_func(NULL) {} - - __inline CCallbackImp(const CCallbackImp &other): m_object(other.m_object), m_func(other.m_func) {} - __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } - - __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } - __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } - - __inline operator bool() const { return m_object && m_func; } - - __inline bool CheckObject(void *object) const { return (object == m_object) ? true : false; } - -protected: - template - __inline CCallbackImp(TClass *object, void ( TClass::*func)(TArgument *argument)): m_object(( CDummy* )object), m_func((TFnCallback)func) {} - - __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } - -private: - typedef void ( CDummy::*TFnCallback)( void *argument ); - - CDummy* m_object; - TFnCallback m_func; -}; - -template -struct CCallback: public CCallbackImp -{ -public: - __inline CCallback() {} - - template - __inline CCallback(TClass *object, void ( TClass::*func)(TArgument *argument)): CCallbackImp(object, func) {} - - __inline CCallback& operator=( const CCallbackImp& x ) { CCallbackImp::operator =( x ); return *this; } - - __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } -}; - -template -__inline CCallback Callback(TClass *object, void (TClass::*func)(TArgument *argument)) - { return CCallback(object, func); } - -///////////////////////////////////////////////////////////////////////////////////////// -// CDlgBase - base dialog class - -class CDlgBase -{ - friend class CCtrlBase; - friend class CCtrlData; - -public: - CDlgBase(int idDialog, HWND hwndParent); - virtual ~CDlgBase(); - - // general utilities - void Create(); - void Show(); - int DoModal(); - - __inline HWND GetHwnd() const { return m_hwnd; } - __inline bool IsInitialized() const { return m_initialized; } - __inline void Close() { SendMessage(m_hwnd, WM_CLOSE, 0, 0); } - __inline const MSG *ActiveMessage() const { return &m_msg; } - - // dynamic creation support (mainly to avoid leaks in options) - struct CreateParam - { - CDlgBase *(*create)(void *param); - void *param; - }; - static INT_PTR CALLBACK DynamicDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - if (msg == WM_INITDIALOG) - { - CreateParam *param = (CreateParam *)lParam; - CDlgBase *wnd = param->create(param->param); - SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)GlobalDlgProc); - return GlobalDlgProc(hwnd, msg, wParam, (LPARAM)wnd); - } - - return FALSE; - } - - LRESULT m_lresult; - -protected: - HWND m_hwnd; - HWND m_hwndParent; - int m_idDialog; - MSG m_msg; - bool m_isModal; - bool m_initialized; - bool m_forceResizable; - - enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; - BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL - - CCtrlBase* m_first; - - // override this handlers to provide custom functionality - // general messages - virtual void OnInitDialog() { } - virtual void OnClose() { } - virtual void OnDestroy() { } - - // miranda-related stuff - virtual int Resizer(UTILRESIZECONTROL *urc); - virtual void OnApply() {} - virtual void OnReset() {} - virtual void OnChange(CCtrlBase*) {} - - // main dialog procedure - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - // resister controls - void AddControl(CCtrlBase *ctrl); - -private: - LIST m_controls; - - void NotifyControls(void (CCtrlBase::*fn)()); - CCtrlBase *FindControl(int idCtrl); - - static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CDbLink - -class CDbLink -{ - char *m_szModule; - char *m_szSetting; - BYTE m_type; - - DWORD m_iDefault; - TCHAR *m_szDefault; - - DBVARIANT dbv; - -public: - CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue); - CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue); - ~CDbLink(); - - __inline BYTE GetDataType() { return m_type; } - - DWORD LoadInt(); - void SaveInt(DWORD value); - - TCHAR *LoadText(); - void SaveText(TCHAR *value); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlBase - -class CCtrlBase -{ - friend class CDlgBase; - -public: - CCtrlBase(CDlgBase *wnd, int idCtrl ); - virtual ~CCtrlBase() { Unsubclass(); } - - __inline int GetCtrlId() const { return m_idCtrl; } - __inline HWND GetHwnd() const { return m_hwnd; } - __inline CDlgBase *GetParent() { return m_parentWnd; } - - void Enable( int bIsEnable = true ); - __inline void Disable() { Enable( false ); } - BOOL Enabled( void ) const; - - LRESULT SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ); - - void SetText(const TCHAR *text); - void SetTextA(const char *text); - void SetInt(int value); - - TCHAR *GetText(); - char *GetTextA(); - - TCHAR *GetText(TCHAR *buf, int size); - char *GetTextA(char *buf, int size); - - int GetInt(); - - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } - virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } - - virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } - - virtual void OnInit(); - virtual void OnDestroy(); - - virtual void OnApply() {} - virtual void OnReset() {} - - static int cmp(const CCtrlBase *c1, const CCtrlBase *c2) - { - if (c1->m_idCtrl < c2->m_idCtrl) return -1; - if (c1->m_idCtrl > c2->m_idCtrl) return +1; - return 0; - } - -protected: - HWND m_hwnd; - int m_idCtrl; - CCtrlBase* m_next; - CDlgBase* m_parentWnd; - - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - void Subclass(); - void Unsubclass(); - -private: - WNDPROC m_wndproc; - static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - if (CCtrlBase *ctrl = (CCtrlBase*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) - if (ctrl) - return ctrl->CustomWndProc(msg, wParam, lParam); - - return DefWindowProc(hwnd, msg, wParam, lParam); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -class CCtrlButton : public CCtrlBase -{ -public: - CCtrlButton( CDlgBase* dlg, int ctrlId ); - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); - - CCallback OnClick; - - int GetState(); - void SetState(int state); -}; - -class CCtrlMButton : public CCtrlButton -{ -public: - CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ); - CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ); - ~CCtrlMButton(); - - void MakeFlat(); - void MakePush(); - - virtual void OnInit(); - -protected: - HICON m_hIcon; - const char* m_toolTip; -}; - -class CCtrlHyperlink : public CCtrlBase -{ -public: - CCtrlHyperlink( CDlgBase* dlg, int ctrlId, const char* url ); - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); - -protected: - const char* m_url; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlClc -class CCtrlClc: public CCtrlBase -{ -public: - CCtrlClc( CDlgBase* dlg, int ctrlId ); - - void AddContact(HANDLE hContact); - void AddGroup(HANDLE hGroup); - void AutoRebuild(); - void DeleteItem(HANDLE hItem); - void EditLabel(HANDLE hItem); - void EndEditLabel(bool save); - void EnsureVisible(HANDLE hItem, bool partialOk); - void Expand(HANDLE hItem, DWORD flags); - HANDLE FindContact(HANDLE hContact); - HANDLE FindGroup(HANDLE hGroup); - COLORREF GetBkColor(); - bool GetCheck(HANDLE hItem); - int GetCount(); - HWND GetEditControl(); - DWORD GetExpand(HANDLE hItem); - int GetExtraColumns(); - BYTE GetExtraImage(HANDLE hItem, int iColumn); - HIMAGELIST GetExtraImageList(); - HFONT GetFont(int iFontId); - HANDLE GetSelection(); - HANDLE HitTest(int x, int y, DWORD *hitTest); - void SelectItem(HANDLE hItem); - void SetBkBitmap(DWORD mode, HBITMAP hBitmap); - void SetBkColor(COLORREF clBack); - void SetCheck(HANDLE hItem, bool check); - void SetExtraColumns(int iColumns); - void SetExtraImage(HANDLE hItem, int iColumn, int iImage); - void SetExtraImageList(HIMAGELIST hImgList); - void SetFont(int iFontId, HANDLE hFont, bool bRedraw); - void SetIndent(int iIndent); - void SetItemText(HANDLE hItem, char *szText); - void SetHideEmptyGroups(bool state); - void SetGreyoutFlags(DWORD flags); - bool GetHideOfflineRoot(); - void SetHideOfflineRoot(bool state); - void SetUseGroups(bool state); - void SetOfflineModes(DWORD modes); - DWORD GetExStyle(); - void SetExStyle(DWORD exStyle); - int GetLefrMargin(); - void SetLeftMargin(int iMargin); - HANDLE AddInfoItem(CLCINFOITEM *cii); - int GetItemType(HANDLE hItem); - HANDLE GetNextItem(HANDLE hItem, DWORD flags); - COLORREF GetTextColot(int iFontId); - void SetTextColor(int iFontId, COLORREF clText); - - struct TEventInfo - { - CCtrlClc *ctrl; - NMCLISTCONTROL *info; - }; - - CCallback OnExpanded; - CCallback OnListRebuilt; - CCallback OnItemChecked; - CCallback OnDragging; - CCallback OnDropped; - CCallback OnListSizeChange; - CCallback OnOptionsChanged; - CCallback OnDragStop; - CCallback OnNewContact; - CCallback OnContactMoved; - CCallback OnCheckChanged; - CCallback OnClick; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlData - data access controls base class - -class CCtrlData : public CCtrlBase -{ -public: - CCtrlData( CDlgBase* dlg, int ctrlId ); - - virtual ~CCtrlData() - { - if (m_dbLink) delete m_dbLink; - } - - __inline bool IsChanged() const { return m_changed; } - - void CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ); - void CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ); - - virtual void OnInit(); - - // Events - CCallback OnChange; - -protected: - CDbLink *m_dbLink; - bool m_changed; - - void NotifyChange(); - - __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } - __inline DWORD LoadInt() { return m_dbLink ? m_dbLink->LoadInt() : 0; } - __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } - __inline const TCHAR *LoadText() { return m_dbLink ? m_dbLink->LoadText() : _T(""); } - __inline void SaveText(TCHAR *value) { if (m_dbLink) m_dbLink->SaveText(value); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCheck - -class CCtrlCheck : public CCtrlData -{ -public: - CCtrlCheck( CDlgBase* dlg, int ctrlId ); - virtual BOOL OnCommand(HWND, WORD, WORD) { NotifyChange(); return TRUE; } - virtual void OnInit() - { - CCtrlData::OnInit(); - OnReset(); - } - virtual void OnApply() - { - SaveInt(GetState()); - } - virtual void OnReset() - { - SetState(LoadInt()); - } - - int GetState(); - void SetState(int state); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlEdit - -class CCtrlEdit : public CCtrlData -{ -public: - CCtrlEdit( CDlgBase* dlg, int ctrlId ); - virtual BOOL OnCommand(HWND, WORD, WORD idCode) - { - if (idCode == EN_CHANGE) - NotifyChange(); - return TRUE; - } - virtual void OnInit() - { - CCtrlData::OnInit(); - OnReset(); - } - virtual void OnApply() - { - if (GetDataType() == DBVT_TCHAR) - { - int len = GetWindowTextLength(m_hwnd) + 1; - TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); - GetWindowText(m_hwnd, buf, len); - SaveText(buf); - } - else if (GetDataType() != DBVT_DELETED) - { - SaveInt(GetInt()); - } - } - virtual void OnReset() - { - if (GetDataType() == DBVT_TCHAR) - SetText(LoadText()); - else if (GetDataType() != DBVT_DELETED) - SetInt(LoadInt()); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListBox - -class CCtrlListBox : public CCtrlBase -{ -public: - CCtrlListBox( CDlgBase* dlg, int ctrlId ); - - int AddString(TCHAR *text, LPARAM data=0); - void DeleteString(int index); - int FindString(TCHAR *str, int index = -1, bool exact = false); - int GetCount(); - int GetCurSel(); - LPARAM GetItemData(int index); - TCHAR* GetItemText(int index); - TCHAR* GetItemText(int index, TCHAR *buf, int size); - bool GetSel(int index); - int GetSelCount(); - int* GetSelItems(int *items, int count); - int* GetSelItems(); - int InsertString(TCHAR *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(TCHAR *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void SetSel(int index, bool sel=true); - - // Events - CCallback OnDblClick; - CCallback OnSelCancel; - CCallback OnSelChange; - -protected: - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCombo - -class CCtrlCombo : public CCtrlData -{ -public: - CCtrlCombo( CDlgBase* dlg, int ctrlId ); - - virtual BOOL OnCommand(HWND, WORD, WORD idCode) - { - switch (idCode) - { - case CBN_CLOSEUP: OnCloseup(this); break; - case CBN_DROPDOWN: OnDropdown(this); break; - - case CBN_EDITCHANGE: - case CBN_EDITUPDATE: - case CBN_SELCHANGE: - case CBN_SELENDOK: - NotifyChange(); - break; - } - return TRUE; - } - - virtual void OnInit() - { - CCtrlData::OnInit(); - OnReset(); - } - virtual void OnApply() - { - if (GetDataType() == DBVT_TCHAR) - { - int len = GetWindowTextLength(m_hwnd) + 1; - TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); - GetWindowText(m_hwnd, buf, len); - SaveText(buf); - } - else if (GetDataType() != DBVT_DELETED) - { - SaveInt(GetInt()); - } - } - virtual void OnReset() - { - if (GetDataType() == DBVT_TCHAR) - SetText(LoadText()); - else if (GetDataType() != DBVT_DELETED) - SetInt(LoadInt()); - } - - // Control interface - int AddString(const TCHAR *text, LPARAM data = 0 ); - int AddStringA(const char *text, LPARAM data = 0 ); - void DeleteString(int index); - int FindString(const TCHAR *str, int index = -1, bool exact = false); - int FindStringA(const char *str, int index = -1, bool exact = false); - int GetCount(); - int GetCurSel(); - bool GetDroppedState(); - LPARAM GetItemData(int index); - TCHAR* GetItemText(int index); - TCHAR* GetItemText(int index, TCHAR *buf, int size); - int InsertString(TCHAR *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(TCHAR *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void ShowDropdown(bool show = true); - - // Events - CCallback OnCloseup; - CCallback OnDropdown; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListView - -class CCtrlListView : public CCtrlBase -{ -public: - CCtrlListView( CDlgBase* dlg, int ctrlId ); - - // Classic LV interface - DWORD ApproximateViewRect(int cx, int cy, int iCount); - void Arrange(UINT code); - void CancelEditLabel(); - HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); - void DeleteAllItems(); - void DeleteColumn(int iCol); - void DeleteItem(int iItem); - HWND EditLabel(int iItem); - int EnableGroupView(BOOL fEnable); - BOOL EnsureVisible(int i, BOOL fPartialOK); - int FindItem(int iStart, const LVFINDINFO *plvfi); - COLORREF GetBkColor(); - void GetBkImage(LPLVBKIMAGE plvbki); - UINT GetCallbackMask(); - BOOL GetCheckState(UINT iIndex); - void GetColumn(int iCol, LPLVCOLUMN pcol); - void GetColumnOrderArray(int iCount, int *lpiArray); - int GetColumnWidth(int iCol); - int GetCountPerPage(); - HWND GetEditControl(); - //void GetEmptyText(PWSTR pszText, UINT cchText); - DWORD GetExtendedListViewStyle(); - INT GetFocusedGroup(); - //void GetFooterInfo(LVFOOTERINFO *plvfi); - //void GetFooterItem(UINT iItem, LVFOOTERITEM *pfi); - //void GetFooterItemRect(UINT iItem, RECT *prc); - //void GetFooterRect(RECT *prc); - int GetGroupCount(); - //HIMAGELIST GetGroupHeaderImageList(); - void GetGroupInfo(int iGroupId, PLVGROUP pgrp); - void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp); - void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics); - //BOOL GetGroupRect(int iGroupId, RECT *prc); - UINT GetGroupState(UINT dwGroupId, UINT dwMask); - HWND GetHeader(); - HCURSOR GetHotCursor(); - INT GetHotItem(); - DWORD GetHoverTime(); - HIMAGELIST GetImageList(int iImageList); - BOOL GetInsertMark(LVINSERTMARK *plvim); - COLORREF GetInsertMarkColor(); - int GetInsertMarkRect(LPRECT prc); - BOOL GetISearchString(LPSTR lpsz); - void GetItem(LPLVITEM pitem); - int GetItemCount(); - //void GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc); - void GetItemPosition(int i, POINT *ppt); - void GetItemRect(int i, RECT *prc, int code); - DWORD GetItemSpacing(BOOL fSmall); - UINT GetItemState(int i, UINT mask); - void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax); - int GetNextItem(int iStart, UINT flags); - //BOOL GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags); - BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas); - BOOL GetOrigin(LPPOINT lpptOrg); - COLORREF GetOutlineColor(); - UINT GetSelectedColumn(); - UINT GetSelectedCount(); - INT GetSelectionMark(); - int GetStringWidth(LPCSTR psz); - BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect); - COLORREF GetTextBkColor(); - COLORREF GetTextColor(); - void GetTileInfo(PLVTILEINFO plvtinfo); - void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); - HWND GetToolTips(); - int GetTopIndex(); - BOOL GetUnicodeFormat(); - DWORD GetView(); - BOOL GetViewRect(RECT *prc); - void GetWorkAreas(INT nWorkAreas, LPRECT lprc); - BOOL HasGroup(int dwGroupId); - int HitTest(LPLVHITTESTINFO pinfo); - int HitTestEx(LPLVHITTESTINFO pinfo); - int InsertColumn(int iCol, const LPLVCOLUMN pcol); - int InsertGroup(int index, PLVGROUP pgrp); - void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); - int InsertItem(const LPLVITEM pitem); - BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); - BOOL IsGroupViewEnabled(); - UINT IsItemVisible(UINT index); - UINT MapIDToIndex(UINT id); - UINT MapIndexToID(UINT index); - BOOL RedrawItems(int iFirst, int iLast); - void RemoveAllGroups(); - int RemoveGroup(int iGroupId); - BOOL Scroll(int dx, int dy); - BOOL SetBkColor(COLORREF clrBk); - BOOL SetBkImage(LPLVBKIMAGE plvbki); - BOOL SetCallbackMask(UINT mask); - void SetCheckState(UINT iIndex, BOOL fCheck); - BOOL SetColumn(int iCol, LPLVCOLUMN pcol); - BOOL SetColumnOrderArray(int iCount, int *lpiArray); - BOOL SetColumnWidth(int iCol, int cx); - void SetExtendedListViewStyle(DWORD dwExStyle); - void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); - //HIMAGELIST SetGroupHeaderImageList(HIMAGELIST himl); - int SetGroupInfo(int iGroupId, PLVGROUP pgrp); - void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); - void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); - HCURSOR SetHotCursor(HCURSOR hCursor); - INT SetHotItem(INT iIndex); - void SetHoverTime(DWORD dwHoverTime); - DWORD SetIconSpacing(int cx, int cy); - HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); - BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); - BOOL SetInsertMark(LVINSERTMARK *plvim); - COLORREF SetInsertMarkColor(COLORREF color); - BOOL SetItem(const LPLVITEM pitem); - void SetItemCount(int cItems); - void SetItemCountEx(int cItems, DWORD dwFlags); - //HRESULT SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask); - BOOL SetItemPosition(int i, int x, int y); - void SetItemPosition32(int iItem, int x, int y); - void SetItemState(int i, UINT state, UINT mask); - void SetItemText(int i, int iSubItem, TCHAR *pszText); - COLORREF SetOutlineColor(COLORREF color); - void SetSelectedColumn(int iCol); - INT SetSelectionMark(INT iIndex); - BOOL SetTextBkColor(COLORREF clrText); - BOOL SetTextColor(COLORREF clrText); - BOOL SetTileInfo(PLVTILEINFO plvtinfo); - BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); - HWND SetToolTips(HWND ToolTip); - BOOL SetUnicodeFormat(BOOL fUnicode); - int SetView(DWORD iView); - void SetWorkAreas(INT nWorkAreas, LPRECT lprc); - int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); - BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - INT SubItemHitTest(LPLVHITTESTINFO pInfo); - INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); - BOOL Update(int iItem); - - // Events - struct TEventInfo { - CCtrlListView *treeviewctrl; - union { - NMHDR *nmhdr; - NMLISTVIEW *nmlv; - NMLVDISPINFO *nmlvdi; - NMLVSCROLL *nmlvscr; - NMLVGETINFOTIP *nmlvit; - NMLVFINDITEM *nmlvfi; - NMITEMACTIVATE *nmlvia; - NMLVKEYDOWN *nmlvkey; - }; - }; - - CCallback OnBeginDrag; - CCallback OnBeginLabelEdit; - CCallback OnBeginRDrag; - CCallback OnBeginScroll; - CCallback OnColumnClick; - //CCallback OnColumnDropdown; - //CCallback OnColumnOverflowClick; - CCallback OnDeleteAllItems; - CCallback OnDeleteItem; - CCallback OnDoubleClick; - CCallback OnEndLabelEdit; - CCallback OnEndScroll; - CCallback OnGetDispInfo; - //CCallback OnGetEmptyMarkup; - CCallback OnGetInfoTip; - CCallback OnHotTrack; - CCallback OnIncrementalSearch; - CCallback OnInsertItem; - CCallback OnItemActivate; - CCallback OnItemChanged; - CCallback OnItemChanging; - CCallback OnKeyDown; - //CCallback OnLinkClick; - CCallback OnMarqueeBegin; - CCallback OnSetDispInfo; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -class CCtrlTreeView : public CCtrlBase -{ -public: - CCtrlTreeView( CDlgBase* dlg, int ctrlId ); - - // Classic TV interface - HIMAGELIST CreateDragImage(HTREEITEM hItem); - void DeleteAllItems(); - void DeleteItem(HTREEITEM hItem); - HWND EditLabel(HTREEITEM hItem); - void EndEditLabelNow(BOOL cancel); - void EnsureVisible(HTREEITEM hItem); - void Expand(HTREEITEM hItem, DWORD flag); - COLORREF GetBkColor(); - DWORD GetCheckState(HTREEITEM hItem); - HTREEITEM GetChild(HTREEITEM hItem); - int GetCount(); - HTREEITEM GetDropHilight(); - HWND GetEditControl(); - HTREEITEM GetFirstVisible(); - HIMAGELIST GetImageList(int iImage); - int GetIndent(); - COLORREF GetInsertMarkColor(); - void GetItem(TVITEMEX *tvi); - int GetItemHeight(); - void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect); - DWORD GetItemState(HTREEITEM hItem, DWORD stateMask); - HTREEITEM GetLastVisible(); - COLORREF GetLineColor(); - HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag); - HTREEITEM GetNextSibling(HTREEITEM hItem); - HTREEITEM GetNextVisible(HTREEITEM hItem); - HTREEITEM GetParent(HTREEITEM hItem); - HTREEITEM GetPrevSibling(HTREEITEM hItem); - HTREEITEM GetPrevVisible(HTREEITEM hItem); - HTREEITEM GetRoot(); - DWORD GetScrollTime(); - HTREEITEM GetSelection(); - COLORREF GetTextColor(); - HWND GetToolTips(); - BOOL GetUnicodeFormat(); - unsigned GetVisibleCount(); - HTREEITEM HitTest(TVHITTESTINFO *hti); - HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); - //HTREEITEM MapAccIDToHTREEITEM(UINT id); - //UINT MapHTREEITEMtoAccID(HTREEITEM hItem); - void Select(HTREEITEM hItem, DWORD flag); - void SelectDropTarget(HTREEITEM hItem); - void SelectItem(HTREEITEM hItem); - void SelectSetFirstVisible(HTREEITEM hItem); - COLORREF SetBkColor(COLORREF clBack); - void SetCheckState(HTREEITEM hItem, DWORD state); - void SetImageList(HIMAGELIST hIml, int iImage); - void SetIndent(int iIndent); - void SetInsertMark(HTREEITEM hItem, BOOL fAfter); - COLORREF SetInsertMarkColor(COLORREF clMark); - void SetItem(TVITEMEX *tvi); - void SetItemHeight(short cyItem); - void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); - COLORREF SetLineColor(COLORREF clLine); - void SetScrollTime(UINT uMaxScrollTime); - COLORREF SetTextColor(COLORREF clText); - HWND SetToolTips(HWND hwndToolTips); - BOOL SetUnicodeFormat(BOOL fUnicode); - void SortChildren(HTREEITEM hItem, BOOL fRecurse); - void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); - - // Additional stuff - void TranslateItem(HTREEITEM hItem); - void TranslateTree(); - HTREEITEM FindNamedItem(HTREEITEM hItem, const TCHAR *name); - void GetItem(HTREEITEM hItem, TVITEMEX *tvi); - void GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength); - - // Events - struct TEventInfo { - CCtrlTreeView *treeviewctrl; - union { - NMHDR *nmhdr; - NMTREEVIEW *nmtv; - NMTVDISPINFO *nmtvdi; - NMTVGETINFOTIP *nmtvit; - NMTVKEYDOWN *nmtvkey; - }; - }; - - CCallback OnBeginDrag; - CCallback OnBeginLabelEdit; - CCallback OnBeginRDrag; - CCallback OnDeleteItem; - CCallback OnEndLabelEdit; - CCallback OnGetDispInfo; - CCallback OnGetInfoTip; - CCallback OnItemExpanded; - CCallback OnItemExpanding; - CCallback OnKeyDown; - CCallback OnSelChanged; - CCallback OnSelChanging; - CCallback OnSetDispInfo; - CCallback OnSingleExpand; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCustom - -template -class CCtrlCustom : public CCtrlBase -{ -private: - void (TDlg::*m_pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode); - void (TDlg::*m_pfnOnNotify)(int idCtrl, NMHDR *pnmh); - void (TDlg::*m_pfnOnMeasureItem)(MEASUREITEMSTRUCT *param); - void (TDlg::*m_pfnOnDrawItem)(DRAWITEMSTRUCT *param); - void (TDlg::*m_pfnOnDeleteItem)(DELETEITEMSTRUCT *param); - -public: - CCtrlCustom(TDlg *wnd, int idCtrl, - void (TDlg::*pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode), - void (TDlg::*pfnOnNotify)(int idCtrl, NMHDR *pnmh), - void (TDlg::*pfnOnMeasureItem)(MEASUREITEMSTRUCT *param) = NULL, - void (TDlg::*pfnOnDrawItem)(DRAWITEMSTRUCT *param) = NULL, - void (TDlg::*pfnOnDeleteItem)(DELETEITEMSTRUCT *param) = NULL): CCtrlBase(wnd, idCtrl) - { - m_pfnOnCommand = pfnOnCommand; - m_pfnOnNotify = pfnOnNotify; - m_pfnOnMeasureItem = pfnOnMeasureItem; - m_pfnOnDrawItem = pfnOnDrawItem; - m_pfnOnDeleteItem = pfnOnDeleteItem; - } - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) - { - if (m_parentWnd && m_pfnOnCommand) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnCommand)(hwndCtrl, idCtrl, idCode); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnNotify(int idCtrl, NMHDR *pnmh) - { - if (m_parentWnd && m_pfnOnNotify) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnNotify)(idCtrl, pnmh); - return m_parentWnd->m_lresult; - } - return FALSE; - } - - virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnMeasureItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnMeasureItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnDrawItem(DRAWITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnDrawItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnDrawItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnDeleteItem(DELETEITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnDeleteItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnDeleteItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CProtoDlgBase - -template -class CProtoDlgBase : public CDlgBase -{ -public: - __inline CProtoDlgBase(TProto *proto, int idDialog, HWND parent ) : - CDlgBase( idDialog, parent ), - m_proto( proto ) - { - } - - __inline void CreateLink( CCtrlData& ctrl, char *szSetting, BYTE type, DWORD iValue) - { - ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, type, iValue ); - } - __inline void CreateLink( CCtrlData& ctrl, const char *szSetting, TCHAR *szValue) - { - ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, szValue ); - } - - __inline TProto *GetProto() { return m_proto; } - -protected: - TProto* m_proto; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton); -void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow); - -#endif // __jabber_ui_utils_h__ diff --git a/protocols/IRCG/userinfo.cpp b/protocols/IRCG/userinfo.cpp deleted file mode 100644 index 8f6378a3ce..0000000000 --- a/protocols/IRCG/userinfo.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// 'User details' dialog - -struct UserDetailsDlgProcParam -{ - UserDetailsDlgProcParam( CIrcProto* _pro, HANDLE _info ) : - ppro( _pro ), - hContact( _info ) - {} - - CIrcProto* ppro; - HANDLE hContact; -}; - -#define STR_BASIC "Faster! Searches the network for an exact match of the nickname only. The hostmask is optional and provides further security if used. Wildcards (? and *) are allowed." -#define STR_ADVANCED "Slower! Searches the network for nicknames matching a wildcard string. The hostmask is mandatory and a minimum of 4 characters is necessary in the \"Nick\" field. Wildcards (? and *) are allowed." -#define STR_ERROR "Settings could not be saved!\n\nThe \"Nick\" field must contain at least four characters including wildcards,\n and it must also match the default nickname for this contact." -#define STR_ERROR2 "Settings could not be saved!\n\nA full hostmask must be set for this online detection mode to work." - -INT_PTR CALLBACK UserDetailsDlgProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - UserDetailsDlgProcParam* p = ( UserDetailsDlgProcParam* )GetWindowLongPtr( m_hwnd, GWLP_USERDATA ); - switch (msg) { - case WM_INITDIALOG: - p = new UserDetailsDlgProcParam( NULL, ( HANDLE )lParam ); - SetWindowLongPtr( m_hwnd, GWLP_USERDATA, ( LPARAM )p ); - break; - - case WM_NOTIFY: - if ((( LPNMHDR )lParam )->idFrom == 0 && (( LPNMHDR )lParam )->code == PSN_PARAMCHANGED ) { - p->ppro = ( CIrcProto* )(( PSHNOTIFY* )lParam )->lParam; - - DBVARIANT dbv; - BYTE bAdvanced = p->ppro->getByte( p->hContact, "AdvancedMode", 0); - - TranslateDialogDefault( m_hwnd); - - CheckDlgButton( m_hwnd, IDC_RADIO1, bAdvanced?BST_UNCHECKED:BST_CHECKED); - CheckDlgButton( m_hwnd, IDC_RADIO2, bAdvanced?BST_CHECKED:BST_UNCHECKED); - EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), bAdvanced); - - if ( !bAdvanced ) { - SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); - if ( !p->ppro->getTString( p->hContact, "Default", &dbv)) { - SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); - DBFreeVariant(&dbv); - } - } - else { - SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); - if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv)) { - SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); - DBFreeVariant(&dbv); - } } - - if ( !p->ppro->getTString( p->hContact, "UUser", &dbv)) { - SetDlgItemText( m_hwnd, IDC_USER, dbv.ptszVal); - DBFreeVariant(&dbv); - } - - if ( !p->ppro->getTString( p->hContact, "UHost", &dbv)) { - SetDlgItemText( m_hwnd, IDC_HOST, dbv.ptszVal); - DBFreeVariant(&dbv); - } - ProtoBroadcastAck(p->ppro->m_szModuleName, p->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); - } - break; - - case WM_COMMAND: - if (( LOWORD(wParam) == IDC_WILDCARD || LOWORD(wParam) == IDC_USER || LOWORD(wParam) == IDC_HOST ) && - ( HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) - return true; - - EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), true); - EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), true); - - if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON ) { - TCHAR temp[500]; - GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); - DBVARIANT dbv; - - BYTE bAdvanced = IsDlgButtonChecked( m_hwnd, IDC_RADIO1)?0:1; - if ( bAdvanced ) { - if ( GetWindowTextLength(GetDlgItem( m_hwnd, IDC_WILDCARD)) == 0 || - GetWindowTextLength(GetDlgItem( m_hwnd, IDC_USER)) == 0 || - GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HOST)) == 0) - { - MessageBox( NULL, TranslateT(STR_ERROR2), TranslateT("IRC error"), MB_OK|MB_ICONERROR); - return FALSE; - } - - if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { - CMString S = _T(STR_ERROR); - S += _T(" ("); - S += dbv.ptszVal; - S += _T(")"); - if (( lstrlen(temp) < 4 && lstrlen(temp)) || !WCCmp(CharLower(temp), CharLower(dbv.ptszVal))) { - MessageBox( NULL, TranslateTS( S.c_str()), TranslateT( "IRC error" ), MB_OK | MB_ICONERROR ); - DBFreeVariant( &dbv ); - return FALSE; - } - DBFreeVariant( &dbv ); - } - - GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); - if ( lstrlen( GetWord(temp, 0).c_str())) - p->ppro->setTString( p->hContact, "UWildcard", GetWord(temp, 0).c_str()); - else - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); - } - - p->ppro->setByte( p->hContact, "AdvancedMode", bAdvanced); - - GetDlgItemText( m_hwnd, IDC_USER, temp, SIZEOF(temp)); - if (lstrlen(GetWord(temp, 0).c_str())) - p->ppro->setTString( p->hContact, "UUser", GetWord(temp, 0).c_str()); - else - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); - - GetDlgItemText( m_hwnd, IDC_HOST, temp, SIZEOF(temp)); - if (lstrlen(GetWord(temp, 0).c_str())) - p->ppro->setTString( p->hContact, "UHost", GetWord(temp, 0).c_str()); - else - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); - - EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE); - } - - if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON2 ) { - if ( IsDlgButtonChecked( m_hwnd, IDC_RADIO2 )) - SetDlgItemTextA( m_hwnd, IDC_WILDCARD, ""); - SetDlgItemTextA( m_hwnd, IDC_HOST, "" ); - SetDlgItemTextA( m_hwnd, IDC_USER, "" ); - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); - DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); - EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE ); - EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), FALSE ); - } - - if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO1 ) { - SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); - - DBVARIANT dbv; - if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { - SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); - DBFreeVariant( &dbv ); - } - EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), FALSE ); - } - - if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO2 ) { - DBVARIANT dbv; - SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); - if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv )) { - SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); - DBFreeVariant( &dbv ); - } - EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), true); - } - break; - } - return FALSE; -} - -int __cdecl CIrcProto::OnInitUserInfo(WPARAM wParam, LPARAM lParam) -{ - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, lParam, 0); - HANDLE hContact = (HANDLE) lParam; - if ( !hContact || !szProto || lstrcmpiA( szProto, m_szModuleName )) - return 0; - - if ( getByte( hContact, "ChatRoom", 0 ) != 0 ) - return 0; - - if ( getByte( hContact, "DCC", 0 ) != 0 ) - return 0; - - DBVARIANT dbv; - if ( !getTString( hContact, "Default", &dbv )) { - if ( IsChannel( dbv.ptszVal )) { - DBFreeVariant( &dbv ); - return 0; - } - DBFreeVariant(&dbv); - } - - OPTIONSDIALOGPAGE odp = { 0 }; - odp.cbSize = sizeof(odp); - odp.flags = ODPF_DONTTRANSLATE; - odp.pszTitle = m_szModuleName; - odp.hIcon = NULL; - odp.dwInitParam = ( LPARAM )this; - odp.hInstance = hInst; - odp.position = -1900000000; - odp.pfnDlgProc = UserDetailsDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO); - odp.pszTitle = m_szModuleName; - UserInfo_AddPage(wParam, &odp); - return 0; -} diff --git a/protocols/IRCG/version.h b/protocols/IRCG/version.h deleted file mode 100644 index 4def5ec467..0000000000 --- a/protocols/IRCG/version.h +++ /dev/null @@ -1,12 +0,0 @@ -#define __FILEVERSION_STRING 0,11,0,1 -#define __VERSION_STRING "0.11.0.1" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 11, 0, 1) - -#define __DESC "IRC protocol for Miranda NG." -#define __AUTHOR "Miranda team" -#define __AUTHOREMAIL "ghazan@miranda-im.org" -#define __COPYRIGHT "c 2003-2011 Jurgen Persson, George Hazan" -#define __AUTHORWEB "http://miranda-ng.org/" - -#define __PLUGIN_NAME "IRC protocol" -#define __FILENAME "IRC.dll" diff --git a/protocols/IRCG/version.rc b/protocols/IRCG/version.rc deleted file mode 100644 index 3089b54d06..0000000000 --- a/protocols/IRCG/version.rc +++ /dev/null @@ -1,41 +0,0 @@ -#ifdef APSTUDIO_INVOKED -#error this file is not editable by Microsoft Visual C++ -#endif //APSTUDIO_INVOKED - -#include -#include "version.h" - -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#endif //_WIN32 - -VS_VERSION_INFO VERSIONINFO - FILEVERSION __FILEVERSION_STRING - PRODUCTVERSION __FILEVERSION_STRING - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004b0" - BEGIN - VALUE "Author", __AUTHOR - VALUE "FileDescription", __DESC - VALUE "FileVersion", __VERSION_STRING - VALUE "InternalName", __PLUGIN_NAME - VALUE "LegalCopyright", __COPYRIGHT - VALUE "OriginalFilename", __FILENAME - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END -END diff --git a/protocols/IRCG/windows.cpp b/protocols/IRCG/windows.cpp deleted file mode 100644 index 313e99353c..0000000000 --- a/protocols/IRCG/windows.cpp +++ /dev/null @@ -1,1406 +0,0 @@ -/* -IRC plugin for Miranda IM - -Copyright (C) 2003-05 Jurgen Persson -Copyright (C) 2007-09 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "irc.h" - -static WNDPROC OldMgrEditProc; - -///////////////////////////////////////////////////////////////////////////////////////// -// Message Box - -CMessageBoxDlg::CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ) : - CProtoDlgBase( _pro, IDD_MESSAGEBOX, NULL ), - pdci( _dci ), - m_Ok( this, IDOK ) -{ - m_Ok.OnClick = Callback( this, &CMessageBoxDlg::OnOk ); -} - -void CMessageBoxDlg::OnInitDialog() -{ -} - -void CMessageBoxDlg::OnOk( CCtrlButton* ) -{ - CDccSession* dcc = new CDccSession(m_proto, pdci); - - CDccSession* olddcc = m_proto->FindDCCSession(pdci->hContact); - if (olddcc) - olddcc->Disconnect(); - m_proto->AddDCCSession(pdci->hContact, dcc); - - dcc->Connect(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Whois dialog - -CWhoisDlg::CWhoisDlg( CIrcProto* _pro ) : - CCoolIrcDlg( _pro, IDD_INFO ), - m_InfoNick( this, IDC_INFO_NICK ), - m_Reply( this, IDC_REPLY ), - m_Caption( this, IDC_CAPTION ), - m_AwayTime( this, IDC_AWAYTIME ), - m_InfoName( this, IDC_INFO_NAME ), - m_InfoId( this, IDC_INFO_ID ), - m_InfoAddress( this, IDC_INFO_ADDRESS ), - m_InfoChannels( this, IDC_INFO_CHANNELS ), - m_InfoAuth( this, IDC_INFO_AUTH ), - m_InfoServer( this, IDC_INFO_SERVER ), - m_InfoAway2( this, IDC_INFO_AWAY2 ), - m_InfoOther( this, IDC_INFO_OTHER ), - m_Ping( this, IDC_PING ), - m_Version( this, IDC_VERSION ), - m_Time( this, IDC_TIME ), - m_userInfo( this, IDC_USERINFO ), - m_Refresh( this, ID_INFO_GO ), - m_Query( this, ID_INFO_QUERY ) -{ - m_Ping.OnClick = Callback( this, &CWhoisDlg::OnPing ); - m_Version.OnClick = Callback( this, &CWhoisDlg::OnVersion ); - m_Time.OnClick = Callback( this, &CWhoisDlg::OnTime ); - m_userInfo.OnClick = Callback( this, &CWhoisDlg::OnUserInfo ); - m_Refresh.OnClick = Callback( this, &CWhoisDlg::OnGo ); - m_Query.OnClick = Callback( this, &CWhoisDlg::OnQuery ); -} - -void CWhoisDlg::OnInitDialog() -{ - LOGFONT lf; - HFONT hFont = ( HFONT )m_AwayTime.SendMsg( WM_GETFONT, 0, 0 ); - GetObject( hFont, sizeof( lf ), &lf ); - lf.lfWeight = FW_BOLD; - hFont = CreateFontIndirect( &lf ); - m_AwayTime.SendMsg( WM_SETFONT, ( WPARAM )hFont, 0 ); - - CCoolIrcDlg::OnInitDialog(); - - WindowSetIcon( m_hwnd, IDI_WHOIS ); -} - -void CWhoisDlg::OnClose() -{ - ShowWindow( m_hwnd, SW_HIDE); - SendMessage( m_hwnd, WM_SETREDRAW, FALSE, 0); -} - -void CWhoisDlg::OnDestroy() -{ - CCoolIrcDlg::OnDestroy(); - - HFONT hFont2=(HFONT)SendDlgItemMessage( m_hwnd,IDC_AWAYTIME,WM_GETFONT,0,0); - SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); - DeleteObject(hFont2); - - m_proto->m_whoisDlg = NULL; -} - -void CWhoisDlg::OnGo( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_proto->PostIrcMessage( _T("/WHOIS %s %s"), szTemp, szTemp ); -} - -void CWhoisDlg::OnQuery( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_proto->PostIrcMessage( _T("/QUERY %s"), szTemp ); -} - -void CWhoisDlg::OnPing( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_Reply.SetText( TranslateT("Please wait...")); - m_proto->PostIrcMessage( _T("/PRIVMSG %s \001PING %u\001"), szTemp, time(0)); -} - -void CWhoisDlg::OnUserInfo( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_Reply.SetText( TranslateT("Please wait...")); - m_proto->PostIrcMessage( _T("/PRIVMSG %s \001USERINFO\001"), szTemp); -} - -void CWhoisDlg::OnTime( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_Reply.SetText( TranslateT("Please wait...")); - m_proto->PostIrcMessage( _T("/PRIVMSG %s \001TIME\001"), szTemp); -} - -void CWhoisDlg::OnVersion( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); - m_Reply.SetText( TranslateT("Please wait...")); - m_proto->PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), szTemp); -} - -void CWhoisDlg::ShowMessage( const CIrcMessage* pmsg ) -{ - if ( m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()) == CB_ERR) - m_InfoNick.SendMsg( CB_ADDSTRING, 0, (LPARAM) pmsg->parameters[1].c_str()); - int i = m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()); - m_InfoNick.SendMsg( CB_SETCURSEL, i, 0); - m_Caption.SetText( pmsg->parameters[1].c_str()); - m_InfoName.SetText( pmsg->parameters[5].c_str()); - m_InfoAddress.SetText( pmsg->parameters[3].c_str()); - m_InfoId.SetText( pmsg->parameters[2].c_str()); - m_InfoChannels.SetText( _T("")); - m_InfoServer.SetText( _T("")); - m_InfoAway2.SetText( _T("")); - m_InfoAuth.SetText( _T("")); - m_InfoOther.SetText( _T("")); - m_Reply.SetText( _T("")); - SetWindowText( m_hwnd, TranslateT("User information")); - EnableWindow( GetDlgItem( m_hwnd, ID_INFO_QUERY), true ); - ShowWindow( m_hwnd, SW_SHOW); - if ( IsIconic( m_hwnd )) - ShowWindow( m_hwnd, SW_SHOWNORMAL ); - SendMessage( m_hwnd, WM_SETREDRAW, TRUE, 0); - InvalidateRect( m_hwnd, NULL, TRUE); -} - -void CWhoisDlg::ShowMessageNoUser( const CIrcMessage* pmsg ) -{ - m_InfoNick.SetText( pmsg->parameters[2].c_str()); - m_InfoNick.SendMsg( CB_SETEDITSEL, 0,MAKELPARAM(0,-1)); - m_Caption.SetText( pmsg->parameters[2].c_str()); - m_InfoName.SetText( _T("")); - m_InfoAddress.SetText( _T("")); - m_InfoId.SetText( _T("")); - m_InfoChannels.SetText( _T("")); - m_InfoServer.SetText( _T("")); - m_InfoAway2.SetText( _T("")); - m_InfoAuth.SetText( _T("")); - m_Reply.SetText( _T("")); - EnableWindow(GetDlgItem(m_hwnd, ID_INFO_QUERY), false); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Change nickname' dialog - -CNickDlg::CNickDlg(CIrcProto *_pro) : - CCoolIrcDlg( _pro, IDD_NICK ), - m_Ok( this, IDOK ), - m_Enick( this, IDC_ENICK ) -{ - m_Ok.OnClick = Callback( this, &CNickDlg::OnOk ); -} - -void CNickDlg::OnInitDialog() -{ - CCoolIrcDlg::OnInitDialog(); - WindowSetIcon( m_hwnd, IDI_RENAME ); - - DBVARIANT dbv; - if ( !m_proto->getTString( "RecentNicks", &dbv)) { - for (int i = 0; i<10; i++) - if ( !GetWord( dbv.ptszVal, i).IsEmpty()) - SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)GetWord(dbv.ptszVal, i).c_str()); - - DBFreeVariant(&dbv); -} } - -void CNickDlg::OnDestroy() -{ - CCoolIrcDlg::OnDestroy(); - m_proto->m_nickDlg = NULL; -} - -void CNickDlg::OnOk( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_Enick.GetText( szTemp, SIZEOF(szTemp)); - m_proto->PostIrcMessage( _T("/NICK %s"), szTemp); - - CMString S = szTemp; - DBVARIANT dbv; - if ( !m_proto->getTString( "RecentNicks", &dbv )) { - for ( int i = 0; i<10; i++ ) { - CMString s = GetWord(dbv.ptszVal, i); - if ( !s.IsEmpty() && s != szTemp) - S += _T(" ") + s; - } - DBFreeVariant(&dbv); - } - m_proto->setTString( "RecentNicks", S.c_str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Change nickname' dialog - -#define LIST_TIMER 10 - -CListDlg::CListDlg(CIrcProto *_pro) : - CProtoDlgBase( _pro, IDD_LIST, NULL ), - m_Join( this, IDC_JOIN ), - m_list( this, IDC_INFO_LISTVIEW ), - m_list2( this, IDC_INFO_LISTVIEW2 ), - m_status( this, IDC_TEXT ), - m_filter( this, IDC_FILTER_STRING ) -{ - m_list2.OnDoubleClick = m_list.OnDoubleClick = m_Join.OnClick = Callback( this, &CListDlg::OnJoin ); - m_list.OnColumnClick = Callback( this, &CListDlg::List_OnColumnClick ); -} - -void CListDlg::OnInitDialog() -{ - RECT screen; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0); - LVCOLUMN lvC; - int COLUMNS_SIZES[4] ={200, 50,50,2000}; - TCHAR szBuffer[32]; - - lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - lvC.fmt = LVCFMT_LEFT; - for ( int index = 0; index < 4; index++ ) { - lvC.iSubItem = index; - lvC.cx = COLUMNS_SIZES[index]; - - switch( index ) { - case 0: lstrcpy( szBuffer, TranslateT("Channel")); break; - case 1: lstrcpy( szBuffer, _T("#")); break; - case 2: lstrcpy( szBuffer, TranslateT("Mode")); break; - case 3: lstrcpy( szBuffer, TranslateT("Topic")); break; - } - lvC.pszText = szBuffer; - m_list.InsertColumn( index, &lvC ); - m_list2.InsertColumn( index, &lvC ); - } - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); - - m_list.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); - m_list2.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); - WindowSetIcon( m_hwnd, IDI_LIST ); - m_status.SetText( TranslateT( "Please wait..." )); -} - -INT_PTR CListDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if ( msg == WM_TIMER ) { - ::KillTimer( m_hwnd, m_timer ); m_timer = 0; - - // Retrieve the input text - TCHAR strFilterText[255]; - m_filter.GetText( strFilterText, SIZEOF(strFilterText)); - - if ( strFilterText[0] ) { - int itemCount = 0; - int j = m_list.GetItemCount(); - if ( j <= 0 ) - return FALSE; - - // Empty the filtered list - m_list2.DeleteAllItems(); - - LVITEM lvm; - TCHAR text[255]; - lvm.pszText = text; // Set buffer for texts - lvm.cchTextMax = 128; - lvm.mask = LVIF_TEXT; - for ( int i = 0; i < j; i++ ) { - lvm.iSubItem = 0; // First column - lvm.iItem = i; - m_list.GetItem( &lvm ); - - // Match the text? - TCHAR* t = _tcsstr( lvm.pszText, strFilterText); - if ( t == NULL ) // If no, then Check if in the topics - { - LVITEM lvm2; // To avoid to overwrite the external lvm - TCHAR text[300]; - lvm2.pszText = text; // Set buffer for texts - lvm2.cchTextMax = SIZEOF(text); - lvm2.mask = LVIF_TEXT; - lvm2.iSubItem = 3; // Topic column - lvm2.iItem = i; - m_list.GetItem( &lvm ); - - // Match the text? - t = _tcsstr( lvm.pszText, strFilterText); - } - if ( t ) { - ++itemCount; - - // Column 0 - LVITEM lvItem; - lvItem.iItem = m_list2.GetItemCount(); - lvItem.mask = LVIF_TEXT | LVIF_PARAM; - - lvItem.iSubItem = 0; - lvItem.pszText = lvm.pszText; - lvItem.lParam = lvItem.iItem; - lvItem.iItem = m_list2.InsertItem( &lvItem ); - - // Column 2 - lvm.mask = LVIF_TEXT; - lvm.iSubItem = 1; - lvm.iItem = i; - m_list.GetItem( &lvm ); - - lvItem.mask = LVIF_TEXT; - lvItem.iSubItem = 1; - lvItem.pszText = lvm.pszText; - m_list2.SetItem( &lvItem ); - - // Column 4 - lvm.mask= LVIF_TEXT; - lvm.iSubItem = 3; - lvm.iItem = i; - m_list.GetItem( &lvm ); - - lvItem.mask = LVIF_TEXT; - lvItem.pszText = lvm.pszText; - lvItem.iSubItem = 3; - m_list2.SetItem( &lvItem ); - } } - - // Show the list - SetWindowPos( m_list2.GetHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); - ShowWindow( m_list.GetHwnd(), SW_HIDE ); - - // New dialog title - TCHAR newTitle[255]; - wsprintf( newTitle, TranslateT("%s - Filtered - %d items"), m_title, itemCount ); - SetWindowText( m_hwnd, newTitle ); - } - else { - ShowWindow( m_list.GetHwnd(), SW_SHOW ); - ShowWindow( m_list2.GetHwnd(), SW_HIDE); - SetWindowText( m_hwnd, m_title ); - } } - - return CProtoDlgBase::DlgProc( msg, wParam, lParam ); -} - -void CListDlg::OnChange( CCtrlBase* ctrl ) -{ - if ( ctrl->GetCtrlId() == IDC_FILTER_STRING ) - m_timer = ::SetTimer( m_hwnd, LIST_TIMER, 200, NULL ); -} - -void CListDlg::OnDestroy() -{ - if ( m_timer ) - ::KillTimer( m_hwnd, m_timer ); - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); - m_proto->m_listDlg = NULL; -} - -struct ListViewSortParam -{ - CCtrlListView* pList; - int iSubItem; -}; - -static int CALLBACK ListViewSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - ListViewSortParam* param = ( ListViewSortParam* )lParamSort; - if ( !param->pList->GetHwnd()) - return 0; - - TCHAR temp1[512]; - TCHAR temp2[512]; - LVITEM lvm; - lvm.mask = LVIF_TEXT; - lvm.iItem = lParam1; - lvm.iSubItem = param->iSubItem; - lvm.pszText = temp1; - lvm.cchTextMax = 511; - param->pList->GetItem( &lvm ); - lvm.iItem = lParam2; - lvm.pszText = temp2; - param->pList->GetItem( &lvm ); - if (param->iSubItem != 1){ - if (lstrlen(temp1) != 0 && lstrlen(temp2) !=0) - return lstrcmpi(temp1, temp2); - - return ( *temp1 == 0 ) ? 1 : -1; - } - - return ( StrToInt(temp1) < StrToInt(temp2)) ? 1 : -1; -} - -int CListDlg::Resizer( UTILRESIZECONTROL *urc) -{ - switch( urc->wId ) { - case IDC_INFO_LISTVIEW: - case IDC_INFO_LISTVIEW2: - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH; - case IDC_FILTER_STRING: - case IDC_FILTER_BTN: - return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; - case IDC_TEXT: - return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM | RD_ANCHORX_WIDTH; - } - - return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; -} - -void CListDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ev ) -{ - ListViewSortParam param = { &m_list, ev->nmlv->iSubItem }; - m_list.SortItems( ListViewSort, (LPARAM)¶m ); - UpdateList(); -} - -void CListDlg::OnJoin( CCtrlButton* ) -{ - TCHAR szTemp[255]; - m_filter.GetText( szTemp, SIZEOF(szTemp)); - - if ( szTemp[0] ) - m_list2.GetItemText( m_list2.GetSelectionMark(), 0, szTemp, 255 ); - else - m_list.GetItemText( m_list.GetSelectionMark(), 0, szTemp, 255 ); - m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); -} - -void CListDlg::UpdateList() -{ - GetWindowText( m_hwnd, m_title, 128); - - int j = m_list.GetItemCount(); - if ( j > 0 ) { - LVITEM lvm; - lvm.mask= LVIF_PARAM; - lvm.iSubItem = 0; - for ( int i = 0; i < j; i++ ) { - lvm.iItem = i; - lvm.lParam = i; - m_list.SetItem( &lvm ); -} } } - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Join' dialog - -CJoinDlg::CJoinDlg(CIrcProto *_pro) : - CCoolIrcDlg( _pro, IDD_NICK, NULL ), - m_Ok( this, IDOK ) -{ - m_Ok.OnClick = Callback( this, &CJoinDlg::OnOk ); -} - -void CJoinDlg::OnInitDialog() -{ - CCoolIrcDlg::OnInitDialog(); - - DBVARIANT dbv; - if ( !m_proto->getTString( "RecentChannels", &dbv)) { - for ( int i = 0; i < 20; i++ ) { - if ( !GetWord( dbv.ptszVal, i).IsEmpty()) { - CMString S = GetWord(dbv.ptszVal, i); - ReplaceString( S, _T("%newl"), _T(" ")); - SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)S.c_str()); - } } - DBFreeVariant(&dbv); -} } - -void CJoinDlg::OnDestroy() -{ - CCoolIrcDlg::OnDestroy(); - m_proto->m_joinDlg = NULL; -} - -void CJoinDlg::OnOk( CCtrlButton* ) -{ - TCHAR szTemp[255]; - GetDlgItemText( m_hwnd, IDC_ENICK, szTemp, SIZEOF(szTemp)); - if ( m_proto->IsChannel( szTemp )) - m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); - else - m_proto->PostIrcMessage( _T("/JOIN #%s"), szTemp ); - - CMString S = szTemp; - ReplaceString( S, _T(" "), _T("%newl")); - CMString SL = S; - - DBVARIANT dbv; - if ( !m_proto->getTString( "RecentChannels", &dbv)) { - for (int i = 0; i < 20; i++ ) { - CMString W = GetWord(dbv.ptszVal, i); - if ( !W.IsEmpty() && W != SL) - S += _T(" ") + W; - } - DBFreeVariant(&dbv); - } - m_proto->setTString("RecentChannels", S.c_str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Quick' dialog - -CQuickDlg::CQuickDlg(CIrcProto *_pro) : - CCoolIrcDlg( _pro, IDD_QUICKCONN ), - m_Ok( this, IDOK ), - m_serverCombo( this, IDC_SERVERCOMBO ) -{ - m_Ok.OnClick = Callback( this, &CQuickDlg::OnOk ); - m_serverCombo.OnChange = Callback( this, &CQuickDlg::OnServerCombo ); -} - -void CQuickDlg::OnInitDialog() -{ - CCoolIrcDlg::OnInitDialog(); - - if ( g_servers.getCount() > 0 ) { - for ( int i=0; i < g_servers.getCount(); i++ ) { - const SERVER_INFO& si = g_servers[i]; - m_serverCombo.AddStringA( si.m_name, ( LPARAM )&si ); - } - } - else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); - - m_si = new SERVER_INFO; - m_si->m_group = mir_strdup( "" ); - m_si->m_name = mir_strdup( Translate("---- Not listed server ----")); - - DBVARIANT dbv; - if ( !m_proto->getString( "ServerName", &dbv )) { - m_si->m_address = mir_strdup( dbv.pszVal ); - DBFreeVariant(&dbv); - } - else m_si->m_address = mir_strdup( Translate("Type new server address here")); - - if ( !m_proto->getString( "PortStart", &dbv )) { - m_si->m_portStart = atoi( dbv.pszVal ); - DBFreeVariant(&dbv); - } - else m_si->m_portStart = 6667; - - if ( !m_proto->getString( "PortEnd", &dbv )) { - m_si->m_portEnd = atoi( dbv.pszVal ); - DBFreeVariant(&dbv); - } - else m_si->m_portEnd = 6667; - - m_si->m_iSSL = m_proto->getByte( "UseSSL", 0 ); - - m_serverCombo.AddStringA( m_si->m_name, ( LPARAM )m_si ); - - if ( m_proto->m_quickComboSelection != -1 ) { - m_serverCombo.SetCurSel( m_proto->m_quickComboSelection ); - OnServerCombo( NULL ); - } - else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); -} - -void CQuickDlg::OnDestroy() -{ - CCoolIrcDlg::OnDestroy(); - - delete m_si; - m_proto->m_quickDlg = NULL; -} - -void CQuickDlg::OnOk( CCtrlButton* ) -{ - GetDlgItemTextA( m_hwnd, IDC_SERVER, m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); - GetDlgItemTextA( m_hwnd, IDC_PORT, m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); - GetDlgItemTextA( m_hwnd, IDC_PORT2, m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); - GetDlgItemTextA( m_hwnd, IDC_PASS, m_proto->m_password, SIZEOF(m_proto->m_password)); - - int i = m_serverCombo.GetCurSel(); - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - if ( pData && (INT_PTR)pData != CB_ERR ) { - lstrcpyA( m_proto->m_network, pData->m_group ); - pData->m_iSSL = 0; - if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_ON )) - pData->m_iSSL = 2; - if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_AUTO )) - pData->m_iSSL = 1; - m_proto->m_iSSL = pData->m_iSSL; - } - - TCHAR windowname[20]; - GetWindowText( m_hwnd, windowname, 20); - if ( lstrcmpi(windowname, _T("Miranda IRC")) == 0 ) { - m_proto->m_serverComboSelection = m_serverCombo.GetCurSel() - 1; - m_proto->setDword("ServerComboSelection",m_proto->m_serverComboSelection); - m_proto->setString("ServerName",m_proto->m_serverName); - m_proto->setString("PortStart",m_proto->m_portStart); - m_proto->setString("PortEnd",m_proto->m_portEnd); - CallService( MS_DB_CRYPT_ENCODESTRING, 499, (LPARAM)m_proto->m_password); - m_proto->setString("Password",m_proto->m_password); - CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_proto->m_password); - m_proto->setString("Network",m_proto->m_network); - m_proto->setByte("UseSSL",m_proto->m_iSSL); - } - m_proto->m_quickComboSelection = m_serverCombo.GetCurSel(); - m_proto->setDword("QuickComboSelection",m_proto->m_quickComboSelection); - m_proto->DisconnectFromServer(); - m_proto->ConnectToServer(); -} - -void CQuickDlg::OnServerCombo( CCtrlData* ) -{ - int i = m_serverCombo.GetCurSel(); - if ( i == CB_ERR ) - return; - - SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); - SetDlgItemTextA( m_hwnd, IDC_SERVER, pData->m_address ); - SetDlgItemTextA( m_hwnd, IDC_PASS, "" ); - SetDlgItemInt( m_hwnd, IDC_PORT, pData->m_portStart, FALSE ); - SetDlgItemInt( m_hwnd, IDC_PORT2, pData->m_portEnd, FALSE ); - - if ( pData->m_iSSL == 0 ) { - CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_CHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); - } - if ( pData->m_iSSL == 1 ) { - CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_CHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); - } - if ( pData->m_iSSL == 2 ) { - CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_CHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); - CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); - } - - if ( !strcmp( pData->m_name, Translate("---- Not listed server ----" ))) { - SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, false, 0); - SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, false, 0); - SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, false, 0); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), TRUE); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),TRUE); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), TRUE); - } - else { - SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, true, 0); - SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, true, 0); - SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, true, 0); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), FALSE); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),FALSE); - EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), FALSE); - } - - EnableWindow(GetDlgItem( m_hwnd, IDOK), true); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Question' dialog - -CQuestionDlg::CQuestionDlg(CIrcProto *_pro, CManagerDlg* owner ) : - CCoolIrcDlg( _pro, IDD_QUESTION, ( owner == NULL ) ? NULL : owner->GetHwnd()), - m_Ok( this, IDOK ), - m_owner( owner ) -{ - m_Ok.OnClick = Callback( this, &CQuestionDlg::OnOk ); -} - -void CQuestionDlg::OnInitDialog() -{ - CCoolIrcDlg::OnInitDialog(); - - WindowSetIcon( m_hwnd, IDI_IRCQUESTION ); -} - -void CQuestionDlg::OnClose() -{ - if ( m_owner ) - m_owner->CloseQuestion(); -} - -void CQuestionDlg::OnOk( CCtrlButton* ) -{ - int i = GetWindowTextLength( GetDlgItem( m_hwnd, IDC_EDIT )); - if ( i > 0 ) { - TCHAR* l = new TCHAR[ i+2 ]; - GetDlgItemText( m_hwnd, IDC_EDIT, l, i+1 ); - - int j = GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HIDDENEDIT)); - TCHAR* m = new TCHAR[ j+2 ]; - GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, m, j+1 ); - - TCHAR* text = _tcsstr( m, _T("%question")); - TCHAR* p1 = text; - TCHAR* p2 = NULL; - if ( p1 ) { - p1 += 9; - if ( *p1 == '=' && p1[1] == '\"' ) { - p1 += 2; - for ( int k =0; k < 3; k++ ) { - p2 = _tcschr( p1, '\"' ); - if ( p2 ) { - p2++; - if ( k == 2 || (*p2 != ',' || (*p2 == ',' && p2[1] != '\"'))) - *p2 = '\0'; - else - p2 += 2; - p1 = p2; - } } - } - else *p1 = '\0'; - } - - TCHAR* n = ( TCHAR* )alloca( sizeof( TCHAR )*( j+2 )); - GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, n, j+1 ); - CMString S( n ); - ReplaceString( S, text, l ); - m_proto->PostIrcMessageWnd( NULL, NULL, (TCHAR*)S.c_str()); - - delete []m; - delete []l; - - if ( m_owner ) - m_owner->ApplyQuestion(); -} } - -void CQuestionDlg::Activate() -{ - ShowWindow( m_hwnd, SW_SHOW ); - SetActiveWindow( m_hwnd ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// 'Channel Manager' dialog - -CManagerDlg::CManagerDlg(CIrcProto *_pro) : - CCoolIrcDlg( _pro, IDD_CHANMANAGER ), - m_list( this, IDC_LIST ), - - m_check1( this, IDC_CHECK1 ), - m_check2( this, IDC_CHECK2 ), - m_check3( this, IDC_CHECK3 ), - m_check4( this, IDC_CHECK4 ), - m_check5( this, IDC_CHECK5 ), - m_check6( this, IDC_CHECK6 ), - m_check7( this, IDC_CHECK7 ), - m_check8( this, IDC_CHECK8 ), - m_check9( this, IDC_CHECK9 ), - - m_key( this, IDC_KEY ), - m_limit( this, IDC_LIMIT ), - m_topic( this, IDC_TOPIC ), - - m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add ban/invite/exception")), - m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit selected ban/invite/exception")), - m_remove( this, IDC_REMOVE, LoadIconEx(IDI_DELETE), LPGEN("Delete selected ban/invite/exception")), - m_applyModes( this, IDC_APPLYMODES, LoadIconEx( IDI_APPLY ), LPGEN("Set these modes for the channel")), - m_applyTopic( this, IDC_APPLYTOPIC, LoadIconEx( IDI_APPLY ), LPGEN("Set this topic for the channel")), - - m_radio1( this, IDC_RADIO1 ), - m_radio2( this, IDC_RADIO2 ), - m_radio3( this, IDC_RADIO3 ) -{ - m_add.OnClick = Callback( this, &CManagerDlg::OnAdd ); - m_edit.OnClick = Callback( this, &CManagerDlg::OnEdit ); - m_remove.OnClick = Callback( this, &CManagerDlg::OnRemove ); - - m_applyModes.OnClick = Callback( this, &CManagerDlg::OnApplyModes ); - m_applyTopic.OnClick = Callback( this, &CManagerDlg::OnApplyTopic ); - - m_check1.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check2.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check3.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check4.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check5.OnChange = Callback( this, &CManagerDlg::OnCheck5 ); - m_check6.OnChange = Callback( this, &CManagerDlg::OnCheck6 ); - m_check7.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check8.OnChange = Callback( this, &CManagerDlg::OnCheck ); - m_check9.OnChange = Callback( this, &CManagerDlg::OnCheck ); - - m_key.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); - m_limit.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); - m_topic.OnChange = Callback( this, &CManagerDlg::OnChangeTopic ); - - m_radio1.OnChange = Callback( this, &CManagerDlg::OnRadio ); - m_radio2.OnChange = Callback( this, &CManagerDlg::OnRadio ); - m_radio3.OnChange = Callback( this, &CManagerDlg::OnRadio ); - - m_list.OnDblClick = Callback( this, &CManagerDlg::OnListDblClick ); - m_list.OnSelChange = Callback( this, &CManagerDlg::OnChangeList ); -} - -LRESULT CALLBACK MgrEditSubclassProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch( msg ) { - case WM_CHAR : - if ( wParam == 21 || wParam == 11 || wParam == 2 ) { - char w[2]; - if ( wParam == 11 ) { - w[0] = 3; - w[1] = '\0'; - } - if ( wParam == 2 ) { - w[0] = 2; - w[1] = '\0'; - } - if ( wParam == 21 ) { - w[0] = 31; - w[1] = '\0'; - } - SendMessage( m_hwnd, EM_REPLACESEL, false, (LPARAM) w); - SendMessage( m_hwnd, EM_SCROLLCARET, 0, 0 ); - return 0; - } - break; - } - - return CallWindowProc(OldMgrEditProc, m_hwnd, msg, wParam, lParam); -} - -void CManagerDlg::OnInitDialog() -{ - CCoolIrcDlg::OnInitDialog(); - - POINT pt; - pt.x = 3; - pt.y = 3; - HWND hwndEdit = ChildWindowFromPoint( m_topic.GetHwnd(), pt); - OldMgrEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit, GWLP_WNDPROC,(LONG_PTR)MgrEditSubclassProc); - - WindowSetIcon( m_hwnd, IDI_MANAGER ); - - m_list.SendMsg( LB_SETHORIZONTALEXTENT, 750, NULL ); - m_radio1.SetState( true ); - - const char* modes = m_proto->sChannelModes.c_str(); - if ( !strchr( modes, 't')) m_check1.Disable(); - if ( !strchr( modes, 'n')) m_check2.Disable(); - if ( !strchr( modes, 'i')) m_check3.Disable(); - if ( !strchr( modes, 'm')) m_check4.Disable(); - if ( !strchr( modes, 'k')) m_check5.Disable(); - if ( !strchr( modes, 'l')) m_check6.Disable(); - if ( !strchr( modes, 'p')) m_check7.Disable(); - if ( !strchr( modes, 's')) m_check8.Disable(); - if ( !strchr( modes, 'c')) m_check9.Disable(); -} - -void CManagerDlg::OnClose() -{ - if ( m_applyModes.Enabled() || m_applyTopic.Enabled()) { - int i = MessageBox( NULL, TranslateT("You have not applied all changes!\n\nApply before exiting?"), TranslateT("IRC warning"), MB_YESNOCANCEL|MB_ICONWARNING|MB_DEFBUTTON3); - if ( i == IDCANCEL ) { - m_lresult = TRUE; - return; - } - - if ( i == IDYES ) { - if ( m_applyModes.Enabled()) - OnApplyModes( NULL ); - if ( m_applyTopic.Enabled()) - OnApplyTopic( NULL ); - } } - - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255 ); - CMString S = _T(""); - TCHAR temp[1000]; - for ( int i = 0; i < 5; i++ ) { - if ( m_topic.SendMsg( CB_GETLBTEXT, i, (LPARAM)temp) != LB_ERR) { - CMString S1 = temp; -/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ -#if !defined(__GNUC__) || !defined(UNICODE) - ReplaceString( S1, _T(" "), _T("%¤")); -#endif - S += _T(" ") + S1; - } } - - if ( !S.IsEmpty() && m_proto->IsConnected()) { - mir_sntprintf( temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); - char* p = mir_t2a(temp); - m_proto->setTString(p, S.c_str()); - mir_free(p); - } - DestroyWindow( m_hwnd); -} - -void CManagerDlg::OnDestroy() -{ - CCoolIrcDlg::OnDestroy(); - m_proto->m_managerDlg = NULL; -} - -void CManagerDlg::OnAdd( CCtrlButton* ) -{ - TCHAR temp[100]; - TCHAR mode[3]; - if ( m_radio1.GetState()) { - lstrcpy( mode, _T("+b")); - lstrcpyn( temp, TranslateT("Add ban"), 100 ); - } - if ( m_radio2.GetState()) { - lstrcpy( mode, _T("+I")); - lstrcpyn( temp, TranslateT("Add invite"), 100 ); - } - if ( m_radio3.GetState()) { - lstrcpy( mode, _T("+e")); - lstrcpyn( temp, TranslateT("Add exception"), 100); - } - - m_add.Disable(); - m_edit.Disable(); - m_remove.Disable(); - - CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); - dlg->Show(); - HWND addban_hWnd = dlg->GetHwnd(); - SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); - SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); - - TCHAR temp2[450]; - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); - mir_sntprintf(temp2, 450, _T("/MODE %s %s %s"), window, mode, _T("%question")); - SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); - dlg->Activate(); -} - -void CManagerDlg::OnEdit( CCtrlButton* ) -{ - if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { - int i = m_list.GetCurSel(); - if ( i != LB_ERR ) { - TCHAR* m = m_list.GetItemText( i ); - CMString user = GetWord(m, 0); - mir_free( m ); - - TCHAR temp[100]; - TCHAR mode[3]; - if ( m_radio1.GetState()) { - lstrcpy( mode, _T("b")); - lstrcpyn( temp, TranslateT("Edit ban"), 100 ); - } - if ( m_radio2.GetState()) { - lstrcpy( mode, _T("I")); - lstrcpyn( temp, TranslateT("Edit invite?"), 100 ); - } - if ( m_radio3.GetState()) { - lstrcpy( mode, _T("e")); - lstrcpyn( temp, TranslateT("Edit exception?"), 100 ); - } - - CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); - dlg->Show(); - HWND addban_hWnd = dlg->GetHwnd(); - SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); - SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); - SetWindowText(GetDlgItem(addban_hWnd, IDC_EDIT), user.c_str()); - - m_add.Disable(); - m_edit.Disable(); - m_remove.Disable(); - - TCHAR temp2[450]; - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); - mir_sntprintf(temp2, 450, _T("/MODE %s -%s %s%s/MODE %s +%s %s"), window, mode, user.c_str(), _T("%newl"), window, mode, _T("%question")); - SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); - dlg->Activate(); -} } } - -void CManagerDlg::OnRemove( CCtrlButton* ) -{ - int i = m_list.GetCurSel(); - if ( i != LB_ERR ) { - m_add.Disable(); - m_edit.Disable(); - m_remove.Disable(); - - TCHAR temp[100], mode[3]; - TCHAR* m = m_list.GetItemText( i, temp, SIZEOF( temp )); - CMString user = GetWord(m, 0); - - if ( m_radio1.GetState()) { - lstrcpy(mode, _T("-b")); - lstrcpyn(temp, TranslateT( "Remove ban?" ), 100 ); - } - if ( m_radio2.GetState()) { - lstrcpy(mode, _T("-I")); - lstrcpyn(temp, TranslateT( "Remove invite?" ), 100 ); - } - if ( m_radio3.GetState()) { - lstrcpy(mode, _T("-e")); - lstrcpyn(temp, TranslateT( "Remove exception?" ), 100 ); - } - - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); - if ( MessageBox( m_hwnd, user.c_str(), temp, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 ) == IDYES ) { - m_proto->PostIrcMessage( _T("/MODE %s %s %s"), window, mode, user.c_str()); - ApplyQuestion(); - } - CloseQuestion(); -} } - -void CManagerDlg::OnListDblClick( CCtrlListBox* ) -{ - OnEdit( NULL ); -} - -void CManagerDlg::OnChangeList( CCtrlListBox* ) -{ - if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { - m_edit.Enable(); - m_remove.Enable(); -} } - -void CManagerDlg::OnChangeModes( CCtrlData* ) -{ - m_applyModes.Enable(); -} - -void CManagerDlg::OnChangeTopic( CCtrlData* ) -{ - m_applyTopic.Enable(); -} - -void CManagerDlg::OnApplyModes( CCtrlButton* ) -{ - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); - CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if ( wi ) { - TCHAR toadd[10]; *toadd = '\0'; - TCHAR toremove[10]; *toremove = '\0'; - CMString appendixadd = _T(""); - CMString appendixremove = _T(""); - if ( wi->pszMode && _tcschr( wi->pszMode, 't' )) { - if ( !m_check1.GetState()) - lstrcat( toremove, _T("t")); - } - else if ( m_check1.GetState()) - lstrcat( toadd, _T("t")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 'n' )) { - if ( !m_check2.GetState()) - lstrcat( toremove, _T("n")); - } - else if ( m_check2.GetState()) - lstrcat( toadd, _T("n")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 'i' )) { - if ( !m_check3.GetState()) - lstrcat( toremove, _T("i")); - } - else if ( m_check3.GetState()) - lstrcat( toadd, _T("i")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 'm' )) { - if ( !m_check4.GetState()) - lstrcat( toremove, _T("m")); - } - else if ( m_check4.GetState()) - lstrcat( toadd, _T("m")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 'p' )) { - if ( !m_check7.GetState()) - lstrcat( toremove, _T("p")); - } - else if ( m_check7.GetState()) - lstrcat( toadd, _T("p")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 's' )) { - if ( !m_check8.GetState()) - lstrcat( toremove, _T("s")); - } - else if ( m_check8.GetState()) - lstrcat( toadd, _T("s")); - - if ( wi->pszMode && _tcschr( wi->pszMode, 'c' )) { - if ( !m_check9.GetState()) - lstrcat( toremove, _T("c")); - } - else if ( m_check9.GetState()) - lstrcat( toadd, _T("c")); - - CMString Key = _T(""); - CMString Limit = _T(""); - if ( wi->pszMode && wi->pszPassword && _tcschr( wi->pszMode, 'k' )) { - if ( !m_check5.GetState()) { - lstrcat( toremove, _T("k")); - appendixremove += _T(" ") + CMString(wi->pszPassword); - } - else if ( GetWindowTextLength( m_key.GetHwnd())) { - TCHAR temp[400]; - m_key.GetText( temp, 14); - - if ( Key != temp ) { - lstrcat( toremove, _T("k")); - lstrcat( toadd, _T("k")); - appendixadd += _T(" ") + CMString(temp); - appendixremove += _T(" ") + CMString(wi->pszPassword); - } } - } - else if ( m_check5.GetState() && GetWindowTextLength( m_key.GetHwnd())) { - lstrcat( toadd, _T("k")); - appendixadd += _T(" "); - - TCHAR temp[400]; - m_key.GetText( temp, SIZEOF(temp)); - appendixadd += temp; - } - - if ( _tcschr( wi->pszMode, 'l' )) { - if ( !m_check6.GetState()) - lstrcat( toremove, _T("l")); - else if ( GetWindowTextLength( GetDlgItem( m_hwnd, IDC_LIMIT ))) { - TCHAR temp[15]; - GetDlgItemText( m_hwnd, IDC_LIMIT, temp, SIZEOF(temp)); - if ( wi->pszLimit && lstrcmpi( wi->pszLimit, temp )) { - lstrcat( toadd, _T("l")); - appendixadd += _T(" ") + CMString(temp); - } } - } - else if ( m_check6.GetState() && GetWindowTextLength( m_limit.GetHwnd())) { - lstrcat( toadd, _T("l")); - appendixadd += _T(" "); - - TCHAR temp[15]; - m_limit.GetText( temp, SIZEOF(temp)); - appendixadd += temp; - } - - if ( lstrlen(toadd) || lstrlen( toremove )) { - TCHAR temp[500]; - lstrcpy(temp, _T("/mode ")); - lstrcat(temp, window); - lstrcat(temp, _T(" ")); - if ( lstrlen( toremove )) - mir_sntprintf( temp, 499, _T("%s-%s"), temp, toremove ); - if ( lstrlen( toadd )) - mir_sntprintf( temp, 499, _T("%s+%s"), temp, toadd ); - if (!appendixremove.IsEmpty()) - lstrcat(temp, appendixremove.c_str()); - if (!appendixadd.IsEmpty()) - lstrcat(temp, appendixadd.c_str()); - m_proto->PostIrcMessage( temp); - } } - - m_applyModes.Disable(); -} - -void CManagerDlg::OnApplyTopic( CCtrlButton* ) -{ - TCHAR temp[470]; - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); - m_topic.GetText( temp, SIZEOF(temp)); - m_proto->PostIrcMessage( _T("/TOPIC %s %s"), window, temp); - int i = m_topic.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM)temp); - if ( i != LB_ERR ) - m_topic.SendMsg( CB_DELETESTRING, i, 0); - m_topic.SendMsg( CB_INSERTSTRING, 0, (LPARAM)temp); - m_topic.SetText( temp ); - m_applyTopic.Disable(); -} - -void CManagerDlg::OnCheck( CCtrlData* ) -{ - m_applyModes.Enable(); -} - -void CManagerDlg::OnCheck5( CCtrlData* ) -{ - m_key.Enable( m_check5.GetState()); - m_applyModes.Enable(); -} - -void CManagerDlg::OnCheck6( CCtrlData* ) -{ - m_limit.Enable( m_check6.GetState()); - m_applyModes.Enable(); -} - -void CManagerDlg::OnRadio( CCtrlData* ) -{ - ApplyQuestion(); -} - -void CManagerDlg::ApplyQuestion() -{ - TCHAR window[256]; - GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255); - - TCHAR mode[3]; - lstrcpy( mode, _T("+b")); - if ( m_radio2.GetState()) - lstrcpy( mode, _T("+I")); - if ( m_radio3.GetState()) - lstrcpy( mode, _T("+e")); - m_list.ResetContent(); - m_radio1.Disable(); - m_radio2.Disable(); - m_radio3.Disable(); - m_add.Disable(); - m_edit.Disable(); - m_remove.Disable(); - m_proto->PostIrcMessage( _T("%s %s %s"), _T("/MODE"), window, mode); //wrong overloaded operator if three args -} - -void CManagerDlg::CloseQuestion() -{ - m_add.Enable(); - if ( m_list.GetCurSel() != LB_ERR) { - m_edit.Enable(); - m_remove.Enable(); -} } - -void CManagerDlg::InitManager( int mode, const TCHAR* window ) -{ - SetWindowText( GetDlgItem( m_hwnd, IDC_CAPTION ), window ); - - CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); - if ( wi ) { - if ( m_proto->IsConnected()) { - TCHAR temp[1000]; - mir_sntprintf(temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); - - char* p = mir_t2a(temp); - - DBVARIANT dbv; - if ( !m_proto->getTString( p, &dbv )) { - for ( int i = 0; i<5; i++ ) { - CMString S = GetWord(dbv.ptszVal, i); - if ( !S.IsEmpty()) { -/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ -#if !defined(__GNUC__) || !defined(UNICODE) - ReplaceString( S, _T("%¤"), _T(" ")); -#endif - m_topic.SendMsg( CB_ADDSTRING, 0, (LPARAM)S.c_str()); - } } - DBFreeVariant(&dbv); - } - mir_free(p); - } - - if ( wi->pszTopic ) - m_topic.SetText( wi->pszTopic ); - - if ( !IsDlgButtonChecked( m_proto->m_managerDlg->GetHwnd(), IDC_NOTOP )) - m_add.Enable(); - - bool add = false; - TCHAR* p1= wi->pszMode; - if ( p1 ) { - while ( *p1 != '\0' && *p1 != ' ' ) { - if (*p1 == '+') - add = true; - if (*p1 == '-') - add = false; - if (*p1 == 't') - m_check1.SetState( add ); - if (*p1 == 'n') - m_check2.SetState( add ); - if (*p1 == 'i') - m_check3.SetState( add ); - if (*p1 == 'm') - m_check4.SetState( add ); - if (*p1 == 'p') - m_check7.SetState( add ); - if (*p1 == 's') - m_check8.SetState( add ); - if (*p1 == 'c') - m_check9.SetState( add ); - if (*p1 == 'k' && add) { - m_check5.SetState( add ); - m_key.Enable( add ); - if ( wi->pszPassword ) - m_key.SetText( wi->pszPassword ); - } - if (*p1 == 'l' && add) { - m_check6.SetState( add ); - m_limit.Enable( add ); - if ( wi->pszLimit ) - m_limit.SetText( wi->pszLimit ); - } - p1++; - if ( mode == 0 ) { - m_limit.Disable(); - m_key.Disable(); - m_check1.Disable(); - m_check2.Disable(); - m_check3.Disable(); - m_check4.Disable(); - m_check5.Disable(); - m_check6.Disable(); - m_check7.Disable(); - m_check8.Disable(); - m_check9.Disable(); - m_add.Disable(); - if ( m_check1.GetState()) - m_topic.Disable(); - CheckDlgButton( m_hwnd, IDC_NOTOP, BST_CHECKED); - } - ShowWindow( m_hwnd, SW_SHOW ); - } } } - - if ( strchr( m_proto->sChannelModes.c_str(), 'b' )) { - m_radio1.SetState( true ); - m_proto->PostIrcMessage( _T("/MODE %s +b"), window); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// 'cool' dialog - -CCoolIrcDlg::CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent ) : - CProtoDlgBase( _pro, dlgId, parent ) -{ -} - -void CCoolIrcDlg::OnInitDialog() -{ - HFONT hFont; - LOGFONT lf; - hFont=(HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); - GetObject(hFont,sizeof(lf),&lf); - lf.lfHeight=(int)(lf.lfHeight*1.2); - lf.lfWeight=FW_BOLD; - hFont=CreateFontIndirect(&lf); - SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,(WPARAM)hFont,0); - - SendDlgItemMessage( m_hwnd, IDC_LOGO, STM_SETICON,(LPARAM)(HICON)LoadIconEx(IDI_LOGO), 0); -} - -void CCoolIrcDlg::OnDestroy() -{ - HFONT hFont = (HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); - SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); - DeleteObject(hFont); - - ReleaseIconEx((HICON)SendDlgItemMessage(m_hwnd, IDC_LOGO, STM_SETICON, 0, 0)); - WindowFreeIcon(m_hwnd); -} - -INT_PTR CCoolIrcDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if ( msg == WM_CTLCOLOREDIT || msg == WM_CTLCOLORSTATIC ) { - switch( GetDlgCtrlID(( HWND )lParam )) { - case IDC_WHITERECT: case IDC_TEXT: case IDC_CAPTION: case IDC_AWAYTIME: case IDC_LOGO: - SetTextColor((HDC)wParam,RGB(0,0,0)); - SetBkColor((HDC)wParam,RGB(255,255,255)); - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } } - - return CDlgBase::DlgProc(msg, wParam, lParam); -} diff --git a/protocols/IcqOscarJ/UI/askauthentication.cpp b/protocols/IcqOscarJ/UI/askauthentication.cpp deleted file mode 100644 index 818d5ce6de..0000000000 --- a/protocols/IcqOscarJ/UI/askauthentication.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -struct AskAuthParam -{ - CIcqProto* ppro; - HANDLE hContact; -}; - -static INT_PTR CALLBACK AskAuthProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - AskAuthParam* dat = (AskAuthParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch (msg) { - case WM_INITDIALOG: - dat = (AskAuthParam*)lParam; - if (!dat->hContact || !dat->ppro->icqOnline()) - EndDialog(hwndDlg, 0); - - TranslateDialogDefault(hwndDlg); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - SendDlgItemMessage(hwndDlg, IDC_EDITAUTH, EM_LIMITTEXT, (WPARAM)255, 0); - SetDlgItemText(hwndDlg, IDC_EDITAUTH, TranslateT("Please authorize me to add you to my contact list.")); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - if (dat->ppro->icqOnline()) - { - DWORD dwUin; - uid_str szUid; - if ( dat->ppro->getContactUid(dat->hContact, &dwUin, &szUid)) - return TRUE; // Invalid contact - - char* szReason = GetDlgItemTextUtf(hwndDlg, IDC_EDITAUTH); - dat->ppro->icq_sendAuthReqServ(dwUin, szUid, szReason); - SAFE_FREE((void**)&szReason); - - // auth bug fix (thx Bio) - if (dat->ppro->m_bSsiEnabled && dwUin) - dat->ppro->resetServContactAuthState(dat->hContact, dwUin); - - EndDialog(hwndDlg, 0); - } - return TRUE; - - case IDCANCEL: - EndDialog(hwndDlg, 0); - return TRUE; - } - - break; - - case WM_CLOSE: - EndDialog(hwndDlg,0); - return TRUE; - } - - return FALSE; -} - -INT_PTR CIcqProto::RequestAuthorization(WPARAM wParam, LPARAM lParam) -{ - AskAuthParam param = { this, (HANDLE)wParam }; - DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ASKAUTH), NULL, AskAuthProc, (LPARAM)¶m); - return 0; -} diff --git a/protocols/IcqOscarJ/UI/icqoscar.h b/protocols/IcqOscarJ/UI/icqoscar.h deleted file mode 100644 index 77283f6f7f..0000000000 --- a/protocols/IcqOscarJ/UI/icqoscar.h +++ /dev/null @@ -1,2 +0,0 @@ -/* For MinGW sake */ -#include "../icqoscar.h" diff --git a/protocols/IcqOscarJ/UI/loginpassword.cpp b/protocols/IcqOscarJ/UI/loginpassword.cpp deleted file mode 100644 index ab65212331..0000000000 --- a/protocols/IcqOscarJ/UI/loginpassword.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -INT_PTR CALLBACK LoginPasswdDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - { - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ppro->m_hIconProtocol->GetIcon(true)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ppro->m_hIconProtocol->GetIcon()); - - DWORD dwUin = ppro->getContactUin(NULL); - - char pszUIN[MAX_PATH], str[MAX_PATH]; - null_snprintf(pszUIN, 128, ICQTranslateUtfStatic(LPGEN("Enter a password for UIN %u:"), str, MAX_PATH), dwUin); - SetDlgItemTextUtf(hwndDlg, IDC_INSTRUCTION, pszUIN); - - SendDlgItemMessage(hwndDlg, IDC_LOGINPW, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); - - CheckDlgButton(hwndDlg, IDC_SAVEPASS, ppro->getSettingByte(NULL, "RememberPass", 0)); - } - break; - - case WM_DESTROY: - ppro->m_hIconProtocol->ReleaseIcon(true); - ppro->m_hIconProtocol->ReleaseIcon(); - break; - - case WM_CLOSE: - EndDialog(hwndDlg, 0); - break; - - case WM_COMMAND: - { - switch (LOWORD(wParam)) { - case IDOK: - ppro->m_bRememberPwd = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SAVEPASS); - ppro->setSettingByte(NULL, "RememberPass", ppro->m_bRememberPwd); - - GetDlgItemTextA(hwndDlg, IDC_LOGINPW, ppro->m_szPassword, sizeof(ppro->m_szPassword)); - - ppro->icq_login(ppro->m_szPassword); - - EndDialog(hwndDlg, IDOK); - break; - - case IDCANCEL: - ppro->SetCurrentStatus(ID_STATUS_OFFLINE); - EndDialog(hwndDlg, IDCANCEL); - break; - } - } - break; - } - - return FALSE; -} - -void CIcqProto::RequestPassword() -{ - DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_LOGINPW), NULL, LoginPasswdDlgProc, LPARAM(this)); -} diff --git a/protocols/IcqOscarJ/UI/userinfotab.cpp b/protocols/IcqOscarJ/UI/userinfotab.cpp deleted file mode 100644 index 91d28c0e04..0000000000 --- a/protocols/IcqOscarJ/UI/userinfotab.cpp +++ /dev/null @@ -1,315 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Code for User details ICQ specific pages -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -#define SVS_NORMAL 0 -#define SVS_ZEROISUNSPEC 2 -#define SVS_IP 3 -#define SVS_SIGNED 6 -#define SVS_ICQVERSION 8 -#define SVS_TIMESTAMP 9 -#define SVS_STATUSID 10 - -char* MirandaVersionToString(char* szStr, int bUnicode, int v, int m); - -extern const char *nameXStatus[]; - - -///////////////////////////////////////////////////////////////////////////////////////// - -static void SetValue(CIcqProto* ppro, HWND hwndDlg, int idCtrl, HANDLE hContact, char* szModule, char* szSetting, int special) -{ - DBVARIANT dbv = {0}; - char str[MAX_PATH]; - char* pstr = NULL; - int unspecified = 0; - int bUtf = 0, bDbv = 0, bAlloc = 0; - - dbv.type = DBVT_DELETED; - - if ((hContact == NULL) && ((int)szModule<0x100)) - { - dbv.type = (BYTE)szModule; - - switch((int)szModule) { - case DBVT_BYTE: - dbv.cVal = (BYTE)szSetting; - break; - case DBVT_WORD: - dbv.wVal = (WORD)szSetting; - break; - case DBVT_DWORD: - dbv.dVal = (DWORD)szSetting; - break; - case DBVT_ASCIIZ: - dbv.pszVal = pstr = szSetting; - break; - default: - unspecified = 1; - dbv.type = DBVT_DELETED; - } - } - else - { - if (szModule == NULL) - unspecified = 1; - else - { - unspecified = DBGetContactSetting(hContact, szModule, szSetting, &dbv); - bDbv = 1; - } - } - - if (!unspecified) - { - switch (dbv.type) { - case DBVT_BYTE: - unspecified = (special == SVS_ZEROISUNSPEC && dbv.bVal == 0); - pstr = _itoa(special == SVS_SIGNED ? dbv.cVal:dbv.bVal, str, 10); - break; - - case DBVT_WORD: - if (special == SVS_ICQVERSION) - { - if (dbv.wVal != 0) - { - char szExtra[80]; - - null_snprintf(str, 250, "%d", dbv.wVal); - pstr = str; - - if (hContact && ppro->IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 1)) - { - ICQTranslateUtfStatic(LPGEN(" (DC Established)"), szExtra, 80); - strcat(str, (char*)szExtra); - bUtf = 1; - } - } - else - unspecified = 1; - } - else if (special == SVS_STATUSID) - { - char *pXName; - char *pszStatus = MirandaStatusToStringUtf(dbv.wVal); - BYTE bXStatus = ppro->getContactXStatus(hContact); - - if (bXStatus) - { - pXName = ppro->getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); - if (!strlennull(pXName)) - { // give default name - pXName = ICQTranslateUtf(nameXStatus[bXStatus-1]); - } - null_snprintf(str, sizeof(str), "%s (%s)", pszStatus, pXName); - SAFE_FREE((void**)&pXName); - } - else - null_snprintf(str, sizeof(str), pszStatus); - - bUtf = 1; - SAFE_FREE(&pszStatus); - pstr = str; - unspecified = 0; - } - else - { - unspecified = (special == SVS_ZEROISUNSPEC && dbv.wVal == 0); - pstr = _itoa(special == SVS_SIGNED ? dbv.sVal:dbv.wVal, str, 10); - } - break; - - case DBVT_DWORD: - unspecified = (special == SVS_ZEROISUNSPEC && dbv.dVal == 0); - if (special == SVS_IP) - { - struct in_addr ia; - ia.S_un.S_addr = htonl(dbv.dVal); - pstr = inet_ntoa(ia); - if (dbv.dVal == 0) - unspecified=1; - } - else if (special == SVS_TIMESTAMP) - { - if (dbv.dVal == 0) - unspecified = 1; - else - pstr = time2text(dbv.dVal); - } - else - pstr = _itoa(special == SVS_SIGNED ? dbv.lVal:dbv.dVal, str, 10); - break; - - case DBVT_ASCIIZ: - case DBVT_WCHAR: - unspecified = (special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); - if (!unspecified && pstr != szSetting) - { - pstr = ppro->getSettingStringUtf(hContact, szModule, szSetting, NULL); - bUtf = 1; - bAlloc = 1; - } - if (idCtrl == IDC_UIN) - SetDlgItemTextUtf(hwndDlg, IDC_UINSTATIC, ICQTranslateUtfStatic(LPGEN("ScreenName:"), str, MAX_PATH)); - break; - - default: - pstr = str; - strcpy(str,"???"); - break; - } - } - - EnableDlgItem(hwndDlg, idCtrl, !unspecified); - if (unspecified) - SetDlgItemTextUtf(hwndDlg, idCtrl, ICQTranslateUtfStatic(LPGEN(""), str, MAX_PATH)); - else if (bUtf) - SetDlgItemTextUtf(hwndDlg, idCtrl, pstr); - else - SetDlgItemTextA(hwndDlg, idCtrl, pstr); - - if (bDbv) - ICQFreeVariant(&dbv); - - if (bAlloc) - SAFE_FREE(&pstr); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static INT_PTR CALLBACK IcqDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->idFrom) { - case 0: - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (( PSHNOTIFY* )lParam )->lParam ); - break; - - case PSN_INFOCHANGED: - { - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - if (!ppro) - break; - - char* szProto; - HANDLE hContact = (HANDLE)((LPPSHNOTIFY)lParam)->lParam; - - if (hContact == NULL) - szProto = ppro->m_szModuleName; - else - szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - - if (!szProto) - break; - - SetValue(ppro, hwndDlg, IDC_UIN, hContact, szProto, UNIQUEIDSETTING, SVS_NORMAL); - SetValue(ppro, hwndDlg, IDC_ONLINESINCE, hContact, szProto, "LogonTS", SVS_TIMESTAMP); - SetValue(ppro, hwndDlg, IDC_IDLETIME, hContact, szProto, "IdleTS", SVS_TIMESTAMP); - SetValue(ppro, hwndDlg, IDC_IP, hContact, szProto, "IP", SVS_IP); - SetValue(ppro, hwndDlg, IDC_REALIP, hContact, szProto, "RealIP", SVS_IP); - - if (hContact) - { - SetValue(ppro, hwndDlg, IDC_PORT, hContact, szProto, "UserPort", SVS_ZEROISUNSPEC); - SetValue(ppro, hwndDlg, IDC_VERSION, hContact, szProto, "Version", SVS_ICQVERSION); - SetValue(ppro, hwndDlg, IDC_MIRVER, hContact, szProto, "MirVer", SVS_ZEROISUNSPEC); - if (ppro->getSettingByte(hContact, "ClientID", 0)) - ppro->setSettingDword(hContact, "TickTS", 0); - SetValue(ppro, hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "TickTS", SVS_TIMESTAMP); - SetValue(ppro, hwndDlg, IDC_STATUS, hContact, szProto, "Status", SVS_STATUSID); - } - else - { - char str[MAX_PATH]; - - SetValue(ppro, hwndDlg, IDC_PORT, hContact, (char*)DBVT_WORD, (char*)ppro->wListenPort, SVS_ZEROISUNSPEC); - SetValue(ppro, hwndDlg, IDC_VERSION, hContact, (char*)DBVT_WORD, (char*)ICQ_VERSION, SVS_ICQVERSION); - SetValue(ppro, hwndDlg, IDC_MIRVER, hContact, (char*)DBVT_ASCIIZ, MirandaVersionToString(str, TRUE, ICQ_PLUG_VERSION, CallService(MS_SYSTEM_GETVERSION,0,0)), SVS_ZEROISUNSPEC); - SetDlgItemTextUtf(hwndDlg, IDC_SUPTIME, ICQTranslateUtfStatic(LPGEN("Member since:"), str, MAX_PATH)); - SetValue(ppro, hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "MemberTS", SVS_TIMESTAMP); - SetValue(ppro, hwndDlg, IDC_STATUS, hContact, (char*)DBVT_WORD, (char*)ppro->m_iStatus, SVS_STATUSID); - } - } - break; - } - break; - } - break; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - SendMessage(GetParent(hwndDlg),msg,wParam,lParam); - break; - } - break; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CIcqProto::OnUserInfoInit(WPARAM wParam, LPARAM lParam) -{ - if ((!IsICQContact((HANDLE)lParam)) && lParam) - return 0; - - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.flags = ODPF_TCHAR | ODPF_DONTTRANSLATE; - odp.hInstance = hInst; - odp.dwInitParam = LPARAM(this); - odp.pfnDlgProc = IcqDlgProc; - odp.position = -1900000000; - odp.ptszTitle = m_tszUserName; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_ICQ); - UserInfo_AddPage(wParam, &odp); - - if (!lParam) - { - TCHAR buf[200]; - null_snprintf(buf, SIZEOF(buf), TranslateT("%s Details"), m_tszUserName); - odp.ptszTitle = buf; - - odp.position = -1899999999; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_CHANGEINFO); - odp.pfnDlgProc = ChangeInfoDlgProc; - UserInfo_AddPage(wParam, &odp); - } - return 0; -} diff --git a/protocols/IcqOscarJ/capabilities.cpp b/protocols/IcqOscarJ/capabilities.cpp deleted file mode 100644 index f994f861af..0000000000 --- a/protocols/IcqOscarJ/capabilities.cpp +++ /dev/null @@ -1,271 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Contains helper functions to handle oscar user capabilities. Scanning and -// adding capabilities are assumed to be more timecritical than looking up -// capabilites. During the login sequence there could possibly be many hundred -// scans but only a few lookups. So when you add or change something in this -// code you must have this in mind, dont do anything that will slow down the -// adding process too much. -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -struct icq_capability -{ - DWORD capID; // A bitmask, we use it in order to save database space - capstr capCLSID; // A binary representation of a oscar capability -}; - -static const icq_capability CapabilityRecord[] = -{ - {CAPF_SRV_RELAY, {CAP_SRV_RELAY }}, - {CAPF_UTF, {CAP_UTF }}, - {CAPF_RTF, {CAP_RTF }}, - {CAPF_CONTACTS, {CAP_CONTACTS }}, - {CAPF_TYPING, {CAP_TYPING }}, - {CAPF_ICQDIRECT, {CAP_ICQDIRECT }}, - {CAPF_XTRAZ, {CAP_XTRAZ }}, - {CAPF_OSCAR_FILE,{CAP_OSCAR_FILE}} -}; - -// Mask of all handled capabilities' flags -#define CapabilityFlagsMask (CAPF_SRV_RELAY | CAPF_UTF | CAPF_RTF | CAPF_CONTACTS | CAPF_TYPING | CAPF_ICQDIRECT | CAPF_XTRAZ | CAPF_OSCAR_FILE) - - -#ifdef _DEBUG -struct icq_capability_name -{ - DWORD capID; - const char* capName; -}; - -static const icq_capability_name CapabilityNames[] = -{ - {CAPF_SRV_RELAY, "ServerRelay"}, - {CAPF_UTF, "UTF8 Messages"}, - {CAPF_RTF, "RTF Messages"}, - {CAPF_CONTACTS, "Contact Transfer"}, - {CAPF_TYPING, "Typing Notifications"}, - {CAPF_ICQDIRECT, "Direct Connections"}, - {CAPF_XTRAZ, "Xtraz"}, - {CAPF_OSCAR_FILE, "File Transfers"}, - {CAPF_STATUS_MESSAGES,"Individual Status Messages"}, - {CAPF_STATUS_MOOD, "Mood"}, - {CAPF_XSTATUS, "Custom Status"} -}; - -void NetLog_CapabilityChange(CIcqProto *ppro, const char *szChange, DWORD fdwCapabilities) -{ - char szBuffer[MAX_PATH] = {0}; - - if (!fdwCapabilities) return; - - for (int nIndex = 0; nIndex < SIZEOF(CapabilityNames); nIndex++) - { - // Check if the current capability is present - if ((fdwCapabilities & CapabilityNames[nIndex].capID) == CapabilityNames[nIndex].capID) - { - if (strlennull(szBuffer)) - strcat(szBuffer, ", "); - strcat(szBuffer, CapabilityNames[nIndex].capName); - } - } - // Log the change - ppro->NetLog_Server("Capabilities: %s %s", szChange, szBuffer); -} -#endif - - -// Deletes all oscar capabilities for a given contact -void CIcqProto::ClearAllContactCapabilities(HANDLE hContact) -{ - setSettingDword(hContact, DBSETTING_CAPABILITIES, 0); -} - - -// Deletes one or many oscar capabilities for a given contact -void CIcqProto::ClearContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) -{ - // Get current capability flags - DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); - - if (fdwContactCaps != (fdwContactCaps & ~fdwCapabilities)) - { -#ifdef _DEBUG - NetLog_CapabilityChange(this, "Removed", fdwCapabilities & fdwContactCaps); -#endif - // Clear unwanted capabilities - fdwContactCaps &= ~fdwCapabilities; - - // And write it back to disk - setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); - } -} - - -// Sets one or many oscar capabilities for a given contact -void CIcqProto::SetContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) -{ - // Get current capability flags - DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); - - if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) - { -#ifdef _DEBUG - NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); -#endif - // Update them - fdwContactCaps |= fdwCapabilities; - - // And write it back to disk - setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); - } -} - - -// Returns true if the given contact supports the requested capabilites -BOOL CIcqProto::CheckContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) -{ - // Get current capability flags - DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); - - // Check if all requested capabilities are supported - if ((fdwContactCaps & fdwCapabilities) == fdwCapabilities) - return TRUE; - - return FALSE; -} - - -// Scan capability against the capability buffer -capstr* MatchCapability(BYTE *buf, int bufsize, const capstr *cap, int capsize) -{ - while (bufsize >= BINARY_CAP_SIZE) // search the buffer for a capability - { - if (!memcmp(buf, cap, capsize)) - { - return (capstr*)buf; // give found capability for version info - } - else - { - buf += BINARY_CAP_SIZE; - bufsize -= BINARY_CAP_SIZE; - } - } - return 0; -} - - -// Scan short capability against the capability buffer -capstr* MatchShortCapability(BYTE *buf, int bufsize, const shortcapstr *cap) -{ - capstr fullCap; - - memcpy(fullCap, capShortCaps, BINARY_CAP_SIZE); - fullCap[2] = (*cap)[0]; - fullCap[3] = (*cap)[1]; - - return MatchCapability(buf, bufsize, &fullCap, BINARY_CAP_SIZE); -} - - -// Scans a binary buffer for OSCAR capabilities. -DWORD GetCapabilitiesFromBuffer(BYTE *pBuffer, int nLength) -{ - DWORD fdwCaps = 0; - - // Calculate the number of records - int nRecordSize = SIZEOF(CapabilityRecord); - - // Loop over all capabilities in the buffer and - // compare them to our own record of capabilities - for (int nIndex = 0; nIndex < nRecordSize; nIndex++) - { - if (MatchCapability(pBuffer, nLength, &CapabilityRecord[nIndex].capCLSID, BINARY_CAP_SIZE)) - { // Match, add capability flag - fdwCaps |= CapabilityRecord[nIndex].capID; - } - } - - return fdwCaps; -} - - -// Scans a binary buffer for oscar capabilities and adds them to the contact. -// You probably want to call ClearAllContactCapabilities() first. -void CIcqProto::AddCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength) -{ - // Get current capability flags - DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); - // Get capability flags from buffer - DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength); - - if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) - { -#ifdef _DEBUG - NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); -#endif - // Add capability flags from buffer - fdwContactCaps |= fdwCapabilities; - - // And write them back to database - setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); - } -} - - -// Scans a binary buffer for oscar capabilities and adds them to the contact. -// You probably want to call ClearAllContactCapabilities() first. -void CIcqProto::SetCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength, BOOL bReset) -{ - // Get current capability flags - DWORD fdwContactCaps = bReset ? 0 : getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); - // Get capability flags from buffer - DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength); - -#ifdef _DEBUG - if (bReset) - NetLog_CapabilityChange(this, "Set", fdwCapabilities); - else - { - NetLog_CapabilityChange(this, "Removed", fdwContactCaps & ~fdwCapabilities & CapabilityFlagsMask); - NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); - } -#endif - - if (fdwCapabilities != (fdwContactCaps & ~CapabilityFlagsMask)) - { // Get current unmanaged capability flags - fdwContactCaps &= ~CapabilityFlagsMask; - - // Add capability flags from buffer - fdwContactCaps |= fdwCapabilities; - - // And write them back to database - setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); - } -} diff --git a/protocols/IcqOscarJ/capabilities.h b/protocols/IcqOscarJ/capabilities.h deleted file mode 100644 index 3b6590dd09..0000000000 --- a/protocols/IcqOscarJ/capabilities.h +++ /dev/null @@ -1,45 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Contains helper functions to handle OSCAR user capabilities. -// -// ----------------------------------------------------------------------------- - -#ifndef __CAPABILITIES_H -#define __CAPABILITIES_H - - -// capabilities -typedef BYTE capstr[BINARY_CAP_SIZE]; -typedef BYTE shortcapstr[BINARY_SHORT_CAP_SIZE]; - -extern const capstr capShortCaps; - -capstr* MatchCapability(BYTE *buf, int bufsize, const capstr *cap, int capsize = BINARY_CAP_SIZE); -capstr* MatchShortCapability(BYTE *buf, int bufsize, const shortcapstr *cap); - - -#endif /* __CAPABILITIES_H */ diff --git a/protocols/IcqOscarJ/chan_01login.cpp b/protocols/IcqOscarJ/chan_01login.cpp deleted file mode 100644 index 3c4c4febc6..0000000000 --- a/protocols/IcqOscarJ/chan_01login.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleLoginChannel(BYTE *buf, WORD datalen, serverthread_info *info) -{ - icq_packet packet; - -#ifdef _DEBUG - NetLog_Server("Received SRV_HELLO from %s", info->isLoginServer ? "login server" : "communication server"); -#endif - - // isLoginServer is "1" if we just received SRV_HELLO - if (info->isLoginServer) - { - if (m_bSecureLogin) - { - char szUin[UINMAXLEN]; - WORD wUinLen; - -#ifdef _DEBUG - NetLog_Server("Sending %s to %s", "CLI_HELLO", "login server"); -#endif - packet.wLen = 12; - write_flap(&packet, ICQ_LOGIN_CHAN); - packDWord(&packet, 0x00000001); - packTLVDWord(&packet, 0x8003, 0x00100000); // unknown - sendServPacket(&packet); // greet login server - - wUinLen = strlennull(strUID(m_dwLocalUIN, szUin)); -#ifdef _DEBUG - NetLog_Server("Sending %s to %s", "ICQ_SIGNON_AUTH_REQUEST", "login server"); -#endif - - serverPacketInit(&packet, (WORD)(14 + wUinLen)); - packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_AUTH_REQUEST, 0, 0); - packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin); - sendServPacket(&packet); // request login digest - } - else - { - sendClientAuth((char*)info->szAuthKey, info->wAuthKeyLen, FALSE); -#ifdef _DEBUG - NetLog_Server("Sent CLI_IDENT to %s", "login server"); -#endif - } - - info->isLoginServer = 0; - if (info->cookieDataLen) - { - SAFE_FREE((void**)&info->cookieData); - info->cookieDataLen = 0; - } - } - else - { - if (info->cookieDataLen) - { - wLocalSequence = generate_flap_sequence(); - - serverCookieInit(&packet, info->cookieData, (WORD)info->cookieDataLen); - sendServPacket(&packet); - -#ifdef _DEBUG - NetLog_Server("Sent CLI_IDENT to %s", "communication server"); -#endif - - SAFE_FREE((void**)&info->cookieData); - info->cookieDataLen = 0; - } - else - { - // We need a cookie to identify us to the communication server - NetLog_Server("Error: Connected to %s without a cookie!", "communication server"); - } - } -} diff --git a/protocols/IcqOscarJ/chan_02data.cpp b/protocols/IcqOscarJ/chan_02data.cpp deleted file mode 100644 index d55e0262e9..0000000000 --- a/protocols/IcqOscarJ/chan_02data.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handle channel 2 (Data) packets -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleDataChannel(BYTE *pBuffer, WORD wBufferLength, serverthread_info *info) -{ - snac_header snacHeader = {0}; - - if (!unpackSnacHeader(&snacHeader, &pBuffer, &wBufferLength) || !snacHeader.bValid) - { - NetLog_Server("Error: Failed to parse SNAC header"); - } - else - { -#ifdef _DEBUG - if (snacHeader.wFlags & 0x8000) - NetLog_Server(" Received SNAC(x%02X,x%02X), version %u", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wVersion); - else - NetLog_Server(" Received SNAC(x%02X,x%02X)", snacHeader.wFamily, snacHeader.wSubtype); -#endif - - switch (snacHeader.wFamily) { - - case ICQ_SERVICE_FAMILY: - handleServiceFam(pBuffer, wBufferLength, &snacHeader, info); - break; - - case ICQ_LOCATION_FAMILY: - handleLocationFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_BUDDY_FAMILY: - handleBuddyFam(pBuffer, wBufferLength, &snacHeader, info); - break; - - case ICQ_MSG_FAMILY: - handleMsgFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_BOS_FAMILY: - handleBosFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_LOOKUP_FAMILY: - handleLookupFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_STATS_FAMILY: - handleStatusFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_LISTS_FAMILY: - handleServCListFam(pBuffer, wBufferLength, &snacHeader, info); - break; - - case ICQ_EXTENSIONS_FAMILY: - handleIcqExtensionsFam(pBuffer, wBufferLength, &snacHeader); - break; - - case ICQ_AUTHORIZATION_FAMILY: - handleAuthorizationFam(pBuffer, wBufferLength, &snacHeader, info); - break; - - default: - NetLog_Server("Ignoring SNAC(x%02X,x%02X) - FAMILYx%02X not implemented", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wFamily); - break; - - } - } -} - - -int unpackSnacHeader(snac_header *pSnacHeader, BYTE **pBuffer, WORD *pwBufferLength) -{ - WORD wRef1, wRef2; - - // Check header - if (!pSnacHeader) return 0; - - // 10 bytes is the minimum size of a header - if (*pwBufferLength < 10) - { - // Buffer overflow - pSnacHeader->bValid = FALSE; - return 1; - } - - // Unpack all the standard data - unpackWord(pBuffer, &(pSnacHeader->wFamily)); - unpackWord(pBuffer, &(pSnacHeader->wSubtype)); - unpackWord(pBuffer, &(pSnacHeader->wFlags)); - unpackWord(pBuffer, &wRef1); // unpack reference id (sequence) - unpackWord(pBuffer, &wRef2); // command - pSnacHeader->dwRef = wRef1 | (wRef2<<0x10); - - *pwBufferLength -= 10; - - // If flag bit 15 is set, we also have a version tag - // (...at least that is what I think it is) - if (pSnacHeader->wFlags & 0x8000) - { - if (*pwBufferLength >= 2) - { - WORD wExtraBytes = 0; - - unpackWord(pBuffer, &wExtraBytes); - *pwBufferLength -= 2; - - if (*pwBufferLength >= wExtraBytes) - { - if (wExtraBytes == 6) - { - *pBuffer += 4; // TLV type and length? - unpackWord(pBuffer, &(pSnacHeader->wVersion)); - *pwBufferLength -= wExtraBytes; - pSnacHeader->bValid = TRUE; - } - else if (wExtraBytes == 0x0E) - { - *pBuffer += 8; // TLV(2) - unknown - *pBuffer += 4; - unpackWord(pBuffer, &(pSnacHeader->wVersion)); - *pwBufferLength -= wExtraBytes; - pSnacHeader->bValid = TRUE; - } - else - { - *pBuffer += wExtraBytes; - *pwBufferLength -= wExtraBytes; - pSnacHeader->bValid = TRUE; - } - } - else - { - // Buffer overflow - pSnacHeader->bValid = FALSE; - } - } - else - { - // Buffer overflow - pSnacHeader->bValid = FALSE; - } - } - else - { - pSnacHeader->bValid = TRUE; - } - - return 1; -} - - -void CIcqProto::LogFamilyError(WORD wFamily, WORD wError) -{ - char *msg; - - switch(wError) { - case 0x01: msg = "Invalid SNAC header"; break; - case 0x02: msg = "Server rate limit exceeded"; break; - case 0x03: msg = "Client rate limit exceeded"; break; - case 0x04: msg = "Recipient is not logged in"; break; - case 0x05: msg = "Requested service unavailable"; break; - case 0x06: msg = "Requested service not defined"; break; - case 0x07: msg = "You sent obsolete SNAC"; break; - case 0x08: msg = "Not supported by server"; break; - case 0x09: msg = "Not supported by client"; break; - case 0x0A: msg = "Refused by client"; break; - case 0x0B: msg = "Reply too big"; break; - case 0x0C: msg = "Responses lost"; break; - case 0x0D: msg = "Request denied"; break; - case 0x0E: msg = "Incorrect SNAC format"; break; - case 0x0F: msg = "Insufficient rights"; break; - case 0x10: msg = "In local permit/deny (recipient blocked)"; break; - case 0x11: msg = "Sender is too evil"; break; - case 0x12: msg = "Receiver is too evil"; break; - case 0x13: msg = "User temporarily unavailable"; break; - case 0x14: msg = "No match"; break; - case 0x15: msg = "List overflow"; break; - case 0x16: msg = "Request ambiguous"; break; - case 0x17: msg = "Server queue full"; break; - case 0x18: msg = "Not while on AOL"; break; - case 0x19: msg = "Query failed"; break; - case 0x1A: msg = "Timeout"; break; - case 0x1C: msg = "General failure"; break; - case 0x1D: msg = "Progress"; break; - case 0x1E: msg = "In free area"; break; - case 0x1F: msg = "Restricted by parental controls"; break; - case 0x20: msg = "Remote restricted by parental controls"; break; - default: msg = ""; break; - } - - NetLog_Server("SNAC(x%02X,x01) - Error(%u): %s", wFamily, wError, msg); -} diff --git a/protocols/IcqOscarJ/chan_03error.cpp b/protocols/IcqOscarJ/chan_03error.cpp deleted file mode 100644 index 71c6e2ea7c..0000000000 --- a/protocols/IcqOscarJ/chan_03error.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004,2005 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleErrorChannel(unsigned char* buf, WORD datalen) -{ - NetLog_Server("Ignoring server packet on ERROR channel"); -} diff --git a/protocols/IcqOscarJ/chan_04close.cpp b/protocols/IcqOscarJ/chan_04close.cpp deleted file mode 100644 index 3c9ee46350..0000000000 --- a/protocols/IcqOscarJ/chan_04close.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleCloseChannel(BYTE *buf, WORD datalen, serverthread_info *info) -{ - oscar_tlv_chain *chain = NULL; - - // Parse server reply, prepare reconnection - if (!info->bLoggedIn && datalen && !info->newServerReady) - handleLoginReply(buf, datalen, info); - - if (info->isMigrating) - handleMigration(info); - - if ((!info->bLoggedIn || info->isMigrating) && info->newServerReady) - { - if (!connectNewServer(info)) - { // Connecting failed - if (info->isMigrating) - icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Unable to connect to migrated ICQ communication server")); - else - icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Unable to connect to ICQ communication server")); - - SetCurrentStatus(ID_STATUS_OFFLINE); - - info->isMigrating = 0; - } - info->newServerReady = 0; - - return; - } - - if (chain = readIntoTLVChain(&buf, datalen, 0)) - { - // TLV 9 errors (runtime errors?) - WORD wError = chain->getWord(0x09, 1); - if (wError) - { - SetCurrentStatus(ID_STATUS_OFFLINE); - - handleRuntimeError(wError); - } - - disposeChain(&chain); - } - // Server closed connection on error, or sign off - NetLib_CloseConnection(&hServerConn, TRUE); -} - - -void CIcqProto::handleLoginReply(BYTE *buf, WORD datalen, serverthread_info *info) -{ - oscar_tlv_chain *chain = NULL; - - icq_sendCloseConnection(); // imitate icq5 behaviour - - if (!(chain = readIntoTLVChain(&buf, datalen, 0))) - { - NetLog_Server("Error: Missing chain on close channel"); - NetLib_CloseConnection(&hServerConn, TRUE); - return; // Invalid data - } - - // TLV 8 errors (signon errors?) - WORD wError = chain->getWord(0x08, 1); - if (wError) - { - handleSignonError(wError); - - // we return only if the server did not gave us cookie (possible to connect with soft error) - if (!chain->getLength(0x06, 1)) - { - disposeChain(&chain); - SetCurrentStatus(ID_STATUS_OFFLINE); - icq_serverDisconnect(FALSE); - return; // Failure - } - } - - // We are in the login phase and no errors were reported. - // Extract communication server info. - info->newServer = chain->getString(0x05, 1); - info->newServerSSL = chain->getNumber(0x8E, 1); - info->cookieData = (BYTE*)chain->getString(0x06, 1); - info->cookieDataLen = chain->getLength(0x06, 1); - - // We dont need this anymore - disposeChain(&chain); - - if (!info->newServer || !info->cookieData) - { - icq_LogMessage(LOG_FATAL, LPGEN("You could not sign on because the server returned invalid data. Try again.")); - - SAFE_FREE(&info->newServer); - SAFE_FREE((void**)&info->cookieData); - info->cookieDataLen = 0; - - SetCurrentStatus(ID_STATUS_OFFLINE); - NetLib_CloseConnection(&hServerConn, TRUE); - return; // Failure - } - - NetLog_Server("Authenticated."); - info->newServerReady = 1; - - return; -} - - -int CIcqProto::connectNewServer(serverthread_info *info) -{ - int res = 0; - - /* Get the ip and port */ - WORD wServerPort = info->wServerPort; // prepare default port - parseServerAddress(info->newServer, &wServerPort); - - NETLIBOPENCONNECTION nloc = {0}; - nloc.flags = 0; - nloc.szHost = info->newServer; - nloc.wPort = wServerPort; - - if (!m_bGatewayMode) - { - NetLib_SafeCloseHandle(&info->hPacketRecver); - NetLib_CloseConnection(&hServerConn, TRUE); - - NetLog_Server("Closed connection to login server"); - - hServerConn = NetLib_OpenConnection(m_hServerNetlibUser, NULL, &nloc); - if (hServerConn && info->newServerSSL) - { /* Start SSL session if requested */ - if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hServerConn, 0)) - NetLib_CloseConnection(&hServerConn, FALSE); - } - - if (hServerConn) - { - /* Time to recreate the packet receiver */ - info->hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 0x2400); - if (!info->hPacketRecver) - { - NetLog_Server("Error: Failed to create packet receiver."); - } - else // we need to reset receiving structs - { - info->bReinitRecver = 1; - res = 1; - } - } - } - else - { // TODO: We should really do some checks here - NetLog_Server("Walking in Gateway to %s", info->newServer); - // TODO: This REQUIRES more work (most probably some kind of mid-netlib module) - icq_httpGatewayWalkTo(hServerConn, &nloc); - res = 1; - } - if (!res) SAFE_FREE((void**)&info->cookieData); - - // Free allocated memory - // NOTE: "cookie" will get freed when we have connected to the communication server. - SAFE_FREE(&info->newServer); - - return res; -} - - -void CIcqProto::handleMigration(serverthread_info *info) -{ - // Check the data that was saved when the migration was announced - NetLog_Server("Migrating to %s", info->newServer); - if (!info->newServer || !info->cookieData) - { - icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because the current server shut down.")); - - SAFE_FREE(&info->newServer); - SAFE_FREE((void**)&info->cookieData); - info->newServerReady = 0; - info->isMigrating = 0; - } -} - -void CIcqProto::handleSignonError(WORD wError) -{ - switch (wError) { - - case 0x01: // Unregistered uin - case 0x04: // Incorrect uin or password - case 0x05: // Mismatch uin or password - case 0x06: // Internal Client error (bad input to authorizer) - case 0x07: // Invalid account - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); - ZeroMemory(m_szPassword, sizeof(m_szPassword)); - icq_LogFatalParam(LPGEN("Connection failed.\nYour ICQ number or password was rejected (%d)."), wError); - break; - - case 0x02: // Service temporarily unavailable - case 0x0D: // Bad database status - case 0x10: // Service temporarily offline - case 0x12: // Database send error - case 0x14: // Reservation map error - case 0x15: // Reservation link error - case 0x1A: // Reservation timeout - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER); - icq_LogFatalParam(LPGEN("Connection failed.\nThe server is temporarily unavailable (%d)."), wError); - break; - - case 0x16: // The users num connected from this IP has reached the maximum - case 0x17: // The users num connected from this IP has reached the maximum (reserved) - icq_LogFatalParam(LPGEN("Connection failed.\nServer has too many connections from your IP (%d)."), wError); - break; - - case 0x18: // Reservation rate limit exceeded - case 0x1D: // Rate limit exceeded - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER); - icq_LogFatalParam(LPGEN("Connection failed.\nYou have connected too quickly,\nplease wait and retry 10 to 20 minutes later (%d)."), wError); - break; - - case 0x1B: // You are using an older version of ICQ. Upgrade required - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL); - icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nThe server did not accept this client version.")); - break; - - case 0x1C: // You are using an older version of ICQ. Upgrade recommended - icq_LogMessage(LOG_WARNING, LPGEN("The server sent warning, this version is getting old.\nTry to look for a new one.")); - break; - - case 0x1E: // Can't register on the ICQ network - icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nYou were rejected by the server for an unknown reason.\nThis can happen if the UIN is already connected.")); - break; - - case 0x0C: // Invalid database fields, MD5 login not supported - icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nSecure (MD5) login is not supported on this account.")); - break; - - case 0: // No error - break; - - case 0x08: // Deleted account - case 0x09: // Expired account - case 0x0A: // No access to database - case 0x0B: // No access to resolver - case 0x0E: // Bad resolver status - case 0x0F: // Internal error - case 0x11: // Suspended account - case 0x13: // Database link error - case 0x19: // User too heavily warned - case 0x1F: // Token server timeout - case 0x20: // Invalid SecureID number - case 0x21: // MC error - case 0x22: // Age restriction - case 0x23: // RequireRevalidation - case 0x24: // Link rule rejected - case 0x25: // Missing information or bad SNAC format - case 0x26: // Link broken - case 0x27: // Invalid client IP - case 0x28: // Partner rejected - case 0x29: // SecureID missing - case 0x2A: // Blocked account | Bump user - - default: - icq_LogFatalParam(LPGEN("Connection failed.\nUnknown error during sign on: 0x%02x"), wError); - break; - } -} - - -void CIcqProto::handleRuntimeError(WORD wError) -{ - switch (wError) - { - - case 0x01: - { - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION); - icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number.")); - break; - } - - default: - icq_LogFatalParam(LPGEN("Unknown runtime error: 0x%02x"), wError); - break; - } -} diff --git a/protocols/IcqOscarJ/chan_05ping.cpp b/protocols/IcqOscarJ/chan_05ping.cpp deleted file mode 100644 index 2a2b843509..0000000000 --- a/protocols/IcqOscarJ/chan_05ping.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handlePingChannel(BYTE *buf, WORD datalen) -{ - NetLog_Server("Warning: Ignoring server packet on PING channel"); -} - - -void __cdecl CIcqProto::KeepAliveThread(void *arg) -{ - serverthread_info *info = (serverthread_info*)arg; - icq_packet packet; - DWORD dwInterval = getSettingDword(NULL, "KeepAliveInterval", KEEPALIVE_INTERVAL); - - NetLog_Server("Keep alive thread starting."); - - info->hKeepAliveEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - - for (;;) - { - DWORD dwWait = ICQWaitForSingleObject(info->hKeepAliveEvent, dwInterval); - if (serverThreadHandle == NULL) // connection lost, end - break; - if (dwWait == WAIT_TIMEOUT) - { - // Send a keep alive packet to server - packet.wLen = 0; - write_flap(&packet, ICQ_PING_CHAN); - sendServPacket(&packet); - } - else if (dwWait == WAIT_IO_COMPLETION) - // Possible shutdown in progress - if (Miranda_Terminated()) break; - else - break; - } - - NetLog_Server("Keep alive thread ended."); - - CloseHandle(info->hKeepAliveEvent); - info->hKeepAliveEvent = NULL; -} - - -void CIcqProto::StartKeepAlive(serverthread_info *info) -{ - if (info->hKeepAliveEvent) // start only once - return; - - if (getSettingByte(NULL, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED)) - CloseHandle( ForkThreadEx(&CIcqProto::KeepAliveThread, info)); -} - - -void CIcqProto::StopKeepAlive(serverthread_info *info) -{ // finish keep alive thread - if (info->hKeepAliveEvent) - SetEvent(info->hKeepAliveEvent); -} diff --git a/protocols/IcqOscarJ/changeinfo/changeinfo.h b/protocols/IcqOscarJ/changeinfo/changeinfo.h deleted file mode 100644 index ecc4fc3106..0000000000 --- a/protocols/IcqOscarJ/changeinfo/changeinfo.h +++ /dev/null @@ -1,122 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2010 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- - -#ifndef __CHANGEINFO_H -#define __CHANGEINFO_H - - -#ifndef AW_SLIDE -#define SPI_GETCOMBOBOXANIMATION 0x1004 -#define AW_SLIDE 0x40000 -#define AW_ACTIVATE 0x20000 -#define AW_VER_POSITIVE 0x4 -#define UDM_SETPOS32 (WM_USER+113) -#define UDM_GETPOS32 (WM_USER+114) -#endif - - -#define LI_DIVIDER 0 -#define LI_STRING 1 -#define LI_LIST 2 -#define LI_LONGSTRING 3 -#define LI_NUMBER 4 -#define LIM_TYPE 0x0000FFFF -#define LIF_ZEROISVALID 0x80000000 -#define LIF_SIGNED 0x40000000 -#define LIF_PASSWORD 0x20000000 -#define LIF_CHANGEONLY 0x10000000 - -struct SettingItem -{ - const char *szDescription; - unsigned displayType; //LI_ constant - int dbType; //DBVT_ constant - const char *szDbSetting; - const void *pList; -}; - -struct SettingItemData -{ - LPARAM value; - int changed; -}; - -// contants.c -extern const SettingItem setting[]; -extern const int settingCount; - -//dlgproc.c -struct ChangeInfoData : public MZeroedObject -{ - HWND hwndDlg; - CIcqProto *ppro; - HFONT hListFont; - HWND hwndList; - int editTopIndex; - int iEditItem; - char Password[PASSWORDMAXLEN]; - - SettingItemData *settingData; - - HANDLE hAckHook; - HANDLE hUpload[2]; - - ChangeInfoData() { settingData = (SettingItemData*)SAFE_MALLOC(sizeof(SettingItemData) * settingCount); hAckHook = NULL; hUpload[0] = NULL; hUpload[1] = NULL;} - ~ChangeInfoData() { SAFE_FREE((void**)&settingData); } - - char* GetItemSettingText(int i, char *buf, size_t buf_size); - void PaintItemSetting(HDC hdc, RECT *rc, int i, UINT itemState); - - //db.cpp - void LoadSettingsFromDb(int keepChanged); - void FreeStoredDbSettings(void); - int ChangesMade(void); - void ClearChangeFlags(void); - int SaveSettingsToDb(HWND hwndDlg); - - //upload.cpp - int UploadSettings(void); - - //editstring.cpp - void BeginStringEdit(int iItem,RECT *rc,int i,WORD wVKey); - void EndStringEdit(int save); - //editlist.cpp - void BeginListEdit(int iItem, RECT *rc, int iSetting, WORD wVKey); - void EndListEdit(int save); -}; - -INT_PTR CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -//editstring.c -int IsStringEditWindow(HWND hwnd); -char* BinaryToEscapes(char *str); - -//editlist.c -int IsListEditWindow(HWND hwnd); - -#endif /* __CHANGEINFO_H */ diff --git a/protocols/IcqOscarJ/changeinfo/constants.cpp b/protocols/IcqOscarJ/changeinfo/constants.cpp deleted file mode 100644 index 92403a74f0..0000000000 --- a/protocols/IcqOscarJ/changeinfo/constants.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2009 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static FieldNamesItem timezones[]={ - {24 ,LPGEN("GMT-12:00 Eniwetok; Kwajalein")}, - {23 ,LPGEN("GMT-11:30")}, - {22 ,LPGEN("GMT-11:00 Midway Island; Samoa")}, - {21 ,LPGEN("GMT-10:30")}, - {20 ,LPGEN("GMT-10:00 Hawaii")}, - {19 ,LPGEN("GMT-9:30")}, - {18 ,LPGEN("GMT-9:00 Alaska")}, - {17 ,LPGEN("GMT-8:30")}, - {16 ,LPGEN("GMT-8:00 Pacific Time; Tijuana")}, - {15 ,LPGEN("GMT-7:30")}, - {14 ,LPGEN("GMT-7:00 Arizona; Mountain Time")}, - {13 ,LPGEN("GMT-6:30")}, - {12 ,LPGEN("GMT-6:00 Central Time; Central America; Saskatchewan")}, - {11 ,LPGEN("GMT-5:30")}, - {10 ,LPGEN("GMT-5:00 Eastern Time; Bogota; Lima; Quito")}, - {9 ,LPGEN("GMT-4:30")}, - {8 ,LPGEN("GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz")}, - {7 ,LPGEN("GMT-3:30 Newfoundland")}, - {6 ,LPGEN("GMT-3:00 Greenland; Buenos Aires; Georgetown")}, - {5 ,LPGEN("GMT-2:30")}, - {4 ,LPGEN("GMT-2:00 Mid-Atlantic")}, - {3 ,LPGEN("GMT-1:30")}, - {2 ,LPGEN("GMT-1:00 Cape Verde Islands; Azores")}, - {1 ,LPGEN("GMT-0:30")}, - {0 ,LPGEN("GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca")}, - {-1 ,LPGEN("GMT+0:30")}, - {-2 ,LPGEN("GMT+1:00 Central European Time; West Central Africa; Warsaw")}, - {-3 ,LPGEN("GMT+1:30")}, - {-4 ,LPGEN("GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens")}, - {-5 ,LPGEN("GMT+2:30")}, - {-6 ,LPGEN("GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad")}, - {-7 ,LPGEN("GMT+3:30 Tehran")}, - {-8 ,LPGEN("GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat")}, - {-9 ,LPGEN("GMT+4:30 Kabul")}, - {-10 ,LPGEN("GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg")}, - {-11 ,LPGEN("GMT+5:30")}, - {-12 ,LPGEN("GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk; Sri Jayawardenepura")}, - {-13 ,LPGEN("GMT+6:30 Rangoon")}, - {-14 ,LPGEN("GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk")}, - {-15 ,LPGEN("GMT+7:30")}, - {-16 ,LPGEN("GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing")}, - {-17 ,LPGEN("GMT+8:30")}, - {-18 ,LPGEN("GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk")}, - {-19 ,LPGEN("GMT+9:30 Darwin; Adelaide")}, - {-20 ,LPGEN("GMT+10:00 East Australia; Guam; Vladivostok")}, - {-21 ,LPGEN("GMT+10:30")}, - {-22 ,LPGEN("GMT+11:00 Magadan; Solomon Is.; New Caledonia")}, - {-23 ,LPGEN("GMT+11:30")}, - {-24 ,LPGEN("GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is.")}, - {-100,NULL} -}; - - -static FieldNamesItem months[]={ - {1, LPGEN("January")}, - {2, LPGEN("February")}, - {3, LPGEN("March")}, - {4, LPGEN("April")}, - {5, LPGEN("May")}, - {6, LPGEN("June")}, - {7, LPGEN("July")}, - {8, LPGEN("August")}, - {9, LPGEN("September")}, - {10,LPGEN("October")}, - {11,LPGEN("November")}, - {12,LPGEN("December")}, - {0, NULL} -}; - - -const int ageRange[]={13,0x7FFF}; // 14, 130 -const int yearRange[]={1753,0x7FFF}; // 1880, 2000 -const int dayRange[]={1,31}; - - -const SettingItem setting[]={ - //personal - {LPGEN("Personal"), LI_DIVIDER}, - {LPGEN("Nickname"), LI_STRING, DBVT_UTF8, "Nick"}, - {LPGEN("First name"), LI_STRING, DBVT_UTF8, "FirstName"}, - {LPGEN("Last name"), LI_STRING, DBVT_UTF8, "LastName"}, -// {LPGEN("Age"), LI_NUMBER, DBVT_WORD, "Age", ageRange}, - {LPGEN("Gender"), LI_LIST, DBVT_BYTE, "Gender", genderField}, - {LPGEN("About"), LI_LONGSTRING, DBVT_UTF8, "About"}, - //password - {LPGEN("Password"), LI_DIVIDER}, - {LPGEN("Password"), LI_STRING|LIF_PASSWORD,DBVT_ASCIIZ, "Password"}, - //contact - {LPGEN("Contact"), LI_DIVIDER}, - {LPGEN("Primary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail0"}, - {LPGEN("Secondary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail1"}, - {LPGEN("Tertiary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail2"}, - {LPGEN("Homepage"), LI_STRING, DBVT_ASCIIZ, "Homepage"}, - {LPGEN("Street"), LI_STRING, DBVT_UTF8, "Street"}, - {LPGEN("City"), LI_STRING, DBVT_UTF8, "City"}, - {LPGEN("State"), LI_STRING, DBVT_UTF8, "State"}, - {LPGEN("ZIP/postcode"), LI_STRING, DBVT_UTF8, "ZIP"}, - {LPGEN("Country"), LI_LIST, DBVT_WORD, "Country", countryField}, - {LPGEN("Phone number"), LI_STRING, DBVT_ASCIIZ, "Phone"}, - {LPGEN("Fax number"), LI_STRING, DBVT_ASCIIZ, "Fax"}, - {LPGEN("Cellular number"),LI_STRING, DBVT_ASCIIZ, "Cellular"}, - //more - {LPGEN("Personal Detail"),LI_DIVIDER}, - {LPGEN("Timezone"), LI_LIST|LIF_ZEROISVALID|LIF_SIGNED,DBVT_BYTE, "Timezone", timezones}, - {LPGEN("Year of birth"), LI_NUMBER, DBVT_WORD, "BirthYear", yearRange}, - {LPGEN("Month of birth"), LI_LIST, DBVT_BYTE, "BirthMonth", months}, - {LPGEN("Day of birth"), LI_NUMBER, DBVT_BYTE, "BirthDay", dayRange}, - {LPGEN("Marital Status"), LI_LIST, DBVT_BYTE, "MaritalStatus", maritalField}, - {LPGEN("Spoken language 1"), LI_LIST, DBVT_BYTE, "Language1", languageField}, - {LPGEN("Spoken language 2"), LI_LIST, DBVT_BYTE, "Language2", languageField}, - {LPGEN("Spoken language 3"), LI_LIST, DBVT_BYTE, "Language3", languageField}, - //more - {LPGEN("Originally from"),LI_DIVIDER}, - {LPGEN("Street"), LI_STRING, DBVT_UTF8, "OriginStreet"}, - {LPGEN("City"), LI_STRING, DBVT_UTF8, "OriginCity"}, - {LPGEN("State"), LI_STRING, DBVT_UTF8, "OriginState"}, - {LPGEN("Country"), LI_LIST, DBVT_WORD, "OriginCountry", countryField}, - //study - {LPGEN("Education"), LI_DIVIDER}, - {LPGEN("Level"), LI_LIST, DBVT_WORD, "StudyLevel", studyLevelField}, - {LPGEN("Institute"), LI_STRING, DBVT_UTF8, "StudyInstitute"}, - {LPGEN("Degree"), LI_STRING, DBVT_UTF8, "StudyDegree"}, - {LPGEN("Graduation Year"),LI_NUMBER, DBVT_WORD, "StudyYear", yearRange}, - //work - {LPGEN("Work"), LI_DIVIDER}, - {LPGEN("Company name"), LI_STRING, DBVT_UTF8, "Company"}, - {LPGEN("Company homepage"),LI_STRING, DBVT_ASCIIZ, "CompanyHomepage"}, - {LPGEN("Company street"), LI_STRING, DBVT_UTF8, "CompanyStreet"}, - {LPGEN("Company city"), LI_STRING, DBVT_UTF8, "CompanyCity"}, - {LPGEN("Company state"), LI_STRING, DBVT_UTF8, "CompanyState"}, - {LPGEN("Company phone"), LI_STRING, DBVT_ASCIIZ, "CompanyPhone"}, - {LPGEN("Company fax"), LI_STRING, DBVT_ASCIIZ, "CompanyFax"}, - {LPGEN("Company ZIP/postcode"),LI_STRING,DBVT_UTF8, "CompanyZIP"}, - {LPGEN("Company country"),LI_LIST, DBVT_WORD, "CompanyCountry", countryField}, - {LPGEN("Company department"),LI_STRING, DBVT_UTF8, "CompanyDepartment"}, - {LPGEN("Company position"),LI_STRING, DBVT_UTF8, "CompanyPosition"}, - {LPGEN("Company industry"),LI_LIST, DBVT_WORD, "CompanyIndustry", industryField}, -// {LPGEN("Company occupation"),LI_LIST, DBVT_WORD, "CompanyOccupation", occupationField}, - //interests - {LPGEN("Personal Interests"), LI_DIVIDER}, - {LPGEN("Interest category 1"),LI_LIST, DBVT_WORD, "Interest0Cat", interestsField}, - {LPGEN("Interest areas 1"),LI_STRING, DBVT_ASCIIZ, "Interest0Text"}, - {LPGEN("Interest category 2"),LI_LIST, DBVT_WORD, "Interest1Cat", interestsField}, - {LPGEN("Interest areas 2"),LI_STRING, DBVT_ASCIIZ, "Interest1Text"}, - {LPGEN("Interest category 3"),LI_LIST, DBVT_WORD, "Interest2Cat", interestsField}, - {LPGEN("Interest areas 3"),LI_STRING, DBVT_ASCIIZ, "Interest2Text"}, - {LPGEN("Interest category 4"),LI_LIST, DBVT_WORD, "Interest3Cat", interestsField}, - {LPGEN("Interest areas 4"),LI_STRING, DBVT_ASCIIZ, "Interest3Text"}, - //pastbackground -// {LPGEN("Past Background"), LI_DIVIDER}, -// {LPGEN("Category 1"), LI_LIST, DBVT_ASCIIZ, "Past0", pastField}, -// {LPGEN("Past Background 1"),LI_STRING, DBVT_ASCIIZ, "Past0Text"}, -// {LPGEN("Category 2"), LI_LIST, DBVT_ASCIIZ, "Past1", pastField}, -// {LPGEN("Past Background 2"),LI_STRING, DBVT_ASCIIZ, "Past1Text"}, -// {LPGEN("Category 3"), LI_LIST, DBVT_ASCIIZ, "Past2", pastField}, -// {LPGEN("Past Background 3"),LI_STRING, DBVT_ASCIIZ, "Past2Text"}, - //affiliation -// {LPGEN("Affiliations"), LI_DIVIDER}, -// {LPGEN("Affiliation category 1"),LI_LIST,DBVT_ASCIIZ, "Affiliation0", affiliationField}, -// {LPGEN("Affiliation 1"), LI_STRING, DBVT_ASCIIZ, "Affiliation0Text"}, -// {LPGEN("Affiliation category 2"),LI_LIST,DBVT_ASCIIZ, "Affiliation1", affiliationField}, -// {LPGEN("Affiliation 2"), LI_STRING, DBVT_ASCIIZ, "Affiliation1Text"}, -// {LPGEN("Affiliation category 3"),LI_LIST,DBVT_ASCIIZ, "Affiliation2", affiliationField}, -// {LPGEN("Affiliation 3"), LI_STRING, DBVT_ASCIIZ, "Affiliation2Text"} -}; - -const int settingCount = SIZEOF(setting); diff --git a/protocols/IcqOscarJ/changeinfo/db.cpp b/protocols/IcqOscarJ/changeinfo/db.cpp deleted file mode 100644 index 643dcaa034..0000000000 --- a/protocols/IcqOscarJ/changeinfo/db.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2009 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void ChangeInfoData::LoadSettingsFromDb(int keepChanged) -{ - for (int i=0; i < settingCount; i++) - { - if (setting[i].displayType == LI_DIVIDER) continue; - if (keepChanged && settingData[i].changed) continue; - if (setting[i].dbType == DBVT_ASCIIZ || setting[i].dbType == DBVT_UTF8) - SAFE_FREE((void**)(char**)&settingData[i].value); - else if (!keepChanged) - settingData[i].value = 0; - - settingData[i].changed = 0; - - if (setting[i].displayType & LIF_PASSWORD) continue; - - DBVARIANT dbv = {DBVT_DELETED}; - if (!ppro->getSetting(NULL, setting[i].szDbSetting, &dbv)) - { - switch(dbv.type) { - case DBVT_ASCIIZ: - settingData[i].value = (LPARAM)ppro->getSettingStringUtf(NULL, setting[i].szDbSetting, NULL); - break; - - case DBVT_UTF8: - settingData[i].value = (LPARAM)null_strdup(dbv.pszVal); - break; - - case DBVT_WORD: - if (setting[i].displayType & LIF_SIGNED) - settingData[i].value = dbv.sVal; - else - settingData[i].value = dbv.wVal; - break; - - case DBVT_BYTE: - if (setting[i].displayType & LIF_SIGNED) - settingData[i].value = dbv.cVal; - else - settingData[i].value = dbv.bVal; - break; - -#ifdef _DEBUG - default: - MessageBoxA(NULL, "That's not supposed to happen either", "Huh?", MB_OK); - break; -#endif - } - ICQFreeVariant(&dbv); - } - - char buf[MAX_PATH]; - TCHAR tbuf[MAX_PATH]; - - if (utf8_to_tchar_static(GetItemSettingText(i, buf, SIZEOF(buf)), tbuf, SIZEOF(tbuf))) - ListView_SetItemText(hwndList, i, 1, tbuf); - } -} - - -void ChangeInfoData::FreeStoredDbSettings(void) -{ - for (int i=0; i < settingCount; i++ ) - if (setting[i].dbType == DBVT_ASCIIZ || setting[i].dbType == DBVT_UTF8) - SAFE_FREE((void**)&settingData[i].value); -} - - -int ChangeInfoData::ChangesMade(void) -{ - for (int i=0; i < settingCount; i++ ) - if (settingData[i].changed) - return 1; - return 0; -} - - -void ChangeInfoData::ClearChangeFlags(void) -{ - for (int i=0; i < settingCount; i++) - settingData[i].changed = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct PwConfirmDlgParam -{ - CIcqProto* ppro; - char* Pass; -}; - -static INT_PTR CALLBACK PwConfirmDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - PwConfirmDlgParam* dat = (PwConfirmDlgParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch(msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - SendDlgItemMessage(hwndDlg,IDC_PASSWORD,EM_LIMITTEXT,15,0); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - { - char szTest[16]; - - GetDlgItemTextA(hwndDlg,IDC_OLDPASS,szTest,sizeof(szTest)); - - if (strcmpnull(szTest, dat->ppro->GetUserPassword(TRUE))) - { - MessageBoxUtf(hwndDlg, LPGEN("The password does not match your current password. Check Caps Lock and try again."), LPGEN("Change ICQ Details"), MB_OK); - SendDlgItemMessage(hwndDlg,IDC_OLDPASS,EM_SETSEL,0,(LPARAM)-1); - SetFocus(GetDlgItem(hwndDlg,IDC_OLDPASS)); - break; - } - - GetDlgItemTextA(hwndDlg,IDC_PASSWORD,szTest,sizeof(szTest)); - if(strcmpnull(szTest, dat->Pass)) - { - MessageBoxUtf(hwndDlg, LPGEN("The password does not match the password you originally entered. Check Caps Lock and try again."), LPGEN("Change ICQ Details"), MB_OK); - SendDlgItemMessage(hwndDlg,IDC_PASSWORD,EM_SETSEL,0,(LPARAM)-1); - SetFocus(GetDlgItem(hwndDlg,IDC_PASSWORD)); - break; - } - } - case IDCANCEL: - EndDialog(hwndDlg,wParam); - break; - } - break; - } - return FALSE; -} - - -int ChangeInfoData::SaveSettingsToDb(HWND hwndDlg) -{ - int ret = 1; - - for (int i = 0; i < settingCount; i++) - { - if (!settingData[i].changed) continue; - if (!(setting[i].displayType & LIF_ZEROISVALID) && settingData[i].value==0) - { - ppro->deleteSetting(NULL, setting[i].szDbSetting); - continue; - } - switch(setting[i].dbType) { - case DBVT_ASCIIZ: - if (setting[i].displayType & LIF_PASSWORD) - { - int nSettingLen = strlennull((char*)settingData[i].value); - - if (nSettingLen > 8 || nSettingLen < 1) - { - MessageBoxUtf(hwndDlg, LPGEN("The ICQ server does not support passwords longer than 8 characters. Please use a shorter password."), LPGEN("Change ICQ Details"), MB_OK); - ret=0; - break; - } - PwConfirmDlgParam param = { ppro, (char*)settingData[i].value }; - if (IDOK != DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_PWCONFIRM), hwndDlg, PwConfirmDlgProc, (LPARAM)¶m)) - { - ret = 0; - break; - } - strcpy(ppro->m_szPassword, (char*)settingData[i].value); - } - else { - if (*(char*)settingData[i].value) - ppro->setSettingStringUtf(NULL, setting[i].szDbSetting, (char*)settingData[i].value); - else - ppro->deleteSetting(NULL, setting[i].szDbSetting); - } - break; - - case DBVT_UTF8: - if (*(char*)settingData[i].value) - ppro->setSettingStringUtf(NULL, setting[i].szDbSetting, (char*)settingData[i].value); - else - ppro->deleteSetting(NULL, setting[i].szDbSetting); - break; - - case DBVT_WORD: - ppro->setSettingWord(NULL, setting[i].szDbSetting, (WORD)settingData[i].value); - break; - - case DBVT_BYTE: - ppro->setSettingByte(NULL, setting[i].szDbSetting, (BYTE)settingData[i].value); - break; - } - } - return ret; -} diff --git a/protocols/IcqOscarJ/changeinfo/dlgproc.cpp b/protocols/IcqOscarJ/changeinfo/dlgproc.cpp deleted file mode 100644 index 404777aa97..0000000000 --- a/protocols/IcqOscarJ/changeinfo/dlgproc.cpp +++ /dev/null @@ -1,540 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2010 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -#define DM_PROTOACK (WM_USER+10) - -static int DrawTextUtf(HDC hDC, char *text, LPRECT lpRect, UINT uFormat, LPSIZE lpSize) -{ - int res; - - WCHAR *tmp = make_unicode_string(text); - res = DrawTextW(hDC, tmp, -1, lpRect, uFormat); - if (lpSize) - GetTextExtentPoint32W(hDC, tmp, strlennull(tmp), lpSize); - SAFE_FREE((void**)&tmp); - - return res; -} - - -char* ChangeInfoData::GetItemSettingText(int i, char *buf, size_t bufsize) -{ - char *text = buf; - int alloced = 0; - - buf[0] = '\0'; - - if (settingData[i].value == 0 && !(setting[i].displayType & LIF_ZEROISVALID)) - { - if (setting[i].displayType & LIF_CHANGEONLY) - text = ICQTranslateUtfStatic(LPGEN(""), buf, bufsize); - else - text = ICQTranslateUtfStatic(LPGEN(""), buf, bufsize); - } - else - { - switch (setting[i].displayType & LIM_TYPE) { - case LI_STRING: - case LI_LONGSTRING: - text = BinaryToEscapes((char*)settingData[i].value); - alloced = 1; - break; - - case LI_NUMBER: - _itoa(settingData[i].value, text, 10); - break; - - case LI_LIST: - if (setting[i].dbType == DBVT_ASCIIZ) - text = ICQTranslateUtfStatic((char*)settingData[i].value, buf, bufsize); - else - { - text = ICQTranslateUtfStatic(LPGEN("Unknown value"), buf, bufsize); - - FieldNamesItem *list = (FieldNamesItem*)setting[i].pList; - for (int j=0; TRUE; j++) - if (list[j].code == settingData[i].value) - { - text = ICQTranslateUtfStatic(list[j].text, buf, bufsize); - break; - } - else if (!list[j].text) - { - if (list[j].code == settingData[i].value) - text = ICQTranslateUtfStatic("Unspecified", buf, bufsize); - break; - } - } - break; - } - } - if (setting[i].displayType & LIF_PASSWORD) - { - if (settingData[i].changed) - for (int j=0; text[j]; j++) text[j] = '*'; - else - { - if (alloced) - { - SAFE_FREE(&text); - alloced = 0; - } - text = "********"; - } - } - if (text != buf) - { - char *tmp = text; - - text = null_strcpy(buf, text, bufsize - 1); - if (alloced) - SAFE_FREE(&tmp); - } - - return text; -} - - -void ChangeInfoData::PaintItemSetting(HDC hdc, RECT *rc, int i, UINT itemState) -{ - char str[MAX_PATH]; - char *text = GetItemSettingText(i, str, SIZEOF(str)); - - if (settingData[i].value == 0 && !(setting[i].displayType & LIF_ZEROISVALID)) - SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); - - if ((setting[i].displayType & LIM_TYPE) == LI_LIST && (itemState & CDIS_SELECTED || iEditItem == i)) - { - RECT rcBtn; - - rcBtn = *rc; - rcBtn.left = rcBtn.right - rc->bottom + rc->top; - InflateRect(&rcBtn,-2,-2); - rc->right = rcBtn.left; - DrawFrameControl(hdc, &rcBtn, DFC_SCROLL, iEditItem == i ? DFCS_SCROLLDOWN|DFCS_PUSHED : DFCS_SCROLLDOWN); - } - DrawTextUtf(hdc, text, rc, DT_END_ELLIPSIS|DT_LEFT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, NULL); -} - - -static int ChangeInfoDlg_Resize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc) -{ - switch (urc->wId) { - case IDC_LIST: - return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; - - case IDC_SAVE: - return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; - - case IDC_UPLOADING: - return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; - } - - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; // default -} - - -INT_PTR CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - ChangeInfoData* dat = (ChangeInfoData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch(msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - dat = new ChangeInfoData(); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); - - dat->hwndDlg = hwndDlg; - dat->ppro = (CIcqProto*)lParam; - dat->hwndList = GetDlgItem(hwndDlg, IDC_LIST); - - ListView_SetExtendedListViewStyle(dat->hwndList, LVS_EX_FULLROWSELECT); - dat->iEditItem = -1; - { - HFONT hFont; - LOGFONT lf; - - dat->hListFont = (HFONT)SendMessage(dat->hwndList, WM_GETFONT, 0, 0); - GetObject(dat->hListFont, sizeof(lf), &lf); - lf.lfHeight -= 5; - hFont = CreateFontIndirect(&lf); - SendMessage(dat->hwndList, WM_SETFONT, (WPARAM)hFont, 0); - } - { // Prepare ListView Columns - LV_COLUMN lvc = {0}; - RECT rc; - - GetClientRect(dat->hwndList, &rc); - rc.right -= GetSystemMetrics(SM_CXVSCROLL); - lvc.mask = LVCF_WIDTH; - lvc.cx = rc.right / 3; - ListView_InsertColumn(dat->hwndList, 0, &lvc); - lvc.cx = rc.right - lvc.cx; - ListView_InsertColumn(dat->hwndList, 1, &lvc); - } - { // Prepare Setting Items - LV_ITEM lvi = {0}; - lvi.mask = LVIF_PARAM | LVIF_TEXT; - - for (lvi.iItem = 0; lvi.iItem < settingCount; lvi.iItem++) - { - TCHAR text[MAX_PATH]; - - lvi.lParam = lvi.iItem; - lvi.pszText = text; - utf8_to_tchar_static(setting[lvi.iItem].szDescription, text, SIZEOF(text)); - ListView_InsertItem(dat->hwndList, &lvi); - } - } - - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - return TRUE; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->idFrom) { - case 0: - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - dat->ppro = (CIcqProto*)((PSHNOTIFY*)lParam)->lParam; - dat->LoadSettingsFromDb(0); - { - char *pwd = dat->ppro->GetUserPassword(TRUE); - strcpy(dat->Password, (pwd) ? pwd : "" ); /// FIXME - } - break; - - case PSN_INFOCHANGED: - dat->LoadSettingsFromDb(1); - break; - - case PSN_KILLACTIVE: - dat->EndStringEdit(1); - dat->EndListEdit(1); - break; - - case PSN_APPLY: - if (dat->ChangesMade()) - { - if (IDYES!=MessageBoxUtf(hwndDlg, LPGEN("You've made some changes to your ICQ details but it has not been saved to the server. Are you sure you want to close this dialog?"), LPGEN("Change ICQ Details"), MB_YESNOCANCEL)) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); - return TRUE; - } - } - break; - } - break; - - case IDC_LIST: - switch (((LPNMHDR)lParam)->code) { - case LVN_GETDISPINFO: - if (dat->iEditItem != -1) - { - if (dat->editTopIndex != ListView_GetTopIndex(dat->hwndList)) - { - dat->EndStringEdit(1); - dat->EndListEdit(1); - } - } - break; - - case NM_CUSTOMDRAW: - { - LPNMLVCUSTOMDRAW cd=(LPNMLVCUSTOMDRAW)lParam; - - switch(cd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW); - return TRUE; - - case CDDS_ITEMPREPAINT: - { - RECT rcItem; - - if (dat->iEditItem != -1) - { - if (dat->editTopIndex != ListView_GetTopIndex(dat->hwndList)) - { - dat->EndStringEdit(1); - dat->EndListEdit(1); - } - } - - ListView_GetItemRect(dat->hwndList, cd->nmcd.dwItemSpec, &rcItem, LVIR_BOUNDS); - - if (GetWindowLongPtr(dat->hwndList, GWL_STYLE) & WS_DISABLED) - { // Disabled List - SetTextColor(cd->nmcd.hdc, cd->clrText); - FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_3DFACE)); - } - else if ((cd->nmcd.uItemState & CDIS_SELECTED || dat->iEditItem == (int)cd->nmcd.dwItemSpec) - && setting[cd->nmcd.lItemlParam].displayType != LI_DIVIDER) - { // Selected item - SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - } - else - { // Unselected item - SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_WINDOWTEXT)); - FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_WINDOW)); - } - - HFONT hoFont = (HFONT)SelectObject(cd->nmcd.hdc, dat->hListFont); - - if (setting[cd->nmcd.lItemlParam].displayType == LI_DIVIDER) - { - RECT rcLine; - SIZE textSize; - char str[MAX_PATH]; - char *szText = ICQTranslateUtfStatic(setting[cd->nmcd.lItemlParam].szDescription, str, MAX_PATH); - - SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_3DSHADOW)); - DrawTextUtf(cd->nmcd.hdc, szText, &rcItem, DT_CENTER|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, &textSize); - rcLine.top = (rcItem.top + rcItem.bottom) / 2 - 1; - rcLine.bottom = rcLine.top + 2; - rcLine.left = rcItem.left + 3; - rcLine.right = (rcItem.left + rcItem.right - textSize.cx) / 2 - 3; - DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT); - rcLine.left = (rcItem.left + rcItem.right + textSize.cx) / 2 + 3; - rcLine.right = rcItem.right - 3; - DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT); - } - else - { - RECT rcItemDescr, rcItemValue; - char str[MAX_PATH]; - - ListView_GetSubItemRect(dat->hwndList, cd->nmcd.dwItemSpec, 0, LVIR_BOUNDS, &rcItemDescr); - ListView_GetSubItemRect(dat->hwndList, cd->nmcd.dwItemSpec, 1, LVIR_BOUNDS, &rcItemValue); - - rcItemDescr.right = rcItemValue.left; - rcItemDescr.left += 2; - DrawTextUtf(cd->nmcd.hdc, ICQTranslateUtfStatic(setting[cd->nmcd.lItemlParam].szDescription, str, MAX_PATH), &rcItemDescr, DT_END_ELLIPSIS|DT_LEFT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, NULL); - - dat->PaintItemSetting(cd->nmcd.hdc, &rcItemValue, cd->nmcd.lItemlParam, cd->nmcd.uItemState); - } - SelectObject(cd->nmcd.hdc, hoFont); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT); - - return TRUE; - } - } - break; - } - case NM_CLICK: - { - LPNMLISTVIEW nm=(LPNMLISTVIEW)lParam; - LV_ITEM lvi; - RECT rc; - - dat->EndStringEdit(1); - dat->EndListEdit(1); - if (nm->iSubItem != 1) break; - lvi.mask = LVIF_PARAM|LVIF_STATE; - lvi.stateMask = 0xFFFFFFFF; - lvi.iItem = nm->iItem; lvi.iSubItem = nm->iSubItem; - ListView_GetItem(dat->hwndList, &lvi); - if (!(lvi.state & LVIS_SELECTED)) break; - ListView_EnsureVisible(dat->hwndList, lvi.iItem, FALSE); - ListView_GetSubItemRect(dat->hwndList, lvi.iItem, lvi.iSubItem, LVIR_BOUNDS, &rc); - dat->editTopIndex = ListView_GetTopIndex(dat->hwndList); - switch (setting[lvi.lParam].displayType & LIM_TYPE) { - case LI_STRING: - case LI_LONGSTRING: - case LI_NUMBER: - dat->BeginStringEdit(nm->iItem, &rc, lvi. lParam, 0); - break; - case LI_LIST: - dat->BeginListEdit(nm->iItem, &rc, lvi. lParam, 0); - break; - } - break; - } - case LVN_KEYDOWN: - { - LPNMLVKEYDOWN nm=(LPNMLVKEYDOWN)lParam; - LV_ITEM lvi; - RECT rc; - - dat->EndStringEdit(1); - dat->EndListEdit(1); - if(nm->wVKey==VK_SPACE || nm->wVKey==VK_RETURN || nm->wVKey==VK_F2) nm->wVKey=0; - if(nm->wVKey && (nm->wVKey<'0' || (nm->wVKey>'9' && nm->wVKey<'A') || (nm->wVKey>'Z' && nm->wVKeywVKey>=VK_F1)) - break; - lvi.mask=LVIF_PARAM|LVIF_STATE; - lvi.stateMask=0xFFFFFFFF; - lvi.iItem = ListView_GetNextItem(dat->hwndList, -1, LVNI_ALL|LVNI_SELECTED); - if (lvi.iItem==-1) break; - lvi.iSubItem=1; - ListView_GetItem(dat->hwndList,&lvi); - ListView_EnsureVisible(dat->hwndList,lvi.iItem,FALSE); - ListView_GetSubItemRect(dat->hwndList,lvi.iItem,lvi.iSubItem,LVIR_BOUNDS,&rc); - dat->editTopIndex = ListView_GetTopIndex(dat->hwndList); - switch(setting[lvi.lParam].displayType & LIM_TYPE) { - case LI_STRING: - case LI_LONGSTRING: - case LI_NUMBER: - dat->BeginStringEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey); - break; - case LI_LIST: - dat->BeginListEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey); - break; - } - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); - return TRUE; - } - case NM_KILLFOCUS: - if (!IsStringEditWindow(GetFocus())) dat->EndStringEdit(1); - if (!IsListEditWindow(GetFocus())) dat->EndListEdit(1); - break; - } - break; - } - break; - case WM_KILLFOCUS: - dat->EndStringEdit(1); - dat->EndListEdit(1); - break; - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - SendMessage(GetParent(hwndDlg), msg, wParam, lParam); - break; - - case IDC_SAVE: - if (!dat->SaveSettingsToDb(hwndDlg)) - break; - - EnableDlgItem(hwndDlg, IDC_SAVE, FALSE); - EnableDlgItem(hwndDlg, IDC_LIST, FALSE); - { - char str[MAX_PATH]; - SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload in progress..."), str, MAX_PATH)); - } - EnableDlgItem(hwndDlg, IDC_UPLOADING, TRUE); - ShowDlgItem(hwndDlg, IDC_UPLOADING, SW_SHOW); - dat->hAckHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, DM_PROTOACK); - - if (!dat->UploadSettings()) - { - EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); - EnableDlgItem(hwndDlg, IDC_LIST, TRUE); - ShowDlgItem(hwndDlg, IDC_UPLOADING, SW_HIDE); - UnhookEvent(dat->hAckHook); - dat->hAckHook = NULL; - } - break; - } - break; - - case WM_SIZE: - { // make the dlg resizeable - UTILRESIZEDIALOG urd = {0}; - - if (IsIconic(hwndDlg)) break; - urd.cbSize = sizeof(urd); - urd.hInstance = hInst; - urd.hwndDlg = hwndDlg; - urd.lParam = 0; // user-defined - urd.lpTemplate = MAKEINTRESOURCEA(IDD_INFO_CHANGEINFO); - urd.pfnResizer = ChangeInfoDlg_Resize; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) &urd); - - { // update listview column widths - RECT rc; - - GetClientRect(dat->hwndList, &rc); - rc.right -= GetSystemMetrics(SM_CXVSCROLL); - ListView_SetColumnWidth(dat->hwndList, 0, rc.right / 3); - ListView_SetColumnWidth(dat->hwndList, 1, rc.right - rc.right / 3); - } - break; - } - - case DM_PROTOACK: - { - ACKDATA *ack=(ACKDATA*)lParam; - int i,done; - char str[MAX_PATH]; - char buf[MAX_PATH]; - - if (ack->type != ACKTYPE_SETINFO) break; - if (ack->result == ACKRESULT_SUCCESS) - { - for (i=0; i < SIZEOF(dat->hUpload); i++) - if (dat->hUpload[i] && ack->hProcess == dat->hUpload[i]) break; - - if (i == SIZEOF(dat->hUpload)) break; - dat->hUpload[i] = NULL; - for (done = 0, i = 0; i < SIZEOF(dat->hUpload); i++) - done += dat->hUpload[i] == NULL; - null_snprintf(buf, sizeof(buf), "%s%d%%", ICQTranslateUtfStatic(LPGEN("Upload in progress..."), str, MAX_PATH), 100*done/(SIZEOF(dat->hUpload))); - SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, buf); - if (done < SIZEOF(dat->hUpload)) break; - - dat->ClearChangeFlags(); - UnhookEvent(dat->hAckHook); - dat->hAckHook = NULL; - EnableDlgItem(hwndDlg, IDC_LIST, TRUE); - EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE); - SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload complete"), str, MAX_PATH)); - SendMessage(GetParent(hwndDlg), PSM_FORCECHANGED, 0, 0); - } - else if (ack->result==ACKRESULT_FAILED) - { - UnhookEvent(dat->hAckHook); - dat->hAckHook = NULL; - EnableDlgItem(hwndDlg, IDC_LIST, TRUE); - EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE); - SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload FAILED"), str, MAX_PATH)); - SendMessage(GetParent(hwndDlg), PSM_FORCECHANGED, 0, 0); - EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); - } - break; - } - case WM_DESTROY: - if (dat->hAckHook) - { - UnhookEvent(dat->hAckHook); - dat->hAckHook = NULL; - } - { - HFONT hFont = (HFONT)SendMessage(dat->hwndList, WM_GETFONT, 0, 0); - DeleteObject(hFont); - } - dat->FreeStoredDbSettings(); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - delete dat; - break; - } - return FALSE; -} diff --git a/protocols/IcqOscarJ/changeinfo/editlist.cpp b/protocols/IcqOscarJ/changeinfo/editlist.cpp deleted file mode 100644 index f2a1470fd3..0000000000 --- a/protocols/IcqOscarJ/changeinfo/editlist.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2009 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static ChangeInfoData *dataListEdit = NULL; -static HWND hwndListEdit = NULL; -static BOOL (WINAPI *MyAnimateWindow)(HWND,DWORD,DWORD); -static WNDPROC OldListEditProc; - -static LRESULT CALLBACK ListEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_LBUTTONUP: - CallWindowProc(OldListEditProc, hwnd, msg, wParam, lParam); - { - POINT pt; - - pt.x = (short)LOWORD(lParam); - pt.y = (short)HIWORD(lParam); - ClientToScreen(hwnd, &pt); - if (SendMessage(hwnd, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y)) == HTVSCROLL) break; - } - { - int i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); - - if (dataListEdit) - dataListEdit->EndListEdit(i != LB_ERR); - } - return 0; - - case WM_CHAR: - if (wParam != '\r') break; - { - int i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); - - if (dataListEdit) - dataListEdit->EndListEdit(i != LB_ERR); - } - return 0; - case WM_KILLFOCUS: - if (dataListEdit) - dataListEdit->EndListEdit(1); - return 0; - } - return CallWindowProc(OldListEditProc, hwnd, msg, wParam, lParam); -} - - -void ChangeInfoData::BeginListEdit(int iItem, RECT *rc, int iSetting, WORD wVKey) -{ - int j,n; - POINT pt; - int itemHeight; - char str[MAX_PATH]; - - if (dataListEdit) - dataListEdit->EndListEdit(0); - - pt.x=pt.y=0; - ClientToScreen(hwndList,&pt); - OffsetRect(rc,pt.x,pt.y); - InflateRect(rc,-2,-2); - rc->left-=2; - iEditItem = iItem; - ListView_RedrawItems(hwndList, iEditItem, iEditItem); - UpdateWindow(hwndList); - - dataListEdit = this; - hwndListEdit = CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, _T("LISTBOX"), _T(""), WS_POPUP|WS_BORDER|WS_VSCROLL, rc->left, rc->bottom, rc->right - rc->left, 150, NULL, NULL, hInst, NULL); - SendMessage(hwndListEdit, WM_SETFONT, (WPARAM)hListFont, 0); - itemHeight = SendMessage(hwndListEdit, LB_GETITEMHEIGHT, 0, 0); - - FieldNamesItem *list = (FieldNamesItem*)setting[iSetting].pList; - - if (list == countryField) - { // some country codes were changed leaving old details uknown, convert it for the user - if (settingData[iSetting].value == 420) settingData[iSetting].value = 42; // conversion of obsolete codes (OMG!) - else if (settingData[iSetting].value == 421) settingData[iSetting].value = 4201; - else if (settingData[iSetting].value == 102) settingData[iSetting].value = 1201; - } - - n = ListBoxAddStringUtf(hwndListEdit, "Unspecified"); - for (j=0; ; j++) - if (!list[j].text) - { - SendMessage(hwndListEdit, LB_SETITEMDATA, n, j); - if ((settingData[iSetting].value == 0 && list[j].code == 0) - || (setting[iSetting].dbType != DBVT_ASCIIZ && settingData[iSetting].value == list[j].code)) - SendMessage(hwndListEdit, LB_SETCURSEL, n, 0); - break; - } - - for (j=0; list[j].text; j++) - { - n = ListBoxAddStringUtf(hwndListEdit, list[j].text); - SendMessage(hwndListEdit, LB_SETITEMDATA, n, j); - if ((setting[iSetting].dbType == DBVT_ASCIIZ && (!strcmpnull((char*)settingData[iSetting].value, list[j].text)) - || (setting[iSetting].dbType == DBVT_ASCIIZ && (!strcmpnull((char*)settingData[iSetting].value, ICQTranslateUtfStatic(list[j].text, str, MAX_PATH)))) - || ((char*)settingData[iSetting].value == NULL && list[j].code == 0)) - || (setting[iSetting].dbType != DBVT_ASCIIZ && settingData[iSetting].value == list[j].code)) - SendMessage(hwndListEdit, LB_SETCURSEL, n, 0); - } - SendMessage(hwndListEdit, LB_SETTOPINDEX, SendMessage(hwndListEdit, LB_GETCURSEL, 0, 0) - 3, 0); - int listCount = SendMessage(hwndListEdit, LB_GETCOUNT, 0, 0); - if (itemHeight * listCount < 150) - SetWindowPos(hwndListEdit, 0, 0, 0, rc->right - rc->left, itemHeight * listCount + GetSystemMetrics(SM_CYBORDER) * 2, SWP_NOZORDER|SWP_NOMOVE); - OldListEditProc = (WNDPROC)SetWindowLongPtr(hwndListEdit, GWLP_WNDPROC, (LONG_PTR)ListEditSubclassProc); - if (MyAnimateWindow = (BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("user32"), "AnimateWindow")) - { - BOOL enabled; - - SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &enabled, FALSE); - if (enabled) MyAnimateWindow(hwndListEdit, 200, AW_SLIDE|AW_ACTIVATE|AW_VER_POSITIVE); - } - ShowWindow(hwndListEdit, SW_SHOW); - SetFocus(hwndListEdit); - if (wVKey) - PostMessage(hwndListEdit, WM_KEYDOWN, wVKey, 0); -} - - -void ChangeInfoData::EndListEdit(int save) -{ - if (hwndListEdit == NULL || iEditItem == -1 || this != dataListEdit) return; - if (save) - { - int iItem = SendMessage(hwndListEdit, LB_GETCURSEL, 0, 0); - int i = SendMessage(hwndListEdit, LB_GETITEMDATA, iItem, 0); - - if (setting[iEditItem].dbType == DBVT_ASCIIZ) - { - char *szNewValue = (((FieldNamesItem*)setting[iEditItem].pList)[i].text); - if (((FieldNamesItem*)setting[iEditItem].pList)[i].code || setting[iEditItem].displayType & LIF_ZEROISVALID) - { - settingData[iEditItem].changed = strcmpnull(szNewValue, (char*)settingData[iEditItem].value); - SAFE_FREE((void**)&settingData[iEditItem].value); - settingData[iEditItem].value = (LPARAM)null_strdup(szNewValue); - } - else - { - settingData[iEditItem].changed = (char*)settingData[iEditItem].value!=NULL; - SAFE_FREE((void**)&settingData[iEditItem].value); - } - } - else - { - settingData[iEditItem].changed = ((FieldNamesItem*)setting[iEditItem].pList)[i].code != settingData[iEditItem].value; - settingData[iEditItem].value = ((FieldNamesItem*)setting[iEditItem].pList)[i].code; - } - if (settingData[iEditItem].changed) - { - char buf[MAX_PATH]; - TCHAR tbuf[MAX_PATH]; - - if (utf8_to_tchar_static(ICQTranslateUtfStatic(((FieldNamesItem*)setting[iEditItem].pList)[i].text, buf, SIZEOF(buf)), tbuf, SIZEOF(buf))) - ListView_SetItemText(hwndList, iEditItem, 1, tbuf); - - EnableDlgItem(GetParent(hwndList), IDC_SAVE, TRUE); - - } - } - ListView_RedrawItems(hwndList, iEditItem, iEditItem); - iEditItem = -1; - dataListEdit = NULL; - DestroyWindow(hwndListEdit); - hwndListEdit = NULL; -} - - -int IsListEditWindow(HWND hwnd) -{ - if (hwnd == hwndListEdit) return 1; - return 0; -} diff --git a/protocols/IcqOscarJ/changeinfo/editstring.cpp b/protocols/IcqOscarJ/changeinfo/editstring.cpp deleted file mode 100644 index 288351e8d3..0000000000 --- a/protocols/IcqOscarJ/changeinfo/editstring.cpp +++ /dev/null @@ -1,367 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2009 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static ChangeInfoData *dataStringEdit = NULL; -static WNDPROC OldStringEditProc, OldExpandButtonProc; -static HWND hwndEdit = NULL, hwndExpandButton = NULL, hwndUpDown = NULL; - -static const char escapes[]={'a','\a', -'b','\b', -'e',27, -'f','\f', -'r','\r', -'t','\t', -'v','\v', -'\\','\\'}; - -static void EscapesToMultiline(WCHAR *str,PDWORD selStart,PDWORD selEnd) -{ //converts "\\n" and "\\t" to "\r\n" and "\t" because a multi-line edit box can show them properly - DWORD i; - - for(i=0; *str; str++, i++) - { - if (*str != '\\') continue; - if (str[1] == 'n') - { - *str++ = '\r'; - i++; - *str = '\n'; - } - else if (str[1] == 't') - { - *str = '\t'; - memmove(str+1, str+2, sizeof(WCHAR)*(strlennull(str)-1)); - - if (*selStart>i) --*selStart; - if (*selEnd>i) --*selEnd; - } - } -} - - - -static void EscapesToBinary(char *str) -{ - for (;*str;str++) - { - if (*str!='\\') continue; - if(str[1]=='n') {*str++='\r'; *str='\n'; continue;} - if(str[1]=='0') - { - char *codeend; - *str=(char)strtol(str+1,&codeend,8); - if (*str==0) {*str='\\'; continue;} - memmove(str+1,codeend,strlennull(codeend)+1); - continue; - } - for(int i=0;i=' ') - { - *pout++=*str; - continue; - } - if(str[0]=='\r' && str[1]=='\n') - { - *pout++='\\'; - *pout++='n'; - str++; - continue; - } - if(extra<3) - { - extra+=8; len+=8; - pout=out=(char*)SAFE_REALLOC(out,len); - } - *pout++='\\'; - for(i = 0; i < SIZEOF(escapes); i += 2) - if (*str==escapes[i+1]) - { - *pout++=escapes[i]; - extra--; - break; - } - if(i < SIZEOF(escapes)) continue; - *pout++='0'; extra--; - if (*str>=8) - { - *pout++=(*str>>3)+'0'; - extra--; - } - *pout++=(*str&7)+'0'; extra--; - } - *pout='\0'; - return out; -} - - - -static LRESULT CALLBACK StringEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_KEYDOWN: - if (wParam==VK_ESCAPE) - { - if (dataStringEdit) - dataStringEdit->EndStringEdit(0); - return 0; - } - if (wParam==VK_RETURN) - { - if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_MULTILINE && !(GetKeyState(VK_CONTROL) & 0x8000)) break; - if (dataStringEdit) - dataStringEdit->EndStringEdit(1); - return 0; - } - break; - - case WM_GETDLGCODE: - return DLGC_WANTALLKEYS|CallWindowProc(OldStringEditProc, hwnd, msg, wParam, lParam); - - case WM_KILLFOCUS: - if ((HWND)wParam == hwndExpandButton) break; - if (dataStringEdit) - dataStringEdit->EndStringEdit(1); - return 0; - } - return CallWindowProc(OldStringEditProc, hwnd, msg, wParam, lParam); -} - - - -static LRESULT CALLBACK ExpandButtonSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_LBUTTONUP: - if(GetCapture()==hwnd) - { - //do expand - RECT rcStart,rcEnd; - DWORD selStart,selEnd; - WCHAR *text; - BOOL animEnabled=TRUE; - - GetWindowRect(hwndEdit,&rcStart); - InflateRect(&rcStart,2,2); - - text = GetWindowTextUcs(hwndEdit); - SendMessage(hwndEdit,EM_GETSEL,(WPARAM)&selStart,(LPARAM)&selEnd); - DestroyWindow(hwndEdit); - EscapesToMultiline(text,&selStart,&selEnd); - hwndEdit=CreateWindowExA(WS_EX_TOOLWINDOW,"EDIT","",WS_POPUP|WS_BORDER|WS_VISIBLE|ES_WANTRETURN|ES_AUTOVSCROLL|WS_VSCROLL|ES_MULTILINE,rcStart.left,rcStart.top,rcStart.right-rcStart.left,rcStart.bottom-rcStart.top,NULL,NULL,hInst,NULL); - SetWindowTextUcs(hwndEdit, text); - OldStringEditProc=(WNDPROC)SetWindowLongPtr(hwndEdit,GWLP_WNDPROC,(LONG_PTR)StringEditSubclassProc); - SendMessage(hwndEdit,WM_SETFONT,(WPARAM)dataStringEdit->hListFont,0); - SendMessage(hwndEdit,EM_SETSEL,selStart,selEnd); - SetFocus(hwndEdit); - - rcEnd.left=rcStart.left; rcEnd.top=rcStart.top; - rcEnd.right=rcEnd.left+350; - rcEnd.bottom=rcEnd.top+150; - if (LOBYTE(LOWORD(GetVersion()))>4 || HIBYTE(LOWORD(GetVersion()))>0) - SystemParametersInfo(SPI_GETCOMBOBOXANIMATION,0,&animEnabled,FALSE); - if(animEnabled) - { - DWORD startTime,timeNow; - startTime=GetTickCount(); - for (;;) - { - UpdateWindow(hwndEdit); - timeNow=GetTickCount(); - if(timeNow>startTime+200) break; - SetWindowPos(hwndEdit,0,rcEnd.left,rcEnd.top,(rcEnd.right-rcStart.right)*(timeNow-startTime)/200+rcStart.right-rcEnd.left,(rcEnd.bottom-rcStart.bottom)*(timeNow-startTime)/200+rcStart.bottom-rcEnd.top,SWP_NOZORDER); - } - } - SetWindowPos(hwndEdit,0,rcEnd.left,rcEnd.top,rcEnd.right-rcEnd.left,rcEnd.bottom-rcEnd.top,SWP_NOZORDER); - - DestroyWindow(hwnd); - hwndExpandButton=NULL; - - SAFE_FREE((void**)&text); - } - break; - } - return CallWindowProc(OldExpandButtonProc,hwnd,msg,wParam,lParam); -} - - -void ChangeInfoData::BeginStringEdit(int iItem, RECT *rc, int i, WORD wVKey) -{ - char *szValue; - char str[80]; - int alloced=0; - - EndStringEdit(0); - InflateRect(rc,-2,-2); - rc->left-=2; - if (setting[i].displayType & LIF_PASSWORD && !settingData[i].changed) - szValue = " "; - else if ((setting[i].displayType & LIM_TYPE) == LI_NUMBER) - { - szValue = str; - null_snprintf(str, sizeof(str), "%d", settingData[i].value ); - } - else if (settingData[i].value) - { - szValue = BinaryToEscapes((char*)settingData[i].value); - alloced = 1; - } - else szValue = ""; - - iEditItem = iItem; - - if ((setting[i].displayType & LIM_TYPE)==LI_LONGSTRING) - { - rc->right-=rc->bottom-rc->top; - hwndExpandButton=CreateWindowA("BUTTON","",WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_ICON,rc->right,rc->top,rc->bottom-rc->top,rc->bottom-rc->top,hwndList,NULL,hInst,NULL); - SendMessage(hwndExpandButton,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_EXPANDSTRINGEDIT),IMAGE_ICON,0,0,LR_SHARED)); - OldExpandButtonProc=(WNDPROC)SetWindowLongPtr(hwndExpandButton,GWLP_WNDPROC,(LONG_PTR)ExpandButtonSubclassProc); - } - - dataStringEdit = this; - hwndEdit = CreateWindow(_T("EDIT"),_T(""),WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|((setting[i].displayType&LIM_TYPE)==LI_NUMBER?ES_NUMBER:0)|(setting[i].displayType&LIF_PASSWORD?ES_PASSWORD:0),rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hwndList,NULL,hInst,NULL); - SetWindowTextUtf(hwndEdit, szValue); - if (alloced) SAFE_FREE(&szValue); - OldStringEditProc=(WNDPROC)SetWindowLongPtr(hwndEdit,GWLP_WNDPROC,(LONG_PTR)StringEditSubclassProc); - SendMessage(hwndEdit,WM_SETFONT,(WPARAM)hListFont,0); - if ((setting[i].displayType & LIM_TYPE) == LI_NUMBER) - { - int *range= (int*)setting[i].pList; - RECT rcUpDown; - hwndUpDown=CreateWindow(UPDOWN_CLASS,_T(""),WS_VISIBLE|WS_CHILD|UDS_AUTOBUDDY|UDS_ALIGNRIGHT|UDS_HOTTRACK|UDS_NOTHOUSANDS|UDS_SETBUDDYINT,0,0,0,0,hwndList,NULL,hInst,NULL); - SendMessage(hwndUpDown, UDM_SETRANGE32, range[0], range[1]); - SendMessage(hwndUpDown, UDM_SETPOS32, 0, settingData[i].value); - if (!(setting[i].displayType & LIF_ZEROISVALID) && settingData[i].value==0) - SetWindowTextA(hwndEdit, ""); - GetClientRect(hwndUpDown, &rcUpDown); - rc->right -= rcUpDown.right; - SetWindowPos(hwndEdit,0,0,0,rc->right-rc->left,rc->bottom-rc->top,SWP_NOZORDER|SWP_NOMOVE); - } - SendMessage(hwndEdit,EM_SETSEL,0,(LPARAM)-1); - SetFocus(hwndEdit); - PostMessage(hwndEdit,WM_KEYDOWN,wVKey,0); -} - - -void ChangeInfoData::EndStringEdit(int save) -{ - if (hwndEdit == NULL || iEditItem == -1 || this != dataStringEdit) return; - if (save) - { - char *text = (char*)SAFE_MALLOC(GetWindowTextLength(hwndEdit)+1); - - GetWindowTextA(hwndEdit,(char*)text,GetWindowTextLength(hwndEdit)+1); - EscapesToBinary(text); - if ((setting[iEditItem].displayType&LIM_TYPE)==LI_NUMBER) - { - LPARAM newValue; - int *range=(int*)setting[iEditItem].pList; - newValue = atoi(text); - if (newValue) - { - if (newValuerange[1]) newValue=range[1]; - } - settingData[iEditItem].changed = settingData[iEditItem].value != newValue; - settingData[iEditItem].value = newValue; - SAFE_FREE(&text); - } - else - { - if (!(setting[iEditItem].displayType & LIF_PASSWORD)) - { - SAFE_FREE(&text); - text = GetWindowTextUtf(hwndEdit); - EscapesToBinary(text); - } - if ((setting[iEditItem].displayType & LIF_PASSWORD && strcmpnull(text," ")) || - (!(setting[iEditItem].displayType & LIF_PASSWORD) && strcmpnull(text, (char*)settingData[iEditItem].value) && (strlennull(text) + strlennull((char*)settingData[iEditItem].value)))) - { - SAFE_FREE((void**)&settingData[iEditItem].value); - if (strlennull(text)) - settingData[iEditItem].value = (LPARAM)text; - else - { - settingData[iEditItem].value = 0; - SAFE_FREE(&text); - } - settingData[iEditItem].changed = 1; - } - } - if (settingData[iEditItem].changed) - { - TCHAR tbuf[MAX_PATH]; - - GetWindowText(hwndEdit, tbuf, SIZEOF(tbuf)); - ListView_SetItemText(hwndList, iEditItem, 1, tbuf); - - EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); - } - } - ListView_RedrawItems(hwndList, iEditItem, iEditItem); - iEditItem = -1; - dataStringEdit = NULL; - DestroyWindow(hwndEdit); - hwndEdit = NULL; - if (hwndExpandButton) DestroyWindow(hwndExpandButton); - hwndExpandButton = NULL; - if (hwndUpDown) DestroyWindow(hwndUpDown); - hwndUpDown = NULL; -} - - - -int IsStringEditWindow(HWND hwnd) -{ - if (hwnd == hwndEdit) return 1; - if (hwnd == hwndExpandButton) return 1; - if (hwnd == hwndUpDown) return 1; - return 0; -} diff --git a/protocols/IcqOscarJ/changeinfo/expandst.ico b/protocols/IcqOscarJ/changeinfo/expandst.ico deleted file mode 100644 index 17367fe8d3..0000000000 Binary files a/protocols/IcqOscarJ/changeinfo/expandst.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/changeinfo/icqoscar.h b/protocols/IcqOscarJ/changeinfo/icqoscar.h deleted file mode 100644 index 77283f6f7f..0000000000 --- a/protocols/IcqOscarJ/changeinfo/icqoscar.h +++ /dev/null @@ -1,2 +0,0 @@ -/* For MinGW sake */ -#include "../icqoscar.h" diff --git a/protocols/IcqOscarJ/changeinfo/main.cpp b/protocols/IcqOscarJ/changeinfo/main.cpp deleted file mode 100644 index 22669be3aa..0000000000 --- a/protocols/IcqOscarJ/changeinfo/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2008 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" diff --git a/protocols/IcqOscarJ/changeinfo/upload.cpp b/protocols/IcqOscarJ/changeinfo/upload.cpp deleted file mode 100644 index a468dc9f2b..0000000000 --- a/protocols/IcqOscarJ/changeinfo/upload.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2001-2004 Richard Hughes, Martin Öberg -// Copyright © 2004-2009 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ChangeInfo Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -int CIcqProto::StringToListItemId(const char *szSetting,int def) -{ - int i; - - for(i=0;iicqOnline()) - { - MessageBoxUtf(hwndDlg, LPGEN("You are not currently connected to the ICQ network. You must be online in order to update your information on the server."), LPGEN("Change ICQ Details"), MB_OK); - return 0; - } - - hUpload[0] = (HANDLE)ppro->ChangeInfoEx(CIXT_FULL, 0); - - //password - char* tmp = ppro->GetUserPassword(TRUE); - if (tmp) - { - if (strlennull(Password) > 0 && strcmpnull(Password, tmp)) - { - hUpload[1] = (HANDLE)ppro->icq_changeUserPasswordServ(tmp); - char szPwd[PASSWORDMAXLEN] = {0}; - - if (ppro->GetUserStoredPassword(szPwd, sizeof(szPwd))) - { // password is stored in DB, update - char ptmp[PASSWORDMAXLEN]; - - strcpy(ptmp, tmp); - - CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ptmp), (LPARAM)ptmp); - - ppro->setSettingString(NULL, "Password", ptmp); - } - } - } - - return 1; -} diff --git a/protocols/IcqOscarJ/channels.h b/protocols/IcqOscarJ/channels.h deleted file mode 100644 index ba10483b56..0000000000 --- a/protocols/IcqOscarJ/channels.h +++ /dev/null @@ -1,47 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Header for FLAP Channel packet handlers -// -// ----------------------------------------------------------------------------- -#ifndef __CHANNELS_H -#define __CHANNELS_H - - -struct snac_header -{ - BOOL bValid; - WORD wFamily; - WORD wSubtype; - WORD wFlags; - DWORD dwRef; - WORD wVersion; -}; - -int unpackSnacHeader(snac_header *pSnacHeader, BYTE **pBuffer, WORD *pwBufferLength); - - -#endif /* __CHANNELS_H */ diff --git a/protocols/IcqOscarJ/cookies.cpp b/protocols/IcqOscarJ/cookies.cpp deleted file mode 100644 index 87ffb4bc07..0000000000 --- a/protocols/IcqOscarJ/cookies.cpp +++ /dev/null @@ -1,301 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packet & message cookies -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -#define INVALID_COOKIE_INDEX -1 - -void CIcqProto::RemoveExpiredCookies() -{ - time_t tNow = time(NULL); - - for (int i = cookies.getCount()-1; i >= 0; i--) - { - icq_cookie_info *cookie = cookies[i]; - - if ((cookie->dwTime + COOKIE_TIMEOUT) < tNow) - { - cookies.remove(i); - SAFE_FREE((void**)&cookie); - } - } -} - - -// Generate and allocate cookie -DWORD CIcqProto::AllocateCookie(BYTE bType, WORD wIdent, HANDLE hContact, void *pvExtra) -{ - icq_lock l(cookieMutex); - - DWORD dwThisSeq = wCookieSeq++; - dwThisSeq &= 0x7FFF; - dwThisSeq |= wIdent<<0x10; - - icq_cookie_info* p = (icq_cookie_info*)SAFE_MALLOC(sizeof(icq_cookie_info)); - if (p) - { - p->bType = bType; - p->dwCookie = dwThisSeq; - p->hContact = hContact; - p->pvExtra = pvExtra; - p->dwTime = time(NULL); - cookies.insert(p); - } - return dwThisSeq; -} - - -DWORD CIcqProto::GenerateCookie(WORD wIdent) -{ - icq_lock l(cookieMutex); - - DWORD dwThisSeq = wCookieSeq++; - dwThisSeq &= 0x7FFF; - dwThisSeq |= wIdent<<0x10; - - return dwThisSeq; -} - - -int CIcqProto::GetCookieType(DWORD dwCookie) -{ - icq_lock l(cookieMutex); - - int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); - if ( i != INVALID_COOKIE_INDEX ) - i = cookies[i]->bType; - - return i; -} - - -int CIcqProto::FindCookie(DWORD dwCookie, HANDLE *phContact, void **ppvExtra) -{ - icq_lock l(cookieMutex); - - int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); - if (i != INVALID_COOKIE_INDEX) - { - if (phContact) - *phContact = cookies[i]->hContact; - if (ppvExtra) - *ppvExtra = cookies[i]->pvExtra; - - // Cookie found - return 1; - } - - return 0; -} - - -int CIcqProto::FindCookieByData(void *pvExtra, DWORD *pdwCookie, HANDLE *phContact) -{ - icq_lock l(cookieMutex); - - for (int i = 0; i < cookies.getCount(); i++) - { - if (pvExtra == cookies[i]->pvExtra) - { - if (phContact) - *phContact = cookies[i]->hContact; - if (pdwCookie) - *pdwCookie = cookies[i]->dwCookie; - - // Cookie found - return 1; - } - } - - return 0; -} - - -int CIcqProto::FindCookieByType(BYTE bType, DWORD *pdwCookie, HANDLE *phContact, void** ppvExtra) -{ - icq_lock l(cookieMutex); - - for (int i = 0; i < cookies.getCount(); i++) - { - if (bType == cookies[i]->bType) - { - if (pdwCookie) - *pdwCookie = cookies[i]->dwCookie; - if (phContact) - *phContact = cookies[i]->hContact; - if (ppvExtra) - *ppvExtra = cookies[i]->pvExtra; - - // Cookie found - return 1; - } - } - - return 0; -} - - -int CIcqProto::FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, HANDLE *phContact, cookie_message_data **ppvExtra) -{ - icq_lock l(cookieMutex); - - for (int i = 0; i < cookies.getCount(); i++) - { - if (cookies[i]->bType == CKT_MESSAGE || cookies[i]->bType == CKT_FILE || cookies[i]->bType == CKT_REVERSEDIRECT) - { // message cookie found - cookie_message_data *pCookie = (cookie_message_data*)cookies[i]->pvExtra; - - if (pCookie->dwMsgID1 == dwMsgID1 && pCookie->dwMsgID2 == dwMsgID2) - { - if (phContact) - *phContact = cookies[i]->hContact; - if (pdwCookie) - *pdwCookie = cookies[i]->dwCookie; - if (ppvExtra) - *ppvExtra = pCookie; - - // Cookie found - return 1; - } - } - } - - return 0; -} - - -void CIcqProto::FreeCookie(DWORD dwCookie) -{ - icq_lock l(cookieMutex); - - int i = cookies.getIndex((icq_cookie_info*)&dwCookie); - if (i != INVALID_COOKIE_INDEX) - { // Cookie found, remove from list - icq_cookie_info *cookie = cookies[i]; - - cookies.remove(i); - SAFE_FREE((void**)&cookie); - } - - RemoveExpiredCookies(); -} - - -void CIcqProto::FreeCookieByData(BYTE bType, void *pvExtra) -{ - icq_lock l(cookieMutex); - - for (int i = 0; i < cookies.getCount(); i++) - { - icq_cookie_info *cookie = cookies[i]; - - if (bType == cookie->bType && pvExtra == cookie->pvExtra) - { // Cookie found, remove from list - cookies.remove(i); - SAFE_FREE((void**)&cookie); - break; - } - } - - RemoveExpiredCookies(); -} - - -void CIcqProto::ReleaseCookie(DWORD dwCookie) -{ - icq_lock l(cookieMutex); - - int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); - if (i != INVALID_COOKIE_INDEX) - { // Cookie found, remove from list - icq_cookie_info *cookie = cookies[i]; - - cookies.remove(i); - SAFE_FREE((void**)&cookie->pvExtra); - SAFE_FREE((void**)&cookie); - } - RemoveExpiredCookies(); -} - - -void CIcqProto::InitMessageCookie(cookie_message_data *pCookie) -{ - DWORD dwMsgID1; - DWORD dwMsgID2; - - do - { // ensure that message ids are unique - dwMsgID1 = time(NULL); - dwMsgID2 = RandRange(0, 0x0FFFF); - } while (FindMessageCookie(dwMsgID1, dwMsgID2, NULL, NULL, NULL)); - - if (pCookie) - { - pCookie->dwMsgID1 = dwMsgID1; - pCookie->dwMsgID2 = dwMsgID2; - } -} - - -cookie_message_data* CIcqProto::CreateMessageCookie(WORD bMsgType, BYTE bAckType) -{ - cookie_message_data *pCookie = (cookie_message_data*)SAFE_MALLOC(sizeof(cookie_message_data)); - if (pCookie) - { - pCookie->bMessageType = bMsgType; - pCookie->nAckType = bAckType; - - InitMessageCookie(pCookie); - } - return pCookie; -} - - -cookie_message_data* CIcqProto::CreateMessageCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin, int bUseSrvRelay) -{ - BYTE bAckType; - WORD wStatus = getContactStatus(hContact); - - if (!getSettingByte(hContact, "SlowSend", getSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND)) || - (!dwUin && wStatus == ID_STATUS_OFFLINE)) - bAckType = ACKTYPE_NONE; - else if (bUseSrvRelay) - bAckType = ACKTYPE_CLIENT; - else - bAckType = ACKTYPE_SERVER; - - cookie_message_data* pCookieData = CreateMessageCookie(bMsgType, bAckType); - - // set flag for offline messages - to allow proper error handling - if (wStatus == ID_STATUS_OFFLINE || wStatus == ID_STATUS_INVISIBLE) - pCookieData->isOffline = TRUE; - - return pCookieData; -} diff --git a/protocols/IcqOscarJ/cookies.h b/protocols/IcqOscarJ/cookies.h deleted file mode 100644 index 05e0d170eb..0000000000 --- a/protocols/IcqOscarJ/cookies.h +++ /dev/null @@ -1,148 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __COOKIES_H -#define __COOKIES_H - - -#define CKT_MESSAGE 0x01 -#define CKT_FILE 0x02 -#define CKT_SEARCH 0x04 -#define CKT_SERVERLIST 0x08 -#define CKT_SERVICEREQUEST 0x0A -#define CKT_REVERSEDIRECT 0x0C -#define CKT_FAMILYSPECIAL 0x10 -#define CKT_OFFLINEMESSAGE 0x12 -#define CKT_DIRECTORY_QUERY 0x18 -#define CKT_DIRECTORY_UPDATE 0x19 -#define CKT_AVATAR 0x20 - -struct CIcqProto; - -/* Basic structure used to hold operation cookies list */ -struct icq_cookie_info -{ - DWORD dwCookie; - HANDLE hContact; - void *pvExtra; - time_t dwTime; - BYTE bType; -}; - - -/* Specific structures to hold request specific data - pvExtra */ - -struct cookie_family_request -{ - WORD wFamily; - void (CIcqProto::*familyHandler)(HANDLE hConn, char* cookie, WORD cookieLen); -}; - - -struct cookie_offline_messages -{ - int nMessages; - int nMissed; -}; - - -#define ACKTYPE_NONE 0 -#define ACKTYPE_SERVER 1 -#define ACKTYPE_CLIENT 2 - -struct cookie_message_data -{ - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD bMessageType; - BYTE nAckType; - BYTE isOffline; -}; - -#define REQUESTTYPE_OWNER 0 -#define REQUESTTYPE_USERAUTO 1 -#define REQUESTTYPE_USERMINIMAL 2 -#define REQUESTTYPE_USERDETAILED 3 -#define REQUESTTYPE_PROFILE 4 - -struct cookie_fam15_data -{ - BYTE bRequestType; -}; - - -#define SEARCHTYPE_UID 0 -#define SEARCHTYPE_EMAIL 1 -#define SEARCHTYPE_NAMES 2 -#define SEARCHTYPE_DETAILS 4 - -struct cookie_search -{ - BYTE bSearchType; - char* szObject; - DWORD dwMainId; - DWORD dwStatus; -}; - - -struct cookie_avatar -{ - DWORD dwUin; - HANDLE hContact; - unsigned int hashlen; - BYTE *hash; - unsigned int cbData; - TCHAR *szFile; -}; - - -struct cookie_reverse_connect: public cookie_message_data -{ - HANDLE hContact; - DWORD dwUin; - int type; - void *ft; -}; - - -#define DIRECTORYREQUEST_INFOUSER 0x01 -#define DIRECTORYREQUEST_INFOOWNER 0x02 -#define DIRECTORYREQUEST_INFOMULTI 0x03 -#define DIRECTORYREQUEST_SEARCH 0x08 -#define DIRECTORYREQUEST_UPDATEOWNER 0x10 -#define DIRECTORYREQUEST_UPDATENOTE 0x11 -#define DIRECTORYREQUEST_UPDATEPRIVACY 0x12 - -struct cookie_directory_data -{ - BYTE bRequestType; -}; - - -#endif /* __COOKIES_H */ diff --git a/protocols/IcqOscarJ/directpackets.cpp b/protocols/IcqOscarJ/directpackets.cpp deleted file mode 100644 index 594f005675..0000000000 --- a/protocols/IcqOscarJ/directpackets.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void EncryptDirectPacket(directconnect* dc, icq_packet* p); - -void packEmptyMsg(icq_packet *packet); - -static void packDirectMsgHeader(icq_packet* packet, WORD wDataLen, WORD wCommand, DWORD dwCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wX1, WORD wX2) -{ - directPacketInit(packet, 29 + wDataLen); - packByte(packet, 2); /* channel */ - packLEDWord(packet, 0); /* space for crypto */ - packLEWord(packet, wCommand); - packLEWord(packet, 14); /* unknown */ - packLEWord(packet, (WORD)dwCookie); - packLEDWord(packet, 0); /* unknown */ - packLEDWord(packet, 0); /* unknown */ - packLEDWord(packet, 0); /* unknown */ - packByte(packet, bMsgType); - packByte(packet, bMsgFlags); - packLEWord(packet, wX1); /* unknown. Is 1 for getawaymsg, 0 otherwise */ - packLEWord(packet, wX2); // this is probably priority -} - - -void CIcqProto::icq_sendDirectMsgAck(directconnect* dc, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, char* szCap) -{ - icq_packet packet; - - packDirectMsgHeader(&packet, (WORD)(bMsgType==MTYPE_PLAIN ? (szCap ? 53 : 11) : 3), DIRECT_ACK, wCookie, bMsgType, bMsgFlags, 0, 0); - packEmptyMsg(&packet); /* empty message */ - - if (bMsgType == MTYPE_PLAIN) - { - packMsgColorInfo(&packet); - - if (szCap) - { - packLEDWord(&packet, 0x26); /* CLSID length */ - packBuffer(&packet, (LPBYTE)szCap, 0x26); /* GUID */ - } - } - EncryptDirectPacket(dc, &packet); - sendDirectPacket(dc, &packet); - - NetLog_Direct("Sent acknowledgement thru direct connection"); -} - - -DWORD CIcqProto::icq_sendGetAwayMsgDirect(HANDLE hContact, int type) -{ - icq_packet packet; - DWORD dwCookie; - cookie_message_data *pCookieData; - - if (getSettingWord(hContact, "Version", 0) == 9) - return 0; // v9 DC protocol does not support this message - - pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); - dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - packDirectMsgHeader(&packet, 3, DIRECT_MESSAGE, dwCookie, (BYTE)type, 3, 1, 0); - packEmptyMsg(&packet); // message - - return (SendDirectMessage(hContact, &packet)) ? dwCookie : 0; -} - - -void CIcqProto::icq_sendAwayMsgReplyDirect(directconnect* dc, WORD wCookie, BYTE msgType, const char** szMsg) -{ - icq_packet packet; - - if (validateStatusMessageRequest(dc->hContact, msgType)) - { - NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dc->dwRemoteUin); - - icq_lock l(m_modeMsgsMutex); - - if (szMsg && *szMsg) - { - // prepare Ansi message - only Ansi supported - WORD wMsgLen = strlennull(*szMsg) + 1; - char *szAnsiMsg = (char*)_alloca(wMsgLen); - - utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); - wMsgLen = strlennull(szAnsiMsg); - packDirectMsgHeader(&packet, (WORD)(3 + wMsgLen), DIRECT_ACK, wCookie, msgType, 3, 0, 0); - packLEWord(&packet, (WORD)(wMsgLen + 1)); - packBuffer(&packet, (LPBYTE)szAnsiMsg, (WORD)(wMsgLen + 1)); - EncryptDirectPacket(dc, &packet); - - sendDirectPacket(dc, &packet); - } - } -} - - -void CIcqProto::icq_sendFileAcceptDirect(HANDLE hContact, filetransfer* ft) -{ - // v7 packet - icq_packet packet; - - packDirectMsgHeader(&packet, 18, DIRECT_ACK, ft->dwCookie, MTYPE_FILEREQ, 0, 0, 0); - packLEWord(&packet, 1); // description - packByte(&packet, 0); - packWord(&packet, wListenPort); - packLEWord(&packet, 0); - packLEWord(&packet, 1); // filename - packByte(&packet, 0); // TODO: really send filename - packLEDWord(&packet, ft->dwTotalSize); // file size - packLEDWord(&packet, wListenPort); // FIXME: ideally we want to open a new port for this - - SendDirectMessage(hContact, &packet); - - NetLog_Direct("Sent file accept direct, port %u", wListenPort); -} - - -void CIcqProto::icq_sendFileDenyDirect(HANDLE hContact, filetransfer *ft, const char *szReason) -{ - // v7 packet - icq_packet packet; - char *szReasonAnsi = NULL; - int cbReasonAnsi = 0; - - if (!utf8_decode(szReason, &szReasonAnsi)) - szReasonAnsi = NULL; - else - cbReasonAnsi = strlennull(szReasonAnsi); - - packDirectMsgHeader(&packet, (WORD)(18 + cbReasonAnsi), DIRECT_ACK, ft->dwCookie, MTYPE_FILEREQ, 0, 1, 0); - packLEWord(&packet, (WORD)(1 + cbReasonAnsi)); // description - if (szReasonAnsi) packBuffer(&packet, (LPBYTE)szReasonAnsi, (WORD)cbReasonAnsi); - packByte(&packet, 0); - packWord(&packet, 0); - packLEWord(&packet, 0); - packLEWord(&packet, 1); // filename - packByte(&packet, 0); // TODO: really send filename - packLEDWord(&packet, 0); // file size - packLEDWord(&packet, 0); - - SAFE_FREE(&szReasonAnsi); - - SendDirectMessage(hContact, &packet); - - NetLog_Direct("Sent file deny direct."); -} - - -int CIcqProto::icq_sendFileSendDirectv7(filetransfer *ft, const char *pszFiles) -{ - icq_packet packet; - char *szFilesAnsi = NULL; - WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = 0; - - if (!utf8_decode(pszFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - else - wFilesLen = strlennull(szFilesAnsi); - - packDirectMsgHeader(&packet, (WORD)(18 + wDescrLen + wFilesLen), DIRECT_MESSAGE, (WORD)ft->dwCookie, MTYPE_FILEREQ, 0, 0, 0); - packLEWord(&packet, (WORD)(wDescrLen + 1)); - packBuffer(&packet, (LPBYTE)ft->szDescription, (WORD)(wDescrLen + 1)); - packLEDWord(&packet, 0); // listen port - packLEWord(&packet, (WORD)(wFilesLen + 1)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packLEDWord(&packet, ft->dwTotalSize); - packLEDWord(&packet, 0); // listen port (again) - - SAFE_FREE(&szFilesAnsi); - - NetLog_Direct("Sending v%u file transfer request direct", 7); - - return SendDirectMessage(ft->hContact, &packet); -} - - -int CIcqProto::icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles) -{ - icq_packet packet; - char *szFilesAnsi = NULL; - WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = 0; - - if (!utf8_decode(pszFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - else - wFilesLen = strlennull(szFilesAnsi); - - packDirectMsgHeader(&packet, (WORD)(0x2E + 22 + wDescrLen + wFilesLen + 1), DIRECT_MESSAGE, (WORD)ft->dwCookie, MTYPE_PLUGIN, 0, 0, 0); - packEmptyMsg(&packet); // message - packPluginTypeId(&packet, MTYPE_FILEREQ); - - packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length - packLEDWord(&packet, wDescrLen); // Description - packBuffer(&packet, (LPBYTE)ft->szDescription, wDescrLen); - packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6 - packWord(&packet, 0x0222); // Unknown, seen 0x2e01 - packLEWord(&packet, (WORD)(wFilesLen + 1)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packLEDWord(&packet, ft->dwTotalSize); - packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000) - - SAFE_FREE(&szFilesAnsi); - - NetLog_Direct("Sending v%u file transfer request direct", 8); - - return SendDirectMessage(ft->hContact, &packet); -} - - -DWORD CIcqProto::icq_SendDirectMessage(HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap) -{ - icq_packet packet; - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - // Pack the standard header - packDirectMsgHeader(&packet, (WORD)(nBodyLength + (szCap ? 53:11)), DIRECT_MESSAGE, dwCookie, (BYTE)pCookieData->bMessageType, 0, 0, 0); - - packLEWord(&packet, (WORD)(nBodyLength+1)); // Length of message - packBuffer(&packet, (LPBYTE)szMessage, (WORD)(nBodyLength+1)); // Message - packMsgColorInfo(&packet); - if (szCap) - { - packLEDWord(&packet, 0x00000026); // length of GUID - packBuffer(&packet, (LPBYTE)szCap, 0x26); // UTF-8 GUID - } - - if (SendDirectMessage(hContact, &packet)) - return dwCookie; // Success - - FreeCookie(dwCookie); // release cookie - return 0; // Failure -} - -void CIcqProto::icq_sendXtrazRequestDirect(HANDLE hContact, DWORD dwCookie, char* szBody, int nBodyLen, WORD wType) -{ - icq_packet packet; - - packDirectMsgHeader(&packet, (WORD)(11 + getPluginTypeIdLen(wType) + nBodyLen), DIRECT_MESSAGE, dwCookie, MTYPE_PLUGIN, 0, 0, 1); - packEmptyMsg(&packet); // message (unused) - packPluginTypeId(&packet, wType); - - packLEDWord(&packet, nBodyLen + 4); - packLEDWord(&packet, nBodyLen); - packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); - - SendDirectMessage(hContact, &packet); -} - -void CIcqProto::icq_sendXtrazResponseDirect(HANDLE hContact, WORD wCookie, char* szBody, int nBodyLen, WORD wType) -{ - icq_packet packet; - - packDirectMsgHeader(&packet, (WORD)(getPluginTypeIdLen(wType) + 11 + nBodyLen), DIRECT_ACK, wCookie, MTYPE_PLUGIN, 0, 0, 0); - // - packEmptyMsg(&packet); // Message (unused) - - packPluginTypeId(&packet, wType); - - packLEDWord(&packet, nBodyLen + 4); - packLEDWord(&packet, nBodyLen); - packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); - - SendDirectMessage(hContact, &packet); -} diff --git a/protocols/IcqOscarJ/docs/icqoscarj-translation.txt b/protocols/IcqOscarJ/docs/icqoscarj-translation.txt new file mode 100644 index 0000000000..520c8a1ce6 --- /dev/null +++ b/protocols/IcqOscarJ/docs/icqoscarj-translation.txt @@ -0,0 +1,1044 @@ +; Common strings that belong to many files +;[%d Files] +;[Add to server list] +;[Arabic] +;[Business] +;[Cancel] +;[Change ICQ Details] +;[Close] +;[Education] +;[Grant authorization] +;[Greek] +;[Hebrew] +;[Homepage] +;[ICQ] +;[ICQ Note] +;[Internet] +;[Japanese] +;[Korean] +;[No description given] +;[OK] +;[Other] +;[Request authorization] +;[Revoke authorization] +;[Thai] +;[Turkish] +;[Vietnamese] +;[Work] +;[Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.] +;[Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.] + +; ../../protocols/IcqOscarJ/UI/askauthentication.cpp +;[Please authorize me to add you to my contact list.] + +; ../../protocols/IcqOscarJ/UI/loginpassword.cpp +;[Enter a password for UIN %u:] + +; ../../protocols/IcqOscarJ/UI/userinfotab.cpp +;[ (DC Established)] +;[%s Details] +;[] +;[Member since:] +;[ScreenName:] + +; ../../protocols/IcqOscarJ/chan_04close.cpp +;[Connection failed.\nSecure (MD5) login is not supported on this account.] +;[Connection failed.\nServer has too many connections from your IP (%d).] +;[Connection failed.\nThe server did not accept this client version.] +;[Connection failed.\nThe server is temporarily unavailable (%d).] +;[Connection failed.\nUnknown error during sign on: 0x%02x] +;[Connection failed.\nYou have connected too quickly,\nplease wait and retry 10 to 20 minutes later (%d).] +;[Connection failed.\nYou were rejected by the server for an unknown reason.\nThis can happen if the UIN is already connected.] +;[Connection failed.\nYour ICQ number or password was rejected (%d).] +;[The server sent warning, this version is getting old.\nTry to look for a new one.] +;[Unable to connect to ICQ communication server] +;[Unable to connect to migrated ICQ communication server] +;[Unknown runtime error: 0x%02x] +;[You could not sign on because the server returned invalid data. Try again.] +;[You have been disconnected from the ICQ network because the current server shut down.] +;[You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number.] + +; ../../protocols/IcqOscarJ/changeinfo/constants.cpp +;[About] +;[Affiliation 1] +;[Affiliation 2] +;[Affiliation 3] +;[Affiliation category 1] +;[Affiliation category 2] +;[Affiliation category 3] +;[Affiliations] +;[Age] +;[April] +;[August] +;[Category 1] +;[Category 2] +;[Category 3] +;[Cellular number] +;[City] +;[Company ZIP/postcode] +;[Company city] +;[Company country] +;[Company department] +;[Company fax] +;[Company homepage] +;[Company industry] +;[Company name] +;[Company occupation] +;[Company phone] +;[Company position] +;[Company state] +;[Company street] +;[Contact] +;[Country] +;[Day of birth] +;[December] +;[Degree] +;[Fax number] +;[February] +;[First name] +;[GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca] +;[GMT+0:30] +;[GMT+10:00 East Australia; Guam; Vladivostok] +;[GMT+10:30] +;[GMT+11:00 Magadan; Solomon Is.; New Caledonia] +;[GMT+11:30] +;[GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is.] +;[GMT+1:00 Central European Time; West Central Africa; Warsaw] +;[GMT+1:30] +;[GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens] +;[GMT+2:30] +;[GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad] +;[GMT+3:30 Tehran] +;[GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat] +;[GMT+4:30 Kabul] +;[GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg] +;[GMT+5:30] +;[GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk; Sri Jayawardenepura] +;[GMT+6:30 Rangoon] +;[GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk] +;[GMT+7:30] +;[GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing] +;[GMT+8:30] +;[GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk] +;[GMT+9:30 Darwin; Adelaide] +;[GMT-0:30] +;[GMT-10:00 Hawaii] +;[GMT-10:30] +;[GMT-11:00 Midway Island; Samoa] +;[GMT-11:30] +;[GMT-12:00 Eniwetok; Kwajalein] +;[GMT-1:00 Cape Verde Islands; Azores] +;[GMT-1:30] +;[GMT-2:00 Mid-Atlantic] +;[GMT-2:30] +;[GMT-3:00 Greenland; Buenos Aires; Georgetown] +;[GMT-3:30 Newfoundland] +;[GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz] +;[GMT-4:30] +;[GMT-5:00 Eastern Time; Bogota; Lima; Quito] +;[GMT-5:30] +;[GMT-6:00 Central Time; Central America; Saskatchewan] +;[GMT-6:30] +;[GMT-7:00 Arizona; Mountain Time] +;[GMT-7:30] +;[GMT-8:00 Pacific Time; Tijuana] +;[GMT-8:30] +;[GMT-9:00 Alaska] +;[GMT-9:30] +;[Gender] +;[Graduation Year] +;[Institute] +;[Interest areas 1] +;[Interest areas 2] +;[Interest areas 3] +;[Interest areas 4] +;[Interest category 1] +;[Interest category 2] +;[Interest category 3] +;[Interest category 4] +;[January] +;[July] +;[June] +;[Last name] +;[Level] +;[March] +;[Marital Status] +;[May] +;[Month of birth] +;[Nickname] +;[November] +;[October] +;[Originally from] +;[Password] +;[Past Background] +;[Past Background 1] +;[Past Background 2] +;[Past Background 3] +;[Personal] +;[Personal Detail] +;[Personal Interests] +;[Phone number] +;[Primary e-mail] +;[Secondary e-mail] +;[September] +;[Spoken language 1] +;[Spoken language 2] +;[Spoken language 3] +;[State] +;[Street] +;[Tertiary e-mail] +;[Timezone] +;[Year of birth] +;[ZIP/postcode] + +; ../../protocols/IcqOscarJ/changeinfo/db.cpp +;[The ICQ server does not support passwords longer than 8 characters. Please use a shorter password.] +;[The password does not match the password you originally entered. Check Caps Lock and try again.] +;[The password does not match your current password. Check Caps Lock and try again.] + +; ../../protocols/IcqOscarJ/changeinfo/dlgproc.cpp +;[] +;[] +;[Unknown value] +;[Unspecified] +;[Upload FAILED] +;[Upload complete] +;[Upload in progress...] +;[You've made some changes to your ICQ details but it has not been saved to the server. Are you sure you want to close this dialog?] + +; ../../protocols/IcqOscarJ/changeinfo/upload.cpp +;[You are not currently connected to the ICQ network. You must be online in order to update your information on the server.] + +; ../../protocols/IcqOscarJ/fam_01service.cpp +;[A server migration has failed because the server returned invalid data. You must reconnect manually.] +;[Failed to request offline messages. They may be received next time you log in.] + +; ../../protocols/IcqOscarJ/fam_03buddy.cpp +;[Contact deleted & further events blocked.] +;[Spambot Detected] + +; ../../protocols/IcqOscarJ/fam_04message.cpp +;[Contact \"%s\" has closed the message window.] +;[Incoming URL:] +;[SNAC(4.1) SENDMSG Error (x%02x)] +;[The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E] +;[The contact does not support receiving offline messages.] +;[The messaging service is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x05] +;[The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09] +;[The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04] +;[The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13] +;[You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x02] +;[You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x03] +;[You sent too long message. The receiving client does not support it.\r\nSNAC(4.1) Error x0A] + +; ../../protocols/IcqOscarJ/fam_13servclist.cpp +;[Adding of contact to server list failed.] +;[Adding of group to server list failed.] +;[Adding of privacy item to server list failed.] +;[Contact \"%s\" lost its authorization in the server list.] +;[Contact \"%s\" was authorized in the server list.] +;[Moving of user to another group on server list failed.] +;[Removing of contact from server list failed.] +;[Removing of group from server list failed.] +;[Removing of privacy item from server list failed.] +;[Renaming of server group failed.] +;[Server contact list is unavailable, Miranda will use local contact list.] +;[Updating of group on server list failed.] +;[Updating of server contact failed.] +;[User \"%s\" was removed from server list.] + +; ../../protocols/IcqOscarJ/fam_17signon.cpp +;[Secure login failed.\nInvalid key length.] +;[Secure login failed.\nInvalid server response.] + +; ../../protocols/IcqOscarJ/icq_avatar.cpp +;[Error uploading avatar to server, server refused to accept the image.] +;[Error uploading avatar to server, server temporarily unavailable.] + +; ../../protocols/IcqOscarJ/icq_fieldnames.cpp +;[50's] +;[60's] +;[60-above] +;[70's] +;[80's] +;[Academic] +;[Administrative] +;[Afghanistan] +;[Afrikaans] +;[Agriculture] +;[Albania] +;[Albanian] +;[Algeria] +;[Alumni Org.] +;[Andorra] +;[Angola] +;[Anguilla] +;[Antigua and Barbuda] +;[Antilles] +;[Argentina] +;[Armenia] +;[Armenian] +;[Art] +;[Art/Entertainment] +;[Arts] +;[Aruba] +;[Ascension Island] +;[Associated degree] +;[Astronomy] +;[Audio and Visual] +;[Australia] +;[Australia, Antarctic Territory] +;[Australia, Christmas Island] +;[Australia, Cocos (Keeling) Islands] +;[Australia, Norfolk Island] +;[Austria] +;[Azerbaijan] +;[Azerbaijani] +;[Bachelor's degree] +;[Bahamas] +;[Bahrain] +;[Bangladesh] +;[Barbados] +;[Barbuda] +;[Belarus] +;[Belgium] +;[Belize] +;[Belorussian] +;[Benin] +;[Bermuda] +;[Bhojpuri] +;[Bhutan] +;[Bolivia] +;[Bosnia and Herzegovina] +;[Bosnian] +;[Botswana] +;[Brazil] +;[British Virgin Islands] +;[Brunei] +;[Bulgaria] +;[Bulgarian] +;[Burkina Faso] +;[Burmese] +;[Burundi] +;[Business Services] +;[Cambodia] +;[Cameroon] +;[Canada] +;[Canary Islands] +;[Cantonese] +;[Cape Verde Islands] +;[Cars] +;[Catalan] +;[Cayman Islands] +;[Celebrity Fans] +;[Central African Republic] +;[Chad] +;[Chamorro] +;[Charity Org.] +;[Chile, Republic of] +;[China] +;[Chinese] +;[Close relationships] +;[Clothing] +;[Club/Social Org.] +;[Cocos (Keeling) Islands] +;[Collections] +;[College] +;[College Student] +;[Colombia] +;[Community & Social] +;[Community Org.] +;[Comoros] +;[Computers] +;[Congo, Democratic Republic of (Zaire)] +;[Congo, Republic of the] +;[Construction] +;[Consumer Goods] +;[Cook Islands] +;[Corporate Services] +;[Costa Rica] +;[Cote d'Ivoire (Ivory Coast)] +;[Croatia] +;[Croatian] +;[Cuba] +;[Cultural Org.] +;[Culture] +;[Curacao] +;[Czech] +;[Czech Republic] +;[Danish] +;[Denmark] +;[Diego Garcia] +;[Divorced] +;[Djibouti] +;[Dominica] +;[Dominican Republic] +;[Dutch] +;[Ecology] +;[Ecuador] +;[Egypt] +;[El Salvador] +;[Elementary] +;[Elementary School] +;[Engaged] +;[Engineering] +;[English] +;[Entertainment] +;[Equatorial Guinea] +;[Eritrea] +;[Esperanto] +;[Estonia] +;[Estonian] +;[Ethiopia] +;[Europe] +;[Faeroe Islands] +;[Falkland Islands] +;[Fan Clubs] +;[Farsi] +;[Female] +;[Fiji] +;[Finance] +;[Finance and Corporate] +;[Financial Services] +;[Finland] +;[Finnish] +;[Fitness] +;[France] +;[Fraternity/Sorority] +;[French] +;[French Antilles] +;[French Guiana] +;[French Polynesia] +;[Gabon] +;[Gaelic] +;[Gambia] +;[Games] +;[Georgia] +;[German] +;[Germany] +;[Ghana] +;[Gibraltar] +;[Government] +;[Greece] +;[Greek, Republic of South Cyprus] +;[Greenland] +;[Grenada] +;[Guadeloupe] +;[Guam, US Territory of] +;[Guatemala] +;[Guinea] +;[Guinea-Bissau] +;[Gujarati] +;[Guyana] +;[Haiti] +;[Health and Beauty] +;[High School] +;[High School Student] +;[High Tech] +;[High-school] +;[Hindi] +;[Hobbies] +;[Hobbyists Org.] +;[Home] +;[Home Automation] +;[Honduras] +;[Hong Kong] +;[Household Products] +;[Hungarian] +;[Hungary] +;[ICQ - Help] +;[ICQ - Providing Help] +;[Iceland] +;[Icelandic] +;[India] +;[Indonesia] +;[Indonesian] +;[International Org.] +;[Iran (Islamic Republic of)] +;[Iraq] +;[Ireland] +;[Israel] +;[Italian] +;[Italy] +;[Jamaica] +;[Japan] +;[Jordan] +;[Kazakhstan] +;[Kenya] +;[Khmer] +;[Kiribati] +;[Korea, North] +;[Korea, South] +;[Kosovo, Republic of] +;[Kurdish] +;[Kuwait] +;[Kyrgyzstan] +;[Lao] +;[Laos] +;[Latvia] +;[Latvian] +;[Law] +;[Lebanon] +;[Legal] +;[Lesotho] +;[Liberia] +;[Libyan Arab Jamahiriya] +;[Liechtenstein] +;[Lifestyle] +;[Lithuania] +;[Lithuanian] +;[Luxembourg] +;[Macau] +;[Macedonia, Republic of] +;[Macedonian] +;[Madagascar] +;[Mail Order Catalog] +;[Malawi] +;[Malay] +;[Malaysia] +;[Maldives] +;[Male] +;[Mali] +;[Malta] +;[Managerial] +;[Mandarin] +;[Manufacturing] +;[Married] +;[Marshall Islands] +;[Martinique] +;[Master's degree] +;[Mauritania] +;[Mauritius] +;[Mayotte Island] +;[Media] +;[Medical & Health Care] +;[Medical/Health] +;[Mexico] +;[Micronesia, Federated States of] +;[Military] +;[Moldova, Republic of] +;[Monaco] +;[Mongolia] +;[Mongolian] +;[Montenegro, Republic of] +;[Montserrat] +;[Morocco] +;[Movies and TV] +;[Mozambique] +;[Music] +;[Myanmar] +;[Mystics] +;[Namibia] +;[Nature and Environment Org.] +;[Nauru] +;[Nepal] +;[Netherlands] +;[Netherlands (Bonaire Island)] +;[Netherlands (Saba Island)] +;[Netherlands (St. Eustatius Island)] +;[Netherlands Antilles] +;[Nevis] +;[New Caledonia] +;[New Zealand] +;[News and Media] +;[Nicaragua] +;[Niger] +;[Nigeria] +;[Niue] +;[Non-Government Organization] +;[Non-Profit Organization Management] +;[Northern Mariana Islands, US Territory of] +;[Norway] +;[Norwegian] +;[Oman] +;[Open relationship] +;[Other Services] +;[Outdoors] +;[Pakistan] +;[Palau] +;[Panama] +;[Papua New Guinea] +;[Paraguay] +;[Parenting] +;[Parties] +;[Past Organization] +;[Past Work Place] +;[Persian] +;[Peru] +;[Pets and Animals] +;[PhD] +;[Philippines] +;[Poland] +;[Polish] +;[Portugal] +;[Portuguese] +;[Postdoctoral] +;[Professional] +;[Professional Org.] +;[Publishing] +;[Puerto Rico] +;[Punjabi] +;[Qatar] +;[Recreation, Travel & Entertainment] +;[Religion] +;[Retail] +;[Retail Stores] +;[Retired] +;[Reunion Island] +;[Romania] +;[Romanian] +;[Rota Island] +;[Russia] +;[Russian] +;[Rwanda] +;[Saint Helena] +;[Saint Kitts] +;[Saint Kitts and Nevis] +;[Saint Lucia] +;[Saint Pierre and Miquelon] +;[Saint Vincent and the Grenadines] +;[Saipan Island] +;[Samoa (USA)] +;[Samoa, Western] +;[San Marino] +;[Sao Tome and Principe] +;[Saudi Arabia] +;[Science] +;[Science & Research] +;[Scientific/Technical Org.] +;[Scotland] +;[Self Improvement Group] +;[Senegal] +;[Separated] +;[Serbia, Republic of] +;[Serbian] +;[Service Industry] +;[Seychelles] +;[Sierra Leone] +;[Sindhi] +;[Singapore] +;[Single] +;[Skills] +;[Slovak] +;[Slovakia] +;[Slovenia] +;[Slovenian] +;[Social science] +;[Solomon Islands] +;[Somali] +;[Somalia] +;[South Africa] +;[Space] +;[Spain] +;[Spain, Canary Islands] +;[Spanish] +;[Spiritual/Religious Org.] +;[Sporting and Athletic] +;[Sports] +;[Sports Org.] +;[Sri Lanka] +;[St. Maarten] +;[Sudan] +;[Support Org.] +;[Suriname] +;[Swahili] +;[Swaziland] +;[Sweden] +;[Swedish] +;[Switzerland] +;[Syrian Arab Republic] +;[Tagalog] +;[Taiwan] +;[Taiwanese] +;[Tajikistan] +;[Tamil] +;[Tanzania] +;[Tatar] +;[Technical] +;[Thailand] +;[Timor, East] +;[Tinian Island] +;[Togo] +;[Tokelau] +;[Tonga] +;[Trade and Business Org.] +;[Transportation] +;[Travel] +;[Trinidad and Tobago] +;[Tunisia] +;[Turkey] +;[Turkey, Republic of Northern Cyprus] +;[Turkmenistan] +;[Turks and Caicos Islands] +;[Tuvalu] +;[USA] +;[Uganda] +;[Ukraine] +;[Ukrainian] +;[Union] +;[United Arab Emirates] +;[United Kingdom] +;[University] +;[University / College] +;[University Student] +;[Urdu] +;[Uruguay] +;[Uzbekistan] +;[Vanuatu] +;[Vatican City] +;[Venezuela] +;[Vietnam] +;[Virgin Islands (UK)] +;[Virgin Islands (USA)] +;[Volunteer Org.] +;[Wales] +;[Wallis and Futuna Islands] +;[Web Building] +;[Web Design] +;[Welsh] +;[Widowed] +;[Women] +;[Yemen] +;[Yiddish] +;[Yoruba] +;[Yugoslavia] +;[Zambia] +;[Zimbabwe] + +; ../../protocols/IcqOscarJ/icq_menu.cpp +;[Open ICQ profile] +;[Show custom status details] + +; ../../protocols/IcqOscarJ/icq_opts.cpp +;[Account] +;[Baltic] +;[Central European] +;[Contacts] +;[Cyrillic] +;[Display all problems] +;[Display explanations for disconnection] +;[Display problems causing possible loss of data] +;[Display problems requiring user intervention] +;[Do not display any problems (not recommended)] +;[Features] +;[Korean (Johab)] +;[Latin I] +;[Network] +;[Popups] +;[Privacy] +;[Simplified Chinese] +;[System default codepage] +;[Traditional Chinese] + +; ../../protocols/IcqOscarJ/icq_popups.cpp +;[Popup Title] +;[Sample Error] +;[Sample Fatal] +;[Sample Note] +;[Sample Spambot] +;[Sample Warning] + +; ../../protocols/IcqOscarJ/icq_proto.cpp +;[%s client-to-client connections] +;[%s server connection] +;[User ID] +;[You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again.] + +; ../../protocols/IcqOscarJ/icq_server.cpp +;[Connection failed.\nLogin sequence failed for unknown reason.\nTry again later.] +;[Miranda was unable to allocate a port to listen for direct peer-to-peer connections between clients. You will be able to use most of the ICQ network without problems but you may be unable to send or receive files.\n\nIf you have a firewall this may be blocking Miranda, in which case you should configure your firewall to leave some ports open and tell Miranda which ports to use in M->Options->ICQ->Network.] +;[Unable to connect to ICQ login server] +;[Unable to connect to ICQ login server, SSL could not be negotiated] +;[Your connection with the ICQ server was abortively closed] + +; ../../protocols/IcqOscarJ/icq_servlist.cpp +;[Failed to create the correct sub-group, the using closest parent group.] +;[The contact's information was too big and was truncated.] + +; ../../protocols/IcqOscarJ/icq_uploadui.cpp +;[** All contacts **] +;[ALREADY EXISTS] +;[Adding %s to invisible list...] +;[Adding %s to visible list...] +;[Adding group \"%s\"...] +;[All operations complete] +;[Cleaning groups] +;[Deleting %s from invisible list...] +;[Deleting %s from visible list...] +;[Deleting %s...] +;[Deleting group \"%s\"...] +;[FAILED] +;[INVALID DATA] +;[LIST FULL] +;[Moving %s to group \"%s\"...] +;[NOT FOUND] +;[No upload group available] +;[Ready...] +;[Select contacts you want to store on server.] +;[Server rate warning -> slowing down the process.] +;[Updating group \"%s\"...] +;[Uploading %s...] +;[You have to be online to sychronize the server-list !] + +; ../../protocols/IcqOscarJ/icq_xstatus.cpp +;[%s Custom Status] +;[@home] +;[@work] +;[Afro] +;[Alien] +;[Angel] +;[Angry] +;[Baby] +;[Basketball] +;[Beetle] +;[Birdie] +;[Birthday] +;[Broken hearted] +;[Candy] +;[Celebrating] +;[Cocktail] +;[Coffee] +;[Cooking] +;[Cool] +;[Crazy Professor] +;[Cupid shot me] +;[Cyclop] +;[Depressed] +;[Dog] +;[Donut] +;[Double Rainbow] +;[Drinking beer] +;[Eating] +;[Evil] +;[Feeling Good] +;[Feeling sick] +;[Free for Chat] +;[Gaming] +;[Having fun] +;[Headmaster] +;[Hot Dog] +;[I'm high] +;[Ice-Cream] +;[Kitty] +;[Laughing] +;[Lips] +;[Listening to music] +;[Lollypop] +;[Love] +;[Mask] +;[Meeting] +;[Money] +;[Monkey] +;[Ninja] +;[None] +;[Oink Oink] +;[On WC] +;[On my mobile] +;[On the phone] +;[Picnic] +;[Pilot] +;[Pink Lady] +;[Pirate] +;[Pizza] +;[Playing] +;[Punch] +;[Rock On] +;[Rough] +;[Scooter] +;[Shooting] +;[Shopping] +;[Sleeping] +;[Smoking] +;[Snoring] +;[Soccer] +;[St. Patrick] +;[Strawberry] +;[Studying] +;[Sumo] +;[Surfing] +;[Sushi] +;[Taking a bath] +;[Thinking] +;[Tired] +;[To be or not to be] +;[Typing] +;[Up yours] +;[Watching TV] +;[Watching pro7 on TV] +;[Working] +;[Writing] + +; ../../protocols/IcqOscarJ/icq_xtraz.cpp +;[Greeting card:] + +; ../../protocols/IcqOscarJ/icqosc_svcs.cpp +;[** This message was blocked by the ICQ server ** The message was invalid.] +;[** This message was blocked by the ICQ server ** The message was too long.] +;[** This message was blocked by the ICQ server ** The sender has flooded the server.] +;[** This message was blocked by the ICQ server ** You are too evil.] +;[** Unknown missed message event.] +;[Are you sure you want to revoke user's authorization (this will remove you from his/her list on some clients) ?] +;[Confirmation] + +; ../../protocols/IcqOscarJ/init.cpp +;[ICQ Plugin] +;[You cannot use Unicode version of ICQ Protocol plug-in with Ansi version of Miranda IM.] + +; ../../protocols/IcqOscarJ/log.cpp +;[ICQ Error] +;[ICQ Fatal] +;[ICQ Warning] +;[Miranda was unable to make a connection with a server. It is likely that the server is down, in which case you should wait for a while and try again later.] +;[Miranda was unable to resolve the name of a server to its numeric address. This is most likely caused by a catastrophic loss of your network connection (for example, your modem has disconnected), but if you are behind a proxy, you may need to use the 'Resolve hostnames through proxy' option in M->Options->Network.] +;[The connection with the server was abortively closed during the connection attempt. You may have lost your local network connection.] +;[The server did not respond to the connection attempt within a reasonable time, it may be temporarily down. Try again later.] +;[The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ.] +;[Your proxy rejected the user name and password that you provided. Please check them in M->Options->Network.] +;[error] + +; ../../protocols/IcqOscarJ/oscar_filetransfer.cpp +;[Connection lost during file transfer.] +;[Failed to Initialize File Transfer. No valid files were specified.] +;[Failed to Initialize File Transfer. Unable to bind local port and File proxy unavailable.] +;[File transfer negotiation failed for unknown reason.] +;[The checksum of file \"%s\" does not match, the file is probably damaged.] +;[The file transfer failed: Invalid request] +;[The file transfer failed: Proxy error] +;[The file transfer failed: Proxy unavailable] +;[The file transfer was aborted by the other user.] +;[The files are too big to be sent at once. Files bigger than 4GB can be sent only separately.] + +; ../../protocols/IcqOscarJ/resources.rc +;[&Cancel] +;[&Save changes] +;[&Send] +;[&Use Windows colors] +;[(*) Timeouts require Popup v. 1.0.1.9 or later] +;[Add contacts to the server's list when I add them to mine] +;[Age:] +;[All users may add me to their Contact List] +;[Allow direct connections only when I authorize or initiate them] +;[Allow direct connections with any user] +;[Allow direct connections with users on my contact list] +;[Allow others to view my Online / Offline status from the web (Web Aware)] +;[Allow others to view my primary e-mail address] +;[Allowing direct connections will expose your IP address but may be necessary for some ICQ features to work properly.] +;[Auto-retrieve Custom status details] +;[Back Color] +;[Background info] +;[Block known Spam Bots] +;[Category:] +;[Check avatar validity before saving *] +;[City:] +;[Closing in %d] +;[Company:] +;[Confirm Password Change] +;[Connection settings] +;[Contact List Authorization] +;[Country:] +;[Create a new ICQ account] +;[Create a new ICQ account using the ICQ website] +;[Custom Status \"%s\" Details] +;[Default] +;[Department:] +;[Direct connections] +;[Display errors using popups] +;[Display popup when spambot is detected] +;[E-mail:] +;[Enable AIM contacts support] +;[Enable Custom status support for moods] +;[Enable Custom status support for xtraz] +;[Enable avatar support] +;[Enable peer-to-peer message connections] +;[Enable popup support] +;[Enable server-side contact lists *] +;[Enable unicode messaging support] +;[Enter ICQ Password] +;[Enter a password for UIN %d:] +;[Enter an authorization request] +;[Enter your current password:] +;[Error] +;[External IP:] +;[Extra Features] +;[Fatal] +;[First name:] +;[Gender:] +;[Hint: If you don't enter your password here, Miranda will ask for the password everytime you try to go online.] +;[Hint: Use port 0 to connect on a random port. Try port 80 or port 443 if you are having problems connecting through a http proxy server.] +;[I want to be asked when someone wants to add me to their Contact List] +;[ICQ Number:] +;[ICQ avatars] +;[ICQ contacts stored on server] +;[ICQ number:] +;[Idle since:] +;[Ignore concurrent error messages] +;[Interests] +;[Internal IP:] +;[Keywords:] +;[Language:] +;[Last name:] +;[Load avatars automatically (like ICQ Lite)] +;[Location] +;[Login Server:] +;[Look && Feel] +;[Make me temporarily visible to contacts I send message to] +;[Manage ICQ Server Contacts] +;[Manage server's list...] +;[Marital status:] +;[Message:] +;[Messaging] +;[Misc Settings] +;[Never use legacy messaging (server acknowledgements)] +;[Nickname:] +;[Note] +;[Note: The options marked with an asterisk have important side-effects or caveats that may not be initially apparent documented in the help.] +;[Notify me when a message delivery has failed (recommended)] +;[Occupation:] +;[Online since:] +;[Only reply to status message request from visible contacts] +;[Only reply to status message requests from users on my contact list] +;[Options] +;[Organisation:] +;[Passive mode, i.e. do not initiate new connections] +;[Password:] +;[Past] +;[Peer-to-peer Messaging] +;[Please re-type your new password:] +;[Port:] +;[Position:] +;[Previe&w] +;[Protocol Version:] +;[Remember this session password] +;[Reset Custom status on status change] +;[Retrieve a lost password or ICQ number] +;[Retrieving custom status details...] +;[Search online users only] +;[Secure (MD5) login] +;[Secure Connection (SSL)] +;[Select contacts to store:] +;[Send 'Keep-alives' (enable this if you use a proxy server and frequently get disconnected)] +;[Send all messages in unicode if possible] +;[Show connection error messages:] +;[Slider1] +;[Some options are greyed out because they can only be changed when you are online.] +;[Spam detected] +;[State:] +;[Status:] +;[Summary] +;[Synchronize] +;[System up since:] +;[Text Color] +;[Timeout (*)] +;[Title:] +;[UIN:] +;[Update contacts' details on the server's list when I change them in mine] +;[Update my contacts' details from the server *] +;[Use system &icons] +;[Use this codepage for Ansi <-> Unicode translation :] +;[User Client:] +;[Warning] +;[You cannot enable/disable the server-side contact list while you are connected to the ICQ network.] +;[You will need to reconnect to the ICQ network for the changes you have made on this page to take effect.] + +; ../../protocols/IcqOscarJ/utilities.cpp +;[] diff --git a/protocols/IcqOscarJ/fam_01service.cpp b/protocols/IcqOscarJ/fam_01service.cpp deleted file mode 100755 index 9bc06f19ab..0000000000 --- a/protocols/IcqOscarJ/fam_01service.cpp +++ /dev/null @@ -1,983 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packets from Service family -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" -#include - -extern capstr capXStatus[]; - -void CIcqProto::handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) -{ - icq_packet packet; - - switch (pSnacHeader->wSubtype) { - - case ICQ_SERVER_READY: -#ifdef _DEBUG - NetLog_Server("Server is ready and is requesting my Family versions"); - NetLog_Server("Sending my Families"); -#endif - - // This packet is a response to SRV_FAMILIES SNAC(1,3). - // This tells the server which SNAC families and their corresponding - // versions which the client understands. This also seems to identify - // the client as an ICQ vice AIM client to the server. - // Miranda mimics the behaviour of ICQ 6 - serverPacketInit(&packet, 54); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES); - packDWord(&packet, 0x00220001); - packDWord(&packet, 0x00010004); - packDWord(&packet, 0x00130004); - packDWord(&packet, 0x00020001); - packDWord(&packet, 0x00030001); - packDWord(&packet, 0x00150001); - packDWord(&packet, 0x00040001); - packDWord(&packet, 0x00060001); - packDWord(&packet, 0x00090001); - packDWord(&packet, 0x000a0001); - packDWord(&packet, 0x000b0001); - sendServPacket(&packet); - break; - - case ICQ_SERVER_FAMILIES2: - /* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands. - * We send a rate request packet */ -#ifdef _DEBUG - NetLog_Server("Server told me his Family versions"); - NetLog_Server("Requesting Rate Information"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO); - sendServPacket(&packet); - break; - - case ICQ_SERVER_RATE_INFO: -#ifdef _DEBUG - NetLog_Server("Server sent Rate Info"); -#endif - /* init rates management */ - m_rates = new rates(this, pBuffer, wBufferLength); - /* ack rate levels */ -#ifdef _DEBUG - NetLog_Server("Sending Rate Info Ack"); -#endif - m_rates->initAckPacket(&packet); - sendServPacket(&packet); - - /* CLI_REQINFO - This command requests from the server certain information about the client that is stored on the server. */ -#ifdef _DEBUG - NetLog_Server("Sending CLI_REQINFO"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQINFO); - sendServPacket(&packet); - - if (m_bSsiEnabled) - { - cookie_servlist_action* ack; - DWORD dwCookie; - - DWORD dwLastUpdate = getSettingDword(NULL, "SrvLastUpdate", 0); - WORD wRecordCount = getSettingWord(NULL, "SrvRecordCount", 0); - - // CLI_REQLISTS - we want to use SSI -#ifdef _DEBUG - NetLog_Server("Requesting roster rights"); -#endif - serverPacketInit(&packet, 16); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQLISTS); - packTLVWord(&packet, 0x0B, 0x000F); // mimic ICQ 6 - sendServPacket(&packet); - - if (!wRecordCount) // CLI_REQROSTER - { // we do not have any data - request full list -#ifdef _DEBUG - NetLog_Server("Requesting full roster"); -#endif - serverPacketInit(&packet, 10); - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { // we try to use standalone cookie if available - ack->dwAction = SSA_CHECK_ROSTER; // loading list - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_REQUEST, 0, ack); - } - else // if not use that old fake - dwCookie = ICQ_LISTS_CLI_REQUEST<<0x10; - - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQUEST, 0, dwCookie); - sendServPacket(&packet); - } - else // CLI_CHECKROSTER - { -#ifdef _DEBUG - NetLog_Server("Requesting roster check"); -#endif - serverPacketInit(&packet, 16); - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) // TODO: rewrite - use get list service for empty list - { // we try to use standalone cookie if available - ack->dwAction = SSA_CHECK_ROSTER; // loading list - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_CHECK, 0, ack); - } - else // if not use that old fake - dwCookie = ICQ_LISTS_CLI_CHECK<<0x10; - - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_CHECK, 0, dwCookie); - // check if it was not changed elsewhere (force reload, set that setting to zero) - if (IsServerGroupsDefined()) - { - packDWord(&packet, dwLastUpdate); // last saved time - packWord(&packet, wRecordCount); // number of records saved - } - else - { // we need to get groups info into DB, force receive list - packDWord(&packet, 0); // last saved time - packWord(&packet, 0); // number of records saved - } - sendServPacket(&packet); - } - } - - // CLI_REQLOCATION -#ifdef _DEBUG - NetLog_Server("Requesting Location rights"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_CLI_REQ_RIGHTS); - sendServPacket(&packet); - - // CLI_REQBUDDY -#ifdef _DEBUG - NetLog_Server("Requesting Client-side contactlist rights"); -#endif - serverPacketInit(&packet, 16); - packFNACHeader(&packet, ICQ_BUDDY_FAMILY, ICQ_USER_CLI_REQBUDDY); - // Query flags: 1 = Enable Avatars - // 2 = Enable offline status message notification - // 4 = Enable Avatars for offline contacts - // 8 = Use reject for not authorized contacts - packTLVWord(&packet, 0x05, 0x0007); - sendServPacket(&packet); - - // CLI_REQICBM -#ifdef _DEBUG - NetLog_Server("Sending CLI_REQICBM"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQICBM); - sendServPacket(&packet); - - // CLI_REQBOS -#ifdef _DEBUG - NetLog_Server("Sending CLI_REQBOS"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_BOS_FAMILY, ICQ_PRIVACY_REQ_RIGHTS); - sendServPacket(&packet); - break; - - case ICQ_SERVER_PAUSE: - NetLog_Server("Server is going down in a few seconds... (Flags: %u)", pSnacHeader->wFlags); - // This is the list of groups that we want to have on the next server - serverPacketInit(&packet, 30); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_PAUSE_ACK); - packWord(&packet,ICQ_SERVICE_FAMILY); - packWord(&packet,ICQ_LISTS_FAMILY); - packWord(&packet,ICQ_LOCATION_FAMILY); - packWord(&packet,ICQ_BUDDY_FAMILY); - packWord(&packet,ICQ_EXTENSIONS_FAMILY); - packWord(&packet,ICQ_MSG_FAMILY); - packWord(&packet,0x06); - packWord(&packet,ICQ_BOS_FAMILY); - packWord(&packet,ICQ_LOOKUP_FAMILY); - packWord(&packet,ICQ_STATS_FAMILY); - sendServPacket(&packet); -#ifdef _DEBUG - NetLog_Server("Sent server pause ack"); -#endif - break; - - case ICQ_SERVER_MIGRATIONREQ: - { -#ifdef _DEBUG - NetLog_Server("Server migration requested (Flags: %u)", pSnacHeader->wFlags); -#endif - pBuffer += 2; // Unknown, seen: 0 - wBufferLength -= 2; - - oscar_tlv_chain *chain = readIntoTLVChain(&pBuffer, wBufferLength, 0); - - if (info->cookieDataLen > 0) - SAFE_FREE((void**)&info->cookieData); - - info->newServer = chain->getString(0x05, 1); - info->newServerSSL = chain->getNumber(0x8E, 1); - info->cookieData = (BYTE*)chain->getString(0x06, 1); - info->cookieDataLen = chain->getLength(0x06, 1); - - disposeChain(&chain); - - if (!info->newServer || !info->cookieData) - { - icq_LogMessage(LOG_FATAL, LPGEN("A server migration has failed because the server returned invalid data. You must reconnect manually.")); - SAFE_FREE(&info->newServer); - SAFE_FREE((void**)&info->cookieData); - info->cookieDataLen = 0; - info->newServerReady = 0; - return; - } - - NetLog_Server("Migration has started. New server will be %s", info->newServer); - - m_iDesiredStatus = m_iStatus; - SetCurrentStatus(ID_STATUS_CONNECTING); // revert to connecting state - - info->newServerReady = 1; - info->isMigrating = 1; - } - break; - - case ICQ_SERVER_NAME_INFO: // This is the reply to CLI_REQINFO - { - BYTE bUinLen; - oscar_tlv_chain *chain; - -#ifdef _DEBUG - NetLog_Server("Received self info"); -#endif - unpackByte(&pBuffer, &bUinLen); - pBuffer += bUinLen; - pBuffer += 4; /* warning level & user class */ - wBufferLength -= 5 + bUinLen; - - if (pSnacHeader->dwRef == ICQ_CLIENT_REQINFO<<0x10) - { // This is during the login sequence - DWORD dwValue; - - // TLV(x01) User type? - // TLV(x0C) Empty CLI2CLI Direct connection info - // TLV(x0A) External IP - // TLV(x0F) Number of seconds that user has been online - // TLV(x03) The online since time. - // TLV(x0A) External IP again - // TLV(x22) Unknown - // TLV(x1E) Unknown: empty. - // TLV(x05) Member of ICQ since. - // TLV(x14) Unknown - chain = readIntoTLVChain(&pBuffer, wBufferLength, 0); - - // Save external IP - dwValue = chain->getDWord(0x0A, 1); - setSettingDword(NULL, "IP", dwValue); - - // Save member since timestamp - dwValue = chain->getDWord(0x05, 1); - if (dwValue) setSettingDword(NULL, "MemberTS", dwValue); - - dwValue = chain->getDWord(0x03, 1); - setSettingDword(NULL, "LogonTS", dwValue ? dwValue : time(NULL)); - - disposeChain(&chain); - - // If we are in SSI mode, this is sent after the list is acked instead - // to make sure that we don't set status before seing the visibility code - if (!m_bSsiEnabled || info->isMigrating) - handleServUINSettings(wListenPort, info); - } - else if (m_hNotifyNameInfoEvent) - // Just notify that the set status note & mood process is finished - SetEvent(m_hNotifyNameInfoEvent); - } - break; - - case ICQ_SERVER_RATE_CHANGE: - - if (wBufferLength >= 2) - { - WORD wStatus; - WORD wClass; - DWORD dwLevel; - // We now have global rate management, although controlled are only some - // areas. This should not arrive in most cases. If it does, update our - // local rate levels & issue broadcast. - unpackWord(&pBuffer, &wStatus); - unpackWord(&pBuffer, &wClass); - pBuffer += 20; - unpackDWord(&pBuffer, &dwLevel); - - m_ratesMutex->Enter(); - m_rates->updateLevel(wClass, dwLevel); - m_ratesMutex->Leave(); - - if (wStatus == 2 || wStatus == 3) - { // this is only the simplest solution, needs rate management to every section - BroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus); - if (wStatus == 2) - NetLog_Server("Rates #%u: Alert", wClass); - else - NetLog_Server("Rates #%u: Limit", wClass); - } - else if (wStatus == 4) - { - BroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus); - NetLog_Server("Rates #%u: Clear", wClass); - } - } - - break; - - case ICQ_SERVER_REDIRECT_SERVICE: // reply to family request, got new connection point - { - oscar_tlv_chain *pChain = NULL; - cookie_family_request *pCookieData; - - if (!(pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0))) - { - NetLog_Server("Received Broken Redirect Service SNAC(1,5)."); - break; - } - WORD wFamily = pChain->getWord(0x0D, 1); - - // pick request data - if ((!FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) || (pCookieData->wFamily != wFamily)) - { - disposeChain(&pChain); - NetLog_Server("Received unexpected SNAC(1,5), skipping."); - break; - } - - FreeCookie(pSnacHeader->dwRef); - - { // new family entry point received - char *pServer = pChain->getString(0x05, 1); - BYTE bServerSSL = pChain->getNumber(0x8E, 1); - char *pCookie = pChain->getString(0x06, 1); - WORD wCookieLen = pChain->getLength(0x06, 1); - - if (!pServer || !pCookie) - { - NetLog_Server("Server returned invalid data, family unavailable."); - - SAFE_FREE(&pServer); - SAFE_FREE(&pCookie); - SAFE_FREE((void**)&pCookieData); - disposeChain(&pChain); - break; - } - - // Get new family server ip and port - WORD wPort = info->wServerPort; // get default port - parseServerAddress(pServer, &wPort); - - // establish connection - NETLIBOPENCONNECTION nloc = {0}; - if (m_bGatewayMode) - nloc.flags |= NLOCF_HTTPGATEWAY; - nloc.szHost = pServer; - nloc.wPort = wPort; - - HANDLE hConnection = NetLib_OpenConnection(m_hServerNetlibUser, wFamily == ICQ_AVATAR_FAMILY ? "Avatar " : NULL, &nloc); - - if (hConnection == NULL) - { - NetLog_Server("Unable to connect to ICQ new family server."); - } // we want the handler to be called even if the connecting failed - else if (bServerSSL) - { /* Start SSL session if requested */ -#ifdef _DEBUG - NetLog_Server("(%d) Starting SSL negotiation", CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0)); -#endif - if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hConnection, 0)) - { - NetLog_Server("Unable to connect to ICQ new family server, SSL could not be negotiated"); - NetLib_CloseConnection(&hConnection, FALSE); - } - } - - (this->*pCookieData->familyHandler)(hConnection, pCookie, wCookieLen); - - // Free allocated memory - // NOTE: "cookie" will get freed when we have connected to the avatar server. - disposeChain(&pChain); - SAFE_FREE(&pServer); - SAFE_FREE((void**)&pCookieData); - } - - break; - } - - case ICQ_SERVER_EXTSTATUS: // our session data - { -#ifdef _DEBUG - NetLog_Server("Received owner session data."); -#endif - while (wBufferLength > 4) - { // loop thru all items - WORD itemType = pBuffer[0] * 0x10 | pBuffer[1]; - BYTE itemFlags = pBuffer[2]; - BYTE itemLen = pBuffer[3]; - - if (itemType == AVATAR_HASH_PHOTO) /// TODO: handle photo item - { // skip photo item -#ifdef _DEBUG - NetLog_Server("Photo item recognized"); -#endif - } - else if ((itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH) && (itemLen >= 0x10)) - { -#ifdef _DEBUG - NetLog_Server("Avatar item recognized"); -#endif - if (m_bAvatarsEnabled && !info->bMyAvatarInited) // signal the server after login - { // this refreshes avatar state - it used to work automatically, but now it does not - if (getSettingByte(NULL, "ForceOurAvatar", 0)) - { // keep our avatar - TCHAR *file = GetOwnAvatarFileName(); - SetMyAvatar(0, (LPARAM)file); - SAFE_FREE(&file); - } - else // only change avatar hash to the same one - { - BYTE hash[0x14]; - - memcpy(hash, pBuffer, 0x14); - hash[2] = 1; // update image status - updateServAvatarHash(hash, 0x14); - } - info->bMyAvatarInited = TRUE; - break; - } - // process owner avatar hash changed notification - handleAvatarOwnerHash(itemType, itemFlags, pBuffer, itemLen + 4); - } - else if (itemType == 0x02) - { -#ifdef _DEBUG - NetLog_Server("Status message item recognized"); -#endif - } - else if (itemType == 0x0E) - { -#ifdef _DEBUG - NetLog_Server("Status mood item recognized"); -#endif - } - - // move to next item - if (wBufferLength >= itemLen + 4) - { - wBufferLength -= itemLen + 4; - pBuffer += itemLen + 4; - } - else - { - pBuffer += wBufferLength; - wBufferLength = 0; - } - } - break; - } - - case ICQ_ERROR: - { // Something went wrong, probably the request for avatar family failed - WORD wError; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - LogFamilyError(ICQ_SERVICE_FAMILY, wError); - break; - } - - // Stuff we don't care about - case ICQ_SERVER_MOTD: -#ifdef _DEBUG - NetLog_Server("Server message of the day"); -#endif - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - } -} - - -char* CIcqProto::buildUinList(int subtype, WORD wMaxLen, HANDLE* hContactResume) -{ - char* szList; - HANDLE hContact; - WORD wCurrentLen = 0; - DWORD dwUIN; - uid_str szUID; - char szLen[2]; - int add; - - szList = (char*)SAFE_MALLOC(CallService(MS_DB_CONTACT_GETCOUNT, 0, 0) * UINMAXLEN); - szLen[1] = '\0'; - - if (*hContactResume) - hContact = *hContactResume; - else - hContact = FindFirstContact(); - - while (hContact != NULL) - { - if (!getContactUid(hContact, &dwUIN, &szUID)) - { - szLen[0] = strlennull(strUID(dwUIN, szUID)); - - switch (subtype) - { - - case BUL_VISIBLE: - add = ID_STATUS_ONLINE == getSettingWord(hContact, "ApparentMode", 0); - break; - - case BUL_INVISIBLE: - add = ID_STATUS_OFFLINE == getSettingWord(hContact, "ApparentMode", 0); - break; - - case BUL_TEMPVISIBLE: - add = getSettingByte(hContact, "TemporaryVisible", 0); - // clear temporary flag - // Here we assume that all temporary contacts will be in one packet - setSettingByte(hContact, "TemporaryVisible", 0); - break; - - default: - add = 1; - - // If we are in SS mode, we only add those contacts that are - // not in our SS list, or are awaiting authorization, to our - // client side list - if (m_bSsiEnabled && getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) && - !getSettingByte(hContact, "Auth", 0)) - add = 0; - - // Never add hidden contacts to CS list - if (DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) - add = 0; - - break; - } - - if (add) - { - wCurrentLen += szLen[0] + 1; - if (wCurrentLen > wMaxLen) - { - *hContactResume = hContact; - return szList; - } - - strcat(szList, szLen); - strcat(szList, szUID); - } - } - - hContact = FindNextContact(hContact); - } - *hContactResume = NULL; - - return szList; -} - - -void CIcqProto::sendEntireListServ(WORD wFamily, WORD wSubtype, int listType) -{ - HANDLE hResumeContact = NULL; - - do - { // server doesn't seem to be able to cope with packets larger than 8k - // send only about 100contacts per packet - char *szList = buildUinList(listType, 0x3E8, &hResumeContact); - int nListLen = strlennull(szList); - - if (nListLen) - { - icq_packet packet; - - serverPacketInit(&packet, (WORD)(nListLen + 10)); - packFNACHeader(&packet, wFamily, wSubtype); - packBuffer(&packet, (LPBYTE)szList, (WORD)nListLen); - sendServPacket(&packet); - } - - SAFE_FREE((void**)&szList); - } - while (hResumeContact); -} - - -static void packShortCapability(icq_packet *packet, WORD wCapability) -{ // pack standard capability - DWORD dwQ1 = 0x09460000 | wCapability; - - packDWord(packet, dwQ1); - packDWord(packet, 0x4c7f11d1); - packDWord(packet, 0x82224445); - packDWord(packet, 0x53540000); -} - - -// CLI_SETUSERINFO -void CIcqProto::setUserInfo() -{ - icq_packet packet; - WORD wAdditionalData = 0; - BYTE bXStatus = getContactXStatus(NULL); - - if (m_bAimEnabled) - wAdditionalData += 16; -#ifdef DBG_CAPMTN - wAdditionalData += 16; -#endif - if (m_bUtfEnabled) - wAdditionalData += 16; -#ifdef DBG_NEWCAPS - wAdditionalData += 16; -#endif -#ifdef DBG_CAPXTRAZ - wAdditionalData += 16; -#endif -#ifdef DBG_OSCARFT - wAdditionalData += 16; -#endif - if (m_bAvatarsEnabled) - wAdditionalData += 16; - if (m_bXStatusEnabled && bXStatus != 0) - wAdditionalData += 16; -#ifdef DBG_CAPHTML - wAdditionalData += 16; -#endif -#ifdef DBG_AIMCONTACTSEND - wAdditionalData += 16; -#endif - - wAdditionalData += (WORD)CustomCapList.size() * 16; - - //MIM/PackName - bool bHasPackName = false; - DBVARIANT dbv; - if ( !DBGetContactSettingString(NULL, "ICQCaps", "PackName", &dbv )) { - //MIM/PackName - bHasPackName = true; - wAdditionalData += 16; - } - - serverPacketInit(&packet, (WORD)(62 + wAdditionalData)); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO); - - /* TLV(5): capability data */ - packWord(&packet, 0x0005); - packWord(&packet, (WORD)(48 + wAdditionalData)); - -#ifdef DBG_CAPMTN - { - packDWord(&packet, 0x563FC809); // CAP_TYPING - packDWord(&packet, 0x0B6F41BD); - packDWord(&packet, 0x9F794226); - packDWord(&packet, 0x09DFA2F3); - } -#endif - { - packShortCapability(&packet, 0x1349); // AIM_CAPS_ICQSERVERRELAY - } - if (m_bUtfEnabled) - { - packShortCapability(&packet, 0x134E); // CAP_UTF8MSGS - } // Broadcasts the capability to receive UTF8 encoded messages -#ifdef DBG_NEWCAPS - { - packShortCapability(&packet, 0x0000); // CAP_SHORTCAPS - } // Tells server we understand to new format of caps -#endif -#ifdef DBG_CAPXTRAZ - { - packDWord(&packet, 0x1a093c6c); // CAP_XTRAZ - packDWord(&packet, 0xd7fd4ec5); // Broadcasts the capability to handle - packDWord(&packet, 0x9d51a647); // Xtraz - packDWord(&packet, 0x4e34f5a0); - } -#endif - if (m_bAvatarsEnabled) - { - packShortCapability(&packet, 0x134C); // CAP_DEVILS - } -#ifdef DBG_OSCARFT - { - packShortCapability(&packet, 0x1343); // CAP_AIM_FILE - } // Broadcasts the capability to receive Oscar File Transfers -#endif - if (m_bAimEnabled) - { - packShortCapability(&packet, 0x134D); // CAP_AIM_COMPATIBLE - } // Tells the server we can speak to AIM -#ifdef DBG_AIMCONTACTSEND - { - packShortCapability(&packet, 0x134B); // CAP_SENDBUDDYLIST - } -#endif - if (m_bXStatusEnabled && bXStatus != 0) - { - packBuffer(&packet, capXStatus[bXStatus-1], BINARY_CAP_SIZE); - } - - packShortCapability(&packet, 0x1344); // CAP_ICQDIRECT - -#ifdef DBG_CAPHTML - packShortCapability(&packet, 0x0002); // CAP_HTMLMSGS -#endif - - packDWord(&packet, 0x4D697261); // Miranda Signature - packDWord(&packet, 0x6E64614E); - - int v[4] = { MIRANDA_VERSION_FILEVERSION }; - packWord(&packet, v[0]); - packWord(&packet, v[1]); - packWord(&packet, v[2]); - packWord(&packet, v[3]); - - //MIM/PackName - if ( bHasPackName ) { - packBuffer(&packet, (BYTE*)dbv.pszVal, 0x10); - ICQFreeVariant(&dbv); - } - - if(!CustomCapList.empty()) - { - for(std::list::iterator it = CustomCapList.begin(), end = CustomCapList.end(); it != end; ++it) - packBuffer(&packet, (BYTE*)(*it)->caps, 0x10); - } - - sendServPacket(&packet); -} - - -void CIcqProto::handleServUINSettings(int nPort, serverthread_info *info) -{ - icq_packet packet; - - setUserInfo(); - - /* SNAC 3,4: Tell server who's on our list (deprecated) */ - /* SNAC 3,15: Try to add unauthorised contacts to temporary list */ - sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST, BUL_ALLCONTACTS); - - if (m_iDesiredStatus == ID_STATUS_INVISIBLE) - { - /* Tell server who's on our visible list (deprecated) */ - if (!m_bSsiEnabled) - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE); - else - updateServVisibilityCode(3); - } - - if (m_iDesiredStatus != ID_STATUS_INVISIBLE) - { - /* Tell server who's on our invisible list (deprecated) */ - if (!m_bSsiEnabled) - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE); - else - updateServVisibilityCode(4); - } - - // SNAC 1,1E: Set status - { - DWORD dwDirectCookie = rand() ^ (rand() << 16); - - // Get status - WORD wStatus = MirandaStatusToIcq(m_iDesiredStatus); - - // Get status note & mood - char *szStatusNote = PrepareStatusNote(m_iDesiredStatus); - BYTE bXStatus = getContactXStatus(NULL); - char szMoodData[32]; - - // prepare mood id - if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus-1] != -1) - null_snprintf(szMoodData, SIZEOF(szMoodData), "icqmood%d", moodXStatus[bXStatus-1]); - else - szMoodData[0] = '\0'; - - //! Tricky code, this ensures that the status note will be saved to the directory - SetStatusNote(szStatusNote, m_bGatewayMode ? 5000 : 2500, TRUE); - - WORD wStatusNoteLen = strlennull(szStatusNote); - WORD wStatusMoodLen = strlennull(szMoodData); - WORD wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; - - serverPacketInit(&packet, (WORD)(71 + (wSessionDataLen ? wSessionDataLen + 4 : 0))); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); - packDWord(&packet, 0x00060004); // TLV 6: Status mode and security flags - packWord(&packet, GetMyStatusFlags()); // Status flags - packWord(&packet, wStatus); // Status - packTLVWord(&packet, 0x0008, 0x0A06); // TLV 8: Independent Status Messages - packDWord(&packet, 0x000c0025); // TLV C: Direct connection info - packDWord(&packet, getSettingDword(NULL, "RealIP", 0)); - packDWord(&packet, nPort); - packByte(&packet, DC_TYPE); // TCP/FLAG firewall settings - packWord(&packet, ICQ_VERSION); - packDWord(&packet, dwDirectCookie); // DC Cookie - packDWord(&packet, WEBFRONTPORT); // Web front port - packDWord(&packet, CLIENTFEATURES); // Client features - packDWord(&packet, 0x7fffffff); // Abused timestamp - packDWord(&packet, ICQ_PLUG_VERSION); // Abused timestamp - if (ServiceExists("SecureIM/IsContactSecured")) - packDWord(&packet, 0x5AFEC0DE); // SecureIM Abuse - else - packDWord(&packet, 0x00000000); // Timestamp - packWord(&packet, 0x0000); // Unknown - packTLVWord(&packet, 0x001F, 0x0000); - - if (wSessionDataLen) - { // Pack session data - packWord(&packet, 0x1D); // TLV 1D - packWord(&packet, wSessionDataLen); // TLV length - packWord(&packet, 0x02); // Item Type - if (wStatusNoteLen) - { - packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length - packWord(&packet, wStatusNoteLen); // Text Length - packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen); - packWord(&packet, 0); // Encoding not specified (utf-8 is default) - } - else - packWord(&packet, 0); // Flags + Item Length - packWord(&packet, 0x0E); // Item Type - packWord(&packet, wStatusMoodLen); // Flags + Item Length - if (wStatusMoodLen) - packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood - - // Save current status note & mood - setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, szStatusNote); - setSettingString(NULL, DBSETTING_STATUS_MOOD, szMoodData); - } - // Release memory - SAFE_FREE(&szStatusNote); - - sendServPacket(&packet); - } - - /* SNAC 1,11 */ - serverPacketInit(&packet, 14); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE); - packDWord(&packet, 0x00000000); - - sendServPacket(&packet); - m_bIdleAllow = 0; - - // Change status - SetCurrentStatus(m_iDesiredStatus); - - // Finish Login sequence - serverPacketInit(&packet, 98); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY); - packDWord(&packet, 0x00220001); // imitate ICQ 6 behaviour - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00010004); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00130004); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00020001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00030001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00150001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00040001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00060001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x00090001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x000A0001); - packDWord(&packet, 0x0110164f); - packDWord(&packet, 0x000B0001); - packDWord(&packet, 0x0110164f); - - sendServPacket(&packet); - - NetLog_Server(" *** Yeehah, login sequence complete"); - - // login sequence is complete enter logged-in mode - info->bLoggedIn = 1; - m_bConnectionLost = FALSE; - - // enable auto info-update routine - icq_EnableUserLookup(TRUE); - - if (!info->isMigrating) - { /* Get Offline Messages Reqeust */ - cookie_offline_messages *ack = (cookie_offline_messages*)SAFE_MALLOC(sizeof(cookie_offline_messages)); - if (ack) - { - DWORD dwCookie = AllocateCookie(CKT_OFFLINEMESSAGE, ICQ_MSG_CLI_REQ_OFFLINE, 0, ack); - - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQ_OFFLINE, 0, dwCookie); - - sendServPacket(&packet); - } - else - icq_LogMessage(LOG_WARNING, LPGEN("Failed to request offline messages. They may be received next time you log in.")); - - // Update our information from the server - sendOwnerInfoRequest(); - - // Request info updates on all contacts - icq_RescanInfoUpdate(); - - // Start sending Keep-Alive packets - StartKeepAlive(info); - - if (m_bAvatarsEnabled) - { // Send SNAC 1,4 - request avatar family 0x10 connection - icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread); - - m_avatarsConnectionPending = TRUE; - NetLog_Server("Requesting Avatar family entry point."); - } - } - info->isMigrating = 0; - - if (m_bAimEnabled) - { - char **szAwayMsg = NULL; - icq_lock l(m_modeMsgsMutex); - - szAwayMsg = MirandaStatusToAwayMsg(m_iStatus); - if (szAwayMsg) - icq_sendSetAimAwayMsgServ(*szAwayMsg); - } -} diff --git a/protocols/IcqOscarJ/fam_02location.cpp b/protocols/IcqOscarJ/fam_02location.cpp deleted file mode 100755 index 2398cf18c6..0000000000 --- a/protocols/IcqOscarJ/fam_02location.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packets from Location family -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -extern const char* cliSpamBot; - -void CIcqProto::handleLocationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_LOCATION_RIGHTS_REPLY: // Reply to CLI_REQLOCATION - NetLog_Server("Server sent SNAC(x02,x03) - SRV_LOCATION_RIGHTS_REPLY"); - break; - - case ICQ_LOCATION_USR_INFO_REPLY: // AIM user info reply - handleLocationUserInfoReply(pBuffer, wBufferLength, pSnacHeader->dwRef); - break; - - case ICQ_ERROR: - { - WORD wError; - HANDLE hCookieContact; - cookie_fam15_data *pCookieData; - - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - if (wError == 4) - { - if (FindCookie(pSnacHeader->dwRef, &hCookieContact, (void**)&pCookieData) && !getContactUin(hCookieContact) && pCookieData->bRequestType == REQUESTTYPE_PROFILE) - { - BroadcastAck(hCookieContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - - ReleaseCookie(pSnacHeader->dwRef); - } - } - - LogFamilyError(ICQ_LOCATION_FAMILY, wError); - break; - } - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LOCATION_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - -static char* AimApplyEncoding(char* pszStr, const char* pszEncoding) -{ // decode encoding to ANSI only - if (pszStr && pszEncoding) - { - const char *szEnc = strstrnull(pszEncoding, "charset="); - - if (szEnc) - { // decode custom encoding to Utf-8 - char *szStr = ApplyEncoding(pszStr, szEnc + 9); - // decode utf-8 to ansi - char *szRes = NULL; - - SAFE_FREE((void**)&pszStr); - utf8_decode(szStr, &szRes); - SAFE_FREE((void**)&szStr); - - return szRes; - } - } - return pszStr; -} - -void CIcqProto::handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie) -{ - HANDLE hContact; - DWORD dwUIN; - uid_str szUID; - WORD wTLVCount; - WORD wWarningLevel; - HANDLE hCookieContact; - WORD status; - cookie_message_data *pCookieData; - - // Unpack the sender's user ID - if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; - - // Syntax check - if (wLen < 4) - return; - - // Warning level? - unpackWord(&buf, &wWarningLevel); - wLen -= 2; - - // TLV count - unpackWord(&buf, &wTLVCount); - wLen -= 2; - - // Determine contact - hContact = HContactFromUID(dwUIN, szUID, NULL); - - // Ignore away status if the user is not already on our list - if (hContact == INVALID_HANDLE_VALUE) - { -#ifdef _DEBUG - NetLog_Server("Ignoring away reply (%s)", strUID(dwUIN, szUID)); -#endif - return; - } - - if (!FindCookie(dwCookie, &hCookieContact, (void**)&pCookieData)) - { - NetLog_Server("Error: Received unexpected away reply from %s", strUID(dwUIN, szUID)); - return; - } - - if (hContact != hCookieContact) - { - NetLog_Server("Error: Away reply Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); - - ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe - return; - } - - switch (GetCookieType(dwCookie)) - { - case CKT_FAMILYSPECIAL: - { - ReleaseCookie(dwCookie); - - // Read user info TLVs - { - oscar_tlv_chain* pChain; - BYTE *tmp; - char *szMsg = NULL; - - // Syntax check - if (wLen < 4) - return; - - tmp = buf; - // Get general chain - if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) - return; - - disposeChain(&pChain); - - wLen -= (buf - tmp); - - // Get extra chain - if (pChain = readIntoTLVChain(&buf, wLen, 2)) - { - oscar_tlv *pTLV; - char *szEncoding = NULL; - - // Get Profile encoding TLV - - pTLV = pChain->getTLV(0x05, 1); - if (pTLV && (pTLV->wLen > 0)) - { - // store client capabilities - BYTE* capBuf = pTLV->pData; - WORD capLen = pTLV->wLen; - DBCONTACTWRITESETTING dbcws; - dbcws.value.type = DBVT_BLOB; - dbcws.value.cpbVal = capLen; - dbcws.value.pbVal = capBuf; - dbcws.szModule = m_szModuleName; - dbcws.szSetting = "CapBuf"; - CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&dbcws); - } - else - deleteSetting(hContact, "CapBuf"); - - pTLV = pChain->getTLV(0x01, 1); - if (pTLV && (pTLV->wLen >= 1)) - { - szEncoding = (char*)_alloca(pTLV->wLen + 1); - memcpy(szEncoding, pTLV->pData, pTLV->wLen); - szEncoding[pTLV->wLen] = '\0'; - } - // Get Profile info TLV - pTLV = pChain->getTLV(0x02, 1); - if (pTLV && (pTLV->wLen >= 1)) - { - szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); - memcpy(szMsg, pTLV->pData, pTLV->wLen); - szMsg[pTLV->wLen] = '\0'; - szMsg[pTLV->wLen + 1] = '\0'; - szMsg = AimApplyEncoding(szMsg, szEncoding); - szMsg = EliminateHtml(szMsg, pTLV->wLen); - } - // Free TLV chain - disposeChain(&pChain); - } - - setSettingString(hContact, "About", szMsg); - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0); - - SAFE_FREE((void**)&szMsg); - } - break; - } - - default: // away message - { - status = AwayMsgTypeToStatus(pCookieData->nAckType); - if (status == ID_STATUS_OFFLINE) - { - NetLog_Server("SNAC(2.6) Ignoring unknown status message from %s", strUID(dwUIN, szUID)); - - ReleaseCookie(dwCookie); - return; - } - - ReleaseCookie(dwCookie); - - // Read user info TLVs - { - oscar_tlv_chain* pChain; - oscar_tlv* pTLV; - BYTE *tmp; - char *szMsg = NULL; - CCSDATA ccs; - PROTORECVEVENT pre; - - // Syntax check - if (wLen < 4) - return; - - tmp = buf; - // Get general chain - if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) - return; - - disposeChain(&pChain); - - wLen -= (buf - tmp); - - // Get extra chain - if (pChain = readIntoTLVChain(&buf, wLen, 2)) - { - char* szEncoding = NULL; - - // Get Away encoding TLV - pTLV = pChain->getTLV(0x03, 1); - if (pTLV && (pTLV->wLen >= 1)) - { - szEncoding = (char*)_alloca(pTLV->wLen + 1); - memcpy(szEncoding, pTLV->pData, pTLV->wLen); - szEncoding[pTLV->wLen] = '\0'; - } - // Get Away info TLV - pTLV = pChain->getTLV(0x04, 1); - if (pTLV && (pTLV->wLen >= 1)) - { - szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); - memcpy(szMsg, pTLV->pData, pTLV->wLen); - szMsg[pTLV->wLen] = '\0'; - szMsg[pTLV->wLen + 1] = '\0'; - szMsg = AimApplyEncoding(szMsg, szEncoding); - szMsg = EliminateHtml(szMsg, pTLV->wLen); - } - // Free TLV chain - disposeChain(&pChain); - } - - ccs.szProtoService = PSR_AWAYMSG; - ccs.hContact = hContact; - ccs.wParam = status; - ccs.lParam = (LPARAM)⪯ - pre.flags = 0; - pre.szMessage = szMsg?szMsg:(char *)""; - pre.timestamp = time(NULL); - pre.lParam = dwCookie; - - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); - - SAFE_FREE((void**)&szMsg); - } - break; - } - } -} diff --git a/protocols/IcqOscarJ/fam_03buddy.cpp b/protocols/IcqOscarJ/fam_03buddy.cpp deleted file mode 100644 index caa41d966c..0000000000 --- a/protocols/IcqOscarJ/fam_03buddy.cpp +++ /dev/null @@ -1,787 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packets from Buddy family -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -extern const char* cliSpamBot; - -void CIcqProto::handleBuddyFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) -{ - switch (pSnacHeader->wSubtype) - { - case ICQ_USER_ONLINE: - handleUserOnline(pBuffer, wBufferLength, info); - break; - - case ICQ_USER_OFFLINE: - handleUserOffline(pBuffer, wBufferLength); - break; - - case ICQ_USER_SRV_REPLYBUDDY: - handleReplyBuddy(pBuffer, wBufferLength); - break; - - case ICQ_USER_NOTIFY_REJECTED: - handleNotifyRejected(pBuffer, wBufferLength); - break; - - case ICQ_ERROR: - { - WORD wError; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - LogFamilyError(ICQ_BUDDY_FAMILY, wError); - break; - } - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_BUDDY_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -void CIcqProto::handleReplyBuddy(BYTE *buf, WORD wPackLen) -{ - oscar_tlv_chain *pChain = readIntoTLVChain(&buf, wPackLen, 0); - - if (pChain) - { - DWORD wMaxUins = pChain->getWord(1, 1); - DWORD wMaxWatchers = pChain->getWord(2, 1); - DWORD wMaxTemporary = pChain->getWord(4, 1); - - NetLog_Server("MaxUINs %u", wMaxUins); - NetLog_Server("MaxWatchers %u", wMaxWatchers); - NetLog_Server("MaxTemporary %u", wMaxTemporary); - - disposeChain(&pChain); - } - else - { - NetLog_Server("Error: Malformed BuddyReply"); - } -} - - -int unpackSessionDataItem(oscar_tlv_chain *pChain, WORD wItemType, BYTE **ppItemData, WORD *pwItemSize, BYTE *pbItemFlags) -{ - oscar_tlv *tlv = pChain->getTLV(0x1D, 1); - int len = 0; - BYTE *data; - - if (tlv) - { - len = tlv->wLen; - data = tlv->pData; - } - - while (len >= 4) - { // parse session data items one by one - WORD itemType; - BYTE itemFlags; - BYTE itemLen; - - unpackWord(&data, &itemType); - unpackByte(&data, &itemFlags); - unpackByte(&data, &itemLen); - len -= 4; - - // just some validity check - if (itemLen > len) - itemLen = len; - - if (itemType == wItemType) - { // found the requested item - if (ppItemData) - *ppItemData = data; - if (pwItemSize) - *pwItemSize = itemLen; - if (pbItemFlags) - *pbItemFlags = itemFlags; - - return 1; // Success - } - data += itemLen; - len -= itemLen; - } - return 0; -} - - -// TLV(1) User class -// TLV(3) Signon time -// TLV(4) Idle time (in minutes) -// TLV(5) Member since -// TLV(6) New status -// TLV(8) Status Capabilities -// TLV(A) External IP -// TLV(C) DC Info -// TLV(D) Capabilities -// TLV(F) Session timer (in seconds) -// TLV(14) Instance number (AIM only) -// TLV(19) Short capabilities -// TLV(1D) Session Data (Avatar, Mood, etc.) -// TLV(1F) User class (upper bytes) -// TLV(26) AIM Profile update time -// TLV(27) AIM Away message update time -// TLV(29) Away status since -// TLV(2B) URL to protocol icon -// TLV(2F) unknown key -// TLV(30) unknown timestamp - -void CIcqProto::handleUserOnline(BYTE *buf, WORD wLen, serverthread_info *info) -{ - DWORD dwPort = 0; - DWORD dwRealIP = 0; - DWORD dwUIN; - uid_str szUID; - DWORD dwDirectConnCookie = 0; - DWORD dwWebPort = 0; - DWORD dwFT1 = 0, dwFT2 = 0, dwFT3 = 0; - const char *szClient = NULL; - BYTE bClientId = 0; - WORD wVersion = 0; - WORD wTLVCount; - WORD wWarningLevel; - WORD wStatusFlags; - WORD wStatus = 0, wOldStatus = 0; - BYTE nTCPFlag = 0; - char szStrBuf[MAX_PATH]; - - // Unpack the sender's user ID - if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; - - // Syntax check - if (wLen < 4) - return; - - // Warning level? - unpackWord(&buf, &wWarningLevel); - wLen -= 2; - - // TLV count - unpackWord(&buf, &wTLVCount); - wLen -= 2; - - // notify that the set status note & mood process is finished - if (m_hNotifyNameInfoEvent) - SetEvent(m_hNotifyNameInfoEvent); - - // Ignore status notification if the user is not already on our list - HANDLE hContact = HContactFromUID(dwUIN, szUID, NULL); - if (hContact == INVALID_HANDLE_VALUE) - { -#ifdef _DEBUG - NetLog_Server("Ignoring user online (%s)", strUID(dwUIN, szUID)); -#endif - return; - } - - // Read user info TLVs - oscar_tlv_chain *pChain; - oscar_tlv *pTLV; - - // Syntax check - if (wLen < 4) - return; - - // Get chain - if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) - return; - - // Get Class word - WORD wClass = pChain->getWord(0x01, 1); - int nIsICQ = wClass & CLASS_ICQ; - - if (dwUIN) - { - // Get DC info TLV - pTLV = pChain->getTLV(0x0C, 1); - if (pTLV && (pTLV->wLen >= 15)) - { - BYTE *pBuffer = pTLV->pData; - - nIsICQ = TRUE; - - unpackDWord(&pBuffer, &dwRealIP); - unpackDWord(&pBuffer, &dwPort); - unpackByte(&pBuffer, &nTCPFlag); - unpackWord(&pBuffer, &wVersion); - unpackDWord(&pBuffer, &dwDirectConnCookie); - unpackDWord(&pBuffer, &dwWebPort); // Web front port - pBuffer += 4; // Client features - - // Get faked time signatures, used to identify clients - if (pTLV->wLen >= 0x23) - { - unpackDWord(&pBuffer, &dwFT1); - unpackDWord(&pBuffer, &dwFT2); - unpackDWord(&pBuffer, &dwFT3); - } - } - else - { - // This client doesnt want DCs - } - - // Get Status info TLV - pTLV = pChain->getTLV(0x06, 1); - if (pTLV && (pTLV->wLen >= 4)) - { - BYTE *pBuffer = pTLV->pData; - - unpackWord(&pBuffer, &wStatusFlags); - unpackWord(&pBuffer, &wStatus); - } - else if (!nIsICQ) - { - // Connected thru AIM client, guess by user class - if (wClass & CLASS_AWAY) - wStatus = ID_STATUS_AWAY; - else if (wClass & CLASS_WIRELESS) - wStatus = ID_STATUS_ONTHEPHONE; - else - wStatus = ID_STATUS_ONLINE; - - wStatusFlags = 0; - } - else - { - // Huh? No status TLV? Lets guess then... - wStatusFlags = 0; - wStatus = ICQ_STATUS_ONLINE; - } - } - else - { - nIsICQ = FALSE; - - if (wClass & CLASS_AWAY) - wStatus = ID_STATUS_AWAY; - else if (wClass & CLASS_WIRELESS) - wStatus = ID_STATUS_ONTHEPHONE; - else - wStatus = ID_STATUS_ONLINE; - - wStatusFlags = 0; - } - -#ifdef _DEBUG - NetLog_Server("Flags are %x", wStatusFlags); - NetLog_Server("Status is %x", wStatus); -#endif - - // Get IP TLV - DWORD dwIP = pChain->getDWord(0x0A, 1); - - // Get Online Since TLV - DWORD dwOnlineSince = pChain->getDWord(0x03, 1); - - // Get Away Since TLV - DWORD dwAwaySince = pChain->getDWord(0x29, 1); - - // Get Member Since TLV - DWORD dwMemberSince = pChain->getDWord(0x05, 1); - - // Get Idle timer TLV - WORD wIdleTimer = pChain->getWord(0x04, 1); - time_t tIdleTS = 0; - if (wIdleTimer) - { - time(&tIdleTS); - tIdleTS -= (wIdleTimer*60); - }; - -#ifdef _DEBUG - if (wIdleTimer) - NetLog_Server("Idle timer is %u.", wIdleTimer); - NetLog_Server("Online since %s", time2text(dwOnlineSince)); - if (dwAwaySince) - NetLog_Server("Status was set on %s", time2text(dwAwaySince)); -#endif - - // Check client capabilities - if (hContact != NULL) - { - wOldStatus = getContactStatus(hContact); - - // Collect all Capability info from TLV chain - BYTE *capBuf = NULL; - WORD capLen = 0; - - // Get Location Capability Info TLVs - oscar_tlv *pFullTLV = pChain->getTLV(0x0D, 1); - oscar_tlv *pShortTLV = pChain->getTLV(0x19, 1); - - if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) - capLen += pFullTLV->wLen; - - if (pShortTLV && (pShortTLV->wLen >= 2)) - capLen += (pShortTLV->wLen * 8); - - capBuf = (BYTE*)_alloca(capLen + BINARY_CAP_SIZE); - - if (capLen) - { - BYTE *pCapability = capBuf; - - capLen = 0; // we need to recount that - - if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) - { // copy classic Capabilities - BYTE *cData = pFullTLV->pData; - int cLen = pFullTLV->wLen; - - while (cLen) - { // be impervious to duplicates (AOL sends them sometimes) - if (!capLen || !MatchCapability(capBuf, capLen, (capstr*)cData, BINARY_CAP_SIZE)) - { // not present, add - memcpy(pCapability, cData, BINARY_CAP_SIZE); - capLen += BINARY_CAP_SIZE; - pCapability += BINARY_CAP_SIZE; - } - cData += BINARY_CAP_SIZE; - cLen -= BINARY_CAP_SIZE; - } - } - - if (pShortTLV && (pShortTLV->wLen >= 2)) - { // copy short Capabilities - capstr tmp; - BYTE *cData = pShortTLV->pData; - int cLen = pShortTLV->wLen; - - memcpy(tmp, capShortCaps, BINARY_CAP_SIZE); - while (cLen) - { // be impervious to duplicates (AOL sends them sometimes) - tmp[2] = cData[0]; - tmp[3] = cData[1]; - - if (!capLen || !MatchCapability(capBuf, capLen, &tmp, BINARY_CAP_SIZE)) - { // not present, add - memcpy(pCapability, tmp, BINARY_CAP_SIZE); - capLen += BINARY_CAP_SIZE; - pCapability += BINARY_CAP_SIZE; - } - cData += 2; - cLen -= 2; - } - } -#ifdef _DEBUG - NetLog_Server("Detected %d capability items.", capLen / BINARY_CAP_SIZE); -#endif - } - - if (capLen) - { // Update the contact's capabilies if present in packet - SetCapabilitiesFromBuffer(hContact, capBuf, capLen, wOldStatus == ID_STATUS_OFFLINE); - - char *szCurrentClient = wOldStatus == ID_STATUS_OFFLINE ? NULL : getSettingStringUtf(hContact, "MirVer", NULL); - - szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, szCurrentClient, wVersion, dwFT1, dwFT2, dwFT3, nTCPFlag, dwDirectConnCookie, dwWebPort, capBuf, capLen, &bClientId, szStrBuf); - // Check if the client changed, if not do not change - if (szCurrentClient && !strcmpnull(szCurrentClient, szClient)) - szClient = (const char*)-1; - SAFE_FREE(&szCurrentClient); - } - else if (wOldStatus == ID_STATUS_OFFLINE) - { - // Remove the contact's capabilities if coming from offline - ClearAllContactCapabilities(hContact); - - // no capability - NetLog_Server("No capability info TLVs"); - - szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, NULL, wVersion, dwFT1, dwFT2, dwFT3, nTCPFlag, dwDirectConnCookie, dwWebPort, NULL, capLen, &bClientId, szStrBuf); - } - else - { - // Capabilities not present in update packet, do not touch - szClient = (const char*)-1; // we don't want to client be overwritten - } - - // handle Xtraz status - char *moodData = NULL; - WORD moodSize = 0; - - unpackSessionDataItem(pChain, 0x0E, (BYTE**)&moodData, &moodSize, NULL); - if (capLen || wOldStatus == ID_STATUS_OFFLINE) - handleXStatusCaps(dwUIN, szUID, hContact, capBuf, capLen, moodData, moodSize); - else - handleXStatusCaps(dwUIN, szUID, hContact, NULL, 0, moodData, moodSize); - - // Determine support for extended status messages - if (pChain->getWord(0x08, 1) == 0x0A06) - SetContactCapabilities(hContact, CAPF_STATUS_MESSAGES); - else if (wOldStatus == ID_STATUS_OFFLINE) - ClearContactCapabilities(hContact, CAPF_STATUS_MESSAGES); - -#ifdef _DEBUG - if (wOldStatus == ID_STATUS_OFFLINE) - { - if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) - NetLog_Server("Supports advanced messages"); - else - NetLog_Server("Does NOT support advanced messages"); - } -#endif - - if (!nIsICQ) - { - // AIM clients does not advertise these, but do support them - SetContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING); - // Server relayed messages are only supported by ICQ clients - ClearContactCapabilities(hContact, CAPF_SRV_RELAY); - - if (dwUIN && wOldStatus == ID_STATUS_OFFLINE) - NetLog_Server("Logged in with AIM client"); - } - - if (nIsICQ && wVersion < 8) - { - ClearContactCapabilities(hContact, CAPF_SRV_RELAY); - if (wOldStatus == ID_STATUS_OFFLINE) - NetLog_Server("Forcing simple messages due to compability issues"); - } - - // Process Avatar Hash - pTLV = pChain->getTLV(0x1D, 1); - if (pTLV) - handleAvatarContactHash(dwUIN, szUID, hContact, pTLV->pData, pTLV->wLen, wOldStatus); - else - handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0, wOldStatus); - - // Process Status Note - parseStatusNote(dwUIN, szUID, hContact, pChain); - } - // Free TLV chain - disposeChain(&pChain); - - // Save contacts details in database - if (hContact != NULL) - { - setSettingDword(hContact, "LogonTS", dwOnlineSince); - setSettingDword(hContact, "AwayTS", dwAwaySince); - setSettingDword(hContact, "IdleTS", tIdleTS); - - if (dwMemberSince) - setSettingDword(hContact, "MemberTS", dwMemberSince); - - if (nIsICQ) - { // on AIM these are not used - setSettingDword(hContact, "DirectCookie", dwDirectConnCookie); - setSettingByte(hContact, "DCType", (BYTE)nTCPFlag); - setSettingWord(hContact, "UserPort", (WORD)(dwPort & 0xffff)); - setSettingWord(hContact, "Version", wVersion); - } - else - { - deleteSetting(hContact, "DirectCookie"); - deleteSetting(hContact, "DCType"); - deleteSetting(hContact, "UserPort"); - deleteSetting(hContact, "Version"); - } - - if (!szClient) - { - // if no detection, set uknown - szClient = (nIsICQ ? "Unknown" : "Unknown AIM"); - } - if (szClient != (char*)-1) - { - setSettingStringUtf(hContact, "MirVer", szClient); - setSettingByte(hContact, "ClientID", bClientId); - } - - if (wOldStatus == ID_STATUS_OFFLINE) - { - setSettingDword(hContact, "IP", dwIP); - setSettingDword(hContact, "RealIP", dwRealIP); - } - else - { // if not first notification only write significant information - if (dwIP) - setSettingDword(hContact, "IP", dwIP); - if (dwRealIP) - setSettingDword(hContact, "RealIP", dwRealIP); - } - setSettingWord(hContact, "Status", (WORD)IcqStatusToMiranda(wStatus)); - - // Update info? - if (dwUIN) - { // check if the local copy of user details is up-to-date - if (IsMetaInfoChanged(hContact)) - icq_QueueUser(hContact); - } - } - - if (wOldStatus != IcqStatusToMiranda(wStatus)) - { // And a small log notice... if status was changed - if (nIsICQ) - NetLog_Server("%u changed status to %s (v%d).", dwUIN, MirandaStatusToString(IcqStatusToMiranda(wStatus)), wVersion); - else - NetLog_Server("%s changed status to %s.", strUID(dwUIN, szUID), MirandaStatusToString(IcqStatusToMiranda(wStatus))); - } -#ifdef _DEBUG - else - { - if (nIsICQ) - NetLog_Server("%u has status %s (v%d).", dwUIN, MirandaStatusToString(IcqStatusToMiranda(wStatus)), wVersion); - else - NetLog_Server("%s has status %s.", strUID(dwUIN, szUID), MirandaStatusToString(IcqStatusToMiranda(wStatus))); - } -#endif - - if (szClient == cliSpamBot) - { - if (getSettingByte(NULL, "KillSpambots", DEFAULT_KILLSPAM_ENABLED) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) - { // kill spammer - icq_DequeueUser(dwUIN); - icq_sendRemoveContact(dwUIN, NULL); - AddToSpammerList(dwUIN); - if (getSettingByte(NULL, "PopupsSpamEnabled", DEFAULT_SPAM_POPUPS_ENABLED)) - ShowPopUpMsg(hContact, LPGEN("Spambot Detected"), LPGEN("Contact deleted & further events blocked."), POPTYPE_SPAM); - CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); - - NetLog_Server("Contact %u deleted", dwUIN); - } - } -} - -void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen) -{ - DWORD dwUIN; - uid_str szUID; - - do { - oscar_tlv_chain *pChain = NULL; - WORD wTLVCount; - DWORD dwAwaySince; - - // Unpack the sender's user ID - if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; - - // Warning level? - buf += 2; - - // TLV Count - unpackWord(&buf, &wTLVCount); - wLen -= 4; - - // Skip the TLV chain - while (wTLVCount && wLen >= 4) - { - WORD wTLVType; - WORD wTLVLen; - - unpackWord(&buf, &wTLVType); - unpackWord(&buf, &wTLVLen); - wLen -= 4; - - // stop parsing overflowed packet - if (wTLVLen > wLen) - { - disposeChain(&pChain); - return; - } - - if (wTLVType == 0x1D) - { // read only TLV with Session data into chain - BYTE *pTLV = buf - 4; - disposeChain(&pChain); - pChain = readIntoTLVChain(&pTLV, wLen + 4, 1); - } - else if (wTLVType == 0x29 && wTLVLen == sizeof(DWORD)) - { // get Away Since value - BYTE *pData = buf; - unpackDWord(&pData, &dwAwaySince); - } - - buf += wTLVLen; - wLen -= wTLVLen; - wTLVCount--; - } - - // Determine contact - HANDLE hContact = HContactFromUID(dwUIN, szUID, NULL); - - // Skip contacts that are not already on our list or are already offline - if (hContact != INVALID_HANDLE_VALUE) - { - WORD wOldStatus = getContactStatus(hContact); - - // Process Avatar Hash - oscar_tlv *pAvatarTLV = pChain ? pChain->getTLV(0x1D, 1) : NULL; - if (pAvatarTLV) - handleAvatarContactHash(dwUIN, szUID, hContact, pAvatarTLV->pData, pAvatarTLV->wLen, wOldStatus); - else - handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0, wOldStatus); - - // Process Status Note (offline status note) - parseStatusNote(dwUIN, szUID, hContact, pChain); - - // Update status times - setSettingDword(hContact, "IdleTS", 0); - setSettingDword(hContact, "AwayTS", dwAwaySince); - - // Clear custom status & mood - char tmp = NULL; - handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0); - - if (wOldStatus != ID_STATUS_OFFLINE) - { - NetLog_Server("%s went offline.", strUID(dwUIN, szUID)); - - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - // close Direct Connections to that user - CloseContactDirectConns(hContact); - // Reset DC status - setSettingByte(hContact, "DCStatus", 0); - } -#ifdef _DEBUG - else - NetLog_Server("%s is offline.", strUID(dwUIN, szUID)); -#endif - } - - // Release memory - disposeChain(&pChain); - } - while (wLen >= 1); -} - - -void CIcqProto::parseStatusNote(DWORD dwUin, char *szUid, HANDLE hContact, oscar_tlv_chain *pChain) -{ - DWORD dwStatusNoteTS = time(NULL); - BYTE *pStatusNoteTS, *pStatusNote; - WORD wStatusNoteTSLen, wStatusNoteLen; - BYTE bStatusNoteFlags; - - if (unpackSessionDataItem(pChain, 0x0D, &pStatusNoteTS, &wStatusNoteTSLen, NULL) && wStatusNoteTSLen == sizeof(DWORD)) - unpackDWord(&pStatusNoteTS, &dwStatusNoteTS); - - // Get Status Note session item - if (unpackSessionDataItem(pChain, 0x02, &pStatusNote, &wStatusNoteLen, &bStatusNoteFlags)) - { - char *szStatusNote = NULL; - - if ((bStatusNoteFlags & 4) == 4 && wStatusNoteLen >= 4) - { - BYTE *buf = pStatusNote; - WORD buflen = wStatusNoteLen - 2; - WORD wTextLen; - - unpackWord(&buf, &wTextLen); - if (wTextLen > buflen) - wTextLen = buflen; - - if (wTextLen > 0) - { - szStatusNote = (char*)_alloca(wStatusNoteLen + 1); - unpackString(&buf, szStatusNote, wTextLen); - szStatusNote[wTextLen] = '\0'; - buflen -= wTextLen; - - WORD wEncodingType = 0; - char *szEncoding = NULL; - - if (buflen >= 2) - unpackWord(&buf, &wEncodingType); - - if (wEncodingType == 1 && buflen > 6) - { // Encoding specified - buf += 2; - buflen -= 2; - unpackWord(&buf, &wTextLen); - if (wTextLen > buflen) - wTextLen = buflen; - szEncoding = (char*)_alloca(wTextLen + 1); - unpackString(&buf, szEncoding, wTextLen); - szEncoding[wTextLen] = '\0'; - } - else if (UTF8_IsValid(szStatusNote)) - szEncoding = "utf-8"; - - szStatusNote = ApplyEncoding(szStatusNote, szEncoding); - } - } - // Check if the status note was changed - if (dwStatusNoteTS > getSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, 0)) - { - DBVARIANT dbv = {DBVT_DELETED}; - - if (strlennull(szStatusNote) || (!getSettingString(hContact, DBSETTING_STATUS_NOTE, &dbv) && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_UTF8) && strlennull(dbv.pszVal))) - NetLog_Server("%s changed status note to \"%s\"", strUID(dwUin, szUid), szStatusNote ? szStatusNote : ""); - - ICQFreeVariant(&dbv); - - if (szStatusNote) - setSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, szStatusNote); - else - deleteSetting(hContact, DBSETTING_STATUS_NOTE); - setSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS); - - if (getContactXStatus(hContact) != 0 || !CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) { - setStatusMsgVar(hContact, szStatusNote, false); - - TCHAR* tszNote = mir_utf8decodeT(szStatusNote); - BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, (LPARAM)tszNote); - mir_free(tszNote); - } - } - SAFE_FREE(&szStatusNote); - } - else - { - if (getContactStatus(hContact) == ID_STATUS_OFFLINE) - { - setStatusMsgVar(hContact, NULL, false); - deleteSetting(hContact, DBSETTING_STATUS_NOTE); - setSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS); - } - } -} - - -void CIcqProto::handleNotifyRejected(BYTE *buf, WORD wPackLen) -{ - DWORD dwUIN; - uid_str szUID; - - while (wPackLen) - if (unpackUID(&buf, &wPackLen, &dwUIN, &szUID)) - NetLog_Server("%s status notification rejected.", strUID(dwUIN, szUID)); -} diff --git a/protocols/IcqOscarJ/fam_04message.cpp b/protocols/IcqOscarJ/fam_04message.cpp deleted file mode 100644 index 7d1bc6a829..0000000000 --- a/protocols/IcqOscarJ/fam_04message.cpp +++ /dev/null @@ -1,3043 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packets from Family 4 ICBM Messages -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleMsgFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_MSG_SRV_ERROR: // SNAC(4, 0x01) - handleRecvServMsgError(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_REPLYICBM: // SNAC(4, 0x05) SRV_REPLYICBM - handleReplyICBM(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_RECV: // SNAC(4, 0x07) - handleRecvServMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_MISSED_MESSAGE: // SNAC(4, 0x0A) - handleMissedMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_RESPONSE: // SNAC(4, 0x0B) - handleRecvMsgResponse(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_ACK: // SNAC(4, 0x0C) Server acknowledgements - handleServerAck(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_MTN: // SNAC(4, 0x14) Typing notifications - handleTypingNotification(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_OFFLINE_REPLY: // SNAC(4, 0x17) Offline Messages response - handleOffineMessagesReply(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_MSG_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -static void setMsgChannelParams(CIcqProto *ppro, WORD wChan, DWORD dwFlags) -{ - icq_packet packet; - - // Set message parameters for channel wChan (CLI_SET_ICBM_PARAMS) - serverPacketInit(&packet, 26); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_SETPARAMS); - packWord(&packet, wChan); // Channel - packDWord(&packet, dwFlags); // Flags - packWord(&packet, MAX_MESSAGESNACSIZE); // Max message snac size - packWord(&packet, 0x03E7); // Max sender warning level - packWord(&packet, 0x03E7); // Max receiver warning level - packWord(&packet, CLIENTRATELIMIT); // Minimum message interval in seconds - packWord(&packet, 0x0000); // Unknown - ppro->sendServPacket(&packet); -} - - -void CIcqProto::handleReplyICBM(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ // we don't care about the stuff, just change the params - DWORD dwFlags = 0x00000303; - -#ifdef DBG_CAPHTML - dwFlags |= 0x00000400; -#endif -#ifdef DBG_CAPMTN - dwFlags |= 0x00000008; -#endif - // Set message parameters for all channels (imitate ICQ 6) - setMsgChannelParams(this, 0x0000, dwFlags); -} - - -void CIcqProto::handleRecvServMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD wTLVCount; - WORD wMessageFormat; - uid_str szUID; - - if (wLen < 11) - { // just do some basic packet checking - NetLog_Server("Error: Malformed message thru server"); - return; - } - - // These two values are some kind of reference, we need to save - // them to send file request responses for example - unpackLEDWord(&buf, &dwMsgID1); // TODO: msg cookies should be main - wLen -= 4; - unpackLEDWord(&buf, &dwMsgID2); - wLen -= 4; - - // The message type used: - unpackWord(&buf, &wMessageFormat); // 0x0001: Simple message format - wLen -= 2; // 0x0002: Advanced message format - // 0x0004: 'New' message format - // Sender UIN - if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; - - if (dwUin && IsOnSpammerList(dwUin)) - { - NetLog_Server("Ignored Message from known Spammer"); - return; - } - - if (wLen < 4) - { // just do some basic packet checking - NetLog_Server("Error: Malformed message thru server"); - return; - } - - // Warning level? - buf += 2; - wLen -= 2; - - // Number of following TLVs, until msg-format dependant TLVs - unpackWord(&buf, &wTLVCount); - wLen -= 2; - if (wTLVCount > 0) - { - // Save current buffer pointer so we can calculate - // how much data we have left after the chain read. - BYTE *pBufStart = buf; - oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, wTLVCount); - - // This chain contains info that is filled in by the server. - // TLV(1): unknown - // TLV(2): date: on since - // TLV(3): date: on since - // TLV(4): unknown, usually 0000. Not in file-req or auto-msg-req - // TLV(6): sender's status - // TLV(F): a time in seconds, unknown - - disposeChain(&chain); - - // Update wLen - wLen -= buf - pBufStart; - } - - - // This is where the format specific data begins - - switch (wMessageFormat) { - - case 1: // Simple message format - handleRecvServMsgType1(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - case 2: // Encapsulated messages - handleRecvServMsgType2(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - case 4: // Typed messages - handleRecvServMsgType4(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - default: - NetLog_Server("Unknown format message thru server - Ref %u, Type: %u, UID: %s", dwRef, wMessageFormat, strUID(dwUin, szUID)); - break; - - } -} - - -char* CIcqProto::convertMsgToUserSpecificUtf(HANDLE hContact, const char *szMsg) -{ - WORD wCP = getSettingWord(hContact, "CodePage", m_wAnsiCodepage); - char *usMsg = NULL; - - if (wCP != CP_ACP) - usMsg = ansi_to_utf8_codepage(szMsg, wCP); - - return usMsg; -} - - -void CIcqProto::handleRecvServMsgType1(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE* pMsgTLV; - - if (wLen < 4) - { // just perform basic structure check - NetLog_Server("Message (format %u) - Ignoring empty message", 1); - return; - } - - // Unpack the first TLV(2) - unpackTypedTLV(buf, wLen, 2, &wTLVType, &wTLVLen, &pMsgTLV); - NetLog_Server("Message (format %u) - UID: %s", 1, strUID(dwUin, szUID)); - - // It must be TLV(2) - if (wTLVType == 2) - { - BYTE *pDataBuf = pMsgTLV; - oscar_tlv_chain *pChain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - - // TLV(2) contains yet another TLV chain with the following TLVs: - // TLV(1281): Capability - // TLV(257): This TLV contains the actual message (can be fragmented) - - if (pChain) - { - oscar_tlv* pMessageTLV; - oscar_tlv* pCapabilityTLV; - WORD wMsgPart = 1; - - // Find the capability TLV - pCapabilityTLV = pChain->getTLV(0x0501, 1); - if (pCapabilityTLV && (pCapabilityTLV->wLen > 0)) - { - WORD wDataLen; - BYTE *pDataBuf; - - wDataLen = pCapabilityTLV->wLen; - pDataBuf = pCapabilityTLV->pData; - - if (wDataLen > 0) - NetLog_Server("Message (format 1) - Message has %d caps.", wDataLen); - } - else - NetLog_Server("Message (format 1) - No message cap."); - - { // Parse the message parts, usually only one 0x0101 TLV containing the message, - // but in some cases there can be more 0x0101 TLVs containing message parts in - // different encodings (just like the new format of Offline Messages). - DWORD dwRecvTime; - char* szMsg = NULL; - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - int bAdded; - - HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded); - - while (pMessageTLV = pChain->getTLV(0x0101, wMsgPart)) - { // Loop thru all message parts - if (pMessageTLV->wLen > 4) - { - WORD wMsgLen; - BYTE *pMsgBuf; - WORD wEncoding; - WORD wCodePage; - char *szMsgPart = NULL; - int bMsgPartUnicode = FALSE; - - // The message begins with a encoding specification - // The first WORD is believed to have the following meaning: - // 0x00: US-ASCII - // 0x02: Unicode UCS-2 Big Endian encoding - // 0x03: local 8bit encoding - pMsgBuf = pMessageTLV->pData; - unpackWord(&pMsgBuf, &wEncoding); - unpackWord(&pMsgBuf, &wCodePage); - - wMsgLen = pMessageTLV->wLen - 4; - NetLog_Server("Message (format 1) - Part %d: Encoding is 0x%X, page is 0x%X", wMsgPart, wEncoding, wCodePage); - - switch (wEncoding) { - - case 2: // UCS-2 - { - WCHAR* usMsgPart = (WCHAR*)SAFE_MALLOC(wMsgLen + 2); - - unpackWideString(&pMsgBuf, usMsgPart, wMsgLen); - usMsgPart[wMsgLen/sizeof(WCHAR)] = 0; - - szMsgPart = make_utf8_string(usMsgPart); - if (!IsUSASCII(szMsgPart, strlennull(szMsgPart))) - bMsgPartUnicode = TRUE; - SAFE_FREE(&usMsgPart); - - break; - } - - case 0: // us-ascii - case 3: // ANSI - default: - { - // Copy the message text into a new proper string. - szMsgPart = (char*)SAFE_MALLOC(wMsgLen + 1); - memcpy(szMsgPart, pMsgBuf, wMsgLen); - szMsgPart[wMsgLen] = '\0'; - - break; - } - } - // Check if the new part is compatible with the message - if (!pre.flags && bMsgPartUnicode) - { // make the resulting message utf-8 encoded - need to append utf-8 encoded part - if (szMsg) - { // not necessary to convert - appending first part, only set flags - char *szUtfMsg = ansi_to_utf8_codepage(szMsg, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); - - SAFE_FREE(&szMsg); - szMsg = szUtfMsg; - } - pre.flags = PREF_UTF; - } - if (!bMsgPartUnicode && pre.flags == PREF_UTF) - { // convert message part to utf-8 and append - char *szUtfPart = ansi_to_utf8_codepage((char*)szMsgPart, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); - - SAFE_FREE(&szMsgPart); - szMsgPart = szUtfPart; - } - // Append the new message part - szMsg = (char*)SAFE_REALLOC(szMsg, strlennull(szMsg) + strlennull(szMsgPart) + 1); - - strcat(szMsg, szMsgPart); - SAFE_FREE(&szMsgPart); - } - wMsgPart++; - } - if (strlennull(szMsg)) - { - if (_strnicmp(szMsg, "", 6) == 0) - { // strip HTML formating from AIM message - szMsg = EliminateHtml(szMsg, strlennull(szMsg)); - } - - if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) - { // message is Ansi and contains national characters, create Unicode part by codepage - char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); - if (usMsg) - { - SAFE_FREE(&szMsg); - szMsg = usMsg; - pre.flags = PREF_UTF; - } - } - - dwRecvTime = (DWORD)time(NULL); - - { // Check if the message was received as offline - cookie_offline_messages *cookie; - - if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) - { - WORD wTimeTLVType, wTimeTLVLen; - BYTE *pTimeTLV; - - cookie->nMessages++; - - unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); - if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) - { // found Offline timestamp - BYTE *pBuf = pTimeTLV; - - unpackDWord(&pBuf, &dwRecvTime); - NetLog_Server("Message (format %u) - Offline timestamp is %s", 1, time2text(dwRecvTime)); - } - SAFE_FREE((void**)&pTimeTLV); - } - } - // Create and send the message event - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwRecvTime; - pre.szMessage = (char *)szMsg; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - NetLog_Server("Message (format 1) received"); - - // Save tick value - setSettingDword(ccs.hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); - } - else - NetLog_Server("Message (format %u) - Ignoring empty message", 1); - - SAFE_FREE(&szMsg); - } - - // Free the chain memory - disposeChain(&pChain); - } - else - NetLog_Server("Failed to read TLV chain in message (format 1)"); - } - else - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 1); - - SAFE_FREE((void**)&pMsgTLV); -} - - -void CIcqProto::handleRecvServMsgType2(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE *pDataBuf = NULL; - BYTE *pBuf; - - if (wLen < 4) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - // Unpack the first TLV(5) - unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); - NetLog_Server("Message (format %u) - UID: %s", 2, strUID(dwUin, szUID)); - pBuf = pDataBuf; - - // It must be TLV(5) - if (wTLVType == 5) - { - WORD wCommand; - oscar_tlv_chain* chain; - oscar_tlv* tlv; - DWORD q1,q2,q3,q4; - - if (wTLVLen < 26) - { // just check if all basic data is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - unpackWord(&pDataBuf, &wCommand); - wTLVLen -= 2; // Command 0x0000 - Normal message/file send request -#ifdef _DEBUG // 0x0001 - Abort request - NetLog_Server("Command is %u", wCommand); // 0x0002 - Acknowledge request -#endif - - // Some stuff we don't use - pDataBuf += 8; // dwID1 and dwID2 again - wTLVLen -= 8; - unpackDWord(&pDataBuf, &q1); - unpackDWord(&pDataBuf, &q2); - unpackDWord(&pDataBuf, &q3); - unpackDWord(&pDataBuf, &q4); // Message Capability - wTLVLen -= 16; - - if (CompareGUIDs(q1,q2,q3,q4, MCAP_SRV_RELAY_FMT)) - { // we surely have at least 4 bytes for TLV chain - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - SAFE_FREE((void**)&pBuf); - return; - } - - if (wTLVLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - // This TLV chain may contain the following TLVs: - // TLV(A): Acktype 0x0000 - normal message - // 0x0001 - file request / abort request - // 0x0002 - file ack - // TLV(F): Unknown - // TLV(3): External IP - // TLV(5): DC port (not to use for filetransfers) - // TLV(0x2711): The next message level - - chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - if (!chain) - { // sanity check - NetLog_Server("Message (format %u) - Invalid data", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - - // Update the saved DC info (if contact already exists) - if (hContact != INVALID_HANDLE_VALUE) - { - DWORD dwIP, dwExternalIP; - WORD wPort; - - if (dwExternalIP = chain->getDWord(0x03, 1)) - setSettingDword(hContact, "RealIP", dwExternalIP); - if (dwIP = chain->getDWord(0x04, 1)) - setSettingDword(hContact, "IP", dwIP); - if (wPort = chain->getWord(0x05, 1)) - setSettingWord(hContact, "UserPort", wPort); - - // Save tick value - BYTE bClientID = getSettingByte(hContact, "ClientID", 0); - if (bClientID == CLID_GENERIC || bClientID == CLID_ICQ6) - setSettingDword(hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); - else - setSettingDword(hContact, "TickTS", 0); - } - - // Parse the next message level - if (tlv = chain->getTLV(0x2711, 1)) - { - parseServRelayData(tlv->pData, tlv->wLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType); - } - else - { - NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); - } - // Clean up - disposeChain(&chain); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_REVERSE_DC_REQ)) - { // Handle reverse DC request - if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - SAFE_FREE((void**)&pBuf); - return; - } - if (wTLVLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - SAFE_FREE((void**)&pBuf); - return; - } - chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - if (!chain) - { // Malformed packet - NetLog_Server("Error: Malformed data in packet"); - SAFE_FREE((void**)&pBuf); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - // Parse the next message level - if (tlv = chain->getTLV(0x2711, 1)) - { - if (tlv->wLen == 0x1B) - { - BYTE *buf = tlv->pData; - DWORD dwUin; - - unpackLEDWord(&buf, &dwUin); - - HANDLE hContact = HContactFromUIN(dwUin, NULL); - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("Error: %s from unknown contact %u", "Reverse Connect Request", dwUin); - } - else - { - DWORD dwIp, dwPort; - WORD wVersion; - BYTE bMode; - - unpackDWord(&buf, &dwIp); - unpackLEDWord(&buf, &dwPort); - unpackByte(&buf, &bMode); - buf += 4; // unknown - if (dwPort) - buf += 4; // port, again? - else - unpackLEDWord(&buf, &dwPort); - unpackLEWord(&buf, &wVersion); - - setSettingDword(hContact, "IP", dwIp); - setSettingWord(hContact, "UserPort", (WORD)dwPort); - setSettingByte(hContact, "DCType", bMode); - setSettingWord(hContact, "Version", wVersion); - if (wVersion > 6) - { - cookie_reverse_connect *pCookie = (cookie_reverse_connect*)SAFE_MALLOC(sizeof(cookie_reverse_connect)); - - unpackLEDWord(&buf, (DWORD*)&pCookie->ft); - pCookie->dwMsgID1 = dwMsgID1; - pCookie->dwMsgID2 = dwMsgID2; - - OpenDirectConnection(hContact, DIRECTCONN_REVERSE, (void*)pCookie); - } - else - NetLog_Server("Warning: Unsupported direct protocol version in %s", "Reverse Connect Request"); - } - } - else - { - NetLog_Server("Malformed %s", "Reverse Connect Request"); - } - } - else - { - NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); - } - // Clean up - disposeChain(&chain); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_FILE_TRANSFER)) - { // this is an OFT packet - handleRecvServMsgOFT(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_CONTACTS)) - { // this is Contacts Transfer - handleRecvServMsgContacts(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); - } - else // here should be detection of extra data streams (Xtraz) - { - NetLog_Server("Unknown Message Format Capability"); - } - } - else - { - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 2); - } - - SAFE_FREE((void**)&pBuf); -} - - -void CIcqProto::parseServRelayData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType) -{ - WORD wId; - - if (wLen < 2) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - unpackLEWord(&pDataBuf, &wId); // Incorrect identification, but working - wLen -= 2; - - // Only 0x1B are real messages - if (wId == 0x001B) - { - WORD wVersion; - WORD wCookie; - DWORD dwGuid1,dwGuid2,dwGuid3,dwGuid4; - - if (wLen < 31) - { // just check if we have data to work with - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - unpackLEWord(&pDataBuf, &wVersion); - wLen -= 2; - - if (hContact != INVALID_HANDLE_VALUE) - setSettingWord(hContact, "Version", wVersion); - - unpackDWord(&pDataBuf, &dwGuid1); // plugin type GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - // Skip lots of unused stuff - pDataBuf += 9; - wLen -= 9; - - unpackLEWord(&pDataBuf, &wId); - wLen -= 2; - - unpackLEWord(&pDataBuf, &wCookie); - wLen -= 2; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) - { // is this a normal message ? - BYTE bMsgType; - BYTE bFlags; - WORD wStatus, wPritority; - WORD wMsgLen; - - if (wLen < 20) - { // check if there is everything that should be there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - pDataBuf += 12; /* all zeroes */ - wLen -= 12; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - unpackByte(&pDataBuf, &bFlags); - wLen -= 1; - - // Status - unpackLEWord(&pDataBuf, &wStatus); - wLen -= 2; - - // Priority - unpackLEWord(&pDataBuf, &wPritority); - wLen -= 2; - NetLog_Server("Priority: %u", wPritority); - - // Message - unpackLEWord(&pDataBuf, &wMsgLen); - wLen -= 2; - - // HANDLERS - switch (bMsgType) - { - // File messages, handled by the file module - case MTYPE_FILEREQ: - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - char* szMsg = (char *)_alloca(wMsgLen + 1); - memcpy(szMsg, pDataBuf, wMsgLen); - szMsg[wMsgLen] = '\0'; - pDataBuf += wMsgLen; - wLen -= wMsgLen; - - if (wAckType == 0 || wAckType == 1) - { - // File requests 7 - handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 7, FALSE); - } - else if (wAckType == 2) - { - // File reply 7 - handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); - } - else - { - NetLog_Server("Ignored strange file message"); - } - - break; - } - - // Chat messages, handled by the chat module - case MTYPE_CHAT: - { // TODO: this type is deprecated - break; - } - - // Plugin messages, need further parsing - case MTYPE_PLUGIN: - { - if (wLen < wMsgLen) - { // sanity check - NetLog_Server("Error: Malformed server Greeting message"); - return; - } - - parseServRelayPluginData(pDataBuf + wMsgLen, wLen - wMsgLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType, bFlags, wStatus, wCookie, wVersion); - break; - } - - // Everything else - default: - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - message_ack_params pMsgAck = {0}; - - pMsgAck.bType = MAT_SERVER_ADVANCED; - pMsgAck.dwUin = dwUin; - pMsgAck.dwMsgID1 = dwMsgID1; - pMsgAck.dwMsgID2 = dwMsgID2; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = bMsgType; - pMsgAck.bFlags = bFlags; - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, bMsgType, bFlags, wAckType, wLen, wMsgLen, (char*)pDataBuf, 0, &pMsgAck); - break; - } - } - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_INFO_PLUGIN)) - { // info manager plugin - obsolete - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - BYTE bMsgType; - BYTE bLevel; - - pDataBuf += 16; /* unused stuff */ - wLen -= 16; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - - pDataBuf += 3; // unknown - wLen -= 3; - unpackByte(&pDataBuf, &bLevel); - if (bLevel != 0 || wLen < 16) - { - NetLog_Server("Invalid %s Manager Plugin message from %u", "Info", dwUin); - return; - } - unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_INFO)) - { - NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "info"); - } - else - NetLog_Server("Unknown %s Manager message from %u", "Info", dwUin); - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_STATUS_PLUGIN)) - { // status manager plugin - obsolete - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - BYTE bMsgType; - BYTE bLevel; - - pDataBuf += 16; /* unused stuff */ - wLen -= 16; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - - pDataBuf += 3; // unknown - wLen -= 3; - unpackByte(&pDataBuf, &bLevel); - if (bLevel != 0 || wLen < 16) - { - NetLog_Server("Invalid %s Manager Plugin message from %u", "Status", dwUin); - return; - } - unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_STATUS)) - NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "status"); - else - NetLog_Server("Unknown %s Manager message from %u", "Status", dwUin); - } - else - NetLog_Server("Unknown signature (%08x-%08x-%08x-%08x) in message (format 2)", dwGuid1, dwGuid2, dwGuid3, dwGuid4); - } - else - NetLog_Server("Unknown wId1 (%u) in message (format 2)", wId); -} - - -void CIcqProto::parseServRelayPluginData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wVersion) -{ - int nTypeId; - WORD wFunction; - - NetLog_Server("Parsing Greeting message through server"); - - // Message plugin identification - if (!unpackPluginTypeId(&pDataBuf, &wLen, &nTypeId, &wFunction, FALSE)) return; - - if (wLen > 8) - { - DWORD dwLengthToEnd; - DWORD dwDataLen; - - // Length of remaining data - unpackLEDWord(&pDataBuf, &dwLengthToEnd); - - // Length of message - unpackLEDWord(&pDataBuf, &dwDataLen); - wLen -= 8; - - if (dwDataLen > wLen) - dwDataLen = wLen; - - if (nTypeId == MTYPE_FILEREQ && wAckType == 2) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is file ack"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); - } - else if (nTypeId == MTYPE_FILEREQ && wAckType == 1) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is a file request"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8, FALSE); - } - else if (nTypeId == MTYPE_CHAT && wAckType == 1) - { // TODO: this is deprecated - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is a chat request"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - // handleChatRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8); - } - else if (nTypeId == MTYPE_STATUSMSGEXT && wFunction >= 1 && wFunction <= 3) - { // handle extended status message request - int nMsgType = 0; - - switch (wFunction) - { - case 1: // Away - if (m_iStatus == ID_STATUS_ONLINE || m_iStatus == ID_STATUS_INVISIBLE) - nMsgType = MTYPE_AUTOONLINE; - else if (m_iStatus == ID_STATUS_AWAY) - nMsgType = MTYPE_AUTOAWAY; - else if (m_iStatus == ID_STATUS_FREECHAT) - nMsgType = MTYPE_AUTOFFC; - break; - - case 2: // Busy - if (m_iStatus == ID_STATUS_OCCUPIED) - nMsgType = MTYPE_AUTOBUSY; - else if (m_iStatus == ID_STATUS_DND) - nMsgType = MTYPE_AUTODND; - break; - - case 3: // N/A - if (m_iStatus == ID_STATUS_NA) - nMsgType = MTYPE_AUTONA; - } - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, bFlags, wAckType, dwLengthToEnd, 0, (char*)pDataBuf, MTF_PLUGIN | MTF_STATUS_EXTENDED, NULL); - } - else if (nTypeId) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - message_ack_params pMsgAck = {0}; - - pMsgAck.bType = MAT_SERVER_ADVANCED; - pMsgAck.dwUin = dwUin; - pMsgAck.dwMsgID1 = dwMsgID1; - pMsgAck.dwMsgID2 = dwMsgID2; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = nTypeId; - pMsgAck.bFlags = bFlags; - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nTypeId, bFlags, wAckType, dwLengthToEnd, (WORD)dwDataLen, (char*)pDataBuf, MTF_PLUGIN, &pMsgAck); - } - else - { - NetLog_Server("Unsupported plugin message type %d", nTypeId); - } - } - else - NetLog_Server("Error: Malformed server plugin message"); -} - - -void CIcqProto::handleRecvServMsgContacts(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand) -{ - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (wCommand == 0) - { // received contacts - if (wLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty contacts message", 2); - return; - } - oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, 0); - if (!chain) - { // sanity check - NetLog_Server("Message (format %u) - Invalid data", 2); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - - if (wAckType == 1) - { // it is really message containing contacts, parse them - oscar_tlv *tlvUins = chain->getTLV(0x2711, 1); - oscar_tlv *tlvNames = chain->getTLV(0x2712, 1); - - if (!tlvUins || tlvUins->wLen < 4) - { - NetLog_Server("Malformed '%s' message", "contacts"); - disposeChain(&chain); - return; - } - int nContacts = 0x10, iContact = 0; - ICQSEARCHRESULT **contacts = (ICQSEARCHRESULT**)SAFE_MALLOC(nContacts * sizeof(ICQSEARCHRESULT*)); - WORD wContactsGroup = 0; - int valid = 1; - BYTE *pBuffer = tlvUins->pData; - int nLen = tlvUins->wLen; - - while (nLen > 2) - { // parse UIDs - if (!wContactsGroup) - { - WORD wGroupLen; - - unpackWord(&pBuffer, &wGroupLen); - nLen -= 2; - if (nLen >= wGroupLen + 2) - { - pBuffer += wGroupLen; - unpackWord(&pBuffer, &wContactsGroup); - nLen -= wGroupLen + 2; - } - else - break; - } - else - { // group parsed, UIDs waiting - WORD wUidLen; - - unpackWord(&pBuffer, &wUidLen); - nLen -= 2; - if (nLen >= wUidLen) - { - char *szUid = (char*)SAFE_MALLOC(wUidLen + 1); - unpackString(&pBuffer, szUid, wUidLen); - nLen -= wUidLen; - - if (iContact >= nContacts) - { // the list is too small, resize it - nContacts += 0x10; - contacts = (ICQSEARCHRESULT**)SAFE_REALLOC(contacts, nContacts * sizeof(ICQSEARCHRESULT*)); - } - contacts[iContact] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); - contacts[iContact]->hdr.cbSize = sizeof(ICQSEARCHRESULT); - contacts[iContact]->hdr.flags = PSR_TCHAR; - contacts[iContact]->hdr.nick = null_strdup(_T("")); - contacts[iContact]->hdr.id = ansi_to_tchar(szUid); - - if (IsStringUIN(szUid)) - { // icq contact - contacts[iContact]->uin = atoi(szUid); - if (contacts[iContact]->uin == 0) - valid = 0; - } - else - { // aim contact - if (!strlennull(szUid)) - valid = 0; - } - iContact++; - - SAFE_FREE(&szUid); - } - else - { - if (wContactsGroup) valid = 0; - break; - } - - wContactsGroup--; - } - } - if (!iContact || !valid) - { - NetLog_Server("Malformed '%s' message", "contacts"); - disposeChain(&chain); - for (int i = 0; i < iContact; i++) - { - SAFE_FREE(&contacts[i]->hdr.id); - SAFE_FREE(&contacts[i]->hdr.nick); - SAFE_FREE((void**)&contacts[i]); - } - SAFE_FREE((void**)&contacts); - return; - } - nContacts = iContact; - if (tlvNames && tlvNames->wLen >= 4) - { // parse names, if available - pBuffer = tlvNames->pData; - nLen = tlvNames->wLen; - iContact = 0; - - while (nLen > 2) - { // parse Names - if (!wContactsGroup) - { - WORD wGroupLen; - - unpackWord(&pBuffer, &wGroupLen); - nLen -= 2; - if (nLen >= wGroupLen + 2) - { - pBuffer += wGroupLen; - unpackWord(&pBuffer, &wContactsGroup); - nLen -= wGroupLen + 2; - } - else - break; - } - else - { // group parsed, Names waiting - WORD wNickLen; - - unpackWord(&pBuffer, &wNickLen); - nLen -= 2; - if (nLen >= wNickLen) - { - WORD wNickTLV, wNickTLVLen; - char *pNick = NULL; - - unpackTypedTLV(pBuffer, wNickLen, 0x01, &wNickTLV, &wNickTLVLen, (LPBYTE*)&pNick); - if (wNickTLV == 0x01) - { - SAFE_FREE(&contacts[iContact]->hdr.nick); - contacts[iContact]->hdr.nick = utf8_to_tchar(pNick); - } - else - SAFE_FREE(&pNick); - pBuffer += wNickLen; - nLen -= wNickLen; - - iContact++; - if (iContact >= nContacts) break; - } - else - break; - - wContactsGroup--; - } - } - } - - if (!valid) - { - NetLog_Server("Malformed '%s' message", "contacts"); - } - else - { - int bAdded; - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - hContact = HContactFromUID(dwUin, szUID, &bAdded); - - // ack the message - icq_sendContactsAck(dwUin, szUID, dwID1, dwID2); - - ccs.szProtoService = PSR_CONTACTS; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = (DWORD)time(NULL); - pre.szMessage = (char *)contacts; - pre.lParam = nContacts; - pre.flags = PREF_TCHAR; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - - for (int i = 0; i < iContact; i++) - { - SAFE_FREE(&contacts[i]->hdr.id); - SAFE_FREE(&contacts[i]->hdr.nick); - SAFE_FREE((void**)&contacts[i]); - } - SAFE_FREE((void**)&contacts); - } - else - NetLog_Server("Error: Received unknown contacts message, ignoring."); - // Clean up - disposeChain(&chain); - } - else if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - return; - } - else if (wCommand == 2) - { // acknowledgement - DWORD dwCookie; - HANDLE hCookieContact; - - if (FindMessageCookie(dwID1, dwID2, &dwCookie, &hCookieContact, NULL)) - { - if (hCookieContact != hContact) - NetLog_Server("Warning: Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); - - BroadcastAck(hContact, ACKTYPE_CONTACTS, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); - - ReleaseCookie(dwCookie); - } - else - NetLog_Server("Warning: Unexpected Contact Transfer ack from %s", strUID(dwUin, szUID)); - } -} - - -void CIcqProto::handleRecvServMsgType4(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE* pDataBuf; - DWORD dwUin2; - - if (wLen < 2) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 4); - return; - } - - // Unpack the first TLV(5) - unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); - NetLog_Server("Message (format %u) - UID: %s", 4, strUID(dwUin, szUID)); - - // It must be TLV(5) - if (wTLVType == 5) - { - BYTE bMsgType; - BYTE bFlags; - BYTE* pmsg = pDataBuf; - WORD wMsgLen; - - - unpackLEDWord(&pmsg, &dwUin2); - - if (dwUin2 == dwUin) - { - unpackByte(&pmsg, &bMsgType); - unpackByte(&pmsg, &bFlags); - unpackLEWord(&pmsg, &wMsgLen); - - if (bMsgType == 0 && wMsgLen == 1) - { - NetLog_Server("User %u probably checks his ignore state.", dwUin); - } - else - { - cookie_offline_messages *cookie; - DWORD dwRecvTime = (DWORD)time(NULL); - - if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) - { - WORD wTimeTLVType, wTimeTLVLen; - BYTE *pTimeTLV = NULL; - - cookie->nMessages++; - - unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); - if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) - { // found Offline timestamp - BYTE *pBuf = pTimeTLV; - - unpackDWord(&pBuf, &dwRecvTime); - NetLog_Server("Message (format %u) - Offline timestamp is %s", 4, time2text(dwRecvTime)); - } - SAFE_FREE((void**)&pTimeTLV); - } - - if (bMsgType == MTYPE_PLUGIN) - { - WORD wLen = wTLVLen - 8; - int typeId; - - NetLog_Server("Parsing Greeting message through server"); - - pmsg += wMsgLen; - wLen -= wMsgLen; - - if (unpackPluginTypeId(&pmsg, &wLen, &typeId, NULL, FALSE) && wLen > 8) - { - DWORD dwLengthToEnd; - DWORD dwDataLen; - - // Length of remaining data - unpackLEDWord(&pmsg, &dwLengthToEnd); - - // Length of message - unpackLEDWord(&pmsg, &dwDataLen); - wLen -= 8; - - if (dwDataLen > wLen) - dwDataLen = wLen; - - if (typeId) - { - uid_str szUID; - handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, typeId, bFlags, 0, dwLengthToEnd, (WORD)dwDataLen, (char*)pmsg, MTF_PLUGIN, NULL); - } - else - { - NetLog_Server("Unsupported plugin message type %d", typeId); - } - } - } - else - { - uid_str szUID; - handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, bMsgType, bFlags, 0, wTLVLen - 8, wMsgLen, (char*)pmsg, 0, NULL); - } - } - } - else - { - NetLog_Server("Ignoring spoofed TYPE4 message thru server from %d", dwUin); - } - } - else - { - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 4); - } - - SAFE_FREE((void**)&pDataBuf); -} - - -// -// Helper functions -// - -static int TypeGUIDToTypeId(DWORD dwGuid1, DWORD dwGuid2, DWORD dwGuid3, DWORD dwGuid4, WORD wType) -{ - int nTypeID = MTYPE_UNKNOWN; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_STATUSMSGEXT)) - { - nTypeID = MTYPE_STATUSMSGEXT; - } - else if (wType==MGTYPE_UNDEFINED) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) - { // icq6 message ack - nTypeID = MTYPE_PLAIN; - } - } - else if (wType==MGTYPE_STANDARD_SEND) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_WEBURL)) - { - nTypeID = MTYPE_URL; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) - { - nTypeID = MTYPE_CONTACTS; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CHAT)) - { - nTypeID = MTYPE_CHAT; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_FILE)) - { - nTypeID = MTYPE_FILEREQ; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_GREETING_CARD)) - { - nTypeID = MTYPE_GREETINGCARD; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_MESSAGE)) - { - nTypeID = MTYPE_MESSAGE; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_SMS_MESSAGE)) - { - nTypeID = MTYPE_SMS_MESSAGE; - } - } - else if (wType==MGTYPE_CONTACTS_REQUEST) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) - { - nTypeID = MTYPE_REQUESTCONTACTS; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) - { - nTypeID = MTYPE_SCRIPT_DATA; - } - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) - { - if (wType==MGTYPE_SCRIPT_INVITATION) - { - nTypeID = MTYPE_SCRIPT_INVITATION; - } - else if (wType==MGTYPE_SCRIPT_NOTIFY) - { - nTypeID = MTYPE_SCRIPT_NOTIFY; - } - } - - return nTypeID; -} - - -int CIcqProto::unpackPluginTypeId(BYTE **pBuffer, WORD *pwLen, int *pTypeId, WORD *pFunctionId, BOOL bThruDC) -{ - WORD wLen = *pwLen; - WORD wInfoLen; - DWORD dwPluginNameLen; - DWORD q1,q2,q3,q4; - WORD qt; - - if (wLen < 24) - return 0; // Failure - - unpackLEWord(pBuffer, &wInfoLen); - - unpackDWord(pBuffer, &q1); // get data GUID & function id - unpackDWord(pBuffer, &q2); - unpackDWord(pBuffer, &q3); - unpackDWord(pBuffer, &q4); - unpackLEWord(pBuffer, &qt); - wLen -= 20; - - if (pFunctionId) *pFunctionId = qt; - - unpackLEDWord(pBuffer, &dwPluginNameLen); - wLen -= 4; - - if (dwPluginNameLen > wLen) - { // check for malformed plugin name - dwPluginNameLen = wLen; - NetLog_Uni(bThruDC, "Warning: malformed size of plugin name."); - } - char *szPluginName = (char *)_alloca(dwPluginNameLen + 1); - memcpy(szPluginName, *pBuffer, dwPluginNameLen); - szPluginName[dwPluginNameLen] = '\0'; - wLen -= (WORD)dwPluginNameLen; - - *pBuffer += dwPluginNameLen; - - int typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt); - if (!typeId) - NetLog_Uni(bThruDC, "Error: Unknown type {%08x-%08x-%08x-%08x:%04x}: %s", q1,q2,q3,q4,qt, szPluginName); - - if (wInfoLen >= 22 + dwPluginNameLen) - { // sanity checking - wInfoLen -= (WORD)(22 + dwPluginNameLen); - - // check if enough data is available - skip remaining bytes of info block - if (wLen >= wInfoLen) - { - *pBuffer += wInfoLen; - wLen -= wInfoLen; - } - } - - *pwLen = wLen; - *pTypeId = typeId; - - return 1; // Success -} - - -int getPluginTypeIdLen(int nTypeID) -{ - switch (nTypeID) - { - case MTYPE_SCRIPT_NOTIFY: - return 0x51; - - case MTYPE_FILEREQ: - return 0x2B; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOBUSY: - case MTYPE_AUTODND: - case MTYPE_AUTOFFC: - return 0x3C; - - case MTYPE_AUTONA: - return 0x3B; - - default: - return 0; - } -} - - -void packPluginTypeId(icq_packet *packet, int nTypeID) -{ - switch (nTypeID) - { - case MTYPE_SCRIPT_NOTIFY: - packLEWord(packet, 0x04f); // Length - - packGUID(packet, MGTYPE_XTRAZ_SCRIPT); // Message Type GUID - packLEWord(packet, MGTYPE_SCRIPT_NOTIFY); // Function ID - packLEDWord(packet, 0x002a); // Request type string - packBuffer(packet, (LPBYTE)"Script Plug-in: Remote Notification Arrive", 0x002a); - - packDWord(packet, 0x00000100); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packWord(packet, 0x0000); - packByte(packet, 0x00); - - break; - - case MTYPE_FILEREQ: - packLEWord(packet, 0x029); // Length - - packGUID(packet, MGTYPE_FILE); // Message Type GUID - packWord(packet, 0x0000); // Unknown - packLEDWord(packet, 0x0004); // Request type string - packBuffer(packet, (LPBYTE)"File", 0x0004); - - packDWord(packet, 0x00000100); // More unknown binary stuff - packDWord(packet, 0x00010000); - packDWord(packet, 0x00000000); - packWord(packet, 0x0000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOFFC: - packLEWord(packet, 0x03A); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 1); // Function ID - packLEDWord(packet, 0x13); // Request type string - packBuffer(packet, (LPBYTE)"Away Status Message", 0x13); - - packDWord(packet, 0x01000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTOBUSY: - case MTYPE_AUTODND: - packLEWord(packet, 0x03A); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 2); // Function ID - packLEDWord(packet, 0x13); // Request type string - packBuffer(packet, (LPBYTE)"Busy Status Message", 0x13); - - packDWord(packet, 0x02000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTONA: - packLEWord(packet, 0x039); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 3); // Function ID - packLEDWord(packet, 0x12); // Request type string - packBuffer(packet, (LPBYTE)"N/A Status Message", 0x12); - - packDWord(packet, 0x03000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - } -} - - -void CIcqProto::handleStatusMsgReply(const char *szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char *szMsg, int nMsgFlags) -{ - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("%sIgnoring status message from unknown contact %u", szPrefix, dwUin); - return; - } - - int status = AwayMsgTypeToStatus(bMsgType); - if (status == ID_STATUS_OFFLINE) - { - NetLog_Server("%sIgnoring unknown status message from %u", szPrefix, dwUin); - return; - } - - // it is probably UTF-8 status reply - if (wVersion == 9 || (nMsgFlags & MTF_PLUGIN) && wVersion == 10) - { - if (UTF8_IsValid(szMsg)) pre.flags |= PREF_UTF; - } - - ccs.szProtoService = PSR_AWAYMSG; - ccs.hContact = hContact; - ccs.wParam = status; - ccs.lParam = (LPARAM)⪯ - pre.szMessage = (char*)szMsg; - pre.timestamp = time(NULL); - pre.lParam = wCookie; - - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); -} - - -HANDLE CIcqProto::handleMessageAck(DWORD dwUin, char *szUID, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags, int nMsgFlags) -{ - if (bFlags == 3) - { - HANDLE hCookieContact; - cookie_message_data *pCookieData = NULL; - - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { - NetLog_Server("%sIgnoring unrequested status message from %u", "handleMessageAck: ", dwUin); - - ReleaseCookie(wCookie); - return INVALID_HANDLE_VALUE; - } - - if (hContact != hCookieContact) - { - NetLog_Server("%sAck Contact does not match Cookie Contact(0x%x != 0x%x)", "handleMessageAck: ", hContact, hCookieContact); - - ReleaseCookie(wCookie); - return INVALID_HANDLE_VALUE; - } - ReleaseCookie(wCookie); - - handleStatusMsgReply("handleMessageAck: ", hContact, dwUin, wVersion, type, wCookie, (char*)buf, nMsgFlags); - } - else - { - // Should not happen - NetLog_Server("%sIgnored type %u ack message (this should not happen)", "handleMessageAck: ", type); - } - - return INVALID_HANDLE_VALUE; -} - - -/* this function send all acks from handleMessageTypes */ -void CIcqProto::sendMessageTypesAck(HANDLE hContact, int bUnicode, message_ack_params *pArgs) -{ - if (pArgs) - { - if ((pArgs->msgType == MTYPE_PLAIN && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_MESSAGE)) - || (pArgs->msgType == MTYPE_URL && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_URL)) - || pArgs->msgType == MTYPE_CONTACTS) - { - if (pArgs->bType == MAT_SERVER_ADVANCED) - { // Only ack message packets - icq_sendAdvancedMsgAck(pArgs->dwUin, pArgs->dwMsgID1, pArgs->dwMsgID2, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags); - } - else if (pArgs->bType == MAT_DIRECT) - { // Send acknowledgement - icq_sendDirectMsgAck(pArgs->pDC, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags, bUnicode ? (char *)CAP_UTF8MSGS : NULL); - } - } - } -} - - -/* this function also processes direct packets, so it should be bulletproof */ -/* pMsg points to the beginning of the message */ -void CIcqProto::handleMessageTypes(DWORD dwUin, char *szUID, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, int nMsgFlags, message_ack_params *pAckParams) -{ - HANDLE hContact = INVALID_HANDLE_VALUE; - BOOL bThruDC = (nMsgFlags & MTF_DIRECT) == MTF_DIRECT; - int bAdded; - - - if (dwDataLen < wMsgLen) - { - NetLog_Uni(bThruDC, "Ignoring overflowed message"); - return; - } - - if (wAckType == 2) - { - handleMessageAck(dwUin, szUID, wCookie, wVersion, type, wMsgLen, (LPBYTE)pMsg, (BYTE)flags, nMsgFlags); - return; - } - - char *szMsg = (char *)SAFE_MALLOC(wMsgLen + 1); - if (wMsgLen > 0) - { - memcpy(szMsg, pMsg, wMsgLen); - pMsg += wMsgLen; - dwDataLen -= wMsgLen; - } - szMsg[wMsgLen] = '\0'; - - - char* pszMsgField[2*MAX_CONTACTSSEND+1]; - int nMsgFields = 0; - - pszMsgField[0] = szMsg; - if (type == MTYPE_URL || type == MTYPE_AUTHREQ || type == MTYPE_ADDED || type == MTYPE_CONTACTS || type == MTYPE_EEXPRESS || type == MTYPE_WWP) - { - for (char *pszMsg=szMsg, nMsgFields=1; *pszMsg; pszMsg++) - { - if ((BYTE)*pszMsg == 0xFE) - { - *pszMsg = '\0'; - pszMsgField[nMsgFields++] = pszMsg + 1; - if (nMsgFields >= SIZEOF(pszMsgField)) - break; - } - } - } - - switch (type) { - - case MTYPE_PLAIN: /* plain message */ - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - // Check if this message is marked as UTF8 encoded - if (dwDataLen > 12) - { - DWORD dwGuidLen = 0; - int bDoubleMsg = 0; - - if (bThruDC) - { - DWORD dwExtraLen = *(DWORD*)pMsg; - - if (dwExtraLen < dwDataLen && !strncmp(szMsg, "{\\rtf", 5)) - { // it is icq5 sending us crap, get real message from it - WCHAR* usMsg = (WCHAR*)_alloca((dwExtraLen + 1)*sizeof(WCHAR)); - // make sure it is null-terminated - wcsncpy(usMsg, (WCHAR*)(pMsg + 4), dwExtraLen); - usMsg[dwExtraLen] = '\0'; - SAFE_FREE(&szMsg); - szMsg = (char*)make_utf8_string(usMsg); - - if (!IsUnicodeAscii(usMsg, dwExtraLen)) - pre.flags = PREF_UTF; // only mark real non-ascii messages as unicode - - bDoubleMsg = 1; - } - } - - if (!bDoubleMsg) - { - dwGuidLen = *(DWORD*)(pMsg+8); - dwDataLen -= 12; - pMsg += 12; - } - - while ((dwGuidLen >= 38) && (dwDataLen >= dwGuidLen)) - { - if (!strncmp(pMsg, CAP_UTF8MSGS, 38)) - { // Found UTF8 cap, convert message to ansi - pre.flags = PREF_UTF; - break; - } - else if (!strncmp(pMsg, CAP_RTFMSGS, 38)) - { // Found RichText cap - NetLog_Uni(bThruDC, "Warning: User %u sends us RichText.", dwUin); - break; - } - - dwGuidLen -= 38; - dwDataLen -= 38; - pMsg += 38; - } - } - - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, pre.flags & PREF_UTF, pAckParams); - - if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) - { // message is Ansi and contains national characters, create Unicode part by codepage - char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); - if (usMsg) - { - SAFE_FREE(&szMsg); - szMsg = (char*)usMsg; - pre.flags = PREF_UTF; - } - } - - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)szMsg; - - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - break; - - case MTYPE_URL: - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - if (nMsgFields < 2) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "URL"); - break; - } - - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, 0, pAckParams); - - char *szTitle = ICQTranslateUtf(LPGEN("Incoming URL:")); - char *szDataDescr = ansi_to_utf8(pszMsgField[0]); - char *szDataUrl = ansi_to_utf8(pszMsgField[1]); - char *szBlob = (char *)SAFE_MALLOC(strlennull(szTitle) + strlennull(szDataDescr) + strlennull(szDataUrl) + 8); - strcpy(szBlob, szTitle); - strcat(szBlob, " "); - strcat(szBlob, szDataDescr); // Description - strcat(szBlob, "\r\n"); - strcat(szBlob, szDataUrl); // URL - SAFE_FREE(&szTitle); - SAFE_FREE(&szDataDescr); - SAFE_FREE(&szDataUrl); - - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)szBlob; - pre.flags = PREF_UTF; - - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - SAFE_FREE(&szBlob); - } - break; - - case MTYPE_AUTHREQ: /* auth request */ - /* format: nick FE first FE last FE email FE unk-char FE msg 00 */ - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - char* szBlob; - char* pCurBlob; - - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "auth req"); - break; - } - - ccs.szProtoService=PSR_AUTH; - ccs.hContact=hContact=HContactFromUIN(dwUin, &bAdded); - ccs.wParam=0; - ccs.lParam=(LPARAM)⪯ - pre.timestamp=dwTimestamp; - pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+5; - - /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/ - pCurBlob=szBlob=(char *)_alloca(pre.lParam); - memcpy(pCurBlob,&dwUin,sizeof(DWORD)); pCurBlob+=sizeof(DWORD); - memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE); - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[5]); - pre.szMessage=(char *)szBlob; - - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); - } - break; - - case MTYPE_ADDED: /* 'you were added' */ - /* format: nick FE first FE last FE email 00 */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 4) - { - NetLog_Server("Malformed '%s' message", "you were added"); - break; - } - - hContact = HContactFromUIN(dwUin, &bAdded); - - /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) */ - cbBlob=sizeof(DWORD)*2+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+4; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - *(DWORD*)pCurBlob = dwUin; pCurBlob += sizeof(DWORD); - *(DWORD*)pCurBlob = DWORD(hContact); pCurBlob += sizeof(DWORD); - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, EVENTTYPE_ADDED, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_CONTACTS: - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - char* pszNContactsEnd; - int nContacts; - int i; - - - if (nMsgFields < 3 - || (nContacts = strtol(pszMsgField[0], &pszNContactsEnd, 10)) == 0 - || pszNContactsEnd - pszMsgField[0] != (int)strlennull(pszMsgField[0]) - || nMsgFields < nContacts * 2 + 1) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); - break; - } - - int valid = 1; - ICQSEARCHRESULT** isrList = (ICQSEARCHRESULT**)_alloca(nContacts * sizeof(ICQSEARCHRESULT*)); - for (i = 0; i < nContacts; i++) - { - isrList[i] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); - isrList[i]->hdr.cbSize = sizeof(ICQSEARCHRESULT); - isrList[i]->hdr.flags = PSR_TCHAR; - if (IsStringUIN(pszMsgField[1 + i * 2])) - { // icq contact - isrList[i]->uin = atoi(pszMsgField[1 + i * 2]); - if (isrList[i]->uin == 0) - valid = 0; - } - else - { // aim contact - if (!strlennull(pszMsgField[1 + i * 2])) - valid = 0; - } - isrList[i]->hdr.id = ansi_to_tchar(pszMsgField[1 + i * 2]); - isrList[i]->hdr.nick = ansi_to_tchar(pszMsgField[2 + i * 2]); - } - - if (!valid) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); - } - else - { - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, 0, pAckParams); - - ccs.szProtoService = PSR_CONTACTS; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)isrList; - pre.lParam = nContacts; - pre.flags = PREF_TCHAR; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - - for (i = 0; i < nContacts; i++) - { - SAFE_FREE(&isrList[i]->hdr.id); - SAFE_FREE(&isrList[i]->hdr.nick); - SAFE_FREE((void**)&isrList[i]); - } - } - break; - - case MTYPE_PLUGIN: // FIXME: this should be removed - it is never called - hContact = NULL; - - switch(dwUin) - { - case 1111: /* icqmail 'you've got mail' - not processed */ - break; - } - break; - - case MTYPE_SMS_MESSAGE: - /* it's a SMS message from a mobile - broadcast to SMS plugin */ - if (dwUin != 1002) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "SMS Mobile"); - break; - } - NetLog_Server("Received SMS Mobile message"); - - BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, NULL, (LPARAM)szMsg); - break; - - case MTYPE_STATUSMSGEXT: - /* it's either extended StatusMsg reply from icq2003b or a IcqWebMessage */ - if (dwUin == 1003) - { - NetLog_Server("Received ICQWebMessage - NOT SUPPORTED"); - } - break; - - case MTYPE_WWP: - /* format: fromname FE FE FE fromemail FE unknownbyte FE 'Sender IP: xxx.xxx.xxx.xxx' 0D 0A body */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "web pager"); - break; - } - - /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ - cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, ICQEVENTTYPE_WEBPAGER, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_EEXPRESS: - /* format: fromname FE FE FE fromemail FE unknownbyte FE body */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "e-mail express"); - break; - } - - /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ - cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, ICQEVENTTYPE_EMAILEXPRESS, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_REQUESTCONTACTS: - /* it's a contacts-request */ - NetLog_Uni(bThruDC, "Received %s from %u", "Request for Contacts", dwUin); - break; - - case MTYPE_GREETINGCARD: - /* it's a greeting card */ - NetLog_Uni(bThruDC, "Received %s from %u", "Greeting Card", dwUin); - break; - - case MTYPE_SCRIPT_NOTIFY: - /* it's a xtraz notify request */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Notify Request", dwUin); - handleXtrazNotify(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_SCRIPT_INVITATION: - /* it's a xtraz invitation to session */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Invitation", dwUin); - handleXtrazInvitation(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_SCRIPT_DATA: - /* it's a xtraz data packet */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz data packet", dwUin); - handleXtrazData(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOBUSY: - case MTYPE_AUTONA: - case MTYPE_AUTODND: - case MTYPE_AUTOFFC: - { - char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(type)); - if (szMsg) - { - struct rates_status_message_response: public rates_queue_item - { - protected: - virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) - { - rates_status_message_response *pDest = (rates_status_message_response*)aDest; - if (!pDest) - pDest = new rates_status_message_response(ppro, wGroup); - - pDest->bExtended = bExtended; - pDest->dwMsgID1 = dwMsgID1; - pDest->dwMsgID2 = dwMsgID2; - pDest->wCookie = wCookie; - pDest->wVersion = wVersion; - pDest->nMsgType = nMsgType; - - return rates_queue_item::copyItem(pDest); - }; - public: - rates_status_message_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { }; - virtual ~rates_status_message_response() { }; - - virtual void execute() - { - char **pszMsg = ppro->MirandaStatusToAwayMsg(AwayMsgTypeToStatus(nMsgType)); - if (bExtended) - ppro->icq_sendAwayMsgReplyServExt(dwUin, szUid, dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, pszMsg); - else if (dwUin) - ppro->icq_sendAwayMsgReplyServ(dwUin, dwMsgID1, dwMsgID2, wCookie, wVersion, (BYTE)nMsgType, pszMsg); - else - ppro->NetLog_Server("Error: Malformed UIN in packet"); - }; - - BOOL bExtended; - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD wCookie; - WORD wVersion; - int nMsgType; - }; - - m_ratesMutex->Enter(); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); - m_ratesMutex->Leave(); - - rates_status_message_response rr(this, wGroup); - rr.bExtended = (nMsgFlags & MTF_STATUS_EXTENDED) == MTF_STATUS_EXTENDED; - rr.hContact = hContact; - rr.dwUin = dwUin; - rr.szUid = szUID; - rr.dwMsgID1 = dwMsgID; - rr.dwMsgID2 = dwMsgID2; - rr.wCookie = wCookie; - rr.wVersion = wVersion; - rr.nMsgType = type; - - handleRateItem(&rr, RQT_RESPONSE); - } - - break; - } - - case MTYPE_FILEREQ: // Never happens - default: - NetLog_Uni(bThruDC, "Unprocessed message type %d", type); - break; - - } - - SAFE_FREE(&szMsg); -} - - -void CIcqProto::handleRecvMsgResponse(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - DWORD dwCookie; - WORD wMessageFormat; - WORD wStatus; - WORD bMsgType = 0; - BYTE bFlags; - WORD wLength; - HANDLE hCookieContact; - DWORD dwMsgID1, dwMsgID2; - WORD wVersion = 0; - cookie_message_data *pCookieData = NULL; - - - unpackLEDWord(&buf, &dwMsgID1); // Message ID - unpackLEDWord(&buf, &dwMsgID2); - wLen -= 8; - - unpackWord(&buf, &wMessageFormat); - wLen -= 2; - if (wMessageFormat != 2) - { - NetLog_Server("SNAC(4.B) Unknown type"); - return; - } - - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); - - buf += 2; // 3. unknown - wLen -= 2; - - if (!FindMessageCookie(dwMsgID1, dwMsgID2, &dwCookie, &hCookieContact, &pCookieData)) - { - NetLog_Server("SNAC(4.B) Received an ack that I did not ask for from (%u)", dwUin); - return; - } - - if (IsValidOscarTransfer(pCookieData)) - { // it is OFT response - handleRecvServResponseOFT(buf, wLen, dwUin, szUid, pCookieData); - return; - } - - if (!dwUin) - { // AIM cannot send this - just sanity - NetLog_Server("Error: Invalid UID in message response."); - return; - } - - // Length of sub chunk? - if (wLen >= 2) - { - unpackLEWord(&buf, &wLength); - wLen -= 2; - } - else - wLength = 0; - - if (wLength == 0x1b && pCookieData->bMessageType != MTYPE_REVERSE_REQUEST) - { // this can be v8 greeting message reply - WORD wCookie; - - unpackLEWord(&buf, &wVersion); - buf += 27; /* unknowns from the msg we sent */ - wLen -= 29; - - // Message sequence (SEQ2) - unpackLEWord(&buf, &wCookie); - wLen -= 2; - - // Unknown (12 bytes) - buf += 12; - wLen -= 12; - - // Message type - unpackByte(&buf, (BYTE*)&bMsgType); - unpackByte(&buf, &bFlags); - wLen -= 2; - - // Status - unpackLEWord(&buf, &wStatus); - wLen -= 2; - - // Priority? - buf += 2; - wLen -= 2; - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { // use old reliable method - NetLog_Server("Warning: Invalid cookie in %s from (%u)", "message response", dwUin); - - if (pCookieData->bMessageType != MTYPE_AUTOAWAY && bFlags == 3) - { // most probably a broken ack of some kind (e.g. from R&Q), try to fix that - bMsgType = pCookieData->bMessageType; - bFlags = 0; - - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - } - } - else if (bMsgType != MTYPE_PLUGIN && pCookieData->bMessageType != MTYPE_AUTOAWAY) - { // just because some clients break it... - dwCookie = wCookie; - - if (bMsgType != pCookieData->bMessageType) - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - - bMsgType = pCookieData->bMessageType; - } - else if (pCookieData->bMessageType == MTYPE_AUTOAWAY && bMsgType != MTYPE_PLUGIN) - { - if (bMsgType != pCookieData->nAckType) - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - } - } - else - { - bMsgType = pCookieData->bMessageType; - bFlags = 0; - } - - if (hCookieContact != hContact) - { - NetLog_Server("SNAC(4.B) Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); - - ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe - return; - } - - if (bFlags == 3) // A status message reply - { - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, bMsgType, (WORD)dwCookie, (char*)(buf + 2), 0); - } - else - { // An ack of some kind - int ackType; - - - if (hContact == NULL || hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("SNAC(4.B) Message from unknown contact (%u)", dwUin); - - ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe - return; - } - - switch (bMsgType) { - - case MTYPE_FILEREQ: - { - char* szMsg; - WORD wMsgLen; - - // Message length - unpackLEWord(&buf, &wMsgLen); - wLen -= 2; - szMsg = (char *)_alloca(wMsgLen + 1); - szMsg[wMsgLen] = '\0'; - if (wMsgLen > 0) - { - memcpy(szMsg, buf, wMsgLen); - buf += wMsgLen; - wLen -= wMsgLen; - } - handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); - // No success protoack will be sent here, since all file requests - // will have been 'sent' when the server returns its ack - return; - } - - case MTYPE_PLUGIN: - { - WORD wMsgLen; - DWORD dwLengthToEnd; - DWORD dwDataLen; - int typeId; - WORD wFunctionId; - - - if (wLength != 0x1B) - { - NetLog_Server("Invalid Greeting %s", "message response"); - - ReleaseCookie(dwCookie); - return; - } - - NetLog_Server("Parsing Greeting %s", "message response"); - - // Message - unpackLEWord(&buf, &wMsgLen); - wLen -= 2; - buf += wMsgLen; - wLen -= wMsgLen; - - // This packet is malformed. Possibly a file accept from Miranda IM 0.1.2.1 - if (wLen < 20) - { - ReleaseCookie(dwCookie); - return; - } - - if (!unpackPluginTypeId(&buf, &wLen, &typeId, &wFunctionId, FALSE)) - { - ReleaseCookie(dwCookie); - return; - } - - if (wLen < 4) - { - NetLog_Server("Error: Invalid greeting %s", "message response"); - - ReleaseCookie(dwCookie); - return; - } - - // Length of remaining data - unpackLEDWord(&buf, &dwLengthToEnd); - wLen -= 4; - - if (wLen >= 4 && dwLengthToEnd > 0) - unpackLEDWord(&buf, &dwDataLen); // Length of message - else - dwDataLen = 0; - - - switch (typeId) - { - case MTYPE_PLAIN: - if (pCookieData && pCookieData->bMessageType == MTYPE_AUTOAWAY && dwLengthToEnd >= 4) - { // ICQ 6 invented this - char *szMsg = (char*)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, 0); - - ReleaseCookie(dwCookie); - return; - } - else - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_FILEREQ: - { - NetLog_Server("This is file ack"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - buf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); - // No success protoack will be sent here, since all file requests - // will have been 'sent' when the server returns its ack - } - return; - - case MTYPE_SCRIPT_NOTIFY: - { - char *szMsg = (char*)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - - handleXtrazNotifyResponse(dwUin, hContact, (WORD)dwCookie, szMsg, dwDataLen); - - ReleaseCookie(dwCookie); - } - return; - - case MTYPE_STATUSMSGEXT: - { // handle Away Message response (ICQ 6) - char *szMsg = (char*)SAFE_MALLOC(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - szMsg = EliminateHtml(szMsg, dwDataLen); - - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, MTF_PLUGIN | MTF_STATUS_EXTENDED); - - SAFE_FREE(&szMsg); - - ReleaseCookie(dwCookie); - } - return; - - default: - NetLog_Server("Error: Unknown plugin message response, type %d.", typeId); - return; - } - } - break; - - case MTYPE_PLAIN: - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_AUTHOK: - case MTYPE_AUTHDENY: - ackType = ACKTYPE_AUTHREQ; - break; - - case MTYPE_ADDED: - ackType = ACKTYPE_ADDED; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_REVERSE_REQUEST: - { - cookie_reverse_connect *pReverse = (cookie_reverse_connect*)pCookieData; - - if (pReverse->ft) - { - filetransfer *ft = (filetransfer*)pReverse->ft; - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - } - NetLog_Server("Reverse Connect request failed"); - // Set DC status to failed - setSettingByte(hContact, "DCStatus", 2); - - ReleaseCookie(dwCookie); - } - return; - - case MTYPE_CHAT: - default: - NetLog_Server("SNAC(4.B) Unknown message type (%u) in switch", bMsgType); - return; - } - - if ((ackType == MTYPE_PLAIN && pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) || ackType != MTYPE_PLAIN) - { - BroadcastAck(hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)(WORD)dwCookie, 0); - } - } - - ReleaseCookie(dwCookie); -} - - -// A response to a CLI_SENDMSG -void CIcqProto::handleRecvServMsgError(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) -{ - WORD wError; - char *pszErrorMessage; - HANDLE hContact; - cookie_message_data *pCookieData = NULL; - int nMessageType; - - - if (wLen < 2) - return; - - if (FindCookie((WORD)dwSequence, &hContact, (void**)&pCookieData)) - { // all packet cookies from msg family has command 0 in the queue - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - { // Invalid contact - FreeCookie((WORD)dwSequence); - return; - } - - // Error code - unpackWord(&buf, &wError); - - if (wError == 9 && pCookieData->bMessageType == MTYPE_AUTOAWAY) - { // we failed to request away message the normal way, try it AIM way - icq_packet packet; - - serverPacketInit(&packet, (WORD)(13 + getUINLen(dwUin))); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, (WORD)dwSequence); - packWord(&packet, 0x03); - packUIN(&packet, dwUin); - - sendServPacket(&packet); - return; - } - - // Not all of these are actually used in family 4 - // This will be moved into a special error handling function later - switch (wError) { - - case 0x0002: // Server rate limit exceeded - pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x02"); - break; - - case 0x0003: // Client rate limit exceeded - pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x03"); - break; - - case 0x0004: // Recipient is not logged in (resend in a offline message) - if (pCookieData->bMessageType == MTYPE_PLAIN) - { - if (pCookieData->isOffline) - { // offline failed - most probably to AIM contact - pszErrorMessage = Translate("The contact does not support receiving offline messages."); - break; - } - // TODO: this needs better solution - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - } - pszErrorMessage = Translate("The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04"); - break; - - case 0x0005: // Requested service unavailable - pszErrorMessage = Translate("The messaging service is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x05"); - break; - - case 0x0009: // Not supported by client (resend in a simpler format) - pszErrorMessage = Translate("The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09"); - break; - - case 0x000A: // Refused by client - pszErrorMessage = Translate("You sent too long message. The receiving client does not support it.\r\nSNAC(4.1) Error x0A"); - break; - - case 0x000E: // Incorrect SNAC format - pszErrorMessage = Translate("The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E"); - break; - - case 0x0013: // User temporarily unavailable - pszErrorMessage = Translate("The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13"); - break; - - case 0x0001: // Invalid SNAC header - case 0x0006: // Requested service not defined - case 0x0007: // You sent obsolete SNAC - case 0x0008: // Not supported by server - case 0x000B: // Reply too big - case 0x000C: // Responses lost - case 0x000D: // Request denied - case 0x000F: // Insufficient rights - case 0x0010: // In local permit/deny (recipient blocked) - case 0x0011: // Sender too evil - case 0x0012: // Receiver too evil - case 0x0014: // No match - case 0x0015: // List overflow - case 0x0016: // Request ambiguous - case 0x0017: // Server queue full - case 0x0018: // Not while on AOL - default: - if (pszErrorMessage = (char*)_alloca(256)) - null_snprintf(pszErrorMessage, 256, Translate("SNAC(4.1) SENDMSG Error (x%02x)"), wError); - break; - } - - - switch (pCookieData->bMessageType) { - - case MTYPE_PLAIN: - nMessageType = ACKTYPE_MESSAGE; - break; - - case MTYPE_CHAT: - nMessageType = ACKTYPE_CHAT; - break; - - case MTYPE_FILEREQ: - nMessageType = ACKTYPE_FILE; - break; - - case MTYPE_URL: - nMessageType = ACKTYPE_URL; - break; - - case MTYPE_CONTACTS: - nMessageType = ACKTYPE_CONTACTS; - break; - - default: - nMessageType = -1; - break; - } - - if (nMessageType != -1) - { - BroadcastAck(hContact, nMessageType, ACKRESULT_FAILED, (HANDLE)(WORD)dwSequence, (LPARAM)pszErrorMessage); - } - else - { - NetLog_Server("Error: Message delivery to %u failed: %s", dwUin, pszErrorMessage); - } - - FreeCookie((WORD)dwSequence); - - if (pCookieData->bMessageType != MTYPE_FILEREQ) - SAFE_FREE((void**)&pCookieData); - } - else - { - unpackWord(&buf, &wError); - - LogFamilyError(ICQ_MSG_FAMILY, wError); - } -} - - -void CIcqProto::handleServerAck(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) -{ - DWORD dwUin; - uid_str szUID; - WORD wChannel; - cookie_message_data *pCookieData; - - - if (wLen < 13) - { - NetLog_Server("Ignoring SNAC(4,C) Packet to short"); - return; - } - - buf += 8; // Skip first 8 bytes - wLen -= 8; - - // Message channel - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (FindCookie((WORD)dwSequence, NULL, (void**)&pCookieData)) - { - // If the user requested a full ack, the - // server ack should be ignored here. - if (pCookieData && (pCookieData->nAckType == ACKTYPE_SERVER)) - { - if ((hContact != NULL) && (hContact != INVALID_HANDLE_VALUE)) - { - int ackType; - int ackRes = ACKRESULT_SUCCESS; - - switch (pCookieData->bMessageType) { - case MTYPE_PLAIN: - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_FILEREQ: - ackType = ACKTYPE_FILE; - ackRes = ACKRESULT_SENTREQUEST; - // Note 1: We are not allowed to free the cookie here because it - // contains the filetransfer struct that we will need later - // Note 2: The cookiedata is NOT a message_cookie_data*, it is a - // filetransfer*. IMPORTANT! (it's one of those silly things) - break; - - default: - ackType = -1; - NetLog_Server("Error: Unknown message type %d in ack", pCookieData->bMessageType); - break; - } - if (ackType != -1) - BroadcastAck(hContact, ackType, ackRes, (HANDLE)(WORD)dwSequence, 0); - - if (pCookieData->bMessageType != MTYPE_FILEREQ) - SAFE_FREE((void**)&pCookieData); // this could be a bad idea, but I think it is safe - } - FreeCookie((WORD)dwSequence); - } - else if (pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) - NetLog_Server("Received a server ack, waiting for client ack."); - else - NetLog_Server("Ignored a server ack I did not ask for"); - } -} - - -void CIcqProto::handleMissedMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - WORD wChannel; - WORD wWarningLevel; - WORD wCount; - WORD wError; - WORD wTLVCount; - - if (wLen < 14) - return; // Too short - - // Message channel? - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - if (wLen < 8) - return; // Too short - - // Warning level? - unpackWord(&buf, &wWarningLevel); - wLen -= 2; - - // TLV count - unpackWord(&buf, &wTLVCount); - wLen -= 2; - - // Read past user info TLVs - oscar_tlv_chain *pChain = readIntoTLVChain(&buf, (WORD)(wLen-4), wTLVCount); - if (pChain) - disposeChain(&pChain); - - if (wLen < 4) - return; // Too short - - // Number of missed messages - unpackWord(&buf, &wCount); - wLen -= 2; - - // Error code - unpackWord(&buf, &wError); - wLen -= 2; - - { // offline retrieval process in progress, note that we received missed message notification - cookie_offline_messages *cookie; - - if (FindCookieByType(CKT_OFFLINEMESSAGE, NULL, NULL, (void**)&cookie)) - cookie->nMissed++; - } - - switch (wError) { - - case 0: // The message was invalid - case 1: // The message was too long - case 2: // The sender has flooded the server - case 4: // You are too evil - break; - - default: - // 3 = Sender too evil (sender warn level > your max_msg_sevil) - return; - break; - } - - // Create event to notify user - int bAdded; - - AddEvent(HContactFromUID(dwUin, szUid, &bAdded), ICQEVENTTYPE_MISSEDMESSAGE, time(NULL), 0, sizeof(wError), (PBYTE)&wError); -} - - -void CIcqProto::handleOffineMessagesReply(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - cookie_offline_messages *cookie; - - if (FindCookie(dwRef, NULL, (void**)&cookie)) - { - NetLog_Server("End of offline msgs, %u received", cookie->nMessages); - if (cookie->nMissed) - { // NASTY WORKAROUND!! - // The ICQ server has a bug that causes offline messages to be received again and again when some - // missed message notification is present (most probably it is not processed correctly and causes - // the server to fail the purging process); try to purge them using the old offline messages - // protocol. 2008/05/21 - NetLog_Server("Warning: Received %u missed message notifications, trying to fix the server.", cookie->nMissed); - - icq_packet packet; - // This will delete the messages stored on server - serverPacketInit(&packet, 24); - packFNACHeader(&packet, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); - packWord(&packet, 1); // TLV Type - packWord(&packet, 10); // TLV Length - packLEWord(&packet, 8); // Data length - packLEDWord(&packet, m_dwLocalUIN); // My UIN - packLEWord(&packet, CLI_DELETE_OFFLINE_MSGS_REQ); // Ack offline msgs - packLEWord(&packet, 0x0000); // Request sequence number (we dont use this for now) - - // Send it - sendServPacket(&packet); - } - - ReleaseCookie(dwRef); - } - else - NetLog_Server("Error: Received unexpected end of offline msgs."); -} - - -void CIcqProto::handleTypingNotification(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - WORD wChannel; - WORD wNotification; - - if (wLen < 14) - { - NetLog_Server("Ignoring SNAC(4.x11) Packet to short"); - return; - } - -#ifndef DBG_CAPMTN - { - NetLog_Server("Ignoring unexpected typing notification"); - return; - } -#endif - - // The message ID, unused? - buf += 8; - wLen -= 8; - - // Message channel, unused? - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); - - if (hContact == INVALID_HANDLE_VALUE) return; - - // Typing notification code - unpackWord(&buf, &wNotification); - wLen -= 2; - - SetContactCapabilities(hContact, CAPF_TYPING); - - // Notify user - switch (wNotification) { - - case MTN_FINISHED: - case MTN_TYPED: - CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); - NetLog_Server("%s has stopped typing (ch %u).", strUID(dwUin, szUid), wChannel); - break; - - case MTN_BEGUN: - CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60); - NetLog_Server("%s is typing a message (ch %u).", strUID(dwUin, szUid), wChannel); - break; - - case MTN_WINDOW_CLOSED: - { - char szFormat[MAX_PATH]; - char szMsg[MAX_PATH]; - char *nick = NickFromHandleUtf(hContact); - - null_snprintf(szMsg, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" has closed the message window."), szFormat, MAX_PATH), nick); - ShowPopUpMsg(hContact, ICQTranslateUtfStatic(LPGEN("ICQ Note"), szFormat, MAX_PATH), szMsg, LOG_NOTE); - SAFE_FREE((void**)&nick); - - NetLog_Server("%s has closed the message window.", strUID(dwUin, szUid)); - } - break; - - default: - NetLog_Server("Unknown typing notification from %s, type %u (ch %u)", strUID(dwUin, szUid), wNotification, wChannel); - break; - } -} - - -void CIcqProto::sendTypingNotification(HANDLE hContact, WORD wMTNCode) -{ - _ASSERTE((wMTNCode == MTN_FINISHED) || (wMTNCode == MTN_TYPED) || (wMTNCode == MTN_BEGUN) || (wMTNCode == MTN_WINDOW_CLOSED)); - - DWORD dwUin; - uid_str szUid; - if (getContactUid(hContact, &dwUin, &szUid)) - return; // Invalid contact - - WORD wLen = getUIDLen(dwUin, szUid); - - icq_packet packet; - serverPacketInit(&packet, 23 + wLen); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_MTN); - packLEDWord(&packet, 0x0000); // Msg ID - packLEDWord(&packet, 0x0000); // Msg ID - packWord(&packet, 0x01); // Channel - packUID(&packet, dwUin, szUid); // User ID - packWord(&packet, wMTNCode); // Notification type - - sendServPacketAsync(&packet); -} diff --git a/protocols/IcqOscarJ/fam_09bos.cpp b/protocols/IcqOscarJ/fam_09bos.cpp deleted file mode 100644 index 327e045a96..0000000000 --- a/protocols/IcqOscarJ/fam_09bos.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleBosFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_PRIVACY_RIGHTS_REPLY: // Reply to CLI_REQBOS - handlePrivacyRightsReply(pBuffer, wBufferLength); - break; - - case ICQ_ERROR: - { - WORD wError; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - LogFamilyError(ICQ_BOS_FAMILY, wError); - break; - } - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_BOS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - } -} - -void CIcqProto::handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength) -{ - if (wBufferLength >= 12) - { - oscar_tlv_chain* pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0); - if (pChain) - { - WORD wMaxVisibleContacts; - WORD wMaxInvisibleContacts; - WORD wMaxTemporaryVisibleContacts; - - wMaxVisibleContacts = pChain->getWord(0x0001, 1); - wMaxInvisibleContacts = pChain->getWord(0x0002, 1); - wMaxTemporaryVisibleContacts = pChain->getWord(0x0003, 1); - - disposeChain(&pChain); - - NetLog_Server("PRIVACY: Max visible %u, max invisible %u, max temporary visible %u items.", wMaxVisibleContacts, wMaxInvisibleContacts, wMaxTemporaryVisibleContacts); - - // Success - return; - } - } - - // Failure - NetLog_Server("Warning: Malformed SRV_PRIVACY_RIGHTS_REPLY"); -} - -void CIcqProto::makeContactTemporaryVisible(HANDLE hContact) -{ - DWORD dwUin; - uid_str szUid; - - if (getSettingByte(hContact, "TemporaryVisible", 0)) - return; // already there - - if (getContactUid(hContact, &dwUin, &szUid)) - return; // Invalid contact - - icq_sendGenericContact(dwUin, szUid, ICQ_BOS_FAMILY, ICQ_CLI_ADDTEMPVISIBLE); - - setSettingByte(hContact, "TemporaryVisible", 1); - -#ifdef _DEBUG - NetLog_Server("Added contact %s to temporary visible list", strUID(dwUin, szUid)); -#endif -} diff --git a/protocols/IcqOscarJ/fam_0alookup.cpp b/protocols/IcqOscarJ/fam_0alookup.cpp deleted file mode 100644 index da77295ecb..0000000000 --- a/protocols/IcqOscarJ/fam_0alookup.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleLookupFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_LOOKUP_EMAIL_REPLY: // AIM search reply - handleLookupEmailReply(pBuffer, wBufferLength, pSnacHeader->dwRef); - break; - - case ICQ_ERROR: - { - WORD wError; - cookie_search *pCookie; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookie)) - { - if (wError == 0x14) - NetLog_Server("Lookup: No results"); - - ReleaseLookupCookie(pSnacHeader->dwRef, pCookie); - - if (wError == 0x14) return; - } - - LogFamilyError(ICQ_LOOKUP_FAMILY, wError); - break; - } - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LOOKUP_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - -void CIcqProto::ReleaseLookupCookie(DWORD dwCookie, cookie_search *pCookie) -{ - FreeCookie(dwCookie); - SAFE_FREE(&pCookie->szObject); - - if (pCookie->dwMainId && !pCookie->dwStatus) - { // we need to wait for main search - pCookie->dwStatus = 1; - } - else - { // finish everything - if (pCookie->dwMainId) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)pCookie->dwMainId, 0); - else // we are single - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); - - SAFE_FREE((void**)&pCookie); - } -} - -void CIcqProto::handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie) -{ - ICQSEARCHRESULT sr = {0}; - oscar_tlv_chain *pChain; - cookie_search *pCookie; - - if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) - { - NetLog_Server("Error: Received unexpected lookup reply"); - return; - } - - NetLog_Server("SNAC(0x0A,0x3): Lookup reply"); - - sr.hdr.cbSize = sizeof(sr); - sr.hdr.flags = PSR_TCHAR; - sr.hdr.email = ansi_to_tchar(pCookie->szObject); - - // Syntax check, read chain - if (wLen >= 4 && (pChain = readIntoTLVChain(&buf, wLen, 0))) - { - for (WORD i = 1; TRUE; i++) - { // collect the results - char *szUid = pChain->getString(0x01, i); - if (!szUid) break; - sr.hdr.id = ansi_to_tchar(szUid); - sr.hdr.nick = sr.hdr.id; - // broadcast the result - if (pCookie->dwMainId) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)pCookie->dwMainId, (LPARAM)&sr); - else - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)dwCookie, (LPARAM)&sr); - SAFE_FREE(&sr.hdr.id); - SAFE_FREE(&szUid); - } - disposeChain(&pChain); - } - SAFE_FREE(&sr.hdr.email); - - ReleaseLookupCookie(dwCookie, pCookie); -} diff --git a/protocols/IcqOscarJ/fam_0bstatus.cpp b/protocols/IcqOscarJ/fam_0bstatus.cpp deleted file mode 100644 index 7a979007e2..0000000000 --- a/protocols/IcqOscarJ/fam_0bstatus.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004,2005,2006 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleStatusFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_STATS_MINREPORTINTERVAL: - { - WORD wInterval; - unpackWord(&pBuffer, &wInterval); - NetLog_Server("Server sent SNAC(x0B,x02) - SRV_SET_MINREPORTINTERVAL (Value: %u hours)", wInterval); - } - break; - - case ICQ_ERROR: - { - WORD wError; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - LogFamilyError(ICQ_STATS_FAMILY, wError); - break; - } - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_STATS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} diff --git a/protocols/IcqOscarJ/fam_13servclist.cpp b/protocols/IcqOscarJ/fam_13servclist.cpp deleted file mode 100644 index 5df30ee5ec..0000000000 --- a/protocols/IcqOscarJ/fam_13servclist.cpp +++ /dev/null @@ -1,2068 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static int unpackServerListItem(BYTE **pbuf, WORD *pwLen, char *pszRecordName, WORD *pwGroupId, WORD *pwItemId, WORD *pwItemType, WORD *pwTlvLength); - - -void CIcqProto::handleServCListFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_LISTS_ACK: // UPDATE_ACK - if (wBufferLength >= 2) - { - WORD wError; - cookie_servlist_action* sc; - - unpackWord(&pBuffer, &wError); - - if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) - { // look for action cookie -#ifdef _DEBUG - NetLog_Server("Received expected server list ack, action: %d, result: %d", sc->dwAction, wError); -#endif - FreeCookie(pSnacHeader->dwRef); // release cookie - - if (sc->dwAction == SSA_ACTION_GROUP) - { // group cookie, handle sub-items - int i; - -#ifdef _DEBUG - NetLog_Server("Server-List: Grouped action contains %d actions.", sc->dwGroupCount); -#endif - pBuffer -= 2; // revoke unpack - if (wBufferLength != 2*sc->dwGroupCount) - NetLog_Server("Error: Server list ack does not contain expected amount of result codes (%u != %u)", wBufferLength/2, sc->dwGroupCount); - - for (i = 0; i < sc->dwGroupCount; i++) - { - if (wBufferLength >= 2) - { // get proper result code - unpackWord(&pBuffer, &wError); - wBufferLength -= 2; - } - else // missing result code, give some special - wError = -1; - -#ifdef _DEBUG - NetLog_Server("Action: %d, ack result: %d", sc->pGroupItems[i]->dwAction, wError); -#endif - // call normal ack handler - handleServerCListAck(sc->pGroupItems[i], wError); - } - // Release cookie - SAFE_FREE((void**)&sc->pGroupItems); - SAFE_FREE((void**)&sc); - } - else // single ack - handleServerCListAck(sc, wError); - } - else - { - NetLog_Server("Received unexpected server list ack %u", wError); - } - } - break; - - case ICQ_LISTS_SRV_REPLYLISTS: - { /* received server-list rights */ - handleServerCListRightsReply(pBuffer, wBufferLength); - -#ifdef _DEBUG - NetLog_Server("Server sent SNAC(x13,x03) - SRV_REPLYLISTS"); -#endif - } - break; - - case ICQ_LISTS_LIST: // SRV_REPLYROSTER - { - cookie_servlist_action* sc; - BOOL blWork; - - blWork = bIsSyncingCL; - bIsSyncingCL = TRUE; // this is not used if cookie takes place - - if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) - { // we do it by reliable cookie - if (!sc->lParam) - { // is this first packet ? - ResetSettingsOnListReload(); - sc->lParam = 1; - } - handleServerCListReply(pBuffer, wBufferLength, pSnacHeader->wFlags, info); - if (!(pSnacHeader->wFlags & 0x0001)) - { // was that last packet ? - ReleaseCookie(pSnacHeader->dwRef); // yes, release cookie - } - } - else - { // use old fake - if (!blWork) - { // this can fail on some crazy situations - ResetSettingsOnListReload(); - } - handleServerCListReply(pBuffer, wBufferLength, pSnacHeader->wFlags, info); - } - break; - } - - case ICQ_LISTS_UPTODATE: // SRV_REPLYROSTEROK - { - cookie_servlist_action* sc; - - bIsSyncingCL = FALSE; - - if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) - { // we requested servlist check -#ifdef _DEBUG - NetLog_Server("Server stated roster is ok."); -#endif - ReleaseCookie(pSnacHeader->dwRef); - LoadServerIDs(); - } - else - NetLog_Server("Server sent unexpected SNAC(x13,x0F) - SRV_REPLYROSTEROK"); - - // This will activate the server side list - sendRosterAck(); // this must be here, cause of failures during cookie alloc - handleServUINSettings(wListenPort, info); - break; - } - - case ICQ_LISTS_CLI_MODIFYSTART: - NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_CLI_MODIFYSTART, "Server is modifying contact list"); - break; - - case ICQ_LISTS_CLI_MODIFYEND: - NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_CLI_MODIFYEND, "End of server modification"); - break; - - case ICQ_LISTS_ADDTOLIST: - case ICQ_LISTS_UPDATEGROUP: - case ICQ_LISTS_REMOVEFROMLIST: - { - int nItems = 0; - - while (wBufferLength >= 10) - { - WORD wGroupId, wItemId, wItemType, wTlvLen; - uid_str szRecordName; - - if (unpackServerListItem(&pBuffer, &wBufferLength, szRecordName, &wGroupId, &wItemId, &wItemType, &wTlvLen)) - { - BYTE *buf = pBuffer; - oscar_tlv_chain *pChain = NULL; - - nItems++; - - // parse possible item's data - if (wBufferLength >= wTlvLen && wTlvLen > 0) - { - pChain = readIntoTLVChain(&buf, wTlvLen, 0); - pBuffer += wTlvLen; - wBufferLength -= wTlvLen; - } - else if (wTlvLen > 0) - wBufferLength = 0; - - // process item change - if (pSnacHeader->wSubtype == ICQ_LISTS_ADDTOLIST) - handleServerCListItemAdd(szRecordName, wGroupId, wItemId, wItemType, pChain); - else if (pSnacHeader->wSubtype == ICQ_LISTS_UPDATEGROUP) - handleServerCListItemUpdate(szRecordName, wGroupId, wItemId, wItemType, pChain); - else if (pSnacHeader->wSubtype == ICQ_LISTS_REMOVEFROMLIST) - handleServerCListItemDelete(szRecordName, wGroupId, wItemId, wItemType, pChain); - - // release memory - disposeChain(&pChain); - } - } - { // log packet basics - char *szChange; - char szLogText[MAX_PATH]; - - if (pSnacHeader->wSubtype == ICQ_LISTS_ADDTOLIST) - szChange = "Server added %u item(s) to list"; - else if (pSnacHeader->wSubtype == ICQ_LISTS_UPDATEGROUP) - szChange = "Server updated %u item(s) on list"; - else if (pSnacHeader->wSubtype == ICQ_LISTS_REMOVEFROMLIST) - szChange = "Server removed %u item(s) from list"; - - null_snprintf(szLogText, MAX_PATH, szChange, nItems); - NetLog_Server("Server sent SNAC(x13,x%02x) - %s", pSnacHeader->wSubtype, szLogText); - } - } - break; - - case ICQ_LISTS_AUTHREQUEST: - handleRecvAuthRequest(pBuffer, wBufferLength); - break; - - case ICQ_LISTS_SRV_AUTHRESPONSE: - handleRecvAuthResponse(pBuffer, wBufferLength); - break; - - case ICQ_LISTS_AUTHGRANTED: - NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_AUTHGRANTED, "User granted us future authorization"); - break; - - case ICQ_LISTS_YOUWEREADDED: - handleRecvAdded(pBuffer, wBufferLength); - break; - - case ICQ_LISTS_ERROR: - if (wBufferLength >= 2) - { - WORD wError; - cookie_servlist_action* sc; - - unpackWord(&pBuffer, &wError); - - if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) - { // look for action cookie -#ifdef _DEBUG - NetLog_Server("Received server list error, action: %d, result: %d", sc->dwAction, wError); -#endif - FreeCookie(pSnacHeader->dwRef); // release cookie - - if (sc->dwAction==SSA_CHECK_ROSTER) - { // the serv-list is unavailable turn it off - icq_LogMessage(LOG_ERROR, LPGEN("Server contact list is unavailable, Miranda will use local contact list.")); - m_bSsiEnabled = 0; - handleServUINSettings(wListenPort, info); - } - /// FIXME: properly release pending operations & cookie memory - SAFE_FREE((void**)&sc); - } - else - { - LogFamilyError(ICQ_LISTS_FAMILY, wError); - } - } - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LISTS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -static int unpackServerListItem(BYTE **pbuf, WORD *pwLen, char *pszRecordName, WORD *pwGroupId, WORD *pwItemId, WORD *pwItemType, WORD *pwTlvLength) -{ - WORD wRecordNameLen; - - // The name of the entry. If this is a group header, then this - // is the name of the group. If it is a plain contact list entry, - // then it's the UIN of the contact. - unpackWord(pbuf, &wRecordNameLen); - if (*pwLen < 10 + wRecordNameLen || wRecordNameLen >= MAX_PATH) - return 0; // Failure - - unpackString(pbuf, pszRecordName, wRecordNameLen); - if (pszRecordName) - pszRecordName[wRecordNameLen] = '\0'; - - // The group identifier this entry belongs to. If 0, this is meta information or - // a contact without a group - unpackWord(pbuf, pwGroupId); - - // The ID of this entry. Group headers have ID 0. Otherwise, this - // is a random number generated when the user is added to the - // contact list, or when the user is ignored. See CLI_ADDBUDDY. - unpackWord(pbuf, pwItemId); - - // This field indicates what type of entry this is - unpackWord(pbuf, pwItemType); - - // The length in bytes of the following TLV chain - unpackWord(pbuf, pwTlvLength); - - *pwLen -= wRecordNameLen + 10; - - return 1; // Success -} - - -void CIcqProto::handleServerCListRightsReply(BYTE *buf, WORD wLen) -{ /* received list rights, store the item limits for future use */ - oscar_tlv_chain* chain; - - memset(m_wServerListLimits, -1, sizeof(m_wServerListLimits)); - m_wServerListGroupMaxContacts = 0; - m_wServerListRecordNameMaxLength = 0xFFFF; - - if (chain = readIntoTLVChain(&buf, wLen, 0)) - { - oscar_tlv* pTLV; - - // determine max number of contacts in a group - m_wServerListGroupMaxContacts = chain->getWord(0x0C, 1); - // determine length limit for server-list item's name - m_wServerListRecordNameMaxLength = chain->getWord(0x06, 1); - - if (pTLV = chain->getTLV(0x04, 1)) - { // limits for item types - int i; - WORD *pLimits = (WORD*)pTLV->pData; - - for (i = 0; i < pTLV->wLen / 2; i++) - { - m_wServerListLimits[i] = (pLimits[i] & 0xFF) << 8 | (pLimits[i] >> 8); - - if (i + 1 >= SIZEOF(m_wServerListLimits)) break; - } - - NetLog_Server("SSI: Max %d contacts (%d per group), %d groups, %d permit, %d deny, %d ignore items.", m_wServerListLimits[SSI_ITEM_BUDDY], m_wServerListGroupMaxContacts, m_wServerListLimits[SSI_ITEM_GROUP], m_wServerListLimits[SSI_ITEM_PERMIT], m_wServerListLimits[SSI_ITEM_DENY], m_wServerListLimits[SSI_ITEM_IGNORE]); - } - - disposeChain(&chain); - } -} - - -DWORD CIcqProto::updateServerGroupData(WORD wGroupId, void *groupData, int groupSize, DWORD dwOperationFlags) -{ - DWORD dwCookie; - cookie_servlist_action* ack; - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (!ack) - { - NetLog_Server("Updating of group on server list failed (malloc error)"); - return 0; - } - ack->dwAction = SSA_GROUP_UPDATE; - ack->szGroupName = getServListGroupName(wGroupId); - ack->wGroupId = wGroupId; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - - return icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, ack->wGroupId, ack->szGroupName, groupData, groupSize, dwOperationFlags); -} - - -void CIcqProto::handleServerCListAck(cookie_servlist_action* sc, WORD wError) -{ - switch (sc->dwAction) - { - case SSA_VISIBILITY: - { - if (wError) - NetLog_Server("Server visibility update failed, error %d", wError); - break; - } - case SSA_CONTACT_UPDATE: - { - servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, wError ? PENDING_RESULT_FAILED : PENDING_RESULT_SUCCESS); - if (wError) - { - NetLog_Server("Updating of server contact failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Updating of server contact failed.")); - } - break; - } - case SSA_PRIVACY_ADD: - { - if (wError) - { - NetLog_Server("Adding of privacy item to server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Adding of privacy item to server list failed.")); - } - break; - } - case SSA_PRIVACY_REMOVE: - { - if (wError) - { - NetLog_Server("Removing of privacy item from server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Removing of privacy item from server list failed.")); - } - FreeServerID(sc->wContactId, SSIT_ITEM); // release server id - break; - } - case SSA_CONTACT_ADD: - { - if (wError) - { - if (wError == 0xE) // server refused to add contact w/o auth, add with - { - DWORD dwCookie; - - NetLog_Server("Contact could not be added without authorization, add with await auth flag."); - - setSettingByte(sc->hContact, "Auth", 1); // we need auth - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, sc->hContact, sc); - icq_sendServerContact(sc->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, sc->wGroupId, sc->wContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 500, NULL); - - sc = NULL; // we do not want it to be freed now - break; - } - FreeServerID(sc->wContactId, SSIT_ITEM); - - NetLog_Server("Adding of contact to server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Adding of contact to server list failed.")); - - servlistPendingRemoveContact(sc->hContact, 0, sc->wGroupId, PENDING_RESULT_FAILED); - - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here - } - else - { - void* groupData; - int groupSize; - - setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, sc->wContactId); - setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, sc->wGroupId); - - servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, PENDING_RESULT_SUCCESS); - - if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) - { // the group is not empty, just update it - updateServerGroupData(sc->wGroupId, groupData, groupSize, SSOF_END_OPERATION); - SAFE_FREE((void**)&groupData); - } - else - { // this should never happen - NetLog_Server("Group update failed."); - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here - } - } - break; - } - case SSA_GROUP_ADD: - { - if (wError) - { - FreeServerID(sc->wGroupId, SSIT_GROUP); - NetLog_Server("Adding of group to server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Adding of group to server list failed.")); - - servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_FAILED); - } - else // group added, we need to update master group - { - void* groupData; - int groupSize; - cookie_servlist_action* ack; - DWORD dwCookie; - - setServListGroupName(sc->wGroupId, sc->szGroupName); // add group to namelist - { // add group to known - char *szCListGroup = getServListGroupCListPath(sc->wGroupId); - - // create link to the original CList group - setServListGroupLinkID(sc->szGroup, sc->wGroupId); - - servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_SUCCESS); - SAFE_FREE((void**)&szCListGroup); - } - - groupData = collectGroups(&groupSize); - groupData = SAFE_REALLOC(groupData, groupSize+2); - *(((WORD*)groupData)+(groupSize>>1)) = sc->wGroupId; // add this new group id - groupSize += 2; - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { - ack->dwAction = SSA_GROUP_UPDATE; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, SSOF_END_OPERATION); - } - else // end server modifications here - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); - - SAFE_FREE((void**)&groupData); - } - if (sc->szGroup != sc->szGroupName) - SAFE_FREE((void**)&sc->szGroup); - - SAFE_FREE((void**)&sc->szGroupName); - break; - } - case SSA_CONTACT_REMOVE: - { - if (!wError) - { - void* groupData; - int groupSize; - - setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, 0); // clear the values - setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, 0); - - FreeServerID(sc->wContactId, SSIT_ITEM); - - servlistPendingRemoveContact(sc->hContact, 0, sc->wGroupId, PENDING_RESULT_SUCCESS); - - if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) - { // the group is still not empty, just update it - updateServerGroupData(sc->wGroupId, groupData, groupSize, SSOF_END_OPERATION); - } - else // the group is empty, delete it - { - char *szGroup = getServListGroupCListPath(sc->wGroupId); - - servlistRemoveGroup(szGroup, sc->wGroupId); - SAFE_FREE((void**)&szGroup); - } - SAFE_FREE((void**)&groupData); // free the memory - } - else - { - NetLog_Server("Removing of contact from server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Removing of contact from server list failed.")); - - servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, PENDING_RESULT_FAILED); - - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here - } - break; - } - case SSA_GROUP_UPDATE: - { - if (wError) - { - NetLog_Server("Updating of group on server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Updating of group on server list failed.")); - } - SAFE_FREE((void**)&sc->szGroupName); - break; - } - case SSA_GROUP_REMOVE: - { - SAFE_FREE((void**)&sc->szGroupName); - if (wError) - { - NetLog_Server("Removing of group from server list failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Removing of group from server list failed.")); - - servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_FAILED); - - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here - SAFE_FREE((void**)&sc->szGroup); - } - else // group removed, we need to update master group - { - void* groupData; - int groupSize; - DWORD dwCookie; - - setServListGroupName(sc->wGroupId, NULL); // clear group from namelist - FreeServerID(sc->wGroupId, SSIT_GROUP); - removeGroupPathLinks(sc->wGroupId); - - servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_SUCCESS); - SAFE_FREE((void**)&sc->szGroup); - - groupData = collectGroups(&groupSize); - sc->wGroupId = 0; - sc->dwAction = SSA_GROUP_UPDATE; - sc->szGroupName = NULL; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, sc); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, sc->szGroupName, groupData, groupSize, SSOF_END_OPERATION); - // end server modifications here - - sc = NULL; // we do not want to be freed here - - SAFE_FREE((void**)&groupData); - } - break; - } - case SSA_CONTACT_SET_GROUP: - { // we moved contact to another group - if (sc->lParam == -1) - { // the first was an error - break; - } - if (wError) - { - if (wError == 0x0E && sc->lParam == 1) - { // second ack - adding failed with error 0x0E, try to add with AVAIT_AUTH flag - DWORD dwCookie; - - if (!getSettingByte(sc->hContact, "Auth", 0)) - { // we tried without AWAIT_AUTH, try again with it - NetLog_Server("Contact could not be added without authorization, add with await auth flag."); - - setSettingByte(sc->hContact, "Auth", 1); // we need auth - } - else - { // we tried with AWAIT_AUTH, try again without - NetLog_Server("Contact count not be added awaiting authorization, try authorized."); - - setSettingByte(sc->hContact, "Auth", 0); - } - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, sc->hContact, sc); - icq_sendServerContact(sc->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, sc->wNewGroupId, sc->wNewContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 400, NULL); - - sc->lParam = 2; // do not cycle - sc = NULL; // we do not want to be freed here - break; - } - FreeServerID(sc->wNewContactId, SSIT_ITEM); - NetLog_Server("Moving of user to another group on server list failed, error %d", wError); - icq_LogMessage(LOG_ERROR, LPGEN("Moving of user to another group on server list failed.")); - - servlistPendingRemoveContact(sc->hContact, 0, (WORD)(sc->lParam ? sc->wGroupId : sc->wNewGroupId), PENDING_RESULT_FAILED); - - servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here - - if (!sc->lParam) // is this first ack ? - { - sc->lParam = -1; - sc = NULL; // this can't be freed here - } - break; - } - if (sc->lParam) // is this the second ack ? - { - void* groupData; - int groupSize; - int bEnd = 1; // shall we end the sever modifications - - setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, sc->wNewContactId); - setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, sc->wNewGroupId); - - servlistPendingRemoveContact(sc->hContact, sc->wNewContactId, sc->wNewGroupId, PENDING_RESULT_SUCCESS); - - if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) // update the group we moved from - { // the group is still not empty, just update it - updateServerGroupData(sc->wGroupId, groupData, groupSize, 0); - SAFE_FREE((void**)&groupData); // free the memory - } - else - { // the group is empty, delete it - char* szGroup = getServListGroupCListPath(sc->wGroupId); - - servlistRemoveGroup(szGroup, sc->wGroupId); - SAFE_FREE((void**)&szGroup); - bEnd = 0; // here the modifications go on - } - - groupData = collectBuddyGroup(sc->wNewGroupId, &groupSize); // update the group we moved to - updateServerGroupData(sc->wNewGroupId, groupData, groupSize, bEnd ? SSOF_END_OPERATION : 0); - // end server modifications here - SAFE_FREE((void**)&groupData); - - } - else // contact was deleted from server-list - { - deleteSetting(sc->hContact, DBSETTING_SERVLIST_ID); - deleteSetting(sc->hContact, DBSETTING_SERVLIST_GROUP); - FreeServerID(sc->wContactId, SSIT_ITEM); // release old contact id - sc->lParam = 1; - sc = NULL; // wait for second ack - } - break; - } - case SSA_CONTACT_FIX_AUTH: - { - if (wError) - { // FIXME: something failed, we should handle it properly - } - break; - } - case SSA_GROUP_RENAME: - { - if (wError) - { - NetLog_Server("Renaming of server group failed, error %d", wError); - icq_LogMessage(LOG_WARNING, LPGEN("Renaming of server group failed.")); - - servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_FAILED); - } - else - { - setServListGroupName(sc->wGroupId, sc->szGroupName); - removeGroupPathLinks(sc->wGroupId); - { // add group to known - char *szCListGroup = getServListGroupCListPath(sc->wGroupId); - - /// FIXME: need to create link to the new group name before unique item name correction as well - setServListGroupLinkID(szCListGroup, sc->wGroupId); - SAFE_FREE((void**)&szCListGroup); - } - servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_SUCCESS); - } - SAFE_FREE((void**)&sc->szGroupName); - SAFE_FREE((void**)&sc->szGroup); - break; - } - case SSA_SETAVATAR: - { - if (wError) - { - NetLog_Server("Uploading of avatar hash failed."); - if (sc->wGroupId) // is avatar added or updated? - { - FreeServerID(sc->wContactId, SSIT_ITEM); - deleteSetting(NULL, DBSETTING_SERVLIST_AVATAR); // to fix old versions - } - } - else - { - setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, sc->wContactId); - } - break; - } - case SSA_REMOVEAVATAR: - { - if (wError) - NetLog_Server("Removing of avatar hash failed."); - else - { - FreeServerID(sc->wContactId, SSIT_ITEM); - deleteSetting(NULL, DBSETTING_SERVLIST_AVATAR); - } - break; - } - case SSA_SERVLIST_ACK: - { - BroadcastAck(sc->hContact, ICQACKTYPE_SERVERCLIST, wError?ACKRESULT_FAILED:ACKRESULT_SUCCESS, (HANDLE)sc->lParam, wError); - break; - } - case SSA_IMPORT: - { - if (wError) - NetLog_Server("Re-starting import sequence failed, error %d", wError); - else - { - setSettingWord(NULL, "SrvImportID", 0); - deleteSetting(NULL, "ImportTS"); - } - break; - } - default: - NetLog_Server("Server ack cookie type (%d) not recognized.", sc->dwAction); - } - SAFE_FREE((void**)&sc); // free the memory - - return; -} - - -HANDLE CIcqProto::HContactFromRecordName(const char* szRecordName, int *bAdded) -{ - HANDLE hContact = INVALID_HANDLE_VALUE; - - if (!IsStringUIN(szRecordName)) - { // probably AIM contact - hContact = HContactFromUID(0, szRecordName, bAdded); - } - else - { // this should be ICQ number - DWORD dwUin = atoi(szRecordName); - - hContact = HContactFromUIN(dwUin, bAdded); - } - return hContact; -} - - -int CIcqProto::getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf) /// FIXME: need to keep original order -{ // get server-list item's TLV data - oscar_tlv_chain* list = pChain; - int datalen = 0; - icq_packet pBuf; - - // Initialize our handy data buffer - pBuf.wPlace = 0; - pBuf.pData = buf; - - while (list) - { // collect non-standard TLVs and save them to DB - if (list->tlv.wType != SSI_TLV_AWAITING_AUTH && - list->tlv.wType != SSI_TLV_NAME && - list->tlv.wType != SSI_TLV_COMMENT && - list->tlv.wType != SSI_TLV_METAINFO_TOKEN && - list->tlv.wType != SSI_TLV_METAINFO_TIME) - { // only TLVs which we do not handle on our own - packTLV(&pBuf, list->tlv.wType, list->tlv.wLen, list->tlv.pData); - - datalen += list->tlv.wLen + 4; - } - list = list->next; - } - return datalen; -} - - -void CIcqProto::handleServerCListReply(BYTE *buf, WORD wLen, WORD wFlags, serverthread_info *info) -{ - BYTE bySSIVersion; - WORD wRecordCount; - WORD wRecord; - WORD wGroupId; - WORD wItemId; - WORD wTlvType; - WORD wTlvLength; - BOOL bIsLastPacket; - uid_str szRecordName; - oscar_tlv_chain* pChain = NULL; - oscar_tlv* pTLV = NULL; - char *szActiveSrvGroup = NULL; - WORD wActiveSrvGroupId = -1; - - - // If flag bit 1 is set, this is not the last - // packet. If it is 0, this is the last packet - // and there will be a timestamp at the end. - if (wFlags & 0x0001) - bIsLastPacket = FALSE; - else - bIsLastPacket = TRUE; - - if (wLen < 3) - return; - - // Version number of SSI protocol? - unpackByte(&buf, &bySSIVersion); - wLen -= 1; - - // Total count of following entries. This is the size of the server - // side contact list and should be saved and sent with CLI_CHECKROSTER. - // NOTE: When the entries are split up in several packets, each packet - // has it's own count and they must be added to get the total size of - // server list. - unpackWord(&buf, &wRecordCount); - wLen -= 2; - NetLog_Server("SSI: number of entries is %u, version is %u", wRecordCount, bySSIVersion); - - - // Loop over all items in the packet - for (wRecord = 0; wRecord < wRecordCount; wRecord++) - { - NetLog_Server("SSI: parsing record %u", wRecord + 1); - - if (wLen < 10) - { // minimum: name length (zero), group ID, item ID, empty TLV - NetLog_Server("Warning: SSI parsing error (%d)", 0); - break; - } - - if (!unpackServerListItem(&buf, &wLen, szRecordName, &wGroupId, &wItemId, &wTlvType, &wTlvLength)) - { // unpack basic structure - NetLog_Server("Warning: SSI parsing error (%d)", 1); - break; - } - - NetLog_Server("Name: '%s', GroupID: %u, EntryID: %u, EntryType: %u, TLVlength: %u", - szRecordName, wGroupId, wItemId, wTlvType, wTlvLength); - - if (wLen < wTlvLength) - { - NetLog_Server("Warning: SSI parsing error (%d)", 2); - break; - } - - // Initialize the tlv chain - if (wTlvLength > 0) - { - pChain = readIntoTLVChain(&buf, wTlvLength, 0); - wLen -= wTlvLength; - } - else - { - pChain = NULL; - } - - - switch (wTlvType) - { - - case SSI_ITEM_BUDDY: - { - /* this is a contact */ - HANDLE hContact; - int bAdded; - - hContact = HContactFromRecordName(szRecordName, &bAdded); - - if (hContact != INVALID_HANDLE_VALUE) - { - int bRegroup = 0; - int bNicked = 0; - - if (bAdded) - { // Not already on list: added - NetLog_Server("SSI added new %s contact '%s'", "ICQ", szRecordName); - - AddJustAddedContact(hContact); - } - else - { // we should add new contacts and this contact was just added, show it - if (IsContactJustAdded(hContact)) - { - setContactHidden(hContact, 0); - bAdded = 1; // we want details for new contacts - } - else - NetLog_Server("SSI ignoring existing contact '%s'", szRecordName); - // Contact on server is always on list - DBWriteContactSettingByte(hContact, "CList", "NotOnList", 0); - } - - // Save group and item ID - setSettingWord(hContact, DBSETTING_SERVLIST_ID, wItemId); - setSettingWord(hContact, DBSETTING_SERVLIST_GROUP, wGroupId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - if (!bAdded && getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD)) - { // check if the contact has been moved on the server - if (wActiveSrvGroupId != wGroupId || !szActiveSrvGroup) - { - SAFE_FREE(&szActiveSrvGroup); - szActiveSrvGroup = getServListGroupCListPath(wGroupId); - wActiveSrvGroupId = wGroupId; - } - char *szLocalGroup = getContactCListGroup(hContact); - - if (!strlennull(szLocalGroup)) - { // no CListGroup - SAFE_FREE(&szLocalGroup); - - szLocalGroup = null_strdup(DEFAULT_SS_GROUP); - } - - if (strcmpnull(szActiveSrvGroup, szLocalGroup) && - (strlennull(szActiveSrvGroup) >= strlennull(szLocalGroup) || _strnicmp(szActiveSrvGroup, szLocalGroup, strlennull(szLocalGroup)))) - { // contact moved to new group or sub-group or not to master group - bRegroup = 1; - } - if (bRegroup && !stricmpnull(DEFAULT_SS_GROUP, szActiveSrvGroup)) /// TODO: invent something more clever for "root" group - { // is it the default "General" group ? - bRegroup = 0; // if yes, do not move to it - cause it would hide the contact - } - SAFE_FREE(&szLocalGroup); - } - - if (bRegroup || bAdded) - { // if we should load server details or contact was just added, update its group - if (wActiveSrvGroupId != wGroupId || !szActiveSrvGroup) - { - SAFE_FREE(&szActiveSrvGroup); - szActiveSrvGroup = getServListGroupCListPath(wGroupId); - wActiveSrvGroupId = wGroupId; - } - - if (szActiveSrvGroup) - { // try to get Miranda Group path from groupid, if succeeded save to db - moveContactToCListGroup(hContact, szActiveSrvGroup); - } - } - - if (pChain) - { // Look for nickname TLV and copy it to the db if necessary - if (pTLV = pChain->getTLV(SSI_TLV_NAME, 1)) - { - if (pTLV->pData && (pTLV->wLen > 0)) - { - char *pszNick; - WORD wNickLength; - - wNickLength = pTLV->wLen; - - pszNick = (char*)SAFE_MALLOC(wNickLength + 1); - // Copy buffer to utf-8 buffer - memcpy(pszNick, pTLV->pData, wNickLength); - pszNick[wNickLength] = 0; // Terminate string - - NetLog_Server("Nickname is '%s'", pszNick); - - bNicked = 1; - - // Write nickname to database - if (getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded) - { // if just added contact, save details always - does no harm - char *szOldNick; - - if (szOldNick = getSettingStringUtf(hContact, "CList", "MyHandle", NULL)) - { - if ((strcmpnull(szOldNick, pszNick)) && (strlennull(pszNick) > 0)) - { // check if the truncated nick changed, i.e. do not overwrite locally stored longer nick - if (strlennull(szOldNick) <= strlennull(pszNick) || strncmp(szOldNick, pszNick, null_strcut(szOldNick, MAX_SSI_TLV_NAME_SIZE))) - { - // Yes, we really do need to delete it first. Otherwise the CLUI nick - // cache isn't updated (I'll look into it) - DBDeleteContactSetting(hContact,"CList","MyHandle"); - setSettingStringUtf(hContact, "CList", "MyHandle", pszNick); - } - } - SAFE_FREE(&szOldNick); - } - else if (strlennull(pszNick) > 0) - { - DBDeleteContactSetting(hContact,"CList","MyHandle"); - setSettingStringUtf(hContact, "CList", "MyHandle", pszNick); - } - } - SAFE_FREE(&pszNick); - } - else - { - NetLog_Server("Invalid nickname"); - } - } - if (bAdded && !bNicked) - icq_QueueUser(hContact); // queue user without nick for fast auto info update - - // Look for comment TLV and copy it to the db if necessary - if (pTLV = pChain->getTLV(SSI_TLV_COMMENT, 1)) - { - if (pTLV->pData && (pTLV->wLen > 0)) - { - char *pszComment; - WORD wCommentLength; - - - wCommentLength = pTLV->wLen; - - pszComment = (char*)SAFE_MALLOC(wCommentLength + 1); - // Copy buffer to utf-8 buffer - memcpy(pszComment, pTLV->pData, wCommentLength); - pszComment[wCommentLength] = 0; // Terminate string - - NetLog_Server("Comment is '%s'", pszComment); - - // Write comment to database - if (getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded) - { // if just added contact, save details always - does no harm - char *szOldComment; - - if (szOldComment = getSettingStringUtf(hContact, "UserInfo", "MyNotes", NULL)) - { - if ((strcmpnull(szOldComment, pszComment)) && (strlennull(pszComment) > 0)) - { // check if the truncated comment changed, i.e. do not overwrite locally stored longer comment - if (strlennull(szOldComment) <= strlennull(pszComment) || strncmp((char*)szOldComment, (char*)pszComment, null_strcut(szOldComment, MAX_SSI_TLV_COMMENT_SIZE))) - { - setSettingStringUtf(hContact, "UserInfo", "MyNotes", pszComment); - } - } - SAFE_FREE((void**)&szOldComment); - } - else if (strlennull(pszComment) > 0) - { - setSettingStringUtf(hContact, "UserInfo", "MyNotes", pszComment); - } - } - SAFE_FREE((void**)&pszComment); - } - else - { - NetLog_Server("Invalid comment"); - } - } - - // Look for need-authorization TLV - if (pChain->getTLV(SSI_TLV_AWAITING_AUTH, 1)) - { - setSettingByte(hContact, "Auth", 1); - NetLog_Server("SSI contact need authorization"); - } - else - { - setSettingByte(hContact, "Auth", 0); - } - - if (pTLV = pChain->getTLV(SSI_TLV_METAINFO_TOKEN, 1)) - { - setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pTLV->pData, pTLV->wLen); - if (pChain->getTLV(SSI_TLV_METAINFO_TIME, 1)) - setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pChain->getDouble(SSI_TLV_METAINFO_TIME, 1)); - NetLog_Server("SSI contact has meta info token"); - } - else - { - deleteSetting(hContact, DBSETTING_METAINFO_TOKEN); - deleteSetting(hContact, DBSETTING_METAINFO_TIME); - } - - { // store server-list item's TLV data - BYTE* data = (BYTE*)SAFE_MALLOC(wTlvLength); - int datalen = getServerDataFromItemTLV(pChain, data); - - if (datalen > 0) - setSettingBlob(hContact, DBSETTING_SERVLIST_DATA, data, datalen); - else - deleteSetting(hContact, DBSETTING_SERVLIST_DATA); - - SAFE_FREE((void**)&data); - } - } - } - else - { // failed to add or other error - NetLog_Server("SSI failed to handle %s Item '%s'", "Buddy", szRecordName); - } - } - break; - - case SSI_ITEM_GROUP: - if ((wGroupId == 0) && (wItemId == 0)) - { - /* list of groups. wTlvType=1, data is TLV(C8) containing list of WORDs which */ - /* is the group ids - /* we don't need to use this. Our processing is on-the-fly */ - /* this record is always sent first in the first packet only, */ - } - else if (wGroupId != 0) - { - /* wGroupId != 0: a group record */ - if (wItemId == 0) - { /* no item ID: this is a group */ - /* pszRecordName is the name of the group */ - ReserveServerID(wGroupId, SSIT_GROUP, 0); - - setServListGroupName(wGroupId, szRecordName); - - NetLog_Server("Group %s added to known groups.", szRecordName); - - /* demangle full grouppath, set it to known */ - SAFE_FREE(&szActiveSrvGroup); - szActiveSrvGroup = getServListGroupCListPath(wGroupId); - wActiveSrvGroupId = wGroupId; - - /* TLV contains a TLV(C8) with a list of WORDs of contained contact IDs */ - /* our processing is good enough that we don't need this duplication */ - } - else - { - NetLog_Server("Unhandled type 0x01, wItemID != 0"); - } - } - else - { - NetLog_Server("Unhandled type 0x01"); - } - break; - - case SSI_ITEM_PERMIT: - { - /* item on visible list */ - /* wItemId not related to contact ID */ - /* pszRecordName is the UIN */ - HANDLE hContact; - int bAdded; - - hContact = HContactFromRecordName(szRecordName, &bAdded); - - if (hContact != INVALID_HANDLE_VALUE) - { - if (bAdded) - { - NetLog_Server("SSI added new %s contact '%s'", "Permit", szRecordName); - // It wasn't previously in the list, we hide it so it only appears in the visible list - setContactHidden(hContact, 1); - // Add it to the list, so it can be added properly if proper contact - AddJustAddedContact(hContact); - } - else - NetLog_Server("SSI %s contact already exists '%s'", "Permit", szRecordName); - - // Save permit ID - setSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - // Set apparent mode - setSettingWord(hContact, "ApparentMode", ID_STATUS_ONLINE); - NetLog_Server("Visible-contact (%s)", szRecordName); - } - else - { // failed to add or other error - NetLog_Server("SSI failed to handle %s Item '%s'", "Permit", szRecordName); - - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - } - } - break; - - case SSI_ITEM_DENY: - { - /* Item on invisible list */ - /* wItemId not related to contact ID */ - /* pszRecordName is the UIN */ - HANDLE hContact; - int bAdded; - - hContact = HContactFromRecordName(szRecordName, &bAdded); - - if (hContact != INVALID_HANDLE_VALUE) - { - if (bAdded) - { - /* not already on list: added */ - NetLog_Server("SSI added new %s contact '%s'", "Deny", szRecordName); - // It wasn't previously in the list, we hide it so it only appears in the visible list - setContactHidden(hContact, 1); - // Add it to the list, so it can be added properly if proper contact - AddJustAddedContact(hContact); - } - else - NetLog_Server("SSI %s contact already exists '%s'", "Deny", szRecordName); - - // Save Deny ID - setSettingWord(hContact, DBSETTING_SERVLIST_DENY, wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - // Set apparent mode - setSettingWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); - NetLog_Server("Invisible-contact (%s)", szRecordName); - } - else - { // failed to add or other error - NetLog_Server("SSI failed to handle %s Item '%s'", "Deny", szRecordName); - - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - } - } - break; - - case SSI_ITEM_VISIBILITY: /* My visibility settings */ - { - BYTE bVisibility; - - // Look for visibility TLV - if (bVisibility = pChain->getByte(SSI_TLV_VISIBILITY, 1)) - { // found it, store the id, we do not need current visibility - we do not rely on it - setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - NetLog_Server("Visibility is %u", bVisibility); - } - else - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - } - break; - - case SSI_ITEM_IGNORE: - { - /* item on ignore list */ - /* wItemId not related to contact ID */ - /* pszRecordName is the UIN */ - HANDLE hContact; - int bAdded; - - hContact = HContactFromRecordName(szRecordName, &bAdded); - - if (hContact != INVALID_HANDLE_VALUE) - { - if (bAdded) - { - /* not already on list: add */ - NetLog_Server("SSI added new %s contact '%s'", "Ignore", szRecordName); - // It wasn't previously in the list, we hide it - setContactHidden(hContact, 1); - // Add it to the list, so it can be added properly if proper contact - AddJustAddedContact(hContact); - } - else - NetLog_Server("SSI %s contact already exists '%s'", "Ignore", szRecordName); - - // Save Ignore ID - setSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - // Set apparent mode & ignore - setSettingWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); - // set ignore all events - CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, IGNOREEVENT_ALL); - NetLog_Server("Ignore-contact (%s)", szRecordName); - } - else - { // failed to add or other error - NetLog_Server("SSI failed to handle %s Item '%s'", "Ignore", szRecordName); - - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - } - } - break; - - case SSI_ITEM_UNKNOWN2: - NetLog_Server("SSI unknown type 0x11"); - - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - break; - - case SSI_ITEM_IMPORTTIME: - if (wGroupId == 0) - { - /* time our list was first imported */ - /* pszRecordName is "Import Time" */ - /* data is TLV(13) {TLV(D4) {time_t importTime}} */ - setSettingDword(NULL, "ImportTS", pChain->getDWord(SSI_TLV_TIMESTAMP, 1)); - setSettingWord(NULL, "SrvImportID", wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - NetLog_Server("SSI %s item recognized", "first import"); - } - break; - - case SSI_ITEM_BUDDYICON: - if (wGroupId == 0) - { - /* our avatar MD5-hash */ - /* pszRecordName is "1" */ - /* data is TLV(D5) hash */ - /* we ignore this, just save the id */ - /* cause we get the hash again after login */ - if (!strcmpnull(szRecordName, "12")) - { // need to handle Photo Item separately - setSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, wItemId); - NetLog_Server("SSI %s item recognized", "Photo"); - } - else - { - setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, wItemId); - NetLog_Server("SSI %s item recognized", "Avatar"); - } - ReserveServerID(wItemId, SSIT_ITEM, 0); - } - break; - - case SSI_ITEM_METAINFO: - if (wGroupId == 0) - { - /* our meta info token & last update time */ - /* pszRecordName is "ICQ-MDIR" */ - /* data is TLV(15C) and TLV(15D) */ - oscar_tlv* pToken = pChain->getTLV(SSI_TLV_METAINFO_TOKEN, 1); - oscar_tlv* pTime = pChain->getTLV(SSI_TLV_METAINFO_TIME, 1); - if (pToken) - setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); - if (pTime) - setSettingDouble(NULL, DBSETTING_METAINFO_TIME, pChain->getDouble(SSI_TLV_METAINFO_TIME, 1)); - - setSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - NetLog_Server("SSI %s item recognized", "Meta info"); - } - break; - - case SSI_ITEM_CLIENTDATA: - if (wGroupId == 0) - { - /* ICQ2k ShortcutBar Items */ - /* data is TLV(CD) text */ - if (wItemId) - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - } - - case SSI_ITEM_SAVED: - case SSI_ITEM_PREAUTH: - break; - - default: - NetLog_Server("SSI unhandled item %2x", wTlvType); - - if (wItemId) - ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); - break; - } - - disposeChain(&pChain); - } // end for - - // Release Memory - SAFE_FREE(&szActiveSrvGroup); - - NetLog_Server("Bytes left: %u", wLen); - - setSettingWord(NULL, "SrvRecordCount", (WORD)(wRecord + getSettingWord(NULL, "SrvRecordCount", 0))); - - if (bIsLastPacket) - { - // No contacts left to sync - bIsSyncingCL = FALSE; - - StoreServerIDs(); - - icq_RescanInfoUpdate(); - - if (wLen >= 4) - { - DWORD dwLastUpdateTime; - - /* finally we get a time_t of the last update time */ - unpackDWord(&buf, &dwLastUpdateTime); - setSettingDword(NULL, "SrvLastUpdate", dwLastUpdateTime); - NetLog_Server("Last update of server list was (%u) %s", dwLastUpdateTime, time2text(dwLastUpdateTime)); - - sendRosterAck(); - handleServUINSettings(wListenPort, info); - - servlistProcessLogin(); - } - else - { - NetLog_Server("Last packet missed update time..."); - } - if (getSettingWord(NULL, "SrvRecordCount", 0) == 0) - { // we got empty serv-list, create master group - cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { - DWORD dwCookie; - - ack->dwAction = SSA_GROUP_UPDATE; - ack->szGroupName = null_strdup(""); - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); - icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, 0, ack->szGroupName, NULL, 0, 0); - } - } - // serv-list sync finished, clear just added contacts - FlushJustAddedContacts(); - } - else - { - NetLog_Server("Waiting for more packets"); - } -} - - -void CIcqProto::handleServerCListItemAdd(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) -{ - if (wItemType == SSI_ITEM_IMPORTTIME) - { - if (pItemData) - { - setSettingDword(NULL, "ImportTS", pItemData->getDWord(SSI_TLV_TIMESTAMP, 1)); - setSettingWord(NULL, "SrvImportID", wItemId); - ReserveServerID(wItemId, SSIT_ITEM, 0); - - NetLog_Server("Server added Import timestamp to list"); - - return; - } - } - // Reserve server-list ID - ReserveServerID(wItemId, wItemType == SSI_ITEM_GROUP ? SSIT_GROUP : SSIT_ITEM, SSIF_UNHANDLED); -} - - -void CIcqProto::handleServerCListItemUpdate(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) -{ - HANDLE hContact = (wItemType == SSI_ITEM_BUDDY || wItemType == SSI_ITEM_DENY || wItemType == SSI_ITEM_PERMIT || wItemType == SSI_ITEM_IGNORE) ? HContactFromRecordName(szRecordName, NULL) : NULL; - - if (hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY) - { // a contact was updated on server - if (pItemData) - { - oscar_tlv* pAuth = pItemData->getTLV(SSI_TLV_AWAITING_AUTH, 1); - BYTE bAuth = getSettingByte(hContact, "Auth", 0); - - if (bAuth && !pAuth) - { // server authorized our contact - char str[MAX_PATH]; - char msg[MAX_PATH]; - char *nick = NickFromHandleUtf(hContact); - - setSettingByte(hContact, "Auth", 0); - null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" was authorized in the server list."), msg, MAX_PATH), nick); - icq_LogMessage(LOG_WARNING, str); - SAFE_FREE(&nick); - } - else if (!bAuth && pAuth) - { // server took away authorization of our contact - char str[MAX_PATH]; - char msg[MAX_PATH]; - char *nick = NickFromHandleUtf(hContact); - - setSettingByte(hContact, "Auth", 1); - null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" lost its authorization in the server list."), msg, MAX_PATH), nick); - icq_LogMessage(LOG_WARNING, str); - SAFE_FREE(&nick); - } - - { // update metainfo data - DBVARIANT dbv = {0}; - oscar_tlv *pToken = pItemData->getTLV(SSI_TLV_METAINFO_TOKEN, 1); - oscar_tlv *pTime = pItemData->getTLV(SSI_TLV_METAINFO_TIME, 1); - - if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) - { - if (!pToken || dbv.cpbVal != pToken->wLen || memcmp(dbv.pbVal, pToken->pData, dbv.cpbVal)) - { - if (!pToken) - NetLog_Server("Contact %s, meta info token removed", szRecordName); - else - NetLog_Server("Contact %s, meta info token changed", szRecordName); - - // user info was changed, refresh - if (IsMetaInfoChanged(hContact)) - icq_QueueUser(hContact); - } - - ICQFreeVariant(&dbv); - } - else if (pToken) - { - NetLog_Server("Contact %s, meta info token added", szRecordName); - - // user info was changed, refresh - if (IsMetaInfoChanged(hContact)) - icq_QueueUser(hContact); - } - - if (pToken) - setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); - if (pTime) - setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pItemData->getDouble(SSI_TLV_METAINFO_TIME, 1)); - } - - { // update server's data - otherwise consequent operations can fail with 0x0E - BYTE *data = (BYTE*)_alloca(pItemData->getChainLength()); - int datalen = getServerDataFromItemTLV(pItemData, data); - - if (datalen > 0) - setSettingBlob(hContact, DBSETTING_SERVLIST_DATA, data, datalen); - else - deleteSetting(hContact, DBSETTING_SERVLIST_DATA); - } - } - } - else if (wItemType == SSI_ITEM_METAINFO) - { // owner MetaInfo data updated - if (pItemData) - { - DBVARIANT dbv = {0}; - oscar_tlv *pToken = pItemData->getTLV(SSI_TLV_METAINFO_TOKEN, 1); - oscar_tlv *pTime = pItemData->getTLV(SSI_TLV_METAINFO_TIME, 1); - - if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) - { - if (!pToken || dbv.cpbVal != pToken->wLen || memcmp(dbv.pbVal, pToken->pData, dbv.cpbVal)) - { - if (!pToken) - NetLog_Server("Owner meta info token removed"); - else - NetLog_Server("Owner meta info token changed"); - } - - ICQFreeVariant(&dbv); - } - - if (pToken) - setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); - if (pTime) - setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pItemData->getDouble(SSI_TLV_METAINFO_TIME, 1)); - } - } - else if (wItemType == SSI_ITEM_GROUP) - { // group updated - NetLog_Server("Server updated our group \"%s\" on list", szRecordName); - } -} - - -void CIcqProto::handleServerCListItemDelete(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) -{ - HANDLE hContact = (wItemType == SSI_ITEM_BUDDY || wItemType == SSI_ITEM_DENY || wItemType == SSI_ITEM_PERMIT || wItemType == SSI_ITEM_IGNORE) ? HContactFromRecordName(szRecordName, NULL) : NULL; - - if (hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY) - { // a contact was removed from our list - if (getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) == wItemId) - { - deleteSetting(hContact, DBSETTING_SERVLIST_ID); - deleteSetting(hContact, DBSETTING_SERVLIST_GROUP); - deleteSetting(hContact, "Auth"); - - { - char str[MAX_PATH]; - char msg[MAX_PATH]; - char *nick = NickFromHandleUtf(hContact); - - null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("User \"%s\" was removed from server list."), msg, MAX_PATH), nick); - icq_LogMessage(LOG_WARNING, str); - SAFE_FREE(&nick); - } - } - } - // Release server-list ID - FreeServerID(wItemId, wItemType == SSI_ITEM_GROUP ? SSIT_GROUP : SSIT_ITEM); -} - - -void CIcqProto::handleRecvAuthRequest(unsigned char *buf, WORD wLen) -{ - DWORD dwUin; - uid_str szUid; - int bAdded; - - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - if (dwUin && IsOnSpammerList(dwUin)) - { - NetLog_Server("Ignored Message from known Spammer"); - return; - } - - WORD wReasonLen; - unpackWord(&buf, &wReasonLen); - wLen -= 2; - if (wReasonLen > wLen) - return; - - HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); - CCSDATA ccs; - PROTORECVEVENT pre; - - ccs.szProtoService = PSR_AUTH; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.flags = 0; - pre.timestamp = time(NULL); - pre.lParam = sizeof(DWORD) + sizeof(HANDLE) + 5; - // Prepare reason - char *szReason = (char*)SAFE_MALLOC(wReasonLen + 1); - int nReasonLen = 0; - if (szReason) - { - memcpy(szReason, buf, wReasonLen); - szReason[wReasonLen] = '\0'; - nReasonLen = strlennull(szReason); - - char *temp = (char*)_alloca(nReasonLen + 2); - if (!IsUSASCII(szReason, nReasonLen) && UTF8_IsValid(szReason) && utf8_decode_static(szReason, temp, nReasonLen + 1)) - pre.flags |= PREF_UTF; - } - // Read nick name from DB - char *szNick = NULL; - if (dwUin) - { - DBVARIANT dbv = { 0 }; - if (pre.flags & PREF_UTF) - szNick = getSettingStringUtf(hContact, "Nick", NULL); - else if (!getSettingString(hContact, "Nick", &dbv)) - { - szNick = null_strdup(dbv.pszVal); - ICQFreeVariant(&dbv); - } - } - else - szNick = null_strdup(szUid); - int nNickLen = strlennull(szNick); - - pre.lParam += nNickLen + nReasonLen; - - setSettingByte(ccs.hContact, "Grant", 1); - - /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/ - char *szBlob = (char *)_alloca(pre.lParam); - char *pCurBlob = szBlob; - memcpy(pCurBlob, &dwUin, sizeof(DWORD)); pCurBlob += sizeof(DWORD); - memcpy(pCurBlob, &hContact, sizeof(HANDLE)); pCurBlob += sizeof(HANDLE); - if (nNickLen) - { // if we have nick we add it, otherwise keep trailing zero - memcpy(pCurBlob, szNick, nNickLen); - pCurBlob += nNickLen; - } - *pCurBlob = 0; pCurBlob++; // Nick - *pCurBlob = 0; pCurBlob++; // FirstName - *pCurBlob = 0; pCurBlob++; // LastName - *pCurBlob = 0; pCurBlob++; // email - if (nReasonLen) - { - memcpy(pCurBlob, szReason, nReasonLen); - pCurBlob += nReasonLen; - } - *pCurBlob = 0; // Reason - pre.szMessage = szBlob; - - // TODO: Change for new auth system, include all known informations - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); - - SAFE_FREE(&szNick); - SAFE_FREE(&szReason); - return; -} - - -void CIcqProto::handleRecvAdded(unsigned char *buf, WORD wLen) -{ - DWORD dwUin; - uid_str szUid; - DWORD cbBlob; - PBYTE pBlob,pCurBlob; - int bAdded; - char* szNick; - int nNickLen; - DBVARIANT dbv = {0}; - - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - if (dwUin && IsOnSpammerList(dwUin)) - { - NetLog_Server("Ignored Message from known Spammer"); - return; - } - - HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); - - cbBlob=sizeof(DWORD)*2+4; - - if (dwUin) - { - if (getSettingString(hContact, "Nick", &dbv)) - nNickLen = 0; - else - { - szNick = dbv.pszVal; - nNickLen = strlennull(szNick); - } - } - else - nNickLen = strlennull(szUid); - - cbBlob += nNickLen; - - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - /*blob is: uin(DWORD), hContact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) */ - *(DWORD*)pCurBlob = dwUin; pCurBlob += sizeof(DWORD); - *(DWORD*)pCurBlob = DWORD(hContact); pCurBlob += sizeof(DWORD); - if (nNickLen && dwUin) - { // if we have nick we add it, otherwise keep trailing zero - memcpy(pCurBlob, szNick, nNickLen); - pCurBlob+=nNickLen; - } - else - { - memcpy(pCurBlob, szUid, nNickLen); - pCurBlob+=nNickLen; - } - *(char *)pCurBlob = 0; pCurBlob++; - *(char *)pCurBlob = 0; pCurBlob++; - *(char *)pCurBlob = 0; pCurBlob++; - *(char *)pCurBlob = 0; - // TODO: Change for new auth system - - AddEvent(NULL, EVENTTYPE_ADDED, time(NULL), 0, cbBlob, pBlob); -} - - -void CIcqProto::handleRecvAuthResponse(unsigned char *buf, WORD wLen) -{ - DWORD dwUin; - uid_str szUid; - char* szNick = NULL; - WORD nReasonLen; - char* szReason; - int bAdded; - - BYTE bResponse = 0xFF; - - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - if (dwUin && IsOnSpammerList(dwUin)) - { - NetLog_Server("Ignored Message from known Spammer"); - return; - } - - HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); - - if (hContact != INVALID_HANDLE_VALUE) szNick = NickFromHandle(hContact); - - if (wLen > 0) - { - unpackByte(&buf, &bResponse); - wLen -= 1; - } - if (wLen >= 2) - { - unpackWord(&buf, &nReasonLen); - wLen -= 2; - if (wLen >= nReasonLen) - { - szReason = (char*)_alloca(nReasonLen+1); - unpackString(&buf, szReason, nReasonLen); - szReason[nReasonLen] = '\0'; - } - } - - switch (bResponse) - { - - case 0: - NetLog_Server("Authorization request %s by %s", "denied", strUID(dwUin, szUid)); - // TODO: Add to system history as soon as new auth system is ready - break; - - case 1: - setSettingByte(hContact, "Auth", 0); - NetLog_Server("Authorization request %s by %s", "granted", strUID(dwUin, szUid)); - // TODO: Add to system history as soon as new auth system is ready - break; - - default: - NetLog_Server("Unknown Authorization request response (%u) from %s", bResponse, strUID(dwUin, szUid)); - break; - - } - SAFE_FREE(&szNick); -} - - -// Updates the visibility code used while in SSI mode. If a server ID is -// not stored in the local DB, a new ID will be added to the server list. -// -// Possible values are: -// 01 - Allow all users to see you -// 02 - Block all users from seeing you -// 03 - Allow only users in the permit list to see you -// 04 - Block only users in the invisible list from seeing you -// 05 - Allow only users in the buddy list to see you -// -void CIcqProto::updateServVisibilityCode(BYTE bCode) -{ - icq_packet packet; - WORD wVisibilityID; - WORD wCommand; - - if ((bCode > 0) && (bCode < 6)) - { - cookie_servlist_action* ack; - DWORD dwCookie; - BYTE bVisibility = getSettingByte(NULL, "SrvVisibility", 0); - - if (bVisibility == bCode) // if no change was made, not necescary to update that - return; - setSettingByte(NULL, "SrvVisibility", bCode); - - // Do we have a known server visibility ID? We should, unless we just subscribed to the serv-list for the first time - if ((wVisibilityID = getSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0)) == 0) - { - // No, create a new random ID - wVisibilityID = GenerateServerID(SSIT_ITEM, 0); - setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, wVisibilityID); - wCommand = ICQ_LISTS_ADDTOLIST; -#ifdef _DEBUG - NetLog_Server("Made new srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode); -#endif - } - else - { -#ifdef _DEBUG - NetLog_Server("Reused srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode); -#endif - wCommand = ICQ_LISTS_UPDATEGROUP; - } - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (!ack) - { - NetLog_Server("Cookie alloc failure."); - return; // out of memory, go away - } - ack->dwAction = SSA_VISIBILITY; // update visibility - dwCookie = AllocateCookie(CKT_SERVERLIST, wCommand, 0, ack); // take cookie - - // Build and send packet - serverPacketInit(&packet, 25); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, wCommand, 0, dwCookie); - packWord(&packet, 0); // Name (null) - packWord(&packet, 0); // GroupID (0 if not relevant) - packWord(&packet, wVisibilityID); // EntryID - packWord(&packet, SSI_ITEM_VISIBILITY); // EntryType - packWord(&packet, 5); // Length in bytes of following TLV - packTLV(&packet, SSI_TLV_VISIBILITY, 1, &bCode); // TLV (Visibility) - sendServPacket(&packet); - // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or - // ICQ_LISTS_CLI_MODIFYEND when modifying the visibility code - } -} - -// Updates the avatar hash used while in SSI mode. If a server ID is -// not stored in the local DB, a new ID will be added to the server list. -void CIcqProto::updateServAvatarHash(BYTE *pHash, int size) -{ - void** pDoubleObject = NULL; - void* doubleObject = NULL; - DWORD dwOperationFlags = 0; - WORD wAvatarID; - WORD wCommand; - DBVARIANT dbvHash; - int bResetHash = 0; - char szItemName[2] = {0, 0}; - - if (!getSetting(NULL, "AvatarHash", &dbvHash)) - { - szItemName[0] = 0x30 + dbvHash.pbVal[1]; - - if (memcmp(pHash, dbvHash.pbVal, 2) != 0) - { - /** add code to remove old hash from server */ - bResetHash = 1; - } - ICQFreeVariant(&dbvHash); - } - - if (bResetHash) // start update session - { // pair the packets (need to be send in the correct order - dwOperationFlags |= SSOF_BEGIN_OPERATION | SSOF_END_OPERATION; - pDoubleObject = &doubleObject; - } - - if (bResetHash || !pHash) - { - cookie_servlist_action* ack; - DWORD dwCookie; - - // Do we have a known server avatar ID? - if (wAvatarID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) - { - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (!ack) - { - NetLog_Server("Cookie alloc failure."); - return; // out of memory, go away - } - ack->dwAction = SSA_REMOVEAVATAR; // update avatar hash - ack->wContactId = wAvatarID; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); // take cookie - - icq_sendServerItem(dwCookie, ICQ_LISTS_REMOVEFROMLIST, 0, wAvatarID, szItemName, NULL, 0, SSI_ITEM_BUDDYICON, SSOP_ITEM_ACTION | dwOperationFlags, 400, pDoubleObject); - } - } - - if (pHash) - { - cookie_servlist_action* ack; - DWORD dwCookie; - WORD wTLVlen; - icq_packet pBuffer; - WORD hashsize = size - 2; - - // Do we have a known server avatar ID? We should, unless we just subscribed to the serv-list for the first time - if (bResetHash || (wAvatarID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) == 0) - { - // No, create a new random ID - wAvatarID = GenerateServerID(SSIT_ITEM, 0); - wCommand = ICQ_LISTS_ADDTOLIST; -#ifdef _DEBUG - NetLog_Server("Made new srvAvatarID, id is %u", wAvatarID); -#endif - } - else - { -#ifdef _DEBUG - NetLog_Server("Reused srvAvatarID, id is %u", wAvatarID); -#endif - wCommand = ICQ_LISTS_UPDATEGROUP; - } - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (!ack) - { - NetLog_Server("Cookie alloc failure."); - return; // out of memory, go away - } - ack->dwAction = SSA_SETAVATAR; // update avatar hash - ack->wContactId = wAvatarID; - dwCookie = AllocateCookie(CKT_SERVERLIST, wCommand, 0, ack); // take cookie - - szItemName[0] = 0x30 + pHash[1]; - - // Build the packet - wTLVlen = 8 + hashsize; - - // Initialize our handy data buffer - pBuffer.wPlace = 0; - pBuffer.pData = (BYTE *)_alloca(wTLVlen); - pBuffer.wLen = wTLVlen; - - packTLV(&pBuffer, SSI_TLV_NAME, 0, NULL); // TLV (Name) - packTLV(&pBuffer, SSI_TLV_AVATARHASH, hashsize, pHash + 2); // TLV (Hash) - - icq_sendServerItem(dwCookie, wCommand, 0, wAvatarID, szItemName, pBuffer.pData, wTLVlen, SSI_ITEM_BUDDYICON, SSOP_ITEM_ACTION | dwOperationFlags, 400, pDoubleObject); - // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or - // ICQ_LISTS_CLI_MODIFYEND when modifying the avatar hash - } -} - -// Should be called before the server list is modified. When all -// modifications are done, call icq_sendServerEndOperation(). -// Called automatically thru server-list update board! -void CIcqProto::icq_sendServerBeginOperation(int bImport) -{ - icq_packet packet; - WORD wImportID = getSettingWord(NULL, "SrvImportID", 0); - - if (bImport && wImportID) - { // we should be importing, check if already have import item - if (getSettingDword(NULL, "ImportTS", 0) + 604800 < getSettingDword(NULL, "LogonTS", 0)) - { // is the timestamp week older, clear it and begin new import - DWORD dwCookie; - cookie_servlist_action* ack; - - if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) - { // we have cookie good, go on - ack->dwAction = SSA_IMPORT; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); - - icq_sendSimpleItem(dwCookie, ICQ_LISTS_REMOVEFROMLIST, 0, "ImportTime", 0, wImportID, SSI_ITEM_IMPORTTIME, SSOP_ITEM_ACTION | SSOF_SEND_DIRECTLY, 100); - } - } - } - - serverPacketInit(&packet, (WORD)(bImport?14:10)); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_MODIFYSTART); - if (bImport) packDWord(&packet, 1<<0x10); - sendServPacket(&packet); -} - -// Should be called after the server list has been modified to inform -// the server that we are done. -// Called automatically thru server-list update board! -void CIcqProto::icq_sendServerEndOperation() -{ - icq_packet packet; - - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_MODIFYEND); - sendServPacket(&packet); -} - -// Sent when the last roster packet has been received -void CIcqProto::sendRosterAck(void) -{ - icq_packet packet; - - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_GOTLIST); - sendServPacket(&packet); - -#ifdef _DEBUG - NetLog_Server("Sent SNAC(x13,x07) - CLI_ROSTERACK"); -#endif -} diff --git a/protocols/IcqOscarJ/fam_15icqserver.cpp b/protocols/IcqOscarJ/fam_15icqserver.cpp deleted file mode 100644 index 3f332e4f27..0000000000 --- a/protocols/IcqOscarJ/fam_15icqserver.cpp +++ /dev/null @@ -1,1201 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleIcqExtensionsFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_META_ERROR: - handleExtensionError(pBuffer, wBufferLength); - break; - - case ICQ_META_SRV_REPLY: - handleExtensionServerInfo(pBuffer, wBufferLength, pSnacHeader->wFlags); - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_EXTENSIONS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -void CIcqProto::handleExtensionError(BYTE *buf, WORD wPackLen) -{ - WORD wErrorCode; - - if (wPackLen < 2) - wErrorCode = 0; - - if (wPackLen >= 2 && wPackLen <= 6) - unpackWord(&buf, &wErrorCode); - else - { // TODO: cookies need to be handled and freed here on error - oscar_tlv_chain *chain = NULL; - - unpackWord(&buf, &wErrorCode); - wPackLen -= 2; - chain = readIntoTLVChain(&buf, wPackLen, 0); - if (chain) - { - oscar_tlv* pTLV; - - pTLV = chain->getTLV(0x21, 1); // get meta error data - if (pTLV && pTLV->wLen >= 8) - { - BYTE *pBuffer = pTLV->pData; - WORD wData; - pBuffer += 6; - unpackLEWord(&pBuffer, &wData); // get request type - switch (wData) - { - case CLI_META_INFO_REQ: - if (pTLV->wLen >= 12) - { - WORD wSubType; - WORD wCookie; - - unpackWord(&pBuffer, &wCookie); - unpackLEWord(&pBuffer, &wSubType); - // more sofisticated detection, send ack - if (wSubType == META_REQUEST_FULL_INFO) - { - HANDLE hContact; - cookie_fam15_data *pCookieData = NULL; - int foundCookie; - - foundCookie = FindCookie(wCookie, &hContact, (void**)&pCookieData); - if (foundCookie && pCookieData) - { - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - - ReleaseCookie(wCookie); // we do not leak cookie and memory - } - - NetLog_Server("Full info request error 0x%02x received", wErrorCode); - } - else if (wSubType == META_SET_PASSWORD_REQ) - { // failed to change user password, report to UI - BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); - - NetLog_Server("Meta change password request failed, error 0x%02x", wErrorCode); - } - else - NetLog_Server("Meta request error 0x%02x received", wErrorCode); - } - else - NetLog_Server("Meta request error 0x%02x received", wErrorCode); - - break; - - default: - NetLog_Server("Unknown request 0x%02x error 0x%02x received", wData, wErrorCode); - } - disposeChain(&chain); - return; - } - disposeChain(&chain); - } - } - LogFamilyError(ICQ_EXTENSIONS_FAMILY, wErrorCode); -} - - -void CIcqProto::handleExtensionServerInfo(BYTE *buf, WORD wPackLen, WORD wFlags) -{ - oscar_tlv_chain *chain; - oscar_tlv *dataTlv; - - // The entire packet is encapsulated in a TLV type 1 - chain = readIntoTLVChain(&buf, wPackLen, 0); - if (chain == NULL) - { - NetLog_Server("Error: Broken snac 15/3 %d", 1); - return; - } - - dataTlv = chain->getTLV(0x0001, 1); - if (dataTlv == NULL) - { - disposeChain(&chain); - NetLog_Server("Error: Broken snac 15/3 %d", 2); - return; - } - BYTE *databuf = dataTlv->pData; - wPackLen -= 4; - - _ASSERTE(dataTlv->wLen == wPackLen); - _ASSERTE(wPackLen >= 10); - - if ((dataTlv->wLen == wPackLen) && (wPackLen >= 10)) - { - WORD wBytesRemaining; - WORD wRequestType; - WORD wCookie; - DWORD dwMyUin; - - unpackLEWord(&databuf, &wBytesRemaining); - unpackLEDWord(&databuf, &dwMyUin); - unpackLEWord(&databuf, &wRequestType); - unpackWord(&databuf, &wCookie); - - _ASSERTE(wBytesRemaining == (wPackLen - 2)); - if (wBytesRemaining == (wPackLen - 2)) - { - wPackLen -= 10; - switch (wRequestType) - { - case SRV_META_INFO_REPLY: // SRV_META request replies - handleExtensionMetaResponse(databuf, wPackLen, wCookie, wFlags); - break; - - default: - NetLog_Server("Warning: Ignoring Meta response - Unknown type %d", wRequestType); - break; - } - } - } - else - NetLog_Server("Error: Broken snac 15/3 %d", 3); - - if (chain) - disposeChain(&chain); -} - - -void CIcqProto::handleExtensionMetaResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags) -{ - WORD wReplySubtype; - BYTE bResultCode; - - _ASSERTE(wPacketLen >= 3); - if (wPacketLen >= 3) - { - // Reply subtype - unpackLEWord(&databuf, &wReplySubtype); - wPacketLen -= 2; - - // Success byte - unpackByte(&databuf, &bResultCode); - wPacketLen -= 1; - - switch (wReplySubtype) - { - case META_SET_PASSWORD_ACK: - parseUserInfoUpdateAck(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); - break; - - case SRV_RANDOM_FOUND: - case SRV_USER_FOUND: - case SRV_LAST_USER_FOUND: - parseSearchReplies(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); - break; - - case META_PROCESSING_ERROR: // Meta processing error server reply - // Todo: We only use this as an SMS ack, that will have to change - { - // Terminate buffer - char *pszInfo = (char *)_alloca(wPacketLen + 1); - if (wPacketLen > 0) - memcpy(pszInfo, databuf, wPacketLen); - pszInfo[wPacketLen] = 0; - - BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_FAILED, (HANDLE)wCookie, (LPARAM)pszInfo); - FreeCookie(wCookie); - break; - } - break; - - case META_SMS_DELIVERY_RECEIPT: - // Todo: This overlaps with META_SET_AFFINFO_ACK. - // Todo: Check what happens if result != A - if (wPacketLen > 8) - { - WORD wNetworkNameLen; - WORD wAckLen; - char *pszInfo; - - - databuf += 6; // Some unknowns - wPacketLen -= 6; - - unpackWord(&databuf, &wNetworkNameLen); - if (wPacketLen >= (wNetworkNameLen + 2)) - { - databuf += wNetworkNameLen; - wPacketLen -= wNetworkNameLen; - - unpackWord(&databuf, &wAckLen); - if (pszInfo = (char *)_alloca(wAckLen + 1)) - { - // Terminate buffer - if (wAckLen > 0) - memcpy(pszInfo, databuf, wAckLen); - pszInfo[wAckLen] = 0; - - BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SENTREQUEST, (HANDLE)wCookie, (LPARAM)pszInfo); - FreeCookie(wCookie); - - // Parsing success - break; - } - } - } - - // Parsing failure - NetLog_Server("Error: Failure parsing META_SMS_DELIVERY_RECEIPT"); - break; - - case META_DIRECTORY_DATA: - case META_DIRECTORY_RESPONSE: - if (bResultCode == 0x0A) - handleDirectoryQueryResponse(databuf, wPacketLen, wCookie, wReplySubtype, wFlags); - else - NetLog_Server("Error: Directory request failed, code %u", bResultCode); - break; - - case META_DIRECTORY_UPDATE_ACK: - if (bResultCode == 0x0A) - handleDirectoryUpdateResponse(databuf, wPacketLen, wCookie, wReplySubtype); - else - NetLog_Server("Error: Directory request failed, code %u", bResultCode); - break; - - default: - NetLog_Server("Warning: Ignored 15/03 replysubtype x%x", wReplySubtype); - // _ASSERTE(0); - break; - } - - // Success - return; - } - - // Failure - NetLog_Server("Warning: Broken 15/03 ExtensionMetaResponse"); -} - - -void CIcqProto::ReleaseSearchCookie(DWORD dwCookie, cookie_search *pCookie) -{ - if (pCookie) - { - FreeCookie(dwCookie); - if (pCookie->dwMainId) - { - if (pCookie->dwStatus) - { - SAFE_FREE((void**)&pCookie); - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); - } - else - pCookie->dwStatus = 1; - } - else - { - SAFE_FREE((void**)&pCookie); - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); - } - } - else - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); -} - - -void CIcqProto::parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode) -{ - BYTE bParsingOK = FALSE; // For debugging purposes only - BOOL bLastUser = FALSE; - cookie_search *pCookie; - - if (!FindCookie(wCookie, NULL, (void**)&pCookie)) - { - NetLog_Server("Warning: Received unexpected search reply"); - pCookie = NULL; - } - - switch (wReplySubtype) - { - - case SRV_LAST_USER_FOUND: // Search: last user found reply - bLastUser = TRUE; - - case SRV_USER_FOUND: // Search: user found reply - if (bLastUser) - NetLog_Server("SNAC(0x15,0x3): Last search reply"); - else - NetLog_Server("SNAC(0x15,0x3): Search reply"); - - if (bResultCode == 0xA) - { - ICQSEARCHRESULT sr = {0}; - DWORD dwUin; - char szUin[UINMAXLEN]; - WORD wLen; - - sr.hdr.cbSize = sizeof(sr); - - // Remaining bytes - if (wPacketLen < 2) - break; - unpackLEWord(&databuf, &wLen); - wPacketLen -= 2; - - _ASSERTE(wLen <= wPacketLen); - if (wLen > wPacketLen) - break; - - // Uin - if (wPacketLen < 4) - break; - unpackLEDWord(&databuf, &dwUin); // Uin - wPacketLen -= 4; - sr.uin = dwUin; - _itoa(dwUin, szUin, 10); - sr.hdr.id = (FNAMECHAR*)szUin; - - // Nick - if (wPacketLen < 2) - break; - unpackLEWord(&databuf, &wLen); - wPacketLen -= 2; - if (wLen > 0) - { - if (wPacketLen < wLen || (databuf[wLen-1] != 0)) - break; - sr.hdr.nick = (FNAMECHAR*)databuf; - databuf += wLen; - } - else - { - sr.hdr.nick = NULL; - } - - // First name - if (wPacketLen < 2) - break; - unpackLEWord(&databuf, &wLen); - wPacketLen -= 2; - if (wLen > 0) - { - if (wPacketLen < wLen || (databuf[wLen-1] != 0)) - break; - sr.hdr.firstName = (FNAMECHAR*)databuf; - databuf += wLen; - } - else - { - sr.hdr.firstName = NULL; - } - - // Last name - if (wPacketLen < 2) - break; - unpackLEWord(&databuf, &wLen); - wPacketLen -= 2; - if (wLen > 0) - { - if (wPacketLen < wLen || (databuf[wLen-1] != 0)) - break; - sr.hdr.lastName = (FNAMECHAR*)databuf; - databuf += wLen; - } - else - { - sr.hdr.lastName = NULL; - } - - // E-mail name - if (wPacketLen < 2) - break; - unpackLEWord(&databuf, &wLen); - wPacketLen -= 2; - if (wLen > 0) - { - if (wPacketLen < wLen || (databuf[wLen-1] != 0)) - break; - sr.hdr.email = (FNAMECHAR*)databuf; - databuf += wLen; - } - else - { - sr.hdr.email = NULL; - } - - // Authentication needed flag - if (wPacketLen < 1) - break; - unpackByte(&databuf, &sr.auth); - - // Finally, broadcast the result - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)wCookie, (LPARAM)&sr); - - // Broadcast "Last result" ack if this was the last user found - if (wReplySubtype == SRV_LAST_USER_FOUND) - { - if (wPacketLen>=10) - { - DWORD dwLeft; - - databuf += 5; - unpackLEDWord(&databuf, &dwLeft); - if (dwLeft) - NetLog_Server("Warning: %d search results omitted", dwLeft); - } - ReleaseSearchCookie(wCookie, pCookie); - } - bParsingOK = TRUE; - } - else - { - // Failed search - NetLog_Server("SNAC(0x15,0x3): Search error %u", bResultCode); - - ReleaseSearchCookie(wCookie, pCookie); - - bParsingOK = TRUE; - } - break; - - case SRV_RANDOM_FOUND: // Random search server reply - default: - if (pCookie) - ReleaseCookie(wCookie); - break; - } - - // For debugging purposes only - if (!bParsingOK) - { - NetLog_Server("Warning: Parsing error in 15/03 search reply type x%x", wReplySubtype); - _ASSERTE(!bParsingOK); - } -} - - -void CIcqProto::parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode) -{ - switch (wReplySubtype) { - case META_SET_PASSWORD_ACK: // Set user password server ack - - if (bResultCode == 0xA) - BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - else - BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); - - FreeCookie(wCookie); - break; - - default: - NetLog_Server("Warning: Ignored 15/03 user info update ack type x%x", wReplySubtype); - break; - } -} - - -UserInfoRecordItem rEmail[] = { - {0x64, DBVT_ASCIIZ, "e-mail%u"} -}; - -UserInfoRecordItem rAddress[] = { - {0x64, DBVT_UTF8, "Street"}, - {0x6E, DBVT_UTF8, "City"}, - {0x78, DBVT_UTF8, "State"}, - {0x82, DBVT_UTF8, "ZIP"}, - {0x8C, DBVT_WORD, "Country"} -}; - -UserInfoRecordItem rOriginAddress[] = { - {0x64, DBVT_UTF8, "OriginStreet"}, - {0x6E, DBVT_UTF8, "OriginCity"}, - {0x78, DBVT_UTF8, "OriginState"}, - {0x8C, DBVT_WORD, "OriginCountry"} -}; - -UserInfoRecordItem rCompany[] = { - {0x64, DBVT_UTF8, "CompanyPosition"}, - {0x6E, DBVT_UTF8, "Company"}, - {0x7D, DBVT_UTF8, "CompanyDepartment"}, - {0x78, DBVT_ASCIIZ, "CompanyHomepage"}, - {0x82, DBVT_WORD, "CompanyIndustry"}, - {0xAA, DBVT_UTF8, "CompanyStreet"}, - {0xB4, DBVT_UTF8, "CompanyCity"}, - {0xBE, DBVT_UTF8, "CompanyState"}, - {0xC8, DBVT_UTF8, "CompanyZIP"}, - {0xD2, DBVT_WORD, "CompanyCountry"} -}; - -UserInfoRecordItem rEducation[] = { - {0x64, DBVT_WORD, "StudyLevel"}, - {0x6E, DBVT_UTF8, "StudyInstitute"}, - {0x78, DBVT_UTF8, "StudyDegree"}, - {0x8C, DBVT_WORD, "StudyYear"} -}; - -UserInfoRecordItem rInterest[] = { - {0x64, DBVT_UTF8, "Interest%uText"}, - {0x6E, DBVT_WORD, "Interest%uCat"} -}; - - -int CIcqProto::parseUserInfoRecord(HANDLE hContact, oscar_tlv *pData, UserInfoRecordItem pRecordDef[], int nRecordDef, int nMaxRecords) -{ - int nRecords = 0; - - if (pData && pData->wLen >= 2) - { - BYTE *pRecords = pData->pData; - WORD wRecordCount; - unpackWord(&pRecords, &wRecordCount); - oscar_tlv_record_list *cData = readIntoTLVRecordList(&pRecords, pData->wLen - 2, nMaxRecords > wRecordCount ? wRecordCount : nMaxRecords); - oscar_tlv_record_list *cDataItem = cData; - while (cDataItem) - { - oscar_tlv_chain *cItem = cDataItem->item; - - for (int i = 0; i < nRecordDef; i++) - { - char szItemKey[MAX_PATH]; - - null_snprintf(szItemKey, MAX_PATH, pRecordDef[i].szDbSetting, nRecords); - - switch (pRecordDef[i].dbType) - { - case DBVT_ASCIIZ: - writeDbInfoSettingTLVString(hContact, szItemKey, cItem, pRecordDef[i].wTLV); - break; - - case DBVT_UTF8: - writeDbInfoSettingTLVStringUtf(hContact, szItemKey, cItem, pRecordDef[i].wTLV); - break; - - case DBVT_WORD: - writeDbInfoSettingTLVWord(hContact, szItemKey, cItem, pRecordDef[i].wTLV); - break; - } - } - nRecords++; - - cDataItem = cDataItem->next; - } - // release memory - disposeRecordList(&cData); - } - // remove old data from database - if (!nRecords || nMaxRecords > 1) - for (int i = nRecords; i <= nMaxRecords; i++) - for (int j = 0; j < nRecordDef; j++) - { - char szItemKey[MAX_PATH]; - - null_snprintf(szItemKey, MAX_PATH, pRecordDef[j].szDbSetting, i); - - deleteSetting(hContact, szItemKey); - } - - return nRecords; -} - - -void CIcqProto::handleDirectoryQueryResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, WORD wFlags) -{ - WORD wBytesRemaining = 0; - snac_header requestSnac = {0}; - BYTE requestResult; - -#ifdef _DEBUG - NetLog_Server("Received directory query response"); -#endif - if (wPacketLen >= 2) - unpackLEWord(&databuf, &wBytesRemaining); - wPacketLen -= 2; - _ASSERTE(wPacketLen == wBytesRemaining); - - if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) - { - NetLog_Server("Error: Failed to parse directory response"); - return; - } - - cookie_directory_data *pCookieData; - HANDLE hContact; - // check request cookie - if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) - { - NetLog_Server("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); - return; - } - /// FIXME: we should really check the snac contents according to cookie data here ?? - - // Check if this is the last packet for this request - BOOL bMoreDataFollows = wFlags&0x0001 && requestSnac.wFlags&0x0001; - - if (wPacketLen >= 3) - unpackByte(&databuf, &requestResult); - else - { - NetLog_Server("Error: Malformed directory response"); - if (!bMoreDataFollows) - ReleaseCookie(wCookie); - return; - } - if (requestResult != 1 && requestResult != 4) - { - NetLog_Server("Error: Directory request failed, status %u", requestResult); - - if (!bMoreDataFollows) - { - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that - ReleaseCookie(wCookie); - } - return; - } - WORD wLen; - - unpackWord(&databuf, &wLen); - wPacketLen -= 3; - if (wLen) - NetLog_Server("Warning: Data in error message present!"); - - if (wPacketLen <= 0x16) - { // sanity check - NetLog_Server("Error: Malformed directory response"); - - if (!bMoreDataFollows) - { - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that - ReleaseCookie(wCookie); - } - return; - } - databuf += 0x10; // unknown stuff - wPacketLen -= 0x10; - - DWORD dwItemCount; - WORD wPageCount; - - /// FIXME: check itemcount, pagecount against the cookie data ??? - - unpackDWord(&databuf, &dwItemCount); - unpackWord(&databuf, &wPageCount); - wPacketLen -= 6; - - if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH && !bMoreDataFollows) - NetLog_Server("Directory Search: %d contacts found (%u pages)", dwItemCount, wPageCount); - - if (wPacketLen <= 2) - { // sanity check, block expected - NetLog_Server("Error: Malformed directory response"); - - if (!bMoreDataFollows) - { - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that - ReleaseCookie(wCookie); - } - return; - } - WORD wData; - - unpackWord(&databuf, &wData); // This probably the count of items following (a block) - wPacketLen -= 2; - if (wPacketLen >= 2 && wData >= 1) - { - unpackWord(&databuf, &wLen); // This is the size of the first item - wPacketLen -= 2; - } - - if (wData == 0 && pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) - { - NetLog_Server("Directory Search: No contacts found"); - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - ReleaseCookie(wCookie); - return; - } - - _ASSERTE(wData == 1 && wPacketLen == wLen); - if (wData != 1 || wPacketLen != wLen) - { - NetLog_Server("Error: Malformed directory response (missing data)"); - - if (!bMoreDataFollows) - { - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); - else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that - ReleaseCookie(wCookie); - } - return; - } - oscar_tlv_chain *pDirectoryData = readIntoTLVChain(&databuf, wLen, -1); - if (pDirectoryData) - { - switch (pCookieData->bRequestType) - { - case DIRECTORYREQUEST_INFOOWNER: - parseDirectoryUserDetailsData(NULL, pDirectoryData, wCookie, pCookieData, wReplySubtype); - break; - - case DIRECTORYREQUEST_INFOUSER: - { - DWORD dwUin = 0; - char *szUid = pDirectoryData->getString(0x32, 1); - if (!szUid) - { - NetLog_Server("Error: Received unrecognized data from the directory"); - break; - } - - if (IsStringUIN(szUid)) - dwUin = atoi(szUid); - - if (hContact != HContactFromUID(dwUin, szUid, NULL)) - { - NetLog_Server("Error: Received data does not match cookie contact, ignoring."); - SAFE_FREE(&szUid); - break; - } - else - SAFE_FREE(&szUid); - } - - case DIRECTORYREQUEST_INFOMULTI: - parseDirectoryUserDetailsData(hContact, pDirectoryData, wCookie, pCookieData, wReplySubtype); - break; - - case DIRECTORYREQUEST_SEARCH: - parseDirectorySearchData(pDirectoryData, wCookie, pCookieData, wReplySubtype); - break; - - default: - NetLog_Server("Error: Unknown cookie type %x for directory response!", pCookieData->bRequestType); - } - disposeChain(&pDirectoryData); - } - else - NetLog_Server("Error: Failed parsing directory response"); - - // Release Memory - if (!bMoreDataFollows) - ReleaseCookie(wCookie); -} - - -static int calcAgeFromBirthDate(double dDate) -{ - if (dDate > 0) - { // date is stored as double with unit equal to a day, incrementing since 1/1/1900 0:00 GMT - SYSTEMTIME sDate = {0}; - if (VariantTimeToSystemTime(dDate + 2, &sDate)) - { - SYSTEMTIME sToday = {0}; - - GetLocalTime(&sToday); - - int nAge = sToday.wYear - sDate.wYear; - - if (sToday.wMonth < sDate.wMonth || (sToday.wMonth == sDate.wMonth && sToday.wDay < sDate.wDay)) - nAge--; - - return nAge; - } - } - return 0; -} - - -void CIcqProto::parseDirectoryUserDetailsData(HANDLE hContact, oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType) -{ - oscar_tlv *pTLV; - WORD wRecordCount; - - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOMULTI && !hContact) - { - DWORD dwUin = 0; - char *szUid = cDetails->getString(0x32, 1); - if (!szUid) - { - NetLog_Server("Error: Received unrecognized data from the directory"); - return; - } - - if (IsStringUIN(szUid)) - dwUin = atoi(szUid); - - hContact = HContactFromUID(dwUin, szUid, NULL); - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("Error: Received details for unknown contact \"%s\"", szUid); - SAFE_FREE(&szUid); - return; - } -#ifdef _DEBUG - else - NetLog_Server("Received user info for %s from directory", szUid); -#endif - SAFE_FREE(&szUid); - } -#ifdef _DEBUG - else - { - char *szUid = cDetails->getString(0x32, 1); - - if (!hContact) - NetLog_Server("Received owner user info from directory"); - else - NetLog_Server("Received user info for %s from directory", szUid); - SAFE_FREE(&szUid); - } -#endif - - pTLV = cDetails->getTLV(0x50, 1); - if (pTLV && pTLV->wLen > 0) - writeDbInfoSettingTLVString(hContact, "e-mail", cDetails, 0x50); // Verified e-mail - else - writeDbInfoSettingTLVString(hContact, "e-mail", cDetails, 0x55); // Pending e-mail - - writeDbInfoSettingTLVStringUtf(hContact, "FirstName", cDetails, 0x64); - writeDbInfoSettingTLVStringUtf(hContact, "LastName", cDetails, 0x6E); - writeDbInfoSettingTLVStringUtf(hContact, "Nick", cDetails, 0x78); - // Home Address - parseUserInfoRecord(hContact, cDetails->getTLV(0x96, 1), rAddress, SIZEOF(rAddress), 1); - // Origin Address - parseUserInfoRecord(hContact, cDetails->getTLV(0xA0, 1), rOriginAddress, SIZEOF(rOriginAddress), 1); - // Phones - pTLV = cDetails->getTLV(0xC8, 1); - if (pTLV && pTLV->wLen >= 2) - { - BYTE *pRecords = pTLV->pData; - unpackWord(&pRecords, &wRecordCount); - oscar_tlv_record_list *cPhones = readIntoTLVRecordList(&pRecords, pTLV->wLen - 2, wRecordCount); - if (cPhones) - { - oscar_tlv_chain *cPhone; - cPhone = cPhones->getRecordByTLV(0x6E, 1); - writeDbInfoSettingTLVString(hContact, "Phone", cPhone, 0x64); - cPhone = cPhones->getRecordByTLV(0x6E, 2); - writeDbInfoSettingTLVString(hContact, "CompanyPhone", cPhone, 0x64); - cPhone = cPhones->getRecordByTLV(0x6E, 3); - writeDbInfoSettingTLVString(hContact, "Cellular", cPhone, 0x64); - cPhone = cPhones->getRecordByTLV(0x6E, 4); - writeDbInfoSettingTLVString(hContact, "Fax", cPhone, 0x64); - cPhone = cPhones->getRecordByTLV(0x6E, 5); - writeDbInfoSettingTLVString(hContact, "CompanyFax", cPhone, 0x64); - - disposeRecordList(&cPhones); - } - else - { // Remove old data when phones not available - deleteSetting(hContact, "Phone"); - deleteSetting(hContact, "CompanyPhone"); - deleteSetting(hContact, "Cellular"); - deleteSetting(hContact, "Fax"); - deleteSetting(hContact, "CompanyFax"); - } - } - else - { // Remove old data when phones not available - deleteSetting(hContact, "Phone"); - deleteSetting(hContact, "CompanyPhone"); - deleteSetting(hContact, "Cellular"); - deleteSetting(hContact, "Fax"); - deleteSetting(hContact, "CompanyFax"); - } - // Emails - parseUserInfoRecord(hContact, cDetails->getTLV(0x8C, 1), rEmail, SIZEOF(rEmail), 4); - - writeDbInfoSettingTLVByte(hContact, "Timezone", cDetails, 0x17C); - // Company - parseUserInfoRecord(hContact, cDetails->getTLV(0x118, 1), rCompany, SIZEOF(rCompany), 1); - // Education - parseUserInfoRecord(hContact, cDetails->getTLV(0x10E, 1), rEducation, SIZEOF(rEducation), 1); - - switch (cDetails->getNumber(0x82, 1)) - { - case 1: - setSettingByte(hContact, "Gender", 'F'); - break; - case 2: - setSettingByte(hContact, "Gender", 'M'); - break; - default: - deleteSetting(hContact, "Gender"); - } - - writeDbInfoSettingTLVString(hContact, "Homepage", cDetails, 0xFA); - writeDbInfoSettingTLVDate(hContact, "BirthYear", "BirthMonth", "BirthDay", cDetails, 0x1A4); - - writeDbInfoSettingTLVByte(hContact, "Language1", cDetails, 0xAA); - writeDbInfoSettingTLVByte(hContact, "Language2", cDetails, 0xB4); - writeDbInfoSettingTLVByte(hContact, "Language3", cDetails, 0xBE); - - writeDbInfoSettingTLVByte(hContact, "MaritalStatus", cDetails, 0x12C); - // Interests - parseUserInfoRecord(hContact, cDetails->getTLV(0x122, 1), rInterest, SIZEOF(rInterest), 4); - - writeDbInfoSettingTLVStringUtf(hContact, "About", cDetails, 0x186); - -// if (hContact) -// writeDbInfoSettingTLVStringUtf(hContact, DBSETTING_STATUS_NOTE, cDetails, 0x226); -// else - if (!hContact) - { // Owner contact needs special processing, in the database is current status note for the client - // We just received the last status note set on directory, if it differs call SetStatusNote() to - // ensure the directory will be updated (it should be in process anyway) - char *szClientStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, NULL); - char *szDirectoryStatusNote = cDetails->getString(0x226, 1); - - if (strcmpnull(szClientStatusNote, szDirectoryStatusNote)) - SetStatusNote(szClientStatusNote, 1000, TRUE); - - // Release memory - SAFE_FREE(&szDirectoryStatusNote); - SAFE_FREE(&szClientStatusNote); - } - - writeDbInfoSettingTLVByte(hContact, "PrivacyLevel", cDetails, 0x1F9); - - if (!hContact) - { - setSettingByte(hContact, "Auth", !cDetails->getByte(0x19A, 1)); - writeDbInfoSettingTLVByte(hContact, "WebAware", cDetails, 0x212); - writeDbInfoSettingTLVByte(hContact, "AllowSpam", cDetails, 0x1EA); - } - - writeDbInfoSettingTLVWord(hContact, "InfoCP", cDetails, 0x1C2); - - if (hContact) - { // Handle deprecated setting (Age & Birthdate are not separate fields anymore) - int nAge = calcAgeFromBirthDate(cDetails->getDouble(0x1A4, 1)); - - if (nAge) - setSettingWord(hContact, "Age", nAge); - else - deleteSetting(hContact, "Age"); - } - else // we do not need to calculate age for owner - deleteSetting(hContact, "Age"); - - { // Save user info last update time and privacy token - double dInfoTime; - BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - int bHasMetaToken = FALSE; - - // Check if the details arrived with privacy token! - if ((pTLV = cDetails->getTLV(0x3C, 1)) && pTLV->wLen == 0x10 && memcmp(pTLV->pData, pbEmptyMetaToken, 0x10)) - bHasMetaToken = TRUE; - - // !Important, we need to save the MDir server-item time - it can be newer than the one from the directory - if ((dInfoTime = getSettingDouble(hContact, DBSETTING_METAINFO_TIME, 0)) > 0) - setSettingDouble(hContact, DBSETTING_METAINFO_SAVED, dInfoTime); - else if (bHasMetaToken || !hContact) - writeDbInfoSettingTLVDouble(hContact, DBSETTING_METAINFO_SAVED, cDetails, 0x1CC); - else - setSettingDword(hContact, DBSETTING_METAINFO_SAVED, time(NULL)); - } - - if (wReplySubType == META_DIRECTORY_RESPONSE) - if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) - BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0); - - // Remove user from info update queue. Removing is fast so we always call this - // even if it is likely that the user is not queued at all. - if (hContact) - icq_DequeueUser(getContactUin(hContact)); -} - - -void CIcqProto::parseDirectorySearchData(oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType) -{ - ICQSEARCHRESULT isr = {0}; - char *szUid = cDetails->getString(0x32, 1); // User ID - -#ifdef _DEBUG - NetLog_Server("Directory Search: Found user %s", szUid); -#endif - isr.hdr.cbSize = sizeof(ICQSEARCHRESULT); - isr.hdr.flags = PSR_TCHAR; - isr.hdr.id = ansi_to_tchar(szUid); - - if (IsStringUIN(szUid)) - isr.uin = atoi(szUid); - else - isr.uin = 0; - - SAFE_FREE(&szUid); - - oscar_tlv *pTLV = cDetails->getTLV(0x50, 1); - char *szData = NULL; - - if (pTLV && pTLV->wLen > 0) - szData = cDetails->getString(0x50, 1); // Verified e-mail - else - szData = cDetails->getString(0x55, 1); // Pending e-mail - if (strlennull(szData)) - isr.hdr.email = ansi_to_tchar(szData); - SAFE_FREE(&szData); - - szData = cDetails->getString(0x64, 1); // First Name - if (strlennull(szData)) - isr.hdr.firstName = utf8_to_tchar(szData); - SAFE_FREE(&szData); - - szData = cDetails->getString(0x6E, 1); // Last Name - if (strlennull(szData)) - isr.hdr.lastName = utf8_to_tchar(szData); - SAFE_FREE(&szData); - - szData = cDetails->getString(0x78, 1); // Nick - if (strlennull(szData)) - isr.hdr.nick = utf8_to_tchar(szData); - SAFE_FREE(&szData); - - switch (cDetails->getNumber(0x82, 1)) // Gender - { - case 1: - isr.gender = 'F'; - break; - case 2: - isr.gender = 'M'; - break; - } - - pTLV = cDetails->getTLV(0x96, 1); - if (pTLV && pTLV->wLen >= 4) - { - BYTE *buf = pTLV->pData; - oscar_tlv_chain *chain = readIntoTLVChain(&buf, pTLV->wLen, 0); - if (chain) - isr.country = chain->getDWord(0x8C, 1); // Home Country - disposeChain(&chain); - } - - isr.auth = !cDetails->getByte(0x19A, 1); // Require Authorization - isr.maritalStatus = cDetails->getNumber(0x12C, 1); // Marital Status - - // calculate Age if Birthdate is available - isr.age = calcAgeFromBirthDate(cDetails->getDouble(0x1A4, 1)); - - // Finally, broadcast the result - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)dwCookie, (LPARAM)&isr); - - // Release memory - SAFE_FREE(&isr.hdr.id); - SAFE_FREE(&isr.hdr.nick); - SAFE_FREE(&isr.hdr.firstName); - SAFE_FREE(&isr.hdr.lastName); - SAFE_FREE(&isr.hdr.email); - - // Search is over, broadcast final ack - if (wReplySubType == META_DIRECTORY_RESPONSE) - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); -} - - -void CIcqProto::handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype) -{ - WORD wBytesRemaining = 0; - snac_header requestSnac = {0}; - BYTE requestResult; - -#ifdef _DEBUG - NetLog_Server("Received directory update response"); -#endif - if (wPacketLen >= 2) - unpackLEWord(&databuf, &wBytesRemaining); - wPacketLen -= 2; - _ASSERTE(wPacketLen == wBytesRemaining); - - if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) - { - NetLog_Server("Error: Failed to parse directory response"); - return; - } - - cookie_directory_data *pCookieData; - HANDLE hContact; - // check request cookie - if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) - { - NetLog_Server("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); - return; - } - /// FIXME: we should really check the snac contents according to cookie data here ?? - - if (wPacketLen >= 3) - unpackByte(&databuf, &requestResult); - else - { - NetLog_Server("Error: Malformed directory response"); - ReleaseCookie(wCookie); - return; - } - if (requestResult != 1 && requestResult != 4) - { - NetLog_Server("Error: Directory request failed, status %u", requestResult); - - if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) - BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); - - ReleaseCookie(wCookie); - return; - } - WORD wLen; - - unpackWord(&databuf, &wLen); - wPacketLen -= 3; - if (wLen) - NetLog_Server("Warning: Data in error message present!"); - - if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) - BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - if (wPacketLen == 0x18) - { - DWORD64 qwMetaTime; - BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - unpackQWord(&databuf, &qwMetaTime); - setSettingBlob(NULL, DBSETTING_METAINFO_TIME, (BYTE*)&qwMetaTime, 8); - - if (memcmp(databuf, pbEmptyMetaToken, 0x10)) - setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, databuf, 0x10); - } - ReleaseCookie(wCookie); -} diff --git a/protocols/IcqOscarJ/fam_17signon.cpp b/protocols/IcqOscarJ/fam_17signon.cpp deleted file mode 100644 index b35a432a48..0000000000 --- a/protocols/IcqOscarJ/fam_17signon.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleAuthorizationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_SIGNON_ERROR: - { - WORD wError; - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - LogFamilyError(ICQ_AUTHORIZATION_FAMILY, wError); - break; - } - - case ICQ_SIGNON_AUTH_KEY: - handleAuthKeyResponse(pBuffer, wBufferLength, info); - break; - - case ICQ_SIGNON_LOGIN_REPLY: - handleLoginReply(pBuffer, wBufferLength, info); - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_AUTHORIZATION_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - -static void icq_encryptPassword(const char *szPassword, BYTE *encrypted) -{ - BYTE table[] = - { - 0xf3, 0x26, 0x81, 0xc4, - 0x39, 0x86, 0xdb, 0x92, - 0x71, 0xa3, 0xb9, 0xe6, - 0x53, 0x7a, 0x95, 0x7c - }; - - for (int i = 0; szPassword[i]; i++) - encrypted[i] = (szPassword[i] ^ table[i % 16]); -} - -void CIcqProto::sendClientAuth(const char *szKey, WORD wKeyLen, BOOL bSecure) -{ - char szUin[UINMAXLEN]; - WORD wUinLen; - icq_packet packet; - - wUinLen = strlennull(strUID(m_dwLocalUIN, szUin)); - - packet.wLen = 70 + sizeof(CLIENT_ID_STRING) + wUinLen + wKeyLen + (m_bSecureConnection ? 4 : 0); - - if (bSecure) - { - serverPacketInit(&packet, (WORD)(packet.wLen + 10)); - packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_LOGIN_REQUEST, 0, 0); - } - else - { - write_flap(&packet, ICQ_LOGIN_CHAN); - packDWord(&packet, 0x00000001); - } - packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin); - - if (bSecure) - { // Pack MD5 auth digest - packTLV(&packet, 0x0025, wKeyLen, (BYTE*)szKey); - packDWord(&packet, 0x004C0000); // empty TLV(0x4C): unknown - } - else - { // Pack old style password hash - BYTE hash[20]; - - icq_encryptPassword(szKey, hash); - packTLV(&packet, 0x0002, wKeyLen, hash); - } - - // Pack client identification details. - packTLV(&packet, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, (LPBYTE)CLIENT_ID_STRING); - packTLVWord(&packet, 0x0017, CLIENT_VERSION_MAJOR); - packTLVWord(&packet, 0x0018, CLIENT_VERSION_MINOR); - packTLVWord(&packet, 0x0019, CLIENT_VERSION_LESSER); - packTLVWord(&packet, 0x001a, CLIENT_VERSION_BUILD); - packTLVWord(&packet, 0x0016, CLIENT_ID_CODE); - packTLVDWord(&packet, 0x0014, CLIENT_DISTRIBUTION); - packTLV(&packet, 0x000f, 0x0002, (LPBYTE)CLIENT_LANGUAGE); - packTLV(&packet, 0x000e, 0x0002, (LPBYTE)CLIENT_COUNTRY); - packTLV(&packet, 0x0094, 0x0001, &m_bConnectionLost); // CLIENT_RECONNECT flag - if (m_bSecureConnection) - packDWord(&packet, 0x008C0000); // empty TLV(0x8C): use SSL - - sendServPacket(&packet); -} - -void CIcqProto::handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info) -{ - WORD wKeyLen; - char szKey[64] = {0}; - mir_md5_state_t state; - mir_md5_byte_t digest[16]; - -#ifdef _DEBUG - NetLog_Server("Received %s", "ICQ_SIGNON_AUTH_KEY"); -#endif - - if (wPacketLen < 2) - { - NetLog_Server("Malformed %s", "ICQ_SIGNON_AUTH_KEY"); - icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid server response.")); - SetCurrentStatus(ID_STATUS_OFFLINE); - return; - } - - unpackWord(&buf, &wKeyLen); - wPacketLen -= 2; - - if (!wKeyLen || wKeyLen > wPacketLen || wKeyLen > sizeof(szKey)) - { - NetLog_Server("Invalid length in %s: %u", "ICQ_SIGNON_AUTH_KEY", wKeyLen); - icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid key length.")); - SetCurrentStatus(ID_STATUS_OFFLINE); - return; - } - - unpackString(&buf, szKey, wKeyLen); - - mir_md5_init(&state); - mir_md5_append(&state, info->szAuthKey, info->wAuthKeyLen); - mir_md5_finish(&state, digest); - - mir_md5_init(&state); - mir_md5_append(&state, (LPBYTE)szKey, wKeyLen); - mir_md5_append(&state, digest, 16); - mir_md5_append(&state, (LPBYTE)CLIENT_MD5_STRING, sizeof(CLIENT_MD5_STRING)-1); - mir_md5_finish(&state, digest); - -#ifdef _DEBUG - NetLog_Server("Sending ICQ_SIGNON_LOGIN_REQUEST to login server"); -#endif - sendClientAuth((char*)digest, 0x10, TRUE); -} diff --git a/protocols/IcqOscarJ/families.h b/protocols/IcqOscarJ/families.h deleted file mode 100644 index 61ac38f17a..0000000000 --- a/protocols/IcqOscarJ/families.h +++ /dev/null @@ -1,74 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Declaration for handlers of Channel 2 SNAC Families -// -// ----------------------------------------------------------------------------- -#ifndef __FAMILIES_H -#define __FAMILIES_H - - -struct message_ack_params -{ - BYTE bType; - DWORD dwUin; - DWORD dwMsgID1; - DWORD dwMsgID2; - directconnect *pDC; - WORD wCookie; - int msgType; - BYTE bFlags; -}; - -#define MAT_SERVER_ADVANCED 0 -#define MAT_DIRECT 1 - - -/* handleMessageTypes(): mMsgFlags constants */ -#define MTF_DIRECT 1 -#define MTF_PLUGIN 2 -#define MTF_STATUS_EXTENDED 4 - - -struct UserInfoRecordItem -{ - WORD wTLV; - int dbType; - char *szDbSetting; -}; - -/*---------* Functions *---------------*/ - -int getPluginTypeIdLen(int nTypeID); -void packPluginTypeId(icq_packet *packet, int nTypeID); - -#define BUL_ALLCONTACTS 0 -#define BUL_VISIBLE 1 -#define BUL_INVISIBLE 2 -#define BUL_TEMPVISIBLE 4 - - -#endif /* __FAMILIES_H */ diff --git a/protocols/IcqOscarJ/globals.h b/protocols/IcqOscarJ/globals.h deleted file mode 100644 index c0d8326689..0000000000 --- a/protocols/IcqOscarJ/globals.h +++ /dev/null @@ -1,57 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Contains global types & variables declarations. -// -// ----------------------------------------------------------------------------- - -#ifndef __GLOBALS_H -#define __GLOBALS_H - - -typedef char uid_str[MAX_PATH]; - -// from init.cpp -extern HINSTANCE hInst; -extern DWORD MIRANDA_VERSION; - -extern IcqIconHandle hStaticIcons[]; - -extern const int moodXStatus[]; - -// from fam_04message.cpp -struct icq_mode_messages -{ - char *szOnline; - char *szAway; - char *szNa; - char *szDnd; - char *szOccupied; - char *szFfc; -}; - - -#endif /* __GLOBALS_H */ diff --git a/protocols/IcqOscarJ/guids.h b/protocols/IcqOscarJ/guids.h deleted file mode 100644 index 24073deec4..0000000000 --- a/protocols/IcqOscarJ/guids.h +++ /dev/null @@ -1,81 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Contains helper functions to handle oscar message GUIDs. -// -// ----------------------------------------------------------------------------- - -#ifndef __GUIDS_H -#define __GUIDS_H - - -typedef DWORD plugin_guid[4]; - -// Message Capability GUIDs -static const plugin_guid MCAP_SRV_RELAY_FMT = {MCAP_SRV_RELAY_FMT_s}; -static const plugin_guid MCAP_REVERSE_DC_REQ = {MCAP_REVERSE_DC_REQ_s}; -static const plugin_guid MCAP_FILE_TRANSFER = {MCAP_FILE_TRANSFER_s}; -static const plugin_guid MCAP_CONTACTS = {MCAP_CONTACTS_s}; - -// Plugin GUIDs -static const plugin_guid PSIG_MESSAGE = {PSIG_MESSAGE_s}; -static const plugin_guid PSIG_INFO_PLUGIN = {PSIG_INFO_PLUGIN_s}; -static const plugin_guid PSIG_STATUS_PLUGIN = {PSIG_STATUS_PLUGIN_s}; - -// Plugin Message GUIDs -static const plugin_guid PMSG_QUERY_INFO = {PMSG_QUERY_INFO_s}; -static const plugin_guid PMSG_QUERY_STATUS = {PMSG_QUERY_STATUS_s}; - -// Message GUIDs -static const plugin_guid MGTYPE_MESSAGE = {MGTYPE_MESSAGE_s}; -static const plugin_guid MGTYPE_STATUSMSGEXT = {MGTYPE_STATUSMSGEXT_s}; -static const plugin_guid MGTYPE_FILE = {MGTYPE_FILE_s}; -static const plugin_guid MGTYPE_WEBURL = {MGTYPE_WEBURL_s}; -static const plugin_guid MGTYPE_CONTACTS = {MGTYPE_CONTACTS_s}; -static const plugin_guid MGTYPE_GREETING_CARD = {MGTYPE_GREETING_CARD_s}; -static const plugin_guid MGTYPE_CHAT = {MGTYPE_CHAT_s}; -static const plugin_guid MGTYPE_SMS_MESSAGE = {MGTYPE_SMS_MESSAGE_s}; -static const plugin_guid MGTYPE_XTRAZ_SCRIPT = {MGTYPE_XTRAZ_SCRIPT_s}; - - -// make GUID checks easy -static BOOL CompareGUIDs(DWORD q1,DWORD q2,DWORD q3,DWORD q4, const plugin_guid guid) -{ - return ((q1 == guid[0]) && (q2 == guid[1]) && (q3 == guid[2]) && (q4 == guid[3]))?TRUE:FALSE; -} - - -// pack entire GUID into icq packet -static __inline void packGUID(icq_packet *packet, const plugin_guid guid) -{ - packDWord(packet, guid[0]); - packDWord(packet, guid[1]); - packDWord(packet, guid[2]); - packDWord(packet, guid[3]); -} - - -#endif /* __GUIDS_H */ diff --git a/protocols/IcqOscarJ/i18n.cpp b/protocols/IcqOscarJ/i18n.cpp deleted file mode 100644 index 535feebcdf..0000000000 --- a/protocols/IcqOscarJ/i18n.cpp +++ /dev/null @@ -1,541 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Contains helper functions to convert text messages between different -// character sets. -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static BOOL bHasCP_UTF8 = FALSE; - - -void InitI18N(void) -{ - CPINFO CPInfo; - - - bHasCP_UTF8 = GetCPInfo(CP_UTF8, &CPInfo); -} - - - -// Returns true if the buffer only contains 7-bit characters. -BOOL __stdcall IsUSASCII(const char *pBuffer, int nSize) -{ - for (int nIndex = 0; nIndex < nSize; nIndex++) - if (BYTE(pBuffer[nIndex]) > 0x7F) - return FALSE; - - return TRUE; -} - -// Returns true if the unicode buffer only contains 7-bit characters. -BOOL __stdcall IsUnicodeAscii(const WCHAR *pBuffer, int nSize) -{ - for (int nIndex = 0; nIndex < nSize; nIndex++) - if (WORD(pBuffer[nIndex]) > 0x7F) - return FALSE; - - return TRUE; -} - - -// Scans a string encoded in UTF-8 to verify that it contains -// only valid sequences. It will return 1 if the string contains -// only legitimate encoding sequences; otherwise it will return 0; -// From 'Secure Programming Cookbook', John Viega & Matt Messier, 2003 -int __stdcall UTF8_IsValid(const char *pszInput) -{ - int nb; - if (!pszInput) - return 0; - - for ( BYTE* c = ( BYTE*)pszInput; *c; c += (nb + 1)) - { - if (!(*c & 0x80)) - nb = 0; - else if ((*c & 0xc0) == 0x80) return 0; - else if ((*c & 0xe0) == 0xc0) nb = 1; - else if ((*c & 0xf0) == 0xe0) nb = 2; - else if ((*c & 0xf8) == 0xf0) nb = 3; - else if ((*c & 0xfc) == 0xf8) nb = 4; - else if ((*c & 0xfe) == 0xfc) nb = 5; - else nb = 0; - - for (int i = 1; i<=nb; i++) // we this forward, do not cross end of string - if ((*(c + i) & 0xc0) != 0x80) - return 0; - } - - return 1; -} - - -int __stdcall get_utf8_size(const WCHAR *unicode) -{ - int size = 0; - int index = 0; - /* calculate the size of the utf-8 string */ - WCHAR c = unicode[index++]; - while (c) - { - if (c < 0x0080) - size += 1; - else if (c < 0x0800) - size += 2; - else - size += 3; - c = unicode[index++]; - } - return size; -} - - -// returns ansi string in all cases -char* __stdcall detect_decode_utf8(const char *from) -{ - char *temp = NULL; - - if (IsUSASCII(from, strlennull(from)) || !UTF8_IsValid(from) || !utf8_decode(from, &temp)) return (char*)from; - SAFE_FREE((void**)&from); - - return temp; -} - - -/* -* The following UTF8 routines are -* -* Copyright (C) 2001 Peter Harris -* Copyright (C) 2001 Edmund Grimley Evans -* -* under a GPL license -* -* -------------------------------------------------------------- -* Convert a string between UTF-8 and the locale's charset. -* Invalid bytes are replaced by '#', and characters that are -* not available in the target encoding are replaced by '?'. -* -* If the locale's charset is not set explicitly then it is -* obtained using nl_langinfo(CODESET), where available, the -* environment variable CHARSET, or assumed to be US-ASCII. -* -* Return value of conversion functions: -* -* -1 : memory allocation failed -* 0 : data was converted exactly -* 1 : valid data was converted approximately (using '?') -* 2 : input was invalid (but still converted, using '#') -* 3 : unknown encoding (but still converted, using '?') -*/ - - - -/* -* Convert a string between UTF-8 and the locale's charset. -*/ -char* __stdcall make_utf8_string_static(const WCHAR *unicode, char *utf8, size_t utf_size) -{ - int index = 0; - unsigned int out_index = 0; - unsigned short c; - - c = unicode[index++]; - while (c) - { - if (c < 0x080) - { - if (out_index + 1 >= utf_size) break; - utf8[out_index++] = (unsigned char)c; - } - else if (c < 0x800) - { - if (out_index + 2 >= utf_size) break; - utf8[out_index++] = 0xc0 | (c >> 6); - utf8[out_index++] = 0x80 | (c & 0x3f); - } - else - { - if (out_index + 3 >= utf_size) break; - utf8[out_index++] = 0xe0 | (c >> 12); - utf8[out_index++] = 0x80 | ((c >> 6) & 0x3f); - utf8[out_index++] = 0x80 | (c & 0x3f); - } - c = unicode[index++]; - } - utf8[out_index] = 0x00; - - return utf8; -} - - -char* __stdcall make_utf8_string(const WCHAR *unicode) -{ - if (!unicode) return NULL; - - /* first calculate the size of the target string */ - size_t size = get_utf8_size(unicode); - - char *out = (char*)SAFE_MALLOC(size + 1); - if (!out) - return NULL; - - return make_utf8_string_static(unicode, out, size + 1); -} - - -WCHAR* __stdcall make_unicode_string_static(const char *utf8, WCHAR *unicode, size_t unicode_size) -{ - unsigned int out_index = 0; - - if (utf8) - { - unsigned int index = 0; - unsigned char c = utf8[index++]; - - while (c) - { - if (out_index + 1 >= unicode_size) break; - if ((c & 0x80) == 0) - { - unicode[out_index++] = c; - } - else if ((c & 0xe0) == 0xe0) - { - unicode[out_index] = (c & 0x1F) << 12; - c = utf8[index++]; - unicode[out_index] |= (c & 0x3F) << 6; - c = utf8[index++]; - unicode[out_index++] |= (c & 0x3F); - } - else - { - unicode[out_index] = (c & 0x3F) << 6; - c = utf8[index++]; - unicode[out_index++] |= (c & 0x3F); - } - c = utf8[index++]; - } - } - unicode[out_index] = 0; - - return unicode; -} - - -WCHAR* __stdcall make_unicode_string(const char *utf8) -{ - int size = 0, index = 0; - - if (!utf8) return NULL; - - /* first calculate the size of the target string */ - unsigned char c = utf8[index++]; - while (c) - { - if ((c & 0x80) == 0) - { - index += 0; - } - else if ((c & 0xe0) == 0xe0) - { - index += 2; - } - else - { - index += 1; - } - size += 1; - c = utf8[index++]; - } - - WCHAR *out = (WCHAR*)SAFE_MALLOC((size + 1) * sizeof(WCHAR)); - if (!out) - return NULL; - else - return make_unicode_string_static(utf8, out, size + 1); -} - - -int __stdcall utf8_encode(const char *from, char **to) -{ - int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlennull(from), NULL, 0); - - if (wchars == 0) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return -1; - } - - WCHAR *unicode = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); - ZeroMemory(unicode, (wchars + 1) * sizeof(WCHAR)); - - int err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlennull(from), unicode, wchars); - if (err != wchars) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return -1; - } - - /* On NT-based windows systems, we could use WideCharToMultiByte(), but - * MS doesn't actually have a consistent API across win32. - */ - *to = make_utf8_string(unicode); - return 0; -} - - -char* __stdcall ansi_to_utf8(const char *ansi) -{ - char *szUtf = NULL; - - if (strlennull(ansi)) - { - utf8_encode(ansi, &szUtf); - return szUtf; - } - - return null_strdup(""); -} - - -char* __stdcall ansi_to_utf8_codepage(const char *ansi, WORD wCp) -{ - int wchars = strlennull(ansi); - WCHAR *unicode = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); - ZeroMemory(unicode, (wchars + 1) * sizeof(WCHAR)); - - MultiByteToWideChar(wCp, MB_PRECOMPOSED, ansi, wchars, unicode, wchars); - - return make_utf8_string(unicode); -} - - -// Returns 0 on error, 1 on success -int __stdcall utf8_decode_codepage(const char *from, char **to, WORD wCp) -{ - int nResult = 0; - - _ASSERTE(!(*to)); // You passed a non-zero pointer, make sure it doesnt point to unfreed memory - - // Validate the string - if (!UTF8_IsValid(from)) - return 0; - - // Use the native conversion routines when available - if (bHasCP_UTF8) - { - int inlen = strlennull(from) + 1; - WCHAR *wszTemp = (WCHAR *)_alloca(inlen * sizeof(WCHAR)); - ZeroMemory(wszTemp, inlen * sizeof(WCHAR)); - - // Convert the UTF-8 string to UCS - if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen)) - { - // Convert the UCS string to local ANSI codepage - *to = (char*)SAFE_MALLOC(inlen); - if (WideCharToMultiByte(wCp, 0, wszTemp, -1, *to, inlen, NULL, NULL)) - { - nResult = 1; - } - else - { - SAFE_FREE(to); - } - } - } - else - { - int chars = strlennull(from) + 1; - WCHAR *unicode = (WCHAR*)_alloca(chars * sizeof(WCHAR)); - make_unicode_string_static(from, unicode, chars); - - chars = WideCharToMultiByte(wCp, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); - - if (chars == 0) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return 0; - } - - *to = (char*)SAFE_MALLOC((chars + 1)*sizeof(char)); - if (*to == NULL) - { -#ifdef _DEBUG - fprintf(stderr, "Out of memory processing string to local charset\n"); -#endif - return 0; - } - - int err = WideCharToMultiByte(wCp, WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL); - if (err != chars) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - SAFE_FREE(to); - return 0; - } - - nResult = 1; - } - - return nResult; -} - - -// Standard version with current codepage -int __stdcall utf8_decode(const char *from, char **to) -{ - return utf8_decode_codepage(from, to, CP_ACP); -} - - -// Returns 0 on error, 1 on success -int __stdcall utf8_decode_static(const char *from, char *to, int to_size) -{ - int nResult = 0; - - _ASSERTE(to); // You passed a zero pointer - - // Validate the string - if (!UTF8_IsValid(from)) - return 0; - - // Clear target - ZeroMemory(to, to_size); - - // Use the native conversion routines when available - if (bHasCP_UTF8) - { - int inlen = strlennull(from) + 1; - WCHAR *wszTemp = (WCHAR*)_alloca(inlen * sizeof(WCHAR)); - ZeroMemory(wszTemp, inlen * sizeof(WCHAR)); - - // Convert the UTF-8 string to UCS - if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen)) - { - // Convert the UCS string to local ANSI codepage - if (WideCharToMultiByte(CP_ACP, 0, wszTemp, -1, to, to_size, NULL, NULL)) - { - nResult = 1; - } - } - } - else - { - size_t chars = strlennull(from) + 1; - WCHAR *unicode = (WCHAR*)_alloca(chars * sizeof(WCHAR)); - - make_unicode_string_static(from, unicode, chars); - - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, to, to_size, NULL, NULL); - - nResult = 1; - } - - return nResult; -} - - -WCHAR* __stdcall ansi_to_unicode(const char *ansi) -{ - int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ansi, strlennull(ansi), NULL, 0); - - if (wchars == 0) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return NULL; - } - - WCHAR *unicode = (WCHAR*)SAFE_MALLOC((wchars + 1) * sizeof(WCHAR)); - - int err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ansi, strlennull(ansi), unicode, wchars); - if (err != wchars) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - SAFE_FREE(&unicode); - return NULL; - } - return unicode; -} - - -char* __stdcall unicode_to_ansi_static(const WCHAR *unicode, char *ansi, int ansi_size) -{ - ZeroMemory(ansi, ansi_size); - - if (WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), ansi, ansi_size, NULL, NULL) > 1) - return ansi; - - return NULL; -} - - -char* __stdcall unicode_to_ansi(const WCHAR *unicode) -{ - int chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), NULL, 0, NULL, NULL); - - if (chars == 0) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return NULL; - } - - char* ansi = (char*)SAFE_MALLOC((chars + 1)*sizeof(char)); - if (ansi == NULL) - { -#ifdef _DEBUG - fprintf(stderr, "Out of memory processing string to local charset\n"); -#endif - return NULL; - } - - int err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), ansi, chars, NULL, NULL); - if (err != chars) - { -#ifdef _DEBUG - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); -#endif - return NULL; - } - - return ansi; -} diff --git a/protocols/IcqOscarJ/i18n.h b/protocols/IcqOscarJ/i18n.h deleted file mode 100644 index eaeaad54f3..0000000000 --- a/protocols/IcqOscarJ/i18n.h +++ /dev/null @@ -1,70 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Helper functions to convert text messages between different character sets. -// -// ----------------------------------------------------------------------------- - -#ifndef __I18N_H -#define __I18N_H - - -BOOL __stdcall IsUSASCII(const char *pBuffer, int nSize); -BOOL __stdcall IsUnicodeAscii(const WCHAR *pBuffer, int nSize); -int __stdcall UTF8_IsValid(const char *pszInput); - -int __stdcall get_utf8_size(const WCHAR *unicode); - -char* __stdcall detect_decode_utf8(const char *from); - -WCHAR* __stdcall make_unicode_string(const char *utf8); -WCHAR* __stdcall make_unicode_string_static(const char *utf8, WCHAR *unicode, size_t unicode_size); - -char* __stdcall make_utf8_string(const WCHAR *unicode); -char* __stdcall make_utf8_string_static(const WCHAR *unicode, char *utf8, size_t utf_size); - -char* __stdcall ansi_to_utf8(const char *ansi); -char* __stdcall ansi_to_utf8_codepage(const char *ansi, WORD wCp); - -WCHAR* __stdcall ansi_to_unicode(const char *ansi); -char* __stdcall unicode_to_ansi(const WCHAR *unicode); -char* __stdcall unicode_to_ansi_static(const WCHAR *unicode, char *ansi, int ansi_size); - -int __stdcall utf8_encode(const char *from, char **to); -int __stdcall utf8_decode(const char *from, char **to); -int __stdcall utf8_decode_codepage(const char *from, char **to, WORD wCp); -int __stdcall utf8_decode_static(const char *from, char *to, int to_size); - -#define tchar_to_utf8 make_utf8_string -#define utf8_to_tchar_static make_unicode_string_static -#define utf8_to_tchar make_unicode_string -#define ansi_to_tchar ansi_to_unicode -#define tchar_to_ansi unicode_to_ansi - -void InitI18N(void); - - -#endif /* __I18N_H */ diff --git a/protocols/IcqOscarJ/iconlib.cpp b/protocols/IcqOscarJ/iconlib.cpp deleted file mode 100644 index 7c93bae17a..0000000000 --- a/protocols/IcqOscarJ/iconlib.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Support for IcoLib plug-in -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" -#include "m_icolib.h" - -IcqIconHandle IconLibDefine(const char *desc, const char *section, const char *module, const char *ident, const TCHAR *def_file, int def_idx) -{ - SKINICONDESC sid = {0}; - sid.cbSize = sizeof(sid); - sid.pwszSection = make_unicode_string(section); - sid.pwszDescription = make_unicode_string(desc); - sid.flags = SIDF_ALL_TCHAR; - - char szName[MAX_PATH + 128]; - null_snprintf(szName, sizeof(szName), "%s_%s", module ? module : ICQ_PROTOCOL_NAME, ident); - sid.pszName = szName; - sid.ptszDefaultFile = (TCHAR*)def_file; - sid.iDefaultIndex = def_idx; - - IcqIconHandle hIcon = (IcqIconHandle)SAFE_MALLOC(sizeof(IcqIconHandle_s)); - hIcon->szName = null_strdup(sid.pszName); - hIcon->hIcoLib = Skin_AddIcon(&sid); - - SAFE_FREE(&sid.pwszSection); - SAFE_FREE(&sid.pwszDescription); - - return hIcon; -} - - -void IconLibRemove(IcqIconHandle *phIcon) -{ - if (phIcon && *phIcon) - { - IcqIconHandle hIcon = *phIcon; - - CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)hIcon->szName); - SAFE_FREE(&hIcon->szName); - SAFE_FREE((void**)phIcon); - } -} - - -HANDLE IcqIconHandle_s::Handle() -{ - if (this) - return hIcoLib; - - return NULL; -} - - -HICON IcqIconHandle_s::GetIcon(bool big) -{ - if (this) - return (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)hIcoLib); - - return NULL; -} - -void IcqIconHandle_s::ReleaseIcon(bool big) -{ - CallService(big ? MS_SKIN2_RELEASEICONBIG : MS_SKIN2_RELEASEICON, 0, (LPARAM)szName); -} - diff --git a/protocols/IcqOscarJ/iconlib.h b/protocols/IcqOscarJ/iconlib.h deleted file mode 100644 index 3a7482f872..0000000000 --- a/protocols/IcqOscarJ/iconlib.h +++ /dev/null @@ -1,52 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Headers for IconLib Plugin / module support -// -// ----------------------------------------------------------------------------- -#ifndef __ICONLIB_H -#define __ICONLIB_H - - -struct IcqIconHandle_s -{ - char *szName; - HANDLE hIcoLib; - - HANDLE Handle(); - HICON GetIcon(bool big = false); - void ReleaseIcon(bool big = false); -}; - -typedef IcqIconHandle_s *IcqIconHandle; - - -IcqIconHandle IconLibDefine(const char *desc, const char *section, const char *module, const char *ident, const TCHAR *def_file, int def_idx); -void IconLibRemove(IcqIconHandle *phIcon); - - - -#endif /* __ICONLIB_H */ diff --git a/protocols/IcqOscarJ/icons_pack/ICONS.rc b/protocols/IcqOscarJ/icons_pack/ICONS.rc deleted file mode 100644 index b0c7ea1b05..0000000000 --- a/protocols/IcqOscarJ/icons_pack/ICONS.rc +++ /dev/null @@ -1,132 +0,0 @@ -//Microsoft Developer Studio generated resource script. -// -#include "../resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_XSTATUS1 ICON DISCARDABLE "../icos/xstatus01.ico" -IDI_XSTATUS2 ICON DISCARDABLE "../icos/xstatus02.ico" -IDI_XSTATUS3 ICON DISCARDABLE "../icos/xstatus03.ico" -IDI_XSTATUS4 ICON DISCARDABLE "../icos/xstatus04.ico" -IDI_XSTATUS5 ICON DISCARDABLE "../icos/xstatus05.ico" -IDI_XSTATUS6 ICON DISCARDABLE "../icos/xstatus06.ico" -IDI_XSTATUS7 ICON DISCARDABLE "../icos/xstatus07.ico" -IDI_XSTATUS8 ICON DISCARDABLE "../icos/xstatus08.ico" -IDI_XSTATUS9 ICON DISCARDABLE "../icos/xstatus09.ico" -IDI_XSTATUS10 ICON DISCARDABLE "../icos/xstatus10.ico" -IDI_XSTATUS11 ICON DISCARDABLE "../icos/xstatus11.ico" -IDI_XSTATUS12 ICON DISCARDABLE "../icos/xstatus12.ico" -IDI_XSTATUS13 ICON DISCARDABLE "../icos/xstatus13.ico" -IDI_XSTATUS14 ICON DISCARDABLE "../icos/xstatus14.ico" -IDI_XSTATUS15 ICON DISCARDABLE "../icos/xstatus15.ico" -IDI_XSTATUS16 ICON DISCARDABLE "../icos/xstatus16.ico" -IDI_XSTATUS17 ICON DISCARDABLE "../icos/xstatus17.ico" -IDI_XSTATUS18 ICON DISCARDABLE "../icos/xstatus18.ico" -IDI_XSTATUS19 ICON DISCARDABLE "../icos/xstatus19.ico" -IDI_XSTATUS20 ICON DISCARDABLE "../icos/xstatus20.ico" -IDI_XSTATUS21 ICON DISCARDABLE "../icos/xstatus21.ico" -IDI_XSTATUS22 ICON DISCARDABLE "../icos/xstatus22.ico" -IDI_XSTATUS23 ICON DISCARDABLE "../icos/xstatus23.ico" -IDI_XSTATUS24 ICON DISCARDABLE "../icos/xstatus24.ico" -IDI_XSTATUS25 ICON DISCARDABLE "../icos/xstatus25.ico" -IDI_XSTATUS26 ICON DISCARDABLE "../icos/xstatus26.ico" -IDI_XSTATUS27 ICON DISCARDABLE "../icos/xstatus27.ico" -IDI_XSTATUS28 ICON DISCARDABLE "../icos/xstatus28.ico" -IDI_XSTATUS29 ICON DISCARDABLE "../icos/xstatus29.ico" -IDI_XSTATUS30 ICON DISCARDABLE "../icos/xstatus30.ico" -IDI_XSTATUS31 ICON DISCARDABLE "../icos/xstatus31.ico" -IDI_XSTATUS32 ICON DISCARDABLE "../icos/xstatus32.ico" -IDI_XSTATUS33 ICON DISCARDABLE "../icos/xstatus33.ico" -IDI_XSTATUS34 ICON DISCARDABLE "../icos/xstatus34.ico" -IDI_XSTATUS35 ICON DISCARDABLE "../icos/xstatus35.ico" -IDI_XSTATUS36 ICON DISCARDABLE "../icos/xstatus36.ico" -IDI_XSTATUS37 ICON DISCARDABLE "../icos/xstatus37.ico" -IDI_XSTATUS38 ICON DISCARDABLE "../icos/xstatus38.ico" -IDI_XSTATUS39 ICON DISCARDABLE "../icos/xstatus39.ico" -IDI_XSTATUS40 ICON DISCARDABLE "../icos/xstatus40.ico" -IDI_XSTATUS41 ICON DISCARDABLE "../icos/xstatus41.ico" -IDI_XSTATUS42 ICON DISCARDABLE "../icos/xstatus42.ico" -IDI_XSTATUS43 ICON DISCARDABLE "../icos/xstatus43.ico" -IDI_XSTATUS44 ICON DISCARDABLE "../icos/xstatus44.ico" -IDI_XSTATUS45 ICON DISCARDABLE "../icos/xstatus45.ico" -IDI_XSTATUS46 ICON DISCARDABLE "../icos/xstatus46.ico" -IDI_XSTATUS47 ICON DISCARDABLE "../icos/xstatus47.ico" -IDI_XSTATUS48 ICON DISCARDABLE "../icos/xstatus48.ico" -IDI_XSTATUS49 ICON DISCARDABLE "../icos/xstatus49.ico" -IDI_XSTATUS50 ICON DISCARDABLE "../icos/xstatus50.ico" -IDI_XSTATUS51 ICON DISCARDABLE "../icos/xstatus51.ico" -IDI_XSTATUS52 ICON DISCARDABLE "../icos/xstatus52.ico" -IDI_XSTATUS53 ICON DISCARDABLE "../icos/xstatus53.ico" -IDI_XSTATUS54 ICON DISCARDABLE "../icos/xstatus54.ico" -IDI_XSTATUS55 ICON DISCARDABLE "../icos/xstatus55.ico" -IDI_XSTATUS56 ICON DISCARDABLE "../icos/xstatus56.ico" -IDI_XSTATUS57 ICON DISCARDABLE "../icos/xstatus57.ico" -IDI_XSTATUS58 ICON DISCARDABLE "../icos/xstatus58.ico" -IDI_XSTATUS59 ICON DISCARDABLE "../icos/xstatus59.ico" -IDI_XSTATUS60 ICON DISCARDABLE "../icos/xstatus60.ico" -IDI_XSTATUS61 ICON DISCARDABLE "../icos/xstatus61.ico" -IDI_XSTATUS62 ICON DISCARDABLE "../icos/xstatus62.ico" -IDI_XSTATUS63 ICON DISCARDABLE "../icos/xstatus63.ico" -IDI_XSTATUS64 ICON DISCARDABLE "../icos/xstatus64.ico" -IDI_XSTATUS65 ICON DISCARDABLE "../icos/xstatus65.ico" -IDI_XSTATUS66 ICON DISCARDABLE "../icos/xstatus66.ico" -IDI_XSTATUS67 ICON DISCARDABLE "../icos/xstatus67.ico" -IDI_XSTATUS68 ICON DISCARDABLE "../icos/xstatus68.ico" -IDI_XSTATUS69 ICON DISCARDABLE "../icos/xstatus69.ico" -IDI_XSTATUS70 ICON DISCARDABLE "../icos/xstatus70.ico" -IDI_XSTATUS71 ICON DISCARDABLE "../icos/xstatus71.ico" -IDI_XSTATUS72 ICON DISCARDABLE "../icos/xstatus72.ico" -IDI_XSTATUS73 ICON DISCARDABLE "../icos/xstatus73.ico" -IDI_XSTATUS74 ICON DISCARDABLE "../icos/xstatus74.ico" -IDI_XSTATUS75 ICON DISCARDABLE "../icos/xstatus75.ico" -IDI_XSTATUS76 ICON DISCARDABLE "../icos/xstatus76.ico" -IDI_XSTATUS77 ICON DISCARDABLE "../icos/xstatus77.ico" -IDI_XSTATUS78 ICON DISCARDABLE "../icos/xstatus78.ico" -IDI_XSTATUS79 ICON DISCARDABLE "../icos/xstatus79.ico" -IDI_XSTATUS80 ICON DISCARDABLE "../icos/xstatus80.ico" -IDI_XSTATUS81 ICON DISCARDABLE "../icos/xstatus81.ico" -IDI_XSTATUS82 ICON DISCARDABLE "../icos/xstatus82.ico" -IDI_XSTATUS83 ICON DISCARDABLE "../icos/xstatus83.ico" -IDI_XSTATUS84 ICON DISCARDABLE "../icos/xstatus84.ico" -IDI_XSTATUS85 ICON DISCARDABLE "../icos/xstatus85.ico" -IDI_XSTATUS86 ICON DISCARDABLE "../icos/xstatus86.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_IDENTIFY "# Custom Status Icons #" -END - - - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - diff --git a/protocols/IcqOscarJ/icons_pack/ICONS.vcxproj b/protocols/IcqOscarJ/icons_pack/ICONS.vcxproj index 8200455671..a4ef138a57 100644 --- a/protocols/IcqOscarJ/icons_pack/ICONS.vcxproj +++ b/protocols/IcqOscarJ/icons_pack/ICONS.vcxproj @@ -122,7 +122,10 @@ - + + + + diff --git a/protocols/IcqOscarJ/icons_pack/res/ICONS.rc b/protocols/IcqOscarJ/icons_pack/res/ICONS.rc new file mode 100644 index 0000000000..3c6fbe73e6 --- /dev/null +++ b/protocols/IcqOscarJ/icons_pack/res/ICONS.rc @@ -0,0 +1,132 @@ +//Microsoft Developer Studio generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_XSTATUS1 ICON "xstatus01.ico" +IDI_XSTATUS2 ICON "xstatus02.ico" +IDI_XSTATUS3 ICON "xstatus03.ico" +IDI_XSTATUS4 ICON "xstatus04.ico" +IDI_XSTATUS5 ICON "xstatus05.ico" +IDI_XSTATUS6 ICON "xstatus06.ico" +IDI_XSTATUS7 ICON "xstatus07.ico" +IDI_XSTATUS8 ICON "xstatus08.ico" +IDI_XSTATUS9 ICON "xstatus09.ico" +IDI_XSTATUS10 ICON "xstatus10.ico" +IDI_XSTATUS11 ICON "xstatus11.ico" +IDI_XSTATUS12 ICON "xstatus12.ico" +IDI_XSTATUS13 ICON "xstatus13.ico" +IDI_XSTATUS14 ICON "xstatus14.ico" +IDI_XSTATUS15 ICON "xstatus15.ico" +IDI_XSTATUS16 ICON "xstatus16.ico" +IDI_XSTATUS17 ICON "xstatus17.ico" +IDI_XSTATUS18 ICON "xstatus18.ico" +IDI_XSTATUS19 ICON "xstatus19.ico" +IDI_XSTATUS20 ICON "xstatus20.ico" +IDI_XSTATUS21 ICON "xstatus21.ico" +IDI_XSTATUS22 ICON "xstatus22.ico" +IDI_XSTATUS23 ICON "xstatus23.ico" +IDI_XSTATUS24 ICON "xstatus24.ico" +IDI_XSTATUS25 ICON "xstatus25.ico" +IDI_XSTATUS26 ICON "xstatus26.ico" +IDI_XSTATUS27 ICON "xstatus27.ico" +IDI_XSTATUS28 ICON "xstatus28.ico" +IDI_XSTATUS29 ICON "xstatus29.ico" +IDI_XSTATUS30 ICON "xstatus30.ico" +IDI_XSTATUS31 ICON "xstatus31.ico" +IDI_XSTATUS32 ICON "xstatus32.ico" +IDI_XSTATUS33 ICON "xstatus33.ico" +IDI_XSTATUS34 ICON "xstatus34.ico" +IDI_XSTATUS35 ICON "xstatus35.ico" +IDI_XSTATUS36 ICON "xstatus36.ico" +IDI_XSTATUS37 ICON "xstatus37.ico" +IDI_XSTATUS38 ICON "xstatus38.ico" +IDI_XSTATUS39 ICON "xstatus39.ico" +IDI_XSTATUS40 ICON "xstatus40.ico" +IDI_XSTATUS41 ICON "xstatus41.ico" +IDI_XSTATUS42 ICON "xstatus42.ico" +IDI_XSTATUS43 ICON "xstatus43.ico" +IDI_XSTATUS44 ICON "xstatus44.ico" +IDI_XSTATUS45 ICON "xstatus45.ico" +IDI_XSTATUS46 ICON "xstatus46.ico" +IDI_XSTATUS47 ICON "xstatus47.ico" +IDI_XSTATUS48 ICON "xstatus48.ico" +IDI_XSTATUS49 ICON "xstatus49.ico" +IDI_XSTATUS50 ICON "xstatus50.ico" +IDI_XSTATUS51 ICON "xstatus51.ico" +IDI_XSTATUS52 ICON "xstatus52.ico" +IDI_XSTATUS53 ICON "xstatus53.ico" +IDI_XSTATUS54 ICON "xstatus54.ico" +IDI_XSTATUS55 ICON "xstatus55.ico" +IDI_XSTATUS56 ICON "xstatus56.ico" +IDI_XSTATUS57 ICON "xstatus57.ico" +IDI_XSTATUS58 ICON "xstatus58.ico" +IDI_XSTATUS59 ICON "xstatus59.ico" +IDI_XSTATUS60 ICON "xstatus60.ico" +IDI_XSTATUS61 ICON "xstatus61.ico" +IDI_XSTATUS62 ICON "xstatus62.ico" +IDI_XSTATUS63 ICON "xstatus63.ico" +IDI_XSTATUS64 ICON "xstatus64.ico" +IDI_XSTATUS65 ICON "xstatus65.ico" +IDI_XSTATUS66 ICON "xstatus66.ico" +IDI_XSTATUS67 ICON "xstatus67.ico" +IDI_XSTATUS68 ICON "xstatus68.ico" +IDI_XSTATUS69 ICON "xstatus69.ico" +IDI_XSTATUS70 ICON "xstatus70.ico" +IDI_XSTATUS71 ICON "xstatus71.ico" +IDI_XSTATUS72 ICON "xstatus72.ico" +IDI_XSTATUS73 ICON "xstatus73.ico" +IDI_XSTATUS74 ICON "xstatus74.ico" +IDI_XSTATUS75 ICON "xstatus75.ico" +IDI_XSTATUS76 ICON "xstatus76.ico" +IDI_XSTATUS77 ICON "xstatus77.ico" +IDI_XSTATUS78 ICON "xstatus78.ico" +IDI_XSTATUS79 ICON "xstatus79.ico" +IDI_XSTATUS80 ICON "xstatus80.ico" +IDI_XSTATUS81 ICON "xstatus81.ico" +IDI_XSTATUS82 ICON "xstatus82.ico" +IDI_XSTATUS83 ICON "xstatus83.ico" +IDI_XSTATUS84 ICON "xstatus84.ico" +IDI_XSTATUS85 ICON "xstatus85.ico" +IDI_XSTATUS86 ICON "xstatus86.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_IDENTIFY "# Custom Status Icons #" +END + + + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus34.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus34.ico new file mode 100644 index 0000000000..38114d9acf Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus34.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus35.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus35.ico new file mode 100644 index 0000000000..c5c30aaeb7 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus35.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus36.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus36.ico new file mode 100644 index 0000000000..dee0c22ca5 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus36.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus38.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus38.ico new file mode 100644 index 0000000000..afadf91c75 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus38.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus39.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus39.ico new file mode 100644 index 0000000000..b54a71dfe4 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus39.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus40.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus40.ico new file mode 100644 index 0000000000..ea17ad64eb Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus40.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus41.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus41.ico new file mode 100644 index 0000000000..59782c42e0 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus41.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus42.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus42.ico new file mode 100644 index 0000000000..bb73d54be7 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus42.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus45.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus45.ico new file mode 100644 index 0000000000..dbbd46b51b Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus45.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus46.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus46.ico new file mode 100644 index 0000000000..377b5b7a1b Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus46.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus47.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus47.ico new file mode 100644 index 0000000000..f2333035af Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus47.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus48.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus48.ico new file mode 100644 index 0000000000..af9bc70b11 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus48.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus49.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus49.ico new file mode 100644 index 0000000000..274eb57cc2 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus49.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus50.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus50.ico new file mode 100644 index 0000000000..f86143e326 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus50.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus51.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus51.ico new file mode 100644 index 0000000000..a0cd9fb014 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus51.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus52.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus52.ico new file mode 100644 index 0000000000..47addb388a Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus52.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus53.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus53.ico new file mode 100644 index 0000000000..d3ef8d1154 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus53.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus54.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus54.ico new file mode 100644 index 0000000000..8cfb718724 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus54.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus56.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus56.ico new file mode 100644 index 0000000000..60dbf31dc6 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus56.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus57.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus57.ico new file mode 100644 index 0000000000..cf58a2c4f9 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus57.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus58.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus58.ico new file mode 100644 index 0000000000..e421d43285 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus58.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus59.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus59.ico new file mode 100644 index 0000000000..9ebab2cb61 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus59.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus60.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus60.ico new file mode 100644 index 0000000000..44c7c56542 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus60.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus61.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus61.ico new file mode 100644 index 0000000000..70751da56c Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus61.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus62.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus62.ico new file mode 100644 index 0000000000..1024cd9af3 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus62.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus63.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus63.ico new file mode 100644 index 0000000000..ae1e0c8c87 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus63.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus65.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus65.ico new file mode 100644 index 0000000000..784978cc7b Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus65.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus66.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus66.ico new file mode 100644 index 0000000000..46174f0280 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus66.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus67.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus67.ico new file mode 100644 index 0000000000..52cd285f23 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus67.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus68.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus68.ico new file mode 100644 index 0000000000..72e77bbe24 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus68.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus69.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus69.ico new file mode 100644 index 0000000000..f4c396f5e3 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus69.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus70.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus70.ico new file mode 100644 index 0000000000..9c422ad470 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus70.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus71.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus71.ico new file mode 100644 index 0000000000..4fc5b36117 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus71.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus72.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus72.ico new file mode 100644 index 0000000000..f759dca12d Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus72.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus73.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus73.ico new file mode 100644 index 0000000000..3a6edc17ce Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus73.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus74.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus74.ico new file mode 100644 index 0000000000..52683e7266 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus74.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus75.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus75.ico new file mode 100644 index 0000000000..2ff37ebed6 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus75.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus76.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus76.ico new file mode 100644 index 0000000000..b4b1304d0a Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus76.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus77.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus77.ico new file mode 100644 index 0000000000..4394522002 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus77.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus78.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus78.ico new file mode 100644 index 0000000000..e7681eaaa1 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus78.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus79.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus79.ico new file mode 100644 index 0000000000..22b8bde3f3 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus79.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus81.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus81.ico new file mode 100644 index 0000000000..658c06df23 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus81.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus82.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus82.ico new file mode 100644 index 0000000000..5a02cd4b0e Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus82.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus83.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus83.ico new file mode 100644 index 0000000000..df1b96b669 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus83.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus84.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus84.ico new file mode 100644 index 0000000000..59461759dc Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus84.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/Xstatus86.ico b/protocols/IcqOscarJ/icons_pack/res/Xstatus86.ico new file mode 100644 index 0000000000..6a1c484040 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/Xstatus86.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus01.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus01.ico new file mode 100644 index 0000000000..98e1a70a8c Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus01.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus02.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus02.ico new file mode 100644 index 0000000000..6153e0d4ab Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus02.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus03.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus03.ico new file mode 100644 index 0000000000..70796a2128 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus03.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus04.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus04.ico new file mode 100644 index 0000000000..0c86d1a6b3 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus04.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus05.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus05.ico new file mode 100644 index 0000000000..a7f0bfc99e Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus05.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus06.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus06.ico new file mode 100644 index 0000000000..7f565d4ac1 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus06.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus07.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus07.ico new file mode 100644 index 0000000000..46c7087662 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus07.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus08.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus08.ico new file mode 100644 index 0000000000..63c385f9da Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus08.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus09.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus09.ico new file mode 100644 index 0000000000..d7fdbd4bd5 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus09.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus10.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus10.ico new file mode 100644 index 0000000000..baf014ec1c Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus10.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus11.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus11.ico new file mode 100644 index 0000000000..2007ba936a Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus11.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus12.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus12.ico new file mode 100644 index 0000000000..b0daef70f4 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus12.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus13.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus13.ico new file mode 100644 index 0000000000..b0ae976442 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus13.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus14.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus14.ico new file mode 100644 index 0000000000..17cfd90007 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus14.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus15.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus15.ico new file mode 100644 index 0000000000..702ba16f2d Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus15.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus16.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus16.ico new file mode 100644 index 0000000000..853dc12fd2 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus16.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus17.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus17.ico new file mode 100644 index 0000000000..dd891cf169 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus17.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus18.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus18.ico new file mode 100644 index 0000000000..a95d361dcd Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus18.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus19.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus19.ico new file mode 100644 index 0000000000..8eb3821554 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus19.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus20.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus20.ico new file mode 100644 index 0000000000..0d90d8ba1c Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus20.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus21.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus21.ico new file mode 100644 index 0000000000..fa21d3a4e3 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus21.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus22.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus22.ico new file mode 100644 index 0000000000..ad8faded21 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus22.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus23.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus23.ico new file mode 100644 index 0000000000..f6b92255b6 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus23.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus24.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus24.ico new file mode 100644 index 0000000000..3ad736d73b Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus24.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus25.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus25.ico new file mode 100644 index 0000000000..1c0214cd1a Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus25.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus26.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus26.ico new file mode 100644 index 0000000000..b085157f52 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus26.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus27.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus27.ico new file mode 100644 index 0000000000..c3fb1e6678 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus27.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus28.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus28.ico new file mode 100644 index 0000000000..e3cc32037e Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus28.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus29.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus29.ico new file mode 100644 index 0000000000..3217396cbe Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus29.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus30.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus30.ico new file mode 100644 index 0000000000..db97d2d4ea Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus30.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus31.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus31.ico new file mode 100644 index 0000000000..1176383b5b Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus31.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus32.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus32.ico new file mode 100644 index 0000000000..c68ca5bd2a Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus32.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus33.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus33.ico new file mode 100644 index 0000000000..ed8632d5eb Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus33.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus37.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus37.ico new file mode 100644 index 0000000000..4bb33ec9ac Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus37.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus43.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus43.ico new file mode 100644 index 0000000000..6f49a31dc4 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus43.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus44.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus44.ico new file mode 100644 index 0000000000..4644afa89f Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus44.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus55.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus55.ico new file mode 100644 index 0000000000..7ad6286985 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus55.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus64.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus64.ico new file mode 100644 index 0000000000..1144ba9b49 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus64.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus80.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus80.ico new file mode 100644 index 0000000000..30f7dd2670 Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus80.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/res/xstatus85.ico b/protocols/IcqOscarJ/icons_pack/res/xstatus85.ico new file mode 100644 index 0000000000..b9db7058ba Binary files /dev/null and b/protocols/IcqOscarJ/icons_pack/res/xstatus85.ico differ diff --git a/protocols/IcqOscarJ/icons_pack/src/resource.h b/protocols/IcqOscarJ/icons_pack/src/resource.h new file mode 100644 index 0000000000..119ed41495 --- /dev/null +++ b/protocols/IcqOscarJ/icons_pack/src/resource.h @@ -0,0 +1,101 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resources.rc +// +#define IDI_XSTATUS1 201 +#define IDI_XSTATUS2 202 +#define IDI_XSTATUS3 203 +#define IDI_XSTATUS4 204 +#define IDI_XSTATUS5 205 +#define IDI_XSTATUS6 206 +#define IDI_XSTATUS7 207 +#define IDI_XSTATUS8 208 +#define IDI_XSTATUS9 209 +#define IDI_XSTATUS10 210 +#define IDI_XSTATUS11 211 +#define IDI_XSTATUS12 212 +#define IDI_XSTATUS13 213 +#define IDI_XSTATUS14 214 +#define IDI_XSTATUS15 215 +#define IDI_XSTATUS16 216 +#define IDI_XSTATUS17 217 +#define IDI_XSTATUS18 218 +#define IDI_XSTATUS19 219 +#define IDI_XSTATUS20 220 +#define IDI_XSTATUS21 221 +#define IDI_XSTATUS22 222 +#define IDI_XSTATUS23 223 +#define IDI_XSTATUS24 224 +#define IDI_XSTATUS25 225 +#define IDI_XSTATUS26 226 +#define IDI_XSTATUS27 227 +#define IDI_XSTATUS28 228 +#define IDI_XSTATUS29 229 +#define IDI_XSTATUS30 230 +#define IDI_XSTATUS31 231 +#define IDI_XSTATUS32 232 +#define IDI_XSTATUS33 233 +#define IDI_XSTATUS34 234 +#define IDI_XSTATUS35 235 +#define IDI_XSTATUS36 236 +#define IDI_XSTATUS37 237 +#define IDI_XSTATUS38 238 +#define IDI_XSTATUS39 239 +#define IDI_XSTATUS40 240 +#define IDI_XSTATUS41 241 +#define IDI_XSTATUS42 242 +#define IDI_XSTATUS43 243 +#define IDI_XSTATUS44 244 +#define IDI_XSTATUS45 245 +#define IDI_XSTATUS46 246 +#define IDI_XSTATUS47 247 +#define IDI_XSTATUS48 248 +#define IDI_XSTATUS49 249 +#define IDI_XSTATUS50 250 +#define IDI_XSTATUS51 251 +#define IDI_XSTATUS52 252 +#define IDI_XSTATUS53 253 +#define IDI_XSTATUS54 254 +#define IDI_XSTATUS55 255 +#define IDI_XSTATUS56 256 +#define IDI_XSTATUS57 257 +#define IDI_XSTATUS58 258 +#define IDI_XSTATUS59 259 +#define IDI_XSTATUS60 260 +#define IDI_XSTATUS61 261 +#define IDI_XSTATUS62 262 +#define IDI_XSTATUS63 263 +#define IDI_XSTATUS64 264 +#define IDI_XSTATUS65 265 +#define IDI_XSTATUS66 266 +#define IDI_XSTATUS67 267 +#define IDI_XSTATUS68 268 +#define IDI_XSTATUS69 269 +#define IDI_XSTATUS70 270 +#define IDI_XSTATUS71 271 +#define IDI_XSTATUS72 272 +#define IDI_XSTATUS73 273 +#define IDI_XSTATUS74 274 +#define IDI_XSTATUS75 275 +#define IDI_XSTATUS76 276 +#define IDI_XSTATUS77 277 +#define IDI_XSTATUS78 278 +#define IDI_XSTATUS79 279 +#define IDI_XSTATUS80 280 +#define IDI_XSTATUS81 281 +#define IDI_XSTATUS82 282 +#define IDI_XSTATUS83 283 +#define IDI_XSTATUS84 284 +#define IDI_XSTATUS85 285 +#define IDI_XSTATUS86 286 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1026 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/IcqOscarJ/icos/Xstatus34.ico b/protocols/IcqOscarJ/icos/Xstatus34.ico deleted file mode 100644 index 38114d9acf..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus34.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus35.ico b/protocols/IcqOscarJ/icos/Xstatus35.ico deleted file mode 100644 index c5c30aaeb7..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus35.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus36.ico b/protocols/IcqOscarJ/icos/Xstatus36.ico deleted file mode 100644 index dee0c22ca5..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus36.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus38.ico b/protocols/IcqOscarJ/icos/Xstatus38.ico deleted file mode 100644 index afadf91c75..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus38.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus39.ico b/protocols/IcqOscarJ/icos/Xstatus39.ico deleted file mode 100644 index b54a71dfe4..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus39.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus40.ico b/protocols/IcqOscarJ/icos/Xstatus40.ico deleted file mode 100644 index ea17ad64eb..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus40.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus41.ico b/protocols/IcqOscarJ/icos/Xstatus41.ico deleted file mode 100644 index 59782c42e0..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus41.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus42.ico b/protocols/IcqOscarJ/icos/Xstatus42.ico deleted file mode 100644 index bb73d54be7..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus42.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus45.ico b/protocols/IcqOscarJ/icos/Xstatus45.ico deleted file mode 100644 index dbbd46b51b..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus45.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus46.ico b/protocols/IcqOscarJ/icos/Xstatus46.ico deleted file mode 100644 index 377b5b7a1b..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus46.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus47.ico b/protocols/IcqOscarJ/icos/Xstatus47.ico deleted file mode 100644 index f2333035af..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus47.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus48.ico b/protocols/IcqOscarJ/icos/Xstatus48.ico deleted file mode 100644 index af9bc70b11..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus48.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus49.ico b/protocols/IcqOscarJ/icos/Xstatus49.ico deleted file mode 100644 index 274eb57cc2..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus49.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus50.ico b/protocols/IcqOscarJ/icos/Xstatus50.ico deleted file mode 100644 index f86143e326..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus50.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus51.ico b/protocols/IcqOscarJ/icos/Xstatus51.ico deleted file mode 100644 index a0cd9fb014..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus51.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus52.ico b/protocols/IcqOscarJ/icos/Xstatus52.ico deleted file mode 100644 index 47addb388a..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus52.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus53.ico b/protocols/IcqOscarJ/icos/Xstatus53.ico deleted file mode 100644 index d3ef8d1154..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus53.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus54.ico b/protocols/IcqOscarJ/icos/Xstatus54.ico deleted file mode 100644 index 8cfb718724..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus54.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus56.ico b/protocols/IcqOscarJ/icos/Xstatus56.ico deleted file mode 100644 index 60dbf31dc6..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus56.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus57.ico b/protocols/IcqOscarJ/icos/Xstatus57.ico deleted file mode 100644 index cf58a2c4f9..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus57.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus58.ico b/protocols/IcqOscarJ/icos/Xstatus58.ico deleted file mode 100644 index e421d43285..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus58.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus59.ico b/protocols/IcqOscarJ/icos/Xstatus59.ico deleted file mode 100644 index 9ebab2cb61..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus59.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus60.ico b/protocols/IcqOscarJ/icos/Xstatus60.ico deleted file mode 100644 index 44c7c56542..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus60.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus61.ico b/protocols/IcqOscarJ/icos/Xstatus61.ico deleted file mode 100644 index 70751da56c..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus61.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus62.ico b/protocols/IcqOscarJ/icos/Xstatus62.ico deleted file mode 100644 index 1024cd9af3..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus62.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus63.ico b/protocols/IcqOscarJ/icos/Xstatus63.ico deleted file mode 100644 index ae1e0c8c87..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus63.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus65.ico b/protocols/IcqOscarJ/icos/Xstatus65.ico deleted file mode 100644 index 784978cc7b..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus65.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus66.ico b/protocols/IcqOscarJ/icos/Xstatus66.ico deleted file mode 100644 index 46174f0280..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus66.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus67.ico b/protocols/IcqOscarJ/icos/Xstatus67.ico deleted file mode 100644 index 52cd285f23..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus67.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus68.ico b/protocols/IcqOscarJ/icos/Xstatus68.ico deleted file mode 100644 index 72e77bbe24..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus68.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus69.ico b/protocols/IcqOscarJ/icos/Xstatus69.ico deleted file mode 100644 index f4c396f5e3..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus69.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus70.ico b/protocols/IcqOscarJ/icos/Xstatus70.ico deleted file mode 100644 index 9c422ad470..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus70.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus71.ico b/protocols/IcqOscarJ/icos/Xstatus71.ico deleted file mode 100644 index 4fc5b36117..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus71.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus72.ico b/protocols/IcqOscarJ/icos/Xstatus72.ico deleted file mode 100644 index f759dca12d..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus72.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus73.ico b/protocols/IcqOscarJ/icos/Xstatus73.ico deleted file mode 100644 index 3a6edc17ce..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus73.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus74.ico b/protocols/IcqOscarJ/icos/Xstatus74.ico deleted file mode 100644 index 52683e7266..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus74.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus75.ico b/protocols/IcqOscarJ/icos/Xstatus75.ico deleted file mode 100644 index 2ff37ebed6..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus75.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus76.ico b/protocols/IcqOscarJ/icos/Xstatus76.ico deleted file mode 100644 index b4b1304d0a..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus76.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus77.ico b/protocols/IcqOscarJ/icos/Xstatus77.ico deleted file mode 100644 index 4394522002..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus77.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus78.ico b/protocols/IcqOscarJ/icos/Xstatus78.ico deleted file mode 100644 index e7681eaaa1..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus78.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus79.ico b/protocols/IcqOscarJ/icos/Xstatus79.ico deleted file mode 100644 index 22b8bde3f3..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus79.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus81.ico b/protocols/IcqOscarJ/icos/Xstatus81.ico deleted file mode 100644 index 658c06df23..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus81.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus82.ico b/protocols/IcqOscarJ/icos/Xstatus82.ico deleted file mode 100644 index 5a02cd4b0e..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus82.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus83.ico b/protocols/IcqOscarJ/icos/Xstatus83.ico deleted file mode 100644 index df1b96b669..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus83.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus84.ico b/protocols/IcqOscarJ/icos/Xstatus84.ico deleted file mode 100644 index 59461759dc..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus84.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/Xstatus86.ico b/protocols/IcqOscarJ/icos/Xstatus86.ico deleted file mode 100644 index 6a1c484040..0000000000 Binary files a/protocols/IcqOscarJ/icos/Xstatus86.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/auth_ask.ico b/protocols/IcqOscarJ/icos/auth_ask.ico deleted file mode 100644 index 1db6f7f23e..0000000000 Binary files a/protocols/IcqOscarJ/icos/auth_ask.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/auth_grant.ico b/protocols/IcqOscarJ/icos/auth_grant.ico deleted file mode 100644 index 44d5b29a31..0000000000 Binary files a/protocols/IcqOscarJ/icos/auth_grant.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/auth_revoke.ico b/protocols/IcqOscarJ/icos/auth_revoke.ico deleted file mode 100644 index e483681727..0000000000 Binary files a/protocols/IcqOscarJ/icos/auth_revoke.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/icq.ico b/protocols/IcqOscarJ/icos/icq.ico deleted file mode 100644 index 98a99aca1c..0000000000 Binary files a/protocols/IcqOscarJ/icos/icq.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/srvlist_add.ico b/protocols/IcqOscarJ/icos/srvlist_add.ico deleted file mode 100644 index 18b12f8c38..0000000000 Binary files a/protocols/IcqOscarJ/icos/srvlist_add.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus01.ico b/protocols/IcqOscarJ/icos/xstatus01.ico deleted file mode 100644 index 98e1a70a8c..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus01.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus02.ico b/protocols/IcqOscarJ/icos/xstatus02.ico deleted file mode 100644 index 6153e0d4ab..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus02.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus03.ico b/protocols/IcqOscarJ/icos/xstatus03.ico deleted file mode 100644 index 70796a2128..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus03.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus04.ico b/protocols/IcqOscarJ/icos/xstatus04.ico deleted file mode 100644 index 0c86d1a6b3..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus04.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus05.ico b/protocols/IcqOscarJ/icos/xstatus05.ico deleted file mode 100644 index a7f0bfc99e..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus05.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus06.ico b/protocols/IcqOscarJ/icos/xstatus06.ico deleted file mode 100644 index 7f565d4ac1..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus06.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus07.ico b/protocols/IcqOscarJ/icos/xstatus07.ico deleted file mode 100644 index 46c7087662..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus07.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus08.ico b/protocols/IcqOscarJ/icos/xstatus08.ico deleted file mode 100644 index 63c385f9da..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus08.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus09.ico b/protocols/IcqOscarJ/icos/xstatus09.ico deleted file mode 100644 index d7fdbd4bd5..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus09.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus10.ico b/protocols/IcqOscarJ/icos/xstatus10.ico deleted file mode 100644 index baf014ec1c..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus10.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus11.ico b/protocols/IcqOscarJ/icos/xstatus11.ico deleted file mode 100644 index 2007ba936a..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus11.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus12.ico b/protocols/IcqOscarJ/icos/xstatus12.ico deleted file mode 100644 index b0daef70f4..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus12.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus13.ico b/protocols/IcqOscarJ/icos/xstatus13.ico deleted file mode 100644 index b0ae976442..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus13.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus14.ico b/protocols/IcqOscarJ/icos/xstatus14.ico deleted file mode 100644 index 17cfd90007..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus14.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus15.ico b/protocols/IcqOscarJ/icos/xstatus15.ico deleted file mode 100644 index 702ba16f2d..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus15.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus16.ico b/protocols/IcqOscarJ/icos/xstatus16.ico deleted file mode 100644 index 853dc12fd2..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus16.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus17.ico b/protocols/IcqOscarJ/icos/xstatus17.ico deleted file mode 100644 index dd891cf169..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus17.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus18.ico b/protocols/IcqOscarJ/icos/xstatus18.ico deleted file mode 100644 index a95d361dcd..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus18.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus19.ico b/protocols/IcqOscarJ/icos/xstatus19.ico deleted file mode 100644 index 8eb3821554..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus19.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus20.ico b/protocols/IcqOscarJ/icos/xstatus20.ico deleted file mode 100644 index 0d90d8ba1c..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus20.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus21.ico b/protocols/IcqOscarJ/icos/xstatus21.ico deleted file mode 100644 index fa21d3a4e3..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus21.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus22.ico b/protocols/IcqOscarJ/icos/xstatus22.ico deleted file mode 100644 index ad8faded21..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus22.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus23.ico b/protocols/IcqOscarJ/icos/xstatus23.ico deleted file mode 100644 index f6b92255b6..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus23.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus24.ico b/protocols/IcqOscarJ/icos/xstatus24.ico deleted file mode 100644 index 3ad736d73b..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus24.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus25.ico b/protocols/IcqOscarJ/icos/xstatus25.ico deleted file mode 100644 index 1c0214cd1a..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus25.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus26.ico b/protocols/IcqOscarJ/icos/xstatus26.ico deleted file mode 100644 index b085157f52..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus26.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus27.ico b/protocols/IcqOscarJ/icos/xstatus27.ico deleted file mode 100644 index c3fb1e6678..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus27.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus28.ico b/protocols/IcqOscarJ/icos/xstatus28.ico deleted file mode 100644 index e3cc32037e..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus28.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus29.ico b/protocols/IcqOscarJ/icos/xstatus29.ico deleted file mode 100644 index 3217396cbe..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus29.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus30.ico b/protocols/IcqOscarJ/icos/xstatus30.ico deleted file mode 100644 index db97d2d4ea..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus30.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus31.ico b/protocols/IcqOscarJ/icos/xstatus31.ico deleted file mode 100644 index 1176383b5b..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus31.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus32.ico b/protocols/IcqOscarJ/icos/xstatus32.ico deleted file mode 100644 index c68ca5bd2a..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus32.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus33.ico b/protocols/IcqOscarJ/icos/xstatus33.ico deleted file mode 100644 index ed8632d5eb..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus33.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus37.ico b/protocols/IcqOscarJ/icos/xstatus37.ico deleted file mode 100644 index 4bb33ec9ac..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus37.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus43.ico b/protocols/IcqOscarJ/icos/xstatus43.ico deleted file mode 100644 index 6f49a31dc4..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus43.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus44.ico b/protocols/IcqOscarJ/icos/xstatus44.ico deleted file mode 100644 index 4644afa89f..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus44.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus55.ico b/protocols/IcqOscarJ/icos/xstatus55.ico deleted file mode 100644 index 7ad6286985..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus55.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus64.ico b/protocols/IcqOscarJ/icos/xstatus64.ico deleted file mode 100644 index 1144ba9b49..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus64.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus80.ico b/protocols/IcqOscarJ/icos/xstatus80.ico deleted file mode 100644 index 30f7dd2670..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus80.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icos/xstatus85.ico b/protocols/IcqOscarJ/icos/xstatus85.ico deleted file mode 100644 index b9db7058ba..0000000000 Binary files a/protocols/IcqOscarJ/icos/xstatus85.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/icq_advsearch.cpp b/protocols/IcqOscarJ/icq_advsearch.cpp deleted file mode 100644 index 6c3a3ffa89..0000000000 --- a/protocols/IcqOscarJ/icq_advsearch.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -static void InitComboBox(HWND hwndCombo, const FieldNamesItem *names) -{ - int iItem; - int i; - - iItem = ComboBoxAddStringUtf(hwndCombo, NULL, 0); - SendMessage(hwndCombo, CB_SETCURSEL, iItem, 0); - - if (names){ - for (i = 0; names[i].text; i++) { - iItem = ComboBoxAddStringUtf(hwndCombo, names[i].text, names[i].code); - } - } - else { - int ctryCount; - struct CountryListEntry *countries; - CallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM )&ctryCount, ( LPARAM )&countries ); - for (i = 0; i < ctryCount; i++) { - if (countries[i].id != 0xFFFF && countries[i].id != 0) - iItem = ComboBoxAddStringUtf(hwndCombo, LPGEN(countries[i].szName), countries[i].id); - } - } -} - -INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - InitComboBox(GetDlgItem(hwndDlg, IDC_GENDER), genderField); - InitComboBox(GetDlgItem(hwndDlg, IDC_AGERANGE), agesField); - InitComboBox(GetDlgItem(hwndDlg, IDC_MARITALSTATUS), maritalField); - InitComboBox(GetDlgItem(hwndDlg, IDC_WORKFIELD), occupationField); - InitComboBox(GetDlgItem(hwndDlg, IDC_ORGANISATION), affiliationField); - InitComboBox(GetDlgItem(hwndDlg, IDC_LANGUAGE), languageField); - InitComboBox(GetDlgItem(hwndDlg, IDC_COUNTRY), countryField); - InitComboBox(GetDlgItem(hwndDlg, IDC_INTERESTSCAT), interestsField); - InitComboBox(GetDlgItem(hwndDlg, IDC_PASTCAT), pastField); - - return TRUE; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - - case IDOK: - SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(GetParent(hwndDlg), IDOK)); - break; - - case IDCANCEL: - // CheckDlgButton(GetParent(hwndDlg),IDC_ADVANCED,BST_UNCHECKED); - // SendMessage(GetParent(hwndDlg),WM_COMMAND,MAKEWPARAM(IDC_ADVANCED,BN_CLICKED),(LPARAM)GetDlgItem(GetParent(hwndDlg),IDC_ADVANCED)); - break; - - default: - break; - - } - break; - } - - default: - break; - } - - return FALSE; -} - -static DWORD getCurItemData(HWND hwndDlg, UINT iCtrl) -{ - return SendDlgItemMessage(hwndDlg, iCtrl, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, iCtrl, CB_GETCURSEL, 0, 0), 0); -} - -static void searchPackTLVLNTS(PBYTE *buf, int *buflen, HWND hwndDlg, UINT idControl, WORD wType) -{ - char str[512]; - - GetDlgItemTextA(hwndDlg, idControl, str, sizeof(str)); - - ppackLETLVLNTS(buf, buflen, str, wType, 0); -} - -static void searchPackTLVWordLNTS(PBYTE *buf, int *buflen, HWND hwndDlg, UINT idControl, WORD w, WORD wType) -{ - char str[512]; - - GetDlgItemTextA(hwndDlg, idControl, str, sizeof(str)); - - ppackLETLVWordLNTS(buf, buflen, w, str, wType, 0); -} - -static PBYTE createAdvancedSearchStructureTLV(HWND hwndDlg, int *length) -{ - PBYTE buf = NULL; - int buflen = 0; - - ppackLEWord(&buf, &buflen, META_SEARCH_GENERIC); /* subtype: full search */ - - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_FIRSTNAME, TLV_FIRSTNAME); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_LASTNAME, TLV_LASTNAME); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_NICK, TLV_NICKNAME); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_EMAIL, TLV_EMAIL); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_CITY, TLV_CITY); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_STATE, TLV_STATE); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_COMPANY, TLV_COMPANY); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_DEPARTMENT, TLV_DEPARTMENT); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_POSITION, TLV_POSITION); - searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_KEYWORDS, TLV_KEYWORDS); - - ppackLETLVDWord(&buf, &buflen, (DWORD)getCurItemData(hwndDlg, IDC_AGERANGE), TLV_AGERANGE, 0); - - BYTE b = (BYTE)getCurItemData(hwndDlg, IDC_GENDER); - switch (b) { - case 'F': b = 1; break; - case 'M': b = 2; break; - default: b = 0; - }; - ppackLETLVByte(&buf, &buflen, b, TLV_GENDER, 0); - ppackLETLVByte(&buf, &buflen, (BYTE)getCurItemData(hwndDlg, IDC_MARITALSTATUS), TLV_MARITAL, 0); - ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_LANGUAGE), TLV_LANGUAGE, 0); - ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_COUNTRY), TLV_COUNTRY, 0); - ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_WORKFIELD), TLV_OCUPATION, 0); - - WORD w = (WORD)getCurItemData(hwndDlg, IDC_PASTCAT); - searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_PASTKEY, w, TLV_PASTINFO); - - w = (WORD)getCurItemData(hwndDlg, IDC_INTERESTSCAT); - searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_INTERESTSKEY, w, TLV_INTERESTS); - - w = (WORD)getCurItemData(hwndDlg, IDC_ORGANISATION); - searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_ORGKEYWORDS, w, TLV_AFFILATIONS); - - w = (WORD)getCurItemData(hwndDlg, IDC_HOMEPAGECAT); - if (w != 0xFFFF) - searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_HOMEPAGEKEY, w, TLV_HOMEPAGE); - - if (IsDlgButtonChecked(hwndDlg, IDC_ONLINEONLY)) - ppackLETLVByte(&buf, &buflen, 1, TLV_ONLINEONLY, 1); - - if (length) - *length = buflen; - - return buf; -} - -PBYTE createAdvancedSearchStructure(HWND hwndDlg, int *length) -{ - if (!hwndDlg) - return NULL; - - return createAdvancedSearchStructureTLV(hwndDlg, length); -} diff --git a/protocols/IcqOscarJ/icq_advsearch.h b/protocols/IcqOscarJ/icq_advsearch.h deleted file mode 100644 index 83bf35af93..0000000000 --- a/protocols/IcqOscarJ/icq_advsearch.h +++ /dev/null @@ -1,32 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- - - -INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam); -PBYTE createAdvancedSearchStructure(HWND hwndDlg,int *length); diff --git a/protocols/IcqOscarJ/icq_avatar.cpp b/protocols/IcqOscarJ/icq_avatar.cpp deleted file mode 100644 index 6e61f2bc0d..0000000000 --- a/protocols/IcqOscarJ/icq_avatar.cpp +++ /dev/null @@ -1,1814 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Manages Avatar connection, provides internal service for handling avatars -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" -#include "m_folders.h" - - -BYTE hashEmptyAvatar[9] = {0x00, 0x01, 0x00, 0x05, 0x02, 0x01, 0xD2, 0x04, 0x72}; - - -avatars_request::avatars_request(int type) -{ - this->type = type; -} - - -avatars_request::~avatars_request() -{ - if (this) - { - switch (type) - { - case ART_UPLOAD: - SAFE_FREE((void**)&pData); - break; - case ART_GET: - SAFE_FREE((void**)&hash); - SAFE_FREE(&szFile); - break; - case ART_BLOCK: - break; - } - } -} - - -avatars_request* CIcqProto::ReleaseAvatarRequestInQueue(avatars_request *request) -{ - avatars_request *pNext = request->pNext; - - avatars_request **par = &m_avatarsQueue; - avatars_request *ar = m_avatarsQueue; - - while (ar) - { - if (ar == request) - { // found it, remove - *par = ar->pNext; - break; - } - par = &ar->pNext; - ar = ar->pNext; - } - - delete request; - return pNext; -} - - -void CIcqProto::InitAvatars() -{ - if (!bAvatarsFolderInited) - { // do it only once - bAvatarsFolderInited = TRUE; - - if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) - { // check if it does make sense - TCHAR tszPath[MAX_PATH * 2]; - null_snprintf(tszPath, MAX_PATH * 2, _T("%%miranda_avatarcache%%\\") _T(TCHAR_STR_PARAM) _T("\\"), m_szModuleName); - - hAvatarsFolder = FoldersRegisterCustomPathT(m_szModuleName, "Avatars Cache", tszPath); - } - } -} - - -TCHAR* CIcqProto::GetOwnAvatarFileName() -{ - DBVARIANT dbvFile = {DBVT_DELETED}; - - if (!getSettingStringT(NULL, "AvatarFile", &dbvFile)) - { - TCHAR tmp[MAX_PATH * 2]; - CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)dbvFile.ptszVal, (LPARAM)tmp); - ICQFreeVariant(&dbvFile); - - return null_strdup(tmp); - } - return NULL; -} - - -void CIcqProto::GetFullAvatarFileName(int dwUin, const char *szUid, int dwFormat, TCHAR *pszDest, int cbLen) -{ - GetAvatarFileName(dwUin, szUid, pszDest, cbLen); - AddAvatarExt(dwFormat, pszDest); -} - - -void CIcqProto::GetAvatarFileName(int dwUin, const char *szUid, TCHAR *pszDest, int cbLen) -{ - TCHAR szPath[MAX_PATH * 2]; - FOLDERSGETDATA fgd = {0}; - - InitAvatars(); - - fgd.cbSize = sizeof(FOLDERSGETDATA); - fgd.nMaxPathSize = MAX_PATH * 2; - fgd.szPathT = szPath; - fgd.flags = FF_TCHAR; - if (CallService(MS_FOLDERS_GET_PATH, (WPARAM)hAvatarsFolder, (LPARAM)&fgd)) - { - TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_avatarcache%")); - null_snprintf(szPath, MAX_PATH * 2, _T("%s\\") _T(TCHAR_STR_PARAM) _T("\\"), tmpPath, m_szModuleName); - mir_free(tmpPath); - } - else - _tcscat(szPath, _T("\\")); - - // fill the destination - lstrcpyn(pszDest, szPath, cbLen - 1); - int tPathLen = strlennull(pszDest); - - // make sure the avatar cache directory exists - CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)szPath); - - if (dwUin != 0) - { - _ltot(dwUin, pszDest + tPathLen, 10); - } - else if (szUid) - { - TCHAR* p = mir_a2t(szUid); - _tcscpy(pszDest + tPathLen, p); - mir_free( p ); - } - else - { - TCHAR szBuf[MAX_PATH]; - - if (CallService(MS_DB_GETPROFILENAMET, MAX_PATH, (LPARAM)szBuf)) - _tcscpy(pszDest + tPathLen, _T("avatar")); - else - { - TCHAR *szLastDot = _tcsrchr(szBuf, '.'); - if (szLastDot) szLastDot[0] = '\0'; - - _tcscpy(pszDest + tPathLen, szBuf); - _tcscat(pszDest + tPathLen, _T("_avt")); - } - } -} - - -void AddAvatarExt(int dwFormat, TCHAR *pszDest) -{ - if (dwFormat == PA_FORMAT_JPEG) - _tcscat(pszDest, _T(".jpg")); - else if (dwFormat == PA_FORMAT_GIF) - _tcscat(pszDest, _T(".gif")); - else if (dwFormat == PA_FORMAT_PNG) - _tcscat(pszDest, _T(".png")); - else if (dwFormat == PA_FORMAT_BMP) - _tcscat(pszDest, _T(".bmp")); - else if (dwFormat == PA_FORMAT_XML) - _tcscat(pszDest, _T(".xml")); - else if (dwFormat == PA_FORMAT_SWF) - _tcscat(pszDest, _T(".swf")); - else - _tcscat(pszDest, _T(".dat")); -} - - -int DetectAvatarFormatBuffer(const char *pBuffer) -{ - if (!strncmp(pBuffer, "%PNG", 4)) - return PA_FORMAT_PNG; - - if (!strncmp(pBuffer, "GIF8", 4)) - return PA_FORMAT_GIF; - - if (!_strnicmp(pBuffer, "isPending()) - { - NetLog_Server("Avatar, Multiple start thread attempt, ignored."); - SAFE_FREE((void**)&cookie); - return; - } - NetLog_Server("Avatars: Connection failed"); - - m_avatarsConnectionPending = FALSE; - - { // check if any upload request are waiting in the queue - avatars_request *ar = m_avatarsQueue; - int bYet = 0; - - while (ar) - { - if (ar->type == ART_UPLOAD) - { // we found it, return error - if (!bYet) - { - icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server temporarily unavailable.")); - bYet = 1; - } - // remove upload request from queue - ar = ReleaseAvatarRequestInQueue(ar); - continue; - } - ar = ar->pNext; - } - } - SAFE_FREE((void**)&cookie); - - return; - } - - icq_lock l(m_avatarsMutex); - - if (m_avatarsConnection && m_avatarsConnection->isPending()) - { - NetLog_Server("Avatar, Multiple start thread attempt, ignored."); - - NetLib_CloseConnection(&hConn, FALSE); - - SAFE_FREE((void**)&cookie); - - return; - } - else if (m_avatarsConnection) - m_avatarsConnection->closeConnection(); - - m_avatarsConnection = new avatars_server_connection(this, hConn, cookie, cookieLen); // the old connection should not be used anymore - - // connection object created, remove the connection request pending flag - m_avatarsConnectionPending = FALSE; -} - - -void CIcqProto::StopAvatarThread() -{ - icq_lock l(m_avatarsMutex); // the connection is about to close - - if (m_avatarsConnection) - { - m_avatarsConnection->shutdownConnection(); // make the thread stop - } - - return; -} - - -#ifdef _DEBUG -static void NetLog_Hash(CIcqProto *ppro, const char *pszIdent, const BYTE *pHash, int nHashLen) -{ - if (nHashLen == 0x14) - ppro->NetLog_Server("Avatars: %s hash: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", pszIdent, pHash[0], pHash[1], pHash[2], pHash[3], pHash[4], pHash[5], pHash[6], pHash[7], pHash[8], pHash[9], pHash[10], pHash[11], pHash[12], pHash[13], pHash[14], pHash[15], pHash[16], pHash[17], pHash[18], pHash[19]); - else if (nHashLen == 0x09) - ppro->NetLog_Server("Avatars: %s hash: %02X%02X%02X%02X%02X%02X%02X%02X%02X", pszIdent, pHash[0], pHash[1], pHash[2], pHash[3], pHash[4], pHash[5], pHash[6], pHash[7], pHash[8]); - else - ppro->NetLog_Server("Avatars: %s hash: Unknown hash format.", pszIdent); -} -#endif - - -// handle Owner's avatar hash changes -void CIcqProto::handleAvatarOwnerHash(WORD wItemID, BYTE bFlags, BYTE *pData, BYTE nDataLen) -{ - if ((nDataLen >= 0x14) && m_bAvatarsEnabled) - { - switch (bFlags) - { - case 1: // our avatar is on the server - { - setSettingBlob(NULL, "AvatarHash", pData, 0x14); /// TODO: properly handle multiple avatar items (more formats) - - setUserInfo(); - // here we need to find a file, check its hash, if invalid get avatar from server - TCHAR *file = GetOwnAvatarFileName(); - if (!file) - { // we have no avatar file, download from server - TCHAR szFile[MAX_PATH * 2 + 4]; -#ifdef _DEBUG - NetLog_Server("We have no avatar, requesting from server."); -#endif - GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2); - GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile); - } - else - { // we know avatar filename - BYTE *hash = calcMD5HashOfFile(file); - - if (!hash) - { // hash could not be calculated - probably missing file, get avatar from server - TCHAR szFile[MAX_PATH * 2 + 4]; -#ifdef _DEBUG - NetLog_Server("We have no avatar, requesting from server."); -#endif - GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2); - GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile); - } // check if we had set any avatar if yes set our, if not download from server - else if (memcmp(hash, pData + 4, 0x10)) - { // we have different avatar, sync that - if (m_bSsiEnabled && getSettingByte(NULL, "ForceOurAvatar", 1)) - { // we want our avatar, update hash - DWORD dwPaFormat = DetectAvatarFormat(file); - BYTE *pHash = (BYTE*)_alloca(0x14); - - NetLog_Server("Our avatar is different, setting our new hash."); - - pHash[0] = 0; - pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; - pHash[2] = 1; // state of the hash - pHash[3] = 0x10; // len of the hash - memcpy(pHash + 4, hash, 0x10); - updateServAvatarHash(pHash, 0x14); - } - else - { // get avatar from server - TCHAR tszFile[MAX_PATH * 2 + 4]; -#ifdef _DEBUG - NetLog_Server("We have different avatar, requesting new from server."); -#endif - GetAvatarFileName(0, NULL, tszFile, MAX_PATH * 2); - GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, tszFile); - } - } - SAFE_FREE((void**)&hash); - SAFE_FREE(&file); - } - break; - } - case 0x41: // request to upload avatar data - case 0x81: - { // request to re-upload avatar data - if (!m_bSsiEnabled) break; // we could not change serv-list if it is disabled... - - TCHAR *file = GetOwnAvatarFileName(); - if (!file) - { // we have no file to upload, remove hash from server - NetLog_Server("We do not have avatar, removing hash."); - SetMyAvatar(0, 0); - break; - } - DWORD dwPaFormat = DetectAvatarFormat(file); - BYTE *hash = calcMD5HashOfFile(file); - - if (!hash) - { // the hash could not be calculated, remove from server - NetLog_Server("We could not obtain hash, removing hash."); - SetMyAvatar(0, 0); - } - else if (!memcmp(hash, pData + 4, 0x10)) - { // we have the right file - HANDLE hFile = NULL, hMap = NULL; - BYTE *ppMap = NULL; - long cbFileSize = 0; - - NetLog_Server("Uploading our avatar data."); - - if ((hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE) - if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) - if ((ppMap = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) - cbFileSize = GetFileSize(hFile, NULL); - - if (cbFileSize != 0) - { - SetAvatarData(NULL, (WORD)(dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC), ppMap, cbFileSize); - } - - if (ppMap != NULL) UnmapViewOfFile(ppMap); - if (hMap != NULL) CloseHandle(hMap); - if (hFile != NULL) CloseHandle(hFile); - SAFE_FREE((void**)&hash); - } - else - { - BYTE *pHash = (BYTE*)_alloca(0x14); - - NetLog_Server("Our file is different, set our new hash."); - - pHash[0] = 0; - pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; - pHash[2] = 1; // state of the hash - pHash[3] = 0x10; // len of the hash - memcpy(pHash + 4, hash, 0x10); - updateServAvatarHash(pHash, 0x14); - - SAFE_FREE((void**)&hash); - } - - SAFE_FREE(&file); - break; - } - default: - NetLog_Server("Received UNKNOWN Avatar Status."); - } - } -} - - -// handle Contact's avatar hash -void CIcqProto::handleAvatarContactHash(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *pHash, int nHashLen, WORD wOldStatus) -{ - int bJob = FALSE; - BOOL avatarInfoPresent = FALSE; - int avatarType = -1; - BYTE *pAvatarHash = NULL; - int cbAvatarHash; - BYTE emptyItem[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - if (!m_bAvatarsEnabled) return; // only if enabled - - if (nHashLen < 4) return; // nothing to work with - - while (nHashLen >= 4) - { // parse online message items one by one - WORD itemType = pHash[0] << 8 | pHash[1]; - BYTE itemLen = pHash[3]; - BYTE itemFlags = pHash[2]; - - // just some validity check - if (itemLen + 4 > nHashLen) - itemLen = nHashLen - 4; - - if (itemLen && memcmp(pHash + 4, emptyItem, itemLen > 0x10 ? 0x10 : itemLen)) - { // Item types - // 0000: AIM mini avatar - // 0001: AIM/ICQ avatar ID/hash (len 5 or 16 bytes) - // 0002: iChat online message - // 0008: ICQ Flash avatar hash (16 bytes) - // 0009: iTunes music store link - // 000C: ICQ contact photo (16 bytes) - // 000D: Last update time of online message - // 000E: Status mood - if (itemType == AVATAR_HASH_MINI && itemLen == 0x05 && avatarType == -1) - { // mini avatar - pAvatarHash = pHash; - cbAvatarHash = itemLen + 4; - avatarType = itemType; - } - else if (itemType == AVATAR_HASH_STATIC && (itemLen == 0x05 || itemLen == 0x10) && (avatarType == -1 || avatarType == AVATAR_HASH_MINI)) - { // normal avatar - pAvatarHash = pHash; - cbAvatarHash = itemLen + 4; - avatarType = itemType; - } - else if (itemType == AVATAR_HASH_FLASH && itemLen == 0x10 && (avatarType == -1 || avatarType == AVATAR_HASH_MINI || avatarType == AVATAR_HASH_STATIC)) - { // flash avatar - pAvatarHash = pHash; - cbAvatarHash = itemLen + 4; - avatarType = itemType; - } - else if (itemType == AVATAR_HASH_PHOTO && itemLen == 0x10) - { // big avatar (ICQ 6+) - pAvatarHash = pHash; - cbAvatarHash = itemLen + 4; - avatarType = itemType; - } - } - else if ((itemLen == 0) && (itemType == AVATAR_HASH_MINI || itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH || itemType == AVATAR_HASH_PHOTO)) - { // empty item - indicating that avatar of that type was removed - avatarInfoPresent = TRUE; - } - - pHash += itemLen + 4; - nHashLen -= itemLen + 4; - } - - if (avatarType != -1) - { // check settings, should we request avatar immediatelly? - DBVARIANT dbv = {DBVT_DELETED}; - TCHAR tszAvatar[MAX_PATH * 2 +4]; - BYTE bAutoLoad = getSettingByte(NULL, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS); - - if ((avatarType == AVATAR_HASH_STATIC || avatarType == AVATAR_HASH_MINI) && cbAvatarHash == 0x09 && !memcmp(pAvatarHash + 4, hashEmptyAvatar + 4, 0x05)) - { // empty avatar - unlink image, clear hash - if (!getSetting(hContact, "AvatarHash", &dbv)) - { // contact had avatar, clear hash, notify UI -#ifdef _DEBUG - NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); -#endif - ICQFreeVariant(&dbv); - NetLog_Server("%s has removed Avatar.", strUID(dwUIN, szUID)); - - deleteSetting(hContact, "AvatarHash"); - BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); - } -#ifdef _DEBUG - else - NetLog_Server("%s has empty Avatar.", strUID(dwUIN, szUID)); -#endif - return; - } - - if (getSetting(hContact, "AvatarHash", &dbv)) - { // we did not find old avatar hash, i.e. get new avatar - int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash); - - // check saved hash and file, if equal only store hash - if (!avatarState) - { // hashes are the same - int dwPaFormat = getSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN); - - GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2); - if (_taccess(tszAvatar, 0) == 0) - { // the file is there, link to contactphoto, save hash - NetLog_Server("%s has published Avatar. Image was found in the cache.", strUID(dwUIN, szUID)); -#ifdef _DEBUG - NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); -#endif - setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash); - BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); - } - else - { // the file was lost, request avatar again - NetLog_Server("%s has published Avatar.", strUID(dwUIN, szUID)); -#ifdef _DEBUG - NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); -#endif - bJob = TRUE; - } - } - else - { // the hash is not the one we want, request avatar - NetLog_Server("%s has published a new Avatar.", strUID(dwUIN, szUID)); -#ifdef _DEBUG - NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); -#endif - bJob = TRUE; - } - } - else - { // we found hash check if it changed or not - if ((dbv.cpbVal != cbAvatarHash) || memcmp(dbv.pbVal, pAvatarHash, cbAvatarHash)) - { // the hash is different, request new avatar -#ifdef _DEBUG - NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); -#endif - NetLog_Server("%s has changed Avatar.", strUID(dwUIN, szUID)); -#ifdef _DEBUG - NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); -#endif - bJob = TRUE; - } - else - { // the hash was not changed, check if we have the correct file - int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash); - - // we should have file, check if the file really exists - if (!avatarState) - { - int dwPaFormat = getSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN); - if (dwPaFormat == PA_FORMAT_UNKNOWN) - { // we do not know the format, get avatar again -#ifdef _DEBUG - NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); -#endif - NetLog_Server("%s has Avatar. Image is missing.", strUID(dwUIN, szUID)); - bJob = 2; - } - else - { - GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2); - if (_taccess(tszAvatar, 0) != 0) - { // the file was lost, get it again -#ifdef _DEBUG - NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); -#endif - NetLog_Server("%s has Avatar. Image is missing.", strUID(dwUIN, szUID)); - bJob = 2; - } -#ifdef _DEBUG - else - { - NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); - - NetLog_Server("%s has Avatar. Image was found in the cache.", strUID(dwUIN, szUID)); - } -#endif - } - } - else - { // the hash is not the one we want, request avatar -#ifdef _DEBUG - NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); -#endif - NetLog_Server("%s has Avatar. Image was not retrieved yet.", strUID(dwUIN, szUID)); - bJob = 2; - } - } - ICQFreeVariant(&dbv); - } - - if (bJob) - { - if (bJob == TRUE) - { // Remove possible block - hash changed, try again. - icq_lock l(m_avatarsMutex); - - avatars_request *ar = m_avatarsQueue; - - while (ar) - { - if (ar->hContact == hContact && ar->type == ART_BLOCK) - { // found one, remove - ReleaseAvatarRequestInQueue(ar); - break; - } - ar = ar->pNext; - } - } - - setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash); - - BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); - - if (bAutoLoad) - { // auto-load is on, so request the avatar now, otherwise we are done - GetAvatarFileName(dwUIN, szUID, tszAvatar, MAX_PATH * 2); - GetAvatarData(hContact, dwUIN, szUID, pAvatarHash, cbAvatarHash, tszAvatar); - } // avatar request sent or added to queue - } - } - else if (avatarInfoPresent) - { // hash was not found, clear the hash - DBVARIANT dbv = {DBVT_DELETED}; - - if (!getSetting(hContact, "AvatarHash", &dbv)) - { // contact had avatar, clear hash, notify UI -#ifdef _DEBUG - NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); -#endif - ICQFreeVariant(&dbv); - NetLog_Server("%s has removed Avatar.", strUID(dwUIN, szUID)); - - deleteSetting(hContact, "AvatarHash"); - BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); - } -#ifdef _DEBUG - else - NetLog_Server("%s has no Avatar.", strUID(dwUIN, szUID)); -#endif - } -} - - -// request avatar data from server -int CIcqProto::GetAvatarData(HANDLE hContact, DWORD dwUin, const char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file) -{ - uid_str szUidData; - char *pszUid = NULL; - if (!dwUin && szUid) - { // create a copy in local writable buffer - strcpy(szUidData, szUid); - pszUid = szUidData; - } - - m_avatarsMutex->Enter(); - - if (m_avatarsConnection && m_avatarsConnection->isReady()) // check if we are ready - { // check if requests for this user are not blocked - DWORD dwNow = GetTickCount(); - avatars_request *ar = m_avatarsQueue; - - while (ar) - { - if (ar->hContact == hContact && ar->type == ART_BLOCK) - { // found a block item - if (GetTickCount() > ar->timeOut) - { // remove timeouted block - ar = ReleaseAvatarRequestInQueue(ar); - continue; - } - m_avatarsMutex->Leave(); - NetLog_Server("Avatars: Requests for %s avatar are blocked.", strUID(dwUin, pszUid)); - return 0; - } - ar = ar->pNext; - } - - avatars_server_connection *pConnection = m_avatarsConnection; - - pConnection->_Lock(); - m_avatarsMutex->Leave(); - - DWORD dwCookie = pConnection->sendGetAvatarRequest(hContact, dwUin, pszUid, hash, hashlen, file); - - m_avatarsMutex->Enter(); - pConnection->_Release(); - - if (dwCookie) - { // return now if the request was sent successfully - m_avatarsMutex->Leave(); - return dwCookie; - } - } - // we failed to send request, or avatar thread not ready - - // check if any request for this user is not already in the queue - avatars_request *ar = m_avatarsQueue; - - while (ar) - { - if (ar->hContact == hContact) - { // we found it, return error - if (ar->type == ART_BLOCK && GetTickCount() > ar->timeOut) - { // remove timeouted block - ar = ReleaseAvatarRequestInQueue(ar); - continue; - } - m_avatarsMutex->Leave(); - NetLog_Server("Avatars: Ignoring duplicate get %s avatar request.", strUID(dwUin, pszUid)); - - // make sure avatar connection is in progress - requestAvatarConnection(); - return 0; - } - ar = ar->pNext; - } - // add request to queue, processed after successful login - ar = new avatars_request(ART_GET); // get avatar - if (!ar) - { // out of memory, go away - m_avatarsMutex->Leave(); - return 0; - } - ar->hContact = hContact; - ar->dwUin = dwUin; - if (!dwUin) - strcpy(ar->szUid, szUid); - ar->hash = (BYTE*)SAFE_MALLOC(hashlen); - if (!ar->hash) - { // alloc failed - m_avatarsMutex->Leave(); - delete ar; - return 0; - } - memcpy(ar->hash, hash, hashlen); // copy the data - ar->hashlen = hashlen; - ar->szFile = null_strdup(file); // duplicate the string - ar->pNext = m_avatarsQueue; - m_avatarsQueue = ar; - m_avatarsMutex->Leave(); - - NetLog_Server("Avatars: Request to get %s image added to queue.", strUID(dwUin, pszUid)); - - // make sure avatar connection is in progress - requestAvatarConnection(); - - return -1; // we added to queue -} - - -// upload avatar data to server -int CIcqProto::SetAvatarData(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen) -{ - m_avatarsMutex->Enter(); - - if (m_avatarsConnection && m_avatarsConnection->isReady()) // check if we are ready - { - avatars_server_connection *pConnection = m_avatarsConnection; - - pConnection->_Lock(); - m_avatarsMutex->Leave(); - - DWORD dwCookie = pConnection->sendUploadAvatarRequest(hContact, wRef, data, datalen); - - m_avatarsMutex->Enter(); - pConnection->_Release(); - - if (dwCookie) - { // return now if the request was sent successfully - m_avatarsMutex->Leave(); - return dwCookie; - } - } - // we failed to send request, or avatar thread not ready - - // check if any request for this user is not already in the queue - avatars_request *ar = m_avatarsQueue; - int bYet = 0; - - while (ar) - { - if (ar->hContact == hContact && ar->type == ART_UPLOAD) - { // we found it, return error - m_avatarsMutex->Leave(); - NetLog_Server("Avatars: Ignoring duplicate upload avatar request."); - - // make sure avatar connection is in progress - requestAvatarConnection(); - return 0; - } - ar = ar->pNext; - } - // add request to queue, processed after successful login - ar = new avatars_request(ART_UPLOAD); // upload avatar - if (!ar) - { // out of memory, go away - m_avatarsMutex->Leave(); - return 0; - } - ar->hContact = hContact; - ar->pData = (BYTE*)SAFE_MALLOC(datalen); - if (!ar->pData) - { // alloc failed - m_avatarsMutex->Leave(); - delete ar; - return 0; - } - memcpy(ar->pData, data, datalen); // copy the data - ar->cbData = datalen; - ar->wRef = wRef; - ar->pNext = m_avatarsQueue; - m_avatarsQueue = ar; - m_avatarsMutex->Leave(); - - NetLog_Server("Avatars: Request to upload image added to queue."); - - // make sure avatar connection is in progress - requestAvatarConnection(); - - return -1; // we added to queue -} - - -void CIcqProto::requestAvatarConnection() -{ - m_avatarsMutex->Enter(); - if (!m_avatarsConnectionPending && (!m_avatarsConnection || (!m_avatarsConnection->isPending() && !m_avatarsConnection->isReady()))) - { // avatar connection is not pending, request new one - m_avatarsConnectionPending = TRUE; - m_avatarsMutex->Leave(); - - icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread); - } - else - m_avatarsMutex->Leave(); -} - - -void __cdecl CIcqProto::AvatarThread(avatars_server_connection *pInfo) -{ - NetLog_Server("%s thread started.", "Avatar"); - - // Execute connection handler - pInfo->connectionThread(); - - { // Remove connection reference - icq_lock l(m_avatarsMutex); - if (m_avatarsConnection == pInfo) - m_avatarsConnection = NULL; - } - - { // Release connection handler - icq_lock l(m_avatarsMutex); - delete pInfo; - } - - NetLog_Server("%s thread ended.", "Avatar"); -} - - -avatars_server_connection::avatars_server_connection(CIcqProto *ppro, HANDLE hConnection, char *pCookie, WORD wCookieLen): -isLoggedIn(FALSE), stopThread(FALSE), isActive(FALSE) -{ - this->ppro = ppro; - this->hConnection = hConnection; - this->pCookie = pCookie; - this->wCookieLen = wCookieLen; - - // Initialize packet sequence - localSeqMutex = new icq_critical_section(); - wLocalSequence = generate_flap_sequence(); - - // Initialize rates - m_ratesMutex = new icq_critical_section(); - - // Create connection thread - ppro->ForkThread(( IcqThreadFunc )&CIcqProto::AvatarThread, this); -} - - -avatars_server_connection::~avatars_server_connection() -{ - delete m_ratesMutex; - delete localSeqMutex; -} - - -int avatars_server_connection::NetLog_Server(const char *fmt,...) -{ - va_list va; - char szText[1024 + 9]; - - strcpy(szText, "Avatars: "); - va_start(va, fmt); - mir_vsnprintf(szText + 9, sizeof(szText) - 9, fmt, va); - va_end(va); - return CallService(MS_NETLIB_LOG,(WPARAM)ppro->m_hServerNetlibUser,(LPARAM)szText); -} - - -void avatars_server_connection::closeConnection() -{ - stopThread = TRUE; - - icq_lock l(localSeqMutex); - if (hConnection) - NetLib_SafeCloseHandle(&hConnection); -} - - -void avatars_server_connection::shutdownConnection() -{ - stopThread = TRUE; - - icq_lock l(localSeqMutex); - if (hConnection) - Netlib_Shutdown(hConnection); -} - -DWORD avatars_server_connection::sendGetAvatarRequest(HANDLE hContact, DWORD dwUin, char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file) -{ - int i; - DWORD dwNow = GetTickCount(); - - ppro->m_avatarsMutex->Enter(); - - for(i = 0; i < runCount;) - { // look for timeouted requests - if (runTime[i] < dwNow) - { // found outdated, remove - runContact[i] = runContact[runCount - 1]; - runTime[i] = runTime[runCount - 1]; - runCount--; - } - else - i++; - } - - for(i = 0; i < runCount; i++) - { - if (runContact[i] == hContact) - { - ppro->m_avatarsMutex->Leave(); - NetLog_Server("Ignoring duplicate get %s image request.", strUID(dwUin, szUid)); - - return -1; // Success: request ignored - } - } - - if (runCount < 4) - { // 4 concurent requests at most - int bSendNow = TRUE; - - { // rate management - icq_lock l(m_ratesMutex); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST); - - if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT)) - { // we will be over quota if we send the request now, add to queue instead - bSendNow = FALSE; -#ifdef _DEBUG - NetLog_Server("Rates: Delay avatar request."); -#endif - } - } - - if (bSendNow) - { - runContact[runCount] = hContact; - runTime[runCount] = GetTickCount() + 30000; // 30sec to complete request - runCount++; - - ppro->m_avatarsMutex->Leave(); - - int nUinLen = getUIDLen(dwUin, szUid); - - cookie_avatar *ack = (cookie_avatar*)SAFE_MALLOC(sizeof(cookie_avatar)); - if (!ack) return 0; // Failure: out of memory - - ack->dwUin = 1; //dwUin; // I should be damned for this - only to identify get request - ack->hContact = hContact; - ack->hash = (BYTE*)SAFE_MALLOC(hashlen); - memcpy(ack->hash, hash, hashlen); // copy the data - ack->hashlen = hashlen; - ack->szFile = null_strdup(file); // duplicate the string - - DWORD dwCookie = ppro->AllocateCookie(CKT_AVATAR, ICQ_AVATAR_GET_REQUEST, hContact, ack); - icq_packet packet; - - serverPacketInit(&packet, (WORD)(12 + nUinLen + hashlen)); - packFNACHeader(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST, 0, dwCookie); - packUID(&packet, dwUin, szUid); - packByte(&packet, 1); // unknown, probably type of request: 1 = get icon :) - packBuffer(&packet, hash, (WORD)hashlen); - - if (sendServerPacket(&packet)) - { - NetLog_Server("Request to get %s image sent.", strUID(dwUin, szUid)); - - return dwCookie; - } - ppro->FreeCookie(dwCookie); // sending failed, free resources - SAFE_FREE(&ack->szFile); - SAFE_FREE((void**)&ack->hash); - SAFE_FREE((void**)&ack); - } - else - ppro->m_avatarsMutex->Leave(); - } - else - ppro->m_avatarsMutex->Leave(); - - return 0; // Failure -} - - -DWORD avatars_server_connection::sendUploadAvatarRequest(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen) -{ - cookie_avatar *ack = (cookie_avatar*)SAFE_MALLOC(sizeof(cookie_avatar)); - if (!ack) return 0; // Failure: out of memory - - ack->hContact = hContact; - - DWORD dwCookie = ppro->AllocateCookie(CKT_AVATAR, ICQ_AVATAR_UPLOAD_REQUEST, 0, ack); - icq_packet packet; - - serverPacketInit(&packet, (WORD)(14 + datalen)); - packFNACHeader(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_UPLOAD_REQUEST, 0, dwCookie); - packWord(&packet, wRef); // unknown, probably reference - packWord(&packet, (WORD)datalen); - packBuffer(&packet, data, (WORD)datalen); - - if (sendServerPacket(&packet)) - { - NetLog_Server("Upload image packet sent."); - - return dwCookie; - } - ppro->ReleaseCookie(dwCookie); // failed to send, free resources - - return 0; -} - - -void avatars_server_connection::checkRequestQueue() -{ -#ifdef _DEBUG - NetLog_Server("Checking request queue..."); -#endif - - ppro->m_avatarsMutex->Enter(); - - while (ppro->m_avatarsQueue && runCount < 3) // pick up an request and send it - happens immediatelly after login - { // do not fill queue to top, leave one place free - avatars_request *pRequest = ppro->m_avatarsQueue; - - { // rate management - icq_lock l(m_ratesMutex); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, (WORD)(pRequest->type == ART_UPLOAD ? ICQ_AVATAR_GET_REQUEST : ICQ_AVATAR_UPLOAD_REQUEST)); - - if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT)) - { // we are over rate, leave queue and wait -#ifdef _DEBUG - NetLog_Server("Rates: Leaving avatar queue processing"); -#endif - break; - } - } - - if (pRequest->type == ART_BLOCK) - { // block contact processing - avatars_request **ppRequest = &ppro->m_avatarsQueue; - - while (pRequest) - { - if (GetTickCount() > pRequest->timeOut) - { // expired contact block, remove - *ppRequest = pRequest->pNext; - delete pRequest; - } - else // it is not time, move to next request - ppRequest = &pRequest->pNext; - - pRequest = *ppRequest; - } - // end queue processing (only block requests follows) - break; - } - else - ppro->m_avatarsQueue = pRequest->pNext; - - ppro->m_avatarsMutex->Leave(); - -#ifdef _DEBUG - NetLog_Server("Picked up the %s request from queue.", strUID(pRequest->dwUin, pRequest->szUid)); -#endif - switch (pRequest->type) - { - case ART_GET: // get avatar - sendGetAvatarRequest(pRequest->hContact, pRequest->dwUin, pRequest->szUid, pRequest->hash, pRequest->hashlen, pRequest->szFile); - break; - - case ART_UPLOAD: // set avatar - sendUploadAvatarRequest(pRequest->hContact, pRequest->wRef, pRequest->pData, pRequest->cbData); - break; - } - delete pRequest; - - ppro->m_avatarsMutex->Enter(); - } - - ppro->m_avatarsMutex->Leave(); -} - - -void avatars_server_connection::connectionThread() -{ - // This is the "infinite" loop that receives the packets from the ICQ avatar server - NETLIBPACKETRECVER packetRecv = {0}; - DWORD wLastKeepAlive = 0; // we send keep-alive at most one per 30secs - DWORD dwKeepAliveInterval = ppro->getSettingDword(NULL, "KeepAliveInterval", KEEPALIVE_INTERVAL); - - hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hConnection, 65536); - packetRecv.cbSize = sizeof(packetRecv); - packetRecv.dwTimeout = dwKeepAliveInterval < KEEPALIVE_INTERVAL ? dwKeepAliveInterval: KEEPALIVE_INTERVAL; // timeout - for stopThread to work - while (!stopThread) - { - int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); - - if (recvResult == 0) - { - NetLog_Server("Clean closure of server socket"); - break; - } - - if (recvResult == SOCKET_ERROR) - { - if (GetLastError() == ERROR_TIMEOUT) - { // timeout, check if we should be still running - if (Miranda_Terminated()) - { // we must stop here, cause due to a hack in netlib, we always get timeout, even if the connection is already dead - stopThread = 1; - continue; - } -#ifdef _DEBUG - else - NetLog_Server("Thread is Idle."); -#endif - if (GetTickCount() > wLastKeepAlive) - { // limit frequency (HACK: on some systems select() does not work well) - if (!ppro->m_bGatewayMode && ppro->getSettingByte(NULL, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED)) - { // send keep-alive packet - icq_packet packet; - - packet.wLen = 0; - write_flap(&packet, ICQ_PING_CHAN); - sendServerPacket(&packet); - } - wLastKeepAlive = GetTickCount() + dwKeepAliveInterval; - } - else - { // this is bad, the system does not handle select() properly -#ifdef _DEBUG - NetLog_Server("Thread is Forcing Idle."); -#endif - SleepEx(500, TRUE); // wait some time, can we do anything else ?? - if (Miranda_Terminated()) - { - stopThread = 1; - continue; - } - } - // check if we got something to request - checkRequestQueue(); - continue; - } - if (!stopThread) - NetLog_Server("Abortive closure of server socket, error: %d", GetLastError()); - else - NetLog_Server("Connection closed."); - break; - } - - // Deal with the packet - packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable); - - if (isActive && (packetRecv.bytesAvailable == packetRecv.bytesUsed)) // no packets pending - { // process request queue - checkRequestQueue(); - } - } - { // release connection - icq_lock l(localSeqMutex); - NetLib_SafeCloseHandle(&hPacketRecver); // Close the packet receiver - NetLib_CloseConnection(&hConnection, FALSE); // Close the connection - } - - { // release rates - icq_lock l(m_ratesMutex); - SAFE_DELETE((MZeroedObject**)&m_rates); - } - - SAFE_FREE((void**)&pCookie); -} - - -int avatars_server_connection::sendServerPacket(icq_packet *pPacket) -{ - int lResult = 0; - - // This critsec makes sure that the sequence order doesn't get screwed up - localSeqMutex->Enter(); - - if (hConnection) - { - int nRetries; - int nSendResult; - - // :IMPORTANT: - // The FLAP sequence must be a WORD. When it reaches 0xFFFF it should wrap to - // 0x0000, otherwise we'll get kicked by server. - wLocalSequence++; - - // Pack sequence number - pPacket->pData[2] = ((wLocalSequence & 0xff00) >> 8); - pPacket->pData[3] = (wLocalSequence & 0x00ff); - - for (nRetries = 3; nRetries >= 0; nRetries--) - { - nSendResult = Netlib_Send(hConnection, (const char *)pPacket->pData, pPacket->wLen, 0); - - if (nSendResult != SOCKET_ERROR) - break; - - Sleep(1000); - } - - // Send error - if (nSendResult == SOCKET_ERROR) - { // thread stops automatically - NetLog_Server("Your connection with the ICQ avatar server was abortively closed"); - } - else - { - lResult = 1; // packet sent successfully - - icq_lock l(m_ratesMutex); - if (m_rates) - m_rates->packetSent(pPacket); - } - } - else - { - NetLog_Server("Error: Failed to send packet (no connection)"); - } - - localSeqMutex->Leave(); - - SAFE_FREE((void**)&pPacket->pData); - - return lResult; -} - - -int avatars_server_connection::handleServerPackets(BYTE *buf, int buflen) -{ - BYTE channel; - WORD sequence; - WORD datalen; - int bytesUsed = 0; - - while (buflen > 0) - { - // All FLAPS begin with 0x2a - if (*buf++ != FLAP_MARKER) - break; - - if (buflen < 6) - break; - - unpackByte(&buf, &channel); - unpackWord(&buf, &sequence); - unpackWord(&buf, &datalen); - - if (buflen < 6 + datalen) - break; - -#ifdef _DEBUG - NetLog_Server("Server FLAP: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); -#endif - - switch (channel) - { - case ICQ_LOGIN_CHAN: - handleLoginChannel(buf, datalen); - break; - - case ICQ_DATA_CHAN: - handleDataChannel(buf, datalen); - break; - - default: - NetLog_Server("Warning: Unhandled Server FLAP Channel: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); - break; - } - - /* Increase pointers so we can check for more FLAPs */ - buf += datalen; - buflen -= (datalen + 6); - bytesUsed += (datalen + 6); - } - - return bytesUsed; -} - - -void avatars_server_connection::handleLoginChannel(BYTE *buf, WORD datalen) -{ - icq_packet packet; - - if (*(DWORD*)buf == 0x1000000) - { // here check if we received SRV_HELLO - wLocalSequence = generate_flap_sequence(); - - serverCookieInit(&packet, (LPBYTE)pCookie, wCookieLen); - sendServerPacket(&packet); - -#ifdef _DEBUG - NetLog_Server("Sent CLI_IDENT to %s", "avatar server"); -#endif - - SAFE_FREE((void**)&pCookie); - wCookieLen = 0; - } - else - { - NetLog_Server("Invalid Server response, Channel 1."); - } -} - - -void avatars_server_connection::handleDataChannel(BYTE *buf, WORD datalen) -{ - snac_header snacHeader = {0}; - - if (!unpackSnacHeader(&snacHeader, &buf, &datalen) || !snacHeader.bValid) - { - NetLog_Server("Error: Failed to parse SNAC header"); - } - else - { -#ifdef _DEBUG - if (snacHeader.wFlags & 0x8000) - NetLog_Server(" Received SNAC(x%02X,x%02X), version %u", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wVersion); - else - NetLog_Server(" Received SNAC(x%02X,x%02X)", snacHeader.wFamily, snacHeader.wSubtype); -#endif - - switch (snacHeader.wFamily) - { - - case ICQ_SERVICE_FAMILY: - handleServiceFam(buf, datalen, &snacHeader); - break; - - case ICQ_AVATAR_FAMILY: - handleAvatarFam(buf, datalen, &snacHeader); - break; - - default: - NetLog_Server("Ignoring SNAC(x%02X,x%02X) - FAMILYx%02X not implemented", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wFamily); - break; - } - } -} - - -void avatars_server_connection::handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) -{ - icq_packet packet; - - switch (pSnacHeader->wSubtype) - { - - case ICQ_SERVER_READY: -#ifdef _DEBUG - NetLog_Server("Server is ready and is requesting my Family versions"); - NetLog_Server("Sending my Families"); -#endif - - // Miranda mimics the behaviour of Icq5 - serverPacketInit(&packet, 18); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES); - packDWord(&packet, 0x00010004); - packDWord(&packet, 0x00100001); - sendServerPacket(&packet); - break; - - case ICQ_SERVER_FAMILIES2: - /* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands. - * We send a rate request packet */ -#ifdef _DEBUG - NetLog_Server("Server told me his Family versions"); - NetLog_Server("Requesting Rate Information"); -#endif - serverPacketInit(&packet, 10); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO); - sendServerPacket(&packet); - break; - - case ICQ_SERVER_RATE_INFO: -#ifdef _DEBUG - NetLog_Server("Server sent Rate Info"); -#endif - /* init rates management */ - m_rates = new rates(ppro, pBuffer, wBufferLength); - /* ack rate levels */ -#ifdef _DEBUG - NetLog_Server("Sending Rate Info Ack"); -#endif - m_rates->initAckPacket(&packet); - sendServerPacket(&packet); - - // send cli_ready - serverPacketInit(&packet, 26); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY); - packDWord(&packet, 0x00010004); // mimic ICQ 6 - packDWord(&packet, 0x0010164f); - packDWord(&packet, 0x00100001); - packDWord(&packet, 0x0010164f); - sendServerPacket(&packet); - - isActive = TRUE; // we are ready to process requests - isLoggedIn = TRUE; - - NetLog_Server(" *** Yeehah, login sequence complete"); - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -void avatars_server_connection::handleAvatarFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_AVATAR_GET_REPLY: // received avatar data, store to file - { // handle new avatar, notify - cookie_avatar *pCookieData; - - if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) - { - PROTO_AVATAR_INFORMATIONT ai = {0}; - BYTE bResult; - - { // remove from active request list - icq_lock l(ppro->m_avatarsMutex); - for(int i = 0; i < runCount; i++) - { // look for our record - if (runContact[i] == pCookieData->hContact) - { // found, remove - runContact[i] = runContact[runCount - 1]; - runTime[i] = runTime[runCount - 1]; - runCount--; - break; - } - } - } - - ai.cbSize = sizeof(PROTO_AVATAR_INFORMATIONT); - ai.format = PA_FORMAT_JPEG; // this is for error only - ai.hContact = pCookieData->hContact; - lstrcpyn(ai.filename, pCookieData->szFile, SIZEOF(ai.filename)); - AddAvatarExt(PA_FORMAT_JPEG, ai.filename); - - ppro->FreeCookie(pSnacHeader->dwRef); - - BYTE len; - WORD datalen; - - unpackByte(&pBuffer, &len); - if (wBufferLength < ((pCookieData->hashlen)<<1)+4+len) - { - NetLog_Server("Received invalid avatar reply."); - - ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); - - SAFE_FREE(&pCookieData->szFile); - SAFE_FREE((void**)&pCookieData->hash); - SAFE_FREE((void**)&pCookieData); - - break; - } - - pBuffer += len; - pBuffer += pCookieData->hashlen; - unpackByte(&pBuffer, &bResult); - pBuffer += pCookieData->hashlen; - unpackWord(&pBuffer, &datalen); - - wBufferLength -= 4 + len + (pCookieData->hashlen<<1); - if (datalen > wBufferLength) - { - datalen = wBufferLength; - NetLog_Server("Avatar reply broken, trying to do my best."); - } - - if (datalen > 4) - { // store to file... - int aValid = 1; - - if (pCookieData->hashlen == 0x14 && pCookieData->hash[3] == 0x10 && ppro->getSettingByte(NULL, "StrictAvatarCheck", DEFAULT_AVATARS_CHECK)) - { // check only standard hashes - mir_md5_state_t state; - mir_md5_byte_t digest[16]; - - mir_md5_init(&state); - mir_md5_append(&state, (const mir_md5_byte_t *)pBuffer, datalen); - mir_md5_finish(&state, digest); - // check if received data corresponds to specified hash - if (memcmp(pCookieData->hash+4, digest, 0x10)) aValid = 0; - } - - if (aValid) - { - NetLog_Server("Received user avatar, storing (%d bytes).", datalen); - - int dwPaFormat = DetectAvatarFormatBuffer((char*)pBuffer); - TCHAR *tszImageFile = (TCHAR*)_alloca(sizeof(TCHAR)*(strlennull(pCookieData->szFile) + 6)); - - _tcscpy(tszImageFile, pCookieData->szFile); - AddAvatarExt(dwPaFormat, tszImageFile); - - ppro->setSettingByte(pCookieData->hContact, "AvatarType", (BYTE)dwPaFormat); - ai.format = dwPaFormat; // set the format - lstrcpyn(ai.filename, tszImageFile, SIZEOF(ai.filename)); - - int out = _topen(tszImageFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); - if (out != -1) - { - DBVARIANT dbv = {DBVT_DELETED}; - - _write(out, pBuffer, datalen); - _close(out); - - if (!pCookieData->hContact) // our avatar, set filename - { - TCHAR tmp[MAX_PATH * 2]; - CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)tszImageFile, (LPARAM)tmp); - ppro->setSettingStringT(NULL, "AvatarFile", tmp); - } - else - { // contact's avatar set hash - if (!ppro->getSetting(pCookieData->hContact, "AvatarHash", &dbv)) - { - if (ppro->setSettingBlob(pCookieData->hContact, "AvatarSaved", dbv.pbVal, dbv.cpbVal)) - NetLog_Server("Failed to set file hash."); - - ICQFreeVariant(&dbv); - } - else - { - NetLog_Server("Warning: DB error (no hash in DB)."); - // the hash was lost, try to fix that - if (ppro->setSettingBlob(pCookieData->hContact, "AvatarSaved", pCookieData->hash, pCookieData->hashlen) || - ppro->setSettingBlob(pCookieData->hContact, "AvatarHash", pCookieData->hash, pCookieData->hashlen)) - { - NetLog_Server("Failed to save avatar hash to DB"); - } - } - } - - ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, 0); - } - } - else - { // avatar is broken - NetLog_Server("Error: Avatar data does not match avatar hash, ignoring."); - - if (pCookieData->hContact) - { - avatars_request *ar = new avatars_request(ART_BLOCK); - - icq_lock l(ppro->m_avatarsMutex); - - if (ar) - { - avatars_request *last = ppro->m_avatarsQueue; - - ar->hContact = pCookieData->hContact; - ar->timeOut = GetTickCount() + 14400000; // do not allow re-request four hours - - // add it to the end of queue, i.e. do not block other requests - while (last && last->pNext) last = last->pNext; - if (last) - last->pNext = ar; - else - ppro->m_avatarsQueue = ar; - } - } - ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); - } - } - else - { // the avatar is empty - NetLog_Server("Received empty avatar, nothing written (error 0x%x).", bResult); - - ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); - } - SAFE_FREE(&pCookieData->szFile); - SAFE_FREE((void**)&pCookieData->hash); - SAFE_FREE((void**)&pCookieData); - } - else - { - NetLog_Server("Warning: Received unexpected Avatar Reply SNAC(x10,x07)."); - } - - break; - } - case ICQ_AVATAR_UPLOAD_ACK: - { - // upload completed, notify - BYTE res; - unpackByte(&pBuffer, &res); - if (!res && (wBufferLength == 0x15)) - { - cookie_avatar *pCookieData; - if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) - { - // here we store the local hash - ppro->ReleaseCookie(pSnacHeader->dwRef); - } - else - { - NetLog_Server("Warning: Received unexpected Upload Avatar Reply SNAC(x10,x03)."); - } - } - else if (res) - { - NetLog_Server("Error uploading avatar to server, #%d", res); - - ppro->icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server refused to accept the image.")); - } - else - NetLog_Server("Received invalid upload avatar ack."); - - break; - } - case ICQ_ERROR: - { - WORD wError; - cookie_avatar *pCookieData; - - if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) - { - if (pCookieData->dwUin) - { - NetLog_Server("Error: Avatar request failed"); - SAFE_FREE(&pCookieData->szFile); - SAFE_FREE((void**)&pCookieData->hash); - } - else - { - NetLog_Server("Error: Avatar upload failed"); - } - ppro->ReleaseCookie(pSnacHeader->dwRef); - } - - if (wBufferLength >= 2) - unpackWord(&pBuffer, &wError); - else - wError = 0; - - ppro->LogFamilyError(ICQ_AVATAR_FAMILY, wError); - break; - } - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_AVATAR_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - } -} diff --git a/protocols/IcqOscarJ/icq_avatar.h b/protocols/IcqOscarJ/icq_avatar.h deleted file mode 100644 index 6bfcb65c45..0000000000 --- a/protocols/IcqOscarJ/icq_avatar.h +++ /dev/null @@ -1,127 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Avatars connection support declarations -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_AVATAR_H -#define __ICQ_AVATAR_H - - -extern BYTE hashEmptyAvatar[9]; - -#define AVATAR_HASH_MINI 0x00 -#define AVATAR_HASH_STATIC 0x01 -#define AVATAR_HASH_FLASH 0x08 -#define AVATAR_HASH_PHOTO 0x0C - -struct CIcqProto; - -struct avatars_server_connection : public lockable_struct -{ -protected: - CIcqProto *ppro; - HANDLE hConnection; // handle to the connection - HANDLE hPacketRecver; - WORD wLocalSequence; - icq_critical_section *localSeqMutex; - - BOOL isLoggedIn; - BOOL isActive; - BOOL stopThread; // horrible, but simple - signal for thread to stop - - char *pCookie; // auth to server - WORD wCookieLen; - - int sendServerPacket(icq_packet *pPacket); - - int handleServerPackets(BYTE *buf, int buflen); - - void handleLoginChannel(BYTE *buf, WORD datalen); - void handleDataChannel(BYTE *buf, WORD datalen); - - void handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); - void handleAvatarFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); - - rates *m_rates; - icq_critical_section *m_ratesMutex; - - int NetLog_Server(const char *fmt,...); - - HANDLE runContact[4]; - DWORD runTime[4]; - int runCount; - void checkRequestQueue(); -public: - avatars_server_connection(CIcqProto *ppro, HANDLE hConnection, char *pCookie, WORD wCookieLen); - virtual ~avatars_server_connection(); - - void connectionThread(); - void closeConnection(); - void shutdownConnection(); - - __inline BOOL isPending() { return !isLoggedIn; }; - __inline BOOL isReady() { return isLoggedIn && isActive && !stopThread; }; - - DWORD sendGetAvatarRequest(HANDLE hContact, DWORD dwUin, char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file); - DWORD sendUploadAvatarRequest(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen); -}; - -__inline static void SAFE_DELETE(avatars_server_connection **p) { SAFE_DELETE((lockable_struct**)p); }; - - -struct avatars_request : public MZeroedObject -{ - int type; - HANDLE hContact; - DWORD dwUin; - uid_str szUid; - BYTE *hash; - unsigned int hashlen; - TCHAR *szFile; - BYTE *pData; - unsigned int cbData; - WORD wRef; - DWORD timeOut; - avatars_request *pNext; -public: - avatars_request(int type); - virtual ~avatars_request(); -}; - -__inline static void SAFE_DELETE(avatars_request **p) { SAFE_DELETE((MZeroedObject**)p); }; - -#define ART_GET 1 -#define ART_UPLOAD 2 -#define ART_BLOCK 4 - - -int DetectAvatarFormat(const TCHAR *szFile); -void AddAvatarExt(int dwFormat, TCHAR *pszDest); - -BYTE* calcMD5HashOfFile(const TCHAR *szFile); - -#endif /* __ICQ_AVATAR_H */ diff --git a/protocols/IcqOscarJ/icq_clients.cpp b/protocols/IcqOscarJ/icq_clients.cpp deleted file mode 100644 index bb1ebb5621..0000000000 --- a/protocols/IcqOscarJ/icq_clients.cpp +++ /dev/null @@ -1,1155 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Provides capability & signature based client detection -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -const capstr capShortCaps = {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; // CAP_AIM_BUDDYICON - -static const char* makeClientVersion(char *szBuf, const char *szClient, unsigned v1, unsigned v2, unsigned v3, unsigned v4) -{ - if (v4) - null_snprintf(szBuf, 64, "%s%u.%u.%u.%u", szClient, v1, v2, v3, v4); - else if (v3) - null_snprintf(szBuf, 64, "%s%u.%u.%u", szClient, v1, v2, v3); - else - null_snprintf(szBuf, 64, "%s%u.%u", szClient, v1, v2); - - return szBuf; -} - -static void verToStr(char *szStr, int v) -{ - char szVer[64]; - - makeClientVersion(szVer, "", (v>>24)&0x7F, (v>>16)&0xFF, (v>>8)&0xFF, v&0xFF); - strcat(szStr, szVer); - if (v&0x80000000) strcat(szStr, " alpha"); -} - -static char* MirandaVersionToStringEx(char* szStr, int bUnicode, const char* szPlug, int v, int m) -{ - if (!v) // this is not Miranda - return NULL; - - strcpy(szStr, "Miranda IM "); - - if (!m && v == 1) - verToStr(szStr, 0x80010200); - else if (!m && (v&0x7FFFFFFF) <= 0x030301) - verToStr(szStr, v); - else { - if (m) { - verToStr(szStr, m); - strcat(szStr, " "); - } - if (bUnicode) - strcat(szStr, "Unicode "); - - strcat(szStr, "("); - strcat(szStr, szPlug); - strcat(szStr, " v"); - verToStr(szStr, v); - strcat(szStr, ")"); - } - - return szStr; -} - -char* MirandaVersionToString(char* szStr, int bUnicode, int v, int m) -{ - return MirandaVersionToStringEx(szStr, bUnicode, "ICQ", v, m); -} - -char* MirandaModToString(char* szStr, capstr* capId, int bUnicode, const char* szModName) -{ // decode icqj mod version - char* szClient; - DWORD mver = (*capId)[0x4] << 0x18 | (*capId)[0x5] << 0x10 | (*capId)[0x6] << 8 | (*capId)[0x7]; - DWORD iver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; - DWORD scode = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; - - szClient = MirandaVersionToStringEx(szStr, bUnicode, szModName, iver, mver); - if (scode == 0x5AFEC0DE) - { - strcat(szClient, " + SecureIM"); - } - return szClient; -} - -const capstr capMirandaIm = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capMirandaNg = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'N', 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capIcqJs7 = {'i', 'c', 'q', 'j', ' ', 'S', 'e', 'c', 'u', 'r', 'e', ' ', 'I', 'M', 0, 0}; -const capstr capIcqJSin = {'s', 'i', 'n', 'j', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Miranda ICQJ S!N -const capstr capIcqJp = {'i', 'c', 'q', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capAimOscar = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'A', 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capMimMobile = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', 'o', 'b', 'i', 'l', 'e', 0, 0, 0}; -const capstr capMimPack = {'M', 'I', 'M', '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Custom Miranda Pack -const capstr capTrillian = {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}; -const capstr capTrilCrypt = {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb, 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}; -const capstr capSim = {'S', 'I', 'M', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', ' ', 0, 0, 0, 0}; -const capstr capSimOld = {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x00}; -const capstr capLicq = {'L', 'i', 'c', 'q', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', 0, 0, 0, 0}; -const capstr capKopete = {'K', 'o', 'p', 'e', 't', 'e', ' ', 'I', 'C', 'Q', ' ', ' ', 0, 0, 0, 0}; -const capstr capmIcq = {'m', 'I', 'C', 'Q', ' ', 0xA9, ' ', 'R', '.', 'K', '.', ' ', 0, 0, 0, 0}; -const capstr capClimm = {'c', 'l', 'i', 'm', 'm', 0xA9, ' ', 'R', '.', 'K', '.', ' ', 0, 0, 0, 0}; -const capstr capAndRQ = {'&', 'R', 'Q', 'i', 'n', 's', 'i', 'd', 'e', 0, 0, 0, 0, 0, 0, 0}; -const capstr capRAndQ = {'R', '&', 'Q', 'i', 'n', 's', 'i', 'd', 'e', 0, 0, 0, 0, 0, 0, 0}; -const capstr capIMadering = {'I', 'M', 'a', 'd', 'e', 'r', 'i', 'n', 'g', ' ', 'C', 'l', 'i', 'e', 'n', 't'}; -const capstr capmChat = {'m', 'C', 'h', 'a', 't', ' ', 'i', 'c', 'q', ' ', 0, 0, 0, 0, 0, 0}; -const capstr capJimm = {'J', 'i', 'm', 'm', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capCorePager = {'C', 'O', 'R', 'E', ' ', 'P', 'a', 'g', 'e', 'r', 0, 0, 0, 0, 0, 0}; -const capstr capDiChat = {'D', '[', 'i', ']', 'C', 'h', 'a', 't', ' ', 0, 0, 0, 0, 0, 0, 0}; -const capstr capVmIcq = {'V', 'm', 'I', 'C', 'Q', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capSmapeR = {'S', 'm', 'a', 'p', 'e', 'r', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capAnastasia = {0x44, 0xE5, 0xBF, 0xCE, 0xB0, 0x96, 0xE5, 0x47, 0xBD, 0x65, 0xEF, 0xD6, 0xA3, 0x7E, 0x36, 0x02}; -const capstr capPalmJicq = {'J', 'I', 'C', 'Q', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capInluxMsgr = {0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0, 0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4, 0x67, 0xC5, 0x6B, 0x1F}; -const capstr capYapp = {'Y', 'a', 'p', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capMipClient = {0x4d, 0x49, 0x50, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x00, 0x00, 0x00, 0x00}; -const capstr capPigeon = {'P', 'I', 'G', 'E', 'O', 'N', '!', 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capDigsbyBeta= {0x09, 0x46, 0x01, 0x05, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}; -const capstr capDigsby = {'d', 'i', 'g', 's', 'b', 'y', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capJapp = {0x6a, 0x61, 0x70, 0x70, 0xa9, 0x20, 0x62, 0x79, 0x20, 0x53, 0x65, 0x72, 0x67, 0x6f, 0x00, 0x00}; -const capstr capNaim = {0xFF, 0xFF, 0xFF, 0xFF, 'n', 'a', 'i', 'm', 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capCitron = {0x09, 0x19, 0x19, 0x82, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; -const capstr capQip = {0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F, 0x41, 'Q', 'I', 'P', ' ', '2', '0', '0', '5', 'a'}; -const capstr capQipPDA = {0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F, 0x41, 'Q', 'I', 'P', ' ', ' ', ' ', ' ', ' ', '!'}; -const capstr capQipSymbian= {0x51, 0xAD, 0xD1, 0x90, 0x72, 0x04, 0x47, 0x3D, 0xA1, 0xA1, 0x49, 0xF4, 0xA3, 0x97, 0xA4, 0x1F}; -const capstr capQipIphone = {0x60, 0xDE, 0x5C, 0x8A, 0xDF, 0x8C, 0x4E, 0x1D, 0xA4, 0xC8, 0xBC, 0x3B, 0xD9, 0x79, 0x4D, 0xD8}; -const capstr capQipMobile = {0xB0, 0x82, 0x62, 0xF6, 0x7F, 0x7C, 0x45, 0x61, 0xAD, 0xC1, 0x1C, 0x6D, 0x75, 0x70, 0x5E, 0xC5}; -const capstr capQipInfium = {0x7C, 0x73, 0x75, 0x02, 0xC3, 0xBE, 0x4F, 0x3E, 0xA6, 0x9F, 0x01, 0x53, 0x13, 0x43, 0x1E, 0x1A}; -const capstr capQip2010 = {0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x0A, 0x03, 0x0B, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, 0x00}; -const capstr capQip2012 = {0x7F, 0x7F, 0x7C, 0x7D, 0x7E, 0x7F, 0x0A, 0x03, 0x0B, 0x04, 0x01, 0x53, 0x13, 0x43, 0x1E, 0x1A}; -const capstr capIm2 = {0x74, 0xED, 0xC3, 0x36, 0x44, 0xDF, 0x48, 0x5B, 0x8B, 0x1C, 0x67, 0x1A, 0x1F, 0x86, 0x09, 0x9F}; // IM2 Ext Msg -const capstr capQutIm = {'q', 'u', 't', 'i', 'm', 0x30, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const capstr capBayan = {'b', 'a', 'y', 'a', 'n', 'I', 'C', 'Q', 0, 0, 0, 0, 0, 0, 0, 0}; -const capstr capJabberJIT = {'J', 'I', 'T', ' ', 0x76, 0x2E, 0x31, 0x2E, 0x78, 0x2E, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00}; -const capstr capIcqKid2 = {'I', 'c', 'q', 'K', 'i', 'd', '2', 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const capstr capWebIcqPro = {'W', 'e', 'b', 'I', 'c', 'q', 'P', 'r', 'o', ' ', 0, 0, 0, 0, 0, 0}; -const capstr capMraJava = {0x4a, 0x32, 0x4d, 0x45, 0x20, 0x6d, 0x40, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00}; -const capstr capMacIcq = {0xdd, 0x16, 0xf2, 0x02, 0x84, 0xe6, 0x11, 0xd4, 0x90, 0xdb, 0x00, 0x10, 0x4b, 0x9b, 0x4b, 0x7d}; -const capstr capIs2001 = {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}; -const capstr capIs2002 = {0x10, 0xcf, 0x40, 0xd1, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; -const capstr capComm20012 = {0xa0, 0xe9, 0x3f, 0x37, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; -const capstr capStrIcq = {0xa0, 0xe9, 0x3f, 0x37, 0x4f, 0xe9, 0xd3, 0x11, 0xbc, 0xd2, 0x00, 0x04, 0xac, 0x96, 0xdd, 0x96}; -const shortcapstr capAimIcon = {0x13, 0x46}; // CAP_AIM_BUDDYICON -const shortcapstr capAimDirect = {0x13, 0x45}; // CAP_AIM_DIRECTIM -const shortcapstr capAimFileShare = {0x13, 0x48}; // CAP_AIM_FILE_SHARE -const shortcapstr capIcqDevils = {0x13, 0x4C}; // CAP_DEVILS -const shortcapstr capAimSmartCaps = {0x01, 0xFF}; -const shortcapstr capAimLiveVideo = {0x01, 0x01}; // CAP_AIM_LIVE_VIDEO -const shortcapstr capAimLiveAudio = {0x01, 0x04}; // CAP_AIM_LIVE_AUDIO -const shortcapstr capStatusTextAware = {0x01, 0x0A}; // CAP_HOST_STATUS_TEXT_AWARE -const capstr capIcqLiteNew= {0xc8, 0x95, 0x3a, 0x9f, 0x21, 0xf1, 0x4f, 0xaa, 0xb0, 0xb2, 0x6d, 0xe6, 0x63, 0xab, 0xf5, 0xb7}; -const capstr capXtrazVideo= {0x17, 0x8C, 0x2D, 0x9B, 0xDA, 0xA5, 0x45, 0xBB, 0x8D, 0xDB, 0xF3, 0xBD, 0xBD, 0x53, 0xA1, 0x0A}; -const capstr capOscarChat = {0x74, 0x8F, 0x24, 0x20, 0x62, 0x87, 0x11, 0xD1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; -const capstr capUim = {0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0, 0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4, 0x67, 0xC5, 0x6B, 0x1F}; -const capstr capRambler = {0x7E, 0x11, 0xB7, 0x78, 0xA3, 0x53, 0x49, 0x26, 0xA8, 0x02, 0x44, 0x73, 0x52, 0x08, 0xC4, 0x2A}; -const capstr capAbv = {0x00, 0xE7, 0xE0, 0xDF, 0xA9, 0xD0, 0x4F, 0xe1, 0x91, 0x62, 0xC8, 0x90, 0x9A, 0x13, 0x2A, 0x1B}; -const capstr capNetvigator= {0x4C, 0x6B, 0x90, 0xA3, 0x3D, 0x2D, 0x48, 0x0E, 0x89, 0xD6, 0x2E, 0x4B, 0x2C, 0x10, 0xD9, 0x9F}; -const capstr captZers = {0xb2, 0xec, 0x8f, 0x16, 0x7c, 0x6f, 0x45, 0x1b, 0xbd, 0x79, 0xdc, 0x58, 0x49, 0x78, 0x88, 0xb9}; // CAP_TZERS -const capstr capSimpLite = {0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50}; -const capstr capSimpPro = {0x53, 0x49, 0x4D, 0x50, 0x5F, 0x50, 0x52, 0x4F, 0x53, 0x49, 0x4D, 0x50, 0x5F, 0x50, 0x52, 0x4F}; -const capstr capIMsecure = {'I', 'M', 's', 'e', 'c', 'u', 'r', 'e', 'C', 'p', 'h', 'r', 0x00, 0x00, 0x06, 0x01}; // ZoneLabs -const capstr capIMSecKey1 = {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ZoneLabs -const capstr capIMSecKey2 = {2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ZoneLabs -const capstr capFakeHtml = {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15, 0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}; - -const char* cliLibicq2k = "libicq2000"; -const char* cliLicqVer = "Licq "; -const char* cliCentericq = "Centericq"; -const char* cliLibicqUTF = "libicq2000 (Unicode)"; -const char* cliTrillian = "Trillian"; -const char* cliTrillian4 = "Trillian Astra"; -const char* cliQip = "QIP %s"; -const char* cliIM2 = "IM2"; -const char* cliSpamBot = "Spam Bot"; - -const char* CIcqProto::detectUserClient(HANDLE hContact, int nIsICQ, WORD wUserClass, DWORD dwOnlineSince, const char *szCurrentClient, - WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, BYTE bDirectFlag, DWORD dwDirectCookie, DWORD dwWebPort, /* ICQ specific */ - BYTE *caps, WORD wLen, /* Client capabilities */ - BYTE *bClientId, /* Output: detected client-type */ - char *szClientBuf) -{ - LPCSTR szClient = NULL; - int bMirandaIM = FALSE; - - *bClientId = CLID_ALTERNATIVE; // Most clients does not tick as MsgIDs - - // Is this a Miranda IM client? - if (dwFT1 == 0xffffffff) - { - if (dwFT2 == 0xffffffff) - { // This is Gaim not Miranda - szClient = "Gaim"; - } - else if (!dwFT2 && wVersion == 7) - { // This is WebICQ not Miranda - szClient = "WebICQ"; - } - else if (!dwFT2 && dwFT3 == 0x3B7248ED) - { // And this is most probably Spam Bot - szClient = cliSpamBot; - } - else - { // Yes this is most probably Miranda, get the version info - szClient = MirandaVersionToString(szClientBuf, 0, dwFT2, 0); - *bClientId = CLID_MIRANDA; - bMirandaIM = TRUE; - } - } - else if (dwFT1 == 0x7fffffff) - { // This is Miranda with unicode core - szClient = MirandaVersionToString(szClientBuf, 1, dwFT2, 0); - *bClientId = CLID_MIRANDA; - bMirandaIM = TRUE; - } - else if ((dwFT1 & 0xFF7F0000) == 0x7D000000) - { // This is probably an Licq client - DWORD ver = dwFT1 & 0xFFFF; - - szClient = makeClientVersion(szClientBuf, cliLicqVer, ver / 1000, (ver / 10) % 100, ver % 10, 0); - if (dwFT1 & 0x00800000) - strcat(szClientBuf, "/SSL"); - } - else if (dwFT1 == 0xffffff8f) - { - szClient = "StrICQ"; - } - else if (dwFT1 == 0xffffff42) - { - szClient = "mICQ"; - } - else if (dwFT1 == 0xffffffbe) - { - unsigned ver1 = (dwFT2>>24)&0xFF; - unsigned ver2 = (dwFT2>>16)&0xFF; - unsigned ver3 = (dwFT2>>8)&0xFF; - - szClient = makeClientVersion(szClientBuf, "Alicq ", ver1, ver2, ver3, 0); - } - else if (dwFT1 == 0xFFFFFF7F) - { - szClient = "&RQ"; - } - else if (dwFT1 == 0xFFFFFFAB) - { - szClient = "YSM"; - } - else if (dwFT1 == 0x04031980) - { - szClient = "vICQ"; - } - else if ((dwFT1 == 0x3AA773EE) && (dwFT2 == 0x3AA66380)) - { - szClient = cliLibicq2k; - } - else if (dwFT1 == 0x3B75AC09) - { - szClient = cliTrillian; - } - else if (dwFT1 == 0x3BA8DBAF) // FT2: 0x3BEB5373; FT3: 0x3BEB5262; - { - if (wVersion == 2) - szClient = "stICQ"; - } - else if (dwFT1 == 0xFFFFFFFE && dwFT3 == 0xFFFFFFFE) - { - szClient = "Jimm"; - } - else if (dwFT1 == 0x3FF19BEB && dwFT3 == 0x3FF19BEB) - { - szClient = cliIM2; - } - else if (dwFT1 == 0xDDDDEEFF && !dwFT2 && !dwFT3) - { - szClient = "SmartICQ"; - } - else if ((dwFT1 & 0xFFFFFFF0) == 0x494D2B00 && !dwFT2 && !dwFT3) - { // last byte of FT1: (5 = Win32, 3 = SmartPhone, Pocket PC) - szClient = "IM+"; - } - else if (dwFT1 == 0x3B4C4C0C && !dwFT2 && dwFT3 == 0x3B7248ed) - { - szClient = "KXicq2"; - } - else if (dwFT1 == 0xFFFFF666 && !dwFT3) - { // this is R&Q (Rapid Edition) - null_snprintf(szClientBuf, 64, "R&Q %u", (unsigned)dwFT2); - szClient = szClientBuf; - } - else if (dwFT1 == 0x66666666 && dwFT3 == 0x66666666) - { // http://darkjimm.ucoz.ru/ - if (dwFT2 == 0x10000) - { - strcpy(szClientBuf, "D[i]Chat v."); - strcat(szClientBuf, "0.1a"); - } - else - { - makeClientVersion(szClientBuf, "D[i]Chat v.", (dwFT2 >> 8) & 0x0F, (dwFT2 >> 4) & 0x0F, 0, 0); - if ((dwFT2 & 0x0F) == 1) - strcat(szClientBuf, " alpha"); - else if ((dwFT2 & 0x0F) == 2) - strcat(szClientBuf, " beta"); - else if ((dwFT2 & 0x0F) == 3) - strcat(szClientBuf, " final"); - } - szClient = szClientBuf; - } - else if (dwFT1 == dwFT2 && dwFT2 == dwFT3 && wVersion == 8) - { - if ((dwFT1 < dwOnlineSince + 3600) && (dwFT1 > (dwOnlineSince - 3600))) - { - szClient = cliSpamBot; - } - } - else if (!dwFT1 && !dwFT2 && !dwFT3 && !wVersion && !wLen && dwWebPort == 0x75BB) - { - szClient = cliSpamBot; - } - else if (dwFT1 == 0x44F523B0 && dwFT2 == 0x44F523A6 && dwFT3 == 0x44F523A6 && wVersion == 8) - { - szClient = "Virus"; - } - - { // capabilities based detection - capstr* capId; - - if (nIsICQ && caps) - { - // check capabilities for client identification - if (capId = MatchCapability(caps, wLen, &capMirandaIm, 8)) { - // new Miranda Signature - DWORD iver = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; - DWORD mver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; - - szClient = MirandaVersionToString(szClientBuf, dwFT1 == 0x7fffffff, iver, mver); - - if (MatchCapability(caps, wLen, &capIcqJs7, 0x4)) { - // detect mod - strcat(szClientBuf, " (s7 & sss)"); - if (MatchCapability(caps, wLen, &capIcqJs7, 0xE)) - strcat(szClientBuf, " + SecureIM"); - } - else if ((dwFT1 & 0x7FFFFFFF) == 0x7FFFFFFF) - { - if (MatchCapability(caps, wLen, &capMimMobile)) - strcat(szClientBuf, " (Mobile)"); - - if (dwFT3 == 0x5AFEC0DE) - strcat(szClientBuf, " + SecureIM"); - } - *bClientId = CLID_MIRANDA; - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capMirandaNg, 8)) { - WORD v[4]; - BYTE *buf = *capId + 8; - unpackWord(&buf, &v[0]); unpackWord(&buf, &v[1]); unpackWord(&buf, &v[2]); unpackWord(&buf, &v[3]); - mir_snprintf(szClientBuf, MAX_PATH, "Miranda NG ICQ %d.%d.%d.%d", v[0], v[1], v[2], v[3]); - - szClient = szClientBuf; - if ((dwFT1 & 0x7FFFFFFF) == 0x7FFFFFFF && dwFT3 == 0x5AFEC0DE) - strcat(szClientBuf, " + SecureIM"); - - *bClientId = CLID_MIRANDA; - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capIcqJs7, 4)) - { // detect newer icqj mod - szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ S7 & SSS"); - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capIcqJSin, 4)) - { // detect newer icqj mod - szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ S!N"); - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capIcqJp, 4)) - { // detect icqj plus mod - szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ Plus"); - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capMraJava, 12)) - { - unsigned ver1 = (*capId)[13]; - unsigned ver2 = (*capId)[14]; - - szClient = makeClientVersion(szClientBuf, "Mail.ru Agent (Java) v", ver1, ver2, 0, 0); - } - else if (MatchCapability(caps, wLen, &capTrillian) || MatchCapability(caps, wLen, &capTrilCrypt)) - { // this is Trillian, check for new versions - if (CheckContactCapabilities(hContact, CAPF_RTF)) - { - if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) - szClient = cliTrillian4; - else - { // workaroud for a bug in Trillian - make it receive msgs, other features will not work! - ClearContactCapabilities(hContact, CAPF_SRV_RELAY); - szClient = "Trillian v3"; - } - } - else if (MatchCapability(caps, wLen, &capFakeHtml) || CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) - szClient = cliTrillian4; - else - szClient = cliTrillian; - } - else if ((capId = MatchCapability(caps, wLen, &capSimOld, 0xF)) && ((*capId)[0xF] != 0x92 && (*capId)[0xF] >= 0x20 || (*capId)[0xF] == 0)) - { - int hiVer = (((*capId)[0xF]) >> 6) - 1; - unsigned loVer = (*capId)[0xF] & 0x1F; - - if ((hiVer < 0) || ((hiVer == 0) && (loVer == 0))) - szClient = "Kopete"; - else - szClient = makeClientVersion(szClientBuf, "SIM ", (unsigned)hiVer, loVer, 0, 0); - } - else if (capId = MatchCapability(caps, wLen, &capSim, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, ver4 & 0x0F); - if (ver4 & 0x80) - strcat(szClientBuf,"/Win32"); - else if (ver4 & 0x40) - strcat(szClientBuf,"/MacOS X"); - } - else if (capId = MatchCapability(caps, wLen, &capLicq, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD] % 100; - unsigned ver3 = (*capId)[0xE]; - - szClient = makeClientVersion(szClientBuf, cliLicqVer, ver1, ver2, ver3, 0); - if ((*capId)[0xF]) - strcat(szClientBuf,"/SSL"); - } - else if (capId = MatchCapability(caps, wLen, &capKopete, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4); - } - else if (capId = MatchCapability(caps, wLen, &capClimm, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "climm ", ver1, ver2, ver3, ver4); - if ((ver1 & 0x80) == 0x80) - strcat(szClientBuf, " alpha"); - if (dwFT3 == 0x02000020) - strcat(szClientBuf, "/Win32"); - else if (dwFT3 == 0x03000800) - strcat(szClientBuf, "/MacOS X"); - } - else if (capId = MatchCapability(caps, wLen, &capmIcq, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "mICQ ", ver1, ver2, ver3, ver4); - if ((ver1 & 0x80) == 0x80) - strcat(szClientBuf, " alpha"); - } - else if (MatchCapability(caps, wLen, &capIm2)) - { // IM2 v2 provides also Aim Icon cap - szClient = cliIM2; - } - else if (capId = MatchCapability(caps, wLen, &capAndRQ, 9)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xB]; - unsigned ver3 = (*capId)[0xA]; - unsigned ver4 = (*capId)[9]; - - szClient = makeClientVersion(szClientBuf, "&RQ ", ver1, ver2, ver3, ver4); - } - else if (capId = MatchCapability(caps, wLen, &capRAndQ, 9)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xB]; - unsigned ver3 = (*capId)[0xA]; - unsigned ver4 = (*capId)[9]; - - szClient = makeClientVersion(szClientBuf, "R&Q ", ver1, ver2, ver3, ver4); - } - else if (MatchCapability(caps, wLen, &capIMadering)) - { // http://imadering.com - szClient = "IMadering"; - } - else if (MatchCapability(caps, wLen, &capQipPDA)) - { - szClient = "QIP PDA (Windows)"; - } - else if (MatchCapability(caps, wLen, &capQipSymbian)) - { - szClient = "QIP PDA (Symbian)"; - } - else if (MatchCapability(caps, wLen, &capQipIphone)) - { - szClient = "QIP Mobile (IPhone)"; - } - else if (MatchCapability(caps, wLen, &capQipMobile)) - { - szClient = "QIP Mobile (Java)"; - } - else if (MatchCapability(caps, wLen, &capQipInfium)) - { - char ver[10]; - - strcpy(szClientBuf, "QIP Infium"); - if (dwFT1) - { // add build - null_snprintf(ver, 10, " (%d)", dwFT1); - strcat(szClientBuf, ver); - } - if (dwFT2 == 0x0B) - strcat(szClientBuf, " Beta"); - - szClient = szClientBuf; - } - else if (MatchCapability(caps, wLen, &capQip2010, 12)) - { - char ver[10]; - - strcpy(szClientBuf, "QIP 2010"); - if (dwFT1) - { // add build - null_snprintf(ver, 10, " (%d)", dwFT1); - strcat(szClientBuf, ver); - } - - szClient = szClientBuf; - } - else if (MatchCapability(caps, wLen, &capQip2012, 12)) - { - char ver[10]; - - strcpy(szClientBuf, "QIP 2012"); - if (dwFT1) - { // add build - null_snprintf(ver, 10, " (%d)", dwFT1); - strcat(szClientBuf, ver); - } - - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capQip, 0xE)) - { - char ver[10]; - - if (dwFT3 == 0x0F) - strcpy(ver, "2005"); - else - null_strcpy(ver, (char*)(*capId) + 11, 5); - - null_snprintf(szClientBuf, 64, cliQip, ver); - if (dwFT1 && dwFT2 == 0x0E) - { // add QIP build - null_snprintf(ver, 10, " (%d%d%d%d)", dwFT1 >> 0x18, (dwFT1 >> 0x10) & 0xFF, (dwFT1 >> 0x08) & 0xFF, dwFT1 & 0xFF); - strcat(szClientBuf, ver); - } - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capmChat, 0xA)) - { - strcpy(szClientBuf, "mChat "); - strncat(szClientBuf, (char*)(*capId) + 0xA, 6); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capJimm, 5)) - { - strcpy(szClientBuf, "Jimm "); - strncat(szClientBuf, (char*)(*capId) + 5, 11); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capCorePager, 0xA)) - { // http://corepager.net.ru/index/0-2 - strcpy(szClientBuf, "CORE Pager"); - if (dwFT2 == 0x0FFFF0011 && dwFT3 == 0x1100FFFF && (dwFT1 >> 0x18)) - { - char ver[16]; - - null_snprintf(ver, 10, " %d.%d", dwFT1 >> 0x18, (dwFT1 >> 0x10) & 0xFF); - if ((dwFT1 & 0xFF) == 0x0B) - strcat(ver, " Beta"); - strcat(szClientBuf, ver); - } - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capDiChat, 9)) - { // http://darkjimm.ucoz.ru/ - strcpy(szClientBuf, "D[i]Chat"); - strncat(szClientBuf, (char*)(*capId) + 8, 8); - szClient = szClientBuf; - } - else if (MatchCapability(caps, wLen, &capMacIcq)) - { - szClient = "ICQ for Mac"; - } - else if (MatchCapability(caps, wLen, &capUim)) - { - szClient = "uIM"; - } - else if (MatchCapability(caps, wLen, &capAnastasia)) - { // http://chis.nnov.ru/anastasia - szClient = "Anastasia"; - } - else if (capId = MatchCapability(caps, wLen, &capPalmJicq, 0xC)) - { // http://www.jsoft.ru - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "JICQ ", ver1, ver2, ver3, ver4); - } - else if (MatchCapability(caps, wLen, &capInluxMsgr)) - { // http://www.inlusoft.com - szClient = "Inlux Messenger"; - } - else if (capId = MatchCapability(caps, wLen, &capMipClient, 0xC)) - { // http://mip.rufon.net - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - if (ver1 < 30) - { - makeClientVersion(szClientBuf, "MIP ", ver1, ver2, ver3, ver4); - } - else - { - strcpy(szClientBuf, "MIP "); - strncat(szClientBuf, (char*)(*capId) + 11, 5); - } - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capMipClient, 0x04)) - { //http://mip.rufon.net - new signature - strcpy(szClientBuf, "MIP "); - strncat(szClientBuf, (char*)(*capId) + 4, 12); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capVmIcq, 0x06)) - { - strcpy(szClientBuf, "VmICQ"); - strncat(szClientBuf, (char*)(*capId) + 5, 11); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capSmapeR, 0x07)) - { // http://www.smape.com/smaper - strcpy(szClientBuf, "SmapeR"); - strncat(szClientBuf, (char*)(*capId) + 6, 10); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capYapp, 0x04)) - { // http://yapp.ru - strcpy(szClientBuf, "Yapp! v"); - strncat(szClientBuf, (char*)(*capId) + 8, 5); - szClient = szClientBuf; - } - else if (MatchCapability(caps, wLen, &capDigsby, 0x06)) - { // http://www.dibsby.com (newer builds) - szClient = "Digsby"; - } - else if (MatchCapability(caps, wLen, &capDigsbyBeta)) - { // http://www.digsby.com - probably by mistake (feature detection as well) - szClient = "Digsby"; - } - else if (MatchCapability(caps, wLen, &capJapp)) - { // http://www.japp.org.ua - szClient = "japp"; - } - else if (MatchCapability(caps, wLen, &capPigeon, 0x07)) - { // http://pigeon.vpro.ru - szClient = "PIGEON!"; - } - else if (capId = MatchCapability(caps, wLen, &capQutIm, 0x05)) - { // http://www.qutim.org - if ((*capId)[0x6] == 0x2E) - { // old qutim id - unsigned ver1 = (*capId)[0x5] - 0x30; - unsigned ver2 = (*capId)[0x7] - 0x30; - - makeClientVersion(szClientBuf, "qutIM ", ver1, ver2, 0, 0); - } - else - { // new qutim id - unsigned ver1 = (*capId)[0x6]; - unsigned ver2 = (*capId)[0x7]; - unsigned ver3 = (*capId)[0x8]; - unsigned ver4 = ((*capId)[0x9] << 8) || (*capId)[0xA]; - - makeClientVersion(szClientBuf, "qutIM ", ver1, ver2, ver3, ver4); - - switch ((*capId)[0x5]) - { - case 'l': - strcat(szClientBuf, "/Linux"); - break; - case 'w': - strcat(szClientBuf, "/Win32"); - break; - case 'm': - strcat(szClientBuf, "/MacOS X"); - break; - } - } - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capBayan, 8)) - { // http://www.barobin.com/bayanICQ.html - strcpy(szClientBuf, "bayanICQ "); - strncat(szClientBuf, (char*)(*capId) + 8, 5); - szClient = szClientBuf; - } - else if (capId = MatchCapability(caps, wLen, &capJabberJIT, 0x04)) - { - szClient = "Jabber ICQ Transport"; - } - else if (capId = MatchCapability(caps, wLen, &capIcqKid2, 0x07)) - { // http://sourceforge.net/projects/icqkid2 - unsigned ver1 = (*capId)[0x7]; - unsigned ver2 = (*capId)[0x8]; - unsigned ver3 = (*capId)[0x9]; - unsigned ver4 = (*capId)[0xA]; - - szClient = makeClientVersion(szClientBuf, "IcqKid2 v", ver1, ver2, ver3, ver4); - } - else if (capId = MatchCapability(caps, wLen, &capWebIcqPro, 0x0A)) - { // http://intrigue.ru/workshop/webicqpro/webicqpro.html - szClient = "WebIcqPro"; - } - else if (capId = MatchCapability(caps, wLen, &capCitron)) - { // http://www.citron-im.com - szClient = "Citron IM"; - } - else if (szClient == cliLibicq2k) - { // try to determine which client is behind libicq2000 - if (CheckContactCapabilities(hContact, CAPF_RTF)) - szClient = cliCentericq; // centericq added rtf capability to libicq2000 - else if (CheckContactCapabilities(hContact, CAPF_UTF)) - szClient = cliLibicqUTF; // IcyJuice added unicode capability to libicq2000 - // others - like jabber transport uses unmodified library, thus cannot be detected - } - else if (szClient == NULL) // HERE ENDS THE SIGNATURE DETECTION, after this only feature default will be detected - { - if (wVersion == 8 && CheckContactCapabilities(hContact, CAPF_XTRAZ) && (MatchCapability(caps, wLen, &capIMSecKey1, 6) || MatchCapability(caps, wLen, &capIMSecKey2, 6))) - { // ZA mangled the version, OMG! - wVersion = 9; - } - if (wVersion == 8 && (MatchCapability(caps, wLen, &capComm20012) || CheckContactCapabilities(hContact, CAPF_SRV_RELAY))) - { // try to determine 2001-2003 versions - if (MatchCapability(caps, wLen, &capIs2001)) - { - if (!dwFT1 && !dwFT2 && !dwFT3) - if (CheckContactCapabilities(hContact, CAPF_RTF)) - szClient = "TICQClient"; // possibly also older GnomeICU - else - szClient = "ICQ for Pocket PC"; - else - { - *bClientId = CLID_GENERIC; - szClient = "ICQ 2001"; - } - } - else if (MatchCapability(caps, wLen, &capIs2002)) - { - *bClientId = CLID_GENERIC; - szClient = "ICQ 2002"; - } - else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_RTF)) - { - if (!dwFT1 && !dwFT2 && !dwFT3) - { - if (!dwWebPort) - szClient = "GnomeICU 0.99.5+"; // no other way - else - szClient = "IC@"; - } - else - { - *bClientId = CLID_GENERIC; - szClient = "ICQ 2002/2003a"; - } - } - else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && - MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && - MatchCapability(caps, wLen, &capFakeHtml)) - { // libpurple (e.g. Pidgin 2.7.x) - if (MatchShortCapability(caps, wLen, &capAimDirect)) - szClient = "libpurple"; - else - szClient = "Meebo"; - } - else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING)) - { - if (!dwFT1 && !dwFT2 && !dwFT3) - { - szClient = "PreludeICQ"; - } - } - } - else if (wVersion == 8) - { - if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect)) - szClient = "imo.im"; //https://imo.im/ - Web IM - } - else if (wVersion == 9) - { // try to determine lite versions - if (CheckContactCapabilities(hContact, CAPF_XTRAZ)) - { - *bClientId = CLID_GENERIC; - if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) - { - if (MatchCapability(caps, wLen, &captZers)) - { // capable of tZers ? - if (MatchCapability(caps, wLen, &capIcqLiteNew) && MatchShortCapability(caps, wLen, &capStatusTextAware) && - MatchShortCapability(caps, wLen, &capAimLiveVideo) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) - { - strcpy(szClientBuf, "ICQ 7"); - } - else if (MatchCapability(caps, wLen, &capFakeHtml)) - { - if (MatchShortCapability(caps, wLen, &capAimLiveVideo) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) - { - strcpy(szClientBuf, "ICQ 6"); - *bClientId = CLID_ICQ6; - } - else if (CheckContactCapabilities(hContact, CAPF_RTF) && !CheckContactCapabilities(hContact, CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capIcqDevils)) - { - strcpy(szClientBuf, "Qnext v4"); // finally handles SRV_RELAY correctly - *bClientId = CLID_ALTERNATIVE; - } - } - else - { - strcpy(szClientBuf, "icq5.1"); - } - } - else - { - strcpy(szClientBuf, "icq5"); - } - - if (MatchCapability(caps, wLen, &capRambler)) - { - strcat(szClientBuf, " (Rambler)"); - } - else if (MatchCapability(caps, wLen, &capAbv)) - { - strcat(szClientBuf, " (Abv)"); - } - else if (MatchCapability(caps, wLen, &capNetvigator)) - { - strcat(szClientBuf, " (Netvigator)"); - } - szClient = szClientBuf; - } - else if (!CheckContactCapabilities(hContact, CAPF_ICQDIRECT)) - { - *bClientId = CLID_ALTERNATIVE; - if (CheckContactCapabilities(hContact, CAPF_RTF)) - { - // most probably Qnext - try to make that shit at least receiving our msgs - ClearContactCapabilities(hContact, CAPF_SRV_RELAY); - NetLog_Server("Forcing simple messages (QNext client)."); - szClient = "Qnext"; - } - else if (CheckContactCapabilities(hContact, CAPF_TYPING) && MatchCapability(caps, wLen, &captZers) && MatchCapability(caps, wLen, &capFakeHtml)) - { - if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) - szClient = "Mail.ru Agent (PC)"; - else - szClient = "Fring"; - } - else - szClient = "pyICQ"; - } - else - szClient = "ICQ Lite v4"; - } - else if (MatchCapability(caps, wLen, &capIcqLiteNew)) - szClient = "ICQ Lite"; // the new ICQ Lite based on ICQ6 - else if (!CheckContactCapabilities(hContact, CAPF_ICQDIRECT)) - { - if (MatchCapability(caps, wLen, &capFakeHtml) && MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimSmartCaps)) - szClient = cliTrillian4; - else if (CheckContactCapabilities(hContact, CAPF_UTF) && !CheckContactCapabilities(hContact, CAPF_RTF)) - szClient = "pyICQ"; - } - } - else if (wVersion == 7) - { - if (CheckContactCapabilities(hContact, CAPF_RTF)) - szClient = "GnomeICU"; // this is an exception - else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) - { - if (!dwFT1 && !dwFT2 && !dwFT3) - szClient = "&RQ"; - else - { - *bClientId = CLID_GENERIC; - szClient = "ICQ 2000"; - } - } - else if (CheckContactCapabilities(hContact, CAPF_UTF)) - { - if (CheckContactCapabilities(hContact, CAPF_TYPING)) - szClient = "Icq2Go! (Java)"; - else if (wUserClass & CLASS_WIRELESS) - szClient = "Pocket Web 1&1"; - else - szClient = "Icq2Go!"; - } - } - else if (wVersion == 0xA) - { - if (!CheckContactCapabilities(hContact, CAPF_RTF) && !CheckContactCapabilities(hContact, CAPF_UTF)) - { // this is bad, but we must do it - try to detect QNext - ClearContactCapabilities(hContact, CAPF_SRV_RELAY); - NetLog_Server("Forcing simple messages (QNext client)."); - szClient = "Qnext"; - } - else if (!CheckContactCapabilities(hContact, CAPF_RTF) && CheckContactCapabilities(hContact, CAPF_UTF) && !dwFT1 && !dwFT2 && !dwFT3) - { // not really good, but no other option - szClient = "NanoICQ"; - } - } - else if (wVersion == 0xB) - { - if (CheckContactCapabilities(hContact, CAPF_XTRAZ | CAPF_SRV_RELAY | CAPF_TYPING | CAPF_UTF) && MatchShortCapability(caps, wLen, &capIcqDevils)) - { - szClient = "Mail.ru Agent (Symbian)"; - } - } - else if (wVersion == 0) - { // capability footprint based detection - not really reliable - if (!dwFT1 && !dwFT2 && !dwFT3 && !dwWebPort && !dwDirectCookie) - { // DC info is empty - if (CheckContactCapabilities(hContact, CAPF_TYPING) && MatchCapability(caps, wLen, &capIs2001) && - MatchCapability(caps, wLen, &capIs2002) && MatchCapability(caps, wLen, &capComm20012)) - szClient = cliSpamBot; - else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && - CheckContactCapabilities(hContact, CAPF_OSCAR_FILE | CAPF_UTF)) - { // detect libgaim/libpurple versions - if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) - szClient = "Adium X"; // yeah, AFAIK only Adium has this fixed - else if (CheckContactCapabilities(hContact, CAPF_TYPING)) - szClient = "libpurple"; - else - szClient = "libgaim"; - } - else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && - MatchCapability(caps, wLen, &capOscarChat) && CheckContactCapabilities(hContact, CAPF_OSCAR_FILE) && wLen == 0x40) - szClient = "libgaim"; // Gaim 1.5.1 most probably - else if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE) && MatchCapability(caps, wLen, &capOscarChat) && wLen == 0x20) - szClient = "Easy Message"; - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capOscarChat) && wLen == 0x40) - szClient = "Meebo"; - else if (CheckContactCapabilities(hContact, CAPF_UTF) && MatchShortCapability(caps, wLen, &capAimIcon) && wLen == 0x20) - szClient = "PyICQ-t Jabber Transport"; - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_XTRAZ) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capXtrazVideo)) - szClient = "PyICQ-t Jabber Transport"; - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_ICQDIRECT | CAPF_TYPING) && wLen == 0x40) - szClient = "Agile Messenger"; // Smartphone 2002 - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_ICQDIRECT | CAPF_OSCAR_FILE) && MatchShortCapability(caps, wLen, &capAimFileShare)) - szClient = "Slick"; // http://lonelycatgames.com/?app=slick - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_OSCAR_FILE | CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capAimFileShare) && MatchShortCapability(caps, wLen, &capAimIcon)) - szClient = "Digsby"; // http://www.digsby.com - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capFakeHtml)) - szClient = "mundu IM"; // http://messenger.mundu.com - else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_OSCAR_FILE) && MatchCapability(caps, wLen, &capOscarChat)) - szClient = "eBuddy"; //http://www.ebuddy.com - else if (CheckContactCapabilities(hContact, CAPF_CONTACTS | CAPF_OSCAR_FILE) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && MatchCapability(caps, wLen, &capOscarChat)) - szClient = "IloveIM"; //http://www.iloveim.com/ - - } - } - } - } - else if (!nIsICQ) - { // detect AIM clients - if (caps) - { - if (capId = MatchCapability(caps, wLen, &capAimOscar, 8)) - { // AimOscar Signature - DWORD aver = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; - DWORD mver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; - - szClient = MirandaVersionToStringEx(szClientBuf, 0, "AimOscar", aver, mver); - bMirandaIM = TRUE; - } - else if (capId = MatchCapability(caps, wLen, &capSim, 0xC)) - { // Sim is universal - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - - szClient = makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, 0); - if ((*capId)[0xF] & 0x80) - strcat(szClientBuf,"/Win32"); - else if ((*capId)[0xF] & 0x40) - strcat(szClientBuf,"/MacOS X"); - } - else if (capId = MatchCapability(caps, wLen, &capKopete, 0xC)) - { - unsigned ver1 = (*capId)[0xC]; - unsigned ver2 = (*capId)[0xD]; - unsigned ver3 = (*capId)[0xE]; - unsigned ver4 = (*capId)[0xF]; - - szClient = makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4); - } - else if (MatchCapability(caps, wLen, &capIm2)) - { // IM2 extensions - szClient = cliIM2; - } - else if (MatchCapability(caps, wLen, &capNaim, 0x8)) - { - szClient = "naim"; - } - else if (MatchCapability(caps, wLen, &capDigsby, 0x06) || MatchCapability(caps, wLen, &capDigsbyBeta)) - { // http://www.dibsby.com - szClient = "Digsby"; - } - else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capOscarChat) && - CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && wLen == 0x40) - szClient = "Meebo"; - else if (wLen == 0x90 && CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && - MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && - MatchShortCapability(caps, wLen, &capAimDirect) && MatchCapability(caps, wLen, &capFakeHtml)) - { // libpurple (e.g. Pidgin 2.7.x) - szClient = "libpurple"; - } - else if (wLen == 0x70 && CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && - MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && - MatchCapability(caps, wLen, &capFakeHtml)) - { // libpurple - Meebo (without DirectIM and OFT) - szClient = "Meebo"; - } - else - szClient = "AIM"; - } - else if(wUserClass & CLASS_WIRELESS) - szClient = "AIM (Mobile)"; - else - szClient = "AIM"; - } - } - if (caps && bMirandaIM) - { // custom miranda packs - capstr* capId; - - if (capId = MatchCapability(caps, wLen, &capMimPack, 4)) - { - char szPack[16]; - - null_snprintf(szPack, 16, " [%.12s]", (*capId)+4); - - if (szClient != szClientBuf) - { // make sure client string is not constant - strcpy(szClientBuf, szClient); - szClient = szClientBuf; - } - - strcat(szClientBuf, szPack); - } - } - - BOOL bClientDetected = (szClient != NULL); - - if (!szClient) - { - *bClientId = CLID_GENERIC; - - switch (wVersion) - { // client detection failed, provide default clients - case 6: - szClient = "ICQ99"; - break; - case 7: - szClient = "ICQ 2000/Icq2Go"; - break; - case 8: - szClient = "ICQ 2001-2003a"; - break; - case 9: - szClient = "ICQ Lite"; - break; - case 0xA: - szClient = "ICQ 2003b"; - } - } - - if (szClient) - { - char *szExtra = NULL; - - if (MatchCapability(caps, wLen, &capSimpLite)) - szExtra = " + SimpLite"; - else if (MatchCapability(caps, wLen, &capSimpPro)) - szExtra = " + SimpPro"; - else if (MatchCapability(caps, wLen, &capIMsecure) || MatchCapability(caps, wLen, &capIMSecKey1, 6) || MatchCapability(caps, wLen, &capIMSecKey2, 6)) - szExtra = " + IMsecure"; - - if (szExtra) - { - if (szClient != szClientBuf) - { - strcpy(szClientBuf, szClient); - szClient = szClientBuf; - } - strcat(szClientBuf, szExtra); - } - } - - if (!szCurrentClient || strcmpnull(szCurrentClient, szClient)) - { // Log the detection result if it has changed or contact just logged on... - if (bClientDetected) - NetLog_Server("Client identified as %s", szClient); - else - NetLog_Server("No client identification, put default ICQ client for protocol."); - } - - return szClient; -} diff --git a/protocols/IcqOscarJ/icq_constants.h b/protocols/IcqOscarJ/icq_constants.h deleted file mode 100644 index 4da90f1bc0..0000000000 --- a/protocols/IcqOscarJ/icq_constants.h +++ /dev/null @@ -1,652 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Global constants and default settings are defined here -// -// ----------------------------------------------------------------------------- -// Most of the protocol constants follow the naming conventions of the -// Oscar documentation at http://iserverd.khstu.ru/oscar/index.html -// BIG THANKS to Alexandr for maintaining this site and to everyone -// in the ICQ devel community who have helped to collect the data. - -#ifndef __ICQ_CONSTANTS_H -#define __ICQ_CONSTANTS_H - - -/* Static icon indexes */ -#define ISI_AUTH_REQUEST 0 -#define ISI_AUTH_GRANT 1 -#define ISI_AUTH_REVOKE 2 -#define ISI_ADD_TO_SERVLIST 3 - -/* Contact menu item indexes */ -#define ICMI_AUTH_REQUEST 0 -#define ICMI_AUTH_GRANT 1 -#define ICMI_AUTH_REVOKE 2 -#define ICMI_ADD_TO_SERVLIST 3 -#define ICMI_XSTATUS_DETAILS 4 -#define ICMI_OPEN_PROFILE 5 - -/* Some default settings */ -#define DEFAULT_SERVER_PORT 5190 -#define DEFAULT_SERVER_PORT_SSL 443 -#define DEFAULT_SERVER_HOST "login.icq.com" -#define DEFAULT_SERVER_HOST_SSL "slogin.icq.com" -#define DEFAULT_SS_ENABLED 1 -#define DEFAULT_SS_ADDSERVER 1 -#define DEFAULT_SS_LOAD 0 -#define DEFAULT_SS_STORE 1 -#define DEFAULT_SS_GROUP "General" - -#define DEFAULT_SECURE_LOGIN 1 -#define DEFAULT_SECURE_CONNECTION 1 -#define DEFAULT_KEEPALIVE_ENABLED 1 -#define DEFAULT_AIM_ENABLED 1 -#define DEFAULT_UTF_ENABLED 2 // everything unicode is default -#define DEFAULT_ANSI_CODEPAGE CP_ACP -#define DEFAULT_DCMSG_ENABLED 1 // passive dc messaging is default -#define DEFAULT_TEMPVIS_ENABLED 1 // temporary visible is enabled by default -#define DEFAULT_MTN_ENABLED 1 -#define DEFAULT_AVATARS_ENABLED 1 -#define DEFAULT_LOAD_AVATARS 1 -#define DEFAULT_BIGGER_AVATARS 0 -#define DEFAULT_AVATARS_CHECK 1 -#define DEFAULT_XSTATUS_ENABLED 0 -#define DEFAULT_XSTATUS_AUTO 1 -#define DEFAULT_XSTATUS_RESET 0 -#define DEFAULT_MOODS_ENABLED 1 -#define DEFAULT_KILLSPAM_ENABLED 1 - -#define DEFAULT_SLOWSEND 1 -#define DEFAULT_ONLYSERVERACKS 1 - -#define DEFAULT_POPUPS_ENABLED 1 -#define DEFAULT_SPAM_POPUPS_ENABLED 1 -#define DEFAULT_LOG_POPUPS_ENABLED 1 -#define DEFAULT_POPUPS_SYS_ICONS 1 -#define DEFAULT_LOG0_TEXT_COLORS RGB(0,0,0) // LOG_NOTE -#define DEFAULT_LOG0_BACK_COLORS RGB(255,255,255) -#define DEFAULT_LOG0_TIMEOUT 0 -#define DEFAULT_LOG1_TEXT_COLORS RGB(0,0,0) // LOG_WARNING -#define DEFAULT_LOG1_BACK_COLORS RGB(255,255,255) -#define DEFAULT_LOG1_TIMEOUT 0 -#define DEFAULT_LOG2_TEXT_COLORS RGB(0,0,0) // LOG_ERROR -#define DEFAULT_LOG2_BACK_COLORS RGB(255,255,255) -#define DEFAULT_LOG2_TIMEOUT 0 -#define DEFAULT_LOG3_TEXT_COLORS RGB(0,0,0) // LOG_FATAL -#define DEFAULT_LOG3_BACK_COLORS RGB(255,255,255) -#define DEFAULT_LOG3_TIMEOUT 0 -#define DEFAULT_SPAM_TEXT_COLORS RGB(193,0,38) -#define DEFAULT_SPAM_BACK_COLORS RGB(213,209,208) -#define DEFAULT_SPAM_TIMEOUT 0 -#define DEFAULT_POPUPS_WIN_COLORS 0 -#define DEFAULT_POPUPS_DEF_COLORS (BYTE)!DEFAULT_POPUPS_WIN_COLORS - -/* Database setting names */ -#define DBSETTING_CAPABILITIES "caps" -// Contact's server-list items -#define DBSETTING_SERVLIST_ID "ServerId" -#define DBSETTING_SERVLIST_GROUP "SrvGroupId" -#define DBSETTING_SERVLIST_PERMIT "SrvPermitId" -#define DBSETTING_SERVLIST_DENY "SrvDenyId" -#define DBSETTING_SERVLIST_IGNORE "SrvIgnoreId" -// Owner's server-list items -#define DBSETTING_SERVLIST_PRIVACY "SrvVisibilityID" -#define DBSETTING_SERVLIST_PHOTO "SrvPhotoID" -#define DBSETTING_SERVLIST_AVATAR "SrvAvatarID" -#define DBSETTING_SERVLIST_METAINFO "SrvMetaInfoID" -#define DBSETTING_SERVLIST_UNHANDLED "SrvUnhandledIDList" -// Contact's data from server-list -#define DBSETTING_SERVLIST_DATA "ServerData" -// User Details -#define DBSETTING_METAINFO_TOKEN "MetaInfoToken" -#define DBSETTING_METAINFO_TIME "MetaInfoTime" -#define DBSETTING_METAINFO_SAVED "InfoTS" -// Status Note & Mood -#define DBSETTING_STATUS_NOTE "StatusNote" -#define DBSETTING_STATUS_NOTE_TIME "StatusNoteTS" -#define DBSETTING_STATUS_MOOD "StatusMood" -// Custom Status -#define DBSETTING_XSTATUS_ID "XStatusId" -#define DBSETTING_XSTATUS_NAME "XStatusName" -#define DBSETTING_XSTATUS_MSG "XStatusMsg" - - -// Status FLAGS (used to determine status of other users) -#define ICQ_STATUSF_ONLINE 0x0000 -#define ICQ_STATUSF_AWAY 0x0001 -#define ICQ_STATUSF_DND 0x0002 -#define ICQ_STATUSF_NA 0x0004 -#define ICQ_STATUSF_OCCUPIED 0x0010 -#define ICQ_STATUSF_FFC 0x0020 -#define ICQ_STATUSF_INVISIBLE 0x0100 - -// Status values (used to set own status) -#define ICQ_STATUS_ONLINE 0x0000 -#define ICQ_STATUS_AWAY 0x0001 -#define ICQ_STATUS_NA 0x0005 -#define ICQ_STATUS_OCCUPIED 0x0011 -#define ICQ_STATUS_DND 0x0013 -#define ICQ_STATUS_FFC 0x0020 -#define ICQ_STATUS_INVISIBLE 0x0100 - -#define STATUS_WEBAWARE 0x0001 // Status webaware flag -#define STATUS_SHOWIP 0x0002 // Status show ip flag -#define STATUS_BIRTHDAY 0x0008 // User birthday flag -#define STATUS_WEBFRONT 0x0020 // User active webfront flag -#define STATUS_DCDISABLED 0x0100 // Direct connection not supported -#define STATUS_DCAUTH 0x1000 // Direct connection upon authorization -#define STATUS_DCCONT 0x2000 // DC only with contact users - - - -// Typing notification statuses -#define MTN_FINISHED 0x0000 -#define MTN_TYPED 0x0001 -#define MTN_BEGUN 0x0002 -#define MTN_WINDOW_CLOSED 0x000F - - - -// Ascii Capability IDs -#define CAP_RTFMSGS "{97B12751-243C-4334-AD22-D6ABF73F1492}" -#define CAP_UTF8MSGS "{0946134E-4C7F-11D1-8222-444553540000}" - -// Binary Capability Sizes -#define BINARY_CAP_SIZE 16 -#define BINARY_SHORT_CAP_SIZE 2 - -// Binary Capability IDs -#define CAP_SRV_RELAY 0x09, 0x46, 0x13, 0x49, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 -#define CAP_UTF 0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 -#define CAP_RTF 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92 -#define CAP_CONTACTS 0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 -#define CAP_TYPING 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3 -#define CAP_ICQDIRECT 0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 -#define CAP_XTRAZ 0x1A, 0x09, 0x3C, 0x6C, 0xD7, 0xFD, 0x4E, 0xC5, 0x9D, 0x51, 0xA6, 0x47, 0x4E, 0x34, 0xF5, 0xA0 -#define CAP_OSCAR_FILE 0x09, 0x46, 0x13, 0x43, 0x4C, 0x7F, 0x11, 0xD1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 - -// Miranda IM Capability bitmask -#define CAPF_SRV_RELAY 0x00000001 -#define CAPF_UTF 0x00000002 -#define CAPF_RTF 0x00000004 -#define CAPF_CONTACTS 0x00000010 -#define CAPF_TYPING 0x00000020 -#define CAPF_ICQDIRECT 0x00000080 -#define CAPF_XTRAZ 0x00000100 -#define CAPF_OSCAR_FILE 0x00000400 -#define CAPF_STATUS_MESSAGES 0x10000000 -#define CAPF_STATUS_MOOD 0x40000000 -#define CAPF_XSTATUS 0x80000000 - - -// Message Capability IDs -#define MCAP_SRV_RELAY_FMT_s 0x09461349, 0x4c7f11d1, 0x82224445, 0x53540000 -#define MCAP_REVERSE_DC_REQ_s 0x09461344, 0x4c7f11d1, 0x82224445, 0x53540000 -#define MCAP_FILE_TRANSFER_s 0x09461343, 0x4c7f11d1, 0x82224445, 0x53540000 -#define MCAP_CONTACTS_s 0x0946134b, 0x4c7f11d1, 0x82224445, 0x53540000 - -// Plugin Type GUIDs -#define PSIG_MESSAGE_s 0x00000000, 0x00000000, 0x00000000, 0x00000000 -#define PSIG_INFO_PLUGIN_s 0xa0e93f37, 0x4fe9d311, 0xbcd20004, 0xac96dd96 -#define PSIG_STATUS_PLUGIN_s 0x10cf40d1, 0x4fe9d311, 0xbcd20004, 0xac96dd96 - -// Plugin Message GUIDs -#define PMSG_QUERY_INFO_s 0xF002BF71, 0x4371D311, 0x8DD20010, 0x4B06462E -#define PMSG_QUERY_STATUS_s 0x10180670, 0x5471D311, 0x8DD20010, 0x4B06462E - - - -// Message types -#define MTYPE_PLAIN 0x01 // Plain text (simple) message -#define MTYPE_CHAT 0x02 // Chat request message -#define MTYPE_FILEREQ 0x03 // File request / file ok message -#define MTYPE_URL 0x04 // URL message (0xFE formatted) -#define MTYPE_AUTHREQ 0x06 // Authorization request message (0xFE formatted) -#define MTYPE_AUTHDENY 0x07 // Authorization denied message (0xFE formatted) -#define MTYPE_AUTHOK 0x08 // Authorization given message (empty) -#define MTYPE_SERVER 0x09 // Message from OSCAR server (0xFE formatted) -#define MTYPE_ADDED 0x0C // "You-were-added" message (0xFE formatted) -#define MTYPE_WWP 0x0D // Web pager message (0xFE formatted) -#define MTYPE_EEXPRESS 0x0E // Email express message (0xFE formatted) -#define MTYPE_CONTACTS 0x13 // Contact list message -#define MTYPE_PLUGIN 0x1A // Plugin message described by text string -#define MTYPE_AUTOONLINE 0xE7 // Auto online message (internal only) -#define MTYPE_AUTOAWAY 0xE8 // Auto away message -#define MTYPE_AUTOBUSY 0xE9 // Auto occupied message -#define MTYPE_AUTONA 0xEA // Auto not available message -#define MTYPE_AUTODND 0xEB // Auto do not disturb message -#define MTYPE_AUTOFFC 0xEC // Auto free for chat message -// Internal Message types -#define MTYPE_UNKNOWN 0x00 // Unknown message - -#define MTYPE_GREETINGCARD 0x101 // Greeting Card -#define MTYPE_REQUESTCONTACTS 0x102 // Request for Contacts -#define MTYPE_MESSAGE 0x103 // Message+ -#define MTYPE_STATUSMSGEXT 0x104 // StatusMsgExt (2003b) -#define MTYPE_SMS_MESSAGE 0x110 // SMS message from Mobile -#define MTYPE_SCRIPT_INVITATION 0x201 // Xtraz Invitation -#define MTYPE_SCRIPT_DATA 0x202 // Xtraz Message -#define MTYPE_SCRIPT_NOTIFY 0x208 // Xtraz Response -#define MTYPE_REVERSE_REQUEST 0x401 // Reverse DC request - -// Message Plugin Type GUIDs -#define MGTYPE_MESSAGE_s 0xBE6B7305, 0x0FC2104F, 0xA6DE4DB1, 0xE3564B0E -#define MGTYPE_STATUSMSGEXT_s 0x811a18bc, 0x0e6c1847, 0xa5916f18, 0xdcc76f1a -#define MGTYPE_FILE_s 0xF02D12D9, 0x3091D311, 0x8DD70010, 0x4B06462E -#define MGTYPE_WEBURL_s 0x371C5872, 0xE987D411, 0xA4C100D0, 0xB759B1D9 -#define MGTYPE_CONTACTS_s 0x2A0E7D46, 0x7676D411, 0xBCE60004, 0xAC961EA6 -#define MGTYPE_GREETING_CARD_s 0x01E53B48, 0x2AE4D111, 0xB6790060, 0x97E1E294 -#define MGTYPE_CHAT_s 0xBFF720B2, 0x378ED411, 0xBD280004, 0xAC96D905 -#define MGTYPE_SMS_MESSAGE_s 0x0e28f600, 0x11e7d311, 0xbcf30004, 0xac969dc2 -#define MGTYPE_XTRAZ_SCRIPT_s 0x3b60b3ef, 0xd82a6c45, 0xa4e09c5a, 0x5e67e865 - -// Message Plugin Sub-Type IDs -#define MGTYPE_STANDARD_SEND 0x0000 -#define MGTYPE_CONTACTS_REQUEST 0x0002 -#define MGTYPE_SCRIPT_INVITATION 0x0001 -#define MGTYPE_SCRIPT_DATA 0x0002 -#define MGTYPE_SCRIPT_USER_REMOVE 0x0004 -#define MGTYPE_SCRIPT_NOTIFY 0x0008 -#define MGTYPE_UNDEFINED 0xFFFF - - - -/* Channels */ -#define ICQ_LOGIN_CHAN 0x01 -#define ICQ_DATA_CHAN 0x02 -#define ICQ_ERROR_CHAN 0x03 -#define ICQ_CLOSE_CHAN 0x04 -#define ICQ_PING_CHAN 0x05 - -/* Families */ -#define ICQ_SERVICE_FAMILY 0x0001 -#define ICQ_LOCATION_FAMILY 0x0002 -#define ICQ_BUDDY_FAMILY 0x0003 -#define ICQ_MSG_FAMILY 0x0004 -#define ICQ_BOS_FAMILY 0x0009 -#define ICQ_LOOKUP_FAMILY 0x000a -#define ICQ_STATS_FAMILY 0x000b -#define ICQ_CHAT_NAVIGATION_FAMILY 0x000d -#define ICQ_CHAT_FAMILY 0x000e -#define ICQ_AVATAR_FAMILY 0x0010 -#define ICQ_LISTS_FAMILY 0x0013 -#define ICQ_EXTENSIONS_FAMILY 0x0015 -#define ICQ_AUTHORIZATION_FAMILY 0x0017 -#define ICQ_DIRECTORY_FAMILY 0x0025 - -/* Subtypes for Service Family 0x0001 */ -#define ICQ_ERROR 0x0001 -#define ICQ_CLIENT_READY 0x0002 -#define ICQ_SERVER_READY 0x0003 -#define ICQ_CLIENT_NEW_SERVICE 0x0004 -#define ICQ_SERVER_REDIRECT_SERVICE 0x0005 -#define ICQ_CLIENT_REQ_RATE_INFO 0x0006 -#define ICQ_SERVER_RATE_INFO 0x0007 -#define ICQ_CLIENT_RATE_ACK 0x0008 -#define ICQ_SERVER_RATE_CHANGE 0x000a -#define ICQ_SERVER_PAUSE 0x000b -#define ICQ_CLIENT_PAUSE_ACK 0x000c -#define ICQ_SERVER_RESUME 0x000d -#define ICQ_CLIENT_REQINFO 0x000e -#define ICQ_SERVER_NAME_INFO 0x000f -#define ICQ_SERVER_EVIL_NOTICE 0x0010 -#define ICQ_CLIENT_SET_IDLE 0x0011 -#define ICQ_SERVER_MIGRATIONREQ 0x0012 -#define ICQ_SERVER_MOTD 0x0013 -#define ICQ_CLIENT_FAMILIES 0x0017 -#define ICQ_SERVER_FAMILIES2 0x0018 -#define ICQ_CLIENT_SET_STATUS 0x001e -#define ICQ_SERVER_EXTSTATUS 0x0021 - -/* Subtypes for Location Family 0x0002 */ -#define ICQ_LOCATION_CLI_REQ_RIGHTS 0x0002 -#define ICQ_LOCATION_RIGHTS_REPLY 0x0003 -#define ICQ_LOCATION_SET_USER_INFO 0x0004 -#define ICQ_LOCATION_REQ_USER_INFO 0x0005 -#define ICQ_LOCATION_USR_INFO_REPLY 0x0006 -#define ICQ_LOCATION_QRY_USER_INFO 0x0015 - -/* Subtypes for Buddy Family 0x0003 */ -#define ICQ_USER_CLI_REQBUDDY 0x0002 -#define ICQ_USER_SRV_REPLYBUDDY 0x0003 -#define ICQ_USER_ADDTOLIST 0x0004 /* deprecated */ -#define ICQ_USER_REMOVEFROMLIST 0x0005 /* deprecated */ -#define ICQ_USER_NOTIFY_REJECTED 0x000a -#define ICQ_USER_ONLINE 0x000b -#define ICQ_USER_OFFLINE 0x000c -#define ICQ_USER_ADDTOTEMPLIST 0x000f -#define ICQ_USER_REMOVEFROMTEMPLIST 0x0010 - -/* Subtypes for Message Family 0x0004 */ -#define ICQ_MSG_SRV_ERROR 0x0001 -#define ICQ_MSG_CLI_SETPARAMS 0x0002 -#define ICQ_MSG_CLI_RESETPARAMS 0x0003 -#define ICQ_MSG_CLI_REQICBM 0x0004 -#define ICQ_MSG_SRV_REPLYICBM 0x0005 -#define ICQ_MSG_SRV_SEND 0x0006 -#define ICQ_MSG_SRV_RECV 0x0007 -#define ICQ_MSG_SRV_MISSED_MESSAGE 0x000A -#define ICQ_MSG_RESPONSE 0x000B -#define ICQ_MSG_SRV_ACK 0x000C -#define ICQ_MSG_CLI_REQ_OFFLINE 0x0010 -#define ICQ_MSG_MTN 0x0014 -#define ICQ_MSG_SRV_OFFLINE_REPLY 0x0017 - -/* Subtypes for Privacy Family 0x0009 */ -#define ICQ_PRIVACY_REQ_RIGHTS 0x0002 -#define ICQ_PRIVACY_RIGHTS_REPLY 0x0003 -#define ICQ_CLI_ADDVISIBLE 0x0005 -#define ICQ_CLI_REMOVEVISIBLE 0x0006 -#define ICQ_CLI_ADDINVISIBLE 0x0007 -#define ICQ_CLI_REMOVEINVISIBLE 0x0008 -#define ICQ_PRIVACY_SERVICE_ERROR 0x0009 -#define ICQ_CLI_ADDTEMPVISIBLE 0x000A -#define ICQ_CLI_REMOVETEMPVISIBLE 0x000B - -/* Subtypes for Lookup Family 0x000a */ -#define ICQ_LOOKUP_REQUEST 0x0002 -#define ICQ_LOOKUP_EMAIL_REPLY 0x0003 - -/* Subtypes for Stats Family 0x000b */ -#define ICQ_STATS_MINREPORTINTERVAL 0x0002 - -/* Subtypes for Avatar Family 0x0010 */ -#define ICQ_AVATAR_ERROR 0x0001 -#define ICQ_AVATAR_UPLOAD_REQUEST 0x0002 -#define ICQ_AVATAR_UPLOAD_ACK 0x0003 -#define ICQ_AVATAR_GET_REQUEST 0x0006 -#define ICQ_AVATAR_GET_REPLY 0x0007 - -/* Subtypes for Server Lists Family 0x0013 */ -#define ICQ_LISTS_ERROR 0x0001 -#define ICQ_LISTS_CLI_REQLISTS 0x0002 -#define ICQ_LISTS_SRV_REPLYLISTS 0x0003 -#define ICQ_LISTS_CLI_REQUEST 0x0004 -#define ICQ_LISTS_CLI_CHECK 0x0005 -#define ICQ_LISTS_LIST 0x0006 -#define ICQ_LISTS_GOTLIST 0x0007 -#define ICQ_LISTS_ADDTOLIST 0x0008 -#define ICQ_LISTS_UPDATEGROUP 0x0009 -#define ICQ_LISTS_REMOVEFROMLIST 0x000A -#define ICQ_LISTS_ACK 0x000E -#define ICQ_LISTS_UPTODATE 0x000F -#define ICQ_LISTS_CLI_MODIFYSTART 0x0011 -#define ICQ_LISTS_CLI_MODIFYEND 0x0012 -#define ICQ_LISTS_GRANTAUTH 0x0014 -#define ICQ_LISTS_AUTHGRANTED 0x0015 -#define ICQ_LISTS_REVOKEAUTH 0x0016 -#define ICQ_LISTS_REQUESTAUTH 0x0018 -#define ICQ_LISTS_AUTHREQUEST 0x0019 -#define ICQ_LISTS_CLI_AUTHRESPONSE 0x001A -#define ICQ_LISTS_SRV_AUTHRESPONSE 0x001B -#define ICQ_LISTS_YOUWEREADDED 0x001C - -/* Subtypes for ICQ Extensions Family 0x0015 */ -#define ICQ_META_ERROR 0x0001 -#define ICQ_META_CLI_REQUEST 0x0002 -#define ICQ_META_SRV_REPLY 0x0003 -#define ICQ_META_SRV_UPDATE 0x0004 - -/* Subtypes for Authorization Family 0x0017 */ -#define ICQ_SIGNON_ERROR 0x0001 -#define ICQ_SIGNON_LOGIN_REQUEST 0x0002 -#define ICQ_SIGNON_LOGIN_REPLY 0x0003 -#define ICQ_SIGNON_REGISTRATION_REQ 0x0004 -#define ICQ_SIGNON_NEW_UIN 0x0005 -#define ICQ_SIGNON_AUTH_REQUEST 0x0006 -#define ICQ_SIGNON_AUTH_KEY 0x0007 -#define ICQ_SIGNON_REQUEST_IMAGE 0x000C -#define ICQ_SIGNON_REG_AUTH_IMAGE 0x000D - -// Class constants -#define CLASS_UNCONFIRMED 0x0001 -#define CLASS_ADMINISTRATOR 0x0002 -#define CLASS_AOL 0x0004 -#define CLASS_COMMERCIAL 0x0008 -#define CLASS_FREE 0x0010 -#define CLASS_AWAY 0x0020 -#define CLASS_ICQ 0x0040 -#define CLASS_WIRELESS 0x0080 -#define CLASS_FORWARDING 0x0200 -#define CLASS_BOT 0x0400 - -// Reply types for SNAC 15/02 & 15/03 -#define CLI_DELETE_OFFLINE_MSGS_REQ 0x003E -#define CLI_META_INFO_REQ 0x07D0 -#define SRV_META_INFO_REPLY 0x07DA - -// Reply subtypes for SNAC 15/02 & 15/03 -#define META_PROCESSING_ERROR 0x0001 // Meta processing error server reply -#define META_SMS_DELIVERY_RECEIPT 0x0096 // Server SMS response (delivery receipt) -#define META_SET_PASSWORD_ACK 0x00AA // Set user password server ack -#define META_UNREGISTER_ACK 0x00B4 // Unregister account server ack -#define META_BASIC_USERINFO 0x00C8 // User basic info reply -#define META_WORK_USERINFO 0x00D2 // User work info reply -#define META_MORE_USERINFO 0x00DC // User more info reply -#define META_NOTES_USERINFO 0x00E6 // User notes (about) info reply -#define META_EMAIL_USERINFO 0x00EB // User extended email info reply -#define META_INTERESTS_USERINFO 0x00F0 // User interests info reply -#define META_AFFILATIONS_USERINFO 0x00FA // User past/affilations info reply -#define META_SHORT_USERINFO 0x0104 // Short user information reply -#define META_HPAGECAT_USERINFO 0x010E // User homepage category information reply -#define SRV_USER_FOUND 0x01A4 // Search: user found reply -#define SRV_LAST_USER_FOUND 0x01AE // Search: last user found reply -#define META_REGISTRATION_STATS_ACK 0x0302 // Registration stats ack -#define SRV_RANDOM_FOUND 0x0366 // Random search server reply -#define META_SET_PASSWORD_REQ 0x042E // Set user password request -#define META_REQUEST_FULL_INFO 0x04B2 // Request full user info -#define META_REQUEST_SHORT_INFO 0x04BA // Request short user info -#define META_REQUEST_SELF_INFO 0x04D0 // Request full self user info -#define META_SEARCH_GENERIC 0x055F // Search user by details (TLV) -#define META_SEARCH_UIN 0x0569 // Search user by UIN (TLV) -#define META_SEARCH_EMAIL 0x0573 // Search user by E-mail (TLV) -#define META_DIRECTORY_QUERY 0x0FA0 -#define META_DIRECTORY_DATA 0x0FAA -#define META_DIRECTORY_RESPONSE 0x0FB4 -#define META_DIRECTORY_UPDATE 0x0FD2 -#define META_DIRECTORY_UPDATE_ACK 0x0FDC - -#define META_XML_INFO 0x08A2 // Server variable requested via xml -#define META_SET_FULLINFO_REQ 0x0C3A // Set full user info request -#define META_SET_FULLINFO_ACK 0x0C3F // Server ack for set fullinfo command -#define META_SPAM_REPORT_ACK 0x2012 // Server ack for user spam report - -// Subtypes for Directory meta requests (family 0x5b9) -#define DIRECTORY_QUERY_INFO 0x0002 -#define DIRECTORY_SET_INFO 0x0003 -#define DIRECTORY_QUERY_MULTI_INFO 0x0006 -#define DIRECTORY_QUERY_INFO_ACK 0x0009 -#define DIRECTORY_SET_INFO_ACK 0x000A - -// TLV types - -// SECURITY flags -#define TLV_AUTH 0x02F8 // uint8 User authorization permissions -#define TLV_WEBAWARE 0x030C // uint8 User 'show web status' permissions - - -// SEARCH only TLVs -#define TLV_AGERANGE 0x0168 // acombo Age range to search -#define TLV_KEYWORDS 0x0226 // sstring Whitepages search keywords string -#define TLV_ONLINEONLY 0x0230 // uint8 Search only online users flag -#define TLV_UIN 0x0136 // uint32 User uin - -// common -#define TLV_FIRSTNAME 0x0140 // sstring User firstname -#define TLV_LASTNAME 0x014A // sstring User lastname -#define TLV_NICKNAME 0x0154 // sstring User nickname -#define TLV_EMAIL 0x015E // ecombo User email -#define TLV_GENDER 0x017C // uint8 User gender -#define TLV_MARITAL 0x033E // uint8 User marital status -#define TLV_LANGUAGE 0x0186 // uint16 User spoken language -#define TLV_CITY 0x0190 // sstring User home city name -#define TLV_STATE 0x019A // sstring User home state abbr -#define TLV_COUNTRY 0x01A4 // uint16 User home country code -#define TLV_COMPANY 0x01AE // sstring User work company name -#define TLV_DEPARTMENT 0x01B8 // sstring User work department name -#define TLV_POSITION 0x01C2 // sstring User work position (title) -#define TLV_OCUPATION 0x01CC // uint16 User work ocupation code -#define TLV_PASTINFO 0x01D6 // icombo User affilations node -#define TLV_AFFILATIONS 0x01FE // icombo User past info node -#define TLV_INTERESTS 0x01EA // icombo User interests node -#define TLV_HOMEPAGE 0x0212 // sstring User homepage category/keywords - -// changeinfo -#define TLV_AGE 0x0172 // uint16 User age -#define TLV_URL 0x0213 // sstring User homepage url -#define TLV_BIRTH 0x023A // bcombo User birthday info (year, month, day) -#define TLV_ABOUT 0x0258 // sstring User notes (about) text -#define TLV_STREET 0x0262 // sstring User home street address -#define TLV_ZIPCODE 0x026D // sstring User home zip code -#define TLV_PHONE 0x0276 // sstring User home phone number -#define TLV_FAX 0x0280 // sstring User home fax number -#define TLV_MOBILE 0x028A // sstring User home cellular phone number -#define TLV_WORKSTREET 0x0294 // sstring User work street address -#define TLV_WORKCITY 0x029E // sstring User work city name -#define TLV_WORKSTATE 0x02A8 // sstring User work state name -#define TLV_WORKCOUNTRY 0x02B2 // uint16 User work country code -#define TLV_WORKZIPCODE 0x02BD // sstring User work zip code -#define TLV_WORKPHONE 0x02C6 // sstring User work phone number -#define TLV_WORKFAX 0x02D0 // sstring User work fax number -#define TLV_WORKURL 0x02DA // sstring User work webpage url -#define TLV_TIMEZONE 0x0316 // uint8 User GMT offset -#define TLV_ORGCITY 0x0320 // sstring User originally from city -#define TLV_ORGSTATE 0x032A // sstring User originally from state -#define TLV_ORGCOUNTRY 0x0334 // uint16 User originally from country (code) -#define TLV_ALLOWSPAM 0x0348 // uint8 -#define TLV_CODEPAGE 0x0352 // uint16 Codepage used for details - - -/* Direct packet types */ -#define PEER_INIT 0xFF -#define PEER_INIT_ACK 0x01 -#define PEER_MSG_INIT 0x03 -#define PEER_MSG 0x02 -#define PEER_FILE_INIT 0x00 -#define PEER_FILE_INIT_ACK 0x01 -#define PEER_FILE_NEXTFILE 0x02 -#define PEER_FILE_RESUME 0x03 -#define PEER_FILE_STOP 0x04 -#define PEER_FILE_SPEED 0x05 -#define PEER_FILE_DATA 0x06 - -/* Direct command types */ -#define DIRECT_CANCEL 0x07D0 /* 2000 TCP cancel previous file/chat request */ -#define DIRECT_ACK 0x07DA /* 2010 TCP acknowledge message packet */ -#define DIRECT_MESSAGE 0x07EE /* 2030 TCP message */ - -// DC types -#define DC_DISABLED 0x0000 // Direct connection disabled / auth required -#define DC_HTTPS 0x0001 // Direct connection thru firewall or https proxy -#define DC_SOCKS 0x0002 // Direct connection thru socks4/5 proxy server -#define DC_NORMAL 0x0004 // Normal direct connection (without proxy/firewall) -#define DC_WEB 0x0006 // Web client - no direct connection - -// Message flags -#define MFLAG_NORMAL 0x01 // Normal message -#define MFLAG_AUTO 0x03 // Auto-message flag -#define MFLAG_MULTI 0x80 // This is multiple recipients message - -// Some SSI constants -#define SSI_ITEM_BUDDY 0x0000 // Buddy record (name: uin for ICQ and screenname for AIM) -#define SSI_ITEM_GROUP 0x0001 // Group record -#define SSI_ITEM_PERMIT 0x0002 // Permit record ("Allow" list in AIM, and "Visible" list in ICQ) -#define SSI_ITEM_DENY 0x0003 // Deny record ("Block" list in AIM, and "Invisible" list in ICQ) -#define SSI_ITEM_VISIBILITY 0x0004 // Permit/deny settings or/and bitmask of the AIM classes -#define SSI_ITEM_PRESENCE 0x0005 // Presence info (if others can see your idle status, etc) -#define SSI_ITEM_CLIENTDATA 0x0009 // Client specific, e.g. ICQ2k shortcut bar items -#define SSI_ITEM_IGNORE 0x000e // Ignore list record. -#define SSI_ITEM_LASTUPDATE 0x000f // Item that contain roster update time (name: "LastUpdateDate") -#define SSI_ITEM_NONICQ 0x0010 // Non-ICQ contact (to send SMS). Name: 1#EXT, 2#EXT, etc -#define SSI_ITEM_UNKNOWN2 0x0011 // Unknown. -#define SSI_ITEM_IMPORTTIME 0x0013 // Item that contain roster import time (name: "Import time") -#define SSI_ITEM_BUDDYICON 0x0014 // Buddy icon info. (names: "1", "8", etc. according ot the icon type) -#define SSI_ITEM_SAVED 0x0019 -#define SSI_ITEM_PREAUTH 0x001B -#define SSI_ITEM_METAINFO 0x0020 // Owner Details' token & last update time - -#define SSI_TLV_AWAITING_AUTH 0x0066 // Contact not authorized in list -#define SSI_TLV_NOT_IN_LIST 0x006A // Always empty -#define SSI_TLV_UNKNOWN 0x006D // WTF ? -#define SSI_TLV_SUBITEMS 0x00C8 // List of sub-items IDs -#define SSI_TLV_VISIBILITY 0x00CA -#define SSI_TLV_SHORTCUT 0x00CD -#define SSI_TLV_TIMESTAMP 0x00D4 // Import Timestamp -#define SSI_TLV_AVATARHASH 0x00D5 -#define SSI_TLV_NAME 0x0131 // Custom contact nickname -#define SSI_TLV_GROUP_OPENNED 0x0134 -#define SSI_TLV_EMAIL 0x0137 // Custom contact email -#define SSI_TLV_PHONE 0x0138 // Custom contact phone number -#define SSI_TLV_PHONE_CELLULAR 0x0139 // Custom contact cellphone number -#define SSI_TLV_PHONE_SMS 0x013A // Custom contact SMS number -#define SSI_TLV_COMMENT 0x013C // User comment -#define SSI_TLV_METAINFO_TOKEN 0x015C // Privacy token for Contact's details -#define SSI_TLV_METAINFO_TIME 0x015D // Contact's details last update time - -#define MAX_SSI_TLV_NAME_SIZE 0x40 -#define MAX_SSI_TLV_COMMENT_SIZE 0x50 - -// Client ID constants (internal) -#define CLID_GENERIC 0x00 // Generic clients (eg. older official clients) -#define CLID_ALTERNATIVE 0x01 // Clients not using tick for MsgID (most third-party clients) -#define CLID_MIRANDA 0x02 // Hey, that's mate! -#define CLID_ICQ6 0x10 // Mark ICQ6 as it has some non obvious limitations! - - -// Internal Constants -#define ICQ_PROTOCOL_NAME LPGEN("ICQ") -#define ICQ_PLUG_VERSION __VERSION_DWORD -#define ICQ_VERSION 8 // Protocol version -#define DC_TYPE DC_NORMAL // Used for DC settings -#define MAX_CONTACTSSEND 15 -#define MAX_MESSAGESNACSIZE 8000 -#define CLIENTRATELIMIT 0 -#define COOKIE_TIMEOUT 3600 // One hour -#define KEEPALIVE_INTERVAL 57000 // One minute -#define WEBFRONTPORT 0x50 -#define CLIENTFEATURES 0x3 -#define URL_FORGOT_PASSWORD "https://www.icq.com/password/" -#define URL_REGISTER "https://www.icq.com/register/" -#define FLAP_MARKER 0x2a -#define CLIENT_MD5_STRING "AOL Instant Messenger (SM)" -#define UNIQUEIDSETTING "UIN" -#define UINMAXLEN 11 // DWORD string max len + 1 -#define PASSWORDMAXLEN 128 -#define OSCAR_PROXY_HOST "ars.icq.com" -#define OSCAR_PROXY_VERSION 0x044A - -#define CLIENT_ID_STRING "ICQ Client" // Client identification, mimic ICQ 6.5 -#define CLIENT_ID_CODE 0x010a -#define CLIENT_VERSION_MAJOR 0x0014 -#define CLIENT_VERSION_MINOR 0x0034 -#define CLIENT_VERSION_LESSER 0x0000 -#define CLIENT_VERSION_BUILD 0x0c18 -#define CLIENT_DISTRIBUTION 0x00000611 -#define CLIENT_LANGUAGE "en" -#define CLIENT_COUNTRY "us" - -#endif /* __ICQ_CONSTANTS_H */ diff --git a/protocols/IcqOscarJ/icq_db.cpp b/protocols/IcqOscarJ/icq_db.cpp deleted file mode 100644 index f199860df8..0000000000 --- a/protocols/IcqOscarJ/icq_db.cpp +++ /dev/null @@ -1,399 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Internal Database API -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::CreateResidentSetting(const char *szSetting) -{ - char pszSetting[2*MAX_PATH]; - - strcpy(pszSetting, m_szModuleName); - strcat(pszSetting, "/"); - strcat(pszSetting, szSetting); - CallService(MS_DB_SETSETTINGRESIDENT, 1, (WPARAM)pszSetting); -} - - -int CIcqProto::getSetting(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) -{ - return DBGetContactSettingW(hContact, m_szModuleName, szSetting, dbv); -} - - -BYTE CIcqProto::getSettingByte(HANDLE hContact, const char *szSetting, BYTE byDef) -{ - return DBGetContactSettingByte(hContact, m_szModuleName, szSetting, byDef); -} - - -WORD CIcqProto::getSettingWord(HANDLE hContact, const char *szSetting, WORD wDef) -{ - return DBGetContactSettingWord(hContact, m_szModuleName, szSetting, wDef); -} - - -DWORD CIcqProto::getSettingDword(HANDLE hContact, const char *szSetting, DWORD dwDef) -{ - DBVARIANT dbv = {DBVT_DELETED}; - DWORD dwRes; - - if (getSetting(hContact, szSetting, &dbv)) - return dwDef; // not found, give default - - if (dbv.type != DBVT_DWORD) - dwRes = dwDef; // invalid type, give default - else // found and valid, give result - dwRes = dbv.dVal; - - ICQFreeVariant(&dbv); - return dwRes; -} - - -double CIcqProto::getSettingDouble(HANDLE hContact, const char *szSetting, double dDef) -{ - DBVARIANT dbv = {DBVT_DELETED}; - double dRes; - - if (getSetting(hContact, szSetting, &dbv)) - return dDef; // not found, give default - - if (dbv.type != DBVT_BLOB || dbv.cpbVal != sizeof(double)) - dRes = dDef; - else - dRes = *(double*)dbv.pbVal; - - ICQFreeVariant(&dbv); - return dRes; -} - - -DWORD CIcqProto::getContactUin(HANDLE hContact) -{ - return getSettingDword(hContact, UNIQUEIDSETTING, 0); -} - - -int CIcqProto::getContactUid(HANDLE hContact, DWORD *pdwUin, uid_str *ppszUid) -{ - DBVARIANT dbv = {DBVT_DELETED}; - int iRes = 1; - - *pdwUin = 0; - if (ppszUid) *ppszUid[0] = '\0'; - - if (!getSetting(hContact, UNIQUEIDSETTING, &dbv)) - { - if (dbv.type == DBVT_DWORD) - { - *pdwUin = dbv.dVal; - iRes = 0; - } - else if (dbv.type == DBVT_ASCIIZ) - { - if (ppszUid && m_bAimEnabled) - { - strcpy(*ppszUid, dbv.pszVal); - iRes = 0; - } - else - NetLog_Server("AOL screennames not accepted"); - } - ICQFreeVariant(&dbv); - } - return iRes; -} - - -int CIcqProto::getSettingString(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) -{ - int res = DBGetContactSettingString(hContact, m_szModuleName, szSetting, dbv); - - if (res) - ICQFreeVariant(dbv); - - return res; -} - - -int CIcqProto::getSettingStringW(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) -{ - int res = DBGetContactSettingWString(hContact, m_szModuleName, szSetting, dbv); - - if (res) - ICQFreeVariant(dbv); - - return res; -} - - -char* CIcqProto::getSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, char *szDef) -{ - DBVARIANT dbv = {DBVT_DELETED}; - - if (DBGetContactSettingUTF8String(hContact, szModule, szSetting, &dbv)) - { - ICQFreeVariant(&dbv); // for a setting with invalid contents/type - return null_strdup(szDef); - } - - char *szRes = null_strdup(dbv.pszVal); - ICQFreeVariant(&dbv); - return szRes; -} - - -char* CIcqProto::getSettingStringUtf(HANDLE hContact, const char *szSetting, char *szDef) -{ - return getSettingStringUtf(hContact, m_szModuleName, szSetting, szDef); -} - - -WORD CIcqProto::getContactStatus(HANDLE hContact) -{ - return getSettingWord(hContact, "Status", ID_STATUS_OFFLINE); -} - - -int CIcqProto::getSettingStringStatic(HANDLE hContact, const char *szSetting, char *dest, int dest_len) -{ - DBVARIANT dbv = {DBVT_DELETED}; - DBCONTACTGETSETTING sVal = {0}; - - dbv.pszVal = dest; - dbv.cchVal = dest_len; - dbv.type = DBVT_ASCIIZ; - - sVal.pValue = &dbv; - sVal.szModule = m_szModuleName; - sVal.szSetting = szSetting; - - if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0) - { // due to MS_DB_CONTACT_GETSETTINGSTATIC setting type check, we need to request UTF8 as well - dbv.pszVal = dest; - dbv.cchVal = dest_len; - dbv.type = DBVT_UTF8; - - if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0) - return 1; // nothing found - } - - return (dbv.type != DBVT_ASCIIZ); -} - - -int CIcqProto::deleteSetting(HANDLE hContact, const char *szSetting) -{ - return DBDeleteContactSetting(hContact, m_szModuleName, szSetting); -} - - -int CIcqProto::setSettingByte(HANDLE hContact, const char *szSetting, BYTE byValue) -{ - return DBWriteContactSettingByte(hContact, m_szModuleName, szSetting, byValue); -} - - -int CIcqProto::setSettingWord(HANDLE hContact, const char *szSetting, WORD wValue) -{ - return DBWriteContactSettingWord(hContact, m_szModuleName, szSetting, wValue); -} - - -int CIcqProto::setSettingDword(HANDLE hContact, const char *szSetting, DWORD dwValue) -{ - return DBWriteContactSettingDword(hContact, m_szModuleName, szSetting, dwValue); -} - - -int CIcqProto::setSettingDouble(HANDLE hContact, const char *szSetting, double dValue) -{ - return setSettingBlob(hContact, szSetting, (BYTE*)&dValue, sizeof(double)); -} - - -int CIcqProto::setSettingString(HANDLE hContact, const char *szSetting, const char *szValue) -{ - return DBWriteContactSettingString(hContact, m_szModuleName, szSetting, szValue); -} - - -int CIcqProto::setSettingStringW(HANDLE hContact, const char *szSetting, const WCHAR *wszValue) -{ - return DBWriteContactSettingWString(hContact, m_szModuleName, szSetting, wszValue); -} - - -int CIcqProto::setSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, const char *szValue) -{ - return DBWriteContactSettingUTF8String(hContact, szModule, szSetting, (char*)szValue); -} - - -int CIcqProto::setSettingStringUtf(HANDLE hContact, const char *szSetting, const char *szValue) -{ - return setSettingStringUtf(hContact, m_szModuleName, szSetting, szValue); -} - - -int CIcqProto::setSettingBlob(HANDLE hContact, const char *szSetting, const BYTE *pValue, const int cbValue) -{ - return DBWriteContactSettingBlob(hContact, m_szModuleName, szSetting, (void*)pValue, cbValue); -} - - -int CIcqProto::setContactHidden(HANDLE hContact, BYTE bHidden) -{ - int nResult = DBWriteContactSettingByte(hContact, "CList", "Hidden", bHidden); - - if (!bHidden) // clear zero setting - DBDeleteContactSetting(hContact, "CList", "Hidden"); - - return nResult; -} - -void CIcqProto::setStatusMsgVar(HANDLE hContact, char* szStatusMsg, bool isAnsi) -{ - if (szStatusMsg && szStatusMsg[0]) - { - if (isAnsi) - { - char* szStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, ""); - wchar_t* szStatusNoteW = make_unicode_string(szStatusNote); - int len = (int)wcslen(szStatusNoteW) * 3 + 1; - char* szStatusNoteAnsi = (char*)alloca(len); - WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, szStatusNoteW, -1, szStatusNoteAnsi, len, NULL, NULL); - bool notmatch = false; - for (int i=0; ;++i) - { - if (szStatusNoteAnsi[i] != szStatusMsg[i] && szStatusNoteAnsi[i] != '?' && szStatusMsg[i] != '?') - { - notmatch = true; - break; - } - if (!szStatusNoteAnsi[i] || !szStatusMsg[i]) - break; - } - szStatusMsg = notmatch ? ansi_to_utf8(szStatusMsg) : szStatusNote; - SAFE_FREE(&szStatusNoteW); - if (notmatch) SAFE_FREE(&szStatusNote); - } - - char* oldStatusMsg = NULL; - DBVARIANT dbv; - if (!DBGetContactSetting(hContact, "CList", "StatusMsg", &dbv)) - { - switch (dbv.type) - { - case DBVT_UTF8: - oldStatusMsg = null_strdup(dbv.pszVal); - break; - - case DBVT_WCHAR: - oldStatusMsg = make_utf8_string(dbv.pwszVal); - break; - } - ICQFreeVariant(&dbv); - } - - if (!oldStatusMsg || strcmp(oldStatusMsg, szStatusMsg)) - setSettingStringUtf(hContact, "CList", "StatusMsg", szStatusMsg); - SAFE_FREE(&oldStatusMsg); - if (isAnsi) SAFE_FREE(&szStatusMsg); - } - else - DBDeleteContactSetting(hContact, "CList", "StatusMsg"); -} - -int __fastcall ICQFreeVariant(DBVARIANT *dbv) -{ - return DBFreeVariant(dbv); -} - - -int CIcqProto::IsICQContact(HANDLE hContact) -{ - char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - - return !strcmpnull(szProto, m_szModuleName); -} - - -HANDLE CIcqProto::AddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob) -{ - DBEVENTINFO dbei = {0}; - - dbei.cbSize = sizeof(dbei); - dbei.szModule = m_szModuleName; - dbei.timestamp = dwTime; - dbei.flags = flags; - dbei.eventType = wType; - dbei.cbBlob = cbBlob; - dbei.pBlob = pBlob; - - return (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); -} - - -HANDLE CIcqProto::FindFirstContact() -{ - HANDLE hContact = db_find_first(m_szModuleName); - - if (IsICQContact(hContact)) - return hContact; - - return FindNextContact(hContact); -} - - -HANDLE CIcqProto::FindNextContact(HANDLE hContact) -{ - hContact = db_find_next(hContact, m_szModuleName); - while (hContact != NULL) - { - if (IsICQContact(hContact)) - return hContact; - hContact = db_find_next(hContact, m_szModuleName); - } - return hContact; -} - - -char* CIcqProto::getContactCListGroup(HANDLE hContact) -{ - return getSettingStringUtf(hContact, "CList", "Group", NULL); -} - - -int __stdcall ICQSetContactCListGroup(HANDLE hContact, const char *szGroup) -{ - /// TODO - return 0; -} diff --git a/protocols/IcqOscarJ/icq_db.h b/protocols/IcqOscarJ/icq_db.h deleted file mode 100644 index 5bfc22d58b..0000000000 --- a/protocols/IcqOscarJ/icq_db.h +++ /dev/null @@ -1,44 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_DB_H -#define __ICQ_DB_H - - -#ifdef _UNICODE - #define getSettingStringT getSettingStringW - #define setSettingStringT setSettingStringW -#else - #define getSettingStringT getSettingString - #define setSettingStringT setSettingString -#endif - -int __fastcall ICQFreeVariant(DBVARIANT* dbv); - -#endif /* __ICQ_DB_H */ diff --git a/protocols/IcqOscarJ/icq_direct.cpp b/protocols/IcqOscarJ/icq_direct.cpp deleted file mode 100644 index 7779f1bad7..0000000000 --- a/protocols/IcqOscarJ/icq_direct.cpp +++ /dev/null @@ -1,1171 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -struct directthreadstartinfo -{ - int type; // Only valid for outgoing connections - int incoming; // 1=incoming, 0=outgoing - HANDLE hConnection; // only valid for incoming connections, handle to the connection - HANDLE hContact; // Only valid for outgoing connections - void* pvExtra; // Only valid for outgoing connections -}; - -static char client_check_data[] = { - "As part of this software beta version Mirabilis is " - "granting a limited access to the ICQ network, " - "servers, directories, listings, information and databases (\"" - "ICQ Services and Information\"). The " - "ICQ Service and Information may databases (\"" - "ICQ Services and Information\"). The " - "ICQ Service and Information may\0" -}; - -void CIcqProto::CloseContactDirectConns(HANDLE hContact) -{ - icq_lock l(directConnListMutex); - - for ( int i = 0; i < directConns.getCount(); i++) - { - if (!hContact || directConns[i]->hContact == hContact) - { - HANDLE hConnection = directConns[i]->hConnection; - - directConns[i]->hConnection = NULL; // do not allow reuse - NetLib_CloseConnection(&hConnection, FALSE); - } - } -} - - -directconnect* CIcqProto::FindFileTransferDC(filetransfer* ft) -{ - directconnect* dc = NULL; - icq_lock l(directConnListMutex); - - for (int i = 0; i < directConns.getCount(); i++) - { - if ( directConns[i]->ft == ft ) - { - dc = directConns[i]; - break; - } - } - - return dc; -} - - -filetransfer* CIcqProto::FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize) -{ - filetransfer* pFt = NULL; - icq_lock l(expectedFileRecvMutex); - - for (int i = 0; i < expectedFileRecvs.getCount(); i++) - { - if (expectedFileRecvs[i]->dwUin == dwUin && expectedFileRecvs[i]->dwTotalSize == dwTotalSize) - { - pFt = expectedFileRecvs[i]; - expectedFileRecvs.remove( i ); - break; - } - } - - return pFt; -} - - -int CIcqProto::sendDirectPacket(directconnect* dc, icq_packet* pkt) -{ - int nResult = Netlib_Send(dc->hConnection, (const char*)pkt->pData, pkt->wLen + 2, 0); - if (nResult == SOCKET_ERROR) - { - NetLog_Direct("Direct %p socket error: %d, closing", dc->hConnection, GetLastError()); - CloseDirectConnection(dc); - } - - SAFE_FREE((void**)&pkt->pData); - - return nResult; -} - -directthreadstartinfo* CreateDTSI(HANDLE hContact, HANDLE hConnection, int type) -{ - directthreadstartinfo* dtsi = (directthreadstartinfo*)SAFE_MALLOC(sizeof(directthreadstartinfo)); - dtsi->hContact = hContact; - dtsi->hConnection = hConnection; - if (type == -1) - dtsi->incoming = 1; - else - dtsi->type = type; - - return dtsi; -} - -// Check if we have an open and initialized DC with type -// 'type' to the specified contact -BOOL CIcqProto::IsDirectConnectionOpen(HANDLE hContact, int type, int bPassive) -{ - BOOL bIsOpen = FALSE, bIsCreated = FALSE; - - { - icq_lock l(directConnListMutex); - - for (int i = 0; i < directConns.getCount(); i++) - { - if (directConns[i] && (directConns[i]->type == type)) - { - if (directConns[i]->hContact == hContact) - if (directConns[i]->initialised) - { - // Connection is OK - bIsOpen = TRUE; - // we are going to use the conn, so prevent timeout - directConns[i]->packetPending = 1; - break; - } - else - bIsCreated = TRUE; // we found pending connection - } - } - } - - if (!bPassive && !bIsCreated && !bIsOpen && type == DIRECTCONN_STANDARD && m_bDCMsgEnabled == 2) - { // do not try to open DC to offline contact - if (getContactStatus(hContact) == ID_STATUS_OFFLINE) return FALSE; - // do not try to open DC if previous attempt was not successfull - if (getSettingByte(hContact, "DCStatus", 0)) return FALSE; - - // Set DC status as tried - setSettingByte(hContact, "DCStatus", 1); - // Create a new connection - OpenDirectConnection(hContact, DIRECTCONN_STANDARD, NULL); - } - - return bIsOpen; -} - -// This function is called from the Netlib when someone is connecting to -// one of our incomming DC ports -void icq_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra) -{ - // Start a new thread for the incomming connection - CIcqProto* ppro = (CIcqProto*)pExtra; - ppro->ForkThread(( IcqThreadFunc )&CIcqProto::icq_directThread, CreateDTSI(NULL, hNewConnection, -1)); -} - -// Opens direct connection of specified type to specified contact -void CIcqProto::OpenDirectConnection(HANDLE hContact, int type, void* pvExtra) -{ - // Create a new connection - directthreadstartinfo* dtsi = CreateDTSI(hContact, NULL, type); - dtsi->pvExtra = pvExtra; - ForkThread(( IcqThreadFunc )&CIcqProto::icq_directThread, dtsi); -} - -// Safely close NetLib connection - do not corrupt direct connection list -void CIcqProto::CloseDirectConnection(directconnect *dc) -{ - icq_lock l(directConnListMutex); - - NetLib_CloseConnection(&dc->hConnection, FALSE); -#ifdef _DEBUG - if (dc->hConnection) - NetLog_Direct("Direct conn closed (%p)", dc->hConnection); -#endif -} - -// Called from icq_newConnectionReceived when a new incomming dc is done -// Called from OpenDirectConnection when a new outgoing dc is done -// Called from SendDirectMessage when a new outgoing dc is done - -void __cdecl CIcqProto::icq_directThread( directthreadstartinfo *dtsi ) -{ - directconnect dc = {0}; - NETLIBPACKETRECVER packetRecv={0}; - HANDLE hPacketRecver; - BOOL bFirstPacket = TRUE; - int nSkipPacketBytes = 0; - DWORD dwReqMsgID1; - DWORD dwReqMsgID2; - - srand(time(NULL)); - - { // add to DC connection list - icq_lock l(directConnListMutex); - directConns.insert( &dc ); - } - - // Initialize DC struct - dc.hContact = dtsi->hContact; - dc.dwThreadId = GetCurrentThreadId(); - dc.incoming = dtsi->incoming; - dc.hConnection = dtsi->hConnection; - dc.ft = NULL; - - if (!dc.incoming) - { - dc.type = dtsi->type; - dc.dwRemoteExternalIP = getSettingDword(dtsi->hContact, "IP", 0); - dc.dwRemoteInternalIP = getSettingDword(dtsi->hContact, "RealIP", 0); - dc.dwRemotePort = getSettingWord(dtsi->hContact, "UserPort", 0); - dc.dwRemoteUin = getContactUin(dtsi->hContact); - dc.dwConnectionCookie = getSettingDword(dtsi->hContact, "DirectCookie", 0); - dc.wVersion = getSettingWord(dtsi->hContact, "Version", 0); - - if (!dc.dwRemoteExternalIP && !dc.dwRemoteInternalIP) - { // we do not have any ip, do not try to connect - SAFE_FREE((void**)&dtsi); - goto LBL_Exit; - } - if (!dc.dwRemotePort) - { // we do not have port, do not try to connect - SAFE_FREE((void**)&dtsi); - goto LBL_Exit; - } - - if (dc.type == DIRECTCONN_STANDARD) - { - // do nothing - some specific init for msg sessions - } - else if (dc.type == DIRECTCONN_FILE) - { - dc.ft = (filetransfer*)dtsi->pvExtra; - dc.dwRemotePort = dc.ft->dwRemotePort; - } - else if (dc.type == DIRECTCONN_REVERSE) - { - cookie_reverse_connect *pCookie = (cookie_reverse_connect*)dtsi->pvExtra; - - dwReqMsgID1 = pCookie->dwMsgID1; - dwReqMsgID2 = pCookie->dwMsgID2; - dc.dwReqId = (DWORD)pCookie->ft; - SAFE_FREE((void**)&pCookie); - } - } - else - { - dc.type = DIRECTCONN_STANDARD; - } - - SAFE_FREE((void**)&dtsi); - - // Load local IP information - dc.dwLocalExternalIP = getSettingDword(NULL, "IP", 0); - dc.dwLocalInternalIP = getSettingDword(NULL, "RealIP", 0); - - // Create outgoing DC - if (!dc.incoming) - { - NETLIBOPENCONNECTION nloc = {0}; - IN_ADDR addr = {0}, addr2 = {0}; - - if (dc.dwRemoteExternalIP == dc.dwLocalExternalIP && dc.dwRemoteInternalIP) - addr.S_un.S_addr = htonl(dc.dwRemoteInternalIP); - else - { - addr.S_un.S_addr = htonl(dc.dwRemoteExternalIP); - // for different internal, try it also (for LANs with multiple external IP, VPNs, etc.) - if (dc.dwRemoteInternalIP != dc.dwRemoteExternalIP) - addr2.S_un.S_addr = htonl(dc.dwRemoteInternalIP); - } - - // IP to connect to is empty, go away - if (!addr.S_un.S_addr) - goto LBL_Exit; - - nloc.szHost = inet_ntoa(addr); - nloc.wPort = (WORD)dc.dwRemotePort; - nloc.timeout = 8; // 8 secs to connect - dc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, dc.type==DIRECTCONN_REVERSE?"Reverse ":NULL, &nloc); - if (!dc.hConnection && addr2.S_un.S_addr) - { // first address failed, try second one if available - nloc.szHost = inet_ntoa(addr2); - dc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, dc.type==DIRECTCONN_REVERSE?"Reverse ":NULL, &nloc); - } - if (!dc.hConnection) - { - if (CheckContactCapabilities(dc.hContact, CAPF_ICQDIRECT)) - { // only if the contact support ICQ DC connections - if (dc.type != DIRECTCONN_REVERSE) - { // try reverse connect - cookie_reverse_connect *pCookie = (cookie_reverse_connect*)SAFE_MALLOC(sizeof(cookie_reverse_connect)); - DWORD dwCookie; - - NetLog_Direct("connect() failed (%d), trying reverse.", GetLastError()); - - if (pCookie) - { // init cookie - InitMessageCookie(pCookie); - pCookie->bMessageType = MTYPE_REVERSE_REQUEST; - pCookie->hContact = dc.hContact; - pCookie->dwUin = dc.dwRemoteUin; - pCookie->type = dc.type; - pCookie->ft = dc.ft; - dwCookie = AllocateCookie(CKT_REVERSEDIRECT, 0, dc.hContact, pCookie); - icq_sendReverseReq(&dc, dwCookie, (cookie_message_data*)pCookie); - goto LBL_Exit; - } - - NetLog_Direct("Reverse failed (%s)", "malloc failed"); - } - } - else // Set DC status to failed - setSettingByte(dc.hContact, "DCStatus", 2); - - if (dc.type == DIRECTCONN_REVERSE) // failed reverse connection - { // announce we failed - icq_sendReverseFailed(&dc, dwReqMsgID1, dwReqMsgID2, dc.dwReqId); - } - NetLog_Direct("connect() failed (%d)", GetLastError()); - if (dc.type == DIRECTCONN_FILE) - { - BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&dc.ft); - } - goto LBL_Exit; - } - - if (dc.type == DIRECTCONN_FILE) - dc.ft->hConnection = dc.hConnection; - - if (dc.wVersion > 6) - { - sendPeerInit_v78(&dc); - } - else - { - NetLog_Direct("Error: Unsupported direct protocol: %d, closing.", dc.wVersion); - CloseDirectConnection(&dc); - goto LBL_Exit; - } - } - - hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)dc.hConnection, 8192); - packetRecv.cbSize = sizeof(packetRecv); - packetRecv.bytesUsed = 0; - - // Packet receiving loop - - while (dc.hConnection) - { - int recvResult; - - packetRecv.dwTimeout = dc.wantIdleTime ? 0 : 600000; - - recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); - if (recvResult == 0) - { - NetLog_Direct("Clean closure of direct socket (%p)", dc.hConnection); - break; - } - - if (recvResult == SOCKET_ERROR) - { - if (GetLastError() == ERROR_TIMEOUT) - { // TODO: this will not work on some systems - if (dc.wantIdleTime) - { - switch (dc.type) - { - case DIRECTCONN_FILE: - handleFileTransferIdle(&dc); - break; - } - } - else if (dc.packetPending) - { // do we expect packet soon? - NetLog_Direct("Keeping connection, packet pending."); - } - else - { - NetLog_Direct("Connection inactive for 10 minutes, closing."); - break; - } - } - else - { - NetLog_Direct("Abortive closure of direct socket (%p) (%d)", dc.hConnection, GetLastError()); - break; - } - } - - if (dc.type == DIRECTCONN_CLOSING) - packetRecv.bytesUsed = packetRecv.bytesAvailable; - else if (packetRecv.bytesAvailable < nSkipPacketBytes) - { // the whole buffer needs to be skipped - nSkipPacketBytes -= packetRecv.bytesAvailable; - packetRecv.bytesUsed = packetRecv.bytesAvailable; - } - else - { - int i; - - for (i = nSkipPacketBytes, nSkipPacketBytes = 0; i + 2 <= packetRecv.bytesAvailable;) - { - WORD wLen = *(WORD*)(packetRecv.buffer + i); - - if (bFirstPacket) - { - if (wLen > 64) - { // roughly check first packet size - NetLog_Direct("Error: Overflowed packet, closing connection."); - CloseDirectConnection(&dc); - break; - } - bFirstPacket = FALSE; - } - else - { - if (packetRecv.bytesAvailable >= i + 2 && wLen > 8190) - { // check for too big packages - NetLog_Direct("Error: Package too big: %d bytes, skipping."); - nSkipPacketBytes = wLen; - packetRecv.bytesUsed = i + 2; - break; - } - } - - if (wLen + 2 + i > packetRecv.bytesAvailable) - break; - - if (dc.type == DIRECTCONN_STANDARD && wLen && packetRecv.buffer[i + 2] == 2) - { - if (!DecryptDirectPacket(&dc, packetRecv.buffer + i + 3, (WORD)(wLen - 1))) - { - NetLog_Direct("Error: Corrupted packet encryption, ignoring packet"); - i += wLen + 2; - continue; - } - } -#ifdef _DEBUG - NetLog_Direct("New direct package"); -#endif - if (dc.type == DIRECTCONN_FILE && dc.initialised) - handleFileTransferPacket(&dc, packetRecv.buffer + i + 2, wLen); - else - handleDirectPacket(&dc, packetRecv.buffer + i + 2, wLen); - - i += wLen + 2; - } - packetRecv.bytesUsed = i; - } - } - - // End of packet receiving loop - - NetLib_SafeCloseHandle(&hPacketRecver); - CloseDirectConnection(&dc); - - if (dc.ft) - { - if (dc.ft->fileId != -1) - { - _close(dc.ft->fileId); - BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, dc.ft->dwBytesDone==dc.ft->dwTotalSize ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, dc.ft, 0); - } - else if (dc.ft->hConnection) - BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0); - - SafeReleaseFileTransfer((void**)&dc.ft); - _chdir("\\"); /* so we don't leave a subdir handle open so it can't be deleted */ - } - -LBL_Exit: - { // remove from DC connection list - icq_lock l(directConnListMutex); - directConns.remove( &dc ); - } -} - - -void CIcqProto::handleDirectPacket(directconnect* dc, PBYTE buf, WORD wLen) -{ - if (wLen < 1) - return; - - switch (buf[0]) - { - case PEER_FILE_INIT: // first packet of a file transfer -#ifdef _DEBUG - NetLog_Direct("Received PEER_FILE_INIT from %u",dc->dwRemoteUin); -#endif - if (dc->handshake) - handleFileTransferPacket(dc, buf, wLen); - else - NetLog_Direct("Received %s on uninitialised DC, ignoring.", "PEER_FILE_INIT"); - - break; - - case PEER_INIT_ACK: // This is sent as a response to our PEER_INIT packet - if (wLen != 4) - { - NetLog_Direct("Error: Received malformed PEER_INITACK from %u", dc->dwRemoteUin); - break; - } -#ifdef _DEBUG - NetLog_Direct("Received PEER_INITACK from %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); -#endif - if (dc->incoming) dc->handshake = 1; - - if (dc->incoming && dc->type == DIRECTCONN_REVERSE) - { - cookie_reverse_connect *pCookie; - - dc->incoming = 0; - - if (FindCookie(dc->dwReqId, NULL, (void**)&pCookie) && pCookie) - { // valid reverse DC, check and init session - FreeCookie(dc->dwReqId); - if (pCookie->dwUin == dc->dwRemoteUin) - { // valid connection - dc->type = pCookie->type; - dc->ft = (filetransfer*)pCookie->ft; - dc->hContact = pCookie->hContact; - if (dc->type == DIRECTCONN_STANDARD) - { // init message session - sendPeerMsgInit(dc, 0); - } - else if (dc->type == DIRECTCONN_FILE) - { // init file session - sendPeerFileInit(dc); - dc->initialised = 1; - } - SAFE_FREE((void**)&pCookie); - break; - } - else - { - SAFE_FREE((void**)&pCookie); - NetLog_Direct("Error: Invalid connection (UINs does not match)."); - CloseDirectConnection(dc); - return; - } - } - else - { - NetLog_Direct("Error: Received unexpected reverse DC, closing."); - CloseDirectConnection(dc); - return; - } - } - break; - - case PEER_INIT: /* connect packet */ -#ifdef _DEBUG - NetLog_Direct("Received PEER_INIT"); -#endif - buf++; - - if (wLen < 3) - return; - - unpackLEWord(&buf, &dc->wVersion); - - if (dc->wVersion > 6) - { // we support only versions 7 and up - WORD wSecondLen; - DWORD dwUin; - DWORD dwPort; - DWORD dwCookie; - HANDLE hContact; - - if (wLen != 0x30) - { - NetLog_Direct("Error: Received malformed PEER_INIT"); - return; - } - - unpackLEWord(&buf, &wSecondLen); - if (wSecondLen && wSecondLen != 0x2b) - { // OMG? GnomeICU sets this to zero - NetLog_Direct("Error: Received malformed PEER_INIT"); - return; - } - - unpackLEDWord(&buf, &dwUin); - if (dwUin != m_dwLocalUIN) - { - NetLog_Direct("Error: Received PEER_INIT targeted to %u", dwUin); - CloseDirectConnection(dc); - return; - } - - buf += 2; /* 00 00 */ - unpackLEDWord(&buf, &dc->dwRemotePort); - unpackLEDWord(&buf, &dc->dwRemoteUin); - unpackDWord(&buf, &dc->dwRemoteExternalIP); - unpackDWord(&buf, &dc->dwRemoteInternalIP); - buf ++; /* 04: accept direct connections */ - unpackLEDWord(&buf, &dwPort); - if (dwPort != dc->dwRemotePort) - { - NetLog_Direct("Error: Received malformed PEER_INIT (invalid port)"); - return; - } - unpackLEDWord(&buf, &dwCookie); - - buf += 8; // Unknown stuff - unpackLEDWord(&buf, &dc->dwReqId); - - if (dc->dwRemoteUin || !dc->dwReqId) - { // OMG! Licq sends on reverse connection empty uin - hContact = HContactFromUIN(dc->dwRemoteUin, NULL); - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Direct("Error: Received PEER_INIT from %u not on my list", dwUin); - CloseDirectConnection(dc); - return; /* don't allow direct connection with people not on my clist */ - } - - if (dc->incoming) - { // this is the first PEER_INIT with our cookie - if (dwCookie != getSettingDword(hContact, "DirectCookie", 0)) - { - NetLog_Direct("Error: Received PEER_INIT with broken cookie"); - CloseDirectConnection(dc); - return; - } - } - else - { // this is the second PEER_INIT with peer cookie - if (dwCookie != dc->dwConnectionCookie) - { - NetLog_Direct("Error: Received PEER_INIT with broken cookie"); - CloseDirectConnection(dc); - return; - } - } - } - - if (dc->incoming && dc->dwReqId) - { // this is reverse connection - dc->type = DIRECTCONN_REVERSE; - if (!dc->dwRemoteUin) - { // we need to load cookie (licq) - cookie_reverse_connect *pCookie; - - if (FindCookie(dc->dwReqId, NULL, (void**)&pCookie) && pCookie) - { // valid reverse DC, check and init session - dc->dwRemoteUin = pCookie->dwUin; - dc->hContact = pCookie->hContact; - } - else - { - NetLog_Direct("Error: Received unexpected reverse DC, closing."); - CloseDirectConnection(dc); - return; - } - } - } - - sendPeerInitAck(dc); // ack good PEER_INIT packet - - if (dc->incoming) - { // store good IP info - dc->hContact = hContact; - dc->dwConnectionCookie = dwCookie; - setSettingDword(dc->hContact, "IP", dc->dwRemoteExternalIP); - setSettingDword(dc->hContact, "RealIP", dc->dwRemoteInternalIP); - sendPeerInit_v78(dc); // reply with our PEER_INIT - } - else // outgoing - { - dc->handshake = 1; - - if (dc->type == DIRECTCONN_REVERSE) - { - dc->incoming = 1; // this is incoming reverse connection - dc->type = DIRECTCONN_STANDARD; // we still do not know type - } - else if (dc->type == DIRECTCONN_STANDARD) - { // send PEER_MSGINIT - sendPeerMsgInit(dc, 0); - } - else if (dc->type == DIRECTCONN_FILE) - { - sendPeerFileInit(dc); - dc->initialised = 1; - } - } - // Set DC Status to successful - setSettingByte(dc->hContact, "DCStatus", 0); - } - else - { - NetLog_Direct("Unsupported direct protocol: %d, closing connection", dc->wVersion); - CloseDirectConnection(dc); - } - break; - - case PEER_MSG: /* messaging packets */ -#ifdef _DEBUG - NetLog_Direct("Received PEER_MSG from %u", dc->dwRemoteUin); -#endif - if (dc->initialised) - handleDirectMessage(dc, buf + 1, (WORD)(wLen - 1)); - else - NetLog_Direct("Received %s on uninitialised DC, ignoring.", "PEER_MSG"); - - break; - - case PEER_MSG_INIT: /* init message connection */ - { // it is sent by both contains GUID of message channel - DWORD q1,q2,q3,q4; - - if (!m_bDCMsgEnabled) - { // DC messaging disabled, close connection - NetLog_Direct("Messaging DC requested, denied"); - CloseDirectConnection(dc); - break; - } - -#ifdef _DEBUG - NetLog_Direct("Received PEER_MSG_INIT from %u",dc->dwRemoteUin); -#endif - buf++; - if (wLen != 0x21) - break; - - if (!dc->handshake) - { - NetLog_Direct("Received %s on unitialised DC, ignoring.", "PEER_MSG_INIT"); - break; - } - - buf += 4; /* always 10 */ - buf += 4; /* some id */ - buf += 4; /* sequence - always 0 on incoming */ - unpackDWord(&buf, &q1); // session type GUID - unpackDWord(&buf, &q2); - if (!dc->incoming) - { // skip marker on sequence 1 - buf += 4; - } - unpackDWord(&buf, &q3); - unpackDWord(&buf, &q4); - if (!CompareGUIDs(q1,q2,q3,q4,PSIG_MESSAGE)) - { // This is not for normal messages, useless so kill. - if (CompareGUIDs(q1,q2,q3,q4,PSIG_STATUS_PLUGIN)) - { - NetLog_Direct("Status Manager Plugin connections not supported, closing."); - } - else if (CompareGUIDs(q1,q2,q3,q4,PSIG_INFO_PLUGIN)) - { - NetLog_Direct("Info Manager Plugin connection not supported, closing."); - } - else - { - NetLog_Direct("Unknown connection type init, closing."); - } - CloseDirectConnection(dc); - break; - } - - if (dc->incoming) - { // reply with our PEER_MSG_INIT - sendPeerMsgInit(dc, 1); - } - else - { // connection initialized, ready to send message packet - } - NetLog_Direct("Direct message session ready."); - dc->initialised = 1; - } - break; - - default: - NetLog_Direct("Unknown direct packet ignored."); - break; - } -} - -void EncryptDirectPacket(directconnect* dc, icq_packet* p) -{ - unsigned long B1; - unsigned long M1; - unsigned long check; - unsigned int i; - unsigned char X1; - unsigned char X2; - unsigned char X3; - unsigned char* buf = (unsigned char*)(p->pData + 3); - unsigned char bak[6]; - unsigned long offset; - unsigned long key; - unsigned long hex; - unsigned long size = p->wLen - 1; - - - if (dc->wVersion < 4) - return; // no encryption necessary. - - - switch (dc->wVersion) - { - case 4: - case 5: - offset = 6; - break; - - case 6: - case 7: - case 8: - case 9: - case 10: - default: - offset = 0; - } - - // calculate verification data - M1 = (rand() % ((size < 255 ? size : 255)-10))+10; - X1 = buf[M1] ^ 0xFF; - X2 = rand() % 220; - X3 = client_check_data[X2] ^ 0xFF; - if (offset) - { - memcpy(bak, buf, sizeof(bak)); - B1 = (buf[offset+4]<<24) | (buf[offset+6]<<16) | (buf[2]<<8) | buf[0]; - } - else - { - B1 = (buf[4]<<24) | (buf[6]<<16) | (buf[4]<<8) | (buf[6]); - } - - // calculate checkcode - check = (M1<<24) | (X1<<16) | (X2<<8) | X3; - check ^= B1; - - // main XOR key - key = 0x67657268 * size + check; - - // XORing the actual data - for (i = 0; i<(size+3)/4; i+=4) - { - hex = key + client_check_data[i&0xFF]; - *(PDWORD)(buf + i) ^= hex; - } - - // in TCPv4 are the first 6 bytes unencrypted - // so restore them - if (offset) - memcpy(buf, bak, sizeof(bak)); - - // storing the checkcode - *(PDWORD)(buf + offset) = check; -} - -int DecryptDirectPacket(directconnect* dc, PBYTE buf, WORD wLen) -{ - unsigned long hex; - unsigned long key; - unsigned long B1; - unsigned long M1; - unsigned long check; - unsigned int i; - unsigned char X1; - unsigned char X2; - unsigned char X3; - unsigned char bak[6]; - unsigned long size = wLen; - unsigned long offset; - - - if (dc->wVersion < 4) - return 1; // no decryption necessary. - - if (size < 4) - return 1; - - if (dc->wVersion < 4) - return 1; - - if (dc->wVersion == 4 || dc->wVersion == 5) - { - offset = 6; - } - else - { - offset = 0; - } - - // backup the first 6 bytes - if (offset) - memcpy(bak, buf, sizeof(bak)); - - // retrieve checkcode - check = *(PDWORD)(buf+offset); - - // main XOR key - key = 0x67657268 * size + check; - - for (i=4; i<(size+3)/4; i+=4) - { - hex = key + client_check_data[i&0xFF]; - *(PDWORD)(buf + i) ^= hex; - } - - // retrive validate data - if (offset) - { - // in TCPv4 are the first 6 bytes unencrypted - // so restore them - memcpy(buf, bak, sizeof(bak)); - B1 = (buf[offset+4]<<24) | (buf[offset+6]<<16) | (buf[2]<<8) | buf[0]; - } - else - { - B1 = (buf[4]<<24) | (buf[6]<<16) | (buf[4]<<8) | (buf[6]<<0); - } - - // special decryption - B1 ^= check; - - // validate packet - M1 = (B1>>24) & 0xFF; - if (M1 < 10 || M1 >= size) - { - return 0; - } - - X1 = buf[M1] ^ 0xFF; - if (((B1 >> 16) & 0xFF) != X1) - { - return 0; - } - - X2 = (BYTE)((B1 >> 8) & 0xFF); - if (X2 < 220) - { - X3 = client_check_data[X2] ^ 0xFF; - if ((B1 & 0xFF) != X3) - { - return 0; - } - } -#ifdef _DEBUG - { // log decrypted data - char szTitleLine[128]; - char* szBuf; - int titleLineLen; - int line; - int col; - int colsInLine; - char* pszBuf; - - - titleLineLen = null_snprintf(szTitleLine, 128, "DECRYPTED\n"); - szBuf = (char*)_alloca(titleLineLen + ((wLen+15)>>4) * 76 + 1); - CopyMemory(szBuf, szTitleLine, titleLineLen); - pszBuf = szBuf + titleLineLen; - - for (line = 0; ; line += 16) - { - colsInLine = min(16, wLen - line); - pszBuf += wsprintfA(pszBuf, "%08X: ", line); - - for (col = 0; colhContact == hContact) - { - if (directConns[i]->initialised) - { - // This connection can be reused, send packet and exit - NetLog_Direct("Sending direct message"); - - if (pkt->pData[2] == 2) - EncryptDirectPacket(directConns[i], pkt); - - sendDirectPacket(directConns[i], pkt); - directConns[i]->packetPending = 0; // packet done - - return TRUE; // Success - } - break; // connection not ready, use server instead - } - } - - return FALSE; // connection pending, we failed, use server instead -} - -// Sends a PEER_INIT packet through a DC -// ----------------------------------------------------------------------- -// This packet is sent during direct connection initialization between two -// ICQ clients. It is sent by the originator of the connection to start -// the handshake and by the receiver directly after it has sent the -// PEER_ACK packet as a reply to the originator's PEER_INIT. The values -// after the COOKIE field have been added for v7. - -void CIcqProto::sendPeerInit_v78(directconnect* dc) -{ - icq_packet packet; - - directPacketInit(&packet, 48); // Full packet length - packByte(&packet, PEER_INIT); // Command - packLEWord(&packet, dc->wVersion); // Version - packLEWord(&packet, 43); // Data length - packLEDWord(&packet, dc->dwRemoteUin); // UIN of remote user - packWord(&packet, 0); // Unknown - packLEDWord(&packet, wListenPort); // Our port - packLEDWord(&packet, m_dwLocalUIN); // Our UIN - packDWord(&packet, dc->dwLocalExternalIP); // Our external IP - packDWord(&packet, dc->dwLocalInternalIP); // Our internal IP - packByte(&packet, DC_TYPE); // TCP connection flags - packLEDWord(&packet, wListenPort); // Our port - packLEDWord(&packet, dc->dwConnectionCookie); // DC cookie - packLEDWord(&packet, WEBFRONTPORT); // Unknown - packLEDWord(&packet, CLIENTFEATURES); // Unknown - if (dc->type == DIRECTCONN_REVERSE) - packLEDWord(&packet, dc->dwReqId); // Reverse Request Cookie - else - packDWord(&packet, 0); // Unknown - - sendDirectPacket(dc, &packet); -#ifdef _DEBUG - NetLog_Direct("Sent PEER_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); -#endif -} - -// Sends a PEER_INIT packet through a DC -// ----------------------------------------------------------------------- -// This is sent to acknowledge a PEER_INIT packet. - -void CIcqProto::sendPeerInitAck(directconnect* dc) -{ - icq_packet packet; - - directPacketInit(&packet, 4); // Packet length - packLEDWord(&packet, PEER_INIT_ACK); // - - sendDirectPacket(dc, &packet); -#ifdef _DEBUG - NetLog_Direct("Sent PEER_INIT_ACK to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); -#endif -} - -// Sends a PEER_MSG_INIT packet through a DC -// ----------------------------------------------------------------------- -// This packet starts message session. - -void CIcqProto::sendPeerMsgInit(directconnect* dc, DWORD dwSeq) -{ - icq_packet packet; - - directPacketInit(&packet, 33); - packByte(&packet, PEER_MSG_INIT); - packLEDWord(&packet, 10); // unknown - packLEDWord(&packet, 1); // message connection - packLEDWord(&packet, dwSeq); // sequence is 0,1 - if (!dwSeq) - { - packGUID(&packet, PSIG_MESSAGE); // message type GUID - packLEWord(&packet, 1); // delimiter - packLEWord(&packet, 4); - } - else - { - packDWord(&packet, 0); // first part of Message GUID - packDWord(&packet, 0); - packLEWord(&packet, 1); // delimiter - packLEWord(&packet, 4); - packDWord(&packet, 0); // second part of Message GUID - packDWord(&packet, 0); - } - sendDirectPacket(dc, &packet); -#ifdef _DEBUG - NetLog_Direct("Sent PEER_MSG_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); -#endif -} - -// Sends a PEER_FILE_INIT packet through a DC -// ----------------------------------------------------------------------- -// This packet configures file-transfer session. - -void CIcqProto::sendPeerFileInit(directconnect* dc) -{ - icq_packet packet; - DBVARIANT dbv; - char* szNick; - int nNickLen; - - dbv.type = DBVT_DELETED; - if (getSettingString(NULL, "Nick", &dbv)) - szNick = ""; - else - szNick = dbv.pszVal; - nNickLen = strlennull(szNick); - - directPacketInit(&packet, (WORD)(20 + nNickLen)); - packByte(&packet, PEER_FILE_INIT); /* packet type */ - packLEDWord(&packet, 0); /* unknown */ - packLEDWord(&packet, dc->ft->dwFileCount); - packLEDWord(&packet, dc->ft->dwTotalSize); - packLEDWord(&packet, dc->ft->dwTransferSpeed); - packLEWord(&packet, (WORD)(nNickLen + 1)); - packBuffer(&packet, (LPBYTE)szNick, (WORD)(nNickLen + 1)); - sendDirectPacket(dc, &packet); -#ifdef _DEBUG - NetLog_Direct("Sent PEER_FILE_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); -#endif - ICQFreeVariant(&dbv); -} diff --git a/protocols/IcqOscarJ/icq_direct.h b/protocols/IcqOscarJ/icq_direct.h deleted file mode 100644 index 3cf91cb493..0000000000 --- a/protocols/IcqOscarJ/icq_direct.h +++ /dev/null @@ -1,94 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_DIRECT_H -#define __ICQ_DIRECT_H - -struct filetransfer: public basic_filetransfer -{ - int status; - int sending; - int iCurrentFile; - int currentIsDir; - DWORD dwCookie; - DWORD dwUin; - DWORD dwRemotePort; - HANDLE hContact; - char *szFilename; - char *szDescription; - char *szSavePath; - char *szThisFile; - char *szThisSubdir; - char **pszFiles; - DWORD dwThisFileSize; - DWORD dwThisFileDate; - DWORD dwTotalSize; - DWORD dwFileCount; - DWORD dwTransferSpeed; - DWORD dwBytesDone, dwFileBytesDone; - int fileId; - HANDLE hConnection; - DWORD dwLastNotify; - int nVersion; // Was this sent with a v7 or a v8 packet? - BOOL bDC; // Was this received over a DC or through server? - BOOL bEmptyDesc; // Was the description empty ? -}; - -#define DIRECTCONN_STANDARD 0 -#define DIRECTCONN_FILE 1 -#define DIRECTCONN_CHAT 2 -#define DIRECTCONN_REVERSE 10 -#define DIRECTCONN_CLOSING 15 - -struct directconnect -{ - HANDLE hContact; - HANDLE hConnection; - DWORD dwConnectionCookie; - int type; - WORD wVersion; - int incoming; - int wantIdleTime; - int packetPending; - DWORD dwRemotePort; - DWORD dwRemoteUin; - DWORD dwRemoteExternalIP; - DWORD dwRemoteInternalIP; - DWORD dwLocalExternalIP; - DWORD dwLocalInternalIP; - int initialised; - int handshake; - DWORD dwThreadId; - filetransfer *ft; - DWORD dwReqId; // Reverse Connect request cookie -}; - -int DecryptDirectPacket(directconnect* dc, PBYTE buf, WORD wLen); - -#endif /* __ICQ_DIRECT_H */ diff --git a/protocols/IcqOscarJ/icq_directmsg.cpp b/protocols/IcqOscarJ/icq_directmsg.cpp deleted file mode 100644 index 89fbb7cea5..0000000000 --- a/protocols/IcqOscarJ/icq_directmsg.cpp +++ /dev/null @@ -1,361 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleDirectMessage(directconnect* dc, PBYTE buf, WORD wLen) -{ - WORD wCommand; - WORD wCookie; - BYTE bMsgType,bMsgFlags; - WORD wStatus; - WORD wFlags; - WORD wTextLen; - char* pszText = NULL; - - - // The first part of the packet should always be at least 31 bytes - if (wLen < 31) - { - NetLog_Direct("Error during parsing of DC packet 2 PEER_MSG (too short)"); - return; - } - - // Skip packet checksum - buf += 4; - wLen -= 4; - - // Command: - // 0x07d0 = 2000 - cancel given message. - // 0x07da = 2010 - acknowledge message. - // 0x07ee = 2030 - normal message/request. - unpackLEWord(&buf, &wCommand); - wLen -= 2; - - // Unknown, always 0xe (14) - buf += 2; - wLen -= 2; - - // Sequence number - unpackLEWord(&buf, &wCookie); - wLen -=2; - - // Unknown, always zeroes - buf += 12; - wLen -= 12; - - // Peer message type - unpackByte(&buf, &bMsgType); - // Peer message flags - unpackByte(&buf, &bMsgFlags); - wLen -= 2; - - // The current status of the user, or whether the message was accepted or not. - // 0x00 - user is online, or message was receipt, or file transfer accepted - // 0x01 - refused - // 0x04 - auto-refused, because of away - // 0x09 - auto-refused, because of occupied - // 0x0a - auto-refused, because of dnd - // 0x0e - auto-refused, because of na - unpackLEWord(&buf, &wStatus); - wLen -= 2; - - // Flags, or priority - // Seen: 1 - Chat request - // 0 - File auto accept (type 3) - // 33 - priority ? - unpackLEWord(&buf, &wFlags); - wLen -= 2; - - // Messagetext. This is either the status message or the actual message - // when this is a PEER_MSG_MSG packet - unpackLEWord(&buf, &wTextLen); - if (wTextLen > 0) - { - pszText = (char*)_alloca(wTextLen+1); - unpackString(&buf, pszText, wTextLen); - pszText[wTextLen] = '\0'; - } - wLen = (wLen - 2) - wTextLen; - -#ifdef _DEBUG - NetLog_Direct("Handling PEER_MSG '%s', command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", pszText, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); -#else - NetLog_Direct("Message through direct - UID: %u", dc->dwRemoteUin); -#endif - - // The remaining actual message is handled either as a status message request, - // a greeting message, a acknowledge or a normal (text, url, file) message - if (wCommand == DIRECT_MESSAGE) - switch (bMsgType) - { - case MTYPE_FILEREQ: // File inits - handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, pszText, 7, TRUE); - break; - - case MTYPE_AUTOAWAY: - case MTYPE_AUTOBUSY: - case MTYPE_AUTONA: - case MTYPE_AUTODND: - case MTYPE_AUTOFFC: - { - char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(bMsgType)); - if (szMsg) - icq_sendAwayMsgReplyDirect(dc, wCookie, bMsgType, ( const char** )szMsg); - } - break; - - case MTYPE_PLUGIN: // Greeting - handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); - break; - - default: - { - message_ack_params pMsgAck = {0}; - uid_str szUID; - - buf -= wTextLen; - wLen += wTextLen; - - pMsgAck.bType = MAT_DIRECT; - pMsgAck.pDC = dc; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = bMsgType; - pMsgAck.bFlags = bMsgFlags; - handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 0, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, &pMsgAck); - break; - } - } - else if (wCommand == DIRECT_ACK) - { - if (bMsgFlags == 3) - { // this is status reply - uid_str szUID; - - buf -= wTextLen; - wLen += wTextLen; - - handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 2, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, NULL); - } - else - { - HANDLE hCookieContact; - cookie_message_data *pCookieData = NULL; - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { - NetLog_Direct("Received an unexpected direct ack"); - } - else if (hCookieContact != dc->hContact) - { - NetLog_Direct("Direct Contact does not match Cookie Contact(0x%x != 0x%x)", dc->hContact, hCookieContact); - ReleaseCookie(wCookie); // This could be a bad idea, but I think it is safe - } - else - { // the ack is correct - int ackType = -1; - - switch (bMsgType) - { - case MTYPE_PLAIN: - ackType = ACKTYPE_MESSAGE; - break; - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_FILEREQ: // File acks - handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, pszText); - break; - - case MTYPE_PLUGIN: // Greeting - handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); - break; - - default: - NetLog_Direct("Skipped packet from direct connection"); - break; - } - if (ackType != -1) - { // was a good ack to broadcast ? - BroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - ReleaseCookie(wCookie); - } - } - } - } - else if (wCommand == DIRECT_CANCEL) - { - NetLog_Direct("Cannot handle abort messages yet... :("); - } - else - NetLog_Direct("Unknown wCommand, packet skipped"); -} - -void CIcqProto::handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText) -{ - DWORD dwLengthToEnd; - DWORD dwDataLength; - char* pszFileName = NULL; - int typeId; - WORD qt; - -#ifdef _DEBUG - NetLog_Direct("Handling PEER_MSG_GREETING, command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); -#endif - - NetLog_Direct("Parsing Greeting message through direct"); - - if (!unpackPluginTypeId(&buf, &wLen, &typeId, &qt, TRUE)) return; - - // Length of remaining data - unpackLEDWord(&buf, &dwLengthToEnd); - if (dwLengthToEnd < 4 || dwLengthToEnd > wLen) - { - NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 2, dwLengthToEnd, wLen); - return; - } - - // Length of message/reason - unpackLEDWord(&buf, &dwDataLength); - wLen -= 4; - if (dwDataLength > wLen) - { - NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 3, dwDataLength, wLen); - return; - } - - if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_MESSAGE) - { - char* szMsg; - - NetLog_Direct("This is file request"); - szMsg = (char*)_alloca(dwDataLength+1); - unpackString(&buf, szMsg, (WORD)dwDataLength); - szMsg[dwDataLength] = '\0'; - wLen = wLen - (WORD)dwDataLength; - - handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, szMsg, 8, TRUE); - } - else if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_ACK) - { - char* szMsg; - - NetLog_Direct("This is file ack"); - szMsg = (char*)_alloca(dwDataLength+1); - unpackString(&buf, szMsg, (WORD)dwDataLength); - szMsg[dwDataLength] = '\0'; - wLen = wLen - (WORD)dwDataLength; - - // 50 - file request granted/refused - handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, szMsg); - } - else if (typeId && wCommand == DIRECT_MESSAGE) - { - uid_str szUID; - message_ack_params pMsgAck = {0}; - - pMsgAck.bType = MAT_DIRECT; - pMsgAck.pDC = dc; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = typeId; - handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, typeId, 0, 0, dwLengthToEnd, (WORD)dwDataLength, (char*)buf, MTF_PLUGIN | MTF_DIRECT, &pMsgAck); - } - else if (typeId == MTYPE_STATUSMSGEXT && wCommand == DIRECT_ACK) - { // especially for icq2003b - NetLog_Direct("This is extended status reply"); - - char *szMsg = (char*)_alloca(dwDataLength+1); - uid_str szUID; - unpackString(&buf, szMsg, (WORD)dwDataLength); - szMsg[dwDataLength] = '\0'; - - handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)(qt + 0xE7), 3, 2, (DWORD)wLen, (WORD)dwDataLength, szMsg, MTF_PLUGIN | MTF_DIRECT, NULL); - } - else if (typeId && wCommand == DIRECT_ACK) - { - HANDLE hCookieContact; - cookie_message_data *pCookieData = NULL; - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { - NetLog_Direct("Received an unexpected direct ack"); - } - else if (hCookieContact != dc->hContact) - { - NetLog_Direct("Direct Contact does not match Cookie Contact(0x%x != 0x%x)", dc->hContact, hCookieContact); - ReleaseCookie(wCookie); // This could be a bad idea, but I think it is safe - } - else - { - int ackType = -1; - - switch (typeId) - { - case MTYPE_MESSAGE: - ackType = ACKTYPE_MESSAGE; - break; - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - case MTYPE_SCRIPT_NOTIFY: - { - char *szMsg; - - szMsg = (char*)_alloca(dwDataLength + 1); - if (dwDataLength > 0) - memcpy(szMsg, buf, dwDataLength); - szMsg[dwDataLength] = '\0'; - - handleXtrazNotifyResponse(dc->dwRemoteUin, dc->hContact, wCookie, szMsg, dwDataLength); - } - break; - - default: - NetLog_Direct("Skipped packet from direct connection"); - break; - } - - if (ackType != -1) - { // was a good ack to broadcast ? - BroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - } - // Release cookie - ReleaseCookie(wCookie); - } - } - else - NetLog_Direct("Unsupported plugin message type %s", typeId); -} diff --git a/protocols/IcqOscarJ/icq_fieldnames.cpp b/protocols/IcqOscarJ/icq_fieldnames.cpp deleted file mode 100644 index d953a081cf..0000000000 --- a/protocols/IcqOscarJ/icq_fieldnames.cpp +++ /dev/null @@ -1,595 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -const FieldNamesItem countryField[]={ - {9999, LPGEN("Other")}, - {93, LPGEN("Afghanistan")}, - {355, LPGEN("Albania")}, - {213, LPGEN("Algeria")}, - {376, LPGEN("Andorra")}, - {244, LPGEN("Angola")}, - {1264, LPGEN("Anguilla")}, - {1268, LPGEN("Antigua and Barbuda")}, -//{5902, LPGEN("Antilles")}, /* removed: it is not a country, it's a group of islands from diffrent countries (all are included in the list)*/ - {54, LPGEN("Argentina")}, - {374, LPGEN("Armenia")}, - {297, LPGEN("Aruba")}, - {247, LPGEN("Ascension Island")}, - {61, LPGEN("Australia")}, - {6720, LPGEN("Australia, Antarctic Territory")}, /* added country code 672(0)*/ - {614, LPGEN("Australia, Christmas Island")}, /* rename (from Christmas Island) and change to official county code 61(4) (from 672) */ - {61891, LPGEN("Australia, Cocos (Keeling) Islands")}, /* rename and change to official county code 61(891) (from 6102) */ - {6723 , LPGEN("Australia, Norfolk Island")}, /* rename (from Norfolk Island) and change to official county code 672(3) (from 6722) */ - {43, LPGEN("Austria")}, - {994, LPGEN("Azerbaijan")}, - {1242, LPGEN("Bahamas")}, - {973, LPGEN("Bahrain")}, - {880, LPGEN("Bangladesh")}, - {1246, LPGEN("Barbados")}, -//{120, LPGEN("Barbuda")}, /* removed: it is not a country and no special island, see Antigua and Barbuda*/ - {375, LPGEN("Belarus")}, - {32, LPGEN("Belgium")}, - {501, LPGEN("Belize")}, - {229, LPGEN("Benin")}, - {1441, LPGEN("Bermuda")}, - {975, LPGEN("Bhutan")}, - {591, LPGEN("Bolivia")}, - {387, LPGEN("Bosnia and Herzegovina")}, - {267, LPGEN("Botswana")}, - {55, LPGEN("Brazil")}, - {106, LPGEN("British Virgin Islands")}, - {673, LPGEN("Brunei")}, - {359, LPGEN("Bulgaria")}, - {226, LPGEN("Burkina Faso")}, - {257, LPGEN("Burundi")}, - {855, LPGEN("Cambodia")}, - {237, LPGEN("Cameroon")}, - {1002, LPGEN("Canada")}, - {178, LPGEN("Canary Islands")}, - {238, LPGEN("Cape Verde Islands")}, - {1345, LPGEN("Cayman Islands")}, - {236, LPGEN("Central African Republic")}, - {235, LPGEN("Chad")}, - {56, LPGEN("Chile, Republic of")}, - {86, LPGEN("China")}, -//{6101, LPGEN("Cocos (Keeling) Islands")}, /* removed (double): see Australia, Cocos (Keeling) Islands */ - {57, LPGEN("Colombia")}, - {269, LPGEN("Comoros")}, - {243, LPGEN("Congo, Democratic Republic of (Zaire)")}, - {242, LPGEN("Congo, Republic of the")}, - {682, LPGEN("Cook Islands")}, - {506, LPGEN("Costa Rica")}, - {225, LPGEN("Cote d'Ivoire (Ivory Coast)")}, - {385, LPGEN("Croatia")}, - {53, LPGEN("Cuba")}, - {357, LPGEN("Greek, Republic of South Cyprus")}, /* rename coz Turkey, Republic of Northern Cyprus */ - {420, LPGEN("Czech Republic")}, - {45, LPGEN("Denmark")}, - {246, LPGEN("Diego Garcia")}, - {253, LPGEN("Djibouti")}, - {1767, LPGEN("Dominica")}, - {1809, LPGEN("Dominican Republic")}, - {593, LPGEN("Ecuador")}, - {20, LPGEN("Egypt")}, - {503, LPGEN("El Salvador")}, - {240, LPGEN("Equatorial Guinea")}, - {291, LPGEN("Eritrea")}, - {372, LPGEN("Estonia")}, - {251, LPGEN("Ethiopia")}, - {3883,LPGEN("Europe")}, /* add county code +388 3 official European Telephony Numbering Space*/ - {298, LPGEN("Faeroe Islands")}, - {500, LPGEN("Falkland Islands")}, - {679, LPGEN("Fiji")}, - {358, LPGEN("Finland")}, - {33, LPGEN("France")}, - {5901, LPGEN("French Antilles")}, - {594, LPGEN("French Guiana")}, - {689, LPGEN("French Polynesia")}, - {241, LPGEN("Gabon")}, - {220, LPGEN("Gambia")}, - {995, LPGEN("Georgia")}, - {49, LPGEN("Germany")}, - {233, LPGEN("Ghana")}, - {350, LPGEN("Gibraltar")}, - {30, LPGEN("Greece")}, - {299, LPGEN("Greenland")}, - {1473, LPGEN("Grenada")}, - {590, LPGEN("Guadeloupe")}, - {1671, LPGEN("Guam, US Territory of")}, - {502, LPGEN("Guatemala")}, - {224, LPGEN("Guinea")}, - {245, LPGEN("Guinea-Bissau")}, - {592, LPGEN("Guyana")}, - {509, LPGEN("Haiti")}, - {504, LPGEN("Honduras")}, - {852, LPGEN("Hong Kong")}, - {36, LPGEN("Hungary")}, - {354, LPGEN("Iceland")}, - {91, LPGEN("India")}, - {62, LPGEN("Indonesia")}, - {98, LPGEN("Iran (Islamic Republic of)")}, - {964, LPGEN("Iraq")}, - {353, LPGEN("Ireland")}, - {972, LPGEN("Israel")}, - {39, LPGEN("Italy")}, - {1876, LPGEN("Jamaica")}, - {81, LPGEN("Japan")}, - {962, LPGEN("Jordan")}, - {705, LPGEN("Kazakhstan")}, - {254, LPGEN("Kenya")}, - {686, LPGEN("Kiribati")}, - {850, LPGEN("Korea, North")}, - {82, LPGEN("Korea, South")}, - {965, LPGEN("Kuwait")}, - {996, LPGEN("Kyrgyzstan")}, - {856, LPGEN("Laos")}, - {371, LPGEN("Latvia")}, - {961, LPGEN("Lebanon")}, - {266, LPGEN("Lesotho")}, - {231, LPGEN("Liberia")}, - {218, LPGEN("Libyan Arab Jamahiriya")}, - {423, LPGEN("Liechtenstein")}, - {370, LPGEN("Lithuania")}, - {352, LPGEN("Luxembourg")}, - {853, LPGEN("Macau")}, - {389, LPGEN("Macedonia, Republic of")}, - {261, LPGEN("Madagascar")}, - {265, LPGEN("Malawi")}, - {60, LPGEN("Malaysia")}, - {960, LPGEN("Maldives")}, - {223, LPGEN("Mali")}, - {356, LPGEN("Malta")}, - {692, LPGEN("Marshall Islands")}, - {596, LPGEN("Martinique")}, - {222, LPGEN("Mauritania")}, - {230, LPGEN("Mauritius")}, - {262, LPGEN("Mayotte Island")}, - {52, LPGEN("Mexico")}, - {691, LPGEN("Micronesia, Federated States of")}, - {373, LPGEN("Moldova, Republic of")}, - {377, LPGEN("Monaco")}, - {976, LPGEN("Mongolia")}, - {1664, LPGEN("Montserrat")}, - {212, LPGEN("Morocco")}, - {258, LPGEN("Mozambique")}, - {95, LPGEN("Myanmar")}, - {264, LPGEN("Namibia")}, - {674, LPGEN("Nauru")}, - {977, LPGEN("Nepal")}, - {31, LPGEN("Netherlands")}, - {599, LPGEN("Netherlands Antilles")}, /* dissolved 2010 */ - {5995, LPGEN("St. Maarten")}, /* add new country in 2010 (from Netherlands Antilles) */ - {5999, LPGEN("Curacao")}, /* add new country in 2010 (from Netherlands Antilles) */ - {5997, LPGEN("Netherlands (Bonaire Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ - {59946, LPGEN("Netherlands (Saba Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ - {59938, LPGEN("Netherlands (St. Eustatius Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ -//{114, LPGEN("Nevis")}, /* removed: it is not a country, it's part of Saint Kitts and Nevis*/ - {687, LPGEN("New Caledonia")}, - {64, LPGEN("New Zealand")}, - {505, LPGEN("Nicaragua")}, - {227, LPGEN("Niger")}, - {234, LPGEN("Nigeria")}, - {683, LPGEN("Niue")}, - {1670, LPGEN("Northern Mariana Islands, US Territory of")}, /* added NANP */ - {47, LPGEN("Norway")}, - {968, LPGEN("Oman")}, - {92, LPGEN("Pakistan")}, - {680, LPGEN("Palau")}, - {507, LPGEN("Panama")}, - {675, LPGEN("Papua New Guinea")}, - {595, LPGEN("Paraguay")}, - {51, LPGEN("Peru")}, - {63, LPGEN("Philippines")}, - {48, LPGEN("Poland")}, - {351, LPGEN("Portugal")}, - {1939, LPGEN("Puerto Rico")}, - {974, LPGEN("Qatar")}, - {262, LPGEN("Reunion Island")}, - {40, LPGEN("Romania")}, -//{6701, LPGEN("Rota Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ - {7, LPGEN("Russia")}, - {250, LPGEN("Rwanda")}, - {1684, LPGEN("Samoa (USA)")}, /* rename (from American Samoa) change county code to NANP (from 684) */ - {685, LPGEN("Samoa, Western")}, /* rename (from Western Samoa) */ - {290, LPGEN("Saint Helena")}, -//{115, LPGEN("Saint Kitts")}, /* removed: it is not a country it is part of Saint Kitts and Nevis*/ - {1869, LPGEN("Saint Kitts and Nevis")}, - {1758, LPGEN("Saint Lucia")}, - {508, LPGEN("Saint Pierre and Miquelon")}, - {1784, LPGEN("Saint Vincent and the Grenadines")}, -//{670, LPGEN("Saipan Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ - {378, LPGEN("San Marino")}, - {239, LPGEN("Sao Tome and Principe")}, - {966, LPGEN("Saudi Arabia")}, - {442, LPGEN("Scotland")}, - {221, LPGEN("Senegal")}, - {248, LPGEN("Seychelles")}, - {232, LPGEN("Sierra Leone")}, - {65, LPGEN("Singapore")}, - {421, LPGEN("Slovakia")}, - {386, LPGEN("Slovenia")}, - {677, LPGEN("Solomon Islands")}, - {252, LPGEN("Somalia")}, - {27, LPGEN("South Africa")}, - {34, LPGEN("Spain")}, - {3492, LPGEN("Spain, Canary Islands")}, /*rename and change county code to 34(92) spain + canary code*/ - {94, LPGEN("Sri Lanka")}, - {249, LPGEN("Sudan")}, - {597, LPGEN("Suriname")}, - {268, LPGEN("Swaziland")}, - {46, LPGEN("Sweden")}, - {41, LPGEN("Switzerland")}, - {963, LPGEN("Syrian Arab Republic")}, - {886, LPGEN("Taiwan")}, - {992, LPGEN("Tajikistan")}, - {255, LPGEN("Tanzania")}, - {66, LPGEN("Thailand")}, -//{6702, LPGEN("Tinian Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ - {670 , LPGEN("Timor, East")}, /* added (is part off Northern Mariana Islands but not US Territory*/ - {228, LPGEN("Togo")}, - {690, LPGEN("Tokelau")}, - {676, LPGEN("Tonga")}, - {1868, LPGEN("Trinidad and Tobago")}, - {216, LPGEN("Tunisia")}, - {90, LPGEN("Turkey")}, - {90392, LPGEN("Turkey, Republic of Northern Cyprus")}, /* added (is diffrent from Greek part)*/ - {993, LPGEN("Turkmenistan")}, - {1649, LPGEN("Turks and Caicos Islands")}, - {688, LPGEN("Tuvalu")}, - {256, LPGEN("Uganda")}, - {380, LPGEN("Ukraine")}, - {971, LPGEN("United Arab Emirates")}, - {44, LPGEN("United Kingdom")}, - {598, LPGEN("Uruguay")}, - {1, LPGEN("USA")}, - {998, LPGEN("Uzbekistan")}, - {678, LPGEN("Vanuatu")}, - {379, LPGEN("Vatican City")}, - {58, LPGEN("Venezuela")}, - {84, LPGEN("Vietnam")}, - {1284, LPGEN("Virgin Islands (UK)")}, /* change county code to NANP (from 105) - rename coz Virgin Islands (USA) */ - {1340, LPGEN("Virgin Islands (USA)")}, /* change county code to NANP (from 123) */ - {441, LPGEN("Wales")}, - {681, LPGEN("Wallis and Futuna Islands")}, - {967, LPGEN("Yemen")}, - {38, LPGEN("Yugoslavia")}, - {381, LPGEN("Serbia, Republic of")}, /* rename need (from Yugoslavia)*/ - {383, LPGEN("Kosovo, Republic of")}, /*change country code (from 3811), rename need (from Yugoslavia - Serbia) */ - {382, LPGEN("Montenegro, Republic of")}, /* rename need (from Yugoslavia - Montenegro) */ - {260, LPGEN("Zambia")}, - {263, LPGEN("Zimbabwe")}, - {0, NULL} -}; - - -const FieldNamesItem interestsField[]={ - {137, LPGEN("50's")}, - {134, LPGEN("60's")}, - {135, LPGEN("70's")}, - {136, LPGEN("80's")}, - {100, LPGEN("Art")}, - {128, LPGEN("Astronomy")}, - {147, LPGEN("Audio and Visual")}, - {125, LPGEN("Business")}, - {146, LPGEN("Business Services")}, - {101, LPGEN("Cars")}, - {102, LPGEN("Celebrity Fans")}, - {130, LPGEN("Clothing")}, - {103, LPGEN("Collections")}, - {104, LPGEN("Computers")}, - {105, LPGEN("Culture")}, - {122, LPGEN("Ecology")}, - {139, LPGEN("Entertainment")}, - {138, LPGEN("Finance and Corporate")}, - {106, LPGEN("Fitness")}, - {142, LPGEN("Health and Beauty")}, - {108, LPGEN("Hobbies")}, - {150, LPGEN("Home Automation")}, - {144, LPGEN("Household Products")}, - {107, LPGEN("Games")}, - {124, LPGEN("Government")}, - {109, LPGEN("ICQ - Help")}, - {110, LPGEN("Internet")}, - {111, LPGEN("Lifestyle")}, - {145, LPGEN("Mail Order Catalog")}, - {143, LPGEN("Media")}, - {112, LPGEN("Movies and TV")}, - {113, LPGEN("Music")}, - {126, LPGEN("Mystics")}, - {123, LPGEN("News and Media")}, - {114, LPGEN("Outdoors")}, - {115, LPGEN("Parenting")}, - {131, LPGEN("Parties")}, - {116, LPGEN("Pets and Animals")}, - {149, LPGEN("Publishing")}, - {117, LPGEN("Religion")}, - {141, LPGEN("Retail Stores")}, - {118, LPGEN("Science")}, - {119, LPGEN("Skills")}, - {133, LPGEN("Social science")}, - {129, LPGEN("Space")}, - {148, LPGEN("Sporting and Athletic")}, - {120, LPGEN("Sports")}, - {127, LPGEN("Travel")}, - {121, LPGEN("Web Design")}, - {132, LPGEN("Women")}, - {-1, NULL} -}; - - -const FieldNamesItem languageField[]={ - {55, LPGEN("Afrikaans")}, - {58, LPGEN("Albanian")}, - {1, LPGEN("Arabic")}, - {59, LPGEN("Armenian")}, - {68, LPGEN("Azerbaijani")}, - {72, LPGEN("Belorussian")}, - {2, LPGEN("Bhojpuri")}, - {56, LPGEN("Bosnian")}, - {3, LPGEN("Bulgarian")}, - {4, LPGEN("Burmese")}, - {5, LPGEN("Cantonese")}, - {6, LPGEN("Catalan")}, - {61, LPGEN("Chamorro")}, - {7, LPGEN("Chinese")}, - {8, LPGEN("Croatian")}, - {9, LPGEN("Czech")}, - {10, LPGEN("Danish")}, - {11, LPGEN("Dutch")}, - {12, LPGEN("English")}, - {13, LPGEN("Esperanto")}, - {14, LPGEN("Estonian")}, - {15, LPGEN("Farsi")}, - {16, LPGEN("Finnish")}, - {17, LPGEN("French")}, - {18, LPGEN("Gaelic")}, - {19, LPGEN("German")}, - {20, LPGEN("Greek")}, - {70, LPGEN("Gujarati")}, - {21, LPGEN("Hebrew")}, - {22, LPGEN("Hindi")}, - {23, LPGEN("Hungarian")}, - {24, LPGEN("Icelandic")}, - {25, LPGEN("Indonesian")}, - {26, LPGEN("Italian")}, - {27, LPGEN("Japanese")}, - {28, LPGEN("Khmer")}, - {29, LPGEN("Korean")}, - {69, LPGEN("Kurdish")}, - {30, LPGEN("Lao")}, - {31, LPGEN("Latvian")}, - {32, LPGEN("Lithuanian")}, - {65, LPGEN("Macedonian")}, - {33, LPGEN("Malay")}, - {63, LPGEN("Mandarin")}, - {62, LPGEN("Mongolian")}, - {34, LPGEN("Norwegian")}, - {57, LPGEN("Persian")}, - {35, LPGEN("Polish")}, - {36, LPGEN("Portuguese")}, - {60, LPGEN("Punjabi")}, - {37, LPGEN("Romanian")}, - {38, LPGEN("Russian")}, - {39, LPGEN("Serbian")}, - {66, LPGEN("Sindhi")}, - {40, LPGEN("Slovak")}, - {41, LPGEN("Slovenian")}, - {42, LPGEN("Somali")}, - {43, LPGEN("Spanish")}, - {44, LPGEN("Swahili")}, - {45, LPGEN("Swedish")}, - {46, LPGEN("Tagalog")}, - {64, LPGEN("Taiwanese")}, - {71, LPGEN("Tamil")}, - {47, LPGEN("Tatar")}, - {48, LPGEN("Thai")}, - {49, LPGEN("Turkish")}, - {50, LPGEN("Ukrainian")}, - {51, LPGEN("Urdu")}, - {52, LPGEN("Vietnamese")}, - {67, LPGEN("Welsh")}, - {53, LPGEN("Yiddish")}, - {54, LPGEN("Yoruba")}, - {0, NULL} -}; - - -const FieldNamesItem pastField[]={ - {300, LPGEN("Elementary School")}, - {301, LPGEN("High School")}, - {302, LPGEN("College")}, - {303, LPGEN("University")}, - {304, LPGEN("Military")}, - {305, LPGEN("Past Work Place")}, - {306, LPGEN("Past Organization")}, - {399, LPGEN("Other")}, - {0, NULL} -}; - - -const FieldNamesItem genderField[]={ - {'F', LPGEN("Female")}, - {'M', LPGEN("Male")}, - {0, NULL} -}; - - -const FieldNamesItem studyLevelField[]={ - {4, LPGEN("Associated degree")}, - {5, LPGEN("Bachelor's degree")}, - {1, LPGEN("Elementary")}, - {2, LPGEN("High-school")}, - {6, LPGEN("Master's degree")}, - {7, LPGEN("PhD")}, - {8, LPGEN("Postdoctoral")}, - {3, LPGEN("University / College")}, - {0, NULL} -}; - - -const FieldNamesItem industryField[]={ - {2, LPGEN("Agriculture")}, - {3, LPGEN("Arts")}, - {4, LPGEN("Construction")}, - {5, LPGEN("Consumer Goods")}, - {6, LPGEN("Corporate Services")}, - {7, LPGEN("Education")}, - {8, LPGEN("Finance")}, - {9, LPGEN("Government")}, - {10, LPGEN("High Tech")}, - {11, LPGEN("Legal")}, - {12, LPGEN("Manufacturing")}, - {13, LPGEN("Media")}, - {14, LPGEN("Medical & Health Care")}, - {15, LPGEN("Non-Profit Organization Management")}, - {19, LPGEN("Other")}, - {16, LPGEN("Recreation, Travel & Entertainment")}, - {17, LPGEN("Service Industry")}, - {18, LPGEN("Transportation")}, - {0, NULL} -}; - - -const FieldNamesItem occupationField[]={ - {1, LPGEN("Academic")}, - {2, LPGEN("Administrative")}, - {3, LPGEN("Art/Entertainment")}, - {4, LPGEN("College Student")}, - {5, LPGEN("Computers")}, - {6, LPGEN("Community & Social")}, - {7, LPGEN("Education")}, - {8, LPGEN("Engineering")}, - {9, LPGEN("Financial Services")}, - {10, LPGEN("Government")}, - {11, LPGEN("High School Student")}, - {12, LPGEN("Home")}, - {13, LPGEN("ICQ - Providing Help")}, - {14, LPGEN("Law")}, - {15, LPGEN("Managerial")}, - {16, LPGEN("Manufacturing")}, - {17, LPGEN("Medical/Health")}, - {18, LPGEN("Military")}, - {19, LPGEN("Non-Government Organization")}, - {20, LPGEN("Professional")}, - {21, LPGEN("Retail")}, - {22, LPGEN("Retired")}, - {23, LPGEN("Science & Research")}, - {24, LPGEN("Sports")}, - {25, LPGEN("Technical")}, - {26, LPGEN("University Student")}, - {27, LPGEN("Web Building")}, - {99, LPGEN("Other Services")}, - {0, NULL} -}; - - -const FieldNamesItem affiliationField[]={ - {200, LPGEN("Alumni Org.")}, - {201, LPGEN("Charity Org.")}, - {202, LPGEN("Club/Social Org.")}, - {203, LPGEN("Community Org.")}, - {204, LPGEN("Cultural Org.")}, - {205, LPGEN("Fan Clubs")}, - {206, LPGEN("Fraternity/Sorority")}, - {207, LPGEN("Hobbyists Org.")}, - {208, LPGEN("International Org.")}, - {209, LPGEN("Nature and Environment Org.")}, - {210, LPGEN("Professional Org.")}, - {211, LPGEN("Scientific/Technical Org.")}, - {212, LPGEN("Self Improvement Group")}, - {213, LPGEN("Spiritual/Religious Org.")}, - {214, LPGEN("Sports Org.")}, - {215, LPGEN("Support Org.")}, - {216, LPGEN("Trade and Business Org.")}, - {217, LPGEN("Union")}, - {218, LPGEN("Volunteer Org.")}, - {299, LPGEN("Other")}, - {0, NULL} -}; - - -const FieldNamesItem agesField[]={ - {0x0011000D, LPGEN("13-17")}, - {0x00160012, LPGEN("18-22")}, - {0x001D0017, LPGEN("23-29")}, - {0x0027001E, LPGEN("30-39")}, - {0x00310028, LPGEN("40-49")}, - {0x003B0032, LPGEN("50-59")}, - {0x2710003C, LPGEN("60-above")}, - {-1, NULL} -}; - - -const FieldNamesItem maritalField[]={ - {10, LPGEN("Single")}, - {11, LPGEN("Close relationships")}, - {12, LPGEN("Engaged")}, - {20, LPGEN("Married")}, - {30, LPGEN("Divorced")}, - {31, LPGEN("Separated")}, - {40, LPGEN("Widowed")}, - {50, LPGEN("Open relationship")}, - {255, LPGEN("Other")}, - {0, NULL} -}; - - -char *LookupFieldName(const FieldNamesItem *table, int code) -{ - int i; - - if (code != 0) - { - for(i = 0; table[i].text; i++) - { - if (table[i].code == code) - return table[i].text; - } - - // Tried to get unexisting field name, you have an - // error in the data or in the table - _ASSERT(FALSE); - } - - return NULL; -} - - -char *LookupFieldNameUtf(const FieldNamesItem *table, int code, char *str, size_t strsize) -{ - char *szText = LookupFieldName(table, code); - - if (szText) - return ICQTranslateUtfStatic(szText, str, strsize); - - return NULL; -} diff --git a/protocols/IcqOscarJ/icq_fieldnames.h b/protocols/IcqOscarJ/icq_fieldnames.h deleted file mode 100644 index cf15475299..0000000000 --- a/protocols/IcqOscarJ/icq_fieldnames.h +++ /dev/null @@ -1,49 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -struct FieldNamesItem -{ - int code; - char *text; -}; - -extern const FieldNamesItem countryField[]; -extern const FieldNamesItem interestsField[]; -extern const FieldNamesItem languageField[]; -extern const FieldNamesItem pastField[]; -extern const FieldNamesItem genderField[]; -extern const FieldNamesItem agesField[]; -extern const FieldNamesItem studyLevelField[]; -extern const FieldNamesItem industryField[]; -extern const FieldNamesItem occupationField[]; -extern const FieldNamesItem affiliationField[]; -extern const FieldNamesItem maritalField[]; - -char *LookupFieldName(const FieldNamesItem *table, int code); -char *LookupFieldNameUtf(const FieldNamesItem *table, int code, char *str, size_t strsize); diff --git a/protocols/IcqOscarJ/icq_filerequests.cpp b/protocols/IcqOscarJ/icq_filerequests.cpp deleted file mode 100644 index d85de72580..0000000000 --- a/protocols/IcqOscarJ/icq_filerequests.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -void CIcqProto::handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText) -{ - char* pszFileName = NULL; - DWORD dwFileSize; - HANDLE hCookieContact; - WORD wPort; - WORD wFilenameLength; - filetransfer* ft; - - - // Find the filetransfer that belongs to this response - if (!FindCookie(dwCookie, &hCookieContact, (void**)&ft)) - { - NetLog_Direct("Error: Received unexpected file transfer request response"); - return; - } - - FreeCookie(dwCookie); - - if (hCookieContact != HContactFromUIN(dwUin, NULL)) - { - NetLog_Direct("Error: UINs do not match in file transfer request response"); - return; - } - - // If status != 0, a request has been denied - if (wStatus != 0) - { - NetLog_Direct("File transfer denied by %u.", dwUin); - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)ft, 0); - - FreeCookie(dwCookie); - - return; - } - - if (wLen < 6) - { // sanity check - NetLog_Direct("Ignoring malformed file transfer request response"); - return; - } - - // Port to connect to - unpackWord(&buf, &wPort); - ft->dwRemotePort = wPort; - wLen -= 2; - - // Unknown - buf += 2; - wLen -= 2; - - // Filename - unpackLEWord(&buf, &wFilenameLength); - if (wFilenameLength > 0) - { - if (wFilenameLength > wLen - 2) - wFilenameLength = wLen - 2; - pszFileName = (char*)_alloca(wFilenameLength+1); - unpackString(&buf, pszFileName, wFilenameLength); - pszFileName[wFilenameLength] = '\0'; - } - wLen = wLen - 2 - wFilenameLength; - - if (wLen >= 4) - { // Total filesize - unpackLEDWord(&buf, &dwFileSize); - wLen -= 4; - } - else - dwFileSize = 0; - - NetLog_Direct("File transfer ack from %u, port %u, name %s, size %u", dwUin, ft->dwRemotePort, pszFileName, dwFileSize); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft, 0); - - OpenDirectConnection(ft->hContact, DIRECTCONN_FILE, ft); -} - -filetransfer* CIcqProto::CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion) -{ - filetransfer *ft = CreateIcqFileTransfer(); - - ft->dwUin = dwUin; - ft->hContact = hContact; - ft->nVersion = nVersion; - ft->pMessage.bMessageType = MTYPE_FILEREQ; - InitMessageCookie(&ft->pMessage); - - return ft; -} - -// pszDescription points to a string with the reason -// buf points to the first data after the string -void CIcqProto::handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC) -{ - BOOL bEmptyDesc = FALSE; - if (strlennull(pszDescription) == 0) { - pszDescription = Translate("No description given"); - bEmptyDesc = TRUE; - } - - // Empty port+pad - buf += 4; - wLen -= 4; - - // Filename - WORD wFilenameLength; - unpackLEWord(&buf, &wFilenameLength); - if (!wFilenameLength) { - NetLog_Direct("Ignoring malformed file send request"); - return; - } - - char *pszFileName = (char*)_alloca(wFilenameLength + 1); - unpackString(&buf, pszFileName, wFilenameLength); - pszFileName[wFilenameLength] = '\0'; - - wLen = wLen - 2 - wFilenameLength; - - // Total filesize - DWORD dwFileSize; - unpackLEDWord(&buf, &dwFileSize); - wLen -= 4; - - int bAdded; - HANDLE hContact = HContactFromUIN(dwUin, &bAdded); - - // Initialize a filetransfer struct - filetransfer *ft = CreateFileTransfer(hContact, dwUin, nVersion); - ft->dwCookie = dwCookie; - ft->szFilename = mir_strdup(pszFileName); - ft->szDescription = 0; - ft->fileId = -1; - ft->dwTotalSize = dwFileSize; - ft->pMessage.dwMsgID1 = dwID1; - ft->pMessage.dwMsgID2 = dwID2; - ft->bDC = bDC; - ft->bEmptyDesc = bEmptyDesc; - - // Send chain event - TCHAR* ptszFileName = mir_utf8decodeT(pszFileName); - - PROTORECVFILET pre = {0}; - pre.flags = PREF_TCHAR; - pre.fileCount = 1; - pre.timestamp = time(NULL); - pre.tszDescription = mir_utf8decodeT(pszDescription); - pre.ptszFiles = &ptszFileName; - pre.lParam = (LPARAM)ft; - - CCSDATA ccs; - ccs.szProtoService = PSR_FILE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - mir_free(pre.tszDescription); - mir_free(ptszFileName); -} - -void CIcqProto::handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText) -{ - NetLog_Direct("handleDirectCancel: Unhandled cancel"); -} - -// ******************************************************************************* - -void CIcqProto::icq_CancelFileTransfer(HANDLE hContact, filetransfer* ft) -{ - DWORD dwCookie; - - if (FindCookieByData(ft, &dwCookie, NULL)) - FreeCookie(dwCookie); /* this bit stops a send that's waiting for acceptance */ - - if (IsValidFileTransfer(ft)) - { // Transfer still out there, end it - NetLib_CloseConnection(&ft->hConnection, FALSE); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - - if (!FindFileTransferDC(ft)) - { // Release orphan structure only - SafeReleaseFileTransfer((void**)&ft); - } - } -} diff --git a/protocols/IcqOscarJ/icq_filetransfer.cpp b/protocols/IcqOscarJ/icq_filetransfer.cpp deleted file mode 100644 index 61484c3987..0000000000 --- a/protocols/IcqOscarJ/icq_filetransfer.cpp +++ /dev/null @@ -1,515 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static void file_buildProtoFileTransferStatus(filetransfer* ft, PROTOFILETRANSFERSTATUS* pfts) -{ - ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS)); - pfts->cbSize = sizeof(PROTOFILETRANSFERSTATUS); - pfts->hContact = ft->hContact; - pfts->flags = PFTS_UTF | (ft->sending ? PFTS_SENDING : PFTS_RECEIVING); /* Standard FT is Ansi only */ - if (ft->sending) - pfts->pszFiles = ft->pszFiles; - else - pfts->pszFiles = NULL; /* FIXME */ - pfts->totalFiles = ft->dwFileCount; - pfts->currentFileNumber = ft->iCurrentFile; - pfts->totalBytes = ft->dwTotalSize; - pfts->totalProgress = ft->dwBytesDone; - pfts->szWorkingDir = ft->szSavePath; - pfts->szCurrentFile = ft->szThisFile; - pfts->currentFileSize = ft->dwThisFileSize; - pfts->currentFileTime = ft->dwThisFileDate; - pfts->currentFileProgress = ft->dwFileBytesDone; -} - - -static void file_sendTransferSpeed(CIcqProto* ppro, directconnect* dc) -{ - icq_packet packet; - - directPacketInit(&packet, 5); - packByte(&packet, PEER_FILE_SPEED); /* Ident */ - packLEDWord(&packet, dc->ft->dwTransferSpeed); - ppro->sendDirectPacket(dc, &packet); -} - - -static void file_sendNick(CIcqProto* ppro, directconnect* dc) -{ - icq_packet packet; - char* szNick; - WORD wNickLen; - DBVARIANT dbv = {DBVT_DELETED}; - - if (ppro->getSettingString(NULL, "Nick", &dbv)) - szNick = ""; - else - szNick = dbv.pszVal; - - wNickLen = strlennull(szNick); - - directPacketInit(&packet, (WORD)(8 + wNickLen)); - packByte(&packet, PEER_FILE_INIT_ACK); /* Ident */ - packLEDWord(&packet, dc->ft->dwTransferSpeed); - packLEWord(&packet, (WORD)(wNickLen + 1)); - packBuffer(&packet, (LPBYTE)szNick, (WORD)(wNickLen + 1)); - ppro->sendDirectPacket(dc, &packet); - ICQFreeVariant(&dbv); -} - - -static void file_sendNextFile(CIcqProto* ppro, directconnect* dc) -{ - icq_packet packet; - struct _stati64 statbuf; - char szThisSubDir[MAX_PATH]; - - if (dc->ft->iCurrentFile >= (int)dc->ft->dwFileCount) - { - ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0); - ppro->CloseDirectConnection(dc); - dc->ft->hConnection = NULL; - return; - } - - dc->ft->szThisFile = dc->ft->pszFiles[dc->ft->iCurrentFile]; - if (FileStatUtf(dc->ft->szThisFile, &statbuf)) - { - ppro->icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); - ppro->CloseDirectConnection(dc); - dc->ft->hConnection = NULL; - return; - } - - char *pszThisFileName = FindFilePathContainer((LPCSTR*)dc->ft->pszFiles, dc->ft->iCurrentFile, szThisSubDir); - - if (statbuf.st_mode&_S_IFDIR) - { - dc->ft->currentIsDir = 1; - } - else - { - dc->ft->currentIsDir = 0; - dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_RDONLY, _S_IREAD); - if (dc->ft->fileId == -1) - { - ppro->icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); - ppro->CloseDirectConnection(dc); - dc->ft->hConnection = NULL; - return; - } - - } - dc->ft->dwThisFileSize = statbuf.st_size; - dc->ft->dwThisFileDate = statbuf.st_mtime; - dc->ft->dwFileBytesDone = 0; - - char *szThisFileNameAnsi = NULL, *szThisSubDirAnsi = NULL; - if (!utf8_decode(pszThisFileName, &szThisFileNameAnsi)) - szThisFileNameAnsi = NULL; - if (!utf8_decode(szThisSubDir, &szThisSubDirAnsi)) - szThisSubDirAnsi = NULL; - WORD wThisFileNameLen = strlennull(szThisFileNameAnsi); - WORD wThisSubDirLen = strlennull(szThisSubDirAnsi); - - directPacketInit(&packet, (WORD)(20 + wThisFileNameLen + wThisSubDirLen)); - packByte(&packet, PEER_FILE_NEXTFILE); /* Ident */ - packByte(&packet, (BYTE)((statbuf.st_mode & _S_IFDIR) != 0)); // Is subdir - packLEWord(&packet, (WORD)(wThisFileNameLen + 1)); - packBuffer(&packet, (LPBYTE)szThisFileNameAnsi, (WORD)(wThisFileNameLen + 1)); - packLEWord(&packet, (WORD)(wThisSubDirLen + 1)); - packBuffer(&packet, (LPBYTE)szThisSubDirAnsi, (WORD)(wThisSubDirLen + 1)); - packLEDWord(&packet, dc->ft->dwThisFileSize); - packLEDWord(&packet, statbuf.st_mtime); - packLEDWord(&packet, dc->ft->dwTransferSpeed); - SAFE_FREE(&szThisFileNameAnsi); - SAFE_FREE(&szThisSubDirAnsi); - ppro->sendDirectPacket(dc, &packet); - - ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0); -} - - -static void file_sendResume(CIcqProto* ppro, directconnect* dc) -{ - icq_packet packet; - - directPacketInit(&packet, 17); - packByte(&packet, PEER_FILE_RESUME); /* Ident */ - packLEDWord(&packet, dc->ft->dwFileBytesDone); /* file resume */ - packLEDWord(&packet, 0); /* unknown */ - packLEDWord(&packet, dc->ft->dwTransferSpeed); - packLEDWord(&packet, dc->ft->iCurrentFile + 1); /* file number */ - ppro->sendDirectPacket(dc, &packet); -} - - -static void file_sendData(CIcqProto* ppro, directconnect* dc) -{ - BYTE buf[2048]; - int bytesRead = 0; - - if (!dc->ft->currentIsDir) - { - icq_packet packet; - - if (dc->ft->fileId == -1) - return; - bytesRead = _read(dc->ft->fileId, buf, sizeof(buf)); - if (bytesRead == -1) - return; - - directPacketInit(&packet, (WORD)(1 + bytesRead)); - packByte(&packet, PEER_FILE_DATA); /* Ident */ - packBuffer(&packet, buf, (WORD)bytesRead); - ppro->sendDirectPacket(dc, &packet); - } - - dc->ft->dwBytesDone += bytesRead; - dc->ft->dwFileBytesDone += bytesRead; - - if (GetTickCount() > dc->ft->dwLastNotify + 500 || bytesRead == 0) - { - PROTOFILETRANSFERSTATUS pfts; - - file_buildProtoFileTransferStatus(dc->ft, &pfts); - ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts); - - dc->ft->dwLastNotify = GetTickCount(); - } - - if (bytesRead == 0) - { - if (!dc->ft->currentIsDir) _close(dc->ft->fileId); - dc->ft->fileId = -1; - dc->wantIdleTime = 0; - dc->ft->iCurrentFile++; - file_sendNextFile(ppro, dc); /* this will close the socket if no more files */ - } -} - - -void CIcqProto::handleFileTransferIdle(directconnect* dc) -{ - file_sendData(this, dc); -} - - -void CIcqProto::icq_sendFileResume(filetransfer *ft, int action, const char *szFilename) -{ - if (ft->hConnection == NULL) - return; - - directconnect *dc = FindFileTransferDC(ft); - if (!dc) return; // something is broken... - - int openFlags; - - switch (action) - { - case FILERESUME_RESUME: - openFlags = _O_BINARY | _O_WRONLY; - break; - - case FILERESUME_OVERWRITE: - openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; - ft->dwFileBytesDone = 0; - break; - - case FILERESUME_SKIP: - openFlags = _O_BINARY | _O_WRONLY; - ft->dwFileBytesDone = ft->dwThisFileSize; - break; - - case FILERESUME_RENAME: - openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; - SAFE_FREE(&ft->szThisFile); - ft->szThisFile = null_strdup(szFilename); - ft->dwFileBytesDone = 0; - break; - } - - ft->fileId = OpenFileUtf(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE); - if (ft->fileId == -1) - { - icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); - NetLib_CloseConnection(&ft->hConnection, FALSE); - return; - } - - if (action == FILERESUME_RESUME) - ft->dwFileBytesDone = _lseek(ft->fileId, 0, SEEK_END); - else - _lseek(ft->fileId, ft->dwFileBytesDone, SEEK_SET); - - ft->dwBytesDone += ft->dwFileBytesDone; - - file_sendResume(this, dc); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); -} - - -// small utility function -void NormalizeBackslash(char* path) -{ - int len = strlennull(path); - - if (len && path[len-1] != '\\') strcat(path, "\\"); -} - -/* a file transfer looks like this: -S: 0 -R: 5 -R: 1 -S: 2 -R: 3 -S: 6 * many -(for more files, send 2, 3, 6*many) -*/ - -void CIcqProto::handleFileTransferPacket(directconnect* dc, PBYTE buf, WORD wLen) -{ - if (wLen < 1) - return; - - NetLog_Direct("Handling file packet"); - - switch (buf[0]) - { - case PEER_FILE_INIT: /* first packet of a file transfer */ - if (dc->initialised) - return; - if (wLen < 19) - return; - buf += 5; /* id, and unknown 0 */ - dc->type = DIRECTCONN_FILE; - { - DWORD dwFileCount; - DWORD dwTotalSize; - DWORD dwTransferSpeed; - WORD wNickLength; - int bAdded; - - unpackLEDWord(&buf, &dwFileCount); - unpackLEDWord(&buf, &dwTotalSize); - unpackLEDWord(&buf, &dwTransferSpeed); - unpackLEWord(&buf, &wNickLength); - - dc->ft = FindExpectedFileRecv(dc->dwRemoteUin, dwTotalSize); - if (dc->ft == NULL) - { - NetLog_Direct("Unexpected file receive"); - CloseDirectConnection(dc); - return; - } - dc->ft->dwFileCount = dwFileCount; - dc->ft->dwTransferSpeed = dwTransferSpeed; - dc->ft->hContact = HContactFromUIN(dc->ft->dwUin, &bAdded); - dc->ft->dwBytesDone = 0; - dc->ft->iCurrentFile = -1; - dc->ft->fileId = -1; - dc->ft->hConnection = dc->hConnection; - dc->ft->dwLastNotify = GetTickCount(); - - dc->initialised = 1; - - file_sendTransferSpeed(this, dc); - file_sendNick(this, dc); - } - BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, dc->ft, 0); - break; - - case PEER_FILE_INIT_ACK: - if (wLen < 8) - return; - buf++; - unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); - /* followed by nick */ - file_sendNextFile(this, dc); - break; - - case PEER_FILE_NEXTFILE: - if (wLen < 20) - return; - buf++; /* id */ - { - char *szAnsi; - WORD wThisFilenameLen, wSubdirLen; - BYTE isDirectory; - - unpackByte(&buf, &isDirectory); - unpackLEWord(&buf, &wThisFilenameLen); - if (wLen < 19 + wThisFilenameLen) - return; - SAFE_FREE(&dc->ft->szThisFile); - szAnsi = (char *)_alloca(wThisFilenameLen + 1); - memcpy(szAnsi, buf, wThisFilenameLen); - szAnsi[wThisFilenameLen] = '\0'; - dc->ft->szThisFile = ansi_to_utf8(szAnsi); - buf += wThisFilenameLen; - - unpackLEWord(&buf, &wSubdirLen); - if (wLen < 18 + wThisFilenameLen + wSubdirLen) - return; - SAFE_FREE(&dc->ft->szThisSubdir); - szAnsi = (char *)_alloca(wSubdirLen + 1); - memcpy(szAnsi, buf, wSubdirLen); - szAnsi[wSubdirLen] = '\0'; - dc->ft->szThisSubdir = ansi_to_utf8(szAnsi); - buf += wSubdirLen; - - unpackLEDWord(&buf, &dc->ft->dwThisFileSize); - unpackLEDWord(&buf, &dc->ft->dwThisFileDate); - unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); - - /* no cheating with paths */ - if (!IsValidRelativePath(dc->ft->szThisFile) || !IsValidRelativePath(dc->ft->szThisSubdir)) - { - NetLog_Direct("Invalid path information"); - break; - } - - char *szFullPath = (char*)SAFE_MALLOC(strlennull(dc->ft->szSavePath)+strlennull(dc->ft->szThisSubdir)+strlennull(dc->ft->szThisFile)+3); - strcpy(szFullPath, dc->ft->szSavePath); - NormalizeBackslash(szFullPath); - strcat(szFullPath, dc->ft->szThisSubdir); - NormalizeBackslash(szFullPath); -// _chdir(szFullPath); // set current dir - not very useful - strcat(szFullPath, dc->ft->szThisFile); - // we joined the full path to dest file - SAFE_FREE(&dc->ft->szThisFile); - dc->ft->szThisFile = szFullPath; - - dc->ft->dwFileBytesDone = 0; - dc->ft->iCurrentFile++; - - if (isDirectory) - { - MakeDirUtf(dc->ft->szThisFile); - dc->ft->fileId = -1; - } - else - { - /* file resume */ - PROTOFILETRANSFERSTATUS pfts = {0}; - - file_buildProtoFileTransferStatus(dc->ft, &pfts); - if (BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, dc->ft, (LPARAM)&pfts)) - break; /* UI supports resume: it will call PS_FILERESUME */ - - dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); - if (dc->ft->fileId == -1) - { - icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); - CloseDirectConnection(dc); - dc->ft->hConnection = NULL; - break; - } - } - } - file_sendResume(this, dc); - BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0); - break; - - case PEER_FILE_RESUME: - if (dc->ft->fileId == -1 && !dc->ft->currentIsDir) - return; - if (wLen < 13) - return; - if (wLen < 17) - NetLog_Direct("Warning: Received short PEER_FILE_RESUME"); - buf++; - { - DWORD dwRestartFrom; - - unpackLEDWord(&buf, &dwRestartFrom); - if (dwRestartFrom > dc->ft->dwThisFileSize) - return; - buf += 4; /* unknown. 0 */ - unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); - buf += 4; /* unknown. 1 */ - if (!dc->ft->currentIsDir) - _lseek(dc->ft->fileId, dwRestartFrom, 0); - dc->wantIdleTime = 1; - dc->ft->dwBytesDone += dwRestartFrom; - dc->ft->dwFileBytesDone += dwRestartFrom; - } - break; - - case PEER_FILE_SPEED: - if (wLen < 5) - return; - buf++; - unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); - dc->ft->dwLastNotify = GetTickCount(); - break; - - case PEER_FILE_DATA: - if (!dc->ft->currentIsDir) - { - if (dc->ft->fileId == -1) - break; - buf++; wLen--; - _write(dc->ft->fileId, buf, wLen); - } - else - wLen = 0; - dc->ft->dwBytesDone += wLen; - dc->ft->dwFileBytesDone += wLen; - if (GetTickCount() > dc->ft->dwLastNotify + 500 || wLen < 2048) - { - PROTOFILETRANSFERSTATUS pfts; - - file_buildProtoFileTransferStatus(dc->ft, &pfts); - BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts); - dc->ft->dwLastNotify = GetTickCount(); - } - if (wLen < 2048) - { - /* EOF */ - if (!dc->ft->currentIsDir) - _close(dc->ft->fileId); - dc->ft->fileId = -1; - if ((DWORD)dc->ft->iCurrentFile == dc->ft->dwFileCount - 1) - { - dc->type = DIRECTCONN_CLOSING; /* this guarantees that we won't accept any more data but that the sender is still free to closesocket() neatly */ - BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0); - } - } - break; - - default: - NetLog_Direct("Unknown file transfer packet ignored."); - break; - } -} diff --git a/protocols/IcqOscarJ/icq_firstrun.cpp b/protocols/IcqOscarJ/icq_firstrun.cpp deleted file mode 100644 index 1208d6d0ec..0000000000 --- a/protocols/IcqOscarJ/icq_firstrun.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -static void accountLoadDetails(CIcqProto *ppro, HWND hwndDlg) -{ - char pszUIN[20]; - DWORD dwUIN = ppro->getContactUin(NULL); - if (dwUIN) - { - null_snprintf(pszUIN, 20, "%u", dwUIN); - SetDlgItemTextA(hwndDlg, IDC_UIN, pszUIN); - } - - char pszPwd[PASSWORDMAXLEN]; - if (ppro->GetUserStoredPassword(pszPwd, PASSWORDMAXLEN)) - SetDlgItemTextA(hwndDlg, IDC_PW, pszPwd); -} - - -INT_PTR CALLBACK icq_FirstRunDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - { - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ppro->m_hIconProtocol->GetIcon(true)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ppro->m_hIconProtocol->GetIcon()); - - SendDlgItemMessage(hwndDlg, IDC_PW, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); - - accountLoadDetails(ppro, hwndDlg); - } - return TRUE; - - case WM_DESTROY: - ppro->m_hIconProtocol->ReleaseIcon(true); - ppro->m_hIconProtocol->ReleaseIcon(); - break; - - case WM_CLOSE: - EndDialog(hwndDlg, 0); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_REGISTER: - CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_REGISTER); - break; - - case IDC_UIN: - case IDC_PW: - if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) - { - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - break; - } - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) - { - case PSN_APPLY: - { - char str[128]; - GetDlgItemTextA(hwndDlg, IDC_UIN, str, sizeof(str)); - ppro->setSettingDword(NULL, UNIQUEIDSETTING, atoi(str)); - GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(ppro->m_szPassword)); - strcpy(ppro->m_szPassword, str); - CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ppro->m_szPassword), (LPARAM) str); - ppro->setSettingString(NULL, "Password", str); - } - break; - - case PSN_RESET: - accountLoadDetails(ppro, hwndDlg); - break; - } - break; - } - - return FALSE; -} - - -INT_PTR CIcqProto::OnCreateAccMgrUI(WPARAM wParam, LPARAM lParam) -{ - return (INT_PTR)CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ICQACCOUNT), (HWND)lParam, icq_FirstRunDlgProc, LPARAM(this)); -} diff --git a/protocols/IcqOscarJ/icq_http.cpp b/protocols/IcqOscarJ/icq_http.cpp deleted file mode 100644 index 3e50db43ed..0000000000 --- a/protocols/IcqOscarJ/icq_http.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004,2005,2006 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// HTTP Gateway Handling routines -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -int icq_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr) -{ - // initial response from ICQ http gateway - WORD wLen, wVersion, wType; - WORD wIpLen; - DWORD dwSid1, dwSid2, dwSid3, dwSid4; - BYTE *buf; - char szSid[33], szHttpServer[256], szHttpGetUrl[300], szHttpPostUrl[300]; - NETLIBHTTPPROXYINFO nlhpi = {0}; - - if (nlhr->dataLength < 31) - { - SetLastError(ERROR_INVALID_DATA); - return 0; - } - - buf = (PBYTE)nlhr->pData; - unpackWord(&buf, &wLen); - unpackWord(&buf, &wVersion); /* always 0x0443 */ - unpackWord(&buf, &wType); /* hello reply */ - buf += 6; /* dunno */ - unpackDWord(&buf, &dwSid1); - unpackDWord(&buf, &dwSid2); - unpackDWord(&buf, &dwSid3); - unpackDWord(&buf, &dwSid4); - null_snprintf(szSid, 33, "%08x%08x%08x%08x", dwSid1, dwSid2, dwSid3, dwSid4); - unpackWord(&buf, &wIpLen); - - if(nlhr->dataLength < 30 + wIpLen || wIpLen == 0 || wIpLen > sizeof(szHttpServer) - 1) - { - SetLastError(ERROR_INVALID_DATA); - return 0; - } - - SetGatewayIndex(hConn, 1); // new master connection begins here - - memcpy(szHttpServer, buf, wIpLen); - szHttpServer[wIpLen] = '\0'; - - nlhpi.cbSize = sizeof(nlhpi); - nlhpi.flags = NLHPIF_USEPOSTSEQUENCE; - nlhpi.szHttpGetUrl = szHttpGetUrl; - nlhpi.szHttpPostUrl = szHttpPostUrl; - nlhpi.firstPostSequence = 1; - null_snprintf(szHttpGetUrl, 300, "http://%s/monitor?sid=%s", szHttpServer, szSid); - null_snprintf(szHttpPostUrl, 300, "http://%s/data?sid=%s&seq=", szHttpServer, szSid); - - return CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi); -} - - - -int icq_httpGatewayBegin(HANDLE hConn, NETLIBOPENCONNECTION* nloc) -{ // open our "virual data connection" - icq_packet packet; - size_t serverNameLen; - - serverNameLen = strlennull(nloc->szHost); - - packet.wLen = (WORD)(serverNameLen + 4); - write_httphdr(&packet, HTTP_PACKETTYPE_LOGIN, GetGatewayIndex(hConn)); - packWord(&packet, (WORD)serverNameLen); - packBuffer(&packet, (LPBYTE)nloc->szHost, (WORD)serverNameLen); - packWord(&packet, nloc->wPort); - INT_PTR res = Netlib_Send(hConn, (char*)packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP); - SAFE_FREE((void**)&packet.pData); - - return res != SOCKET_ERROR; -} - - - -int icq_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend) -{ - PBYTE sendBuf = buf; - int sendLen = len; - int sendResult = 0; - - while (sendLen > 0) - { // imitate polite behaviour of icq5.1 and split large packets - icq_packet packet; - WORD curLen; - int curResult; - - if (sendLen > 512) curLen = 512; else curLen = (WORD)sendLen; - // send wrapped data - packet.wLen = curLen; - write_httphdr(&packet, HTTP_PACKETTYPE_FLAP, GetGatewayIndex(hConn)); - packBuffer(&packet, sendBuf, (WORD)curLen); - - NETLIBBUFFER nlb={ (char*)packet.pData, packet.wLen, flags }; - curResult = pfnNetlibSend((WPARAM)hConn, (LPARAM)&nlb); - - SAFE_FREE((void**)&packet.pData); - - // sending failed, end loop - if (curResult <= 0) - return curResult; - // calculare real number of data bytes sent - if (curResult > 14) sendResult += curResult - 14; - // move on - sendLen -= curLen; - sendBuf += curLen; - } - - return sendResult; -} - - - -PBYTE icq_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST* nlhr, PBYTE buf, int len, int* outBufLen, void *(*NetlibRealloc)(void *, size_t)) -{ - WORD wLen, wType; - DWORD dwPackSeq; - PBYTE tbuf; - int i, copyBytes; - - - tbuf = buf; - for(i = 0;;) - { - if (tbuf - buf + 2 > len) - break; - unpackWord(&tbuf, &wLen); - if (wLen < 12) - break; - if (tbuf - buf + wLen > len) - break; - tbuf += 2; /* version */ - unpackWord(&tbuf, &wType); - tbuf += 4; /* flags */ - unpackDWord(&tbuf, &dwPackSeq); - if (wType == HTTP_PACKETTYPE_FLAP) - { // it is normal data packet - copyBytes = wLen - 12; - if (copyBytes > len - i) - { - /* invalid data - do our best to get something out of it */ - copyBytes = len - i; - } - memcpy(buf + i, tbuf, copyBytes); - i += copyBytes; - } - else if (wType == HTTP_PACKETTYPE_LOGINREPLY) - { // our "virtual connection" was established, good - BYTE bRes; - - unpackByte(&tbuf, &bRes); - wLen -= 1; - if (!bRes) - Netlib_Logf( NULL, "Gateway Connection #%d Established.", dwPackSeq); - else - Netlib_Logf( NULL, "Gateway Connection #%d Failed, error: %d", dwPackSeq, bRes); - } - else if (wType == HTTP_PACKETTYPE_CLOSEREPLY) - { // "virtual connection" closed - only received if any other "virual connection" still active - Netlib_Logf( NULL, "Gateway Connection #%d Closed.", dwPackSeq); - } - tbuf += wLen - 12; - } - *outBufLen = i; - - return buf; -} - - - -int icq_httpGatewayWalkTo(HANDLE hConn, NETLIBOPENCONNECTION* nloc) -{ // this is bad simplification - for avatars to work we need to handle - // two "virtual connections" at the same time - icq_packet packet; - DWORD dwGatewaySeq = GetGatewayIndex(hConn); - - packet.wLen = 0; - write_httphdr(&packet, HTTP_PACKETTYPE_CLOSE, dwGatewaySeq); - Netlib_Send(hConn, (char*)packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP); - // we closed virtual connection, open new one - dwGatewaySeq++; - SetGatewayIndex(hConn, dwGatewaySeq); - return icq_httpGatewayBegin(hConn, nloc); -} diff --git a/protocols/IcqOscarJ/icq_http.h b/protocols/IcqOscarJ/icq_http.h deleted file mode 100644 index 017a5ea5fc..0000000000 --- a/protocols/IcqOscarJ/icq_http.h +++ /dev/null @@ -1,48 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004,2005 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_HTTP_H -#define __ICQ_HTTP_H - -#define HTTP_PROXY_VERSION 0x0443 - -#define HTTP_PACKETTYPE_HELLOREPLY 2 -#define HTTP_PACKETTYPE_LOGIN 3 -#define HTTP_PACKETTYPE_LOGINREPLY 4 /* contains 1 byte: 0 */ -#define HTTP_PACKETTYPE_FLAP 5 -#define HTTP_PACKETTYPE_CLOSE 6 /* contains no data */ -#define HTTP_PACKETTYPE_CLOSEREPLY 7 /* contains 1 byte: 0 */ - -int icq_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr); -int icq_httpGatewayBegin(HANDLE hConn, NETLIBOPENCONNECTION *nloc); -int icq_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend); -PBYTE icq_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr, PBYTE buf, int bufLen, int *outBufLen, void *(*NetlibRealloc)(void *, size_t)); -int icq_httpGatewayWalkTo(HANDLE hConn, NETLIBOPENCONNECTION* nloc); - -#endif /* __ICQ_HTTP_H */ diff --git a/protocols/IcqOscarJ/icq_infoupdate.cpp b/protocols/IcqOscarJ/icq_infoupdate.cpp deleted file mode 100644 index 014df20e01..0000000000 --- a/protocols/IcqOscarJ/icq_infoupdate.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Background thread for automatic update of user details -// -// ----------------------------------------------------------------------------- - -#include "icqoscar.h" - -// Retrieve users' info -void CIcqProto::icq_InitInfoUpdate(void) -{ - // Create wait objects - hInfoQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (hInfoQueueEvent) { - // Init mutexes - infoUpdateMutex = new icq_critical_section(); - - // Init list - for (int i = 0; iEnter(); - - // Check if in list - for (i = 0; (iLeave(); - - return TRUE; - } - - return FALSE; -} - - -void CIcqProto::icq_DequeueUser(DWORD dwUin) -{ - if (nInfoUserCount > 0) - { - int nChecked = 0; - // Check if in list - infoUpdateMutex->Enter(); - for (int i = 0; (i < LISTSIZE && nChecked < nInfoUserCount); i++) - { - if (m_infoUpdateList[i].dwUin) - { - nChecked++; - // Remove from list - if (m_infoUpdateList[i].dwUin == dwUin) - { -#ifdef _DEBUG - NetLog_Server("Dequeued user %u", m_infoUpdateList[i].dwUin); -#endif - m_infoUpdateList[i].dwUin = 0; - m_infoUpdateList[i].hContact = NULL; - m_infoUpdateList[i].queued = 0; - nInfoUserCount--; - break; - } - } - } - infoUpdateMutex->Leave(); - } -} - - -void CIcqProto::icq_RescanInfoUpdate() -{ - bInfoPendingUsers = 0; - /* This is here, cause we do not want to emit large number of reuqest at once, - fill queue, and let thread deal with it */ - bInfoUpdateEnabled = 0; // freeze thread - - // Queue all outdated users - HANDLE hContact = FindFirstContact(); - while (hContact != NULL) - { - if (IsMetaInfoChanged(hContact)) - { // Queue user - if (!icq_QueueUser(hContact)) - { // The queue is full, pause queuing contacts - bInfoPendingUsers = 1; - break; - } - } - hContact = FindNextContact(hContact); - } - - bInfoUpdateEnabled = TRUE; -} - - -void CIcqProto::icq_EnableUserLookup(BOOL bEnable) -{ - bInfoUpdateEnabled = bEnable; - - // Notify worker thread - if (bInfoUpdateEnabled && hInfoQueueEvent) - SetEvent(hInfoQueueEvent); -} - - -void __cdecl CIcqProto::InfoUpdateThread( void* ) -{ - int i; - DWORD dwWait = WAIT_OBJECT_0; - - NetLog_Server("%s thread starting.", "Info-Update"); - - bInfoUpdateRunning = TRUE; - - while (bInfoUpdateRunning) - { - if (!nInfoUserCount && bInfoPendingUsers) // whole queue processed, check if more users needs updating - icq_RescanInfoUpdate(); - - if (!nInfoUserCount || !bInfoUpdateEnabled || !icqOnline()) - { - dwWait = WAIT_TIMEOUT; - while (bInfoUpdateRunning && dwWait == WAIT_TIMEOUT) - { // wait for new work or until we should end - dwWait = ICQWaitForSingleObject(hInfoQueueEvent, 10000); - } - } - if (!bInfoUpdateRunning) break; - - switch (dwWait) { - case WAIT_IO_COMPLETION: - // Possible shutdown in progress - break; - - case WAIT_OBJECT_0: - case WAIT_TIMEOUT: - // Time to check for new users - if (!bInfoUpdateEnabled) continue; // we can't send requests now - - if (nInfoUserCount && icqOnline()) - { - time_t now = time(NULL); - BOOL bNotReady = FALSE, bTimeOuted = FALSE; - - // Check the list, take only users that were there for at least 5sec - // wait if any user is there shorter than 5sec and not a single user is there longer than 20sec - infoUpdateMutex->Enter(); - for (i = 0; i= now) - bNotReady = TRUE; - } - } - infoUpdateMutex->Leave(); - - if (!bTimeOuted && bNotReady) - { - SleepEx(1000, TRUE); - if (!bInfoUpdateRunning) - { // need to end as fast as possible - NetLog_Server("%s thread ended.", "Info-Update"); - goto LBL_Exit; - } - continue; - } - - if (FindCookie(dwInfoActiveRequest, NULL, NULL)) - { // only send another request, when the previous is completed -#ifdef _DEBUG - NetLog_Server("Info-Update: Request 0x%x still in progress.", dwInfoActiveRequest); -#endif - SleepEx(1000, TRUE); - if (!bInfoUpdateRunning) - { // need to end as fast as possible - NetLog_Server("%s thread ended.", "Info-Update"); - goto LBL_Exit; - } - continue; - } - -#ifdef _DEBUG - NetLog_Server("Info-Update: Users %u in queue.", nInfoUserCount); -#endif - // Either some user is waiting long enough, or all users are ready (waited at least the minimum time) - m_ratesMutex->Enter(); - if (!m_rates) - { // we cannot send info request - icq is offline - m_ratesMutex->Leave(); - break; - } - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); - while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_IDLE_30)) - { // we are over rate, need to wait before sending - int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_50); - - m_ratesMutex->Leave(); -#ifdef _DEBUG - NetLog_Server("Rates: InfoUpdate delayed %dms", nDelay); -#endif - SleepEx(nDelay, TRUE); // do not keep things locked during sleep - if (!bInfoUpdateRunning) - { // need to end as fast as possible - NetLog_Server("%s thread ended.", "Info-Update"); - goto LBL_Exit; - } - m_ratesMutex->Enter(); - if (!m_rates) // we lost connection when we slept, go away - break; - } - if (!m_rates) - { // we cannot send info request - icq is offline - m_ratesMutex->Leave(); - break; - } - m_ratesMutex->Leave(); - - userinfo *hContactList[LISTSIZE]; - int nListIndex = 0; - BYTE *pRequestData = NULL; - int nRequestSize = 0; - - infoUpdateMutex->Enter(); - for (i = 0; iLeave(); - break; - } - if (!(dwInfoActiveRequest = sendUserInfoMultiRequest(pRequestData, nRequestSize, nListIndex))) - { // sending data packet failed - SAFE_FREE((void**)&pRequestData); - infoUpdateMutex->Leave(); - break; - } - SAFE_FREE((void**)&pRequestData); - - for (i = 0; idwUin = 0; - hContactList[i]->hContact = NULL; - hContactList[i]->queued = 0; - nInfoUserCount--; - } - infoUpdateMutex->Leave(); - } - break; - - default: - // Something strange happened. Exit - bInfoUpdateRunning = FALSE; - break; - } - } - - NetLog_Server("%s thread ended.", "Info-Update"); - -LBL_Exit: - SAFE_DELETE(&infoUpdateMutex); - CloseHandle(hInfoQueueEvent); -} - -// Clean up before exit -void CIcqProto::icq_InfoUpdateCleanup(void) -{ - NetLog_Server("%s must die.", "Info-Update"); - bInfoUpdateRunning = FALSE; - if (hInfoQueueEvent) - SetEvent(hInfoQueueEvent); // break queue loop -} diff --git a/protocols/IcqOscarJ/icq_menu.cpp b/protocols/IcqOscarJ/icq_menu.cpp deleted file mode 100644 index f3dd072cde..0000000000 --- a/protocols/IcqOscarJ/icq_menu.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -#include - -static HANDLE hPrebuildMenuHook; - -HANDLE g_hContactMenuItems[6]; -HANDLE g_hContactMenuSvc[6]; - -static int sttCompareProtocols(const CIcqProto *p1, const CIcqProto *p2) -{ - return strcmp(p1->m_szModuleName, p2->m_szModuleName); -} - -LIST g_Instances(1, sttCompareProtocols); - -static CIcqProto* IcqGetInstanceByHContact(HANDLE hContact) -{ - char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); - if (szProto == NULL) - return NULL; - - for (int i = 0; i < g_Instances.getCount(); i++) - if (!strcmp(szProto, g_Instances[i]->m_szModuleName)) - return g_Instances[i]; - - return NULL; -} - -static INT_PTR IcqMenuHandleRequestAuth(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->RequestAuthorization(wParam, lParam) : 0; -} - -static INT_PTR IcqMenuHandleGrantAuth(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->GrantAuthorization(wParam, lParam) : 0; -} - -static INT_PTR IcqMenuHandleRevokeAuth(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->RevokeAuthorization(wParam, lParam) : 0; -} - -static INT_PTR IcqMenuHandleAddServContact(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->AddServerContact(wParam, lParam) : 0; -} - -static INT_PTR IcqMenuHandleXStatusDetails(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->ShowXStatusDetails(wParam, lParam) : 0; -} - -static INT_PTR IcqMenuHandleOpenProfile(WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OpenWebProfile(wParam, lParam) : 0; -} - -static void sttEnableMenuItem( HANDLE hMenuItem, bool bEnable ) -{ - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_FLAGS; - if ( !bEnable ) - clmi.flags |= CMIF_HIDDEN; - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi ); -} - -static int IcqPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) -{ - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REQUEST], FALSE); - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_GRANT], FALSE); - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REVOKE], FALSE); - sttEnableMenuItem(g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], FALSE); - sttEnableMenuItem(g_hContactMenuItems[ICMI_XSTATUS_DETAILS], FALSE); - sttEnableMenuItem(g_hContactMenuItems[ICMI_OPEN_PROFILE], FALSE); - - CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); - return (ppro) ? ppro->OnPreBuildContactMenu(wParam, lParam) : 0; -} - -void g_MenuInit(void) -{ - /////////////// - // Contact menu - - hPrebuildMenuHook = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, IcqPrebuildContactMenu); - - // Contact menu initialization - - char str[MAXMODULELABELLENGTH], *pszDest = str + 3; - strcpy( str, "ICQ" ); - - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(CLISTMENUITEM); - mi.pszService = str; - mi.flags = CMIF_ICONFROMICOLIB; - - // "Request authorization" - mi.pszName = LPGEN("Request authorization"); - mi.position = 1000030000; - mi.icolibItem = hStaticIcons[ISI_AUTH_REQUEST]->Handle(); - strcpy(pszDest, MS_REQ_AUTH); - g_hContactMenuItems[ICMI_AUTH_REQUEST] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_AUTH_REQUEST] = CreateServiceFunction( str, IcqMenuHandleRequestAuth ); - - // "Grant authorization" - mi.pszName = LPGEN("Grant authorization"); - mi.position = 1000029999; - mi.icolibItem = hStaticIcons[ISI_AUTH_GRANT]->Handle(); - strcpy(pszDest, MS_GRANT_AUTH); - g_hContactMenuItems[ICMI_AUTH_GRANT] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_AUTH_GRANT] = CreateServiceFunction(mi.pszService, IcqMenuHandleGrantAuth); - - // "Revoke authorization" - mi.pszName = LPGEN("Revoke authorization"); - mi.position = 1000029998; - mi.icolibItem = hStaticIcons[ISI_AUTH_REVOKE]->Handle(); - strcpy(pszDest, MS_REVOKE_AUTH); - g_hContactMenuItems[ICMI_AUTH_REVOKE] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_AUTH_REVOKE] = CreateServiceFunction(mi.pszService, IcqMenuHandleRevokeAuth); - - // "Add to server list" - mi.pszName = LPGEN("Add to server list"); - mi.position = -2049999999; - mi.icolibItem = hStaticIcons[ISI_ADD_TO_SERVLIST]->Handle(); - strcpy(pszDest, MS_ICQ_ADDSERVCONTACT); - g_hContactMenuItems[ICMI_ADD_TO_SERVLIST] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_ADD_TO_SERVLIST] = CreateServiceFunction(mi.pszService, IcqMenuHandleAddServContact); - - // "Show custom status details" - mi.pszName = LPGEN("Show custom status details"); - mi.position = -2000004999; - mi.flags = 0; - strcpy(pszDest, MS_XSTATUS_SHOWDETAILS); - g_hContactMenuItems[ICMI_XSTATUS_DETAILS] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_XSTATUS_DETAILS] = CreateServiceFunction(mi.pszService, IcqMenuHandleXStatusDetails); - - // "Open ICQ profile" - mi.pszName = LPGEN("Open ICQ profile"); - mi.position = 1000029997; - strcpy(pszDest, MS_OPEN_PROFILE); - g_hContactMenuItems[ICMI_OPEN_PROFILE] = Menu_AddContactMenuItem(&mi); - g_hContactMenuSvc[ICMI_OPEN_PROFILE] = CreateServiceFunction(mi.pszService, IcqMenuHandleOpenProfile); -} - -void g_MenuUninit(void) -{ - UnhookEvent(hPrebuildMenuHook); - - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_REQUEST], 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_GRANT], 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_REVOKE], 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_XSTATUS_DETAILS], 0); - CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_OPEN_PROFILE], 0); - - DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_REQUEST]); - DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_GRANT]); - DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_REVOKE]); - DestroyServiceFunction(g_hContactMenuSvc[ICMI_ADD_TO_SERVLIST]); - DestroyServiceFunction(g_hContactMenuSvc[ICMI_XSTATUS_DETAILS]); - DestroyServiceFunction(g_hContactMenuSvc[ICMI_OPEN_PROFILE]); -} - - -INT_PTR CIcqProto::OpenWebProfile(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - DWORD dwUin = getContactUin(hContact); - char url[256]; - mir_snprintf(url, sizeof(url), "http://www.icq.com/people/%d",dwUin); - return CallService(MS_UTILS_OPENURL, 1, (LPARAM)url); -} - - -int CIcqProto::OnPreBuildContactMenu(WPARAM wParam, LPARAM) -{ - HANDLE hContact = (HANDLE)wParam; - if (hContact == NULL) - return 0; - - if (icqOnline()) - { - BOOL bCtrlPressed = (GetKeyState(VK_CONTROL)&0x8000 ) != 0; - - DWORD dwUin = getContactUin(hContact); - - - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REQUEST], - dwUin && (bCtrlPressed || (getSettingByte((HANDLE)wParam, "Auth", 0) && getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0)))); - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_GRANT], dwUin && (bCtrlPressed || getSettingByte((HANDLE)wParam, "Grant", 0))); - sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REVOKE], - dwUin && (bCtrlPressed || (getSettingByte(NULL, "PrivacyItems", 0) && !getSettingByte((HANDLE)wParam, "Grant", 0)))); - sttEnableMenuItem(g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], - m_bSsiEnabled && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0) && - !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0) && - !DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)); - } - - sttEnableMenuItem(g_hContactMenuItems[ICMI_OPEN_PROFILE],getContactUin(hContact) != 0); - BYTE bXStatus = getContactXStatus((HANDLE)wParam); - - sttEnableMenuItem(g_hContactMenuItems[ICMI_XSTATUS_DETAILS], m_bHideXStatusUI ? 0 : bXStatus != 0); - if (bXStatus && !m_bHideXStatusUI) { - CLISTMENUITEM clmi = {0}; - - clmi.cbSize = sizeof(clmi); - clmi.flags = CMIM_ICON; - - if (bXStatus > 0 && bXStatus <= XSTATUS_COUNT) - clmi.hIcon = getXStatusIcon(bXStatus, LR_SHARED); - else - clmi.hIcon = LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_XSTATUS_DETAILS], (LPARAM)&clmi); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnPreBuildStatusMenu event - -int CIcqProto::OnPreBuildStatusMenu(WPARAM wParam, LPARAM lParam) -{ - InitXStatusItems(TRUE); - return 0; -} diff --git a/protocols/IcqOscarJ/icq_opts.cpp b/protocols/IcqOscarJ/icq_opts.cpp deleted file mode 100644 index 44c1881d14..0000000000 --- a/protocols/IcqOscarJ/icq_opts.cpp +++ /dev/null @@ -1,617 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -#include - -extern BOOL bPopUpService; - -static const char* szLogLevelDescr[] = { - LPGEN("Display all problems"), - LPGEN("Display problems causing possible loss of data"), - LPGEN("Display explanations for disconnection"), - LPGEN("Display problems requiring user intervention"), - LPGEN("Do not display any problems (not recommended)") -}; - -static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0; - -static void LoadDBCheckState(CIcqProto* ppro, HWND hwndDlg, int idCtrl, const char* szSetting, BYTE bDef) -{ - CheckDlgButton(hwndDlg, idCtrl, ppro->getSettingByte(NULL, szSetting, bDef)); -} - -static void StoreDBCheckState(CIcqProto* ppro, HWND hwndDlg, int idCtrl, const char* szSetting) -{ - ppro->setSettingByte(NULL, szSetting, (BYTE)IsDlgButtonChecked(hwndDlg, idCtrl)); -} - -static void OptDlgChanged(HWND hwndDlg) -{ - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// standalone option pages - -static INT_PTR CALLBACK DlgProcIcqOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - { - DWORD dwUin = ppro->getContactUin(NULL); - if (dwUin) - SetDlgItemInt(hwndDlg, IDC_ICQNUM, dwUin, FALSE); - else // keep it empty when no UIN entered - SetDlgItemTextA(hwndDlg, IDC_ICQNUM, ""); - - SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); - - char pszPwd[PASSWORDMAXLEN]; - if (ppro->GetUserStoredPassword(pszPwd, sizeof(pszPwd))) - { - //bit of a security hole here, since it's easy to extract a password from an edit box - SetDlgItemTextA(hwndDlg, IDC_PASSWORD, pszPwd); - } - - LoadDBCheckState(ppro, hwndDlg, IDC_SSL, "SecureConnection", DEFAULT_SECURE_CONNECTION); - LoadDBCheckState(ppro, hwndDlg, IDC_MD5LOGIN, "SecureLogin", DEFAULT_SECURE_LOGIN); - - char szServer[MAX_PATH]; - if (!ppro->getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH)) - SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, szServer); - else - SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); - - SetDlgItemInt(hwndDlg, IDC_ICQPORT, ppro->getSettingWord(NULL, "OscarPort", IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT), FALSE); - LoadDBCheckState(ppro, hwndDlg, IDC_KEEPALIVE, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED); - SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETRANGE, FALSE, MAKELONG(0, 4)); - SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETPOS, TRUE, 4-ppro->getSettingByte(NULL, "ShowLogLevel", LOG_WARNING)); - { - char buf[MAX_PATH]; - SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_GETPOS, 0, 0)], buf, MAX_PATH)); - } - ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_HIDE); - LoadDBCheckState(ppro, hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox", 0); - } - return TRUE; - - case WM_HSCROLL: - { - char str[MAX_PATH]; - - SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL,TBM_GETPOS, 0, 0)], str, MAX_PATH)); - OptDlgChanged(hwndDlg); - } - break; - - case WM_COMMAND: - { - switch (LOWORD(wParam)) { - case IDC_LOOKUPLINK: - CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_FORGOT_PASSWORD); - return TRUE; - - case IDC_NEWUINLINK: - CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_REGISTER); - return TRUE; - - case IDC_RESETSERVER: - SetDlgItemInt(hwndDlg, IDC_ICQPORT, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT, FALSE); - - case IDC_SSL: - SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); - SetDlgItemInt(hwndDlg, IDC_ICQPORT, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT, FALSE); - OptDlgChanged(hwndDlg); - return TRUE; - } - - if (ppro->icqOnline() && LOWORD(wParam) != IDC_NOERRMULTI) - { - char szClass[80]; - GetClassNameA((HWND)lParam, szClass, sizeof(szClass)); - - if (stricmpnull(szClass, "EDIT") || HIWORD(wParam) == EN_CHANGE) - ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_SHOW); - } - - if ((LOWORD(wParam)==IDC_ICQNUM || LOWORD(wParam)==IDC_PASSWORD || LOWORD(wParam)==IDC_ICQSERVER || LOWORD(wParam)==IDC_ICQPORT) && - (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) - { - return 0; - } - - OptDlgChanged(hwndDlg); - break; - } - - case WM_NOTIFY: - { - switch (((LPNMHDR)lParam)->code) - { - - case PSN_APPLY: - { - char str[128]; - - ppro->setSettingDword(NULL, UNIQUEIDSETTING, GetDlgItemInt(hwndDlg, IDC_ICQNUM, NULL, FALSE)); - GetDlgItemTextA(hwndDlg, IDC_PASSWORD, str, sizeof(ppro->m_szPassword)); - if (strlennull(str)) - { - strcpy(ppro->m_szPassword, str); - ppro->m_bRememberPwd = TRUE; - } - else - ppro->m_bRememberPwd = ppro->getSettingByte(NULL, "RememberPass", 0); - - CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ppro->m_szPassword), (LPARAM)str); - ppro->setSettingString(NULL, "Password", str); - GetDlgItemTextA(hwndDlg,IDC_ICQSERVER, str, sizeof(str)); - ppro->setSettingString(NULL, "OscarServer", str); - ppro->setSettingWord(NULL, "OscarPort", (WORD)GetDlgItemInt(hwndDlg, IDC_ICQPORT, NULL, FALSE)); - StoreDBCheckState(ppro, hwndDlg, IDC_KEEPALIVE, "KeepAlive"); - StoreDBCheckState(ppro, hwndDlg, IDC_SSL, "SecureConnection"); - StoreDBCheckState(ppro, hwndDlg, IDC_MD5LOGIN, "SecureLogin"); - StoreDBCheckState(ppro, hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox"); - ppro->setSettingByte(NULL, "ShowLogLevel", (BYTE)(4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_GETPOS, 0, 0))); - - return TRUE; - } - } - } - break; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static const UINT icqPrivacyControls[] = { - IDC_DCALLOW_ANY, IDC_DCALLOW_CLIST, IDC_DCALLOW_AUTH, IDC_ADD_ANY, IDC_ADD_AUTH, - IDC_WEBAWARE, IDC_PUBLISHPRIMARY, IDC_STATIC_DC1, IDC_STATIC_DC2, IDC_STATIC_CLIST -}; - -static INT_PTR CALLBACK DlgProcIcqPrivacyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - { - int nDcType = ppro->getSettingByte(NULL, "DCType", 0); - int nAddAuth = ppro->getSettingByte(NULL, "Auth", 1); - - if (!ppro->icqOnline()) - { - icq_EnableMultipleControls(hwndDlg, icqPrivacyControls, SIZEOF(icqPrivacyControls), FALSE); - ShowDlgItem(hwndDlg, IDC_STATIC_NOTONLINE, SW_SHOW); - } - else - ShowDlgItem(hwndDlg, IDC_STATIC_NOTONLINE, SW_HIDE); - - CheckDlgButton(hwndDlg, IDC_DCALLOW_ANY, (nDcType == 0)); - CheckDlgButton(hwndDlg, IDC_DCALLOW_CLIST, (nDcType == 1)); - CheckDlgButton(hwndDlg, IDC_DCALLOW_AUTH, (nDcType == 2)); - CheckDlgButton(hwndDlg, IDC_ADD_ANY, (nAddAuth == 0)); - CheckDlgButton(hwndDlg, IDC_ADD_AUTH, (nAddAuth == 1)); - LoadDBCheckState(ppro, hwndDlg, IDC_WEBAWARE, "WebAware", 0); - LoadDBCheckState(ppro, hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail", 0); - LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList", 0); - LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible", 0); - if (!ppro->getSettingByte(NULL, "StatusMsgReplyCList", 0)) - EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_DCALLOW_ANY: - case IDC_DCALLOW_CLIST: - case IDC_DCALLOW_AUTH: - case IDC_ADD_ANY: - case IDC_ADD_AUTH: - case IDC_WEBAWARE: - case IDC_PUBLISHPRIMARY: - case IDC_STATUSMSG_VISIBLE: - if ((HWND)lParam != GetFocus()) return 0; - break; - case IDC_STATUSMSG_CLIST: - if (IsDlgButtonChecked(hwndDlg, IDC_STATUSMSG_CLIST)) - { - EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, TRUE); - LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible", 0); - } - else - { - EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); - CheckDlgButton(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); - } - break; - default: - return 0; - } - OptDlgChanged(hwndDlg); - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case PSN_APPLY: - StoreDBCheckState(ppro, hwndDlg, IDC_WEBAWARE, "WebAware"); - StoreDBCheckState(ppro, hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail"); - StoreDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList"); - StoreDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible"); - if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_AUTH)) - ppro->setSettingByte(NULL, "DCType", 2); - else if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_CLIST)) - ppro->setSettingByte(NULL, "DCType", 1); - else - ppro->setSettingByte(NULL, "DCType", 0); - StoreDBCheckState(ppro, hwndDlg, IDC_ADD_AUTH, "Auth"); - - if (ppro->icqOnline()) - { - PBYTE buf=NULL; - int buflen=0; - - ppackTLVWord(&buf, &buflen, 0x19A, !ppro->getSettingByte(NULL, "Auth", 1)); - ppackTLVByte(&buf, &buflen, 0x212, ppro->getSettingByte(NULL, "WebAware", 0)); - ppackTLVWord(&buf, &buflen, 0x1F9, ppro->getSettingByte(NULL, "PrivacyLevel", 1)); - - ppro->icq_changeUserDirectoryInfoServ(buf, (WORD)buflen, DIRECTORYREQUEST_UPDATEPRIVACY); - - SAFE_FREE((void**)&buf); - - // Send a status packet to notify the server about the webaware setting - { - WORD wStatus = MirandaStatusToIcq(ppro->m_iStatus); - - if (ppro->m_iStatus == ID_STATUS_INVISIBLE) - { - if (ppro->m_bSsiEnabled) - ppro->updateServVisibilityCode(3); - ppro->icq_setstatus(wStatus, NULL); - } - else - { - ppro->icq_setstatus(wStatus, NULL); - if (ppro->m_bSsiEnabled) - ppro->updateServVisibilityCode(4); - } - } - } - return TRUE; - } - break; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static HWND hCpCombo; - -struct CPTABLE { - WORD cpId; - char *cpName; -}; - -struct CPTABLE cpTable[] = { - { 874, LPGEN("Thai") }, - { 932, LPGEN("Japanese") }, - { 936, LPGEN("Simplified Chinese") }, - { 949, LPGEN("Korean") }, - { 950, LPGEN("Traditional Chinese") }, - { 1250, LPGEN("Central European") }, - { 1251, LPGEN("Cyrillic") }, - { 1252, LPGEN("Latin I") }, - { 1253, LPGEN("Greek") }, - { 1254, LPGEN("Turkish") }, - { 1255, LPGEN("Hebrew") }, - { 1256, LPGEN("Arabic") }, - { 1257, LPGEN("Baltic") }, - { 1258, LPGEN("Vietnamese") }, - { 1361, LPGEN("Korean (Johab)") }, - { -1, NULL} -}; - -static BOOL CALLBACK FillCpCombo(LPSTR str) -{ - int i; - UINT cp; - - cp = atoi(str); - for (i=0; cpTable[i].cpName != NULL && cpTable[i].cpId!=cp; i++); - if (cpTable[i].cpName) - ComboBoxAddStringUtf(hCpCombo, cpTable[i].cpName, cpTable[i].cpId); - - return TRUE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static const UINT icqUnicodeControls[] = {IDC_UTFALL,IDC_UTFSTATIC,IDC_UTFCODEPAGE}; -static const UINT icqDCMsgControls[] = {IDC_DCPASSIVE}; -static const UINT icqXStatusControls[] = {IDC_XSTATUSAUTO}; -static const UINT icqCustomStatusControls[] = {IDC_XSTATUSRESET}; -static const UINT icqAimControls[] = {IDC_AIMENABLE}; - -static INT_PTR CALLBACK DlgProcIcqFeaturesOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - { - BYTE byData = ppro->getSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED); - CheckDlgButton(hwndDlg, IDC_UTFENABLE, byData?TRUE:FALSE); - CheckDlgButton(hwndDlg, IDC_UTFALL, byData==2?TRUE:FALSE); - icq_EnableMultipleControls(hwndDlg, icqUnicodeControls, SIZEOF(icqUnicodeControls), byData?TRUE:FALSE); - LoadDBCheckState(ppro, hwndDlg, IDC_TEMPVISIBLE, "TempVisListEnabled",DEFAULT_TEMPVIS_ENABLED); - LoadDBCheckState(ppro, hwndDlg, IDC_SLOWSEND, "SlowSend", DEFAULT_SLOWSEND); - LoadDBCheckState(ppro, hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS); - byData = ppro->getSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED); - CheckDlgButton(hwndDlg, IDC_DCENABLE, byData?TRUE:FALSE); - CheckDlgButton(hwndDlg, IDC_DCPASSIVE, byData==1?TRUE:FALSE); - icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, SIZEOF(icqDCMsgControls), byData?TRUE:FALSE); - BYTE byXStatusEnabled = ppro->getSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED); - CheckDlgButton(hwndDlg, IDC_XSTATUSENABLE, byXStatusEnabled); - BYTE byMoodsEnabled = ppro->getSettingByte(NULL, "MoodsEnabled", DEFAULT_MOODS_ENABLED); - CheckDlgButton(hwndDlg, IDC_MOODSENABLE, byMoodsEnabled); - icq_EnableMultipleControls(hwndDlg, icqXStatusControls, SIZEOF(icqXStatusControls), byXStatusEnabled); - icq_EnableMultipleControls(hwndDlg, icqCustomStatusControls, SIZEOF(icqCustomStatusControls), byXStatusEnabled || byMoodsEnabled); - LoadDBCheckState(ppro, hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto", DEFAULT_XSTATUS_AUTO); - LoadDBCheckState(ppro, hwndDlg, IDC_XSTATUSRESET, "XStatusReset", DEFAULT_XSTATUS_RESET); - LoadDBCheckState(ppro, hwndDlg, IDC_KILLSPAMBOTS, "KillSpambots", DEFAULT_KILLSPAM_ENABLED); - LoadDBCheckState(ppro, hwndDlg, IDC_AIMENABLE, "AimEnabled", DEFAULT_AIM_ENABLED); - icq_EnableMultipleControls(hwndDlg, icqAimControls, SIZEOF(icqAimControls), ppro->icqOnline()?FALSE:TRUE); - - hCpCombo = GetDlgItem(hwndDlg, IDC_UTFCODEPAGE); - int sCodePage = ppro->getSettingWord(NULL, "AnsiCodePage", CP_ACP); - ComboBoxAddStringUtf(GetDlgItem(hwndDlg, IDC_UTFCODEPAGE), LPGEN("System default codepage"), 0); - EnumSystemCodePagesA(FillCpCombo, CP_INSTALLED); - if(sCodePage == 0) - SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_SETCURSEL, (WPARAM)0, 0); - else - { - for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETCOUNT, 0, 0); i++) - { - if (SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETITEMDATA, (WPARAM)i, 0) == sCodePage) - { - SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_SETCURSEL, (WPARAM)i, 0); - break; - } - } - } - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_UTFENABLE: - icq_EnableMultipleControls(hwndDlg, icqUnicodeControls, SIZEOF(icqUnicodeControls), IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE)); - OptDlgChanged(hwndDlg); - break; - case IDC_UTFCODEPAGE: - if(HIWORD(wParam)==CBN_SELCHANGE) - OptDlgChanged(hwndDlg); - break; - case IDC_DCENABLE: - icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, SIZEOF(icqDCMsgControls), IsDlgButtonChecked(hwndDlg, IDC_DCENABLE)); - OptDlgChanged(hwndDlg); - break; - case IDC_XSTATUSENABLE: - icq_EnableMultipleControls(hwndDlg, icqXStatusControls, SIZEOF(icqXStatusControls), IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE)); - case IDC_MOODSENABLE: - icq_EnableMultipleControls(hwndDlg, icqCustomStatusControls, SIZEOF(icqCustomStatusControls), IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE) || IsDlgButtonChecked(hwndDlg, IDC_MOODSENABLE)); - default: - OptDlgChanged(hwndDlg); - break; - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case PSN_APPLY: - if (IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE)) - ppro->m_bUtfEnabled = IsDlgButtonChecked(hwndDlg, IDC_UTFALL)?2:1; - else - ppro->m_bUtfEnabled = 0; - { - int i = SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETCURSEL, 0, 0); - ppro->m_wAnsiCodepage = (WORD)SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETITEMDATA, (WPARAM)i, 0); - ppro->setSettingWord(NULL, "AnsiCodePage", ppro->m_wAnsiCodepage); - } - ppro->setSettingByte(NULL, "UtfEnabled", ppro->m_bUtfEnabled); - ppro->m_bTempVisListEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_TEMPVISIBLE); - ppro->setSettingByte(NULL, "TempVisListEnabled", ppro->m_bTempVisListEnabled); - StoreDBCheckState(ppro, hwndDlg, IDC_SLOWSEND, "SlowSend"); - StoreDBCheckState(ppro, hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks"); - if (IsDlgButtonChecked(hwndDlg, IDC_DCENABLE)) - ppro->m_bDCMsgEnabled = IsDlgButtonChecked(hwndDlg, IDC_DCPASSIVE)?1:2; - else - ppro->m_bDCMsgEnabled = 0; - ppro->setSettingByte(NULL, "DirectMessaging", ppro->m_bDCMsgEnabled); - ppro->m_bXStatusEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE); - ppro->setSettingByte(NULL, "XStatusEnabled", ppro->m_bXStatusEnabled); - ppro->m_bMoodsEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_MOODSENABLE); - ppro->setSettingByte(NULL, "MoodsEnabled", ppro->m_bMoodsEnabled); - StoreDBCheckState(ppro, hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto"); - StoreDBCheckState(ppro, hwndDlg, IDC_XSTATUSRESET, "XStatusReset"); - StoreDBCheckState(ppro, hwndDlg, IDC_KILLSPAMBOTS , "KillSpambots"); - StoreDBCheckState(ppro, hwndDlg, IDC_AIMENABLE, "AimEnabled"); - return TRUE; - } - break; - } - return FALSE; -} - -static const UINT icqContactsControls[] = {IDC_ADDSERVER,IDC_LOADFROMSERVER,IDC_SAVETOSERVER,IDC_UPLOADNOW}; -static const UINT icqAvatarControls[] = {IDC_AUTOLOADAVATARS,IDC_STRICTAVATARCHECK}; - -static INT_PTR CALLBACK DlgProcIcqContactsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - LoadDBCheckState(ppro, hwndDlg, IDC_ENABLE, "UseServerCList", DEFAULT_SS_ENABLED); - LoadDBCheckState(ppro, hwndDlg, IDC_ADDSERVER, "ServerAddRemove", DEFAULT_SS_ADDSERVER); - LoadDBCheckState(ppro, hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails", DEFAULT_SS_LOAD); - LoadDBCheckState(ppro, hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails", DEFAULT_SS_STORE); - LoadDBCheckState(ppro, hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED); - LoadDBCheckState(ppro, hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS); - LoadDBCheckState(ppro, hwndDlg, IDC_STRICTAVATARCHECK, "StrictAvatarCheck", DEFAULT_AVATARS_CHECK); - - icq_EnableMultipleControls(hwndDlg, icqContactsControls, SIZEOF(icqContactsControls), - ppro->getSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED)?TRUE:FALSE); - icq_EnableMultipleControls(hwndDlg, icqAvatarControls, SIZEOF(icqAvatarControls), - ppro->getSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED)?TRUE:FALSE); - - if (ppro->icqOnline()) - { - ShowDlgItem(hwndDlg, IDC_OFFLINETOENABLE, SW_SHOW); - EnableDlgItem(hwndDlg, IDC_ENABLE, FALSE); - EnableDlgItem(hwndDlg, IDC_ENABLEAVATARS, FALSE); - } - else - EnableDlgItem(hwndDlg, IDC_UPLOADNOW, FALSE); - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_UPLOADNOW: - ppro->ShowUploadContactsDialog(); - return TRUE; - case IDC_ENABLE: - icq_EnableMultipleControls(hwndDlg, icqContactsControls, SIZEOF(icqContactsControls), IsDlgButtonChecked(hwndDlg, IDC_ENABLE)); - if (ppro->icqOnline()) - ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_SHOW); - else - EnableDlgItem(hwndDlg, IDC_UPLOADNOW, FALSE); - break; - case IDC_ENABLEAVATARS: - icq_EnableMultipleControls(hwndDlg, icqAvatarControls, SIZEOF(icqAvatarControls), IsDlgButtonChecked(hwndDlg, IDC_ENABLEAVATARS)); - break; - } - OptDlgChanged(hwndDlg); - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->code == PSN_APPLY ) - { - StoreDBCheckState(ppro, hwndDlg, IDC_ENABLE, "UseServerCList"); - StoreDBCheckState(ppro, hwndDlg, IDC_ADDSERVER, "ServerAddRemove"); - StoreDBCheckState(ppro, hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails"); - StoreDBCheckState(ppro, hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails"); - StoreDBCheckState(ppro, hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled"); - StoreDBCheckState(ppro, hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad"); - StoreDBCheckState(ppro, hwndDlg, IDC_STRICTAVATARCHECK, "StrictAvatarCheck"); - return TRUE; - } - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -int CIcqProto::OnOptionsInit(WPARAM wParam, LPARAM lParam) -{ - if (IsWinVerXPPlus()) { - HMODULE hUxTheme = GetModuleHandleA("uxtheme.dll"); - if (hUxTheme) - pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); - } - - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.position = -800000000; - odp.hInstance = hInst; - odp.ptszGroup = LPGENT("Network"); - odp.dwInitParam = LPARAM(this); - odp.ptszTitle = m_tszUserName; - odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; - - odp.ptszTab = LPGENT("Account"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQ); - odp.pfnDlgProc = DlgProcIcqOpts; - Options_AddPage(wParam, &odp); - - odp.ptszTab = LPGENT("Contacts"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQCONTACTS); - odp.pfnDlgProc = DlgProcIcqContactsOpts; - Options_AddPage(wParam, &odp); - - odp.ptszTab = LPGENT("Features"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQFEATURES); - odp.pfnDlgProc = DlgProcIcqFeaturesOpts; - Options_AddPage(wParam, &odp); - - odp.ptszTab = LPGENT("Privacy"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQPRIVACY); - odp.pfnDlgProc = DlgProcIcqPrivacyOpts; - Options_AddPage(wParam, &odp); - - if (bPopUpService) { - odp.position = 100000000; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUPS); - odp.groupPosition = 900000000; - odp.pfnDlgProc = DlgProcIcqPopupOpts; - odp.ptszGroup = LPGENT("Popups"); - odp.ptszTab = NULL; - Options_AddPage(wParam, &odp); - } - return 0; -} diff --git a/protocols/IcqOscarJ/icq_packet.cpp b/protocols/IcqOscarJ/icq_packet.cpp deleted file mode 100644 index 79241cf297..0000000000 --- a/protocols/IcqOscarJ/icq_packet.cpp +++ /dev/null @@ -1,898 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -WORD generate_flap_sequence() -{ - DWORD n = rand(), s = 0; - - for (DWORD i = n; i >>= 3; s += i); - - return (((0 - s) ^ (BYTE)n) & 7 ^ n) + 2; -} - -void __fastcall init_generic_packet(icq_packet *pPacket, WORD wHeaderLen) -{ - pPacket->wPlace = 0; - pPacket->wLen += wHeaderLen; - pPacket->pData = (BYTE*)SAFE_MALLOC(pPacket->wLen); -} - -void write_httphdr(icq_packet *pPacket, WORD wType, DWORD dwSeq) -{ - init_generic_packet(pPacket, 14); - - packWord(pPacket, (WORD)(pPacket->wLen - 2)); - packWord(pPacket, HTTP_PROXY_VERSION); - packWord(pPacket, wType); - packDWord(pPacket, 0); // Flags? - packDWord(pPacket, dwSeq); // Connection sequence ? -} - -void __fastcall write_flap(icq_packet *pPacket, BYTE byFlapChannel) -{ - init_generic_packet(pPacket, 6); - - pPacket->nChannel = byFlapChannel; - - packByte(pPacket, FLAP_MARKER); - packByte(pPacket, byFlapChannel); - packWord(pPacket, 0); // This is the sequence ID, it is filled in during the actual sending - packWord(pPacket, (WORD)(pPacket->wLen - 6)); // This counter should not include the flap header (thus the -6) -} - -void __fastcall serverPacketInit(icq_packet *pPacket, WORD wSize) -{ - pPacket->wLen = wSize; - write_flap(pPacket, ICQ_DATA_CHAN); -} - -void __fastcall directPacketInit(icq_packet *pPacket, DWORD dwSize) -{ - pPacket->wPlace = 0; - pPacket->wLen = (WORD)dwSize; - pPacket->pData = (BYTE *)SAFE_MALLOC(dwSize + 2); - - packLEWord(pPacket, pPacket->wLen); -} - -void __fastcall serverCookieInit(icq_packet *pPacket, BYTE *pCookie, WORD wCookieSize) -{ - pPacket->wLen = (WORD)(wCookieSize + 8 + sizeof(CLIENT_ID_STRING) + 66); - - write_flap(pPacket, ICQ_LOGIN_CHAN); - packDWord(pPacket, 0x00000001); - packTLV(pPacket, 0x06, wCookieSize, pCookie); - - // Pack client identification details. - packTLV(pPacket, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, (LPBYTE)CLIENT_ID_STRING); - packTLVWord(pPacket, 0x0017, CLIENT_VERSION_MAJOR); - packTLVWord(pPacket, 0x0018, CLIENT_VERSION_MINOR); - packTLVWord(pPacket, 0x0019, CLIENT_VERSION_LESSER); - packTLVWord(pPacket, 0x001a, CLIENT_VERSION_BUILD); - packTLVWord(pPacket, 0x0016, CLIENT_ID_CODE); - packTLVDWord(pPacket, 0x0014, CLIENT_DISTRIBUTION); - packTLV(pPacket, 0x000f, 0x0002, (LPBYTE)CLIENT_LANGUAGE); - packTLV(pPacket, 0x000e, 0x0002, (LPBYTE)CLIENT_COUNTRY); - packDWord(pPacket, 0x00940001); // reconnect flag - packByte(pPacket, 0); - packTLVDWord(pPacket, 0x8003, 0x00100000); // Unknown -} - -void __fastcall packByte(icq_packet *pPacket, BYTE byValue) -{ - pPacket->pData[pPacket->wPlace++] = byValue; -} - -void __fastcall packWord(icq_packet *pPacket, WORD wValue) -{ - pPacket->pData[pPacket->wPlace++] = ((wValue & 0xff00) >> 8); - pPacket->pData[pPacket->wPlace++] = (wValue & 0x00ff); -} - -void __fastcall packDWord(icq_packet *pPacket, DWORD dwValue) -{ - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0xff000000) >> 24); - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x00ff0000) >> 16); - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x0000ff00) >> 8); - pPacket->pData[pPacket->wPlace++] = (BYTE) (dwValue & 0x000000ff); -} - -void __fastcall packQWord(icq_packet *pPacket, DWORD64 qwValue) -{ - packDWord(pPacket, (DWORD)(qwValue >> 32)); - packDWord(pPacket, (DWORD)(qwValue & 0xffffffff)); -} - -void packTLV(icq_packet *pPacket, WORD wType, WORD wLength, const BYTE *pbyValue) -{ - packWord(pPacket, wType); - packWord(pPacket, wLength); - packBuffer(pPacket, pbyValue, wLength); -} - -void packTLVWord(icq_packet *pPacket, WORD wType, WORD wValue) -{ - packWord(pPacket, wType); - packWord(pPacket, 0x02); - packWord(pPacket, wValue); -} - -void packTLVDWord(icq_packet *pPacket, WORD wType, DWORD dwValue) -{ - packWord(pPacket, wType); - packWord(pPacket, 0x04); - packDWord(pPacket, dwValue); -} - - -void packTLVUID(icq_packet *pPacket, WORD wType, DWORD dwUin, const char *szUid) -{ - if (dwUin) - { - char szUin[UINMAXLEN]; - - _ltoa(dwUin, szUin, 10); - - packTLV(pPacket, wType, getUINLen(dwUin), (BYTE*)szUin); - } - else if (szUid) - packTLV(pPacket, wType, strlennull(szUid), (BYTE*)szUid); -} - - -// Pack a preformatted buffer. -// This can be used to pack strings or any type of raw data. -void packBuffer(icq_packet *pPacket, const BYTE* pbyBuffer, WORD wLength) -{ - while (wLength) - { - pPacket->pData[pPacket->wPlace++] = *pbyBuffer++; - wLength--; - } -} - -// Pack a buffer and prepend it with the size as a LE WORD. -// Commented out since its not actually used anywhere right now. -//void packLEWordSizedBuffer(icq_packet* pPacket, const BYTE* pbyBuffer, WORD wLength) -//{ -// -// packLEWord(pPacket, wLength); -// packBuffer(pPacket, pbyBuffer, wLength); -// -//} - -int __fastcall getUINLen(DWORD dwUin) -{ - BYTE dwUinLen = 0; - - while(dwUin) { - dwUin /= 10; - dwUinLen += 1; - } - return dwUinLen; -} - -int __fastcall getUIDLen(DWORD dwUin, const char *szUid) -{ - if (dwUin) - return getUINLen(dwUin); - else - return strlennull(szUid); -} - -void __fastcall packUIN(icq_packet *pPacket, DWORD dwUin) -{ - char pszUin[UINMAXLEN]; - BYTE nUinLen = getUINLen(dwUin); - - _ltoa(dwUin, pszUin, 10); - - packByte(pPacket, nUinLen); // Length of user id - packBuffer(pPacket, (LPBYTE)pszUin, nUinLen); // Receiving user's id -} - -void __fastcall packUID(icq_packet *pPacket, DWORD dwUin, const char *szUid) -{ - if (dwUin) - packUIN(pPacket, dwUin); - else - { - BYTE nLen = strlennull(szUid); - packByte(pPacket, nLen); - packBuffer(pPacket, (LPBYTE)szUid, nLen); - } -} - - -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype) -{ - packFNACHeader(pPacket, wFamily, wSubtype, 0, wSubtype << 0x10); -} - - -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence) -{ - WORD wSequence = (WORD)dwSequence & 0x7FFF; // this is necessary, if that bit is there we get disconnected - - packWord(pPacket, wFamily); // Family type - packWord(pPacket, wSubtype); // Family subtype - packWord(pPacket, wFlags); // SNAC flags - packWord(pPacket, wSequence); // SNAC request id (sequence) - packWord(pPacket, (WORD)(dwSequence >> 0x10)); // SNAC request id (command) -} - - -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence, WORD wVersion) -{ - packFNACHeader(pPacket, wFamily, wSubtype, wFlags | 0x8000, dwSequence); - packWord(pPacket, 0x06); - packTLVWord(pPacket, 0x01, wVersion); -} - - -void __fastcall packLEWord(icq_packet *pPacket, WORD wValue) -{ - pPacket->pData[pPacket->wPlace++] = (wValue & 0x00ff); - pPacket->pData[pPacket->wPlace++] = ((wValue & 0xff00) >> 8); -} - -void __fastcall packLEDWord(icq_packet *pPacket, DWORD dwValue) -{ - pPacket->pData[pPacket->wPlace++] = (BYTE) (dwValue & 0x000000ff); - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x0000ff00) >> 8); - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x00ff0000) >> 16); - pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0xff000000) >> 24); -} - - -/* helper function to place numerics to buffer */ -static void packWord(PBYTE buf, WORD wValue) -{ - *(buf) = ((wValue & 0xff00) >> 8); - *(buf + 1) = (wValue & 0x00ff); -} - - -static void packDWord(PBYTE buf, DWORD dwValue) -{ - *(buf) = (BYTE)((dwValue & 0xff000000) >> 24); - *(buf + 1) = (BYTE)((dwValue & 0x00ff0000) >> 16); - *(buf + 2) = (BYTE)((dwValue & 0x0000ff00) >> 8); - *(buf + 3) = (BYTE) (dwValue & 0x000000ff); -} - - -static void packQWord(PBYTE buf, DWORD64 qwValue) -{ - packDWord(buf, (DWORD)(qwValue >> 32)); - packDWord(buf + 4, (DWORD)(qwValue & 0xffffffff)); -} - - -void ppackByte(PBYTE *buf, int *buflen, BYTE byValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 1 + *buflen); - *(*buf + *buflen) = byValue; - ++*buflen; -} - - -void ppackWord(PBYTE *buf, int *buflen, WORD wValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 2 + *buflen); - packWord(*buf + *buflen, wValue); - *buflen += 2; -} - - -void ppackLEWord(PBYTE *buf, int *buflen, WORD wValue) -{ - *buf=(PBYTE)SAFE_REALLOC(*buf, 2 + *buflen); - *(PWORD)(*buf + *buflen) = wValue; - *buflen+=2; -} - - -void ppackLEDWord(PBYTE *buf, int *buflen, DWORD dwValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 4 + *buflen); - *(PDWORD)(*buf + *buflen) = dwValue; - *buflen += 4; -} - - -void ppackLELNTS(PBYTE *buf, int *buflen, const char *str) -{ - WORD len = strlennull(str); - ppackLEWord(buf, buflen, len); - *buf = (PBYTE)SAFE_REALLOC(*buf, *buflen + len); - memcpy(*buf + *buflen, str, len); - *buflen += len; -} - - -void ppackBuffer(PBYTE *buf, int *buflen, WORD wLength, const BYTE *pbyValue) -{ - if (wLength) - { - *buf = (PBYTE)SAFE_REALLOC(*buf, wLength + *buflen); - memcpy(*buf + *buflen, pbyValue, wLength); - *buflen += wLength; - } -} - - -void ppackTLV(PBYTE *buf, int *buflen, WORD wType, WORD wLength, const BYTE *pbyValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 4 + wLength + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, wLength); - if (wLength) - memcpy(*buf + *buflen + 4, pbyValue, wLength); - *buflen += 4 + wLength; -} - - -void ppackTLVByte(PBYTE *buf, int *buflen, WORD wType, BYTE byValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 5 + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 1); - *(*buf + *buflen + 4) = byValue; - *buflen += 5; -} - - -void ppackTLVWord(PBYTE *buf, int *buflen, WORD wType, WORD wValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 2); - packWord(*buf + *buflen + 4, wValue); - *buflen += 6; -} - - -void ppackTLVDWord(PBYTE *buf, int *buflen, WORD wType, DWORD dwValue) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 4); - packDWord(*buf + *buflen + 4, dwValue); - *buflen += 8; -} - - -void ppackTLVDouble(PBYTE *buf, int *buflen, WORD wType, double dValue) -{ - DWORD64 qwValue; - - memcpy(&qwValue, &dValue, 8); - - *buf = (PBYTE)SAFE_REALLOC(*buf, 12 + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 8); - packQWord(*buf + *buflen + 4, qwValue); - *buflen += 12; -} - - -void ppackTLVUID(PBYTE *buf, int *buflen, WORD wType, DWORD dwUin, const char *szUid) -{ - if (dwUin) - { - char szUin[UINMAXLEN]; - - _ltoa(dwUin, szUin, 10); - - ppackTLV(buf, buflen, wType, getUINLen(dwUin), (BYTE*)szUin); - } - else if (szUid) - ppackTLV(buf, buflen, wType, strlennull(szUid), (BYTE*)szUid); -} - - -// *** TLV based (!!! WORDs and DWORDs are LE !!!) -void ppackLETLVByte(PBYTE *buf, int *buflen, BYTE byValue, WORD wType, BYTE always) -{ - if (!always && !byValue) return; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 5 + *buflen); - *(PWORD)(*buf + *buflen) = wType; - *(PWORD)(*buf + *buflen + 2) = 1; - *(*buf + *buflen + 4) = byValue; - *buflen += 5; -} - - -void ppackLETLVWord(PBYTE *buf, int *buflen, WORD wValue, WORD wType, BYTE always) -{ - if (!always && !wValue) return; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); - *(PWORD)(*buf + *buflen) = wType; - *(PWORD)(*buf + *buflen + 2) = 2; - *(PWORD)(*buf + *buflen + 4) = wValue; - *buflen += 6; -} - - -void ppackLETLVDWord(PBYTE *buf, int *buflen, DWORD dwValue, WORD wType, BYTE always) -{ - if (!always && !dwValue) return; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen); - *(PWORD)(*buf + *buflen) = wType; - *(PWORD)(*buf + *buflen + 2) = 4; - *(PDWORD)(*buf + *buflen + 4) = dwValue; - *buflen += 8; -} - - -void packLETLVLNTS(PBYTE *buf, int *bufpos, const char *str, WORD wType) -{ - int len = strlennull(str) + 1; - - *(PWORD)(*buf + *bufpos) = wType; - *(PWORD)(*buf + *bufpos + 2) = len + 2; - *(PWORD)(*buf + *bufpos + 4) = len; - memcpy(*buf + *bufpos + 6, str, len); - *bufpos += len + 6; -} - - -void ppackLETLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always) -{ - int len = strlennull(str) + 1; - - if (!always && len < 2) return; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen + len); - packLETLVLNTS(buf, buflen, str, wType); -} - - -void ppackLETLVWordLNTS(PBYTE *buf, int *buflen, WORD w, const char *str, WORD wType, BYTE always) -{ - int len = strlennull(str) + 1; - - if (!always && len < 2 && !w) return; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + len); - *(PWORD)(*buf + *buflen) = wType; - *(PWORD)(*buf + *buflen + 2) = len + 4; - *(PWORD)(*buf + *buflen + 4) = w; - *(PWORD)(*buf + *buflen + 6) = len; - memcpy(*buf + *buflen + 8, str, len); - *buflen += len + 8; -} - - -void ppackLETLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType) -{ - int len = strlennull(str) + 1; - - *buf = (PBYTE)SAFE_REALLOC(*buf, 7 + *buflen + len); - *(PWORD)(*buf + *buflen) = wType; - *(PWORD)(*buf + *buflen + 2) = len + 3; - *(PWORD)(*buf + *buflen + 4) = len; - memcpy(*buf + *buflen + 6, str, len); - *(*buf + *buflen + 6 + len) = b; - *buflen += len + 7; -} - - -void CIcqProto::ppackLETLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) -{ - char szTmp[1024]; - char *str = ""; - - if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) - str = szTmp; - - ppackLETLVLNTS(buf, buflen, str, wType, 1); -} - -void CIcqProto::ppackLETLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType) -{ - char szTmp[1024]; - char *str = ""; - - if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) - str = szTmp; - - ppackLETLVWordLNTS(buf, buflen, w, str, wType, 1); -} - -void CIcqProto::ppackLETLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType) -{ - char szTmp[1024]; - char *str = ""; - - if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) - str = szTmp; - - ppackLETLVLNTSByte(buf, buflen, str, b, wType); -} - - -void CIcqProto::ppackTLVStringFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) -{ - char szTmp[1024]; - char *str = ""; - - if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) - str = szTmp; - - ppackTLV(buf, buflen, wType, strlennull(str), (PBYTE)str); -} - - -void CIcqProto::ppackTLVStringUtfFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) -{ - char *str = getSettingStringUtf(NULL, szSetting, NULL); - - ppackTLV(buf, buflen, wType, strlennull(str), (PBYTE)str); - - SAFE_FREE((void**)&str); -} - - -void CIcqProto::ppackTLVDateFromDB(PBYTE *buf, int *buflen, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, WORD wType) -{ - SYSTEMTIME sTime = {0}; - double time = 0; - - sTime.wYear = getSettingWord(NULL, szSettingYear, 0); - sTime.wMonth = getSettingByte(NULL, szSettingMonth, 0); - sTime.wDay = getSettingByte(NULL, szSettingDay, 0); - if (sTime.wYear || sTime.wMonth || sTime.wDay) - { - SystemTimeToVariantTime(&sTime, &time); - time -= 2; - } - - ppackTLVDouble(buf, buflen, wType, time); -} - - -int CIcqProto::ppackTLVWordStringItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID) -{ - char szTmp[1024]; - char *str = NULL; - - if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) - str = szTmp; - - if (str) - { - WORD wLen = strlennull(str); - - ppackWord(buf, buflen, wLen + 0x0A); - ppackTLVWord(buf, buflen, wTypeID, wID); - ppackTLV(buf, buflen, wTypeData, wLen, (PBYTE)str); - - return 1; // Success - } - - return 0; // No data -} - - -int CIcqProto::ppackTLVWordStringUtfItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID) -{ - char *str = getSettingStringUtf(NULL, szSetting, NULL); - - if (str) - { - WORD wLen = strlennull(str); - - ppackWord(buf, buflen, wLen + 0x0A); - ppackTLVWord(buf, buflen, wTypeID, wID); - ppackTLV(buf, buflen, wTypeData, wLen, (PBYTE)str); - - SAFE_FREE(&str); - - return 1; // Success - } - - return 0; // No data -} - - -void ppackTLVBlockItems(PBYTE *buf, int *buflen, WORD wType, int *nItems, PBYTE *pBlock, WORD *wLength, BOOL bSingleItem) -{ - *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + *wLength); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, (bSingleItem ? 4 : 2) + *wLength); - packWord(*buf + *buflen + 4, *nItems); - if (bSingleItem) - packWord(*buf + *buflen + 6, *wLength); - if (*wLength) - memcpy(*buf + *buflen + (bSingleItem ? 8 : 6), *pBlock, *wLength); - *buflen += (bSingleItem ? 8 : 6) + *wLength; - - SAFE_FREE((void**)pBlock); - *wLength = 0; - *nItems = 0; -} - - -void ppackTLVBlockItem(PBYTE *buf, int *buflen, WORD wType, PBYTE *pItem, WORD *wLength) -{ - if (wLength) - { - *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + *wLength); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 4 + *wLength); - packWord(*buf + *buflen + 4, 1); - packWord(*buf + *buflen + 6, *wLength); - memcpy(*buf + *buflen + 8, *pItem, *wLength); - *buflen += 8 + *wLength; - } - else - { - *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); - packWord(*buf + *buflen, wType); - packWord(*buf + *buflen + 2, 0x02); - packWord(*buf + *buflen + 4, 0); - *buflen += 6; - } - - SAFE_FREE((void**)pItem); - *wLength = 0; -} - - -void __fastcall unpackByte(BYTE **pSource, BYTE *byDestination) -{ - if (byDestination) - *byDestination = *(*pSource)++; - else - *pSource += 1; -} - -void __fastcall unpackWord(BYTE **pSource, WORD *wDestination) -{ - BYTE *tmp = *pSource; - - if (wDestination) - { - *wDestination = *tmp++ << 8; - *wDestination |= *tmp++; - - *pSource = tmp; - } - else - *pSource += 2; -} - -void __fastcall unpackDWord(BYTE **pSource, DWORD *dwDestination) -{ - BYTE *tmp = *pSource; - - if (dwDestination) - { - *dwDestination = *tmp++ << 24; - *dwDestination |= *tmp++ << 16; - *dwDestination |= *tmp++ << 8; - *dwDestination |= *tmp++; - - *pSource = tmp; - } - else - *pSource += 4; -} - -void __fastcall unpackQWord(BYTE **pSource, DWORD64 *qwDestination) -{ - DWORD dwData; - - if (qwDestination) - { - unpackDWord(pSource, &dwData); - *qwDestination = ((DWORD64)dwData) << 32; - unpackDWord(pSource, &dwData); - *qwDestination |= dwData; - } - else - *pSource += 8; -} - -void __fastcall unpackLEWord(BYTE **buf, WORD *w) -{ - BYTE *tmp = *buf; - - if (w) - { - *w = (*tmp++); - *w |= ((*tmp++) << 8); - } - else - tmp += 2; - - *buf = tmp; -} - -void __fastcall unpackLEDWord(BYTE **buf, DWORD *dw) -{ - BYTE *tmp = *buf; - - if (dw) - { - *dw = (*tmp++); - *dw |= ((*tmp++) << 8); - *dw |= ((*tmp++) << 16); - *dw |= ((*tmp++) << 24); - } - else - tmp += 4; - - *buf = tmp; -} - -void unpackString(BYTE **buf, char *string, WORD len) -{ - BYTE *tmp = *buf; - - if (string) - { - while (len) /* Can have 0x00 so go by len */ - { - *string++ = *tmp++; - len--; - } - } - else - tmp += len; - - *buf = tmp; -} - -void unpackWideString(BYTE **buf, WCHAR *string, WORD len) -{ - BYTE *tmp = *buf; - - while (len > 1) - { - *string = (*tmp++ << 8); - *string |= *tmp++; - - string++; - len -= 2; - } - - // We have a stray byte at the end, this means that the buffer had an odd length - // which indicates an error. - _ASSERTE(len == 0); - if (len != 0) - { - // We dont copy the last byte but we still need to increase the buffer pointer - // (we assume that 'len' was correct) since the calling function expects - // that it is increased 'len' bytes. - *tmp += len; - } - - *buf = tmp; -} - -void unpackTypedTLV(BYTE *buf, int buflen, WORD type, WORD *ttype, WORD *tlen, BYTE **ttlv) -{ - WORD wType, wLen; - -NextTLV: - // Unpack type and length - unpackWord(&buf, &wType); - unpackWord(&buf, &wLen); - buflen -= 4; - - if (wType != type && buflen >= wLen + 4) - { // Not the right TLV, try next - buflen -= wLen; - buf += wLen; - goto NextTLV; - } - // Check buffer size - if (wLen > buflen) wLen = buflen; - - // Make sure we have a good pointer - if (ttlv) - { - if (wLen) - { // Unpack and save value - *ttlv = (BYTE*)SAFE_MALLOC(wLen + 1); // Add 1 for \0 - unpackString(&buf, (char*)*ttlv, wLen); - *(*ttlv + wLen) = '\0'; - } - else - *ttlv = NULL; - } - - // Save type and length - if (ttype) - *ttype = wType; - if (tlen) - *tlen = wLen; -} - - -BOOL CIcqProto::unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID) -{ - BYTE nUIDLen; - - // sanity check - if (!ppBuf || !pwLen || *pwLen < 1) - return FALSE; - - // Sender UIN - unpackByte(ppBuf, &nUIDLen); - *pwLen -= 1; - - if ((nUIDLen > *pwLen) || (nUIDLen == 0)) - return FALSE; - - if (nUIDLen <= UINMAXLEN) - { // it can be uin, check - char szUIN[UINMAXLEN+1]; - - unpackString(ppBuf, szUIN, nUIDLen); - szUIN[nUIDLen] = '\0'; - *pwLen -= nUIDLen; - - if (IsStringUIN(szUIN)) - { - *pdwUIN = atoi(szUIN); - return TRUE; - } - else - { // go back - *ppBuf -= nUIDLen; - *pwLen += nUIDLen; - } - } - if (!m_bAimEnabled || !ppszUID || !(*ppszUID)) - { // skip the UID data - *ppBuf += nUIDLen; - *pwLen -= nUIDLen; - - NetLog_Server("Malformed UIN in packet"); - return FALSE; - } - - unpackString(ppBuf, *ppszUID, nUIDLen); - *pwLen -= nUIDLen; - (*ppszUID)[nUIDLen] = '\0'; - - *pdwUIN = 0; // this is how we determine aim contacts internally - - return TRUE; -} diff --git a/protocols/IcqOscarJ/icq_packet.h b/protocols/IcqOscarJ/icq_packet.h deleted file mode 100644 index ccaeb91fcc..0000000000 --- a/protocols/IcqOscarJ/icq_packet.h +++ /dev/null @@ -1,120 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, Bio -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_PACKET_H -#define __ICQ_PACKET_H - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; - -/*---------* Structures *--------------*/ - -struct icq_packet -{ - WORD wPlace; - BYTE nChannel; - WORD wLen; - BYTE *pData; -}; - -/*---------* Functions *---------------*/ - -WORD generate_flap_sequence(); - -void __fastcall init_generic_packet(icq_packet *pPacket, WORD wHeaderLen); -void write_httphdr(icq_packet *pPacket, WORD wType, DWORD dwSeq); -void __fastcall write_flap(icq_packet *pPacket, BYTE byFlapChannel); -void __fastcall serverPacketInit(icq_packet *pPacket, WORD wSize); -void __fastcall directPacketInit(icq_packet *pPacket, DWORD dwSize); - -void __fastcall serverCookieInit(icq_packet *pPacket, BYTE *pCookie, WORD wCookieSize); - -void __fastcall packByte(icq_packet *pPacket, BYTE byValue); -void __fastcall packWord(icq_packet *pPacket, WORD wValue); -void __fastcall packDWord(icq_packet *pPacket, DWORD dwValue); -void __fastcall packQWord(icq_packet *pPacket, DWORD64 qwValue); -void packTLV(icq_packet *pPacket, WORD wType, WORD wLength, const BYTE *pbyValue); -void packTLVWord(icq_packet *pPacket, WORD wType, WORD wData); -void packTLVDWord(icq_packet *pPacket, WORD wType, DWORD dwData); -void packTLVUID(icq_packet *pPacket, WORD wType, DWORD dwUin, const char *szUid); - -void packBuffer(icq_packet *pPacket, const BYTE *pbyBuffer, WORD wLength); -//void packLEWordSizedBuffer(icq_packet* pPacket, const BYTE* pbyBuffer, WORD wLength); -int __fastcall getUINLen(DWORD dwUin); -int __fastcall getUIDLen(DWORD dwUin, const char *szUid); -void __fastcall packUIN(icq_packet *pPacket, DWORD dwUin); -void __fastcall packUID(icq_packet *pPacket, DWORD dwUin, const char *szUid); - -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype); -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence); -void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence, WORD wVersion); - -void __fastcall packLEWord(icq_packet *pPacket, WORD wValue); -void __fastcall packLEDWord(icq_packet *pPacket, DWORD dwValue); - -void packLETLVLNTS(PBYTE *buf, int *bufpos, const char *str, WORD wType); - -void ppackByte(PBYTE *buf, int *buflen, BYTE byValue); -void ppackWord(PBYTE *buf, int *buflen, WORD wValue); -void ppackLEWord(PBYTE *buf, int *buflen, WORD wValue); -void ppackLEDWord(PBYTE *buf, int *buflen, DWORD dwValue); -void ppackLELNTS(PBYTE *buf, int *buflen, const char *str); -void ppackBuffer(PBYTE *buf, int *buflen, WORD wLength, const BYTE *pbyValue); - -void ppackTLV(PBYTE *buf, int *buflen, WORD wType, WORD wLength, const BYTE *pbyValue); -void ppackTLVByte(PBYTE *buf, int *buflen, WORD wType, BYTE byValue); -void ppackTLVWord(PBYTE *buf, int *buflen, WORD wType, WORD wValue); -void ppackTLVDWord(PBYTE *buf, int *buflen, WORD wType, DWORD dwValue); -void ppackTLVDouble(PBYTE *buf, int *buflen, WORD wType, double dValue); -void ppackTLVUID(PBYTE *buf, int *buflen, WORD wType, DWORD dwUin, const char *szUid); - -void ppackLETLVByte(PBYTE *buf, int *buflen, BYTE byValue, WORD wType, BYTE always); -void ppackLETLVWord(PBYTE *buf, int *buflen, WORD wValue, WORD wType, BYTE always); -void ppackLETLVDWord(PBYTE *buf, int *buflen, DWORD dwValue, WORD wType, BYTE always); -void ppackLETLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always); -void ppackLETLVWordLNTS(PBYTE *buf, int *buflen, WORD w, const char *str, WORD wType, BYTE always); -void ppackLETLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType); - -void ppackTLVBlockItems(PBYTE *buf, int *buflen, WORD wType, int *nItems, PBYTE *pBlock, WORD *wLength, BOOL bSingleItem); -void ppackTLVBlockItem(PBYTE *buf, int *buflen, WORD wType, PBYTE *pItem, WORD *wLength); - -void __fastcall unpackByte(BYTE **pSource, BYTE *byDestination); -void __fastcall unpackWord(BYTE **pSource, WORD *wDestination); -void __fastcall unpackDWord(BYTE **pSource, DWORD *dwDestination); -void __fastcall unpackQWord(BYTE **pSource, DWORD64 *qwDestination); -void unpackString(BYTE **buf, char *string, WORD len); -void unpackWideString(BYTE **buf, WCHAR *string, WORD len); -void unpackTypedTLV(BYTE *buf, int buflen, WORD type, WORD *ttype, WORD *tlen, BYTE **ttlv); -BOOL unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID); - -void __fastcall unpackLEWord(BYTE **buf, WORD *w); -void __fastcall unpackLEDWord(BYTE **buf, DWORD *dw); - -#endif /* __ICQ_PACKET_H */ diff --git a/protocols/IcqOscarJ/icq_popups.cpp b/protocols/IcqOscarJ/icq_popups.cpp deleted file mode 100644 index 21ca36348d..0000000000 --- a/protocols/IcqOscarJ/icq_popups.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// PopUp Plugin stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -BOOL bPopUpService = FALSE; - -void InitPopUps() -{ - if (ServiceExists(MS_POPUP_ADDPOPUPEX)) - { - bPopUpService = TRUE; - } -} - -static const UINT icqPopupsControls[] = { - IDC_POPUPS_LOG_ENABLED, IDC_POPUPS_SPAM_ENABLED, IDC_PREVIEW, IDC_USESYSICONS, IDC_POPUP_LOG0_TIMEOUT, - IDC_POPUP_LOG1_TIMEOUT, IDC_POPUP_LOG2_TIMEOUT, IDC_POPUP_LOG3_TIMEOUT, IDC_POPUP_SPAM_TIMEOUT -}; - -static const UINT icqPopupColorControls[] = { - IDC_POPUP_LOG0_TEXTCOLOR, IDC_POPUP_LOG1_TEXTCOLOR, IDC_POPUP_LOG2_TEXTCOLOR, IDC_POPUP_LOG3_TEXTCOLOR, IDC_POPUP_SPAM_TEXTCOLOR, - IDC_POPUP_LOG0_BACKCOLOR, IDC_POPUP_LOG1_BACKCOLOR, IDC_POPUP_LOG2_BACKCOLOR, IDC_POPUP_LOG3_BACKCOLOR, IDC_POPUP_SPAM_BACKCOLOR -}; - -INT_PTR CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static bool bInitDone = true; - BYTE bEnabled; - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch (msg) { - case WM_INITDIALOG: - bInitDone = false; - TranslateDialogDefault(hwndDlg); - - ppro = (CIcqProto*)lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - - CheckDlgButton(hwndDlg, IDC_POPUPS_LOG_ENABLED, ppro->getSettingByte(NULL,"PopupsLogEnabled",DEFAULT_LOG_POPUPS_ENABLED)); - CheckDlgButton(hwndDlg, IDC_POPUPS_SPAM_ENABLED, ppro->getSettingByte(NULL,"PopupsSpamEnabled",DEFAULT_SPAM_POPUPS_ENABLED)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups0TextColor",DEFAULT_LOG0_TEXT_COLORS)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups0BackColor",DEFAULT_LOG0_BACK_COLORS)); - SetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, ppro->getSettingDword(NULL,"Popups0Timeout",DEFAULT_LOG0_TIMEOUT),FALSE); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups1TextColor",DEFAULT_LOG1_TEXT_COLORS)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups1BackColor",DEFAULT_LOG1_BACK_COLORS)); - SetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, ppro->getSettingDword(NULL,"Popups1Timeout",DEFAULT_LOG1_TIMEOUT),FALSE); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups2TextColor",DEFAULT_LOG2_TEXT_COLORS)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups2BackColor",DEFAULT_LOG2_BACK_COLORS)); - SetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, ppro->getSettingDword(NULL,"Popups2Timeout",DEFAULT_LOG2_TIMEOUT),FALSE); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups3TextColor",DEFAULT_LOG3_TEXT_COLORS)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups3BackColor",DEFAULT_LOG3_BACK_COLORS)); - SetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, ppro->getSettingDword(NULL,"Popups3Timeout",DEFAULT_LOG3_TIMEOUT),FALSE); - SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"PopupsSpamTextColor",DEFAULT_SPAM_TEXT_COLORS)); - SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"PopupsSpamBackColor",DEFAULT_SPAM_BACK_COLORS)); - SetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, ppro->getSettingDword(NULL,"PopupsSpamTimeout",DEFAULT_SPAM_TIMEOUT),FALSE); - bEnabled = ppro->getSettingByte(NULL,"PopupsWinColors",DEFAULT_POPUPS_WIN_COLORS); - CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, bEnabled); - bEnabled |= ppro->getSettingByte(NULL,"PopupsDefColors",DEFAULT_POPUPS_DEF_COLORS); - CheckDlgButton(hwndDlg, IDC_USEDEFCOLORS, bEnabled); - icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled); - CheckDlgButton(hwndDlg, IDC_USESYSICONS, ppro->getSettingByte(NULL,"PopupsSysIcons",DEFAULT_POPUPS_SYS_ICONS)); - bEnabled = ppro->getSettingByte(NULL,"PopupsEnabled",DEFAULT_POPUPS_ENABLED); - CheckDlgButton(hwndDlg, IDC_POPUPS_ENABLED, bEnabled); - icq_EnableMultipleControls(hwndDlg, icqPopupsControls, SIZEOF(icqPopupsControls), bEnabled); - if (bEnabled) - { - if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); - } - } - icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & (!IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS) && !IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS))); - bInitDone = true; - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_PREVIEW: - { - ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Note"), LOG_NOTE); - ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Warning"), LOG_WARNING); - ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Error"), LOG_ERROR); - ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Fatal"), LOG_FATAL); - ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Spambot"), POPTYPE_SPAM); - } - return FALSE; - - case IDC_POPUPS_ENABLED: - bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); - if (bEnabled) - { - if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); - } - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); - } - icq_EnableMultipleControls(hwndDlg, icqPopupsControls, SIZEOF(icqPopupsControls), bEnabled); - - case IDC_USEWINCOLORS: - bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); - if (bEnabled) - { - if (IsDlgButtonChecked(hwndDlg, IDC_USEWINCOLORS)) - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); - else - EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); - } - icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & !IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS)); - - case IDC_USEDEFCOLORS: - bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); - if (bEnabled) - { - if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); - else - EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); - } - icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & !IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS)); - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - break; - case IDC_POPUP_LOG0_TIMEOUT: - case IDC_POPUP_LOG1_TIMEOUT: - case IDC_POPUP_LOG2_TIMEOUT: - case IDC_POPUP_LOG3_TIMEOUT: - case IDC_POPUP_SPAM_TIMEOUT: - if ((HIWORD(wParam) == EN_CHANGE) && bInitDone) - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - break; - default: - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - break; - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case PSN_APPLY: - ppro->setSettingByte(NULL,"PopupsEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED)); - ppro->setSettingByte(NULL,"PopupsLogEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_LOG_ENABLED)); - ppro->setSettingByte(NULL,"PopupsSpamEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_SPAM_ENABLED)); - ppro->setSettingDword(NULL,"Popups0TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_TEXTCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups0BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_BACKCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups0Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, NULL, FALSE)); - ppro->setSettingDword(NULL,"Popups1TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_TEXTCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups1BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_BACKCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups1Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, NULL, FALSE)); - ppro->setSettingDword(NULL,"Popups2TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_TEXTCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups2BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_BACKCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups2Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, NULL, FALSE)); - ppro->setSettingDword(NULL,"Popups3TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_TEXTCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups3BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_BACKCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"Popups3Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, NULL, FALSE)); - ppro->setSettingDword(NULL,"PopupsSpamTextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_TEXTCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"PopupsSpamBackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_BACKCOLOR,CPM_GETCOLOUR,0,0)); - ppro->setSettingDword(NULL,"PopupsSpamTimeout",GetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, NULL, FALSE)); - ppro->setSettingByte(NULL,"PopupsWinColors",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS)); - ppro->setSettingByte(NULL,"PopupsDefColors",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS)); - ppro->setSettingByte(NULL,"PopupsSysIcons",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USESYSICONS)); - return TRUE; - } - break; - } - return FALSE; -} - -int CIcqProto::ShowPopUpMsg(HANDLE hContact, const char *szTitle, const char *szMsg, BYTE bType) -{ - if (bPopUpService && getSettingByte(NULL, "PopupsEnabled", DEFAULT_POPUPS_ENABLED)) - { - POPUPDATAEX ppd = {0}; - POPUPDATAW ppdw = {0}; - LPCTSTR rsIcon; - char szPrefix[32], szSetting[32]; - - strcpy(szPrefix, "Popups"); - ppd.iSeconds = 0; - - switch(bType) { - case LOG_NOTE: - rsIcon = MAKEINTRESOURCE(IDI_INFORMATION); - ppd.colorBack = DEFAULT_LOG0_BACK_COLORS; - ppd.colorText = DEFAULT_LOG0_TEXT_COLORS; - strcat(szPrefix, "0"); - break; - - case LOG_WARNING: - rsIcon = MAKEINTRESOURCE(IDI_WARNING); - ppd.colorBack = DEFAULT_LOG1_BACK_COLORS; - ppd.colorText = DEFAULT_LOG1_TEXT_COLORS; - strcat(szPrefix, "1"); - break; - - case LOG_ERROR: - rsIcon = MAKEINTRESOURCE(IDI_ERROR); - ppd.colorBack = DEFAULT_LOG2_BACK_COLORS; - ppd.colorText = DEFAULT_LOG2_TEXT_COLORS; - strcat(szPrefix, "2"); - break; - - case LOG_FATAL: - rsIcon = MAKEINTRESOURCE(IDI_ERROR); - ppd.colorBack = DEFAULT_LOG3_BACK_COLORS; - ppd.colorText = DEFAULT_LOG3_TEXT_COLORS; - strcat(szPrefix, "3"); - break; - - case POPTYPE_SPAM: - rsIcon = MAKEINTRESOURCE(IDI_WARNING); - ppd.colorBack = DEFAULT_SPAM_BACK_COLORS; - ppd.colorText = DEFAULT_SPAM_TEXT_COLORS; - strcat(szPrefix, "Spam"); - break; - default: - return -1; - } - if (!getSettingByte(NULL, "PopupsSysIcons", DEFAULT_POPUPS_SYS_ICONS)) - ppd.lchIcon = m_hIconProtocol->GetIcon(); - else - ppd.lchIcon = (HICON)LoadImage( NULL, rsIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); - if (getSettingByte(NULL, "PopupsWinColors", DEFAULT_POPUPS_WIN_COLORS)) - { - ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); - ppd.colorBack = GetSysColor(COLOR_WINDOW); - } - else - { - if (getSettingByte(NULL, "PopupsDefColors", DEFAULT_POPUPS_DEF_COLORS)) - { - ppd.colorText = NULL; - ppd.colorBack = NULL; - } - else - { - strcpy(szSetting, szPrefix); - strcat(szSetting, "TextColor"); - ppd.colorText = getSettingDword(NULL, szSetting, ppd.colorText); - strcpy(szSetting, szPrefix); - strcat(szSetting, "BackColor"); - ppd.colorBack = getSettingDword(NULL, szSetting, ppd.colorBack); - } - } - strcpy(szSetting, szPrefix); - strcat(szSetting, "Timeout"); - ppd.iSeconds = getSettingDword(NULL, szSetting, ppd.iSeconds); - - // call unicode popup module - only on unicode OS otherwise it will not work properly :( - // due to Popup Plug bug in ADDPOPUPW implementation - if ( ServiceExists( MS_POPUP_ADDPOPUPW )) - { - char str[4096]; - - make_unicode_string_static(ICQTranslateUtfStatic(szTitle, str, sizeof(str)), ppdw.lpwzContactName, MAX_CONTACTNAME); - make_unicode_string_static(ICQTranslateUtfStatic(szMsg, str, sizeof(str)), ppdw.lpwzText, MAX_SECONDLINE); - ppdw.lchContact = hContact; - ppdw.lchIcon = ppd.lchIcon; - ppdw.colorBack = ppd.colorBack; - ppdw.colorText = ppd.colorText; - ppdw.PluginWindowProc = NULL; - ppdw.PluginData = NULL; - ppdw.iSeconds = ppd.iSeconds; - return CallService(MS_POPUP_ADDPOPUPW, (WPARAM)&ppdw, 0); - } - else - - { - char str[MAX_PATH]; - - utf8_decode_static(ICQTranslateUtfStatic(szTitle, str, MAX_PATH), ppd.lpzContactName, MAX_CONTACTNAME); - utf8_decode_static(ICQTranslateUtfStatic(szMsg, str, MAX_PATH), ppd.lpzText, MAX_SECONDLINE); - ppd.lchContact = hContact; - ppd.PluginWindowProc = NULL; - ppd.PluginData = NULL; - - return CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0); - } - } - return -1; // Failure -} diff --git a/protocols/IcqOscarJ/icq_popups.h b/protocols/IcqOscarJ/icq_popups.h deleted file mode 100644 index a42c230634..0000000000 --- a/protocols/IcqOscarJ/icq_popups.h +++ /dev/null @@ -1,41 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Headers for PopUp Plugin support -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_POPUPS_H -#define __ICQ_POPUPS_H - - -#define POPTYPE_SPAM 254 // this is for spambots - - -void InitPopUps(); -void InitPopupOpts(WPARAM wParam); - - -#endif /* __ICQ_POPUPS_H */ diff --git a/protocols/IcqOscarJ/icq_proto.cpp b/protocols/IcqOscarJ/icq_proto.cpp deleted file mode 100755 index d1490fac2e..0000000000 --- a/protocols/IcqOscarJ/icq_proto.cpp +++ /dev/null @@ -1,2375 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, George Hazan -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Protocol Interface Implementation -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -#include "m_icolib.h" - -extern PLUGININFOEX pluginInfo; -extern HANDLE hExtraXStatus; - -#pragma warning(disable:4355) - -static int CompareConns(const directconnect* p1, const directconnect* p2) -{ - if (p1 < p2) - return -1; - - return (p1 == p2) ? 0 : 1; -} - -static int CompareCookies( const icq_cookie_info* p1, const icq_cookie_info* p2 ) -{ - if ( p1->dwCookie < p2->dwCookie ) - return -1; - - return ( p1->dwCookie == p2->dwCookie ) ? 0 : 1; -} - -static int CompareFT( const filetransfer* p1, const filetransfer* p2 ) -{ - if ( p1->dwCookie < p2->dwCookie ) - return -1; - - return ( p1->dwCookie == p2->dwCookie ) ? 0 : 1; -} - -static int CompareContactsCache(const icq_contacts_cache *p1, const icq_contacts_cache *p2) -{ - if (p1->dwUin < p2->dwUin) - return -1; - - if (p1->dwUin > p2->dwUin) - return 1; - - return stricmpnull(p1->szUid, p2->szUid); -} - -CIcqProto::CIcqProto( const char* aProtoName, const TCHAR* aUserName ) : -cookies(10, CompareCookies), -directConns(10, CompareConns), -expectedFileRecvs(10, CompareFT), -contactsCache(10, CompareContactsCache), -cheekySearchId( -1 ) -{ - m_iVersion = 2; - m_iStatus = ID_STATUS_OFFLINE; - m_tszUserName = mir_tstrdup( aUserName ); - m_szModuleName = mir_strdup( aProtoName ); - m_szProtoName = mir_strdup( aProtoName ); - _strlwr( m_szProtoName ); - m_szProtoName[0] = toupper( m_szProtoName[0] ); - NetLog_Server( "Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName ); - - oftMutex = new icq_critical_section(); - - // Initialize direct connections - directConnListMutex = new icq_critical_section(); - expectedFileRecvMutex = new icq_critical_section(); - - // Initialize server lists - servlistMutex = new icq_critical_section(); - servlistQueueMutex = new icq_critical_section(); - HookProtoEvent(ME_CLIST_GROUPCHANGE, &CIcqProto::ServListCListGroupChange); - - // Initialize status message struct - ZeroMemory(&m_modeMsgs, sizeof(icq_mode_messages)); - m_modeMsgsMutex = new icq_critical_section(); - connectionHandleMutex = new icq_critical_section(); - localSeqMutex = new icq_critical_section(); - - m_modeMsgsEvent = CreateProtoEvent(ME_ICQ_STATUSMSGREQ); - hxstatuschanged = CreateProtoEvent(ME_ICQ_CUSTOMSTATUS_CHANGED); - hxstatusiconchanged = CreateProtoEvent(ME_ICQ_CUSTOMSTATUS_EXTRAICON_CHANGED); - - // Initialize cookies - cookieMutex = new icq_critical_section(); - wCookieSeq = 2; - - // Initialize rates - m_ratesMutex = new icq_critical_section(); - - // Initialize avatars - m_avatarsMutex = new icq_critical_section(); - - // Initialize temporary DB settings - CreateResidentSetting("Status"); // NOTE: XStatus cannot be temporary - CreateResidentSetting("TemporaryVisible"); - CreateResidentSetting("TickTS"); - CreateResidentSetting("IdleTS"); - CreateResidentSetting("AwayTS"); - CreateResidentSetting("LogonTS"); - CreateResidentSetting("DCStatus"); - CreateResidentSetting("CapBuf"); //capabilities bufer - CreateResidentSetting(DBSETTING_STATUS_NOTE_TIME); - CreateResidentSetting(DBSETTING_STATUS_MOOD); - - // Setup services - CreateProtoService(PS_CREATEACCMGRUI, &CIcqProto::OnCreateAccMgrUI ); - CreateProtoService(MS_ICQ_SENDSMS, &CIcqProto::SendSms); - CreateProtoService(PS_SET_NICKNAME, &CIcqProto::SetNickName); - - CreateProtoService(PS_GETMYAWAYMSG, &CIcqProto::GetMyAwayMsg); - - CreateProtoService(PS_GETINFOSETTING, &CIcqProto::GetInfoSetting); - - CreateProtoService(PSS_ADDED, &CIcqProto::SendYouWereAdded); - // Session password API - CreateProtoService(PS_ICQ_SETPASSWORD, &CIcqProto::SetPassword); - // ChangeInfo API - CreateProtoService(PS_CHANGEINFOEX, &CIcqProto::ChangeInfoEx); - // Avatar API - CreateProtoService(PS_GETAVATARINFOT, &CIcqProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &CIcqProto::GetAvatarCaps); - CreateProtoService(PS_GETMYAVATART, &CIcqProto::GetMyAvatar); - CreateProtoService(PS_SETMYAVATART, &CIcqProto::SetMyAvatar); - // Custom Status API - CreateProtoService(PS_ICQ_SETCUSTOMSTATUS, &CIcqProto::SetXStatus); - CreateProtoService(PS_ICQ_GETCUSTOMSTATUS, &CIcqProto::GetXStatus); - CreateProtoService(PS_ICQ_SETCUSTOMSTATUSEX, &CIcqProto::SetXStatusEx); - CreateProtoService(PS_ICQ_GETCUSTOMSTATUSEX, &CIcqProto::GetXStatusEx); - CreateProtoService(PS_ICQ_GETCUSTOMSTATUSICON, &CIcqProto::GetXStatusIcon); - CreateProtoService(PS_ICQ_REQUESTCUSTOMSTATUS, &CIcqProto::RequestXStatusDetails); - CreateProtoService(PS_ICQ_GETADVANCEDSTATUSICON, &CIcqProto::RequestAdvStatusIconIdx); - - CreateProtoService(MS_ICQ_ADDSERVCONTACT, &CIcqProto::AddServerContact); - - CreateProtoService(MS_REQ_AUTH, &CIcqProto::RequestAuthorization); - CreateProtoService(MS_GRANT_AUTH, &CIcqProto::GrantAuthorization); - CreateProtoService(MS_REVOKE_AUTH, &CIcqProto::RevokeAuthorization); - - CreateProtoService(MS_XSTATUS_SHOWDETAILS, &CIcqProto::ShowXStatusDetails); - - // Custom caps - CreateProtoService(PS_ICQ_ADDCAPABILITY, &CIcqProto::IcqAddCapability); - CreateProtoService(PS_ICQ_CHECKCAPABILITY, &CIcqProto::IcqCheckCapability); - - - HookProtoEvent(ME_SKIN2_ICONSCHANGED, &CIcqProto::OnReloadIcons); - - { - // Initialize IconLib icons - char szSectionName[MAX_PATH], *szAccountName = tchar_to_utf8(m_tszUserName); - null_snprintf(szSectionName, sizeof(szSectionName), "Protocols/%s/Accounts", ICQ_PROTOCOL_NAME); - - TCHAR lib[MAX_PATH]; - GetModuleFileName(hInst, lib, MAX_PATH); - - m_hIconProtocol = IconLibDefine(szAccountName, szSectionName, m_szModuleName, "main", lib, -IDI_ICQ); - SAFE_FREE(&szAccountName); - } - - // Reset a bunch of session specific settings - UpdateGlobalSettings(); - ResetSettingsOnLoad(); - - // Initialize Contacts Cache - InitContactsCache(); - - // Startup Auto Info-Update thread - icq_InitInfoUpdate(); - - // Init extra statuses - InitXStatusIcons(); - - HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &CIcqProto::OnPreBuildStatusMenu); - - // Register netlib users - NETLIBUSER nlu = {0}; - TCHAR szBuffer[MAX_PATH + 64]; - null_snprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s server connection"), m_tszUserName); - nlu.cbSize = sizeof(nlu); - nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; - nlu.ptszDescriptiveName = szBuffer; - nlu.szSettingsModule = m_szModuleName; - nlu.szHttpGatewayHello = "http://http.proxy.icq.com/hello"; - nlu.szHttpGatewayUserAgent = "Mozilla/4.08 [en] (WinNT; U ;Nav)"; - nlu.pfnHttpGatewayInit = icq_httpGatewayInit; - nlu.pfnHttpGatewayBegin = icq_httpGatewayBegin; - nlu.pfnHttpGatewayWrapSend = icq_httpGatewayWrapSend; - nlu.pfnHttpGatewayUnwrapRecv = icq_httpGatewayUnwrapRecv; - m_hServerNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - char szP2PModuleName[MAX_PATH]; - null_snprintf(szP2PModuleName, SIZEOF(szP2PModuleName), "%sP2P", m_szModuleName); - null_snprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s client-to-client connections"), m_tszUserName); - nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_TCHAR; - nlu.ptszDescriptiveName = szBuffer; - nlu.szSettingsModule = szP2PModuleName; - nlu.minIncomingPorts = 1; - m_hDirectNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - // Register custom database events - DBEVENTTYPEDESCR eventType = {0}; - eventType.cbSize = DBEVENTTYPEDESCR_SIZE; - eventType.eventType = ICQEVENTTYPE_MISSEDMESSAGE; - eventType.module = m_szModuleName; - eventType.descr = "Missed message notifications"; - eventType.textService = ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE; - eventType.flags = DETF_HISTORY | DETF_MSGWINDOW; - // for now keep default "message" icon - CallService(MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&eventType); - - // Protocol instance is ready - NetLog_Server("%s: Protocol instance '%s' created.", ICQ_PROTOCOL_NAME, m_szModuleName); -} - - -CIcqProto::~CIcqProto() -{ - m_bXStatusEnabled = 10; // block clist changing - m_bMoodsEnabled = 10; - - // Serv-list update board clean-up - FlushServerIDs(); - /// TODO: make sure server-list handler thread is not running - /// TODO: save state of server-list update board to DB - servlistPendingFlushOperations(); - SAFE_FREE((void**)&servlistQueueList); - - // Finalize avatars - /// TODO: cleanup remaining avatar requests - SAFE_DELETE(&m_avatarsMutex); - - // NetLib clean-up - NetLib_SafeCloseHandle(&m_hDirectNetlibUser); - NetLib_SafeCloseHandle(&m_hServerNetlibUser); - - // Destroy hookable events - if (m_modeMsgsEvent) - DestroyHookableEvent(m_modeMsgsEvent); - - if (hxstatuschanged) - DestroyHookableEvent(hxstatuschanged); - - if (hxstatusiconchanged) - DestroyHookableEvent(hxstatusiconchanged); - - // Clean-up remaining protocol instance members - cookies.destroy(); - - UninitContactsCache(); - - CustomCapList.clear(); - - SAFE_DELETE(&m_ratesMutex); - - SAFE_DELETE(&servlistMutex); - SAFE_DELETE(&servlistQueueMutex); - - SAFE_DELETE(&m_modeMsgsMutex); - SAFE_DELETE(&localSeqMutex); - SAFE_DELETE(&connectionHandleMutex); - SAFE_DELETE(&oftMutex); - SAFE_DELETE(&directConnListMutex); - SAFE_DELETE(&expectedFileRecvMutex); - SAFE_DELETE(&cookieMutex); - - SAFE_FREE(&m_modeMsgs.szOnline); - SAFE_FREE(&m_modeMsgs.szAway); - SAFE_FREE(&m_modeMsgs.szNa); - SAFE_FREE(&m_modeMsgs.szOccupied); - SAFE_FREE(&m_modeMsgs.szDnd); - SAFE_FREE(&m_modeMsgs.szFfc); - - // Remove account icons - UninitXStatusIcons(); - - IconLibRemove(&m_hIconProtocol); - - NetLog_Server("%s: Protocol instance '%s' destroyed.", ICQ_PROTOCOL_NAME, m_szModuleName); - - mir_free( m_szProtoName ); - mir_free( m_szModuleName ); - mir_free( m_tszUserName ); -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// OnModulesLoadedEx - performs hook registration - - -int CIcqProto::OnModulesLoaded( WPARAM wParam, LPARAM lParam ) -{ - char pszP2PName[MAX_PATH]; - char pszGroupsName[MAX_PATH]; - char pszSrvGroupsName[MAX_PATH]; - char* modules[5] = {0,0,0,0,0}; - - null_snprintf(pszP2PName, SIZEOF(pszP2PName), "%sP2P", m_szModuleName); - null_snprintf(pszGroupsName, SIZEOF(pszGroupsName), "%sGroups", m_szModuleName); - null_snprintf(pszSrvGroupsName, SIZEOF(pszSrvGroupsName), "%sSrvGroups", m_szModuleName); - modules[0] = m_szModuleName; - modules[1] = pszP2PName; - modules[2] = pszGroupsName; - modules[3] = pszSrvGroupsName; - CallService("DBEditorpp/RegisterModule",(WPARAM)modules,(LPARAM)4); - - HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit); - HookProtoEvent(ME_USERINFO_INITIALISE, &CIcqProto::OnUserInfoInit); - HookProtoEvent(ME_IDLE_CHANGED, &CIcqProto::OnIdleChanged); - - InitAvatars(); - - // Init extra optional modules - InitPopUps(); - InitXStatusItems(FALSE); - - if (hExtraXStatus == NULL) - { - if (HookProtoEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CIcqProto::CListMW_ExtraIconsRebuild)) - { // note if the Hook was successful (e.g. clist_nicer creates them too late) - HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CIcqProto::CListMW_ExtraIconsApply); - bXStatusExtraIconsReady = 1; - } - } - else - { - HANDLE hContact = FindFirstContact(); - while (hContact != NULL) - { - DWORD bXStatus = getContactXStatus(hContact); - if (bXStatus > 0) - setContactExtraIcon(hContact, bXStatus); - - hContact = FindNextContact(hContact); - } - } - - return 0; -} - -int CIcqProto::OnPreShutdown(WPARAM wParam,LPARAM lParam) -{ - // signal info update thread to stop - icq_InfoUpdateCleanup(); - - // Make sure all connections are closed - CloseContactDirectConns(NULL); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AddToList - adds a contact to the contact list - -HANDLE CIcqProto::AddToList( int flags, PROTOSEARCHRESULT* psr ) -{ - if (psr) - { - if (psr->cbSize == sizeof(ICQSEARCHRESULT)) - { - ICQSEARCHRESULT *isr = (ICQSEARCHRESULT*)psr; - if (isr->uin) - return AddToListByUIN(isr->uin, flags); - else - { // aim contact - char szUid[MAX_PATH]; - - if (isr->hdr.flags & PSR_UNICODE) - unicode_to_ansi_static((WCHAR*)isr->hdr.id, szUid, MAX_PATH); - else - null_strcpy(szUid, (char*)isr->hdr.id, MAX_PATH); - - if (szUid[0] == 0) return 0; - return AddToListByUID(szUid, flags); - } - } - else - { - char szUid[MAX_PATH]; - - if (psr->flags & PSR_UNICODE) - unicode_to_ansi_static((WCHAR*)psr->id, szUid, MAX_PATH); - else - null_strcpy(szUid, (char*)psr->id, MAX_PATH); - - if (szUid[0] == 0) return 0; - if (IsStringUIN(szUid)) - return AddToListByUIN(atoi(szUid), flags); - else - return AddToListByUID(szUid, flags); - } - } - - return 0; // Failure -} - -HANDLE __cdecl CIcqProto::AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ) -{ - DWORD uin = 0; - uid_str uid = {0}; - - DBEVENTINFO dbei = {0}; - dbei.cbSize = sizeof(dbei); - if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0)) == -1) - return 0; - - dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob + 1); - dbei.pBlob[dbei.cbBlob] = '\0'; - - if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei)) - return 0; // failed to get event - - if (strcmpnull(dbei.szModule, m_szModuleName)) - return 0; // this event is not ours - - switch(dbei.eventType) { - case EVENTTYPE_CONTACTS: - { - char *pbOffset = (char*)dbei.pBlob; - char *pbEnd = pbOffset + dbei.cbBlob; - for (int i = 0; i <= iContact; i++) { - pbOffset += strlennull(pbOffset) + 1; // Nick - if (pbOffset >= pbEnd) break; - if (i == iContact) - { // we found the contact, get uid - if (IsStringUIN((char*)pbOffset)) - uin = atoi((char*)pbOffset); - else - { - uin = 0; - strcpy(uid, (char*)pbOffset); - } - } - pbOffset += strlennull(pbOffset) + 1; // Uin - if (pbOffset >= pbEnd) break; - } - } - break; - - case EVENTTYPE_AUTHREQUEST: - case EVENTTYPE_ADDED: - if ( getContactUid( DbGetAuthEventContact(&dbei), &uin, &uid)) - return 0; - - default: - return 0; - } - - if (uin != 0) - return AddToListByUIN(uin, flags); // Success - - // add aim contact - if (strlennull(uid)) - return AddToListByUID(uid, flags); // Success - - return NULL; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AuthAllow - processes the successful authorization - -int CIcqProto::Authorize( HANDLE hDbEvent ) -{ - if (icqOnline() && hDbEvent) - { - HANDLE hContact = HContactFromAuthEvent( hDbEvent ); - if (hContact == INVALID_HANDLE_VALUE) - return 1; - - DWORD uin; - uid_str uid; - if (getContactUid(hContact, &uin, &uid)) - return 1; - - icq_sendAuthResponseServ(uin, uid, 1, _T("")); - - deleteSetting(hContact, "Grant"); - - return 0; // Success - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AuthDeny - handles the unsuccessful authorization - -int CIcqProto::AuthDeny( HANDLE hDbEvent, const TCHAR* szReason ) -{ - if (icqOnline() && hDbEvent) - { - HANDLE hContact = HContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_HANDLE_VALUE) - return 1; - - DWORD uin; - uid_str uid; - if (getContactUid(hContact, &uin, &uid)) - return 1; - - icq_sendAuthResponseServ(uin, uid, 0, szReason); - - if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) - CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); - - return 0; // Success - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AUTH - -int __cdecl CIcqProto::AuthRecv( HANDLE hContact, PROTORECVEVENT* pre ) -{ - setContactHidden( hContact, 0 ); - ICQAddRecvEvent( NULL, EVENTTYPE_AUTHREQUEST, pre, pre->lParam, (PBYTE)pre->szMessage, 0 ); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AUTHREQUEST - -int __cdecl CIcqProto::AuthRequest( HANDLE hContact, const TCHAR* szMessage ) -{ - if ( !icqOnline()) - return 1; - - if (hContact) - { - DWORD dwUin; - uid_str szUid; - if (getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - if (dwUin) - { - char *utf = tchar_to_utf8(szMessage); - icq_sendAuthReqServ(dwUin, szUid, utf); - SAFE_FREE(&utf); - return 0; // Success - } - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// ChangeInfo - -HANDLE __cdecl CIcqProto::ChangeInfo( int iInfoType, void* pInfoData ) -{ - return NULL; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileAllow - starts a file transfer - -HANDLE __cdecl CIcqProto::FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ) -{ - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 0; // Invalid contact - - if (icqOnline() && hContact && szPath && hTransfer) - { // approve old fashioned file transfer - basic_filetransfer *ft = (basic_filetransfer *)hTransfer; - - if (!IsValidFileTransfer(ft)) - return 0; // Invalid transfer - - if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) - { - filetransfer *ft = (filetransfer *)hTransfer; - ft->szSavePath = tchar_to_utf8(szPath); - - { - icq_lock l(expectedFileRecvMutex); - expectedFileRecvs.insert(ft); - } - - // Was request received thru DC and have we a open DC, send through that - if (ft->bDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - icq_sendFileAcceptDirect(hContact, ft); - else - icq_sendFileAcceptServ(dwUin, ft, 0); - - return hTransfer; // Success - } - else if (ft->ft_magic == FT_MAGIC_OSCAR) - { // approve oscar file transfer - return oftFileAllow(hContact, hTransfer, szPath); - } - } - - return 0; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileCancel - cancels a file transfer - -int __cdecl CIcqProto::FileCancel( HANDLE hContact, HANDLE hTransfer ) -{ - DWORD dwUin; - uid_str szUid; - if ( getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - if (hContact && hTransfer) - { - basic_filetransfer *ft = (basic_filetransfer *)hTransfer; - - if (!IsValidFileTransfer(ft)) - return 1; // Invalid transfer - - if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) - { // cancel old fashioned file transfer - filetransfer * ft = (filetransfer*)hTransfer; - icq_CancelFileTransfer(hContact, ft); - return 0; // Success - } - else if (ft->ft_magic == FT_MAGIC_OSCAR) - { // cancel oscar file transfer - return oftFileCancel(hContact, hTransfer); - } - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileDeny - denies a file transfer - -int __cdecl CIcqProto::FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ) -{ - int nReturnValue = 1; - DWORD dwUin; - uid_str szUid; - basic_filetransfer *ft = (basic_filetransfer*)hTransfer; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - if (icqOnline() && hTransfer && hContact) - { - if (!IsValidFileTransfer(hTransfer)) - return 1; // Invalid transfer - - if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) - { // deny old fashioned file transfer - filetransfer *ft = (filetransfer*)hTransfer; - char *szReasonUtf = tchar_to_utf8(szReason); - // Was request received thru DC and have we a open DC, send through that - if (ft->bDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - icq_sendFileDenyDirect(hContact, ft, szReasonUtf); - else - icq_sendFileDenyServ(dwUin, ft, szReasonUtf, 0); - SAFE_FREE(&szReasonUtf); - - nReturnValue = 0; // Success - } - else if (ft->ft_magic == FT_MAGIC_OSCAR) - { // deny oscar file transfer - return oftFileDeny(hContact, hTransfer, szReason); - } - } - // Release possible orphan structure - SafeReleaseFileTransfer((void**)&ft); - - return nReturnValue; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileResume - processes file renaming etc - -int __cdecl CIcqProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) -{ - if (icqOnline() && hTransfer) - { - basic_filetransfer *ft = (basic_filetransfer *)hTransfer; - - if (!IsValidFileTransfer(ft)) - return 1; // Invalid transfer - - if (ft->ft_magic == FT_MAGIC_ICQ) - { - char *szFileNameUtf = tchar_to_utf8(*szFilename); - icq_sendFileResume((filetransfer *)hTransfer, *action, szFileNameUtf); - SAFE_FREE(&szFileNameUtf); - } - else if (ft->ft_magic == FT_MAGIC_OSCAR) - { - oftFileResume((oscar_filetransfer *)hTransfer, *action, *szFilename); - } - else - return 1; // Failure - - return 0; // Success - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// GetCaps - return protocol capabilities bits - -DWORD_PTR __cdecl CIcqProto::GetCaps( int type, HANDLE hContact ) -{ - DWORD_PTR nReturn = 0; - - switch ( type ) { - - case PFLAGNUM_1: - nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | - PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_EXTSEARCH | - PF1_EXTSEARCHUI | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | - PF1_ADDED | PF1_CONTACT; - if (!m_bAimEnabled) - nReturn |= PF1_NUMERICUSERID; - if (m_bSsiEnabled && getSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER)) - nReturn |= PF1_SERVERCLIST; - break; - - case PFLAGNUM_2: - nReturn = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | - PF2_FREECHAT | PF2_INVISIBLE; - if (m_bAimEnabled) - nReturn |= PF2_ONTHEPHONE; - break; - - case PFLAGNUM_3: - nReturn = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | - PF2_FREECHAT | PF2_INVISIBLE; - break; - - case PFLAGNUM_4: - nReturn = PF4_SUPPORTIDLE | PF4_IMSENDUTF | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC; - if (m_bAvatarsEnabled) - nReturn |= PF4_AVATARS; -#ifdef DBG_CAPMTN - nReturn |= PF4_SUPPORTTYPING; -#endif - break; - - case PFLAGNUM_5: - nReturn = PF2_FREECHAT; - if (m_bAimEnabled) - nReturn |= PF2_ONTHEPHONE; - break; - - case PFLAG_UNIQUEIDTEXT: - nReturn = (DWORD_PTR)Translate("User ID"); - break; - - case PFLAG_UNIQUEIDSETTING: - nReturn = (DWORD_PTR)UNIQUEIDSETTING; - break; - - case PFLAG_MAXCONTACTSPERPACKET: - if ( hContact ) - { // determine per contact - BYTE bClientId = getSettingByte(hContact, "ClientID", CLID_GENERIC); - - if (bClientId == CLID_MIRANDA) - { - if (CheckContactCapabilities(hContact, CAPF_CONTACTS) && getContactStatus(hContact) != ID_STATUS_OFFLINE) - nReturn = 0x100; // limited only by packet size - else - nReturn = MAX_CONTACTSSEND; - } - else if (bClientId == CLID_ICQ6) - { - if (CheckContactCapabilities(hContact, CAPF_CONTACTS)) - nReturn = 1; // crapy ICQ6 cannot handle multiple contacts in the transfer - else - nReturn = 0; // this version does not support contacts transfer at all - } - else - nReturn = MAX_CONTACTSSEND; - } - else // return generic limit - nReturn = MAX_CONTACTSSEND; - break; - - case PFLAG_MAXLENOFMESSAGE: - nReturn = MAX_MESSAGESNACSIZE-102; - } - - return nReturn; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetIcon - loads an icon for the contact list - -HICON __cdecl CIcqProto::GetIcon( int iconIndex ) -{ - if (LOWORD(iconIndex) == PLI_PROTOCOL) - { - if (iconIndex & PLIF_ICOLIBHANDLE) - return (HICON)m_hIconProtocol->Handle(); - - bool big = (iconIndex & PLIF_SMALL) == 0; - HICON hIcon = m_hIconProtocol->GetIcon(big); - - if (iconIndex & PLIF_ICOLIB) - return hIcon; - - hIcon = CopyIcon(hIcon); - m_hIconProtocol->ReleaseIcon(big); - return hIcon; - - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetInfo - retrieves a contact info - -int __cdecl CIcqProto::GetInfo(HANDLE hContact, int infoType) -{ - if (icqOnline()) - { - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - DWORD dwCookie; - if (dwUin) - dwCookie = icq_sendGetInfoServ(hContact, dwUin, (infoType & SGIF_ONOPEN) != 0); - else // TODO: this needs something better - dwCookie = icq_sendGetAimProfileServ(hContact, szUid); - - return (dwCookie) ? 0 : 1; - } - - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchBasic - searches the contact by UID - -void CIcqProto::CheekySearchThread( void* ) -{ - char szUin[UINMAXLEN]; - ICQSEARCHRESULT isr = {0}; - isr.hdr.cbSize = sizeof(isr); - - if (cheekySearchUin) - { - _itoa(cheekySearchUin, szUin, 10); - isr.hdr.id = (FNAMECHAR*)szUin; - } - else - { - isr.hdr.id = (FNAMECHAR*)cheekySearchUid; - } - isr.uin = cheekySearchUin; - - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)cheekySearchId, (LPARAM)&isr); - BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)cheekySearchId, 0); - cheekySearchId = -1; -} - - -HANDLE __cdecl CIcqProto::SearchBasic( const PROTOCHAR *pszSearch ) -{ - if (strlennull(pszSearch) == 0) - return 0; - - char pszUIN[255]; - int nHandle = 0; - int i, j; - - if (!m_bAimEnabled) - { - for (i=j=0; (i=0x30) && (pszSearch[i]<=0x39)) - { - pszUIN[j] = pszSearch[i]; - j++; - } - } - } - else - { - for (i=j=0; (i= 0x80) continue; - pszUIN[j] = pszSearch[i]; - j++; - } - } - } - pszUIN[j] = 0; - - if (strlennull(pszUIN)) - { - DWORD dwUin; - if (IsStringUIN(pszUIN)) - dwUin = atoi(pszUIN); - else - dwUin = 0; - - // Cheeky instant UIN search - if (!dwUin || GetKeyState(VK_CONTROL)&0x8000) - { - cheekySearchId = GenerateCookie(0); - cheekySearchUin = dwUin; - cheekySearchUid = null_strdup(pszUIN); - ForkThread(&CIcqProto::CheekySearchThread, 0); // The caller needs to get this return value before the results - nHandle = cheekySearchId; - } - else if (icqOnline()) - { - nHandle = SearchByUin(dwUin); - } - - // Success - return (HANDLE)nHandle; - } - - // Failure - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchByEmail - searches the contact by its e-mail - -HANDLE __cdecl CIcqProto::SearchByEmail( const PROTOCHAR *email ) -{ - if (email && icqOnline() && strlennull(email) > 0) - { - DWORD dwSearchId, dwSecId; - char *szEmail = tchar_to_ansi(email); - - // Success - dwSearchId = SearchByMail(szEmail); - if (m_bAimEnabled) - dwSecId = icq_searchAimByEmail(szEmail, dwSearchId); - else - dwSecId = 0; - - SAFE_FREE(&szEmail); - - if (dwSearchId) - return ( HANDLE )dwSearchId; - else - return ( HANDLE )dwSecId; - } - - return 0; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SearchByName - searches the contact by its first or last name, or by a nickname - -HANDLE __cdecl CIcqProto::SearchByName(const PROTOCHAR *nick, const PROTOCHAR *firstName, const PROTOCHAR *lastName) -{ - if (icqOnline()) - { - if (nick || firstName || lastName) - { - char *nickUtf = tchar_to_utf8(nick); - char *firstNameUtf = tchar_to_utf8(firstName); - char *lastNameUtf = tchar_to_utf8(lastName); - - // Success - HANDLE dwCookie = (HANDLE)SearchByNames(nickUtf, firstNameUtf, lastNameUtf, 0); - - SAFE_FREE(&nickUtf); - SAFE_FREE(&firstNameUtf); - SAFE_FREE(&lastNameUtf); - - return dwCookie; - } - } - - return 0; // Failure -} - - -HWND __cdecl CIcqProto::CreateExtendedSearchUI( HWND parent ) -{ - if (parent && hInst) - return CreateDialog(hInst, MAKEINTRESOURCE(IDD_ICQADVANCEDSEARCH), parent, AdvancedSearchDlgProc); - - return NULL; // Failure -} - -HWND __cdecl CIcqProto::SearchAdvanced( HWND hwndDlg ) -{ - if (icqOnline() && IsWindow(hwndDlg)) - { - int nDataLen; - BYTE* bySearchData; - - if (bySearchData = createAdvancedSearchStructure(hwndDlg, &nDataLen)) - { - int result = icq_sendAdvancedSearchServ(bySearchData, nDataLen); - SAFE_FREE((void**)&bySearchData); - return ( HWND )result; // Success - } - } - - return NULL; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvContacts - -int __cdecl CIcqProto::RecvContacts( HANDLE hContact, PROTORECVEVENT* pre ) -{ - ICQSEARCHRESULT **isrList = (ICQSEARCHRESULT**)pre->szMessage; - int i; - DWORD cbBlob = 0; - DWORD flags = 0; - - if (pre->flags & PREF_UTF || pre->flags & PREF_UNICODE) - flags |= DBEF_UTF; - - for (i = 0; i < pre->lParam; i++) - { - if (pre->flags & PREF_UNICODE) - cbBlob += get_utf8_size((WCHAR*)isrList[i]->hdr.nick) + 2; - else - cbBlob += strlennull((char*)isrList[i]->hdr.nick) + 2; // both trailing zeros - if (isrList[i]->uin) - cbBlob += getUINLen(isrList[i]->uin); - else if (pre->flags & PREF_UNICODE) - cbBlob += strlennull((WCHAR*)isrList[i]->hdr.id); - else - cbBlob += strlennull((char*)isrList[i]->hdr.id); - } - PBYTE pBlob = (PBYTE)_alloca(cbBlob), pCurBlob; - for (i = 0, pCurBlob = pBlob; i < pre->lParam; i++) - { - if (pre->flags & PREF_UNICODE) - make_utf8_string_static((WCHAR*)isrList[i]->hdr.nick, (char*)pCurBlob, cbBlob - (pCurBlob - pBlob)); - else - strcpy((char*)pCurBlob, (char*)isrList[i]->hdr.nick); - pCurBlob += strlennull((char*)pCurBlob) + 1; - if (isrList[i]->uin) - { - char szUin[UINMAXLEN]; - _itoa(isrList[i]->uin, szUin, 10); - strcpy((char*)pCurBlob, szUin); - } - else - { // aim contact - if (pre->flags & PREF_UNICODE) - unicode_to_ansi_static((WCHAR*)isrList[i]->hdr.id, (char*)pCurBlob, cbBlob - (pCurBlob - pBlob)); - else - strcpy((char*)pCurBlob, (char*)isrList[i]->hdr.id); - } - pCurBlob += strlennull((char*)pCurBlob) + 1; - } - - ICQAddRecvEvent(hContact, EVENTTYPE_CONTACTS, pre, cbBlob, pBlob, flags); - return 0; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvFile - -int __cdecl CIcqProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) -{ - return Proto_RecvFile(hContact, evt); -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvMsg - -int __cdecl CIcqProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* pre ) -{ - DWORD cbBlob; - DWORD flags = 0; - - cbBlob = strlennull(pre->szMessage) + 1; - // process utf-8 encoded messages - if ((pre->flags & PREF_UTF) && !IsUSASCII(pre->szMessage, strlennull(pre->szMessage))) - flags |= DBEF_UTF; - // process unicode ucs-2 messages - if ((pre->flags & PREF_UNICODE) && !IsUnicodeAscii((WCHAR*)(pre->szMessage+cbBlob), strlennull((WCHAR*)(pre->szMessage+cbBlob)))) - cbBlob *= (sizeof(WCHAR)+1); - - ICQAddRecvEvent(hContact, EVENTTYPE_MESSAGE, pre, cbBlob, (PBYTE)pre->szMessage, flags); - - // stop contact from typing - some clients do not sent stop notify - if (CheckContactCapabilities(hContact, CAPF_TYPING)) - CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, PROTOTYPE_CONTACTTYPING_OFF); - - return 0; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvUrl - -int __cdecl CIcqProto::RecvUrl( HANDLE hContact, PROTORECVEVENT* ) -{ - return 1; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// SendContacts - -int __cdecl CIcqProto::SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ) -{ - if (hContact && hContactsList) - { - int i; - DWORD dwUin; - uid_str szUid; - WORD wRecipientStatus; - DWORD dwCookie; - - if (getContactUid(hContact, &dwUin, &szUid)) - { // Invalid contact - return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The receiver has an invalid user ID."); - } - - wRecipientStatus = getContactStatus(hContact); - - // Failures - if (!icqOnline()) - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "You cannot send messages when you are offline."); - } - else if (!hContactsList || (nContacts < 1) || (nContacts > MAX_CONTACTSSEND)) - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #1)"); - } - // OK - else - { - if (CheckContactCapabilities(hContact, CAPF_CONTACTS) && wRecipientStatus != ID_STATUS_OFFLINE) - { // Use the new format if possible - int nDataLen, nNamesLen; - struct icq_contactsend_s* contacts = NULL; - - // Format the data part and the names part - // This is kinda messy, but there is no simple way to do it. First - // we need to calculate the length of the packet. - contacts = (struct icq_contactsend_s*)_alloca(sizeof(struct icq_contactsend_s)*nContacts); - ZeroMemory(contacts, sizeof(struct icq_contactsend_s)*nContacts); - { - nDataLen = 0; nNamesLen = 0; - for (i = 0; i < nContacts; i++) - { - uid_str szContactUid; - - if (!IsICQContact(hContactsList[i])) - break; // Abort if a non icq contact is found - if (getContactUid(hContactsList[i], &contacts[i].uin, &szContactUid)) - break; // Abort if invalid contact - contacts[i].uid = contacts[i].uin?NULL:null_strdup(szContactUid); - contacts[i].szNick = NickFromHandleUtf(hContactsList[i]); - nDataLen += getUIDLen(contacts[i].uin, contacts[i].uid) + 4; - nNamesLen += strlennull(contacts[i].szNick) + 8; - } - - if (i == nContacts) - { - icq_packet mData, mNames; - -#ifdef _DEBUG - NetLog_Server("Sending contacts to %s.", strUID(dwUin, szUid)); -#endif - // Do not calculate the exact size of the data packet - only the maximal size (easier) - // Sumarize size of group information - // - we do not utilize the full power of the protocol and send all contacts with group "General" - // just like ICQ6 does - nDataLen += 9; - nNamesLen += 9; - - // Create data structures - mData.wPlace = 0; - mData.pData = (LPBYTE)SAFE_MALLOC(nDataLen); - mData.wLen = nDataLen; - mNames.wPlace = 0; - mNames.pData = (LPBYTE)SAFE_MALLOC(nNamesLen); - - // pack Group Name - packWord(&mData, 7); - packBuffer(&mData, (LPBYTE)"General", 7); - packWord(&mNames, 7); - packBuffer(&mNames, (LPBYTE)"General", 7); - - // all contacts in one group - packWord(&mData, (WORD)nContacts); - packWord(&mNames, (WORD)nContacts); - for (i = 0; i < nContacts; i++) - { - uid_str szContactUid; - WORD wLen; - - if (contacts[i].uin) - strUID(contacts[i].uin, szContactUid); - else - strcpy(szContactUid, contacts[i].uid); - - // prepare UID - wLen = strlennull(szContactUid); - packWord(&mData, wLen); - packBuffer(&mData, (LPBYTE)szContactUid, wLen); - - // prepare Nick - wLen = strlennull(contacts[i].szNick); - packWord(&mNames, (WORD)(wLen + 4)); - packTLV(&mNames, 0x01, wLen, (LPBYTE)contacts[i].szNick); - } - - // Cleanup temporary list - for(i = 0; i < nContacts; i++) - { - SAFE_FREE(&contacts[i].szNick); - SAFE_FREE(&contacts[i].uid); - } - - // Rate check - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) - { // rate is too high, the message will not go thru... - SAFE_FREE((void**)&mData.pData); - SAFE_FREE((void**)&mNames.pData); - - return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The message could not be delivered. You are sending too fast. Wait a while and try again."); - } - - // Set up the ack type - cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_CONTACTS, hContact, dwUin, FALSE); - - // AIM clients do not send acknowledgement - if (!dwUin && pCookieData->nAckType == ACKTYPE_CLIENT) - pCookieData->nAckType = ACKTYPE_SERVER; - // Send the message - dwCookie = icq_SendChannel2Contacts(dwUin, szUid, hContact, (char*)mData.pData, mData.wPlace, (char*)mNames.pData, mNames.wPlace, pCookieData); - - // This will stop the message dialog from waiting for the real message delivery ack - if (pCookieData->nAckType == ACKTYPE_NONE) - { - SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_CONTACTS, NULL); - // We need to free this here since we will never see the real ack - // The actual cookie value will still have to be returned to the message dialog though - ReleaseCookie(dwCookie); - } - // Release our buffers - SAFE_FREE((void**)&mData.pData); - SAFE_FREE((void**)&mNames.pData); - } - else - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #2)"); - } - - for(i = 0; i < nContacts; i++) - { - SAFE_FREE(&contacts[i].szNick); - SAFE_FREE(&contacts[i].uid); - } - } - } - else if (dwUin) - { // old format is only understood by ICQ clients - int nBodyLength; - char szContactUin[UINMAXLEN]; - char szCount[17]; - struct icq_contactsend_s* contacts = NULL; - uid_str szContactUid; - - - // Format the body - // This is kinda messy, but there is no simple way to do it. First - // we need to calculate the length of the packet. - contacts = (struct icq_contactsend_s*)_alloca(sizeof(struct icq_contactsend_s)*nContacts); - ZeroMemory(contacts, sizeof(struct icq_contactsend_s)*nContacts); - { - nBodyLength = 0; - for (i = 0; i < nContacts; i++) - { - if (!IsICQContact(hContactsList[i])) - break; // Abort if a non icq contact is found - if (getContactUid(hContactsList[i], &contacts[i].uin, &szContactUid)) - break; // Abort if invalid contact - contacts[i].uid = contacts[i].uin?NULL:null_strdup(szContactUid); - contacts[i].szNick = NickFromHandle(hContactsList[i]); - // Compute this contact's length - nBodyLength += getUIDLen(contacts[i].uin, contacts[i].uid) + 1; - nBodyLength += strlennull(contacts[i].szNick) + 1; - } - - if (i == nContacts) - { - char* pBody; - char* pBuffer; - -#ifdef _DEBUG - NetLog_Server("Sending contacts to %d.", dwUin); -#endif - // Compute count record's length - _itoa(nContacts, szCount, 10); - nBodyLength += strlennull(szCount) + 1; - - // Finally we need to copy the contact data into the packet body - pBuffer = pBody = (char *)SAFE_MALLOC(nBodyLength); - null_strcpy(pBuffer, szCount, nBodyLength - 1); - pBuffer += strlennull(pBuffer); - *pBuffer++ = (char)0xFE; - for (i = 0; i < nContacts; i++) - { - if (contacts[i].uin) - { - _itoa(contacts[i].uin, szContactUin, 10); - strcpy(pBuffer, szContactUin); - } - else - strcpy(pBuffer, contacts[i].uid); - pBuffer += strlennull(pBuffer); - *pBuffer++ = (char)0xFE; - strcpy(pBuffer, contacts[i].szNick); - pBuffer += strlennull(pBuffer); - *pBuffer++ = (char)0xFE; - } - - for (i = 0; i < nContacts; i++) - { // release memory - SAFE_FREE(&contacts[i].szNick); - SAFE_FREE(&contacts[i].uid); - } - - // Set up the ack type - cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_CONTACTS, hContact, dwUin, TRUE); - - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { - int iRes = icq_SendDirectMessage(hContact, pBody, nBodyLength, 1, pCookieData, NULL); - - if (iRes) - { - SAFE_FREE((void**)&pBody); - - return iRes; // we succeded, return - } - } - - // Rate check - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) - { // rate is too high, the message will not go thru... - SAFE_FREE((void**)&pCookieData); - SAFE_FREE((void**)&pBody); - - return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The message could not be delivered. You are sending too fast. Wait a while and try again."); - } - // Select channel and send -/* - if (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || wRecipientStatus == ID_STATUS_OFFLINE) - { - dwCookie = icq_SendChannel4Message(dwUin, hContact, MTYPE_CONTACTS, (WORD)nBodyLength, pBody, pCookieData); - } - else -*/ - { - WORD wPriority; - - if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) - wPriority = 0x0001; - else - wPriority = 0x0021; - - dwCookie = icq_SendChannel2Message(dwUin, hContact, pBody, nBodyLength, wPriority, pCookieData, NULL); - } - - // This will stop the message dialog from waiting for the real message delivery ack - if (pCookieData->nAckType == ACKTYPE_NONE) - { - SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_CONTACTS, NULL); - // We need to free this here since we will never see the real ack - // The actual cookie value will still have to be returned to the message dialog though - ReleaseCookie(dwCookie); - } - SAFE_FREE((void**)&pBody); - } - else - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #2)"); - } - } - } - else - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The reciever does not support receiving of contacts."); - } - } - return dwCookie; - } - - // Exit with Failure - return 0; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// SendFile - sends a file - -HANDLE __cdecl CIcqProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) -{ - if ( !icqOnline()) - return 0; - - if (hContact && szDescription && ppszFiles) - { - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 0; // Invalid contact - - if (getContactStatus(hContact) != ID_STATUS_OFFLINE) - { - if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) - return oftInitTransfer(hContact, dwUin, szUid, (LPCTSTR*)ppszFiles, szDescription); - - if (dwUin) - { - WORD wClientVersion = getSettingWord(hContact, "Version", 7); - - if (wClientVersion < 7) - NetLog_Server("IcqSendFile() can't send to version %u", wClientVersion); - else - { - int i; - filetransfer* ft; - struct _stat statbuf; - - // Initialize filetransfer struct - ft = CreateFileTransfer(hContact, dwUin, (wClientVersion == 7) ? 7: 8); - - for (ft->dwFileCount = 0; ppszFiles[ft->dwFileCount]; ft->dwFileCount++); - ft->pszFiles = (char **)SAFE_MALLOC(sizeof(char *) * ft->dwFileCount); - ft->dwTotalSize = 0; - for (i = 0; i < (int)ft->dwFileCount; i++) - { - ft->pszFiles[i] = (ppszFiles[i]) ? tchar_to_utf8(ppszFiles[i]) : NULL; - - if (_tstat(ppszFiles[i], &statbuf)) - NetLog_Server("IcqSendFile() was passed invalid filename(s)"); - else - ft->dwTotalSize += statbuf.st_size; - } - ft->szDescription = tchar_to_utf8(szDescription); - ft->dwTransferSpeed = 100; - ft->sending = 1; - ft->fileId = -1; - ft->iCurrentFile = 0; - ft->dwCookie = AllocateCookie(CKT_FILE, 0, hContact, ft); - ft->hConnection = NULL; - - // Send file transfer request - { - char szFiles[64], tmp[64]; - char *pszFiles; - - - NetLog_Server("Init file send"); - - if (ft->dwFileCount == 1) - { - pszFiles = strchr(ft->pszFiles[0], '\\'); - if (pszFiles) - pszFiles++; - else - pszFiles = ft->pszFiles[0]; - } - else - { - null_snprintf(szFiles, SIZEOF(szFiles), ICQTranslateUtfStatic("%d Files", tmp, SIZEOF(tmp)), ft->dwFileCount); - pszFiles = szFiles; - } - - // Send packet - { - if (ft->nVersion == 7) - { - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { - int iRes = icq_sendFileSendDirectv7(ft, pszFiles); - if (iRes) return ft; // Success - } - NetLog_Server("Sending v%u file transfer request through server", 7); - icq_sendFileSendServv7(ft, pszFiles); - } - else - { - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { - int iRes = icq_sendFileSendDirectv8(ft, pszFiles); - if (iRes) return ft; // Success - } - NetLog_Server("Sending v%u file transfer request through server", 8); - icq_sendFileSendServv8(ft, pszFiles, ACKTYPE_NONE); - } - } - } - - return ft; // Success - } - } - } - } - - return 0; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SendMessage - sends a message - -int __cdecl CIcqProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) -{ - if (hContact && pszSrc) - { - DWORD dwCookie; - char* puszText = NULL; - int bNeedFreeU = 0; - cookie_message_data *pCookieData = NULL; - - // Invalid contact - DWORD dwUin; - uid_str szUID; - if (getContactUid(hContact, &dwUin, &szUID)) - return ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The receiver has an invalid user ID."); - - if (flags & PREF_UNICODE) - { - puszText = make_utf8_string((WCHAR*)(pszSrc + strlennull(pszSrc) + 1)); // get the UTF-16 part - bNeedFreeU = 1; - } - else if (flags & PREF_UTF) - puszText = (char*)pszSrc; - else - { - puszText = (char*)ansi_to_utf8(pszSrc); - bNeedFreeU = 1; - } - - WORD wRecipientStatus = getContactStatus(hContact); - - BOOL plain_ascii = IsUSASCII(puszText, strlennull(puszText)); - - BOOL oldAnsi = plain_ascii || !m_bUtfEnabled || - (!(flags & (PREF_UTF | PREF_UNICODE)) && m_bUtfEnabled == 1) || - !CheckContactCapabilities(hContact, CAPF_UTF) || - !getSettingByte(hContact, "UnicodeSend", 1); - - if (m_bTempVisListEnabled && m_iStatus == ID_STATUS_INVISIBLE) - makeContactTemporaryVisible(hContact); // make us temporarily visible to contact - - // Failure scenarios - if (!icqOnline()) - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "You cannot send messages when you are offline."); - } - else if ((wRecipientStatus == ID_STATUS_OFFLINE) && (strlennull(puszText) > 4096)) - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "Messages to offline contacts must be shorter than 4096 characters."); - } - // Looks OK - else - { -#ifdef _DEBUG - NetLog_Server("Send %smessage - Message cap is %u", puszText ? "unicode " : "", CheckContactCapabilities(hContact, CAPF_SRV_RELAY)); - NetLog_Server("Send %smessage - Contact status is %u", puszText ? "unicode " : "", wRecipientStatus); -#endif - if (dwUin && m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { // send thru direct - char *dc_msg = puszText; - char *dc_cap = plain_ascii ? NULL : CAP_UTF8MSGS; - char *szUserAnsi = NULL; - - if (!plain_ascii && oldAnsi) - { - szUserAnsi = ConvertMsgToUserSpecificAnsi(hContact, puszText); - if (szUserAnsi) - { - dc_msg = szUserAnsi; - dc_cap = NULL; - } - } - - // Set up the ack type - pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, TRUE); - pCookieData->nAckType = ACKTYPE_CLIENT; - dwCookie = icq_SendDirectMessage(hContact, dc_msg, strlennull(dc_msg), 1, pCookieData, dc_cap); - - SAFE_FREE(&szUserAnsi); - if (dwCookie) - { // free the buffers if alloced - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; // we succeded, return - } - // on failure, fallback to send thru server - } - - if (!dwUin || !CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || - wRecipientStatus == ID_STATUS_OFFLINE || wRecipientStatus == ID_STATUS_INVISIBLE || - getSettingByte(hContact, "OnlyServerAcks", getSettingByte(NULL, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS)) || - !getSettingByte(hContact, "SlowSend", getSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND))) - { - /// TODO: add support for RTL & user customizable font - { - char *mng = MangleXml(puszText, strlennull(puszText)); - int len = strlennull(mng); - mng = (char*)SAFE_REALLOC(mng, len + 28); - memmove(mng + 12, mng, len + 1); - memcpy(mng, "", 12); - strcat(mng, ""); - if (bNeedFreeU) SAFE_FREE(&puszText); - puszText = mng; - bNeedFreeU = 1; - } - - WCHAR *pwszText = plain_ascii ? NULL : make_unicode_string(puszText); - if ((plain_ascii ? strlennull(puszText) : strlennull(pwszText) * sizeof(WCHAR)) > MAX_MESSAGESNACSIZE) - { // max length check // TLV(2) is currently limited to 0xA00 bytes in online mode - // only limit to not get disconnected, all other will be handled by error 0x0A - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered, it is too long."); - - // free the buffers if alloced - SAFE_FREE((void**)&pwszText); - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; - } - // Rate check - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) - { // rate is too high, the message will not go thru... - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered. You are sending too fast. Wait a while and try again."); - - // free the buffers if alloced - SAFE_FREE((void**)&pwszText); - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; - } - - pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, FALSE); - - if (plain_ascii) - dwCookie = icq_SendChannel1Message(dwUin, szUID, hContact, puszText, pCookieData); - else - dwCookie = icq_SendChannel1MessageW(dwUin, szUID, hContact, pwszText, pCookieData); - // free the unicode message - SAFE_FREE((void**)&pwszText); - } - else - { - WORD wPriority; - - char *srv_msg = puszText; - char *srv_cap = plain_ascii ? NULL : CAP_UTF8MSGS; - char *szUserAnsi = NULL; - - if (!plain_ascii && oldAnsi) - { - szUserAnsi = ConvertMsgToUserSpecificAnsi(hContact, puszText); - if (szUserAnsi) - { - srv_msg = szUserAnsi; - srv_cap = NULL; - } - } - - if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) - wPriority = 0x0001; - else - wPriority = 0x0021; - - if (strlennull(srv_msg) + (!oldAnsi ? 144 : 102) > MAX_MESSAGESNACSIZE) - { // max length check - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered, it is too long."); - - SAFE_FREE(&szUserAnsi); - // free the buffers if alloced - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; - } - // Rate check - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) - { // rate is too high, the message will not go thru... - dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered. You are sending too fast. Wait a while and try again."); - - SAFE_FREE(&szUserAnsi); - // free the buffers if alloced - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; - } - - pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, TRUE); - dwCookie = icq_SendChannel2Message(dwUin, hContact, srv_msg, strlennull(srv_msg), wPriority, pCookieData, srv_cap); - SAFE_FREE(&szUserAnsi); - } - - // This will stop the message dialog from waiting for the real message delivery ack - if (pCookieData && pCookieData->nAckType == ACKTYPE_NONE) - { - SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_MESSAGE, NULL); - // We need to free this here since we will never see the real ack - // The actual cookie value will still have to be returned to the message dialog though - ReleaseCookie(dwCookie); - } - } - // free the buffers if alloced - if (bNeedFreeU) SAFE_FREE(&puszText); - - return dwCookie; // Success - } - - return 0; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// SendUrl - -int __cdecl CIcqProto::SendUrl( HANDLE hContact, int flags, const char* url ) -{ - if (hContact && url) - { - DWORD dwCookie; - WORD wRecipientStatus; - DWORD dwUin; - - if (getContactUid(hContact, &dwUin, NULL)) - { // Invalid contact - return ReportGenericSendError(hContact, ACKTYPE_URL, "The receiver has an invalid user ID."); - } - - wRecipientStatus = getContactStatus(hContact); - - // Failure - if (!icqOnline()) - { - dwCookie = ReportGenericSendError(hContact, ACKTYPE_URL, "You cannot send messages when you are offline."); - } - // Looks OK - else - { - char* szDesc; - char* szBody; - int nBodyLen; - int nDescLen; - int nUrlLen; - - - // Set up the ack type - cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_URL, hContact, dwUin, TRUE); - - // Format the body - nUrlLen = strlennull(url); - szDesc = (char *)url + nUrlLen + 1; - nDescLen = strlennull(szDesc); - nBodyLen = nUrlLen + nDescLen + 2; - szBody = (char *)_alloca(nBodyLen); - strcpy(szBody, szDesc); - szBody[nDescLen] = (char)0xFE; // Separator - strcpy(szBody + nDescLen + 1, url); - - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { - int iRes = icq_SendDirectMessage(hContact, szBody, nBodyLen, 1, pCookieData, NULL); - if (iRes) return iRes; // we succeded, return - } - - // Rate check - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) - { // rate is too high, the message will not go thru... - SAFE_FREE((void**)&pCookieData); - - return ReportGenericSendError(hContact, ACKTYPE_URL, "The message could not be delivered. You are sending too fast. Wait a while and try again."); - } - // Select channel and send -/* - if (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || - wRecipientStatus == ID_STATUS_OFFLINE) - { - dwCookie = icq_SendChannel4Message(dwUin, hContact, MTYPE_URL, - (WORD)nBodyLen, szBody, pCookieData); - } - else -*/ - { - WORD wPriority; - - if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) - wPriority = 0x0001; - else - wPriority = 0x0021; - - dwCookie = icq_SendChannel2Message(dwUin, hContact, szBody, nBodyLen, wPriority, pCookieData, NULL); - } - - // This will stop the message dialog from waiting for the real message delivery ack - if (pCookieData->nAckType == ACKTYPE_NONE) - { - SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_URL, NULL); - // We need to free this here since we will never see the real ack - // The actual cookie value will still have to be returned to the message dialog though - ReleaseCookie(dwCookie); - } - } - - return dwCookie; // Success - } - - return 0; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetApparentMode - sets the visibility status - -int __cdecl CIcqProto::SetApparentMode( HANDLE hContact, int mode ) -{ - DWORD uin; - uid_str uid; - - if (getContactUid(hContact, &uin, &uid)) - return 1; // Invalid contact - - if (hContact) - { - // Only 3 modes are supported - if (mode == 0 || mode == ID_STATUS_ONLINE || mode == ID_STATUS_OFFLINE) - { - int oldMode = getSettingWord(hContact, "ApparentMode", 0); - - // Don't send redundant updates - if (mode != oldMode) - { - setSettingWord(hContact, "ApparentMode", (WORD)mode); - - // Not being online is only an error when in SS mode. This is not handled - // yet so we just ignore this for now. - if (icqOnline()) - { - if (oldMode != 0) - { // Remove from old list - if (oldMode == ID_STATUS_OFFLINE && getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) - { // Need to remove Ignore item as well - icq_removeServerPrivacyItem(hContact, uin, uid, getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0), SSI_ITEM_IGNORE); - - setSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0); - } - icq_sendChangeVisInvis(hContact, uin, uid, oldMode==ID_STATUS_OFFLINE, 0); - } - if (mode != 0) - { // Add to new list - if (mode==ID_STATUS_OFFLINE && getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) - return 0; // Success: offline by ignore item - - icq_sendChangeVisInvis(hContact, uin, uid, mode==ID_STATUS_OFFLINE, 1); - } - } - - return 0; // Success - } - } - } - - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PrepareStatusNote - returns correct status note for given status - -char* CIcqProto::PrepareStatusNote(int nStatus) -{ - char *szStatusNote = NULL; - BYTE bXStatus = getContactXStatus(NULL); - - // use custom status message as status note - if (bXStatus) - szStatusNote = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); - - if (!szStatusNote || !szStatusNote[0]) - { // get standard status message (no custom status defined) - icq_lock l(m_modeMsgsMutex); - - char **pszStatusNote = MirandaStatusToAwayMsg(nStatus); - if (pszStatusNote) - szStatusNote = null_strdup(*pszStatusNote); - } - - if (!szStatusNote) - // nothing available set empty status note - szStatusNote = null_strdup(""); - - return szStatusNote; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetStatus - sets the protocol status - -int __cdecl CIcqProto::SetStatus(int iNewStatus) -{ - int nNewStatus = MirandaStatusToSupported(iNewStatus); - - // check if netlib handles are ready - if (!m_hServerNetlibUser) - return 0; - - if (m_bTempVisListEnabled && icqOnline()) // remove temporary visible users - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_REMOVETEMPVISIBLE, BUL_TEMPVISIBLE); - - if (nNewStatus == m_iStatus) - return 0; - - // clear custom status on status change - if (getSettingByte(NULL, "XStatusReset", DEFAULT_XSTATUS_RESET)) - setXStatusEx(0, 0); - - // New status is OFFLINE - if (nNewStatus == ID_STATUS_OFFLINE) - { // for quick logoff - if (icqOnline()) - { // set offline status note (otherwise the old will remain) - char *szOfflineNote = PrepareStatusNote(nNewStatus); - - // Create unnamed event to wait until the status note change process is completed - m_hNotifyNameInfoEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - - int bNoteChanged = SetStatusNote(szOfflineNote, 0, FALSE); - - SAFE_FREE(&szOfflineNote); - - // Note was changed, wait until the process is over - if (bNoteChanged) - ICQWaitForSingleObject(m_hNotifyNameInfoEvent, 4000, TRUE); - - // Release the event - CloseHandle(m_hNotifyNameInfoEvent); - m_hNotifyNameInfoEvent = NULL; - } - - m_iDesiredStatus = nNewStatus; - - if (hServerConn) - { // Connected, Send disconnect packet - icq_sendCloseConnection(); - - icq_serverDisconnect(FALSE); - - SetCurrentStatus(ID_STATUS_OFFLINE); - - NetLog_Server("Logged off."); - } - } - else - { - switch (m_iStatus) { - - // We are offline and need to connect - case ID_STATUS_OFFLINE: - { - // Update user connection settings - UpdateGlobalSettings(); - - // Read UIN from database - m_dwLocalUIN = getContactUin(NULL); - if (m_dwLocalUIN == 0) - { - SetCurrentStatus(ID_STATUS_OFFLINE); - BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID); - icq_LogMessage(LOG_FATAL, LPGEN("You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again.")); - return 0; - } - - // Set status to 'Connecting' - m_iDesiredStatus = nNewStatus; - SetCurrentStatus(ID_STATUS_CONNECTING); - - // Read password from database - char *pszPwd = GetUserPassword(FALSE); - - if (pszPwd) - icq_login(pszPwd); - else - RequestPassword(); - - break; - } - - // We are connecting... We only need to change the going online status - case ID_STATUS_CONNECTING: - m_iDesiredStatus = nNewStatus; - break; - - // We are already connected so we should just change status - default: - SetCurrentStatus(nNewStatus); - - char *szStatusNote = PrepareStatusNote(nNewStatus); - - //! This is a bit tricky, we do trigger status note change thread and then - // change the status note right away (this spares one packet) - so SetStatusNote() - // will only change User Details Directory - SetStatusNote(szStatusNote, 6000, FALSE); - - if (m_iStatus == ID_STATUS_INVISIBLE) - { - if (m_bSsiEnabled) - updateServVisibilityCode(3); - icq_setstatus(MirandaStatusToIcq(m_iStatus), szStatusNote); - } - else - { - icq_setstatus(MirandaStatusToIcq(m_iStatus), szStatusNote); - if (m_bSsiEnabled) - updateServVisibilityCode(4); - } - SAFE_FREE(&szStatusNote); - - if (m_bAimEnabled) - { - icq_lock l(m_modeMsgsMutex); - - char ** pszStatusNote = MirandaStatusToAwayMsg(m_iStatus); - - if (pszStatusNote) - icq_sendSetAimAwayMsgServ(*pszStatusNote); - else // clear the away message - icq_sendSetAimAwayMsgServ(NULL); - } - } - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetAwayMsgThread - return a contact's status message - -struct status_message_thread_data -{ - HANDLE hContact; - char *szMessage; - HANDLE hProcess; -}; - -void __cdecl CIcqProto::GetAwayMsgThread( void *pStatusData ) -{ - status_message_thread_data *pThreadData = (status_message_thread_data*)pStatusData; - if (pThreadData) { - // wait a little - Sleep(100); - - setStatusMsgVar(pThreadData->hContact, pThreadData->szMessage, false); - - TCHAR *tszMsg = mir_utf8decodeT(pThreadData->szMessage); - BroadcastAck(pThreadData->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, pThreadData->hProcess, (LPARAM)tszMsg); - mir_free(tszMsg); - - SAFE_FREE(&pThreadData->szMessage); - SAFE_FREE((void**)&pThreadData); - } -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_GetAwayMsg - returns a contact's away message - -HANDLE __cdecl CIcqProto::GetAwayMsg( HANDLE hContact ) -{ - DWORD dwUin; - uid_str szUID; - - if (getContactUid(hContact, &dwUin, &szUID)) - return 0; // Invalid contact - - if (!dwUin || !CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) - { // No individual status messages, check if the contact has Status Note, if yes give it - char *szStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, NULL); - - if (strlennull(szStatusNote) > 0) - { // Give Status Note - status_message_thread_data *pThreadData = (status_message_thread_data*)SAFE_MALLOC(sizeof(status_message_thread_data)); - - pThreadData->hContact = hContact; - pThreadData->szMessage = szStatusNote; - pThreadData->hProcess = (HANDLE)GenerateCookie(0); - ForkThread(&CIcqProto::GetAwayMsgThread, pThreadData); - - return pThreadData->hProcess; - } - SAFE_FREE(&szStatusNote); - } - - if (!icqOnline()) - return 0; - - WORD wStatus = getContactStatus(hContact); - - if (dwUin) - { - int wMessageType = 0; - - switch(wStatus) - { - case ID_STATUS_ONLINE: - if (CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) - wMessageType = MTYPE_AUTOONLINE; - break; - - case ID_STATUS_AWAY: - wMessageType = MTYPE_AUTOAWAY; - break; - - case ID_STATUS_NA: - wMessageType = MTYPE_AUTONA; - break; - - case ID_STATUS_OCCUPIED: - wMessageType = MTYPE_AUTOBUSY; - break; - - case ID_STATUS_DND: - wMessageType = MTYPE_AUTODND; - break; - - case ID_STATUS_FREECHAT: - wMessageType = MTYPE_AUTOFFC; - break; - - default: - break; - } - - if (wMessageType) - { - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - { - int iRes = icq_sendGetAwayMsgDirect(hContact, wMessageType); - if (iRes) return (HANDLE)iRes; // we succeded, return - } - if (CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) - return (HANDLE)icq_sendGetAwayMsgServExt(hContact, dwUin, szUID, wMessageType, - (WORD)(getSettingWord(hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success - else - return (HANDLE)icq_sendGetAwayMsgServ(hContact, dwUin, wMessageType, - (WORD)(getSettingWord(hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success - } - } - else - { // AIM contact - if (wStatus == ID_STATUS_AWAY) - return (HANDLE)icq_sendGetAimAwayMsgServ(hContact, szUID, MTYPE_AUTOAWAY); - } - - return 0; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AWAYMSG - processes received status mode message - -int __cdecl CIcqProto::RecvAwayMsg( HANDLE hContact, int statusMode, PROTORECVEVENT* evt ) -{ - if (evt->flags & PREF_UTF) { - setStatusMsgVar(hContact, evt->szMessage, false); - - TCHAR* pszMsg = mir_utf8decodeT(evt->szMessage); - BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)pszMsg); - mir_free(pszMsg); - } - else { - setStatusMsgVar(hContact, evt->szMessage, true); - BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)(TCHAR*)_A2T(evt->szMessage)); - } - return 0; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AWAYMSG - send status mode message (individual mode) - -int __cdecl CIcqProto::SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ) -{ - return 1; -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetAwayMsg - sets the away status message - -int __cdecl CIcqProto::SetAwayMsg(int status, const TCHAR* msg) -{ - icq_lock l(m_modeMsgsMutex); - - char **ppszMsg = MirandaStatusToAwayMsg(MirandaStatusToSupported(status)); - if (!ppszMsg) - return 1; // Failure - - // Prepare UTF-8 status message - char *szNewUtf = tchar_to_utf8(msg); - - if (strcmpnull(szNewUtf, *ppszMsg)) - { - // Free old message - SAFE_FREE(ppszMsg); - - // Set new message - *ppszMsg = szNewUtf; - szNewUtf = NULL; - - if ((m_iStatus == status) && icqOnline()) - { // update current status note - char *szNote = *ppszMsg ? *ppszMsg : ""; - - BYTE bXStatus = getContactXStatus(NULL); - if (!bXStatus) - SetStatusNote(szNote, 1000, FALSE); - - if (m_bAimEnabled) - icq_sendSetAimAwayMsgServ(*ppszMsg); - } - } - SAFE_FREE(&szNewUtf); - - return 0; // Success -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// GetMyAwayMsg - obtain the current away message - -INT_PTR CIcqProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam) -{ - icq_lock l(m_modeMsgsMutex); - - char **ppszMsg = MirandaStatusToAwayMsg(wParam ? wParam : m_iStatus); - - if (!ppszMsg || !*ppszMsg) - return 0; - - int nMsgLen = strlennull(*ppszMsg) + 1; - - if (lParam & SGMA_UNICODE) - { - WCHAR *szMsg = (WCHAR*)_alloca(nMsgLen * sizeof(WCHAR)); - - make_unicode_string_static(*ppszMsg, szMsg, nMsgLen); - return (INT_PTR)mir_wstrdup(szMsg); - } - else - { // convert to ansi - char *szMsg = (char*)_alloca(nMsgLen); - - if (utf8_decode_static(*ppszMsg, szMsg, nMsgLen)) - return (INT_PTR)mir_strdup(szMsg); - } - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// PS_UserIsTyping - sends a UTN notification - -int __cdecl CIcqProto::UserIsTyping( HANDLE hContact, int type ) -{ - if (hContact && icqOnline()) - { - if (CheckContactCapabilities(hContact, CAPF_TYPING)) - { - switch (type) { - case PROTOTYPE_SELFTYPING_ON: - sendTypingNotification(hContact, MTN_BEGUN); - return 0; - - case PROTOTYPE_SELFTYPING_OFF: - sendTypingNotification(hContact, MTN_FINISHED); - return 0; - } - } - } - - return 1; -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// OnEvent - maintain protocol events - -int __cdecl CIcqProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) -{ - switch( eventType ) { - case EV_PROTO_ONLOAD: - return OnModulesLoaded(0, 0); - - case EV_PROTO_ONEXIT: - return OnPreShutdown(0, 0); - - case EV_PROTO_ONOPTIONS: - return OnOptionsInit(wParam, lParam); - - case EV_PROTO_ONERASE: - { - char szDbSetting[MAX_PATH]; - - null_snprintf(szDbSetting, sizeof(szDbSetting), "%sP2P", m_szModuleName); - CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); - null_snprintf(szDbSetting, sizeof(szDbSetting), "%sSrvGroups", m_szModuleName); - CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); - null_snprintf(szDbSetting, sizeof(szDbSetting), "%sGroups", m_szModuleName); - CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); - break; - } - - case EV_PROTO_ONCONTACTDELETED: - return ServListDbContactDeleted(wParam, lParam); - - case EV_PROTO_DBSETTINGSCHANGED: - return ServListDbSettingChanged(wParam, lParam); - } - return 1; -} diff --git a/protocols/IcqOscarJ/icq_proto.h b/protocols/IcqOscarJ/icq_proto.h deleted file mode 100755 index aa903689ad..0000000000 --- a/protocols/IcqOscarJ/icq_proto.h +++ /dev/null @@ -1,984 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, George Hazan -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Protocol Interface declarations -// -// ----------------------------------------------------------------------------- -#ifndef _ICQ_PROTO_H_ -#define _ICQ_PROTO_H_ - -#include "m_system_cpp.h" -#include "m_protoint.h" - -#define LISTSIZE 100 - -#define XSTATUS_COUNT 86 - -struct CIcqProto; -typedef void ( __cdecl CIcqProto::*IcqThreadFunc )( void* ); -typedef int ( __cdecl CIcqProto::*IcqEventFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CIcqProto::*IcqServiceFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CIcqProto::*IcqServiceFuncParam )( WPARAM, LPARAM, LPARAM ); - -// for InfoUpdate -struct userinfo -{ - DWORD dwUin; - HANDLE hContact; - time_t queued; -}; - -struct CIcqProto : public PROTO_INTERFACE, public MZeroedObject -{ - CIcqProto( const char*, const TCHAR* ); - ~CIcqProto(); - - //==================================================================================== - // PROTO_INTERFACE - //==================================================================================== - - virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); - virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); - - virtual int __cdecl Authorize( HANDLE hContact ); - virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); - virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); - - virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); - - virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); - virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); - virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); - virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); - - virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); - virtual HICON __cdecl GetIcon( int iconIndex ); - virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); - - virtual HANDLE __cdecl SearchBasic( const PROTOCHAR *id ); - virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR *email ); - virtual HANDLE __cdecl SearchByName(const PROTOCHAR *nick, const PROTOCHAR *firstName, const PROTOCHAR *lastName); - virtual HWND __cdecl SearchAdvanced( HWND owner ); - virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); - - virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); - virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); - - virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); - virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); - virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); - virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); - - virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); - virtual int __cdecl SetStatus( int iNewStatus ); - - virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); - virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); - virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); - virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); - - virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); - - virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); - - //====| Services |==================================================================== - INT_PTR __cdecl AddServerContact(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetInfoSetting(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl ChangeInfoEx(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetAvatarCaps(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetAvatarInfo(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetMyAvatar(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetMyAwayMsg(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetXStatus(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetXStatusEx(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetXStatusIcon(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GrantAuthorization(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl menuXStatus(WPARAM wParam,LPARAM lParam,LPARAM fParam); - INT_PTR __cdecl OpenWebProfile(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl RequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl RequestAuthorization(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl RequestXStatusDetails(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl RevokeAuthorization(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SendSms(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SendYouWereAdded(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SetMyAvatar(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SetNickName(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SetPassword(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SetXStatus(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl SetXStatusEx(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl ShowXStatusDetails(WPARAM wParam, LPARAM lParam); - - INT_PTR __cdecl OnCreateAccMgrUI(WPARAM, LPARAM); - - //====| Events |====================================================================== - void __cdecl OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - int __cdecl OnIdleChanged( WPARAM, LPARAM ); - int __cdecl OnModernOptInit( WPARAM, LPARAM ); - int __cdecl OnModulesLoaded( WPARAM, LPARAM ); - int __cdecl OnOptionsInit( WPARAM, LPARAM ); - int __cdecl OnPreShutdown( WPARAM, LPARAM ); - int __cdecl OnPreBuildContactMenu( WPARAM, LPARAM ); - int __cdecl OnMsgUserTyping( WPARAM, LPARAM ); - int __cdecl OnProcessSrmmIconClick( WPARAM, LPARAM ); - int __cdecl OnProcessSrmmEvent( WPARAM, LPARAM ); - int __cdecl OnReloadIcons( WPARAM, LPARAM ); - void __cdecl OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - void __cdecl OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - int __cdecl OnUserInfoInit( WPARAM, LPARAM ); - - int __cdecl CListMW_ExtraIconsRebuild( WPARAM, LPARAM ); - int __cdecl CListMW_ExtraIconsApply( WPARAM, LPARAM ); - int __cdecl OnPreBuildStatusMenu( WPARAM, LPARAM ); - - //====| Data |======================================================================== - IcqIconHandle m_hIconProtocol; - HANDLE m_hServerNetlibUser, m_hDirectNetlibUser; - HANDLE hxstatuschanged, hxstatusiconchanged; - - BYTE m_bGatewayMode; - BYTE m_bSecureLogin; - BYTE m_bSecureConnection; - BYTE m_bAimEnabled; - BYTE m_bUtfEnabled; - WORD m_wAnsiCodepage; - BYTE m_bDCMsgEnabled; - BYTE m_bTempVisListEnabled; - BYTE m_bSsiEnabled; - BYTE m_bSsiSimpleGroups; - BYTE m_bAvatarsEnabled; - BYTE m_bXStatusEnabled; - BYTE m_bMoodsEnabled; - - icq_critical_section *localSeqMutex; - icq_critical_section *connectionHandleMutex; - - int m_bIdleAllow; - DWORD m_dwLocalUIN; - BYTE m_bConnectionLost; - - char m_szPassword[PASSWORDMAXLEN]; - BYTE m_bRememberPwd; - - int cheekySearchId; - DWORD cheekySearchUin; - char* cheekySearchUid; - - /******************************************************************* - * Function declarations - *******************************************************************/ - - //----| capabilities.cpp |------------------------------------------------------------ - // Deletes all oscar capabilities for a given contact. - void ClearAllContactCapabilities(HANDLE hContact); - - // Deletes one or many oscar capabilities for a given contact. - void ClearContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); - - // Sets one or many oscar capabilities for a given contact. - void SetContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); - - // Returns true if the given contact supports the requested capabilites. - BOOL CheckContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); - - // Scans a binary buffer for oscar capabilities and adds them to the contact. - void AddCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength); - - // Scans a binary buffer for oscar capabilities and sets them to the contact. - void SetCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength, BOOL bReset); - - //----| chan_01login.cpp |------------------------------------------------------------ - void handleLoginChannel(BYTE *buf, WORD datalen, serverthread_info *info); - - //----| chan_02data.cpp |------------------------------------------------------------- - void handleDataChannel(BYTE *buf, WORD wLen, serverthread_info *info); - - void LogFamilyError(WORD wFamily, WORD wError); - - //----| chan_03error.cpp |------------------------------------------------------------ - void handleErrorChannel(unsigned char *buf, WORD datalen); - - //----| chan_04close.cpp |------------------------------------------------------------ - void handleCloseChannel(BYTE *buf, WORD datalen, serverthread_info *info); - void handleLoginReply(BYTE *buf, WORD datalen, serverthread_info *info); - void handleMigration(serverthread_info *info); - void handleSignonError(WORD wError); - - int connectNewServer(serverthread_info *info); - - //----| chan_05ping.cpp |------------------------------------------------------------- - void handlePingChannel(BYTE *buf, WORD wLen); - - void __cdecl KeepAliveThread(void *arg); - - void StartKeepAlive(serverthread_info *info); - void StopKeepAlive(serverthread_info *info); - - //----| cookies.cpp |----------------------------------------------------------------- - icq_critical_section *cookieMutex; // we want this in avatar thread, used as queue lock - LIST cookies; - WORD wCookieSeq; - - DWORD AllocateCookie(BYTE bType, WORD wIdent, HANDLE hContact, void *pvExtra); - void FreeCookie(DWORD dwCookie); - void FreeCookieByData(BYTE bType, void *pvExtra); - void ReleaseCookie(DWORD dwCookie); - DWORD GenerateCookie(WORD wIdent); - - int GetCookieType(DWORD dwCookie); - - int FindCookie(DWORD wCookie, HANDLE *phContact, void **ppvExtra); - int FindCookieByData(void *pvExtra, DWORD *pdwCookie, HANDLE *phContact); - int FindCookieByType(BYTE bType, DWORD *pdwCookie, HANDLE *phContact, void **ppvExtra); - int FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, HANDLE *phContact, cookie_message_data **ppvExtra); - - void InitMessageCookie(cookie_message_data *pCookie); - cookie_message_data* CreateMessageCookie(WORD bMsgType, BYTE bAckType); - cookie_message_data* CreateMessageCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin, int bUseSrvRelay); - - void RemoveExpiredCookies(void); - - //----| directpackets.cpp |----------------------------------------------------------- - void icq_sendDirectMsgAck(directconnect* dc, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, char* szCap); - DWORD icq_sendGetAwayMsgDirect(HANDLE hContact, int type); - void icq_sendAwayMsgReplyDirect(directconnect *dc, WORD wCookie, BYTE msgType, const char** szMsg); - void icq_sendFileAcceptDirect(HANDLE hContact, filetransfer *ft); - void icq_sendFileDenyDirect(HANDLE hContact, filetransfer *ft, const char *szReason); - int icq_sendFileSendDirectv7(filetransfer *ft, const char *pszFiles); - int icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles); - DWORD icq_SendDirectMessage(HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap); - void icq_sendXtrazRequestDirect(HANDLE hContact, DWORD dwCookie, char* szBody, int nBodyLen, WORD wType); - void icq_sendXtrazResponseDirect(HANDLE hContact, WORD wCookie, char* szBody, int nBodyLen, WORD wType); - - //----| fam_01service.cpp |----------------------------------------------------------- - HANDLE m_hNotifyNameInfoEvent; - - void handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); - char* buildUinList(int subtype, WORD wMaxLen, HANDLE *hContactResume); - void sendEntireListServ(WORD wFamily, WORD wSubtype, int listType); - void setUserInfo(void); - void handleServUINSettings(int nPort, serverthread_info *info); - - //----| fam_02location.cpp |---------------------------------------------------------- - void handleLocationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); - void handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie); - - //----| fam_03buddy.cpp |------------------------------------------------------------- - void handleBuddyFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); - void handleReplyBuddy(BYTE *buf, WORD wPackLen); - void handleUserOffline(BYTE *buf, WORD wPackLen); - void handleUserOnline(BYTE *buf, WORD wPackLen, serverthread_info *info); - void parseStatusNote(DWORD dwUin, char *szUid, HANDLE hContact, oscar_tlv_chain *pChain); - void handleNotifyRejected(BYTE *buf, WORD wPackLen); - - //----| fam_04message.cpp |----------------------------------------------------------- - icq_mode_messages m_modeMsgs; - icq_critical_section *m_modeMsgsMutex; - HANDLE m_modeMsgsEvent; - - void handleMsgFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); - - void handleReplyICBM(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleRecvServMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleRecvServMsgType1(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); - void handleRecvServMsgType2(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); - void handleRecvServMsgType4(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); - void handleRecvServMsgError(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleRecvMsgResponse(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleServerAck(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleStatusMsgReply(const char *szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char *szMsg, int nMsgFlags); - void handleTypingNotification(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleMissedMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleOffineMessagesReply(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); - void handleRecvServMsgContacts(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand); - void handleRuntimeError(WORD wError); - - void parseServRelayData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType); - void parseServRelayPluginData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wVersion); - - HANDLE handleMessageAck(DWORD dwUin, char *szUID, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags, int nMsgFlags); - void handleMessageTypes(DWORD dwUin, char *szUID, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, int nMsgFlags, message_ack_params *pAckParams); - void sendMessageTypesAck(HANDLE hContact, int bUnicode, message_ack_params *pArgs); - void sendTypingNotification(HANDLE hContact, WORD wMTNCode); - - int unpackPluginTypeId(BYTE **pBuffer, WORD *pwLen, int *pTypeId, WORD *pFunctionId, BOOL bThruDC); - - char* convertMsgToUserSpecificUtf(HANDLE hContact, const char *szMsg); - - //----| fam_09bos.cpp |--------------------------------------------------------------- - void handleBosFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); - void handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength); - void makeContactTemporaryVisible(HANDLE hContact); - - //----| fam_0alookup.cpp |------------------------------------------------------------ - void handleLookupFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); - - void handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie); - void ReleaseLookupCookie(DWORD dwCookie, cookie_search *pCookie); - - //----| fam_0bstatus.cpp |------------------------------------------------------------ - void handleStatusFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); - - //----| fam_13servclist.cpp |--------------------------------------------------------- - BOOL bIsSyncingCL; - - WORD m_wServerListLimits[0x20]; - WORD m_wServerListGroupMaxContacts; - WORD m_wServerListRecordNameMaxLength; - - void handleServCListFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info); - void handleServerCListRightsReply(BYTE *buf, WORD wLen); - void handleServerCListAck(cookie_servlist_action* sc, WORD wError); - void handleServerCListReply(BYTE *buf, WORD wLen, WORD wFlags, serverthread_info *info); - void handleServerCListItemAdd(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); - void handleServerCListItemUpdate(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); - void handleServerCListItemDelete(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); - void handleRecvAuthRequest(BYTE *buf, WORD wLen); - void handleRecvAuthResponse(BYTE *buf, WORD wLen); - void handleRecvAdded(BYTE *buf, WORD wLen); - - HANDLE HContactFromRecordName(const char *szRecordName, int *bAdded); - - void processCListReply(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); - - void icq_sendServerBeginOperation(int bImport); - void icq_sendServerEndOperation(); - void sendRosterAck(void); - - int getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf); - DWORD updateServerGroupData(WORD wGroupId, void *groupData, int groupSize, DWORD dwOperationFlags); - void updateServAvatarHash(BYTE *pHash, int size); - void updateServVisibilityCode(BYTE bCode); - - //----| fam_15icqserver.cpp |--------------------------------------------------------- - void handleIcqExtensionsFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); - - void handleExtensionError(BYTE *buf, WORD wPackLen); - void handleExtensionServerInfo(BYTE *buf, WORD wPackLen, WORD wFlags); - void handleExtensionMetaResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags); - - int parseUserInfoRecord(HANDLE hContact, oscar_tlv *pData, UserInfoRecordItem pRecordDef[], int nRecordDef, int nMaxRecords); - - void handleDirectoryQueryResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, WORD wFlags); - void handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype); - - void parseDirectoryUserDetailsData(HANDLE hContact, oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType); - void parseDirectorySearchData(oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType); - - void parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode); - void parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode); - - void ReleaseSearchCookie(DWORD dwCookie, cookie_search *pCookie); - - //----| fam_17signon.cpp |------------------------------------------------------------ - void handleAuthorizationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); - void handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info); - - void sendClientAuth(const char *szKey, WORD wKeyLen, BOOL bSecure); - - //----| icq_avatars.cpp |------------------------------------------------------------- - icq_critical_section *m_avatarsMutex; - avatars_request *m_avatarsQueue; - - BOOL m_avatarsConnectionPending; - avatars_server_connection *m_avatarsConnection; - - int bAvatarsFolderInited; - HANDLE hAvatarsFolder; - - void requestAvatarConnection(); - void __cdecl AvatarThread(avatars_server_connection *pInfo); - - void handleAvatarOwnerHash(WORD wItemID, BYTE bFlags, BYTE *pData, BYTE nDataLen); - void handleAvatarContactHash(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *pHash, int nHashLen, WORD wOldStatus); - - void InitAvatars(); - avatars_request *ReleaseAvatarRequestInQueue(avatars_request *request); - - TCHAR* GetOwnAvatarFileName(); - void GetFullAvatarFileName(int dwUin, const char *szUid, int dwFormat, TCHAR *pszDest, int cbLen); - void GetAvatarFileName(int dwUin, const char *szUid, TCHAR *pszDest, int cbLen); - int IsAvatarChanged(HANDLE hContact, const BYTE *pHash, int nHashLen); - - int GetAvatarData(HANDLE hContact, DWORD dwUin, const char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file); - int SetAvatarData(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen); - - void StartAvatarThread(HANDLE hConn, char* cookie, WORD cookieLen); - void StopAvatarThread(); - - //----| icq_clients.cpp |------------------------------------------------------------- - const char* detectUserClient(HANDLE hContact, int nIsICQ, WORD wUserClass, DWORD dwOnlineSince, const char *szCurrentClient, WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, BYTE bDirectFlag, DWORD dwDirectCookie, DWORD dwWebPort, BYTE *caps, WORD wLen, BYTE *bClientId, char *szClientBuf); - - //----| icq_db.cpp |------------------------------------------------------------------ - HANDLE AddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob); - void CreateResidentSetting(const char* szSetting); - HANDLE FindFirstContact(); - HANDLE FindNextContact(HANDLE hContact); - int IsICQContact(HANDLE hContact); - - int getSetting(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); - BYTE getSettingByte(HANDLE hContact, const char *szSetting, BYTE byDef); - WORD getSettingWord(HANDLE hContact, const char *szSetting, WORD wDef); - DWORD getSettingDword(HANDLE hContact, const char *szSetting, DWORD dwDef); - double getSettingDouble(HANDLE hContact, const char *szSetting, double dDef); - int getSettingString(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); - int getSettingStringW(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); - int getSettingStringStatic(HANDLE hContact, const char *szSetting, char *dest, int dest_len); - char* getSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, char *szDef); - char* getSettingStringUtf(HANDLE hContact, const char *szSetting, char *szDef); - int getContactUid(HANDLE hContact, DWORD *pdwUin, uid_str *ppszUid); - DWORD getContactUin(HANDLE hContact); - WORD getContactStatus(HANDLE hContact); - char* getContactCListGroup(HANDLE hContact); - - int deleteSetting(HANDLE hContact, const char *szSetting); - - int setSettingByte(HANDLE hContact, const char *szSetting, BYTE byValue); - int setSettingWord(HANDLE hContact, const char *szSetting, WORD wValue); - int setSettingDword(HANDLE hContact, const char *szSetting, DWORD dwValue); - int setSettingDouble(HANDLE hContact, const char *szSetting, double dValue); - int setSettingString(HANDLE hContact, const char *szSetting, const char *szValue); - int setSettingStringW(HANDLE hContact, const char *szSetting, const WCHAR *wszValue); - int setSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, const char *szValue); - int setSettingStringUtf(HANDLE hContact, const char *szSetting, const char *szValue); - int setSettingBlob(HANDLE hContact, const char *szSetting, const BYTE *pValue, const int cbValue); - int setContactHidden(HANDLE hContact, BYTE bHidden); - void setStatusMsgVar(HANDLE hContact, char* szStatusMsg, bool isAnsi); - - //----| icq_direct.cpp |-------------------------------------------------------------- - icq_critical_section *directConnListMutex; - LIST directConns; - - icq_critical_section *expectedFileRecvMutex; - LIST expectedFileRecvs; - - void __cdecl icq_directThread(struct directthreadstartinfo* dtsi); - - void handleDirectPacket(directconnect* dc, PBYTE buf, WORD wLen); - void sendPeerInit_v78(directconnect* dc); - void sendPeerInitAck(directconnect* dc); - void sendPeerMsgInit(directconnect* dc, DWORD dwSeq); - void sendPeerFileInit(directconnect* dc); - int sendDirectPacket(directconnect* dc, icq_packet* pkt); - - void CloseContactDirectConns(HANDLE hContact); - directconnect* FindFileTransferDC(filetransfer* ft); - filetransfer* FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize); - BOOL IsDirectConnectionOpen(HANDLE hContact, int type, int bPassive); - void OpenDirectConnection(HANDLE hContact, int type, void* pvExtra); - void CloseDirectConnection(directconnect *dc); - int SendDirectMessage(HANDLE hContact, icq_packet *pkt); - - //----| icq_directmsg.cpp |----------------------------------------------------------- - void handleDirectMessage(directconnect* dc, PBYTE buf, WORD wLen); - void handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText); - - //----| icq_filerequests.cpp |-------------------------------------------------------- - filetransfer* CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion); - - void handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText); - void handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC); - void handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText); - - void icq_CancelFileTransfer(HANDLE hContact, filetransfer* ft); - - //----| icq_filetransfer.cpp |-------------------------------------------------------- - void icq_AcceptFileTransfer(HANDLE hContact, filetransfer *ft); - void icq_sendFileResume(filetransfer *ft, int action, const char *szFilename); - void icq_InitFileSend(filetransfer *ft); - - void handleFileTransferPacket(directconnect *dc, PBYTE buf, WORD wLen); - void handleFileTransferIdle(directconnect *dc); - - //----| icq_infoupdate.cpp |---------------------------------------------------------- - icq_critical_section *infoUpdateMutex; - HANDLE hInfoQueueEvent; - int nInfoUserCount; - int bInfoPendingUsers; - BOOL bInfoUpdateEnabled; - BOOL bInfoUpdateRunning; - HANDLE hInfoThread; - DWORD dwInfoActiveRequest; - userinfo m_infoUpdateList[LISTSIZE]; - - void __cdecl InfoUpdateThread(void*); - - void icq_InitInfoUpdate(void); // Queues all outdated users - BOOL icq_QueueUser(HANDLE hContact); // Queue one UIN to the list for updating - void icq_DequeueUser(DWORD dwUin); // Remove one UIN from the list - void icq_RescanInfoUpdate(); // Add all outdated contacts to the list - void icq_InfoUpdateCleanup(void); // Clean up on exit - void icq_EnableUserLookup(BOOL bEnable); // Enable/disable user info lookups - - //----| log.cpp |----------------------------------------------------------------- - BOOL bErrorBoxVisible; - - void __cdecl icq_LogMessageThread(void* arg); - - void icq_LogMessage(int level, const char *szMsg); - void icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg); //szMsg is optional - void icq_LogFatalParam(const char *szMsg, WORD wError); - - //----| icq_packet.cpp |-------------------------------------------------------------- - void ppackLETLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); - void ppackLETLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType); - void ppackLETLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType); - - void ppackTLVStringFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); - void ppackTLVStringUtfFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); - void ppackTLVDateFromDB(PBYTE *buf, int *buflen, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, WORD wType); - - int ppackTLVWordStringItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID); - int ppackTLVWordStringUtfItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID); - - BOOL unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID); - - //----| icq_popups.cpp |-------------------------------------------------------------- - int ShowPopUpMsg(HANDLE hContact, const char *szTitle, const char *szMsg, BYTE bType); - - //----| icq_proto.cpp |-------------------------------------------------------------- - void __cdecl CheekySearchThread( void* ); - - void __cdecl GetAwayMsgThread( void *pStatusData ); - - char* PrepareStatusNote(int nStatus); - - //----| icq_rates.cpp |--------------------------------------------------------------- - icq_critical_section *m_ratesMutex; - rates *m_rates; - - rates_queue *m_ratesQueue_Request; // rate queue for xtraz requests - rates_queue *m_ratesQueue_Response; // rate queue for msg responses - - int handleRateItem(rates_queue_item *item, int nQueueType = RQT_DEFAULT, int nMinDelay = 0, BOOL bAllowDelay = TRUE); - - void __cdecl rateDelayThread(struct rate_delay_args *pArgs); - - //----| icq_server.cpp |-------------------------------------------------------------- - HANDLE hServerConn; - WORD wListenPort; - WORD wLocalSequence; - UINT serverThreadId; - HANDLE serverThreadHandle; - - __inline bool icqOnline() const - { return (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING); - } - - void __cdecl SendPacketAsyncThread(icq_packet* pArgs); - void __cdecl ServerThread(serverthread_start_info *infoParam); - - void icq_serverDisconnect(BOOL bBlock); - void icq_login(const char* szPassword); - - int handleServerPackets(BYTE *buf, int len, serverthread_info *info); - void sendServPacket(icq_packet *pPacket); - void sendServPacketAsync(icq_packet *pPacket); - - int IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel); - - //----| icq_servlist.cpp |------------------------------------------------------------ - HANDLE hHookSettingChanged; - HANDLE hHookContactDeleted; - HANDLE hHookCListGroupChange; - icq_critical_section *servlistMutex; - - DWORD* pdwServerIDList; - int nServerIDListCount; - int nServerIDListSize; - - // server-list update board - icq_critical_section *servlistQueueMutex; - int servlistQueueCount; - int servlistQueueSize; - ssiqueueditems **servlistQueueList; - int servlistQueueState; - HANDLE servlistQueueThreadHandle; - int servlistEditCount; - - void servlistBeginOperation(int operationCount, int bImport); - void servlistEndOperation(int operationCount); - - void __cdecl servlistQueueThread(void* queueState); - - void servlistQueueAddGroupItem(servlistgroupitem* pGroupItem, int dwTimeout); - int servlistHandlePrimitives(DWORD dwOperation); - void servlistProcessLogin(); - - void servlistPostPacket(icq_packet* packet, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout); - void servlistPostPacketDouble(icq_packet* packet1, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout, icq_packet* packet2, WORD wAction2); - - // server-list pending queue - int servlistPendingCount; - int servlistPendingSize; - servlistpendingitem** servlistPendingList; - - int servlistPendingFindItem(int nType, HANDLE hContact, const char *pszGroup); - void servlistPendingAddItem(servlistpendingitem* pItem); - servlistpendingitem* servlistPendingRemoveItem(int nType, HANDLE hContact, const char *pszGroup); - - void servlistPendingAddContactOperation(HANDLE hContact, LPARAM param, PENDING_CONTACT_CALLBACK callback, DWORD flags); - void servlistPendingAddGroupOperation(const char *pszGroup, LPARAM param, PENDING_GROUP_CALLBACK callback, DWORD flags); - int servlistPendingAddContact(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM param, PENDING_CONTACT_CALLBACK callback, int bDoInline, LPARAM operationParam = 0, PENDING_CONTACT_CALLBACK operationCallback = NULL); - int servlistPendingAddGroup(const char *pszGroup, WORD wGroupID, LPARAM param, PENDING_GROUP_CALLBACK callback, int bDoInline, LPARAM operationParam = 0, PENDING_GROUP_CALLBACK operationCallback = NULL); - void servlistPendingRemoveContact(HANDLE hContact, WORD wContactID, WORD wGroupID, int nResult); - void servlistPendingRemoveGroup(const char *pszGroup, WORD wGroupID, int nResult); - void servlistPendingFlushOperations(); - - // server-list support functions - int nJustAddedCount; - int nJustAddedSize; - HANDLE* pdwJustAddedList; - - void AddJustAddedContact(HANDLE hContact); - BOOL IsContactJustAdded(HANDLE hContact); - void FlushJustAddedContacts(); - - WORD GenerateServerID(int bGroupType, int bFlags, int wCount = 0); - void ReserveServerID(WORD wID, int bGroupType, int bFlags); - void FreeServerID(WORD wID, int bGroupType); - BOOL CheckServerID(WORD wID, unsigned int wCount); - void FlushServerIDs(); - void LoadServerIDs(); - void StoreServerIDs(); - - void* collectGroups(int *count); - void* collectBuddyGroup(WORD wGroupID, int *count); - char* getServListGroupName(WORD wGroupID); - void setServListGroupName(WORD wGroupID, const char *szGroupName); - WORD getServListGroupLinkID(const char *szPath); - void setServListGroupLinkID(const char *szPath, WORD wGroupID); - int IsServerGroupsDefined(); - char* getServListGroupCListPath(WORD wGroupId); - char* getServListUniqueGroupName(const char *szGroupName, int bAlloced); - - int __cdecl servlistCreateGroup_gotParentGroup(const char *szGroup, WORD wGroupID, LPARAM param, int nResult); - int __cdecl servlistCreateGroup_Ready(const char *szGroup, WORD groupID, LPARAM param, int nResult); - void servlistCreateGroup(const char *szGroupPath, LPARAM param, PENDING_GROUP_CALLBACK callback); - - int __cdecl servlistAddContact_gotGroup(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult); - int __cdecl servlistAddContact_Ready(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM lParam, int nResult); - void servlistAddContact(HANDLE hContact, const char *pszGroup); - - int __cdecl servlistRemoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); - void servlistRemoveContact(HANDLE hContact); - - int __cdecl servlistMoveContact_gotTargetGroup(const char *szGroup, WORD wNewGroupID, LPARAM lParam, int nResult); - int __cdecl servlistMoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); - void servlistMoveContact(HANDLE hContact, const char *pszNewGroup); - - int __cdecl servlistUpdateContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); - void servlistUpdateContact(HANDLE hContact); - - int __cdecl servlistRenameGroup_Ready(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult); - void servlistRenameGroup(char *szGroup, WORD wGroupId, char *szNewGroup); - - int __cdecl servlistRemoveGroup_Ready(const char *szGroup, WORD groupID, LPARAM lParam, int nResult); - void servlistRemoveGroup(const char *szGroup, WORD wGroupId); - - void removeGroupPathLinks(WORD wGroupID); - int getServListGroupLevel(WORD wGroupId); - - void resetServContactAuthState(HANDLE hContact, DWORD dwUin); - - void FlushSrvGroupsCache(); - int getCListGroupHandle(const char *szGroup); - int getCListGroupExists(const char *szGroup); - int moveContactToCListGroup(HANDLE hContact, const char *szGroup); /// TODO: this should be DB function - - DWORD icq_sendServerItem(DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wItemId, const char *szName, BYTE *pTLVs, int nTlvLength, WORD wItemType, DWORD dwOperation, DWORD dwTimeout, void **doubleObject); - DWORD icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId, DWORD dwOperation, DWORD dwTimeout, void **doubleObject); - DWORD icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType, DWORD dwOperation, DWORD dwTimeout); - DWORD icq_sendServerGroup(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent, DWORD dwOperationFlags); - - DWORD icq_modifyServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wAction, DWORD dwOperation, WORD wItemId, WORD wType); - DWORD icq_removeServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType); - DWORD icq_addServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType); - - int __cdecl ServListDbSettingChanged(WPARAM wParam, LPARAM lParam); - int __cdecl ServListDbContactDeleted(WPARAM wParam, LPARAM lParam); - int __cdecl ServListCListGroupChange(WPARAM wParam, LPARAM lParam); - - //----| stdpackets.cpp |---------------------------------------------------------- - void icq_sendCloseConnection(); - - void icq_requestnewfamily(WORD wFamily, void (CIcqProto::*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen)); - - void icq_setidle(int bAllow); - void icq_setstatus(WORD wStatus, const char *szStatusNote = NULL); - DWORD icq_sendGetInfoServ(HANDLE, DWORD, int); - DWORD icq_sendGetAimProfileServ(HANDLE hContact, char *szUid); - DWORD icq_sendGetAwayMsgServ(HANDLE, DWORD, int, WORD); - DWORD icq_sendGetAwayMsgServExt(HANDLE hContact, DWORD dwUin, char *szUID, int type, WORD wVersion); - DWORD icq_sendGetAimAwayMsgServ(HANDLE hContact, char *szUID, int type); - void icq_sendSetAimAwayMsgServ(const char *szMsg); - - void icq_sendFileSendServv7(filetransfer* ft, const char *szFiles); - void icq_sendFileSendServv8(filetransfer* ft, const char *szFiles, int nAckType); - - void icq_sendFileAcceptServ(DWORD dwUin, filetransfer *ft, int nAckType); - void icq_sendFileAcceptServv7(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType); - void icq_sendFileAcceptServv8(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType); - - void icq_sendFileDenyServ(DWORD dwUin, filetransfer *ft, const char *szReason, int nAckType); - - DWORD icq_sendAdvancedSearchServ(BYTE *fieldsBuffer,int bufferLen); - DWORD icq_changeUserPasswordServ(const char *szPassword); - DWORD icq_changeUserDirectoryInfoServ(const BYTE *pData, WORD wDataLen, BYTE bRequestType); - void icq_sendGenericContact(DWORD dwUin, const char *szUid, WORD wFamily, WORD wSubType); - void icq_sendNewContact(DWORD dwUin, const char *szUid); - void icq_sendRemoveContact(DWORD dwUin, const char *szUid); - void icq_sendChangeVisInvis(HANDLE hContact, DWORD dwUin, char* szUID, int list, int add); - void icq_sendEntireVisInvisList(int); - void icq_sendAwayMsgReplyServ(DWORD, DWORD, DWORD, WORD, WORD, BYTE, char **); - void icq_sendAwayMsgReplyServExt(DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char **szMsg); - - DWORD icq_sendSMSServ(const char *szPhoneNumber, const char *szMsg); - void icq_sendMessageCapsServ(DWORD dwUin); - void icq_sendRevokeAuthServ(DWORD dwUin, char *szUid); - void icq_sendGrantAuthServ(DWORD dwUin, const char *szUid, const char *szMsg); - void icq_sendAuthReqServ(DWORD dwUin, char* szUid, const char *szMsg); - void icq_sendAuthResponseServ(DWORD dwUin, char* szUid,int auth,const TCHAR *szReason); - void icq_sendYouWereAddedServ(DWORD,DWORD); - - DWORD sendDirectorySearchPacket(const BYTE *pSearchData, WORD wDataLen, WORD wPage, BOOL bOnlineUsersOnly); - DWORD sendTLVSearchPacket(BYTE bType, char* pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly); - void sendOwnerInfoRequest(void); - DWORD sendUserInfoMultiRequest(BYTE *pRequestData, WORD wDataLen, int nItems); - - DWORD icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, cookie_message_data *pCookieData); - DWORD icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, WCHAR *pszText, cookie_message_data *pCookieData); // UTF-16 - DWORD icq_SendChannel2Message(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap); - DWORD icq_SendChannel2Contacts(DWORD dwUin, char *szUid, HANDLE hContact, const char *pData, WORD wDataLen, const char *pNames, WORD wNamesLen, cookie_message_data *pCookieData); - DWORD icq_SendChannel4Message(DWORD dwUin, HANDLE hContact, BYTE bMsgType, WORD wMsgLen, const char *szMsg, cookie_message_data *pCookieData); - - void icq_sendAdvancedMsgAck(DWORD, DWORD, DWORD, WORD, BYTE, BYTE); - void icq_sendContactsAck(DWORD dwUin, char *szUid, DWORD dwMsgID1, DWORD dwMsgID2); - - void icq_sendReverseReq(directconnect *dc, DWORD dwCookie, cookie_message_data *pCookie); - void icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie); - - void icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, cookie_message_data *pCookieData); - void icq_sendXtrazResponseServ(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szBody, int nBodyLen, int nType); - - DWORD SearchByUin(DWORD dwUin); - DWORD SearchByNames(const char *pszNick, const char *pszFirstName, const char *pszLastName, WORD wPage); - DWORD SearchByMail(const char *pszEmail); - - DWORD icq_searchAimByEmail(const char* pszEmail, DWORD dwSearchId); - - void oft_sendFileRequest(DWORD dwUin, char *szUid, oscar_filetransfer *ft, const char *pszFiles, DWORD dwLocalInternalIP); - void oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer *ft); - void oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer *ft); - void oft_sendFileCancel(DWORD dwUin, char *szUid, oscar_filetransfer *ft); - void oft_sendFileResponse(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResponse); - void oft_sendFileRedirect(DWORD dwUin, char *szUid, oscar_filetransfer *ft, DWORD dwIP, WORD wPort, int bProxy); - - //---- | icq_svcs.cpp |---------------------------------------------------------------- - HANDLE AddToListByUIN(DWORD dwUin, DWORD dwFlags); - HANDLE AddToListByUID(const char *szUID, DWORD dwFlags); - - void ICQAddRecvEvent(HANDLE hContact, WORD wType, PROTORECVEVENT* pre, DWORD cbBlob, PBYTE pBlob, DWORD flags); - INT_PTR __cdecl IcqAddCapability(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl IcqCheckCapability(WPARAM wParam, LPARAM lParam); - - std::list CustomCapList; - - //----| icq_uploadui.cpp |------------------------------------------------------------ - void ShowUploadContactsDialog(void); - - //----| icq_xstatus.cpp |------------------------------------------------------------- - int m_bHideXStatusUI; - int m_bHideXStatusMenu; - int bXStatusExtraIconsReady; - HANDLE hHookExtraIconsRebuild; - HANDLE hHookStatusBuild; - HANDLE hHookExtraIconsApply; - HANDLE hXStatusExtraIcons[XSTATUS_COUNT]; - IcqIconHandle hXStatusIcons[XSTATUS_COUNT]; - HANDLE hXStatusItems[XSTATUS_COUNT + 1]; - - int hXStatusCListIcons[XSTATUS_COUNT]; - BOOL bXStatusCListIconsValid[XSTATUS_COUNT]; - - void InitXStatusItems(BOOL bAllowStatus); - BYTE getContactXStatus(HANDLE hContact); - DWORD sendXStatusDetailsRequest(HANDLE hContact, int bForced); - DWORD requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay); - HICON getXStatusIcon(int bStatus, UINT flags); - void releaseXStatusIcon(int bStatus, UINT flags); - void setXStatusEx(BYTE bXStatus, BYTE bQuiet); - void setContactExtraIcon(HANDLE hContact, int xstatus); - void handleXStatusCaps(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *caps, int capsize, char *moods, int moodsize); - void updateServerCustomStatus(int fullUpdate); - - void InitXStatusIcons(); - void UninitXStatusIcons(); - - //----| icq_xtraz.cpp |--------------------------------------------------------------- - void handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); - void handleXtrazNotifyResponse(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szMsg, int nMsgLen); - - void handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); - void handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); - - DWORD SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced); - void SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC); - - //----| init.cpp |-------------------------------------------------------------------- - void UpdateGlobalSettings(); - - //----| loginpassword.cpp |----------------------------------------------------------- - void RequestPassword(); - - //----| oscar_filetransfer.cpp |------------------------------------------------------ - icq_critical_section *oftMutex; - int fileTransferCount; - basic_filetransfer** fileTransferList; - - oscar_filetransfer* CreateOscarTransfer(); - filetransfer *CreateIcqFileTransfer(); - void ReleaseFileTransfer(void *ft); - void SafeReleaseFileTransfer(void **ft); - oscar_filetransfer* FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2); - - oscar_listener* CreateOscarListener(oscar_filetransfer *ft, NETLIBNEWCONNECTIONPROC_V2 handler); - void ReleaseOscarListener(oscar_listener **pListener); - - void OpenOscarConnection(HANDLE hContact, oscar_filetransfer *ft, int type); - void CloseOscarConnection(oscar_connection *oc); - int CreateOscarProxyConnection(oscar_connection *oc); - - int getFileTransferIndex(void *ft); - int IsValidFileTransfer(void *ft); - int IsValidOscarTransfer(void *ft); - - void handleRecvServMsgOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand); - void handleRecvServResponseOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, void* ft); - - HANDLE oftInitTransfer(HANDLE hContact, DWORD dwUin, char *szUid, const TCHAR **pszFiles, const TCHAR *szDescription); - HANDLE oftFileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR *szPath); - DWORD oftFileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR *szReason); - DWORD oftFileCancel(HANDLE hContact, HANDLE hTransfer); - void oftFileResume(oscar_filetransfer *ft, int action, const TCHAR *szFilename); - - void sendOscarPacket(oscar_connection *oc, icq_packet *packet); - void handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen); - void sendOFT2FramePacket(oscar_connection *oc, WORD datatype); - - void proxy_sendInitTunnel(oscar_connection *oc); - void proxy_sendJoinTunnel(oscar_connection *oc, WORD wPort); - - //----| stdpackets.cpp |-------------------------------------------------------------- - void __cdecl oft_connectionThread(struct oscarthreadstartinfo *otsi); - - int oft_handlePackets(oscar_connection *oc, BYTE *buf, int len); - int oft_handleFileData(oscar_connection *oc, BYTE *buf, int len); - int oft_handleProxyData(oscar_connection *oc, BYTE *buf, int len); - void oft_sendFileData(oscar_connection *oc); - void oft_sendPeerInit(oscar_connection *oc); - void oft_sendFileReply(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResult); - - //----| upload.cpp |------------------------------------------------------------------ - int StringToListItemId(const char *szSetting,int def); - - //----| utilities.cpp |--------------------------------------------------------------- - int BroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam); - char* ConvertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg); - - char* GetUserStoredPassword(char *szBuffer, int cbSize); - char* GetUserPassword(BOOL bAlways); - WORD GetMyStatusFlags(); - - DWORD ReportGenericSendError(HANDLE hContact, int nType, const char* szErrorMsg); - void SetCurrentStatus(int nStatus); - - void ForkThread( IcqThreadFunc pFunc, void* arg ); - HANDLE ForkThreadEx( IcqThreadFunc pFunc, void* arg, UINT* threadID = NULL ); - - void __cdecl ProtocolAckThread(icq_ack_args* pArguments); - void SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage); - - HANDLE CreateProtoEvent(const char* szEvent); - void CreateProtoService(const char* szService, IcqServiceFunc serviceProc); - void CreateProtoServiceParam(const char* szService, IcqServiceFuncParam serviceProc, LPARAM lParam); - HANDLE HookProtoEvent(const char* szEvent, IcqEventFunc pFunc); - - int NetLog_Server(const char *fmt,...); - int NetLog_Direct(const char *fmt,...); - int NetLog_Uni(BOOL bDC, const char *fmt,...); - - icq_critical_section *contactsCacheMutex; - LIST contactsCache; - - void AddToContactsCache(HANDLE hContact, DWORD dwUin, const char *szUid); - void DeleteFromContactsCache(HANDLE hContact); - void InitContactsCache(); - void UninitContactsCache(); - - void AddToSpammerList(DWORD dwUIN); - BOOL IsOnSpammerList(DWORD dwUIN); - - HANDLE NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP); - - HANDLE HandleFromCacheByUid(DWORD dwUin, const char *szUid); - HANDLE HContactFromUIN(DWORD dwUin, int *Added); - HANDLE HContactFromUID(DWORD dwUin, const char *szUid, int *Added); - HANDLE HContactFromAuthEvent(HANDLE hEvent); - - void ResetSettingsOnListReload(); - void ResetSettingsOnConnect(); - void ResetSettingsOnLoad(); - - int IsMetaInfoChanged(HANDLE hContact); - - char *setStatusNoteText, *setStatusMoodData; - void __cdecl SetStatusNoteThread(void *pArguments); - int SetStatusNote(const char *szStatusNote, DWORD dwDelay, int bForced); - int SetStatusMood(const char *szMoodData, DWORD dwDelay); - - BOOL writeDbInfoSettingString(HANDLE hContact, const char* szSetting, char** buf, WORD* pwLength); - BOOL writeDbInfoSettingWord(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength); - BOOL writeDbInfoSettingWordWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength); - BOOL writeDbInfoSettingByte(HANDLE hContact, const char *pszSetting, char **buf, WORD* pwLength); - BOOL writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength); - - void writeDbInfoSettingTLVStringUtf(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVString(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVWord(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVByte(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVDouble(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVDate(HANDLE hContact, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, oscar_tlv_chain *chain, WORD wTlv); - void writeDbInfoSettingTLVBlob(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); - - char** MirandaStatusToAwayMsg(int nStatus); - - BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType); -}; - -#endif diff --git a/protocols/IcqOscarJ/icq_rates.cpp b/protocols/IcqOscarJ/icq_rates.cpp deleted file mode 100644 index e7513ec148..0000000000 --- a/protocols/IcqOscarJ/icq_rates.cpp +++ /dev/null @@ -1,529 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Rate Management stuff -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -// -// Rate Level 1 Management -///////////////////////////// - -rates::rates(CIcqProto *ppro, BYTE *pBuffer, WORD wLen) -{ - nGroups = 0; - memset(&groups, 0, MAX_RATES_GROUP_COUNT * sizeof(rates_group)); - this->ppro = ppro; - - // Parse Rate Data Block - WORD wCount; - unpackWord(&pBuffer, &wCount); - wLen -= 2; - - if (wCount > MAX_RATES_GROUP_COUNT) - { // just sanity check - ppro->NetLog_Server("Rates: Error: Data packet contains too many rate groups!"); - wCount = MAX_RATES_GROUP_COUNT; - } - - nGroups = wCount; - // Parse Group details - int i; - for (i=0; i= 35) - { - pBuffer += 2; // Group ID - unpackDWord(&pBuffer, &pGroup->dwWindowSize); - unpackDWord(&pBuffer, &pGroup->dwClearLevel); - unpackDWord(&pBuffer, &pGroup->dwAlertLevel); - unpackDWord(&pBuffer, &pGroup->dwLimitLevel); - pBuffer += 8; - unpackDWord(&pBuffer, &pGroup->dwMaxLevel); - pBuffer += 5; - wLen -= 35; - } - else - { // packet broken, put some basic defaults - pGroup->dwWindowSize = 10; - pGroup->dwMaxLevel = 5000; - } - pGroup->rCurrentLevel = pGroup->dwMaxLevel; - } - // Parse Group associated pairs - for (i=0; inPairs = wNum; - pGroup->pPairs = (WORD*)SAFE_MALLOC(wNum*4); - for (int n=0; npPairs[n] = wItem; - } -#ifdef _DEBUG - ppro->NetLog_Server("Rates: %d# %d pairs.", i+1, wNum); -#endif - wLen -= wNum*4; - } -} - - -rates::~rates() -{ - for (int i = 0; i < nGroups; i++) - SAFE_FREE((void**)&groups[i].pPairs); - - nGroups = 0; -} - - -WORD rates::getGroupFromSNAC(WORD wFamily, WORD wCommand) -{ - if (this) - { - for (int i = 0; i < nGroups; i++) - { - rates_group* pGroup = &groups[i]; - - for (int j = 0; j < 2 * pGroup->nPairs; j += 2) - { - if (pGroup->pPairs[j] == wFamily && pGroup->pPairs[j + 1] == wCommand) - { // we found the group - return (WORD)(i + 1); - } - } - } - _ASSERTE(0); - } - - return 0; // Failure -} - - -WORD rates::getGroupFromPacket(icq_packet *pPacket) -{ - if (this) - { - if (pPacket->nChannel == ICQ_DATA_CHAN && pPacket->wLen >= 0x10) - { - WORD wFamily, wCommand; - BYTE *pBuf = pPacket->pData + 6; - - unpackWord(&pBuf, &wFamily); - unpackWord(&pBuf, &wCommand); - - return getGroupFromSNAC(wFamily, wCommand); - } - } - return 0; -} - - -rates_group* rates::getGroup(WORD wGroup) -{ - if (this && wGroup && wGroup <= nGroups) - return &groups[wGroup - 1]; - - return NULL; -} - - -int rates::getNextRateLevel(WORD wGroup) -{ - rates_group *pGroup = getGroup(wGroup); - - if (pGroup) - { - int nLevel = pGroup->rCurrentLevel*(pGroup->dwWindowSize-1)/pGroup->dwWindowSize + (GetTickCount() - pGroup->tCurrentLevel)/pGroup->dwWindowSize; - - return nLevel < (int)pGroup->dwMaxLevel ? nLevel : pGroup->dwMaxLevel; - } - return -1; // Failure -} - - -int rates::getDelayToLimitLevel(WORD wGroup, int nLevel) -{ - rates_group *pGroup = getGroup(wGroup); - - if (pGroup) - return (getLimitLevel(wGroup, nLevel) - pGroup->rCurrentLevel)*pGroup->dwWindowSize + pGroup->rCurrentLevel; - - return 0; // Failure -} - - -void rates::packetSent(icq_packet *pPacket) -{ - if (this) - { - WORD wGroup = getGroupFromPacket(pPacket); - - if (wGroup) - updateLevel(wGroup, getNextRateLevel(wGroup)); - } -} - - -void rates::updateLevel(WORD wGroup, int nLevel) -{ - rates_group *pGroup = getGroup(wGroup); - - if (pGroup) - { - pGroup->rCurrentLevel = nLevel; - pGroup->tCurrentLevel = GetTickCount(); -#ifdef _DEBUG - ppro->NetLog_Server("Rates: New level %d for #%d", nLevel, wGroup); -#endif - } -} - - -int rates::getLimitLevel(WORD wGroup, int nLevel) -{ - rates_group *pGroup = getGroup(wGroup); - - if (pGroup) - { - switch(nLevel) - { - case RML_CLEAR: - return pGroup->dwClearLevel; - - case RML_ALERT: - return pGroup->dwAlertLevel; - - case RML_LIMIT: - return pGroup->dwLimitLevel; - - case RML_IDLE_10: - return pGroup->dwClearLevel + ((pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); - - case RML_IDLE_30: - return pGroup->dwClearLevel + (3*(pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); - - case RML_IDLE_50: - return pGroup->dwClearLevel + ((pGroup->dwMaxLevel - pGroup->dwClearLevel)/2); - - case RML_IDLE_70: - return pGroup->dwClearLevel + (7*(pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); - } - } - return 9999; // some high number - without rates we allow anything -} - - -void rates::initAckPacket(icq_packet *pPacket) -{ - serverPacketInit(pPacket, 10 + nGroups * (int)sizeof(WORD)); - packFNACHeader(pPacket, ICQ_SERVICE_FAMILY, ICQ_CLIENT_RATE_ACK); - for (WORD wGroup = 1; wGroup <= nGroups; wGroup++) - packWord(pPacket, wGroup); -} - - - -// -// Rate Level 2 Management -///////////////////////////// - - -rates_queue_item::rates_queue_item(CIcqProto *ppro, WORD wGroup) : bCreated(FALSE), dwUin(0), szUid(NULL) -{ - this->ppro = ppro; - this->wGroup = wGroup; -} - -rates_queue_item::~rates_queue_item() -{ - if (bCreated) - { - SAFE_FREE(&szUid); - bCreated = FALSE; - } -} - - -BOOL rates_queue_item::isEqual(rates_queue_item *pItem) -{ // the same event (equal address of _vftable) for the same contact - return (pItem->hContact == this->hContact) && (*(void**)pItem == *(void**)this); -} - - -rates_queue_item* rates_queue_item::copyItem(rates_queue_item *pDest) -{ - if (!pDest) - pDest = new rates_queue_item(ppro, wGroup); - - pDest->hContact = hContact; - pDest->dwUin = dwUin; - pDest->szUid = dwUin ? null_strdup(szUid) : NULL; - pDest->bCreated = TRUE; - - return pDest; -} - - -void rates_queue_item::execute() -{ -#ifdef _DEBUG - ppro->NetLog_Server("Rates: Error executing abstract event."); -#endif -} - - -BOOL rates_queue_item::isOverRate(int nLevel) -{ - icq_lock l(ppro->m_ratesMutex); - - if (ppro->m_rates) - return ppro->m_rates->getNextRateLevel(wGroup) < ppro->m_rates->getLimitLevel(wGroup, nLevel); - - return FALSE; -} - - -rates_queue::rates_queue(CIcqProto *ppro, const char *szDescr, int nLimitLevel, int nWaitLevel, int nDuplicates) -{ - this->listsMutex = new icq_critical_section(); - this->ppro = ppro; - this->szDescr = szDescr; - limitLevel = nLimitLevel; - waitLevel = nWaitLevel; - duplicates = nDuplicates; -} - - -rates_queue::~rates_queue() -{ - cleanup(); - delete listsMutex; -} - - -// links to functions that are under Rate Control -struct rate_delay_args -{ - int nDelay; - rates_queue *queue; - IcqRateFunc delaycode; -}; - -void __cdecl CIcqProto::rateDelayThread(rate_delay_args *pArgs) -{ - SleepEx(pArgs->nDelay, TRUE); - (pArgs->queue->*pArgs->delaycode)(); - SAFE_FREE((void**)&pArgs); -} - - -void rates_queue::initDelay(int nDelay, IcqRateFunc delaycode) -{ -#ifdef _DEBUG - ppro->NetLog_Server("Rates: Delay %dms", nDelay); -#endif - - rate_delay_args *pArgs = (rate_delay_args*)SAFE_MALLOC(sizeof(rate_delay_args)); // This will be freed in the new thread - pArgs->queue = this; - pArgs->nDelay = nDelay; - pArgs->delaycode = delaycode; - - ppro->ForkThread((IcqThreadFunc)&CIcqProto::rateDelayThread, pArgs); -} - - -void rates_queue::cleanup() -{ - icq_lock l(listsMutex); - - if (pendingListSize) - ppro->NetLog_Server("Rates: Purging %d %s(s).", pendingListSize, szDescr); - - for (int i=0; i < pendingListSize; i++) - delete pendingList[i]; - SAFE_FREE((void**)&pendingList); - pendingListSize = 0; -} - - -void rates_queue::processQueue() -{ - if (!pendingList) - return; - - if (!ppro->icqOnline()) - { - cleanup(); - return; - } - // take from queue, execute - rates_queue_item *item = pendingList[0]; - - ppro->m_ratesMutex->Enter(); - listsMutex->Enter(); - if (item->isOverRate(limitLevel)) - { // the rate is higher, keep sleeping - int nDelay = ppro->m_rates->getDelayToLimitLevel(item->wGroup, ppro->m_rates->getLimitLevel(item->wGroup, waitLevel)); - - listsMutex->Leave(); - ppro->m_ratesMutex->Leave(); - if (nDelay < 10) nDelay = 10; - initDelay(nDelay, &rates_queue::processQueue); - return; - } - ppro->m_ratesMutex->Leave(); - - if (pendingListSize > 1) - { // we need to keep order - memmove(&pendingList[0], &pendingList[1], (pendingListSize - 1) * sizeof(rates_queue_item*)); - } - else - SAFE_FREE((void**)&pendingList); - - int bSetupTimer = --pendingListSize != 0; - - listsMutex->Leave(); - - if (ppro->icqOnline()) - { - ppro->NetLog_Server("Rates: Resuming %s.", szDescr); - item->execute(); - } - else - ppro->NetLog_Server("Rates: Discarding %s.", szDescr); - - if (bSetupTimer) - { - // in queue remained some items, setup timer - ppro->m_ratesMutex->Enter(); - int nDelay = ppro->m_rates->getDelayToLimitLevel(item->wGroup, waitLevel); - ppro->m_ratesMutex->Leave(); - - if (nDelay < 10) nDelay = 10; - initDelay(nDelay, &rates_queue::processQueue); - } - delete item; -} - - -void rates_queue::putItem(rates_queue_item *pItem, int nMinDelay) -{ - int bFound = FALSE; - - if (!ppro->icqOnline()) - return; - - ppro->NetLog_Server("Rates: Delaying %s.", szDescr); - - listsMutex->Enter(); - if (pendingListSize) - { - for (int i = 0; i < pendingListSize; i++) - { - if (pendingList[i]->isEqual(pItem)) - { - if (duplicates == -1) - { // discard existing, append new item - delete pendingList[i]; - memcpy(&pendingList[i], &pendingList[i + 1], (pendingListSize - i - 1) * sizeof(rates_queue_item*)); - bFound = TRUE; - } - else if (duplicates == 1) - { // keep existing, ignore new - listsMutex->Leave(); - return; - } - // otherwise keep existing and append new - } - } - } - if (!bFound) - { // not found, enlarge the queue - pendingListSize++; - pendingList = (rates_queue_item**)SAFE_REALLOC(pendingList, pendingListSize * sizeof(rates_queue_item*)); - } - pendingList[pendingListSize - 1] = pItem->copyItem(); - - if (pendingListSize == 1) - { // queue was empty setup timer - listsMutex->Leave(); - ppro->m_ratesMutex->Enter(); - int nDelay = ppro->m_rates->getDelayToLimitLevel(pItem->wGroup, waitLevel); - ppro->m_ratesMutex->Leave(); - - if (nDelay < 10) nDelay = 10; - if (nDelay < nMinDelay) nDelay = nMinDelay; - initDelay(nDelay, &rates_queue::processQueue); - } - else - listsMutex->Leave(); -} - - -int CIcqProto::handleRateItem(rates_queue_item *item, int nQueueType, int nMinDelay, BOOL bAllowDelay) -{ - rates_queue *pQueue = NULL; - - m_ratesMutex->Enter(); - switch (nQueueType) - { - case RQT_REQUEST: - pQueue = m_ratesQueue_Request; - break; - case RQT_RESPONSE: - pQueue = m_ratesQueue_Response; - break; - } - - if (pQueue) - { - if (bAllowDelay && (item->isOverRate(pQueue->waitLevel) || nMinDelay)) - { // limit reached or min delay configured, add to queue - pQueue->putItem(item, nMinDelay); - - m_ratesMutex->Leave(); - return 1; - } - } - m_ratesMutex->Leave(); - - item->execute(); - return 0; -} diff --git a/protocols/IcqOscarJ/icq_rates.h b/protocols/IcqOscarJ/icq_rates.h deleted file mode 100644 index ab16e74007..0000000000 --- a/protocols/IcqOscarJ/icq_rates.h +++ /dev/null @@ -1,146 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Rate management -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_RATES_H -#define __ICQ_RATES_H - -#define MAX_RATES_GROUP_COUNT 5 - -struct rates_group -{ - DWORD dwWindowSize; - DWORD dwClearLevel; - DWORD dwAlertLevel; - DWORD dwLimitLevel; - DWORD dwMaxLevel; - // current level - int rCurrentLevel; - int tCurrentLevel; - // links - WORD *pPairs; - int nPairs; -}; - -struct rates : public MZeroedObject -{ -private: - CIcqProto *ppro; - int nGroups; - rates_group groups[MAX_RATES_GROUP_COUNT]; - - rates_group *getGroup(WORD wGroup); -public: - rates(CIcqProto *ppro, BYTE *pBuffer, WORD wLen); - ~rates(); - - WORD getGroupFromSNAC(WORD wFamily, WORD wCommand); - WORD getGroupFromPacket(icq_packet *pPacket); - - int getLimitLevel(WORD wGroup, int nLevel); - int getDelayToLimitLevel(WORD wGroup, int nLevel); - int getNextRateLevel(WORD wGroup); - - void packetSent(icq_packet *pPacket); - void updateLevel(WORD wGroup, int nLevel); - - void initAckPacket(icq_packet *pPacket); -}; - -#define RML_CLEAR 0x01 -#define RML_ALERT 0x02 -#define RML_LIMIT 0x03 -#define RML_IDLE_10 0x10 -#define RML_IDLE_30 0x11 -#define RML_IDLE_50 0x12 -#define RML_IDLE_70 0x13 - -// Rates - Level 2 - -// queue types -#define RQT_DEFAULT 0 // standard - pushes all items without much delay -#define RQT_REQUEST 1 // request - pushes only first item on duplicity -#define RQT_RESPONSE 2 // response - pushes only last item on duplicity - -// -// generic queue item -// -struct rates_queue_item : public MZeroedObject -{ - friend struct rates_queue; -protected: - CIcqProto *ppro; - BOOL bCreated; - WORD wGroup; - - virtual BOOL isEqual(rates_queue_item *pItem); - virtual rates_queue_item* copyItem(rates_queue_item *pDest = NULL); -public: - rates_queue_item(CIcqProto *ppro, WORD wGroup); - virtual ~rates_queue_item(); - - BOOL isOverRate(int nLevel); - - virtual void execute(); - - HANDLE hContact; - DWORD dwUin; - char *szUid; -}; - -struct rates_queue; -typedef void (rates_queue::*IcqRateFunc)(void); - -// -// generic item queue (FIFO) -// -struct rates_queue : public MZeroedObject -{ -private: - CIcqProto *ppro; - const char *szDescr; - icq_critical_section *listsMutex; // we need to be thread safe - int pendingListSize; - rates_queue_item **pendingList; - int duplicates; -protected: - void cleanup(); - void processQueue(); - void initDelay(int nDelay, IcqRateFunc delaycode); -public: - rates_queue(CIcqProto *ppro, const char *szDescr, int nLimitLevel, int nWaitLevel, int nDuplicates = 0); - ~rates_queue(); - - void putItem(rates_queue_item *pItem, int nMinDelay); - - int limitLevel; // RML_* - int waitLevel; -}; - - -#endif /* __ICQ_RATES_H */ diff --git a/protocols/IcqOscarJ/icq_server.cpp b/protocols/IcqOscarJ/icq_server.cpp deleted file mode 100644 index 63a5d63d84..0000000000 --- a/protocols/IcqOscarJ/icq_server.cpp +++ /dev/null @@ -1,444 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Manages main server connection, low-level communication -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void icq_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra); - -///////////////////////////////////////////////////////////////////////////////////////// -// ICQ Server thread - -void __cdecl CIcqProto::ServerThread(serverthread_start_info *infoParam) -{ - serverthread_info info = {0}; - - info.isLoginServer = 1; - info.wAuthKeyLen = infoParam->wPassLen; - null_strcpy((char*)info.szAuthKey, infoParam->szPass, info.wAuthKeyLen); - // store server port - info.wServerPort = infoParam->nloc.wPort; - - srand(time(NULL)); - - ResetSettingsOnConnect(); - - // Connect to the login server - NetLog_Server("Authenticating to server"); - { - NETLIBOPENCONNECTION nloc = infoParam->nloc; - nloc.timeout = 6; - if (m_bGatewayMode) - nloc.flags |= NLOCF_HTTPGATEWAY; - - hServerConn = NetLib_OpenConnection(m_hServerNetlibUser, NULL, &nloc); - - SAFE_FREE((void**)&nloc.szHost); - SAFE_FREE((void**)&infoParam); - - if (hServerConn && m_bSecureConnection) - { - if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hServerConn, 0)) - { - icq_LogMessage(LOG_ERROR, LPGEN("Unable to connect to ICQ login server, SSL could not be negotiated")); - SetCurrentStatus(ID_STATUS_OFFLINE); - NetLib_CloseConnection(&hServerConn, TRUE); - return; - } - } - } - - // Login error - if (hServerConn == NULL) - { - DWORD dwError = GetLastError(); - - SetCurrentStatus(ID_STATUS_OFFLINE); - - icq_LogUsingErrorCode(LOG_ERROR, dwError, LPGEN("Unable to connect to ICQ login server")); - return; - } - - // Initialize direct connection ports - { - DWORD dwInternalIP; - BYTE bConstInternalIP = getSettingByte(NULL, "ConstRealIP", 0); - - info.hDirectBoundPort = NetLib_BindPort(icq_newConnectionReceived, this, &wListenPort, &dwInternalIP); - if (!info.hDirectBoundPort) - { - icq_LogUsingErrorCode(LOG_WARNING, GetLastError(), LPGEN("Miranda was unable to allocate a port to listen for direct peer-to-peer connections between clients. You will be able to use most of the ICQ network without problems but you may be unable to send or receive files.\n\nIf you have a firewall this may be blocking Miranda, in which case you should configure your firewall to leave some ports open and tell Miranda which ports to use in M->Options->ICQ->Network.")); - wListenPort = 0; - if (!bConstInternalIP) deleteSetting(NULL, "RealIP"); - } - else if (!bConstInternalIP) - setSettingDword(NULL, "RealIP", dwInternalIP); - } - - // Initialize rate limiting queues - { - icq_lock l(m_ratesMutex); - - m_ratesQueue_Request = new rates_queue(this, "request", RML_IDLE_30, RML_IDLE_50, 1); - m_ratesQueue_Response = new rates_queue(this, "response", RML_IDLE_10, RML_IDLE_30, -1); - } - - // This is the "infinite" loop that receives the packets from the ICQ server - { - int recvResult; - NETLIBPACKETRECVER packetRecv = {0}; - - info.hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 0x2400); - packetRecv.cbSize = sizeof(packetRecv); - packetRecv.dwTimeout = INFINITE; - while (serverThreadHandle) - { - if (info.bReinitRecver) - { // we reconnected, reinit struct - info.bReinitRecver = 0; - ZeroMemory(&packetRecv, sizeof(packetRecv)); - packetRecv.cbSize = sizeof(packetRecv); - packetRecv.dwTimeout = INFINITE; - } - - recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)info.hPacketRecver, (LPARAM)&packetRecv); - - if (recvResult == 0) - { - NetLog_Server("Clean closure of server socket"); - break; - } - - if (recvResult == SOCKET_ERROR) - { - NetLog_Server("Abortive closure of server socket, error: %d", GetLastError()); - break; - } - - if (m_iDesiredStatus == ID_STATUS_OFFLINE) - { // Disconnect requested, send disconnect packet - icq_sendCloseConnection(); - - // disconnected upon request - m_bConnectionLost = FALSE; - SetCurrentStatus(ID_STATUS_OFFLINE); - - NetLog_Server("Logged off."); - break; - } - - // Deal with the packet - packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable, &info); - } - serverThreadHandle = NULL; - - // Time to shutdown - NetLib_CloseConnection(&hServerConn, TRUE); - - // Close the packet receiver (connection may still be open) - NetLib_SafeCloseHandle(&info.hPacketRecver); - - // Close DC port - NetLib_SafeCloseHandle(&info.hDirectBoundPort); - } - - // disable auto info-update thread - icq_EnableUserLookup(FALSE); - - if (m_iStatus != ID_STATUS_OFFLINE && m_iDesiredStatus != ID_STATUS_OFFLINE) - { - if (!info.bLoggedIn) - icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nLogin sequence failed for unknown reason.\nTry again later.")); - - // set flag indicating we were kicked out - m_bConnectionLost = TRUE; - - SetCurrentStatus(ID_STATUS_OFFLINE); - } - - // signal keep-alive thread to stop - StopKeepAlive(&info); - - // Close all open DC connections - CloseContactDirectConns(NULL); - - // Close avatar connection if any - StopAvatarThread(); - - // Offline all contacts - HANDLE hContact = FindFirstContact(); - while (hContact) - { - DWORD dwUIN; - uid_str szUID; - - if (!getContactUid(hContact, &dwUIN, &szUID)) - { - if (getContactStatus(hContact) != ID_STATUS_OFFLINE) - { - char tmp = 0; - - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - - handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0); - } - } - - hContact = FindNextContact(hContact); - } - - setSettingDword(NULL, "LogonTS", 0); // clear logon time - - servlistPendingFlushOperations(); // clear pending operations list - - // release rates queues - { - icq_lock l(m_ratesMutex); - - SAFE_DELETE((MZeroedObject**)&m_ratesQueue_Request); - SAFE_DELETE((MZeroedObject**)&m_ratesQueue_Response); - SAFE_DELETE((MZeroedObject**)&m_rates); - } - - FlushServerIDs(); // clear server IDs list - - NetLog_Server("%s thread ended.", "Server"); -} - - -void CIcqProto::icq_serverDisconnect(BOOL bBlock) -{ - if ( !hServerConn) - return; - - NetLog_Server("Server shutdown requested"); - Netlib_Shutdown(hServerConn); - - if (serverThreadHandle) { - // Not called from network thread? - if (bBlock && GetCurrentThreadId() != serverThreadId) - while (ICQWaitForSingleObject(serverThreadHandle, INFINITE) != WAIT_OBJECT_0); - - CloseHandle(serverThreadHandle); - serverThreadHandle = NULL; - } -} - - -int CIcqProto::handleServerPackets(BYTE *buf, int len, serverthread_info *info) -{ - BYTE channel; - WORD sequence; - WORD datalen; - int bytesUsed = 0; - - while (len > 0) - { - if (info->bReinitRecver) - break; - - // All FLAPS begin with 0x2a - if (*buf++ != FLAP_MARKER) - break; - - if (len < 6) - break; - - unpackByte(&buf, &channel); - unpackWord(&buf, &sequence); - unpackWord(&buf, &datalen); - - if (len < 6 + datalen) - break; - - -#ifdef _DEBUG - NetLog_Server("Server FLAP: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); -#endif - - switch (channel) { - case ICQ_LOGIN_CHAN: - handleLoginChannel(buf, datalen, info); - break; - - case ICQ_DATA_CHAN: - handleDataChannel(buf, datalen, info); - break; - - case ICQ_ERROR_CHAN: - handleErrorChannel(buf, datalen); - break; - - case ICQ_CLOSE_CHAN: - handleCloseChannel(buf, datalen, info); - break; // we need this for walking thru proxy - - case ICQ_PING_CHAN: - handlePingChannel(buf, datalen); - break; - - default: - NetLog_Server("Warning: Unhandled Server FLAP Channel: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); - break; - } - - /* Increase pointers so we can check for more FLAPs */ - buf += datalen; - len -= (datalen + 6); - bytesUsed += (datalen + 6); - } - - return bytesUsed; -} - - -void CIcqProto::sendServPacket(icq_packet *pPacket) -{ - // make sure to have the connection handle - connectionHandleMutex->Enter(); - - if (hServerConn) - { - int nSendResult; - - // This critsec makes sure that the sequence order doesn't get screwed up - localSeqMutex->Enter(); - - // :IMPORTANT: - // The FLAP sequence must be a WORD. When it reaches 0xFFFF it should wrap to - // 0x0000, otherwise we'll get kicked by server. - wLocalSequence++; - - // Pack sequence number - pPacket->pData[2] = ((wLocalSequence & 0xff00) >> 8); - pPacket->pData[3] = (wLocalSequence & 0x00ff); - - nSendResult = Netlib_Send(hServerConn, (const char *)pPacket->pData, pPacket->wLen, 0); - - localSeqMutex->Leave(); - connectionHandleMutex->Leave(); - - // Send error - if (nSendResult == SOCKET_ERROR) - { - icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Your connection with the ICQ server was abortively closed")); - icq_serverDisconnect(FALSE); - - if (m_iStatus != ID_STATUS_OFFLINE) - { - SetCurrentStatus(ID_STATUS_OFFLINE); - } - } - else - { // Rates management - icq_lock l(m_ratesMutex); - m_rates->packetSent(pPacket); - } - - } - else - { - connectionHandleMutex->Leave(); - NetLog_Server("Error: Failed to send packet (no connection)"); - } - - SAFE_FREE((void**)&pPacket->pData); -} - - -void __cdecl CIcqProto::SendPacketAsyncThread(icq_packet* pkt) -{ - sendServPacket( pkt ); - SAFE_FREE((void**)&pkt); -} - - -void CIcqProto::sendServPacketAsync(icq_packet *packet) -{ - icq_packet *pPacket; - - pPacket = (icq_packet*)SAFE_MALLOC(sizeof(icq_packet)); // This will be freed in the new thread - memcpy(pPacket, packet, sizeof(icq_packet)); - - ForkThread(( IcqThreadFunc )&CIcqProto::SendPacketAsyncThread, pPacket); -} - - -int CIcqProto::IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel) -{ - icq_lock l(m_ratesMutex); - - if (m_rates) - { - WORD wGroup = m_rates->getGroupFromSNAC(wFamily, wCommand); - - // check if the rate is not over specified level - if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, nLevel)) - return TRUE; - } - - return FALSE; -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// ICQ Server thread - -void CIcqProto::icq_login(const char* szPassword) -{ - DWORD dwUin = getContactUin(NULL); - serverthread_start_info* stsi = (serverthread_start_info*)SAFE_MALLOC(sizeof(serverthread_start_info)); - - // Server host name - char szServer[MAX_PATH]; - if (getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH)) - stsi->nloc.szHost = null_strdup(m_bSecureConnection ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); - else - stsi->nloc.szHost = null_strdup(szServer); - - // Server port - stsi->nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); - if (stsi->nloc.wPort == 0) - stsi->nloc.wPort = RandRange(1024, 65535); - - // User password - stsi->wPassLen = strlennull(szPassword); - if (stsi->wPassLen > 8) stsi->wPassLen = 8; - null_strcpy(stsi->szPass, szPassword, stsi->wPassLen); - - // Randomize sequence - wLocalSequence = generate_flap_sequence(); - - m_dwLocalUIN = dwUin; - - // Initialize members - m_avatarsConnectionPending = TRUE; - - serverThreadHandle = ForkThreadEx(( IcqThreadFunc )&CIcqProto::ServerThread, stsi, &serverThreadId); -} diff --git a/protocols/IcqOscarJ/icq_server.h b/protocols/IcqOscarJ/icq_server.h deleted file mode 100644 index eba3ecfa42..0000000000 --- a/protocols/IcqOscarJ/icq_server.h +++ /dev/null @@ -1,71 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Declarations for server thread -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_SERVER_H -#define __ICQ_SERVER_H - -struct serverthread_start_info -{ - NETLIBOPENCONNECTION nloc; - WORD wPassLen; - char szPass[128]; -}; - -struct serverthread_info -{ - struct CIcqProto *ppro; - int bLoggedIn; - int isLoginServer; - BYTE szAuthKey[20]; - WORD wAuthKeyLen; - WORD wServerPort; - char *newServer; - BYTE *cookieData; - int cookieDataLen; - int newServerSSL; - int newServerReady; - int isMigrating; - HANDLE hPacketRecver; - int bReinitRecver; - int bMyAvatarInited; -// - HANDLE hDirectBoundPort; -// - HANDLE hKeepAliveEvent; -}; - -/*---------* Functions *---------------*/ - -void icq_serverDisconnect(BOOL bBlock); -void icq_login(const char *szPassword); - -int IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel); - - -#endif /* __ICQ_SERVER_H */ diff --git a/protocols/IcqOscarJ/icq_servlist.cpp b/protocols/IcqOscarJ/icq_servlist.cpp deleted file mode 100644 index b2adc4831c..0000000000 --- a/protocols/IcqOscarJ/icq_servlist.cpp +++ /dev/null @@ -1,2829 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Functions that handles list of used server IDs, sends low-level packets for SSI information -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -// SERVER-LIST UPDATE BOARD -// - -void CIcqProto::servlistBeginOperation(int operationCount, int bImport) -{ - if (operationCount) - { // check if we should send operation begin packet - if (!servlistEditCount) - icq_sendServerBeginOperation(bImport); - // update count of active operations - servlistEditCount += operationCount; -#ifdef _DEBUG - NetLog_Server("Server-List: Begin operation processed (%d operations active)", servlistEditCount); -#endif - } -} - -void CIcqProto::servlistEndOperation(int operationCount) -{ - if (operationCount) - { - if (operationCount > servlistEditCount) - { // sanity check - NetLog_Server("Error: Server-List End operation is not paired!"); - operationCount = servlistEditCount; - } - // update count of active operations - servlistEditCount -= operationCount; - // check if we should send operation end packet - if (!servlistEditCount) - icq_sendServerEndOperation(); -#ifdef _DEBUG - NetLog_Server("Server-List: End operation processed (%d operations active)", servlistEditCount); -#endif - } -} - -void __cdecl CIcqProto::servlistQueueThread(void *param) -{ - int* queueState = ( int* )param; - -#ifdef _DEBUG - NetLog_Server("Server-List: Starting Update board."); -#endif - - SleepEx(50, FALSE); - // handle server-list requests queue - servlistQueueMutex->Enter(); - while (servlistQueueCount) - { - ssiqueueditems* pItem = NULL; - int bItemDouble; - WORD wItemAction; - icq_packet groupPacket = {0}; - icq_packet groupPacket2 = {0}; - cookie_servlist_action* pGroupCookie = NULL; - int nEndOperations; - - // first check if the state is calm - while (*queueState) - { - int i; - time_t tNow = time(NULL); - int bFound = FALSE; - - for (i = 0; i < servlistQueueCount; i++) - { // check if we do not have some expired items to handle, otherwise keep sleeping - if ((servlistQueueList[i]->tAdded + servlistQueueList[i]->dwTimeout) < tNow) - { // got expired item, stop sleep even when changes goes on - bFound = TRUE; - break; - } - } - if (bFound) break; - // reset queue state, keep sleeping - *queueState = FALSE; - servlistQueueMutex->Leave(); - SleepEx(100, TRUE); - servlistQueueMutex->Enter(); - } - if (!icqOnline()) - { // do not try to send packets if offline - servlistQueueMutex->Leave(); - SleepEx(100, TRUE); - servlistQueueMutex->Enter(); - continue; - } -#ifdef _DEBUG - NetLog_Server("Server-List: %d items in queue.", servlistQueueCount); -#endif - // take the oldest item (keep the board FIFO) - pItem = servlistQueueList[0]; // take first (queue contains at least one item here) - wItemAction = (WORD)(pItem->pItems[0]->dwOperation & SSOF_ACTIONMASK); - bItemDouble = pItem->pItems[0]->dwOperation & SSOG_DOUBLE; - // check item rate - too high -> sleep - m_ratesMutex->Enter(); - { - WORD wRateGroup = m_rates->getGroupFromSNAC(ICQ_LISTS_FAMILY, wItemAction); - int nRateLevel = bItemDouble ? RML_IDLE_30 : RML_IDLE_10; - - while (m_rates->getNextRateLevel(wRateGroup) < m_rates->getLimitLevel(wRateGroup, nRateLevel)) - { // the rate is higher, keep sleeping - int nDelay = m_rates->getDelayToLimitLevel(wRateGroup, nRateLevel); - - m_ratesMutex->Leave(); - // do not keep the queue frozen - servlistQueueMutex->Leave(); - if (nDelay < 10) nDelay = 10; -#ifdef _DEBUG - NetLog_Server("Server-List: Delaying %dms [Rates]", nDelay); -#endif - SleepEx(nDelay, FALSE); - // check if the rate is now ok - servlistQueueMutex->Enter(); - m_ratesMutex->Enter(); - } - } - m_ratesMutex->Leave(); - { // setup group packet(s) & cookie - int totalSize = 0; - int i; - cookie_servlist_action *pGroupCookie; - DWORD dwGroupCookie; - // determine the total size of the packet - for(i = 0; i < pItem->nItems; i++) - totalSize += pItem->pItems[i]->packet.wLen - 0x10; - - // process begin & end operation flags - { - int bImportOperation = FALSE; - int nBeginOperations = 0; - - nEndOperations = 0; - for(i = 0; i < pItem->nItems; i++) - { // collect begin & end operation flags - if (pItem->pItems[i]->dwOperation & SSOF_BEGIN_OPERATION) - nBeginOperations++; - if (pItem->pItems[i]->dwOperation & SSOF_END_OPERATION) - nEndOperations++; - // check if the operation is import - if (pItem->pItems[i]->dwOperation & SSOF_IMPORT_OPERATION) - bImportOperation = TRUE; - } - // really begin operation if requested - if (nBeginOperations) - servlistBeginOperation(nBeginOperations, bImportOperation); - } - - if (pItem->nItems > 1) - { // pack all packet's data, create group cookie - pGroupCookie = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - pGroupCookie->dwAction = SSA_ACTION_GROUP; - pGroupCookie->dwGroupCount = pItem->nItems; - pGroupCookie->pGroupItems = (cookie_servlist_action**)SAFE_MALLOC(pItem->nItems * sizeof(cookie_servlist_action*)); - for (i = 0; i < pItem->nItems; i++) - { // build group cookie data - assign cookies datas - pGroupCookie->pGroupItems[i] = pItem->pItems[i]->cookie; - // release the separate cookie id - FreeCookieByData(CKT_SERVERLIST, pItem->pItems[i]->cookie); - } - // allocate cookie id - dwGroupCookie = AllocateCookie(CKT_SERVERLIST, wItemAction, 0, pGroupCookie); - // prepare packet data - serverPacketInit(&groupPacket, (WORD)(totalSize + 0x0A)); // FLAP size added inside - packFNACHeader(&groupPacket, ICQ_LISTS_FAMILY, wItemAction, 0, dwGroupCookie); - for (i = 0; i < pItem->nItems; i++) - packBuffer(&groupPacket, pItem->pItems[i]->packet.pData + 0x10, (WORD)(pItem->pItems[i]->packet.wLen - 0x10)); - - if (bItemDouble) - { // prepare second packet - wItemAction = ((servlistgroupitemdouble*)(pItem->pItems[0]))->wAction2; - totalSize = 0; - // determine the total size of the packet - for(i = 0; i < pItem->nItems; i++) - totalSize += ((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.wLen - 0x10; - - pGroupCookie = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - pGroupCookie->dwAction = SSA_ACTION_GROUP; - pGroupCookie->dwGroupCount = pItem->nItems; - pGroupCookie->pGroupItems = (cookie_servlist_action**)SAFE_MALLOC(pItem->nItems * sizeof(cookie_servlist_action*)); - for (i = 0; i < pItem->nItems; i++) - pGroupCookie->pGroupItems[i] = pItem->pItems[i]->cookie; - // allocate cookie id - dwGroupCookie = AllocateCookie(CKT_SERVERLIST, wItemAction, 0, pGroupCookie); - // prepare packet data - serverPacketInit(&groupPacket2, (WORD)(totalSize + 0x0A)); // FLAP size added inside - packFNACHeader(&groupPacket2, ICQ_LISTS_FAMILY, wItemAction, 0, dwGroupCookie); - for (i = 0; i < pItem->nItems; i++) - packBuffer(&groupPacket2, ((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.pData + 0x10, (WORD)(((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.wLen - 0x10)); - } - } - else - { // just send the one packet, do not create action group - pGroupCookie = pItem->pItems[0]->cookie; - memcpy(&groupPacket, &pItem->pItems[0]->packet, sizeof(icq_packet)); - if (bItemDouble) - memcpy(&groupPacket2, &((servlistgroupitemdouble*)(pItem->pItems[0]))->packet2, sizeof(icq_packet)); - } - - { // remove grouped item from queue & release grouped item - servlistQueueCount--; - servlistQueueList[0] = servlistQueueList[servlistQueueCount]; - - for (i = 0; i < pItem->nItems; i++) - { // release memory - if (pItem->nItems > 1) - { // free the packet only if we created the group packet - SAFE_FREE((void**)&pItem->pItems[i]->packet.pData); - if (pItem->pItems[i]->dwOperation & SSOG_DOUBLE) - SAFE_FREE((void**)&((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.pData); - } - SAFE_FREE((void**)&pItem->pItems[i]); - break; - } - SAFE_FREE((void**)&pItem); - // resize the queue - if (servlistQueueSize > servlistQueueCount + 6) - { - servlistQueueSize -= 4; - servlistQueueList = (ssiqueueditems**)SAFE_REALLOC(servlistQueueList, servlistQueueSize * sizeof(ssiqueueditems*)); - } - } - } - servlistQueueMutex->Leave(); - // send group packet - sendServPacket(&groupPacket); - // send second group packet (if present) - if (bItemDouble) - sendServPacket(&groupPacket2); - // process end operation marks - if (nEndOperations) - servlistEndOperation(nEndOperations); - // loose the loop a bit - SleepEx(100, TRUE); - servlistQueueMutex->Enter(); - } - // clean-up thread - CloseHandle(servlistQueueThreadHandle); - servlistQueueThreadHandle = NULL; - servlistQueueMutex->Leave(); -#ifdef _DEBUG - NetLog_Server("Server-List: Update Board ending."); -#endif -} - -void CIcqProto::servlistQueueAddGroupItem(servlistgroupitem* pGroupItem, int dwTimeout) -{ - icq_lock l(servlistQueueMutex); - - { // add the packet to queue - DWORD dwMark = pGroupItem->dwOperation & SSOF_GROUPINGMASK; - ssiqueueditems* pItem = NULL; - - // try to find compatible item - for (int i = 0; i < servlistQueueCount; i++) - { - if ((servlistQueueList[i]->pItems[0]->dwOperation & SSOF_GROUPINGMASK) == dwMark && servlistQueueList[i]->nItems < MAX_SERVLIST_PACKET_ITEMS) - { // found compatible item, check if it does not contain operation for the same server-list item - pItem = servlistQueueList[i]; - - for (int j = 0; j < pItem->nItems; j++) - if (pItem->pItems[j]->cookie->wContactId == pGroupItem->cookie->wContactId && - pItem->pItems[j]->cookie->wGroupId == pGroupItem->cookie->wGroupId) - { - pItem = NULL; - break; - } - // cannot send two operations for the same server-list record in one packet, look for another - if (!pItem) continue; - -#ifdef _DEBUG - NetLog_Server("Server-List: Adding packet to item #%d with operation %x.", i, servlistQueueList[i]->pItems[0]->dwOperation); -#endif - break; - } - } - if (!pItem) - { // compatible item was not found, create new one, add to queue - pItem = (ssiqueueditems*)SAFE_MALLOC(sizeof(ssiqueueditems)); - pItem->tAdded = time(NULL); - pItem->dwTimeout = dwTimeout; - - if (servlistQueueCount == servlistQueueSize) - { // resize the queue - it is too small - servlistQueueSize += 4; - servlistQueueList = (ssiqueueditems**)SAFE_REALLOC(servlistQueueList, servlistQueueSize * sizeof(ssiqueueditems*)); - } - // really add to queue - servlistQueueList[servlistQueueCount++] = pItem; -#ifdef _DEBUG - NetLog_Server("Server-List: Adding new item to queue."); -#endif - } - else if (pItem->dwTimeout > dwTimeout) - { // if the timeout of currently added packet is shorter, update the previous one - pItem->dwTimeout = dwTimeout; - } - // add GroupItem to queueditems (pItem) - pItem->pItems[pItem->nItems++] = pGroupItem; - } - // wake up board thread (keep sleeping or start new one) - if (!servlistQueueThreadHandle) - { - // create new board thread - servlistQueueThreadHandle = ForkThreadEx( &CIcqProto::servlistQueueThread, &servlistQueueState ); - } - else // signal thread, that queue was changed during sleep - servlistQueueState = TRUE; -} - -int CIcqProto::servlistHandlePrimitives(DWORD dwOperation) -{ - if (dwOperation & SSO_BEGIN_OPERATION) - { // operation starting, no action ready yet - servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); - return TRUE; - } - else if (dwOperation & SSO_END_OPERATION) - { // operation ending without action - servlistEndOperation(1); - return TRUE; - } - - return FALSE; -} - -void CIcqProto::servlistPostPacket(icq_packet* packet, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout) -{ - cookie_servlist_action* pCookie; - - if (servlistHandlePrimitives(dwOperation)) - return; - - if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) - return; // invalid cookie - - if (dwOperation & SSOF_SEND_DIRECTLY) - { // send directly - this is for some special cases - // begin operation if requested - if (dwOperation & SSOF_BEGIN_OPERATION) - servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); - - // send the packet - sendServPacket(packet); - - // end operation if requested - if (dwOperation & SSOF_END_OPERATION) - servlistEndOperation(1); - } - else - { // add to server-list update board - servlistgroupitem* pGroupItem; - - // prepare group item - pGroupItem = (servlistgroupitem*)SAFE_MALLOC(sizeof(servlistgroupitem)); - pGroupItem->dwOperation = dwOperation; - pGroupItem->cookie = pCookie; - // packet data are alloced, keep them until they are sent - memcpy(&pGroupItem->packet, packet, sizeof(icq_packet)); - - servlistQueueAddGroupItem(pGroupItem, dwTimeout); - } -} - -void CIcqProto::servlistPostPacketDouble(icq_packet* packet1, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout, icq_packet* packet2, WORD wAction2) -{ - cookie_servlist_action* pCookie; - - if (servlistHandlePrimitives(dwOperation)) - return; - - if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) - return; // invalid cookie - - if (dwOperation & SSOF_SEND_DIRECTLY) - { // send directly - this is for some special cases - // begin operation if requested - if (dwOperation & SSOF_BEGIN_OPERATION) - servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); - - // send the packets - sendServPacket(packet1); - sendServPacket(packet2); - - // end operation if requested - if (dwOperation & SSOF_END_OPERATION) - servlistEndOperation(1); - } - else - { // add to server-list update board - servlistgroupitemdouble* pGroupItem; - - // prepare group item - pGroupItem = (servlistgroupitemdouble*)SAFE_MALLOC(sizeof(servlistgroupitemdouble)); - pGroupItem->dwOperation = dwOperation; - pGroupItem->cookie = pCookie; - pGroupItem->wAction2 = wAction2; - // packets data are alloced, keep them until they are sent - memcpy(&pGroupItem->packet, packet1, sizeof(icq_packet)); - memcpy(&pGroupItem->packet2, packet2, sizeof(icq_packet)); - - servlistQueueAddGroupItem((servlistgroupitem*)pGroupItem, dwTimeout); - } -} - -void CIcqProto::servlistProcessLogin() -{ - // reset edit state counter - servlistEditCount = 0; - - /// TODO: preserve queue state in DB! restore here! - - // if the server-list queue contains items and thread is not running, start it - if (servlistQueueCount && !servlistQueueThreadHandle) - servlistQueueThreadHandle = ForkThreadEx( &CIcqProto::servlistQueueThread, &servlistQueueState ); -} - -// HERE ENDS SERVER-LIST UPDATE BOARD IMPLEMENTATION // -/////////////////////////////////////////////////////// -//===================================================// - -// PENDING SERVER-LIST OPERATIONS -// -#define ITEM_PENDING_CONTACT 0x01 -#define ITEM_PENDING_GROUP 0x02 - -#define CALLBACK_RESULT_CONTINUE 0x00 -#define CALLBACK_RESULT_POSTPONE 0x0D -#define CALLBACK_RESULT_PURGE 0x10 - - -#define SPOF_AUTO_CREATE_ITEM 0x01 - -int CIcqProto::servlistPendingFindItem(int nType, HANDLE hContact, const char *pszGroup) -{ - if (servlistPendingList) - for (int i = 0; i < servlistPendingCount; i++) - if (servlistPendingList[i]->nType == nType) - { - if (((nType == ITEM_PENDING_CONTACT) && (servlistPendingList[i]->hContact == hContact)) || - ((nType == ITEM_PENDING_GROUP) && (!strcmpnull(servlistPendingList[i]->szGroup, pszGroup)))) - return i; - } - return -1; -} - - -void CIcqProto::servlistPendingAddItem(servlistpendingitem *pItem) -{ - if (servlistPendingCount >= servlistPendingSize) // add new - { - servlistPendingSize += 10; - servlistPendingList = (servlistpendingitem**)SAFE_REALLOC(servlistPendingList, servlistPendingSize * sizeof(servlistpendingitem*)); - } - - servlistPendingList[servlistPendingCount++] = pItem; -} - - -servlistpendingitem* CIcqProto::servlistPendingRemoveItem(int nType, HANDLE hContact, const char *pszGroup) -{ // unregister pending item, trigger pending operations - int iItem; - servlistpendingitem *pItem = NULL; - - icq_lock l(servlistMutex); - - if ((iItem = servlistPendingFindItem(nType, hContact, pszGroup)) != -1) - { // found, remove from the pending list - pItem = servlistPendingList[iItem]; - - servlistPendingList[iItem] = servlistPendingList[--servlistPendingCount]; - - if (servlistPendingCount + 10 < servlistPendingSize) - { - servlistPendingSize -= 5; - servlistPendingList = (servlistpendingitem**)SAFE_REALLOC(servlistPendingList, servlistPendingSize * sizeof(servlistpendingitem*)); - } - // was the first operation was created automatically to postpone ItemAdd? - if (pItem->operations && pItem->operations[0].flags & SPOF_AUTO_CREATE_ITEM) - { // yes, add new item - servlistpendingitem *pNewItem = (servlistpendingitem*)SAFE_MALLOC(sizeof(servlistpendingitem)); - - if (pNewItem) - { // move the remaining operations -#ifdef _DEBUG - if (pItem->nType == ITEM_PENDING_CONTACT) - NetLog_Server("Server-List: Resuming contact %x operation.", pItem->hContact); - else - NetLog_Server("Server-List: Resuming group \"%s\" operation.", pItem->szGroup); -#endif - - pNewItem->nType = pItem->nType; - pNewItem->hContact = pItem->hContact; - pNewItem->szGroup = null_strdup(pItem->szGroup); - pNewItem->wContactID = pItem->wContactID; - pNewItem->wGroupID = pItem->wGroupID; - pNewItem->operationsCount = pItem->operationsCount - 1; - pNewItem->operations = (servlistpendingoperation*)SAFE_MALLOC(pNewItem->operationsCount * sizeof(servlistpendingoperation)); - memcpy(pNewItem->operations, pItem->operations + 1, pNewItem->operationsCount * sizeof(servlistpendingoperation)); - pItem->operationsCount = 1; - - servlistPendingAddItem(pNewItem); - // clear the flag - pItem->operations[0].flags &= ~SPOF_AUTO_CREATE_ITEM; - } - } - } -#ifdef _DEBUG - else - NetLog_Server("Server-List Error: Trying to remove non-existing pending %s.", nType == ITEM_PENDING_CONTACT ? "contact" : "group"); -#endif - - return pItem; -} - - -void CIcqProto::servlistPendingAddContactOperation(HANDLE hContact, LPARAM param, PENDING_CONTACT_CALLBACK callback, DWORD flags) -{ // add postponed operation (add contact, update contact, regroup resume, etc.) - // - after contact is added - int iItem; - servlistpendingitem *pItem = NULL; - - icq_lock l(servlistMutex); - - if ((iItem = servlistPendingFindItem(ITEM_PENDING_CONTACT, hContact, NULL)) != -1) - pItem = servlistPendingList[iItem]; - - if (pItem) - { - int iOperation = pItem->operationsCount++; - - pItem->operations = (servlistpendingoperation*)SAFE_REALLOC(pItem->operations, pItem->operationsCount * sizeof(servlistpendingoperation)); - pItem->operations[iOperation].param = param; - pItem->operations[iOperation].callback = (PENDING_GROUP_CALLBACK)callback; - pItem->operations[iOperation].flags = flags; - } - else - { - NetLog_Server("Server-List Error: Trying to add pending operation to a non existing contact."); - } -} - - -void CIcqProto::servlistPendingAddGroupOperation(const char *pszGroup, LPARAM param, PENDING_GROUP_CALLBACK callback, DWORD flags) -{ // add postponed operation - after group is added - int iItem; - servlistpendingitem *pItem = NULL; - - icq_lock l(servlistMutex); - - if ((iItem = servlistPendingFindItem(ITEM_PENDING_GROUP, NULL, pszGroup)) != -1) - pItem = servlistPendingList[iItem]; - - if (pItem) - { - int iOperation = pItem->operationsCount++; - - pItem->operations = (servlistpendingoperation*)SAFE_REALLOC(pItem->operations, pItem->operationsCount * sizeof(servlistpendingoperation)); - pItem->operations[iOperation].param = param; - pItem->operations[iOperation].callback = callback; - pItem->operations[iOperation].flags = flags; - } - else - { - NetLog_Server("Server-List Error: Trying to add pending operation to a non existing group."); - } -} - - -int CIcqProto::servlistPendingAddContact(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM param, PENDING_CONTACT_CALLBACK callback, int bDoInline, LPARAM operationParam, PENDING_CONTACT_CALLBACK operationCallback) -{ - int iItem; - servlistpendingitem *pItem = NULL; - - servlistMutex->Enter(); - - if ((iItem = servlistPendingFindItem(ITEM_PENDING_CONTACT, hContact, NULL)) != -1) - pItem = servlistPendingList[iItem]; - - if (pItem) - { -#ifdef _DEBUG - NetLog_Server("Server-List: Pending contact %x already in list; adding as operation.", hContact); -#endif - servlistPendingAddContactOperation(hContact, param, callback, SPOF_AUTO_CREATE_ITEM); - - if (operationCallback) - servlistPendingAddContactOperation(hContact, operationParam, operationCallback, 0); - - servlistMutex->Leave(); - - return 0; // Pending - } - -#ifdef _DEBUG - NetLog_Server("Server-List: Starting contact %x operation.", hContact); -#endif - - pItem = (servlistpendingitem *)SAFE_MALLOC(sizeof(servlistpendingitem)); - pItem->nType = ITEM_PENDING_CONTACT; - pItem->hContact = hContact; - pItem->wContactID = wContactID; - pItem->wGroupID = wGroupID; - - servlistPendingAddItem(pItem); - - if (operationCallback) - servlistPendingAddContactOperation(hContact, operationParam, operationCallback, 0); - - servlistMutex->Leave(); - - if (bDoInline) - { // not postponed, called directly if requested - (this->*callback)(hContact, wContactID, wGroupID, param, PENDING_RESULT_INLINE); - } - - return 1; // Ready -} - - -int CIcqProto::servlistPendingAddGroup(const char *pszGroup, WORD wGroupID, LPARAM param, PENDING_GROUP_CALLBACK callback, int bDoInline, LPARAM operationParam, PENDING_GROUP_CALLBACK operationCallback) -{ - int iItem; - servlistpendingitem *pItem = NULL; - - servlistMutex->Enter(); - - if ((iItem = servlistPendingFindItem(ITEM_PENDING_GROUP, NULL, pszGroup)) != -1) - pItem = servlistPendingList[iItem]; - - if (pItem) - { -#ifdef _DEBUG - NetLog_Server("Server-List: Pending group \"%s\" already in list; adding as operation.", pszGroup); -#endif - servlistPendingAddGroupOperation(pszGroup, param, callback, SPOF_AUTO_CREATE_ITEM); - - if (operationCallback) - servlistPendingAddGroupOperation(pszGroup, operationParam, operationCallback, 0); - - servlistMutex->Leave(); - - return 0; // Pending - } - -#ifdef _DEBUG - NetLog_Server("Server-List: Starting group \"%s\" operation.", pszGroup); -#endif - - pItem = (servlistpendingitem *)SAFE_MALLOC(sizeof(servlistpendingitem)); - pItem->nType = ITEM_PENDING_GROUP; - pItem->szGroup = null_strdup(pszGroup); - pItem->wGroupID = wGroupID; - - servlistPendingAddItem(pItem); - - if (operationCallback) - servlistPendingAddGroupOperation(pszGroup, operationParam, operationCallback, 0); - - servlistMutex->Leave(); - - if (bDoInline) - { // not postponed, called directly if requested - (this->*callback)(pszGroup, wGroupID, param, PENDING_RESULT_INLINE); - } - - return 1; // Ready -} - - -void CIcqProto::servlistPendingRemoveContact(HANDLE hContact, WORD wContactID, WORD wGroupID, int nResult) -{ -#ifdef _DEBUG - NetLog_Server("Server-List: %s contact %x operation.", (nResult != PENDING_RESULT_PURGE) ? "Ending" : "Purging", hContact); -#endif - - servlistpendingitem *pItem = servlistPendingRemoveItem(ITEM_PENDING_CONTACT, hContact, NULL); - - if (pItem) - { // process pending operations - if (pItem->operations) - { - for (int i = 0; i < pItem->operationsCount; i++) - { - int nCallbackState = (this->*(PENDING_CONTACT_CALLBACK)(pItem->operations[i].callback))(hContact, wContactID, wGroupID, pItem->operations[i].param, nResult); - - if (nResult != PENDING_RESULT_PURGE && nCallbackState == CALLBACK_RESULT_POSTPONE) - { // any following pending operations cannot be processed now, move them to the new pending contact - for (int j = i + 1; j < pItem->operationsCount; j++) - servlistPendingAddContactOperation(hContact, pItem->operations[j].param, (PENDING_CONTACT_CALLBACK)(pItem->operations[j].callback), pItem->operations[j].flags); - break; - } - else if (nCallbackState == CALLBACK_RESULT_PURGE) - { // purge all following operations - fatal failure occured - nResult = PENDING_RESULT_PURGE; - } - } - SAFE_FREE((void**)&pItem->operations); - } - // release item's memory - SAFE_FREE((void**)&pItem); - } - else - NetLog_Server("Server-List Error: Trying to remove a non existing pending contact."); -} - - -void CIcqProto::servlistPendingRemoveGroup(const char *pszGroup, WORD wGroupID, int nResult) -{ -#ifdef _DEBUG - NetLog_Server("Server-List: %s group \"%s\" operation.", (nResult != PENDING_RESULT_PURGE) ? "Ending" : "Purging", pszGroup); -#endif - - servlistpendingitem *pItem = servlistPendingRemoveItem(ITEM_PENDING_GROUP, NULL, pszGroup); - - if (pItem) - { // process pending operations - if (pItem->operations) - { - for (int i = 0; i < pItem->operationsCount; i++) - { - int nCallbackState = (this->*pItem->operations[i].callback)(pItem->szGroup, wGroupID, pItem->operations[i].param, nResult); - - if (nResult != PENDING_RESULT_PURGE && nCallbackState == CALLBACK_RESULT_POSTPONE) - { // any following pending operations cannot be processed now, move them to the new pending group - for (int j = i + 1; j < pItem->operationsCount; j++) - servlistPendingAddGroupOperation(pItem->szGroup, pItem->operations[j].param, pItem->operations[j].callback, pItem->operations[j].flags); - break; - } - else if (nCallbackState == CALLBACK_RESULT_PURGE) - { // purge all following operations - fatal failure occured - nResult = PENDING_RESULT_PURGE; - } - } - SAFE_FREE((void**)&pItem->operations); - } - // release item's memory - SAFE_FREE((void**)&pItem->szGroup); - SAFE_FREE((void**)&pItem); - } - else - NetLog_Server("Server-List Error: Trying to remove a non existing pending group."); -} - - -// Remove All pending operations -void CIcqProto::servlistPendingFlushOperations() -{ - icq_lock l(servlistMutex); - - for (int i = servlistPendingCount; i; i--) - { // purge all items - servlistpendingitem *pItem = servlistPendingList[i - 1]; - - if (pItem->nType == ITEM_PENDING_CONTACT) - servlistPendingRemoveContact(pItem->hContact, 0, 0, PENDING_RESULT_PURGE); - else if (pItem->nType == ITEM_PENDING_GROUP) - servlistPendingRemoveGroup(pItem->szGroup, 0, PENDING_RESULT_PURGE); - } - // release the list completely - SAFE_FREE((void**)&servlistPendingList); - servlistPendingCount = 0; - servlistPendingSize = 0; -} - -// END OF SERVER-LIST PENDING OPERATIONS -//// - - -// used for adding new contacts to list - sync with visible items -void CIcqProto::AddJustAddedContact(HANDLE hContact) -{ - icq_lock l(servlistMutex); - - if (nJustAddedCount >= nJustAddedSize) - { - nJustAddedSize += 10; - pdwJustAddedList = (HANDLE*)SAFE_REALLOC(pdwJustAddedList, nJustAddedSize * sizeof(HANDLE)); - } - - pdwJustAddedList[nJustAddedCount] = hContact; - nJustAddedCount++; -} - - -// was the contact added during this serv-list load -BOOL CIcqProto::IsContactJustAdded(HANDLE hContact) -{ - icq_lock l(servlistMutex); - - if (pdwJustAddedList) - { - for (int i = 0; iEnter(); - if (nServerIDListCount >= nServerIDListSize) - { - nServerIDListSize += 100; - pdwServerIDList = (DWORD*)SAFE_REALLOC(pdwServerIDList, nServerIDListSize * sizeof(DWORD)); - } - - pdwServerIDList[nServerIDListCount] = wID | (bGroupType & 0x00FF0000) | (bFlags & 0xFF000000); - nServerIDListCount++; - servlistMutex->Leave(); - - if (!bIsSyncingCL) - StoreServerIDs(); -} - - -// Remove a server ID from the list of reserved IDs. -// Used for deleting contacts and other modifications. -void CIcqProto::FreeServerID(WORD wID, int bGroupType) -{ - DWORD dwId = wID | (bGroupType & 0x00FF0000); - - icq_lock l(servlistMutex); - - if (pdwServerIDList) - { - for (int i = 0; i= wID) && ((pdwServerIDList[i] & 0xFFFF) <= wID + wCount)) - return TRUE; - } - } - - return FALSE; -} - -void CIcqProto::FlushServerIDs() -{ - icq_lock l(servlistMutex); - - SAFE_FREE((void**)&pdwServerIDList); - nServerIDListCount = 0; - nServerIDListSize = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct GroupReserveIdsEnumParam -{ - CIcqProto *ppro; - char *szModule; -}; - -static int GroupReserveIdsEnumProc(const char *szSetting,LPARAM lParam) -{ - if (szSetting && strlennull(szSetting)<5) - { - // it is probably server group - GroupReserveIdsEnumParam *param = (GroupReserveIdsEnumParam*)lParam; - char val[MAX_PATH+2]; // dummy - - DBVARIANT dbv = {DBVT_DELETED}; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = val; - dbv.cchVal = MAX_PATH; - - DBCONTACTGETSETTING cgs; - cgs.szModule = param->szModule; - cgs.szSetting = szSetting; - cgs.pValue = &dbv; - if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) - { // we failed to read setting, try also utf8 - DB bug - dbv.type = DBVT_UTF8; - dbv.pszVal = val; - dbv.cchVal = MAX_PATH; - if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) - return 0; // we failed also, invalid setting - } - if (dbv.type != DBVT_ASCIIZ) - { // it is not a cached server-group name - return 0; - } - param->ppro->ReserveServerID((WORD)strtoul(szSetting, NULL, 0x10), SSIT_GROUP, 0); -#ifdef _DEBUG - param->ppro->NetLog_Server("Loaded group %u:'%s'", strtoul(szSetting, NULL, 0x10), val); -#endif - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Load all known server IDs from DB to list -void CIcqProto::LoadServerIDs() -{ - WORD wSrvID; - int nGroups = 0, nContacts = 0, nPermits = 0, nDenys = 0, nIgnores = 0, nUnhandled = 0; - - servlistMutex->Enter(); - if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) - ReserveServerID(wSrvID, SSIT_ITEM, 0); - if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, 0)) - ReserveServerID(wSrvID, SSIT_ITEM, 0); - if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0)) - ReserveServerID(wSrvID, SSIT_ITEM, 0); - if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, 0)) - ReserveServerID(wSrvID, SSIT_ITEM, 0); - if (wSrvID = getSettingWord(NULL, "SrvImportID", 0)) - ReserveServerID(wSrvID, SSIT_ITEM, 0); - - DBCONTACTENUMSETTINGS dbces; - int nStart = nServerIDListCount; - - char szModule[MAX_PATH]; - null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); - - GroupReserveIdsEnumParam param = { this, szModule }; - dbces.pfnEnumProc = &GroupReserveIdsEnumProc; - dbces.szModule = szModule; - dbces.lParam = (LPARAM)¶m; - CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); - - nGroups = nServerIDListCount - nStart; - - HANDLE hContact = FindFirstContact(); - - while (hContact) - { // search all our contacts, reserve their server IDs - if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) - { - ReserveServerID(wSrvID, SSIT_ITEM, 0); - nContacts++; - } - if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0)) - { - ReserveServerID(wSrvID, SSIT_ITEM, 0); - nDenys++; - } - if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0)) - { - ReserveServerID(wSrvID, SSIT_ITEM, 0); - nPermits++; - } - if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) - { - ReserveServerID(wSrvID, SSIT_ITEM, 0); - nIgnores++; - } - - hContact = FindNextContact(hContact); - } - servlistMutex->Leave(); - - DBVARIANT dbv = {0}; - if (!getSetting(NULL, DBSETTING_SERVLIST_UNHANDLED, &dbv)) - { - int dataLen = dbv.cpbVal; - BYTE *pData = dbv.pbVal; - - while (dataLen >= 4) - { - BYTE bGroupType; - BYTE bFlags; - - unpackLEWord(&pData, &wSrvID); - unpackByte(&pData, &bGroupType); - unpackByte(&pData, &bFlags); - - ReserveServerID(wSrvID, bGroupType, bFlags); - dataLen -= 4; - nUnhandled++; - } - - ICQFreeVariant(&dbv); - } - - NetLog_Server("Loaded SSI: %d contacts, %d groups, %d permit, %d deny, %d ignore, %d unknown items.", nContacts, nGroups, nPermits, nDenys, nIgnores, nUnhandled); -} - - -void CIcqProto::StoreServerIDs() /// TODO: allow delayed -{ - BYTE *pUnhandled = NULL; - int cbUnhandled = 0; - - servlistMutex->Enter(); - if (pdwServerIDList) - for (int i = 0; i> 0x10); - ppackByte(&pUnhandled, &cbUnhandled, (pdwServerIDList[i] & 0xFF000000) >> 0x18); - } - servlistMutex->Leave(); - - if (pUnhandled) - setSettingBlob(NULL, DBSETTING_SERVLIST_UNHANDLED, pUnhandled, cbUnhandled); - else - deleteSetting(NULL, DBSETTING_SERVLIST_UNHANDLED); - - SAFE_FREE((void**)&pUnhandled); -} - - -// Generate server ID with wCount IDs free after it, for sub-groups. -WORD CIcqProto::GenerateServerID(int bGroupType, int bFlags, int wCount) -{ - WORD wId; - - while (TRUE) - { - // Randomize a new ID - // Max value is probably 0x7FFF, lowest value is probably 0x0001 (generated by Icq2Go) - // We use range 0x1000-0x7FFF. - wId = (WORD)RandRange(0x1000, 0x7FFF); - - if (!CheckServerID(wId, wCount)) - break; - } - - ReserveServerID(wId, bGroupType, bFlags); - - return wId; -} - - -/*********************************************** -* -* --- Low-level packet sending functions --- -* -*/ - -struct doubleServerItemObject -{ - WORD wAction; - icq_packet packet; -}; - -DWORD CIcqProto::icq_sendServerItem(DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wItemId, const char *szName, BYTE *pTLVs, int nTlvLength, WORD wItemType, DWORD dwOperation, DWORD dwTimeout, void **doubleObject) -{ // generic packet - icq_packet packet; - int nNameLen; - WORD wTLVlen = (WORD)nTlvLength; - - // Prepare item name length - nNameLen = strlennull(szName); - - // Build the packet - serverPacketInit(&packet, (WORD)(nNameLen + 20 + wTLVlen)); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, wAction, 0, dwCookie); - packWord(&packet, (WORD)nNameLen); - if (nNameLen) - packBuffer(&packet, (LPBYTE)szName, (WORD)nNameLen); - packWord(&packet, wGroupId); - packWord(&packet, wItemId); - packWord(&packet, wItemType); - packWord(&packet, wTLVlen); - if (wTLVlen) - packBuffer(&packet, pTLVs, wTLVlen); - - if (!doubleObject) - { // Send the packet and return the cookie - servlistPostPacket(&packet, dwCookie, dwOperation | wAction, dwTimeout); - } - else - { - if (*doubleObject) - { // Send both packets and return the cookie - doubleServerItemObject* helper = (doubleServerItemObject*)*doubleObject; - - servlistPostPacketDouble(&helper->packet, dwCookie, dwOperation | helper->wAction, dwTimeout, &packet, wAction); - SAFE_FREE(doubleObject); - } - else - { // Create helper object, return the cookie - doubleServerItemObject* helper = (doubleServerItemObject*)SAFE_MALLOC(sizeof(doubleServerItemObject)); - - if (helper) - { - helper->wAction = wAction; - memcpy(&helper->packet, &packet, sizeof(icq_packet)); - *doubleObject = helper; - } - else // memory alloc failed - return 0; - } - } - - // Force reload of server-list after change - setSettingWord(NULL, "SrvRecordCount", 0); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId, DWORD dwOperation, DWORD dwTimeout, void **doubleObject) -{ - DWORD dwUin; - uid_str szUid; - icq_packet pBuffer; - char *szNick = NULL, *szNote = NULL; - BYTE *pData = NULL, *pMetaToken = NULL, *pMetaTime = NULL; - int nNickLen, nNoteLen, nDataLen = 0, nMetaTokenLen = 0, nMetaTimeLen = 0; - WORD wTLVlen; - BYTE bAuth; - int bDataTooLong = FALSE; - - // Prepare UID - if (getContactUid(hContact, &dwUin, &szUid)) - { - NetLog_Server("Buddy upload failed (UID missing)."); - return 0; - } - - bAuth = getSettingByte(hContact, "Auth", 0); - szNick = getSettingStringUtf(hContact, "CList", "MyHandle", NULL); - szNote = getSettingStringUtf(hContact, "UserInfo", "MyNotes", NULL); - - DBVARIANT dbv; - - if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) - { - nMetaTokenLen = dbv.cpbVal; - pMetaToken = (BYTE*)_alloca(dbv.cpbVal); - memcpy(pMetaToken, dbv.pbVal, dbv.cpbVal); - - ICQFreeVariant(&dbv); - } - if (!getSetting(hContact, DBSETTING_METAINFO_TIME, &dbv)) - { - nMetaTimeLen = dbv.cpbVal; - pMetaTime = (BYTE*)_alloca(dbv.cpbVal); - for (int i = 0; i < dbv.cpbVal; i++) - pMetaTime[i] = dbv.pbVal[dbv.cpbVal - i - 1]; - - ICQFreeVariant(&dbv); - } - - if (!getSetting(hContact, DBSETTING_SERVLIST_DATA, &dbv)) - { // read additional server item data - nDataLen = dbv.cpbVal; - pData = (BYTE*)_alloca(nDataLen); - memcpy(pData, dbv.pbVal, nDataLen); - - ICQFreeVariant(&dbv); - } - - nNickLen = strlennull(szNick); - nNoteLen = strlennull(szNote); - - // Limit the strings - if (nNickLen > MAX_SSI_TLV_NAME_SIZE) - { - bDataTooLong = TRUE; - nNickLen = null_strcut(szNick, MAX_SSI_TLV_NAME_SIZE); - } - if (nNoteLen > MAX_SSI_TLV_COMMENT_SIZE) - { - bDataTooLong = TRUE; - nNoteLen = null_strcut(szNote, MAX_SSI_TLV_COMMENT_SIZE); - } - if (bDataTooLong) - { // Inform the user - /// TODO: do something with this for Manage Server-List dialog. - if (wAction != ICQ_LISTS_REMOVEFROMLIST) // do not report this when removing from list - icq_LogMessage(LOG_WARNING, LPGEN("The contact's information was too big and was truncated.")); - } - - // Build the packet - wTLVlen = (nNickLen?4+nNickLen:0) + (nNoteLen?4+nNoteLen:0) + (bAuth?4:0) + nDataLen + (nMetaTokenLen?4+nMetaTokenLen:0) + (nMetaTimeLen?4+nMetaTimeLen:0); - - // Initialize our handy data buffer - pBuffer.wPlace = 0; - pBuffer.pData = (BYTE *)_alloca(wTLVlen); - pBuffer.wLen = wTLVlen; - - if (nNickLen) - packTLV(&pBuffer, SSI_TLV_NAME, (WORD)nNickLen, (LPBYTE)szNick); // Nickname TLV - - if (nNoteLen) - packTLV(&pBuffer, SSI_TLV_COMMENT, (WORD)nNoteLen, (LPBYTE)szNote); // Comment TLV - - if (nMetaTokenLen) - packTLV(&pBuffer, SSI_TLV_METAINFO_TOKEN, (WORD)nMetaTokenLen, pMetaToken); - - if (nMetaTimeLen) - packTLV(&pBuffer, SSI_TLV_METAINFO_TIME, (WORD)nMetaTimeLen, pMetaTime); - - if (pData) - packBuffer(&pBuffer, pData, (WORD)nDataLen); - - if (bAuth) // icq5 gives this as last TLV - packDWord(&pBuffer, 0x00660000); // "Still waiting for auth" TLV - - SAFE_FREE((void**)&szNick); - SAFE_FREE((void**)&szNote); - - return icq_sendServerItem(dwCookie, wAction, wGroupId, wContactId, strUID(dwUin, szUid), pBuffer.pData, wTLVlen, SSI_ITEM_BUDDY, dwOperation, dwTimeout, doubleObject); -} - - -DWORD CIcqProto::icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType, DWORD dwOperation, DWORD dwTimeout) -{ // for privacy items - return icq_sendServerItem(dwCookie, wAction, wGroupId, wItemId, strUID(dwUin, szUID), NULL, 0, wItemType, dwOperation, dwTimeout, NULL); -} - - -DWORD CIcqProto::icq_sendServerGroup(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent, DWORD dwOperationFlags) -{ - WORD wTLVlen; - icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer - // I should be ashamed! ;) - - if (strlennull(szName) == 0 && wGroupId != 0) - { - NetLog_Server("Group upload failed (GroupName missing)."); - return 0; // without name we could not change the group - } - - // Calculate buffer size - wTLVlen = (cbContent?4+cbContent:0); - - // Initialize our handy data buffer - pBuffer.wPlace = 0; - pBuffer.pData = (BYTE *)_alloca(wTLVlen); - pBuffer.wLen = wTLVlen; - - if (wTLVlen) - packTLV(&pBuffer, SSI_TLV_SUBITEMS, (WORD)cbContent, (LPBYTE)pContent); // Groups TLV - - return icq_sendServerItem(dwCookie, wAction, wGroupId, 0, szName, pBuffer.pData, wTLVlen, SSI_ITEM_GROUP, SSOP_GROUP_ACTION | dwOperationFlags, 400, NULL); -} - - -DWORD CIcqProto::icq_modifyServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wAction, DWORD dwOperation, WORD wItemId, WORD wType) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - DWORD dwCookie; - - if (ack) - { - ack->dwAction = dwOperation; // remove privacy item - ack->hContact = hContact; - ack->wContactId = wItemId; - - dwCookie = AllocateCookie(CKT_SERVERLIST, wAction, hContact, ack); - } - else // cookie failed - return 0; - - return icq_sendSimpleItem(dwCookie, wAction, dwUin, szUid, 0, wItemId, wType, SSOP_ITEM_ACTION, 400); -} - - -DWORD CIcqProto::icq_removeServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType) -{ - return icq_modifyServerPrivacyItem(hContact, dwUin, szUid, ICQ_LISTS_REMOVEFROMLIST, SSA_PRIVACY_REMOVE, wItemId, wType); -} - - -DWORD CIcqProto::icq_addServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType) -{ - return icq_modifyServerPrivacyItem(hContact, dwUin, szUid, ICQ_LISTS_ADDTOLIST, SSA_PRIVACY_ADD, wItemId, wType); -} - -/***************************************** -* -* --- Contact DB Utilities --- -* -*/ - - -/// TODO: do not check by plugin version, check by ServListStructures version! -int CIcqProto::IsServerGroupsDefined() -{ - int iRes = 1; - - if (getSettingDword(NULL, "Version", 0) < 0x00030608) - { // group cache & linking data too old, flush, reload from server - char szModule[MAX_PATH]; - - // flush obsolete linking data - null_snprintf(szModule, SIZEOF(szModule), "%sGroups", m_szModuleName); - CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szModule); - - iRes = 0; // no groups defined, or older version - } - // store our current version - setSettingDword(NULL, "Version", ICQ_PLUG_VERSION & 0x00FFFFFF); - - return iRes; -} - - -void CIcqProto::FlushSrvGroupsCache() -{ - char szModule[MAX_PATH]; - - null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); - CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szModule); -} - - -// Look thru DB and collect all ContactIDs from a group -void* CIcqProto::collectBuddyGroup(WORD wGroupID, int *count) -{ - WORD* buf = NULL; - int cnt = 0; - HANDLE hContact; - WORD wItemID; - - hContact = FindFirstContact(); - - while (hContact) - { // search all contacts - if (wGroupID == getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0)) - { // add only buddys from specified group - wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); - - if (wItemID) - { // valid ID, add - cnt++; - buf = (WORD*)SAFE_REALLOC(buf, cnt*sizeof(WORD)); - buf[cnt-1] = wItemID; - if (!count) break; - } - } - - hContact = FindNextContact(hContact); - } - - if (count) - *count = cnt<<1; // we return size in bytes - return buf; -} - - -// Look thru DB and collect all GroupIDs -void* CIcqProto::collectGroups(int *count) -{ - WORD* buf = NULL; - int cnt = 0; - int i; - HANDLE hContact; - WORD wGroupID; - - hContact = FindFirstContact(); - - while (hContact) - { // search all contacts - if (wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0)) - { // add only valid IDs - for (i = 0; ipfnGetGroupName() -int CIcqProto::getCListGroupExists(const char *szGroup) -{ - int hGroup = 0; - CLIST_INTERFACE *clint = NULL; - - if (!szGroup) return 0; - - if (ServiceExists(MS_CLIST_RETRIEVE_INTERFACE)) - clint = (CLIST_INTERFACE*)CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, 0); - - if (clint && clint->version >= 1) - { // we've got clist interface, use it - int size = strlennull(szGroup) + 2; - TCHAR *tszGroup = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(szGroup, tszGroup, size)) - for (int i = 1; TRUE; i++) - { - TCHAR *tszGroupName = (TCHAR*)clint->pfnGetGroupName(i, NULL); - - if (!tszGroupName) break; - - if (!_tcscmp(tszGroup, tszGroupName)) - { // we have found the group - hGroup = i; - break; - } - } - } - else - { // old ansi version - no other way - int size = strlennull(szGroup) + 2; - char *aszGroup = (char*)_alloca(size); - - utf8_decode_static(szGroup, aszGroup, size); - - for (int i = 1; TRUE; i++) - { - char *paszGroup = (char*)CallService(MS_CLIST_GROUPGETNAME, i, 0); - - if (!paszGroup) break; - - if (!strcmpnull(aszGroup, paszGroup)) - { // we found the group - hGroup = i; - break; - } - } - } - - return hGroup; -} - - -int CIcqProto::moveContactToCListGroup(HANDLE hContact, const char *szGroup) -{ - int hGroup = getCListGroupHandle(szGroup); - - if (ServiceExists(MS_CLIST_CONTACTCHANGEGROUP)) - return CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, hGroup); - else /// TODO: is this neccessary ? - return setSettingStringUtf(hContact, "CList", "Group", szGroup); -} - - -// utility function which counts > on start of a server group name -static int countGroupNameLevel(const char *szGroupName) -{ - int nNameLen = strlennull(szGroupName); - int i = 0; - - while (i 0) - { // it is probably a sub-group locate parent group - WORD wParentGroupId = wGroupId; - int nParentGroupLevel; - - do - { // we look for parent group at the correct level - wParentGroupId--; - nParentGroupLevel = getServListGroupLevel(wParentGroupId); - } while ((nParentGroupLevel >= nGroupLevel) && (nParentGroupLevel != -1)); - - if (nParentGroupLevel == -1) - { // that was not a sub-group, it was just a group starting with > - setServListGroupLinkID(szGroup, wGroupId); - return szGroup; - } - - { // recursively determine parent group clist path - char *szParentGroup = getServListGroupCListPath(wParentGroupId); - - /// FIXME: properly handle ~N suffixes - szParentGroup = (char*)SAFE_REALLOC(szParentGroup, strlennull(szGroup) + strlennull(szParentGroup) + 2); - strcat(szParentGroup, "\\"); - strcat(szParentGroup, (char*)szGroup + nGroupLevel); - /* if (strstrnull(szGroup, "~")) - { // check if the ~ was not added to obtain unique servlist item name - char *szUniqueMark = strrchr(szParentGroup, '~'); - - *szUniqueMark = '\0'; - // not the same group without ~, return it - if (getServListGroupLinkID(szParentGroup) != wGroupId) - *szUniqueMark = '~'; - } */ /// FIXME: this is necessary, but needs group loading changes - SAFE_FREE((void**)&szGroup); - szGroup = szParentGroup; - - - if (getServListGroupLinkID(szGroup) == wGroupId) - { // known path, give - return szGroup; - } - else - { // unknown path, setup a link - setServListGroupLinkID(szGroup, wGroupId); - return szGroup; - } - } - } - else - { // normal group, setup a link - setServListGroupLinkID(szGroup, wGroupId); - return szGroup; - } - } - } - return NULL; -} - - -static int SrvGroupNamesEnumProc(const char *szSetting, LPARAM lParam) -{ // check server-group cache item - const char **params = (const char**)lParam; - CIcqProto *ppro = (CIcqProto*)params[0]; - char *szGroupName = ppro->getSettingStringUtf(NULL, params[3], szSetting, NULL); - - if (!strcmpnull(szGroupName, params[2])) - params[1] = szSetting; // do not need the real value, just arbitrary non-NULL - - SAFE_FREE(&szGroupName); - return 0; -} - -char* CIcqProto::getServListUniqueGroupName(const char *szGroupName, int bAlloced) -{ // enum ICQSrvGroups and create unique name if neccessary - DBCONTACTENUMSETTINGS dbces; - char szModule[MAX_PATH]; - char *pars[4]; - int uniqueID = 1; - char *szGroupNameBase = (char*)szGroupName; - char *szNewGroupName = NULL; - - if (!bAlloced) - szGroupNameBase = null_strdup(szGroupName); - null_strcut(szGroupNameBase, m_wServerListRecordNameMaxLength); - - null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); - - do { - pars[0] = (char*)this; - pars[1] = NULL; - pars[2] = szNewGroupName ? szNewGroupName : szGroupNameBase; - pars[3] = szModule; - - dbces.pfnEnumProc = &SrvGroupNamesEnumProc; - dbces.szModule = szModule; - dbces.lParam = (LPARAM)pars; - - CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); - - if (pars[1]) - { // the groupname already exists, create another - SAFE_FREE((void**)&szNewGroupName); - - char szUnique[10]; - _itoa(uniqueID++, szUnique, 10); - null_strcut(szGroupNameBase, m_wServerListRecordNameMaxLength - strlennull(szUnique) - 1); - szNewGroupName = (char*)SAFE_MALLOC(strlennull(szUnique) + strlennull(szGroupNameBase) + 2); - if (szNewGroupName) - { - strcpy(szNewGroupName, szGroupNameBase); - strcat(szNewGroupName, "~"); - strcat(szNewGroupName, szUnique); - } - } - } while (pars[1] && szNewGroupName); - - if (szNewGroupName) - { - SAFE_FREE(&szGroupNameBase); - return szNewGroupName; - } - if (szGroupName != szGroupNameBase) - { - SAFE_FREE(&szGroupNameBase); - return (char*)szGroupName; - } - else - return szGroupNameBase; -} - - -// this is the second part of recursive event-driven procedure -int CIcqProto::servlistCreateGroup_gotParentGroup(const char *szGroup, WORD wGroupID, LPARAM param, int nResult) -{ - cookie_servlist_action* clue = (cookie_servlist_action*)param; - char *szSubGroupName = clue->szGroupName; - char *szSubGroup; - int wSubGroupLevel = -1; - WORD wSubGroupID; - - SAFE_FREE((void**)&clue); - - if (nResult == PENDING_RESULT_PURGE) - { // only cleanup - return CALLBACK_RESULT_CONTINUE; - } - - szSubGroup = (char*)SAFE_MALLOC(strlennull(szGroup) + strlennull(szSubGroupName) + 2); - if (szSubGroup) - { - strcpy(szSubGroup, szGroup); - strcat(szSubGroup, "\\"); - strcat(szSubGroup, szSubGroupName); - } - - if (nResult == PENDING_RESULT_SUCCESS) // if we got an id count level - wSubGroupLevel = getServListGroupLevel(wGroupID); - - if (wSubGroupLevel == -1) - { // something went wrong, give the id and go away - servlistPendingRemoveGroup(szSubGroup, wGroupID, PENDING_RESULT_FAILED); - - SAFE_FREE((void**)&szSubGroupName); - SAFE_FREE((void**)&szSubGroup); - return CALLBACK_RESULT_CONTINUE; - } - wSubGroupLevel++; // we are a sub-group - wSubGroupID = wGroupID + 1; - - // check if on that id is not group of the same or greater level, if yes, try next - while (CheckServerID(wSubGroupID, 0) && (getServListGroupLevel(wSubGroupID) >= wSubGroupLevel)) - { - wSubGroupID++; - } - - if (!CheckServerID(wSubGroupID, 0)) - { // the next id is free, so create our group with that id - cookie_servlist_action *ack; - DWORD dwCookie; - char *szSubGroupItem = (char*)SAFE_MALLOC(strlennull(szSubGroupName) + wSubGroupLevel + 1); - - if (szSubGroupItem) - { - int i; - - for (i=0; i < wSubGroupLevel; i++) - szSubGroupItem[i] = '>'; - - strcpy(szSubGroupItem + wSubGroupLevel, szSubGroupName); - szSubGroupItem[strlennull(szSubGroupName) + wSubGroupLevel] = '\0'; - SAFE_FREE((void**)&szSubGroupName); - // check and create unique group name (Miranda does allow more subgroups with the same name!) - szSubGroupItem = getServListUniqueGroupName(szSubGroupItem, TRUE); - - if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) - { // we have cookie good, go on -#ifdef _DEBUG - NetLog_Server("Server-List: Creating sub-group \"%s\", parent group \"%s\".", szSubGroupItem, szGroup); -#endif - ReserveServerID(wSubGroupID, SSIT_GROUP, 0); - - ack->wGroupId = wSubGroupID; - ack->szGroupName = szSubGroupItem; // we need that name - ack->szGroup = szSubGroup; - ack->dwAction = SSA_GROUP_ADD; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, szSubGroupItem, NULL, 0, SSOF_BEGIN_OPERATION); - return CALLBACK_RESULT_CONTINUE; - } - SAFE_FREE((void**)&szSubGroupItem); - } - } - // we failed to create sub-group give parent groupid - icq_LogMessage(LOG_ERROR, LPGEN("Failed to create the correct sub-group, the using closest parent group.")); - - servlistPendingRemoveGroup(szSubGroup, wGroupID, PENDING_RESULT_FAILED); - - SAFE_FREE((void**)&szSubGroupName); - SAFE_FREE((void**)&szSubGroup); - return CALLBACK_RESULT_CONTINUE; -} - - -int CIcqProto::servlistCreateGroup_Ready(const char *szGroup, WORD groupID, LPARAM param, int nResult) -{ - WORD wGroupID = 0; - - if (nResult == PENDING_RESULT_PURGE) - return CALLBACK_RESULT_CONTINUE; - - if (wGroupID = getServListGroupLinkID(szGroup)) - { // the path is known, continue the process - servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_SUCCESS); - return CALLBACK_RESULT_CONTINUE; - } - - if (!strstrnull(szGroup, "\\") || m_bSsiSimpleGroups) - { // a root group can be simply created without problems; simple groups are mapped directly - cookie_servlist_action* ack; - DWORD dwCookie; - - if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) - { // we have cookie good, go on -#ifdef _DEBUG - NetLog_Server("Server-List: Creating root group \"%s\".", szGroup); -#endif - ack->wGroupId = GenerateServerID(SSIT_GROUP, 0); - ack->szGroup = null_strdup(szGroup); // we need that name - // check if the groupname is unique - just to be sure, Miranda should handle that! - ack->szGroupName = getServListUniqueGroupName(ack->szGroup, FALSE); - ack->dwAction = SSA_GROUP_ADD; - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, ack->szGroup, NULL, 0, SSOF_BEGIN_OPERATION); - - return CALLBACK_RESULT_POSTPONE; - } - } - else - { // this is a sub-group - char* szSub = null_strdup(szGroup); // create subgroup, recursive, event-driven, possibly relocate - cookie_servlist_action* ack; - char *szLast; - - if (strstrnull(szSub, "\\")) - { // determine parent group - szLast = strrchr(szSub, '\\') + 1; - - szLast[-1] = '\0'; - } - // make parent group id - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { - ack->szGroupName = null_strdup(szLast); // groupname - servlistCreateGroup(szSub, (LPARAM)ack, &CIcqProto::servlistCreateGroup_gotParentGroup); - SAFE_FREE((void**)&szSub); - - return CALLBACK_RESULT_POSTPONE; - } - - SAFE_FREE((void**)&szSub); - } - servlistPendingRemoveGroup(szGroup, groupID, PENDING_RESULT_FAILED); - - return CALLBACK_RESULT_CONTINUE; -} - - -// create group with this path, a bit complex task -// this supposes that all server groups are known -void CIcqProto::servlistCreateGroup(const char *szGroupPath, LPARAM param, PENDING_GROUP_CALLBACK callback) -{ - char *szGroup = (char*)szGroupPath; - - if (!strlennull(szGroup)) szGroup = DEFAULT_SS_GROUP; - - servlistPendingAddGroup(szGroup, 0, 0, &CIcqProto::servlistCreateGroup_Ready, TRUE, param, callback); -} - - -/***************************************** -* -* --- Server-List Operations --- -* -*/ - -int CIcqProto::servlistAddContact_gotGroup(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action* ack = (cookie_servlist_action*)lParam; - - if (ack) SAFE_FREE(&ack->szGroup); - - if (nResult == PENDING_RESULT_PURGE) - { // only cleanup - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - if (!ack || !wGroupID) // something went wrong - { - if (ack) servlistPendingRemoveContact(ack->hContact, 0, wGroupID, PENDING_RESULT_FAILED); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); - - if (wItemID) /// TODO: redundant ??? - { // Only add the contact if it doesnt already have an ID - servlistPendingRemoveContact(ack->hContact, wItemID, wGroupID, PENDING_RESULT_SUCCESS); - NetLog_Server("Failed to add contact to server side list (%s)", "already there"); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - wItemID = GenerateServerID(SSIT_ITEM, 0); - - ack->dwAction = SSA_CONTACT_ADD; - ack->wGroupId = wGroupID; - ack->wContactId = wItemID; - - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, ack->hContact, ack); - - icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT | SSOF_BEGIN_OPERATION, 400, NULL); - - return CALLBACK_RESULT_CONTINUE; -} - - -// Need to be called when Pending Contact is active -int CIcqProto::servlistAddContact_Ready(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action* ack = (cookie_servlist_action*)lParam; - - if (nResult == PENDING_RESULT_PURGE) - { // removing obsolete items, just free the memory - SAFE_FREE((void**)&ack->szGroup); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); - - if (wItemID) - { // Only add the contact if it doesn't already have an ID - servlistPendingRemoveContact(ack->hContact, wItemID, getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0), PENDING_RESULT_SUCCESS); - NetLog_Server("Failed to add contact to server side list (%s)", "already there"); - SAFE_FREE((void**)&ack->szGroup); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - // obtain a correct groupid first - servlistCreateGroup(ack->szGroup, lParam, &CIcqProto::servlistAddContact_gotGroup); - - return CALLBACK_RESULT_POSTPONE; -} - - -// Called when contact should be added to server list, if group does not exist, create one -void CIcqProto::servlistAddContact(HANDLE hContact, const char *pszGroup) -{ - DWORD dwUin; - uid_str szUid; - cookie_servlist_action* ack; - - // Get UID - if (getContactUid(hContact, &dwUin, &szUid)) - { // Could not do anything without uid - NetLog_Server("Failed to add contact to server side list (%s)", "no UID"); - return; - } - - if (!(ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)))) - { // Could not do anything without cookie - NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed"); - return; - } - else - { - ack->hContact = hContact; - ack->szGroup = null_strdup(pszGroup); - // call thru pending operations - makes sure the contact is ready to be added - servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistAddContact_Ready, TRUE); - return; - } -} - - -int CIcqProto::servlistRemoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) -{ - WORD wGroupID; - WORD wItemID; - cookie_servlist_action* ack = (cookie_servlist_action*)lParam; - DWORD dwCookie; - - if (nResult == PENDING_RESULT_PURGE) - { - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - // Get the contact's group ID - if (!(wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0))) - { // Could not find a usable group ID - servlistPendingRemoveContact(hContact, contactID, groupID, PENDING_RESULT_FAILED); - - NetLog_Server("Failed to remove contact from server side list (%s)", "no group ID"); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - // Get the contact's item ID - if (!(wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0))) - { // Could not find usable item ID - servlistPendingRemoveContact(hContact, contactID, wGroupID, PENDING_RESULT_FAILED); - - NetLog_Server("Failed to remove contact from server side list (%s)", "no item ID"); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - ack->dwAction = SSA_CONTACT_REMOVE; - ack->hContact = hContact; - ack->wGroupId = wGroupID; - ack->wContactId = wItemID; - - dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, hContact, ack); - - icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT | SSOF_BEGIN_OPERATION, 400, NULL); - - return CALLBACK_RESULT_POSTPONE; -} - - -// Called when contact should be removed from server list, remove group if it remain empty -void CIcqProto::servlistRemoveContact(HANDLE hContact) -{ - DWORD dwUin; - uid_str szUid; - cookie_servlist_action* ack; - - // Get UID - if (getContactUid(hContact, &dwUin, &szUid)) - { - // Could not do anything without uid - NetLog_Server("Failed to remove contact from server side list (%s)", "no UID"); - return; - } - - if (!(ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)))) - { // Could not do anything without cookie - NetLog_Server("Failed to remove contact from server side list (%s)", "malloc failed"); - return; - } - else - { - ack->hContact = hContact; - // call thru pending operations - makes sure the contact is ready to be removed - servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistRemoveContact_Ready, TRUE); - return; - } -} - - -int CIcqProto::servlistMoveContact_gotTargetGroup(const char *szGroup, WORD wNewGroupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)lParam; - - if (ack) SAFE_FREE(&ack->szGroup); - - if (nResult == PENDING_RESULT_PURGE) - { // removing obsolete items, just free the memory - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - if (!ack || !wNewGroupID || !ack->hContact) // something went wrong - { - if (ack) servlistPendingRemoveContact(ack->hContact, 0, 0, PENDING_RESULT_FAILED); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); - WORD wGroupID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_GROUP, 0); - - if (!wItemID) - { // We have no ID, so try to simply add the contact to serv-list - NetLog_Server("Unable to move contact (no ItemID) -> trying to add"); - // we know the GroupID, so directly call add - return servlistAddContact_gotGroup(szGroup, wNewGroupID, lParam, nResult); - } - - if (wGroupID == wNewGroupID) - { // Only move the contact if it had different GroupID - servlistPendingRemoveContact(ack->hContact, wItemID, wNewGroupID, PENDING_RESULT_SUCCESS); - NetLog_Server("Contact not moved to group on server side list (same Group)"); - return CALLBACK_RESULT_CONTINUE; - } - - ack->szGroupName = NULL; - ack->dwAction = SSA_CONTACT_SET_GROUP; - ack->wGroupId = wGroupID; - ack->wContactId = wItemID; - ack->wNewContactId = GenerateServerID(SSIT_ITEM, 0); // icq5 recreates also this, imitate - ack->wNewGroupId = wNewGroupID; - ack->lParam = 0; // we use this as a sign - - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, ack->hContact, ack); - DWORD dwCookie2 = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, ack->hContact, ack); - - { // imitate icq5, previously here was different order, but AOL changed and it ceased to work - void *doubleObject = NULL; - - icq_sendServerContact(ack->hContact, dwCookie2, ICQ_LISTS_ADDTOLIST, wNewGroupID, ack->wNewContactId, SSO_CONTACT_SETGROUP | SSOF_BEGIN_OPERATION, 500, &doubleObject); - icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID, SSO_CONTACT_SETGROUP | SSOF_BEGIN_OPERATION, 500, &doubleObject); - } - return CALLBACK_RESULT_CONTINUE; -} - - -int CIcqProto::servlistMoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)lParam; - - if (nResult == PENDING_RESULT_PURGE) - { // removing obsolete items, just free the memory - SAFE_FREE(&ack->szGroup); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); - WORD wGroupID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_GROUP, 0); - - if (!wGroupID && wItemID) - { // Only move the contact if it had an GroupID - servlistPendingRemoveContact(ack->hContact, contactID, groupID, PENDING_RESULT_FAILED); - - NetLog_Server("Failed to move contact to group on server side list (%s)", "no Group"); - SAFE_FREE(&ack->szGroup); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - // obtain a correct target groupid first - servlistCreateGroup(ack->szGroup, lParam, &CIcqProto::servlistMoveContact_gotTargetGroup); - - return CALLBACK_RESULT_POSTPONE; -} - - -// Called when contact should be moved from one group to another, create new, remove empty -void CIcqProto::servlistMoveContact(HANDLE hContact, const char *pszNewGroup) -{ - DWORD dwUin; - uid_str szUid; - - if (!hContact) return; // we do not move us, caused our uin was wrongly added to list - - // Get UID - if (getContactUid(hContact, &dwUin, &szUid)) - { // Could not do anything without uin - NetLog_Server("Failed to move contact to group on server side list (%s)", "no UID"); - return; - } - - if ((pszNewGroup != NULL) && (pszNewGroup[0]!='\0') && !getCListGroupExists(pszNewGroup)) - { // the contact moved to non existing group, do not do anything: MetaContact hack - NetLog_Server("Contact not moved - probably hiding by MetaContacts."); - return; - } - - if (!getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) /// FIXME:::: this should be in _ready - { // the contact is not stored on the server, check if we should try to add - if (!getSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER) || - DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) - return; - } - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - if (!ack) - { // Could not do anything without cookie - NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed"); - return; - } - else - { - ack->hContact = hContact; - ack->szGroup = null_strdup(pszNewGroup); - // call thru pending operations - makes sure the contact is ready to be moved - servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistMoveContact_Ready, TRUE); - return; - } -} - - -int CIcqProto::servlistUpdateContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)lParam; - - if (nResult == PENDING_RESULT_PURGE) - { // removing obsolete items, just free the memory - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - WORD wItemID; - WORD wGroupID; - - // Get the contact's group ID - if (!(wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0))) - { - servlistPendingRemoveContact(hContact, contactID, groupID, PENDING_RESULT_FAILED); - // Could not find a usable group ID - NetLog_Server("Failed to update contact's details on server side list (%s)", "no group ID"); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - // Get the contact's item ID - if (!(wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0))) - { - servlistPendingRemoveContact(hContact, contactID, wGroupID, PENDING_RESULT_FAILED); - // Could not find usable item ID - NetLog_Server("Failed to update contact's details on server side list (%s)", "no item ID"); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - ack->dwAction = SSA_CONTACT_UPDATE; - ack->wContactId = wItemID; - ack->wGroupId = wGroupID; - ack->hContact = hContact; - - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, hContact, ack); - - // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or - // ICQ_LISTS_CLI_MODIFYEND when just changing nick name - icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_UPDATEGROUP, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT, 400, NULL); - - return CALLBACK_RESULT_POSTPONE; -} - - -// Is called when a contact' details has been changed locally to update -// the server side details. -void CIcqProto::servlistUpdateContact(HANDLE hContact) -{ - DWORD dwUin; - uid_str szUid; - - // Get UID - if (getContactUid(hContact, &dwUin, &szUid)) - { - // Could not set nickname on server without uid - NetLog_Server("Failed to update contact's details on server side list (%s)", "no UID"); - return; - } - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - if (!ack) - { - // Could not allocate cookie - use old fake - NetLog_Server("Failed to update contact's details on server side list (%s)", "malloc failed"); - return; - } - else - { - ack->hContact = hContact; - // call thru pending operations - makes sure the contact is ready to be updated - servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistUpdateContact_Ready, TRUE); - return; - } -} - - -int CIcqProto::servlistRenameGroup_Ready(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)lParam; - - if (nResult == PENDING_RESULT_PURGE) - { // only cleanup - if (ack) SAFE_FREE(&ack->szGroupName); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - if (!ack || !wGroupID) // something went wrong - { - servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_FAILED); - - if (ack) SAFE_FREE(&ack->szGroupName); - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - void *groupData; - int groupSize; - - if (groupData = collectBuddyGroup(wGroupID, &groupSize)) - { - ack->dwAction = SSA_GROUP_RENAME; - ack->wGroupId = wGroupID; - ack->szGroup = null_strdup(szGroup); // we need this name - // check if the new name is unique, create unique groupname if necessary - ack->szGroupName = getServListUniqueGroupName(ack->szGroupName, TRUE); - - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, wGroupID, ack->szGroupName, groupData, groupSize, 0); - SAFE_FREE(&groupData); - } - return CALLBACK_RESULT_POSTPONE; -} - - -void CIcqProto::servlistRenameGroup(char *szGroup, WORD wGroupId, char *szNewGroup) -{ - char *szNewGroupName; - int nGroupLevel = getServListGroupLevel(wGroupId); - - if (nGroupLevel == -1) return; // we failed to prepare group - - if (!m_bSsiSimpleGroups) - { - char *szGroupName = szGroup; - int i = nGroupLevel; - while (i) - { // find correct part of grouppath - szGroupName = strstrnull(szGroupName, "\\"); - if (!szGroupName) return; // failed to get correct part of the grouppath - szGroupName++; - i--; - } - szNewGroupName = szNewGroup; - i = nGroupLevel; - while (i) - { // find correct part of new grouppath - szNewGroupName = strstrnull(szNewGroupName, "\\"); - if (!szNewGroupName) return; // failed to get correct part of the new grouppath - szNewGroupName++; - i--; - } - // truncate possible sub-groups - char *szLast = strstrnull(szGroupName, "\\"); - if (szLast) - szLast[0] = '\0'; - szLast = strstrnull(szNewGroupName, "\\"); - if (szLast) - szLast[0] = '\0'; - - // this group was not changed, nothing to rename - if (!strcmpnull(szGroupName, szNewGroupName)) return; - - szGroupName = szNewGroupName; - szNewGroupName = (char*)SAFE_MALLOC(strlennull(szGroupName) + 1 + nGroupLevel); - if (!szNewGroupName) return; // Failure - - for (i = 0; i < nGroupLevel; i++) - { // create level prefix - szNewGroupName[i] = '>'; - } - strcat(szNewGroupName, szGroupName); - } - else // simple groups do not require any conversion - szNewGroupName = null_strdup(szNewGroup); - - cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (!ack) - { // cookie failed - NetLog_Server("Error: Failed to allocate cookie"); - - SAFE_FREE(&szNewGroupName); - return; - } - // store new group name for future use - ack->szGroupName = szNewGroupName; - // call thru pending operations - makes sure the group is ready for rename - servlistPendingAddGroup(szGroup, wGroupId, (LPARAM)ack, &CIcqProto::servlistRenameGroup_Ready, TRUE); -} - - -int CIcqProto::servlistRemoveGroup_Ready(const char *szGroup, WORD groupID, LPARAM lParam, int nResult) -{ - cookie_servlist_action *ack = (cookie_servlist_action*)lParam; - - if (nResult == PENDING_RESULT_PURGE) - { // only cleanup - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - WORD wGroupID = getServListGroupLinkID(szGroup); - char *szGroupName; - - if (wGroupID && (szGroupName = getServListGroupName(wGroupID))) - { // the group is valid, check if it is empty - void *groupData = collectBuddyGroup(wGroupID, NULL); - - if (groupData) - { // the group is not empty, cannot delete - SAFE_FREE(&groupData); - SAFE_FREE(&szGroupName); - // end operation - servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_SUCCESS); - // cleanup - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; - } - - if (!CheckServerID((WORD)(wGroupID+1), 0) || getServListGroupLevel((WORD)(wGroupID+1)) == 0) - { // is next id an sub-group, if yes, we cannot delete this group - ack->dwAction = SSA_GROUP_REMOVE; - ack->wContactId = 0; - ack->wGroupId = wGroupID; - ack->hContact = NULL; - ack->szGroup = null_strdup(szGroup); // we need that name - ack->szGroupName = szGroupName; - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); - - icq_sendServerGroup(dwCookie, ICQ_LISTS_REMOVEFROMLIST, ack->wGroupId, ack->szGroupName, NULL, 0, 0); - } - return CALLBACK_RESULT_POSTPONE; - } - // end operation - servlistPendingRemoveGroup(szGroup, groupID, PENDING_RESULT_SUCCESS); - // cleanup - SAFE_FREE((void**)&ack); - return CALLBACK_RESULT_CONTINUE; -} - - -void CIcqProto::servlistRemoveGroup(const char *szGroup, WORD wGroupId) -{ - if (!szGroup) return; - - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - if (!ack) - { // cookie failed - NetLog_Server("Error: Failed to allocate cookie"); - return; - } - - // call thru pending operations - makes sure the group is ready for removal - servlistPendingAddGroup(szGroup, wGroupId, (LPARAM)ack, &CIcqProto::servlistRemoveGroup_Ready, TRUE); -} - - -/*void CIcqProto::servlistMoveGroup(const char *szGroup, WORD wNewGroupId) -{ -// relocate the group -}*/ - - -void CIcqProto::resetServContactAuthState(HANDLE hContact, DWORD dwUin) -{ - WORD wContactId = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); - WORD wGroupId = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); - - if (wContactId && wGroupId) - { - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - if (ack) - { // we have cookie good, go on - ack->hContact = hContact; - ack->wContactId = wContactId; - ack->wGroupId = wGroupId; - ack->dwAction = SSA_CONTACT_FIX_AUTH; - - DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, 0, hContact, ack); - - { - void *doubleObject = NULL; - - icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupId, wContactId, SSO_CONTACT_FIXAUTH | SSOF_BEGIN_OPERATION | SSOF_END_OPERATION, 200, &doubleObject); - deleteSetting(hContact, DBSETTING_METAINFO_TOKEN); - deleteSetting(hContact, DBSETTING_METAINFO_TIME); - deleteSetting(hContact, DBSETTING_SERVLIST_DATA); - icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_ADDTOLIST, wGroupId, wContactId, SSO_CONTACT_FIXAUTH | SSOF_BEGIN_OPERATION | SSOF_END_OPERATION, 200, &doubleObject); - } - } - else - NetLog_Server("Error: Failed to allocate cookie"); - } -} - -/***************************************** -* -* --- Miranda Contactlist Hooks --- -* -*/ - -int CIcqProto::ServListDbSettingChanged(WPARAM wParam, LPARAM lParam) -{ - DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; - - // TODO: Queue changes that occur while offline - if (!icqOnline() || !m_bSsiEnabled || bIsSyncingCL) - return 0; - -#ifdef _DEBUG - if (cws->value.type == DBVT_DELETED) - NetLog_Server("DB-Events: Module \"%s\", setting \"%s\" deleted.", cws->szModule, cws->szSetting); - else - NetLog_Server("DB-Events: Module \"%s\", setting \"%s\" changed, data type %x.", cws->szModule, cws->szSetting, cws->value.type); -#endif - - if (!strcmpnull(cws->szModule, "CList")) - { - // Has contact been renamed? - if (!strcmpnull(cws->szSetting, "MyHandle") && - getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) - { // Update contact's details in server-list - servlistUpdateContact((HANDLE)wParam); - } - - // Has contact been moved to another group? - if (!strcmpnull(cws->szSetting, "Group") && - getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) - { // Read group from DB - char* szNewGroup = getContactCListGroup((HANDLE)wParam); - - SAFE_FREE(&szNewGroup); - } - } - else if (!strcmpnull(cws->szModule, "UserInfo")) - { - if (!strcmpnull(cws->szSetting, "MyNotes") && - getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) - { // Update contact's details in server-list - servlistUpdateContact((HANDLE)wParam); - } - } - - return 0; -} - - -int CIcqProto::ServListDbContactDeleted(WPARAM wParam, LPARAM lParam) -{ -#ifdef _DEBUG - NetLog_Server("DB-Events: Contact %x deleted.", wParam); -#endif - - DeleteFromContactsCache((HANDLE)wParam); - - if ( !icqOnline() && m_bSsiEnabled) - { // contact was deleted only locally - retrieve full list on next connect - setSettingWord((HANDLE)wParam, "SrvRecordCount", 0); - } - - if ( !icqOnline() || !m_bSsiEnabled) - return 0; - - { // we need all server contacts on local buddy list - DWORD dwUIN; - uid_str szUID; - - if (getContactUid((HANDLE)wParam, &dwUIN, &szUID)) - return 0; - - WORD wContactID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0); - WORD wGroupID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_GROUP, 0); - WORD wVisibleID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_PERMIT, 0); - WORD wInvisibleID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_DENY, 0); - WORD wIgnoreID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0); - - // Remove from queue for user details request - icq_DequeueUser(dwUIN); - - // Close all opened peer connections - CloseContactDirectConns((HANDLE)wParam); - - if ((wGroupID && wContactID) || wVisibleID || wInvisibleID || wIgnoreID) - { - if (wContactID) - { // delete contact from server - servlistRemoveContact((HANDLE)wParam); - } - - if (wVisibleID) - { // detete permit record - icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wVisibleID, SSI_ITEM_PERMIT); - } - - if (wInvisibleID) - { // delete deny record - icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wInvisibleID, SSI_ITEM_DENY); - } - - if (wIgnoreID) - { // delete ignore record - icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wIgnoreID, SSI_ITEM_IGNORE); - } - } - } - - return 0; -} - - -int CIcqProto::ServListCListGroupChange(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - CLISTGROUPCHANGE *grpchg = (CLISTGROUPCHANGE*)lParam; - - if (!icqOnline() || !m_bSsiEnabled || bIsSyncingCL) - return 0; - - // only change server-list if it is allowed - if (!getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) - return 0; - - - if (hContact == NULL) - { // change made to group - if (grpchg->pszNewName == NULL && grpchg->pszOldName != NULL) - { // group removed - char *szOldName = tchar_to_utf8(grpchg->pszOldName); - WORD wGroupId = getServListGroupLinkID(szOldName); - -#ifdef _DEBUG - NetLog_Server("CList-Events: Group %x:\"%s\" deleted.", wGroupId, szOldName); -#endif - if (wGroupId) - { // the group is known, remove from server - servlistPostPacket(NULL, 0, SSO_BEGIN_OPERATION, 100); // start server modifications here - servlistRemoveGroup(szOldName, wGroupId); - } - SAFE_FREE(&szOldName); - } - else if (grpchg->pszNewName != NULL && grpchg->pszOldName != NULL) - { // group renamed - char *szNewName = tchar_to_utf8(grpchg->pszNewName); - char *szOldName = tchar_to_utf8(grpchg->pszOldName); - WORD wGroupId = getServListGroupLinkID(szOldName); - -#ifdef _DEBUG - NetLog_Server("CList-Events: Group %x:\"%s\" changed to \"%s\".", wGroupId, szOldName, szNewName); -#endif - if (wGroupId) - { // group is known, rename on server - servlistRenameGroup(szOldName, wGroupId, szNewName); - } - SAFE_FREE(&szOldName); - SAFE_FREE(&szNewName); - } - } - else - { // change to contact - if (IsICQContact(hContact)) - { // our contact, fine move on the server as well - char *szNewName = grpchg->pszNewName ? tchar_to_utf8(grpchg->pszNewName) : NULL; - -#ifdef _DEBUG - NetLog_Server("CList-Events: Contact %x moved to group \"%s\".", hContact, szNewName); -#endif - servlistMoveContact(hContact, szNewName); - SAFE_FREE(&szNewName); - } - } - return 0; -} diff --git a/protocols/IcqOscarJ/icq_servlist.h b/protocols/IcqOscarJ/icq_servlist.h deleted file mode 100644 index 76118ce3c0..0000000000 --- a/protocols/IcqOscarJ/icq_servlist.h +++ /dev/null @@ -1,172 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQ_SERVLIST_H -#define __ICQ_SERVLIST_H - -// actions: -#define SSA_CHECK_ROSTER 0 // request serv-list -#define SSA_VISIBILITY 1 // update visibility -#define SSA_CONTACT_UPDATE 2 // update contact's details -#define SSA_GROUP_RENAME 5 // rename group -#define SSA_PRIVACY_ADD 0xA // add privacy item -#define SSA_PRIVACY_REMOVE 0xB // remove privacy item -#define SSA_CONTACT_ADD 0x10 // add contact w/o auth -#define SSA_CONTACT_SET_GROUP 0x12 // move to group -#define SSA_CONTACT_REMOVE 0x13 // delete contact -#define SSA_CONTACT_FIX_AUTH 0x40 // reuploading contact for auth re-request -#define SSA_GROUP_ADD 0x15 // create group -#define SSA_GROUP_REMOVE 0x16 // delete group -#define SSA_GROUP_UPDATE 0x17 // update group -#define SSA_SERVLIST_ACK 0x20 // send proto ack only (UploadUI) -#define SSA_SETAVATAR 0x30 -#define SSA_REMOVEAVATAR 0x31 -#define SSA_IMPORT 7 -#define SSA_ACTION_GROUP 0x80 // grouped action - -struct CIcqProto; -// callback prototypes for pending operation mechanism: -typedef int (__cdecl CIcqProto::*PENDING_GROUP_CALLBACK)(const char* pszGroup, WORD wGroupId, LPARAM lParam, int nResult); -typedef int (__cdecl CIcqProto::*PENDING_CONTACT_CALLBACK)(HANDLE hContact, WORD wContactId, WORD wGroupId, LPARAM lParam, int nResult); - -// cookie struct for SSI actions -struct cookie_servlist_action -{ - HANDLE hContact; - char *szGroup; - WORD wContactId; - WORD wGroupId; - char *szGroupName; - WORD wNewContactId; - WORD wNewGroupId; - int dwAction; - LPARAM lParam; - int dwGroupCount; - cookie_servlist_action **pGroupItems; -}; - -// server id type groups -#define SSIT_ITEM 0x00000000 -#define SSIT_GROUP 0x00010000 - -// server id flags -#define SSIF_UNHANDLED 0x01000000 - - -// pending operations -#define PENDING_RESULT_SUCCESS 0x00 -#define PENDING_RESULT_INLINE 0x01 -#define PENDING_RESULT_FAILED 0x0F -#define PENDING_RESULT_PURGE 0x10 - -// serv-list update board -#define SSOG_SINGLE 0x00010000 -#define SSOG_DOUBLE 0x00020000 - -#define SSOF_CONTACT 0x00800000 -#define SSOF_BEGIN_OPERATION 0x00100000 -#define SSOF_END_OPERATION 0x00200000 -#define SSOF_IMPORT_OPERATION 0x00400000 - -#define SSOP_ITEM_ACTION 0x01000000 | SSOG_SINGLE -// SSA_PRIVACY_ADD -// SSA_CONTACT_ADD -// SSA_CONTACT_UPDATE -// SSA_VISIBILITY -// SSA_PRIVACY_REMOVE -// SSA_CONTACT_REMOVE -// SSA_SETAVATAR -// SSA_REMOVEAVATAR -#define SSOP_GROUP_ACTION 0x02000000 | SSOG_SINGLE -// SSA_GROUP_ADD -// SSA_GROUP_RENAME -// SSA_GROUP_UPDATE -// SSA_GROUP_REMOVE -#define SSO_CONTACT_SETGROUP 0x04000000 | SSOG_DOUBLE -// SSA_CONTACT_SET_GROUP -#define SSO_CONTACT_FIXAUTH 0x06000000 | SSOG_DOUBLE -// SSA_CONTACT_FIX_AUTH - -#define SSO_BEGIN_OPERATION 0x80000000 -#define SSO_END_OPERATION 0x40000000 - -#define SSOF_SEND_DIRECTLY 0x10000000 - -#define SSOF_ACTIONMASK 0x0000FFFF -#define SSOF_GROUPINGMASK 0x0F0FFFFF - - -#define MAX_SERVLIST_PACKET_ITEMS 200 - -// server-list request handler item -struct servlistgroupitem -{ // generic parent - DWORD dwOperation; - cookie_servlist_action* cookie; - icq_packet packet; - // perhaps add some dummy bytes -}; - -struct servlistgroupitemdouble: public servlistgroupitem -{ - icq_packet packet2; - WORD wAction2; -}; - -struct ssiqueueditems -{ - time_t tAdded; - int dwTimeout; - int nItems; - servlistgroupitem* pItems[MAX_SERVLIST_PACKET_ITEMS]; -}; - - -// cookie structs for pending records -struct servlistpendingoperation -{ - DWORD flags; - PENDING_GROUP_CALLBACK callback; - LPARAM param; -}; - -struct servlistpendingitem -{ - int nType; - HANDLE hContact; - char* szGroup; - WORD wContactID; - WORD wGroupID; - - servlistpendingoperation* operations; - int operationsCount; -}; - - -#endif /* __ICQ_SERVLIST_H */ diff --git a/protocols/IcqOscarJ/icq_uploadui.cpp b/protocols/IcqOscarJ/icq_uploadui.cpp deleted file mode 100644 index f5e5c937b3..0000000000 --- a/protocols/IcqOscarJ/icq_uploadui.cpp +++ /dev/null @@ -1,1019 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Implements Manage Server List dialog -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -static int bListInit = 0; -static HANDLE hItemAll; -static int dwUploadDelay = 1000; // initial setting, it is too low for icq server but good for short updates - -static HWND hwndUploadContacts=NULL; -static const UINT settingsControls[]={IDOK}; - -static WORD* pwGroupIds = NULL; -static int cbGroupIds = 0; - -// Init default clist options -static void ResetCListOptions(HWND hwndList) -{ - int i; - - SendMessage(hwndList, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP)NULL); - SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); - SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0); - SendMessage(hwndList, CLM_SETLEFTMARGIN, 2, 0); - SendMessage(hwndList, CLM_SETINDENT, 10, 0); - for(i=0; i<=FONTID_MAX; i++) - SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); - SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList, GWL_STYLE)|CLS_SHOWHIDDEN); - if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS) // hide empty groups - SendMessage(hwndList, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0); -} - -// Selects the "All contacts" checkbox if all other list entries -// are selected, deselects it if not. -static void UpdateAllContactsCheckmark(HWND hwndList, CIcqProto* ppro, HANDLE phItemAll) -{ - int check = 1; - - HANDLE hContact = ppro->FindFirstContact(); - while (hContact) - { - HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); - if (hItem) - { - if (!SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) - { // if any of our contacts is unchecked, uncheck all contacts as well - check = 0; - break; - } - } - hContact = ppro->FindNextContact(hContact); - } - - SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)phItemAll, check); -} - -// Loop over all contacts and update the checkmark -// that indicates wether or not they are already uploaded -static int UpdateCheckmarks(HWND hwndList, CIcqProto* ppro, HANDLE phItemAll) -{ - int bAll = 1; - bListInit = 1; // lock CLC events - - HANDLE hContact = ppro->FindFirstContact(); - while (hContact) - { - HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); - if (hItem) - { - if (ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) - SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)hItem, 1); - else - bAll = 0; - } - hContact = ppro->FindNextContact(hContact); - } - - // Update the "All contacts" checkmark - if (phItemAll) - SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)phItemAll, bAll); - - bListInit = 0; - - return bAll; -} - -static void DeleteOtherContactsFromControl(HWND hCtrl, CIcqProto* ppro) -{ - HANDLE hContact; - HANDLE hItem; - - hContact = db_find_first(); - while (hContact) - { - hItem = (HANDLE)SendMessage(hCtrl, CLM_FINDCONTACT, (WPARAM)hContact, 0); - if (hItem) - { - if (!ppro->IsICQContact(hContact)) - SendMessage(hCtrl, CLM_DELETEITEM, (WPARAM)hItem, 0); - } - hContact = db_find_next(hContact); - } -} - -static void AppendToUploadLog(HWND hwndDlg, const char *fmt, ...) -{ - va_list va; - char szText[1024]; - int iItem; - - va_start(va, fmt); - mir_vsnprintf(szText, sizeof(szText), fmt, va); - va_end(va); - - iItem = ListBoxAddStringUtf(GetDlgItem(hwndDlg, IDC_LOG), szText); - SendDlgItemMessage(hwndDlg, IDC_LOG, LB_SETTOPINDEX, iItem, 0); -} - -static void DeleteLastUploadLogLine(HWND hwndDlg) -{ - SendDlgItemMessage(hwndDlg, IDC_LOG, LB_DELETESTRING, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, 0); -} - -static void GetLastUploadLogLine(HWND hwndDlg, char *szBuf, size_t cbBuf) -{ - WCHAR str[MAX_PATH]; - SendDlgItemMessageW(hwndDlg, IDC_LOG, LB_GETTEXT, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, (LPARAM)str); - make_utf8_string_static(str, szBuf, cbBuf); -} - -static int GroupEnumIdsEnumProc(const char *szSetting,LPARAM lParam) -{ - if (szSetting && strlennull(szSetting)<5) - { // it is probably server group - char val[MAX_PATH+2]; // dummy - DBVARIANT dbv; - DBCONTACTGETSETTING cgs; - - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = val; - dbv.cchVal = MAX_PATH; - - cgs.szModule=(char*)lParam; - cgs.szSetting=szSetting; - cgs.pValue=&dbv; - if(CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) - return 0; // this converts all string types to DBVT_ASCIIZ - if(dbv.type!=DBVT_ASCIIZ) - { // it is not a cached server-group name - return 0; - } - pwGroupIds = (WORD*)SAFE_REALLOC(pwGroupIds, (cbGroupIds+1)*sizeof(WORD)); - pwGroupIds[cbGroupIds] = (WORD)strtoul(szSetting, NULL, 0x10); - cbGroupIds++; - } - return 0; -} - -static void enumServerGroups(CIcqProto* ppro) -{ - DBCONTACTENUMSETTINGS dbces; - - char szModule[MAX_PATH+9]; - - strcpy(szModule, ppro->m_szModuleName); - strcat(szModule, "SrvGroups"); - - dbces.pfnEnumProc = &GroupEnumIdsEnumProc; - dbces.szModule = szModule; - dbces.lParam = (LPARAM)szModule; - - CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); -} - -static DWORD sendUploadGroup(CIcqProto* ppro, WORD wAction, WORD wGroupId, char* szItemName) -{ - DWORD dwCookie; - cookie_servlist_action* ack; - - if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) - { // we have cookie good, go on - ack->wGroupId = wGroupId; - ack->dwAction = SSA_SERVLIST_ACK; - dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, wAction, 0, ack); - ack->lParam = dwCookie; - - ppro->icq_sendServerGroup(dwCookie, wAction, ack->wGroupId, szItemName, NULL, 0, 0); - return dwCookie; - } - return 0; -} - -static DWORD sendUploadBuddy(CIcqProto* ppro, HANDLE hContact, WORD wAction, DWORD dwUin, char *szUID, WORD wContactId, WORD wGroupId, WORD wItemType) -{ - DWORD dwCookie; - cookie_servlist_action* ack; - - if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) - { // we have cookie good, go on - ack->hContact = hContact; - ack->wContactId = wContactId; - ack->wGroupId = wGroupId; - ack->dwAction = SSA_SERVLIST_ACK; - dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, wAction, hContact, ack); - ack->lParam = dwCookie; - - if (wItemType == SSI_ITEM_BUDDY) - ppro->icq_sendServerContact(hContact, dwCookie, wAction, ack->wGroupId, ack->wContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 500, NULL); - else - ppro->icq_sendSimpleItem(dwCookie, wAction, dwUin, szUID, ack->wGroupId, ack->wContactId, wItemType, SSOP_ITEM_ACTION, 500); - - return dwCookie; - } - return 0; -} - -static char* getServerResultDesc(int wCode) -{ - switch (wCode) - { - case 0: return LPGEN("OK"); - case 2: return LPGEN("NOT FOUND"); - case 3: return LPGEN("ALREADY EXISTS"); - case 0xA: return LPGEN("INVALID DATA"); - case 0xC: return LPGEN("LIST FULL"); - default: return LPGEN("FAILED"); - } -} - -#define ACTION_NONE 0 -#define ACTION_ADDBUDDY 1 -#define ACTION_ADDBUDDYAUTH 2 -#define ACTION_REMOVEBUDDY 3 -#define ACTION_ADDGROUP 4 -#define ACTION_REMOVEGROUP 5 -#define ACTION_UPDATESTATE 6 -#define ACTION_MOVECONTACT 7 -#define ACTION_ADDVISIBLE 8 -#define ACTION_REMOVEVISIBLE 9 -#define ACTION_ADDINVISIBLE 10 -#define ACTION_REMOVEINVISIBLE 11 - -#define STATE_READY 1 -#define STATE_REGROUP 2 -#define STATE_ITEMS 3 -#define STATE_VISIBILITY 5 -#define STATE_CONSOLIDATE 4 - -#define M_PROTOACK (WM_USER+100) -#define M_UPLOADMORE (WM_USER+101) -#define M_INITCLIST (WM_USER+102) - -static INT_PTR CALLBACK DlgProcUploadList(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam) -{ - CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - static int working; - static HANDLE hProtoAckHook; - static int currentSequence; - static int currentAction; - static int currentState; - static HANDLE hCurrentContact; - static int lastAckResult = 0; - static WORD wNewContactId; - static WORD wNewGroupId; - static char *szNewGroupName; - static WORD wNewVisibilityId; - - switch(message) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - { - char str[MAX_PATH]; - - working = 0; - hProtoAckHook = NULL; - currentState = STATE_READY; - - ResetCListOptions(GetDlgItem(hwndDlg, IDC_CLIST)); - - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Select contacts you want to store on server."), str, MAX_PATH)); - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Ready..."), str, MAX_PATH)); - } - return TRUE; - - // The M_PROTOACK message is received when the - // server has responded to our last update packet - case M_PROTOACK: - { - int bMulti = 0; - ACKDATA *ack = (ACKDATA*)lParam; - char szLastLogLine[MAX_PATH]; - char str[MAX_PATH]; - - // Is this an ack we are waiting for? - if (strcmpnull(ack->szModule, ppro->m_szModuleName)) - break; - - if (ack->type == ICQACKTYPE_RATEWARNING) - { // we are sending tooo fast, slow down the process - if (ack->hProcess != (HANDLE)1) break; // check class - if (ack->lParam == 2 || ack->lParam == 3) // check status - { - GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); - DeleteLastUploadLogLine(hwndDlg); - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Server rate warning -> slowing down the process."), str, MAX_PATH)); - AppendToUploadLog(hwndDlg, szLastLogLine); - - dwUploadDelay *= 2; - - break; - } - if (ack->lParam == 4) dwUploadDelay /= 2; // the rate is ok, turn up - } - - if (ack->type != ICQACKTYPE_SERVERCLIST) - break; - - if ((int)ack->hProcess != currentSequence) - break; - - lastAckResult = ack->result == ACKRESULT_SUCCESS ? 0 : 1; - - switch (currentAction) { - case ACTION_ADDBUDDY: - if (ack->result == ACKRESULT_SUCCESS) - { - ppro->setSettingByte(hCurrentContact, "Auth", 0); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); - break; - } - else - { // If the server refused to add the contact without authorization, - // we try again _with_ authorization TLV - DWORD dwUIN; - uid_str szUID; - - ppro->setSettingByte(hCurrentContact, "Auth", 1); - - if (!ppro->getContactUid(hCurrentContact, &dwUIN, &szUID)) - { - currentAction = ACTION_ADDBUDDYAUTH; - currentSequence = sendUploadBuddy(ppro, hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUIN, szUID, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); - } - - return FALSE; - } - - case ACTION_ADDBUDDYAUTH: - if (ack->result == ACKRESULT_SUCCESS) - { - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); - } - else - { - ppro->deleteSetting(hCurrentContact, "Auth"); - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - } - - break; - - case ACTION_REMOVEBUDDY: - if (ack->result == ACKRESULT_SUCCESS) - { // clear obsolete settings - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - ppro->deleteSetting(hCurrentContact, DBSETTING_SERVLIST_ID); - ppro->deleteSetting(hCurrentContact, DBSETTING_SERVLIST_GROUP); - ppro->deleteSetting(hCurrentContact, "Auth"); - } - break; - - case ACTION_ADDGROUP: - if (ack->result == ACKRESULT_SUCCESS) - { - void* groupData; - int groupSize; - cookie_servlist_action* ack; - - ppro->setServListGroupName(wNewGroupId, szNewGroupName); // add group to list - ppro->setServListGroupLinkID(szNewGroupName, wNewGroupId); // grouppath is known - - groupData = ppro->collectGroups(&groupSize); - groupData = SAFE_REALLOC(groupData, groupSize+2); - *(((WORD*)groupData)+(groupSize>>1)) = wNewGroupId; // add this new group id - groupSize += 2; - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { - DWORD dwCookie; // we do not use this - - ack->dwAction = SSA_SERVLIST_ACK; - dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - - ppro->icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, 0); - } - SAFE_FREE((void**)&groupData); - } - else - ppro->FreeServerID(wNewGroupId, SSIT_GROUP); - - SAFE_FREE((void**)&szNewGroupName); - break; - - case ACTION_REMOVEGROUP: - if (ack->result == ACKRESULT_SUCCESS) - { - void* groupData; - int groupSize; - cookie_servlist_action* ack; - - ppro->FreeServerID(wNewGroupId, SSIT_GROUP); - ppro->setServListGroupName(wNewGroupId, NULL); // remove group from list - ppro->removeGroupPathLinks(wNewGroupId); // grouppath is known - - groupData = ppro->collectGroups(&groupSize); - - ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - if (ack) - { - DWORD dwCookie; // we do not use this - - ack->dwAction = SSA_SERVLIST_ACK; - dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - - ppro->icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, 0); - } - SAFE_FREE((void**)&groupData); - } - break; - - case ACTION_UPDATESTATE: - // do nothing - break; - - case ACTION_MOVECONTACT: - if (ack->result == ACKRESULT_SUCCESS) - { - ppro->FreeServerID(ppro->getSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, 0), SSIT_ITEM); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); - dwUploadDelay *= 2; // we double the delay here (2 packets) - } - break; - - case ACTION_ADDVISIBLE: - if (ack->result == ACKRESULT_SUCCESS) - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_PERMIT, wNewContactId); - else - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - break; - - case ACTION_ADDINVISIBLE: - if (ack->result == ACKRESULT_SUCCESS) - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_DENY, wNewContactId); - else - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - break; - - case ACTION_REMOVEVISIBLE: - if (ack->result == ACKRESULT_SUCCESS) - { - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_PERMIT, 0); - } - break; - - case ACTION_REMOVEINVISIBLE: - if (ack->result == ACKRESULT_SUCCESS) - { - ppro->FreeServerID(wNewContactId, SSIT_ITEM); - ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_DENY, 0); - } - break; - } - - // Update the log window - GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); - DeleteLastUploadLogLine(hwndDlg); - AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine, - ICQTranslateUtfStatic(getServerResultDesc(ack->lParam), str, MAX_PATH)); - - if (!bMulti) - { - SetTimer(hwndDlg, M_UPLOADMORE, dwUploadDelay, 0); // delay - } - } - break; - - case WM_TIMER: - { - switch (wParam) - { - case M_UPLOADMORE: - KillTimer(hwndDlg, M_UPLOADMORE); - if (currentAction == ACTION_MOVECONTACT) - dwUploadDelay /= 2; // turn it back - - PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); - - return 0; - } - } - - // The M_UPLOADMORE window message is received when the user presses 'Update' - // and every time an ack from the server has been taken care of. - case M_UPLOADMORE: - { - HANDLE hContact; - HANDLE hItem; - DWORD dwUin; - uid_str szUid; - char *pszNick; - char *pszGroup; - int isChecked; - int isOnServer; - BOOL bUidOk; - char str[MAX_PATH]; - HWND hwndList = GetDlgItem(hwndDlg, IDC_CLIST); - - switch (currentState) - { - case STATE_REGROUP: - - // TODO: iterate over all checked groups and create if needed - // if creation requires reallocation of groups do it here - - currentState = STATE_ITEMS; - hCurrentContact = NULL; - PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); - break; - - case STATE_ITEMS: - // Iterate over all contacts until one is found that - // needs to be updated on the server - if (hCurrentContact == NULL) - hContact = ppro->FindFirstContact(); - else // we do not want to go thru all contacts over and over again - { - hContact = hCurrentContact; - if (lastAckResult) // if the last operation on this contact fail, do not do it again, go to next - hContact = ppro->FindNextContact(hContact); - } - - while (hContact) - { - hCurrentContact = hContact; - - hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); - if (hItem) - { - isChecked = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0) != 0; - isOnServer = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) != 0; - - bUidOk = !ppro->getContactUid(hContact, &dwUin, &szUid); - - // Is this one out of sync? - if (bUidOk && (isChecked != isOnServer)) - { - // Only upload custom nicks - pszNick = ppro->getSettingStringUtf(hContact, "CList", "MyHandle", NULL); - - if (isChecked) - { // Queue for uploading - pszGroup = ppro->getContactCListGroup(hContact); - if (!strlennull(pszGroup)) - pszGroup = null_strdup(DEFAULT_SS_GROUP); - - // Get group ID from cache, if not ready use parent group, if still not ready create one - wNewGroupId = ppro->getServListGroupLinkID(pszGroup); - if (!wNewGroupId && strstrnull(pszGroup, "\\") != NULL) - { // if it is sub-group, take master parent - strstrnull(pszGroup, "\\")[0] = '\0'; - wNewGroupId = ppro->getServListGroupLinkID(pszGroup); - } - if (!wNewGroupId && currentAction != ACTION_ADDGROUP) - { // if the group still does not exist and there was no try before, try to add group - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding group \"%s\"..."), str, MAX_PATH), pszGroup); - - wNewGroupId = ppro->GenerateServerID(SSIT_GROUP, 0); // ??? - szNewGroupName = pszGroup; - currentAction = ACTION_ADDGROUP; - currentSequence = sendUploadGroup(ppro, ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup); - SAFE_FREE(&pszNick); - - return FALSE; - } - - SAFE_FREE(&pszGroup); - - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Uploading %s..."), str, MAX_PATH), pszNick ? pszNick : strUID(dwUin, szUid)); - - currentAction = ACTION_ADDBUDDY; - - if (wNewGroupId) - { - wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); - - currentSequence = sendUploadBuddy(ppro, hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, - wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); - SAFE_FREE(&pszNick); - - return FALSE; - } - else - { - char szLastLogLine[MAX_PATH]; - // Update the log window with the failure and continue with next contact - GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); - DeleteLastUploadLogLine(hwndDlg); - AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine, ICQTranslateUtfStatic(LPGEN("FAILED"), str, MAX_PATH)); - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("No upload group available"), str, MAX_PATH)); - ppro->NetLog_Server("Upload failed, no group"); - currentState = STATE_READY; - } - } - else - { // Queue for deletion - if (pszNick) - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s..."), str, MAX_PATH), pszNick); - else - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s..."), str, MAX_PATH), strUID(dwUin, szUid)); - - wNewGroupId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); - wNewContactId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); - currentAction = ACTION_REMOVEBUDDY; - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, - wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); - } - SAFE_FREE((void**)&pszNick); - - break; - } - else if (bUidOk && isChecked) - { // the contact is and should be on server, check if it is in correct group, move otherwise - WORD wCurrentGroupId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); - - pszGroup = ppro->getContactCListGroup(hContact); - if (!strlennull(pszGroup)) - pszGroup = null_strdup(DEFAULT_SS_GROUP); - wNewGroupId = ppro->getServListGroupLinkID(pszGroup); - if (!wNewGroupId && strstrnull(pszGroup, "\\") != NULL) - { // if it is sub-group, take master parent - strstrnull(pszGroup, "\\")[0] = '\0'; - wNewGroupId = ppro->getServListGroupLinkID(pszGroup); - } - if (!wNewGroupId && currentAction != ACTION_ADDGROUP) - { // if the group still does not exist and there was no try before, try to add group - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding group \"%s\"..."), str, MAX_PATH), pszGroup); - - wNewGroupId = ppro->GenerateServerID(SSIT_GROUP, 0); - szNewGroupName = pszGroup; - currentAction = ACTION_ADDGROUP; - currentSequence = sendUploadGroup(ppro, ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup); - - return FALSE; - } - if (wNewGroupId && (wNewGroupId != wCurrentGroupId)) - { // we have a group the contact should be in, move it - WORD wCurrentContactId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); - BYTE bAuth = ppro->getSettingByte(hContact, "Auth", 0); - - pszNick = ppro->getSettingStringUtf(hContact, "CList", "MyHandle", NULL); - - if (pszNick) - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Moving %s to group \"%s\"..."), str, MAX_PATH), pszNick, pszGroup); - else - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Moving %s to group \"%s\"..."), str, MAX_PATH), strUID(dwUin, szUid), pszGroup); - - currentAction = ACTION_MOVECONTACT; - wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); - sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wCurrentContactId, wCurrentGroupId, SSI_ITEM_BUDDY); - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); - SAFE_FREE((void**)&pszNick); - SAFE_FREE((void**)&pszGroup); - - break; - } - SAFE_FREE((void**)&pszGroup); - } - } - hContact = db_find_next(hContact); - } - if (!hContact) - { - currentState = STATE_VISIBILITY; - hCurrentContact = NULL; - PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); - } - break; - - case STATE_VISIBILITY: - // Iterate over all contacts until one is found that - // needs to be updated on the server - if (hCurrentContact == NULL) - hContact = ppro->FindFirstContact(); - else // we do not want to go thru all contacts over and over again - { - hContact = hCurrentContact; - if (lastAckResult) // if the last operation on this contact fail, do not do it again, go to next - hContact = ppro->FindNextContact(hContact); - } - - while (hContact) - { - WORD wApparentMode = ppro->getSettingWord(hContact, "ApparentMode", 0); - WORD wDenyId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0); - WORD wPermitId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0); - WORD wIgnoreId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0); - - hCurrentContact = hContact; - ppro->getContactUid(hContact, &dwUin, &szUid); - - if (wApparentMode == ID_STATUS_ONLINE) - { // contact is on the visible list - if (wPermitId == 0) - { - currentAction = ACTION_ADDVISIBLE; - wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding %s to visible list..."), str, MAX_PATH), strUID(dwUin, szUid)); - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_PERMIT); - break; - } - } - if (wApparentMode == ID_STATUS_OFFLINE) - { // contact is on the invisible list - if (wDenyId == 0 && wIgnoreId == 0) - { - currentAction = ACTION_ADDINVISIBLE; - wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding %s to invisible list..."), str, MAX_PATH), strUID(dwUin, szUid)); - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_DENY); - break; - } - } - if (wApparentMode != ID_STATUS_ONLINE) - { // contact is not on visible list - if (wPermitId != 0) - { - currentAction = ACTION_REMOVEVISIBLE; - wNewContactId = wPermitId; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s from visible list..."), str, MAX_PATH), strUID(dwUin, szUid)); - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_PERMIT); - break; - } - } - if (wApparentMode != ID_STATUS_OFFLINE) - { // contact is not on invisible list - if (wDenyId != 0) - { - currentAction = ACTION_REMOVEINVISIBLE; - wNewContactId = wDenyId; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s from invisible list..."), str, MAX_PATH), strUID(dwUin, szUid)); - currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_DENY); - break; - } - } - hContact = db_find_next(hContact); - } - if (!hContact) - { - currentState = STATE_CONSOLIDATE; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Cleaning groups"), str, MAX_PATH)); - EnableDlgItem(hwndDlg, IDCANCEL, FALSE); - enumServerGroups(ppro); - PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); - } - break; - - case STATE_CONSOLIDATE: // updage group data, remove redundant groups - if (currentAction == ACTION_UPDATESTATE) - DeleteLastUploadLogLine(hwndDlg); - - if (cbGroupIds) // some groups in the list - { - void* groupData; - int groupSize; - - cbGroupIds--; - wNewGroupId = pwGroupIds[cbGroupIds]; - - if (groupData = ppro->collectBuddyGroup(wNewGroupId, &groupSize)) - { // the group is still not empty, just update it - char* pszGroup = ppro->getServListGroupName(wNewGroupId); - cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - ack->dwAction = SSA_SERVLIST_ACK; - ack->wGroupId = wNewGroupId; - currentSequence = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - ack->lParam = currentSequence; - currentAction = ACTION_UPDATESTATE; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Updating group \"%s\"..."), str, MAX_PATH), pszGroup); - - ppro->icq_sendServerGroup(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, groupData, groupSize, 0); - - SAFE_FREE((void**)&pszGroup); - } - else // the group is empty, delete it if it does not have sub-groups - { - if (!ppro->CheckServerID((WORD)(wNewGroupId+1), 0) || ppro->getServListGroupLevel((WORD)(wNewGroupId+1)) == 0) - { // is next id an sub-group, if yes, we cannot delete this group - char *pszGroup = ppro->getServListGroupName(wNewGroupId); - currentAction = ACTION_REMOVEGROUP; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting group \"%s\"..."), str, MAX_PATH), pszGroup); - currentSequence = sendUploadGroup(ppro, ICQ_LISTS_REMOVEFROMLIST, wNewGroupId, pszGroup); - SAFE_FREE((void**)&pszGroup); - } - else // update empty group - { - char *pszGroup = ppro->getServListGroupName(wNewGroupId); - cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); - - ack->dwAction = SSA_SERVLIST_ACK; - ack->wGroupId = wNewGroupId; - currentSequence = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); - ack->lParam = currentSequence; - currentAction = ACTION_UPDATESTATE; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Updating group \"%s\"..."), str, MAX_PATH), pszGroup); - - ppro->icq_sendServerGroup(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, 0, 0, 0); - - SAFE_FREE((void**)&pszGroup); - } - } - SAFE_FREE((void**)&groupData); // free the memory - } - else - { // all groups processed - SAFE_FREE((void**)&pwGroupIds); - currentState = STATE_READY; - } - break; - } - - if (currentState == STATE_READY) - { - // All contacts are in sync - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("All operations complete"), str, MAX_PATH)); - EnableDlgItem(hwndDlg, IDCANCEL, TRUE); - SetDlgItemTextUtf(hwndDlg, IDCANCEL, ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); - // end server modifications here - ppro->servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); - working = 0; - // SendMessage(hwndList, CLM_SETGREYOUTFLAGS,0,0); - UpdateCheckmarks(hwndList, ppro, hItemAll); - // EnableWindow(hwndList, FALSE); - if (hProtoAckHook) - UnhookEvent(hProtoAckHook); - } - break; - } - - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - SendDlgItemMessage(hwndDlg, IDC_LOG, LB_RESETCONTENT, 0, 0); - if (!ppro->icqOnline()) - { - char str[MAX_PATH]; - AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("You have to be online to sychronize the server-list !"), str, MAX_PATH)); - break; - } - working = 1; - hCurrentContact = NULL; - currentState = STATE_REGROUP; - currentAction = ACTION_NONE; - icq_ShowMultipleControls(hwndDlg, settingsControls, SIZEOF(settingsControls), SW_HIDE); - // SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0xFFFFFFFF, 0); - // InvalidateRect(GetDlgItem(hwndDlg, IDC_CLIST), NULL, FALSE); - EnableDlgItem(hwndDlg, IDC_CLIST, FALSE); - hProtoAckHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, M_PROTOACK); - // start server modifications here - ppro->servlistPostPacket(NULL, 0, SSO_BEGIN_OPERATION | SSOF_IMPORT_OPERATION, 100); - PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); - break; - - case IDCANCEL: // TODO: this must be clean - DestroyWindow(hwndDlg); - break; - } - break; - - case WM_NOTIFY: - switch(((NMHDR*)lParam)->idFrom) { - case IDC_CLIST: - { - HWND hClist = GetDlgItem(hwndDlg, IDC_CLIST); - - switch(((NMHDR*)lParam)->code) { - case CLN_OPTIONSCHANGED: - ResetCListOptions(hClist); - break; - - case CLN_NEWCONTACT: - case CLN_CONTACTMOVED: - // Delete non-icq contacts - DeleteOtherContactsFromControl(hClist, ppro); - if (hItemAll) - UpdateAllContactsCheckmark(hClist, ppro, hItemAll); - break; - - case CLN_LISTREBUILT: - { - int bCheck = false; - - // Delete non-icq contacts - if ( ppro ) { - DeleteOtherContactsFromControl(hClist, ppro); - if (!bListInit) // do not enter twice - bCheck = UpdateCheckmarks(hClist, ppro, NULL); - } - - if (!hItemAll) // Add the "All contacts" item - { - CLCINFOITEM cii = {0}; - - cii.cbSize = sizeof(cii); - cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX; - cii.pszText = TranslateT(LPGEN("** All contacts **")); - hItemAll = (HANDLE)SendMessage(hClist, CLM_ADDINFOITEM, 0, (LPARAM)&cii); - } - - SendMessage(hClist, CLM_SETCHECKMARK, (WPARAM)hItemAll, bCheck); - } - break; - - case CLN_CHECKCHANGED: - { - NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam; - HANDLE hContact; - HANDLE hItem; - - if (bListInit) break; - - if (nm->flags&CLNF_ISINFO) - { - int check; - - check = SendMessage(hClist, CLM_GETCHECKMARK, (WPARAM)hItemAll, 0); - - hContact = ppro->FindFirstContact(); - while (hContact) - { - hItem = (HANDLE)SendMessage(hClist, CLM_FINDCONTACT, (WPARAM)hContact, 0); - if (hItem) - SendMessage(hClist, CLM_SETCHECKMARK, (WPARAM)hItem, check); - hContact = ppro->FindNextContact(hContact); - } - } - else - UpdateAllContactsCheckmark(hClist, ppro, hItemAll); - } - break; - } - } - break; - } - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - - case WM_DESTROY: - if (hProtoAckHook) - UnhookEvent(hProtoAckHook); - if (working) - { // end server modifications here - ppro->servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); - } - hwndUploadContacts = NULL; - working = 0; - break; - } - - return FALSE; -} - -void CIcqProto::ShowUploadContactsDialog(void) -{ - if (hwndUploadContacts == NULL) - { - hItemAll = NULL; - hwndUploadContacts = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ICQUPLOADLIST), NULL, DlgProcUploadList, LPARAM(this)); - } - - SetForegroundWindow(hwndUploadContacts); -} diff --git a/protocols/IcqOscarJ/icq_xstatus.cpp b/protocols/IcqOscarJ/icq_xstatus.cpp deleted file mode 100644 index 92ae0eea14..0000000000 --- a/protocols/IcqOscarJ/icq_xstatus.cpp +++ /dev/null @@ -1,1380 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Angeli-Ka, Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Support for Custom Statuses -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" -#include "m_extraicons.h" - - -extern HANDLE hExtraXStatus; - -void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow); - -BYTE CIcqProto::getContactXStatus(HANDLE hContact) -{ - if (!m_bXStatusEnabled && !m_bMoodsEnabled) - return 0; - - BYTE bXStatus = getSettingByte(hContact, DBSETTING_XSTATUS_ID, 0); - - if (bXStatus < 1 || bXStatus > XSTATUS_COUNT) return 0; - - return bXStatus; -} - - -DWORD CIcqProto::sendXStatusDetailsRequest(HANDLE hContact, int bForced) -{ - DWORD dwCookie = 0; - - if (m_bXStatusEnabled && getContactXStatus(hContact) != 0) - { // only request custom status detail when the contact has one - int nNotifyLen = 94 + UINMAXLEN; - char *szNotify = (char*)_alloca(nNotifyLen); - - null_snprintf(szNotify, nNotifyLen, "cAwaySrvAwayStat1%d", m_dwLocalUIN); - - dwCookie = SendXtrazNotifyRequest(hContact, "srvMng", szNotify, bForced); - } - return dwCookie; -} - - -DWORD CIcqProto::requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay) -{ - if (!validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY)) - return 0; // apply privacy rules - - if (!CheckContactCapabilities(hContact, CAPF_XSTATUS)) - return 0; // contact does not have xstatus - - // delay is disabled only if fired from dialog - if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && bAllowDelay) - return 0; // Contact does not support xtraz, do not request details - - struct rates_xstatus_request: public rates_queue_item { - protected: - virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) { - rates_xstatus_request *pDest = (rates_xstatus_request*)aDest; - if (!pDest) - pDest = new rates_xstatus_request(ppro, wGroup); - - pDest->bForced = bForced; - return rates_queue_item::copyItem(pDest); - }; - public: - rates_xstatus_request(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { }; - virtual ~rates_xstatus_request() { }; - - virtual void execute() { - dwCookie = ppro->sendXStatusDetailsRequest(hContact, bForced); - }; - - BOOL bForced; - DWORD dwCookie; - }; - - m_ratesMutex->Enter(); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND); - m_ratesMutex->Leave(); - - rates_xstatus_request rr(this, wGroup); - rr.bForced = !bAllowDelay; - rr.hContact = hContact; - - // delay at least one sec if allowed - if (!handleRateItem(&rr, RQT_REQUEST, 1000, bAllowDelay)) - return rr.dwCookie; - - return -1; // delayed -} - - -static HANDLE LoadXStatusIconLibrary(TCHAR *path, const TCHAR *sub) -{ - TCHAR* p = _tcsrchr(path, '\\'); - HANDLE hLib; - - _tcscpy(p, sub); - _tcscat(p, _T("\\xstatus_ICQ.dll")); - if (hLib = LoadLibrary(path)) return hLib; - _tcscpy(p, sub); - _tcscat(p, _T("\\xstatus_icons.dll")); - if (hLib = LoadLibrary(path)) return hLib; - _tcscpy(p, _T("\\")); - return hLib; -} - -static TCHAR *InitXStatusIconLibrary(TCHAR *buf, size_t buf_size) -{ - TCHAR path[2*MAX_PATH]; - HMODULE hXStatusIconsDLL; - - // get miranda's exe path - GetModuleFileName(NULL, path, MAX_PATH); - - hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Icons")); - if (!hXStatusIconsDLL) // TODO: add "Custom Folders" support - hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Plugins")); - - if (hXStatusIconsDLL) - { - null_strcpy(buf, path, buf_size - 1); - - char ident[MAX_PATH]; - if (LoadStringA(hXStatusIconsDLL, IDS_IDENTIFY, ident, sizeof(ident)) == 0 || strcmpnull(ident, "# Custom Status Icons #")) - { // library is invalid - *buf = 0; - } - FreeLibrary(hXStatusIconsDLL); - } - else - *buf = 0; - - return buf; -} - - -HICON CIcqProto::getXStatusIcon(int bStatus, UINT flags) -{ - HICON icon = NULL; - - if (bStatus > 0 && bStatus <= XSTATUS_COUNT) - icon = hXStatusIcons[bStatus - 1]->GetIcon((flags & LR_BIGICON) != 0); - - if (flags & LR_SHARED || !icon) - return icon; - else - return CopyIcon(icon); -} - - -void CIcqProto::releaseXStatusIcon(int bStatus, UINT flags) -{ - if (bStatus > 0 && bStatus <= XSTATUS_COUNT) { - IcqIconHandle p = hXStatusIcons[bStatus - 1]; - if (p) - p->ReleaseIcon((flags & LR_BIGICON) != 0); - } -} - - -void CIcqProto::setContactExtraIcon(HANDLE hContact, int xstatus) -{ - HANDLE hIcon; - - if (hExtraXStatus == NULL) - { - if (xstatus > 0 && bXStatusExtraIconsReady < 2) - CListMW_ExtraIconsRebuild(0, 0); - - hIcon = (xstatus <= 0 ? (HANDLE)-1 : hXStatusExtraIcons[xstatus-1]); - - IconExtraColumn iec; - - iec.cbSize = sizeof(iec); - iec.hImage = hIcon; - iec.ColumnType = EXTRA_ICON_ADV1; - CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); - } - else - { - hIcon = (HANDLE) -1; - - if (xstatus <= 0) - { - ExtraIcon_SetIcon(hExtraXStatus, hContact, (char *) NULL); - } - else - { - char szTemp[MAX_PATH]; - null_snprintf(szTemp, sizeof(szTemp), "%s_xstatus%d", m_szModuleName, xstatus-1); - ExtraIcon_SetIcon(hExtraXStatus, hContact, szTemp); - } - } - - NotifyEventHooks(hxstatusiconchanged, (WPARAM)hContact, (LPARAM)hIcon); -} - - -int CIcqProto::CListMW_ExtraIconsRebuild(WPARAM wParam, LPARAM lParam) -{ - if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) - { - for (int i = 0; i < XSTATUS_COUNT; i++) - { - hXStatusExtraIcons[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)getXStatusIcon(i + 1, LR_SHARED), 0); - releaseXStatusIcon(i + 1, 0); - } - - if (!bXStatusExtraIconsReady) - { // try to hook the events again if they did not existed during init - HookProtoEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CIcqProto::CListMW_ExtraIconsRebuild); - HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CIcqProto::CListMW_ExtraIconsApply); - } - - bXStatusExtraIconsReady = 2; - } - return 0; -} - - -int CIcqProto::CListMW_ExtraIconsApply(WPARAM wParam, LPARAM lParam) -{ - if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_SET_ICON)) - { - if (IsICQContact((HANDLE)wParam)) - { - // only apply icons to our contacts, do not mess others - DWORD bXStatus = getContactXStatus((HANDLE)wParam); - - if ((m_bXStatusEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_XSTATUS)) || - (m_bMoodsEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_STATUS_MOOD))) - setContactExtraIcon((HANDLE)wParam, bXStatus); - } - } - return 0; -} - -#define NULLCAP {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - -capstr capXStatus[XSTATUS_COUNT] = { - {0x01, 0xD8, 0xD7, 0xEE, 0xAC, 0x3B, 0x49, 0x2A, 0xA5, 0x8D, 0xD3, 0xD8, 0x77, 0xE6, 0x6B, 0x92}, - {0x5A, 0x58, 0x1E, 0xA1, 0xE5, 0x80, 0x43, 0x0C, 0xA0, 0x6F, 0x61, 0x22, 0x98, 0xB7, 0xE4, 0xC7}, - {0x83, 0xC9, 0xB7, 0x8E, 0x77, 0xE7, 0x43, 0x78, 0xB2, 0xC5, 0xFB, 0x6C, 0xFC, 0xC3, 0x5B, 0xEC}, - {0xE6, 0x01, 0xE4, 0x1C, 0x33, 0x73, 0x4B, 0xD1, 0xBC, 0x06, 0x81, 0x1D, 0x6C, 0x32, 0x3D, 0x81}, - {0x8C, 0x50, 0xDB, 0xAE, 0x81, 0xED, 0x47, 0x86, 0xAC, 0xCA, 0x16, 0xCC, 0x32, 0x13, 0xC7, 0xB7}, - {0x3F, 0xB0, 0xBD, 0x36, 0xAF, 0x3B, 0x4A, 0x60, 0x9E, 0xEF, 0xCF, 0x19, 0x0F, 0x6A, 0x5A, 0x7F}, - {0xF8, 0xE8, 0xD7, 0xB2, 0x82, 0xC4, 0x41, 0x42, 0x90, 0xF8, 0x10, 0xC6, 0xCE, 0x0A, 0x89, 0xA6}, - {0x80, 0x53, 0x7D, 0xE2, 0xA4, 0x67, 0x4A, 0x76, 0xB3, 0x54, 0x6D, 0xFD, 0x07, 0x5F, 0x5E, 0xC6}, - {0xF1, 0x8A, 0xB5, 0x2E, 0xDC, 0x57, 0x49, 0x1D, 0x99, 0xDC, 0x64, 0x44, 0x50, 0x24, 0x57, 0xAF}, - {0x1B, 0x78, 0xAE, 0x31, 0xFA, 0x0B, 0x4D, 0x38, 0x93, 0xD1, 0x99, 0x7E, 0xEE, 0xAF, 0xB2, 0x18}, - {0x61, 0xBE, 0xE0, 0xDD, 0x8B, 0xDD, 0x47, 0x5D, 0x8D, 0xEE, 0x5F, 0x4B, 0xAA, 0xCF, 0x19, 0xA7}, - {0x48, 0x8E, 0x14, 0x89, 0x8A, 0xCA, 0x4A, 0x08, 0x82, 0xAA, 0x77, 0xCE, 0x7A, 0x16, 0x52, 0x08}, - {0x10, 0x7A, 0x9A, 0x18, 0x12, 0x32, 0x4D, 0xA4, 0xB6, 0xCD, 0x08, 0x79, 0xDB, 0x78, 0x0F, 0x09}, - {0x6F, 0x49, 0x30, 0x98, 0x4F, 0x7C, 0x4A, 0xFF, 0xA2, 0x76, 0x34, 0xA0, 0x3B, 0xCE, 0xAE, 0xA7}, - {0x12, 0x92, 0xE5, 0x50, 0x1B, 0x64, 0x4F, 0x66, 0xB2, 0x06, 0xB2, 0x9A, 0xF3, 0x78, 0xE4, 0x8D}, - {0xD4, 0xA6, 0x11, 0xD0, 0x8F, 0x01, 0x4E, 0xC0, 0x92, 0x23, 0xC5, 0xB6, 0xBE, 0xC6, 0xCC, 0xF0}, - {0x60, 0x9D, 0x52, 0xF8, 0xA2, 0x9A, 0x49, 0xA6, 0xB2, 0xA0, 0x25, 0x24, 0xC5, 0xE9, 0xD2, 0x60}, - {0x63, 0x62, 0x73, 0x37, 0xA0, 0x3F, 0x49, 0xFF, 0x80, 0xE5, 0xF7, 0x09, 0xCD, 0xE0, 0xA4, 0xEE}, - {0x1F, 0x7A, 0x40, 0x71, 0xBF, 0x3B, 0x4E, 0x60, 0xBC, 0x32, 0x4C, 0x57, 0x87, 0xB0, 0x4C, 0xF1}, - {0x78, 0x5E, 0x8C, 0x48, 0x40, 0xD3, 0x4C, 0x65, 0x88, 0x6F, 0x04, 0xCF, 0x3F, 0x3F, 0x43, 0xDF}, - {0xA6, 0xED, 0x55, 0x7E, 0x6B, 0xF7, 0x44, 0xD4, 0xA5, 0xD4, 0xD2, 0xE7, 0xD9, 0x5C, 0xE8, 0x1F}, - {0x12, 0xD0, 0x7E, 0x3E, 0xF8, 0x85, 0x48, 0x9E, 0x8E, 0x97, 0xA7, 0x2A, 0x65, 0x51, 0xE5, 0x8D}, - {0xBA, 0x74, 0xDB, 0x3E, 0x9E, 0x24, 0x43, 0x4B, 0x87, 0xB6, 0x2F, 0x6B, 0x8D, 0xFE, 0xE5, 0x0F}, - {0x63, 0x4F, 0x6B, 0xD8, 0xAD, 0xD2, 0x4A, 0xA1, 0xAA, 0xB9, 0x11, 0x5B, 0xC2, 0x6D, 0x05, 0xA1}, - {0x2C, 0xE0, 0xE4, 0xE5, 0x7C, 0x64, 0x43, 0x70, 0x9C, 0x3A, 0x7A, 0x1C, 0xE8, 0x78, 0xA7, 0xDC}, - {0x10, 0x11, 0x17, 0xC9, 0xA3, 0xB0, 0x40, 0xF9, 0x81, 0xAC, 0x49, 0xE1, 0x59, 0xFB, 0xD5, 0xD4}, - {0x16, 0x0C, 0x60, 0xBB, 0xDD, 0x44, 0x43, 0xF3, 0x91, 0x40, 0x05, 0x0F, 0x00, 0xE6, 0xC0, 0x09}, - {0x64, 0x43, 0xC6, 0xAF, 0x22, 0x60, 0x45, 0x17, 0xB5, 0x8C, 0xD7, 0xDF, 0x8E, 0x29, 0x03, 0x52}, - {0x16, 0xF5, 0xB7, 0x6F, 0xA9, 0xD2, 0x40, 0x35, 0x8C, 0xC5, 0xC0, 0x84, 0x70, 0x3C, 0x98, 0xFA}, - {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0, 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}, - {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27, 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}, - {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48, 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}, - NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, - NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, - NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, - NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, - NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, - NULLCAP, NULLCAP, NULLCAP, NULLCAP}; - -const char *nameXStatus[XSTATUS_COUNT] = { - LPGEN("Angry"), // 23 - LPGEN("Taking a bath"), // 1 - LPGEN("Tired"), // 2 - LPGEN("Birthday"), // 3 - LPGEN("Drinking beer"), // 4 - LPGEN("Thinking"), // 5 - LPGEN("Eating"), // 80 - LPGEN("Watching TV"), // 7 - LPGEN("Meeting"), // 8 - LPGEN("Coffee"), // 9 - LPGEN("Listening to music"),// 10 - LPGEN("Business"), // 11 - LPGEN("Shooting"), // 12 - LPGEN("Having fun"), // 13 - LPGEN("On the phone"), // 14 - LPGEN("Gaming"), // 15 - LPGEN("Studying"), // 16 - LPGEN("Shopping"), // 0 - LPGEN("Feeling sick"), // 17 - LPGEN("Sleeping"), // 18 - LPGEN("Surfing"), // 19 - LPGEN("Internet"), // 20 - LPGEN("Working"), // 21 - LPGEN("Typing"), // 22 - LPGEN("Picnic"), // 66 - LPGEN("Cooking"), - LPGEN("Smoking"), - LPGEN("I'm high"), - LPGEN("On WC"), // 68 - LPGEN("To be or not to be"),// 77 - LPGEN("Watching pro7 on TV"), - LPGEN("Love"), // 61 - LPGEN("Hot Dog"), //6 - LPGEN("Rough"), //24 - LPGEN("Rock On"), //25 - LPGEN("Baby"), //26 - LPGEN("Soccer"), //27 - LPGEN("Pirate"), //28 - LPGEN("Cyclop"), //29 - LPGEN("Monkey"), //30 - LPGEN("Birdie"), //31 - LPGEN("Cool"), //32 - LPGEN("Evil"), //33 - LPGEN("Alien"), //34 - LPGEN("Scooter"), //35 - LPGEN("Mask"), //36 - LPGEN("Money"), //37 - LPGEN("Pilot"), //38 - LPGEN("Afro"), //39 - LPGEN("St. Patrick"), //40 - LPGEN("Headmaster"), //41 - LPGEN("Lips"), //42 - LPGEN("Ice-Cream"), //43 - LPGEN("Pink Lady"), //44 - LPGEN("Up yours"), //45 - LPGEN("Laughing"), //46 - LPGEN("Dog"), //47 - LPGEN("Candy"), //48 - LPGEN("Crazy Professor"),//50 - LPGEN("Ninja"), //51 - LPGEN("Cocktail"), //52 - LPGEN("Punch"), //53 - LPGEN("Donut"), //54 - LPGEN("Feeling Good"), //55 - LPGEN("Lollypop"), //56 - LPGEN("Oink Oink"), //57 - LPGEN("Kitty"), //58 - LPGEN("Sumo"), //59 - LPGEN("Broken hearted"),//60 - LPGEN("Free for Chat"), //62 - LPGEN("@home"), //63 - LPGEN("@work"), //64 - LPGEN("Strawberry"), //65 - LPGEN("Angel"), //67 - LPGEN("Pizza"), //69 - LPGEN("Snoring"), //70 - LPGEN("On my mobile"), //71 - LPGEN("Depressed"), //72 - LPGEN("Beetle"), //73 - LPGEN("Double Rainbow"),//74 - LPGEN("Basketball"), //75 - LPGEN("Cupid shot me"), //76 - LPGEN("Celebrating"), //78 - LPGEN("Sushi"), //79 - LPGEN("Playing"), //81 - LPGEN("Writing") //84 - }; - -const int moodXStatus[XSTATUS_COUNT] = { - 23, - 1, - 2, - 3, - 4, - 5, - 80, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 0, - 17, - 18, - 19, - 20, - 21, - 22, - 66, - -1, - -1, - -1, - 68, - 77, - -1, - 61, - 6, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 62, - 63, - 64, - 65, - 67, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 78, - 79, - 81, - 84}; - -void CIcqProto::handleXStatusCaps(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *caps, int capsize, char *moods, int moodsize) -{ - int bChanged = FALSE; - int nCustomStatusID = 0, nMoodID = 0; - - if (!m_bXStatusEnabled && !m_bMoodsEnabled) - { - ClearContactCapabilities(hContact, CAPF_STATUS_MOOD | CAPF_XSTATUS); - return; - } - int nOldXStatusID = getContactXStatus(hContact); - - if (m_bXStatusEnabled) - { - if (caps) - { // detect custom status capabilities - if (capsize > 0) - for (int i = 0; i < XSTATUS_COUNT; i++) - { - if (MatchCapability(caps, capsize, (const capstr*)capXStatus[i], BINARY_CAP_SIZE)) - { - BYTE bXStatusId = (BYTE)(i+1); - char str[MAX_PATH]; - - SetContactCapabilities(hContact, CAPF_XSTATUS); - - if (nOldXStatusID != bXStatusId) - { // only write default name when it is really needed, i.e. on Custom Status change - setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId); - setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); - deleteSetting(hContact, DBSETTING_XSTATUS_MSG); - - NetLog_Server("%s changed custom status to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); - bChanged = TRUE; - } -#ifdef _DEBUG - else - NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); -#endif - - if (getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO)) - requestXStatusDetails(hContact, TRUE); - - nCustomStatusID = bXStatusId; - - break; - } - } - - if (nCustomStatusID == 0) - { -#ifdef _DEBUG - if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_XSTATUS)) - NetLog_Server("%s has removed custom status.", strUID(dwUIN, szUID)); -#endif - ClearContactCapabilities(hContact, CAPF_XSTATUS); - } - } -#ifdef _DEBUG - else if (CheckContactCapabilities(hContact, CAPF_XSTATUS)) - { - char str[MAX_PATH]; - NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH)); - } -#endif - } - if (m_bMoodsEnabled) - { - if (moods && moodsize < 32) - { // process custom statuses (moods) from ICQ6 - if (moodsize > 0) - for (int i = 0; i < XSTATUS_COUNT; i++) - { - char szMoodId[32], szMoodData[32]; - - null_strcpy(szMoodData, moods, moodsize); - - if (moodXStatus[i] == -1) continue; - null_snprintf(szMoodId, SIZEOF(szMoodId), "0icqmood%d", moodXStatus[i]); - if (!strcmpnull(szMoodId, szMoodData)) - { - BYTE bXStatusId = (BYTE)(i+1); - char str[MAX_PATH]; - - SetContactCapabilities(hContact, CAPF_STATUS_MOOD); - - if (nCustomStatusID == 0 && nOldXStatusID != bXStatusId) - { // only write default name when it is really needed, i.e. on Custom Status change - setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId); - setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); - deleteSetting(hContact, DBSETTING_XSTATUS_MSG); - - NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); - bChanged = TRUE; - } -#ifdef _DEBUG - else if (nOldXStatusID != bXStatusId) - NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); - else - NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); -#endif - // cannot retrieve mood details here - need to be processed with new user details - nMoodID = bXStatusId; - - break; - } - } - - if (nMoodID == 0 && moods) - { -#ifdef _DEBUG - if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_STATUS_MOOD)) - NetLog_Server("%s has removed mood.", strUID(dwUIN, szUID)); -#endif - ClearContactCapabilities(hContact, CAPF_STATUS_MOOD); - } - } -#ifdef _DEBUG - else if (CheckContactCapabilities(hContact, CAPF_STATUS_MOOD)) - { // Mood was not changed, but contact has one, add a small log notice - char str[MAX_PATH]; - NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH)); - } -#endif - } - - if (nCustomStatusID != 0 && nMoodID != 0 && nCustomStatusID != nMoodID) - NetLog_Server("Warning: Diverse custom statuses detected, using custom status."); - - if ((nCustomStatusID == 0 && (caps || !m_bXStatusEnabled)) && (nMoodID == 0 && (moods || !m_bMoodsEnabled))) - { - if (getSettingByte(hContact, DBSETTING_XSTATUS_ID, -1) != -1) - bChanged = TRUE; - deleteSetting(hContact, DBSETTING_XSTATUS_ID); - deleteSetting(hContact, DBSETTING_XSTATUS_NAME); - deleteSetting(hContact, DBSETTING_XSTATUS_MSG); - } - - if (m_bXStatusEnabled != 10 && m_bMoodsEnabled != 10) - { - setContactExtraIcon(hContact, nCustomStatusID ? nCustomStatusID : (nMoodID ? nMoodID : (moods ? 0 : nOldXStatusID))); - - if (bChanged) - NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0); - } -} - - -void CIcqProto::updateServerCustomStatus(int fullUpdate) -{ - BYTE bXStatus = getContactXStatus(NULL); - - if (fullUpdate) - { // update client capabilities - if (m_bXStatusEnabled) - setUserInfo(); - - char szMoodData[32]; - - // prepare mood id - if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus-1] != -1) - null_snprintf(szMoodData, SIZEOF(szMoodData), "0icqmood%d", moodXStatus[bXStatus-1]); - else - szMoodData[0] = '\0'; - - SetStatusMood(szMoodData, 1500); - } - - char *szStatusNote = NULL; - - if (bXStatus && (m_bXStatusEnabled || m_bMoodsEnabled)) - { // use custom status message as status note - szStatusNote = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); - } - else - { // retrieve standard status message (e.g. custom status set to none) - char **pszMsg = MirandaStatusToAwayMsg(m_iStatus); - - m_modeMsgsMutex->Enter(); - if (pszMsg) - szStatusNote = null_strdup(*pszMsg); - m_modeMsgsMutex->Leave(); - // no default status message, set empty - if (!szStatusNote) - szStatusNote = null_strdup(""); - } - - if (szStatusNote) - SetStatusNote(szStatusNote, 1500, FALSE); - - SAFE_FREE(&szStatusNote); -} - - -static WNDPROC OldMessageEditProc; - -static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) { - case WM_CHAR: - if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) - { - PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0); - return 0; - } - if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) - { // ctrl-a - SendMessage(hwnd, EM_SETSEL, 0, -1); - return 0; - } - if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) - { // ctrl-w - SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0); - return 0; - } - if (wParam == 127 && GetKeyState(VK_CONTROL) & 0x8000) - { // ctrl-backspace - DWORD start, end; - WCHAR *text; - - SendMessage(hwnd, EM_GETSEL, (WPARAM) & end, (LPARAM) (PDWORD) NULL); - SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0); - SendMessage(hwnd, EM_GETSEL, (WPARAM) & start, (LPARAM) (PDWORD) NULL); - text = GetWindowTextUcs(hwnd); - MoveMemory(text + start, text + end, sizeof(WCHAR) * (strlennull(text) + 1 - end)); - SetWindowTextUcs(hwnd, text); - SAFE_FREE(&text); - SendMessage(hwnd, EM_SETSEL, start, start); - SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd); - return 0; - } - break; - } - return CallWindowProc(OldMessageEditProc,hwnd,msg,wParam,lParam); -} - -struct SetXStatusData -{ - CIcqProto* ppro; - BYTE bAction; - BYTE bXStatus; - HANDLE hContact; - HANDLE hEvent; - DWORD iEvent; - int countdown; - char* okButtonFormat; -}; - -struct InitXStatusData -{ - CIcqProto* ppro; - BYTE bAction; - BYTE bXStatus; - char* szXStatusName; - char* szXStatusMsg; - HANDLE hContact; -}; - -#define HM_PROTOACK (WM_USER+10) -static INT_PTR CALLBACK SetXStatusDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam) -{ - SetXStatusData *dat = (SetXStatusData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - char str[MAX_PATH]; - - switch(message) { - case HM_PROTOACK: - { - ACKDATA *ack = (ACKDATA*)lParam; - if (ack->type != ICQACKTYPE_XSTATUS_RESPONSE) break; - if (ack->hContact != dat->hContact) break; - if ((DWORD)ack->hProcess != dat->iEvent) break; - - ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_HIDE); - ShowDlgItem(hwndDlg, IDC_XMSG, SW_SHOW); - ShowDlgItem(hwndDlg, IDC_XTITLE, SW_SHOW); - SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); - UnhookEvent(dat->hEvent); dat->hEvent = NULL; - char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, ""); - SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText); - SAFE_FREE(&szText); - szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, ""); - SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText); - SAFE_FREE(&szText); - } - break; - - case WM_INITDIALOG: - { - InitXStatusData *init = (InitXStatusData*)lParam; - - TranslateDialogDefault(hwndDlg); - dat = (SetXStatusData*)SAFE_MALLOC(sizeof(SetXStatusData)); - dat->ppro = init->ppro; - SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat); - dat->bAction = init->bAction; - - if (!init->bAction) - { // set our xStatus - dat->bXStatus = init->bXStatus; - SendDlgItemMessage(hwndDlg, IDC_XMSG, EM_LIMITTEXT, 1024, 0); - OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc); - SetDlgItemTextUtf(hwndDlg, IDC_XMSG, init->szXStatusMsg); - - if (dat->ppro->m_bXStatusEnabled) - { // custom status enabled, prepare title edit - SendDlgItemMessage(hwndDlg, IDC_XTITLE, EM_LIMITTEXT, 256, 0); - OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc); - SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, init->szXStatusName); - } - else - { // only moods enabled, hide title, resize message edit control - ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE); - ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); - MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8); - MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65); - } - - dat->okButtonFormat = GetDlgItemTextUtf(hwndDlg,IDOK); - dat->countdown = 5; - SendMessage(hwndDlg, WM_TIMER, 0, 0); - SetTimer(hwndDlg,1,1000,0); - } - else - { // retrieve contact's xStatus - dat->hContact = init->hContact; - dat->bXStatus = dat->ppro->getContactXStatus(dat->hContact); - dat->okButtonFormat = NULL; - SendMessage(GetDlgItem(hwndDlg, IDC_XTITLE), EM_SETREADONLY, 1, 0); - SendMessage(GetDlgItem(hwndDlg, IDC_XMSG), EM_SETREADONLY, 1, 0); - - if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS) && !dat->ppro->getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO)) - { - SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Cancel"), str, MAX_PATH)); - dat->hEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_PROTOACK); - ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_SHOW); - ShowDlgItem(hwndDlg, IDC_XMSG, SW_HIDE); - ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); - dat->iEvent = dat->ppro->requestXStatusDetails(dat->hContact, FALSE); - } - else - { - SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); - dat->hEvent = NULL; - char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, ""); - SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText); - SAFE_FREE(&szText); - - if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_STATUS_MOOD) && !dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS)) - { // only for clients supporting just moods and not custom status - szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_STATUS_NOTE, ""); - // hide title, resize message edit control - ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE); - ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); - MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8); - MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65); - } - else - szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, ""); - - SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText); - SAFE_FREE(&szText); - } - } - - if (dat->bXStatus) - { - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED | LR_BIGICON)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED)); - } - - char buf[MAX_PATH]; - char *format = GetWindowTextUtf(hwndDlg); - - null_snprintf(str, sizeof(str), format, dat->bXStatus?ICQTranslateUtfStatic(nameXStatus[dat->bXStatus-1], buf, MAX_PATH):""); - SetWindowTextUtf(hwndDlg, str); - SAFE_FREE(&format); - return TRUE; - } - case WM_TIMER: - if(dat->countdown==-1) - { - DestroyWindow(hwndDlg); - break; - } - { - null_snprintf(str,sizeof(str),dat->okButtonFormat,dat->countdown); - SetDlgItemTextUtf(hwndDlg,IDOK,str); - } - dat->countdown--; - break; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - DestroyWindow(hwndDlg); - break; - case IDC_XTITLE: - case IDC_XMSG: - if (!dat->bAction) - { // set our xStatus - KillTimer(hwndDlg,1); - SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("OK"), str, MAX_PATH)); - } - break; - } - break; - - case WM_DESTROY: - if (!dat->bAction) - { // set our xStatus - char szSetting[64]; - char *szValue; - - dat->ppro->setSettingByte(NULL, DBSETTING_XSTATUS_ID, dat->bXStatus); - szValue = GetDlgItemTextUtf(hwndDlg,IDC_XMSG); - null_snprintf(szSetting, 64, "XStatus%dMsg", dat->bXStatus); - dat->ppro->setSettingStringUtf(NULL, szSetting, szValue); - dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szValue); - SAFE_FREE(&szValue); - - if (dat->ppro->m_bXStatusEnabled) - { - szValue = GetDlgItemTextUtf(hwndDlg,IDC_XTITLE); - null_snprintf(szSetting, 64, "XStatus%dName", dat->bXStatus); - dat->ppro->setSettingStringUtf(NULL, szSetting, szValue); - dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szValue); - SAFE_FREE(&szValue); - - if (dat->bXStatus) - { - dat->ppro->releaseXStatusIcon(dat->bXStatus, LR_BIGICON); - dat->ppro->releaseXStatusIcon(dat->bXStatus, 0); - } - } - dat->ppro->updateServerCustomStatus(TRUE); - - SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc); - if (dat->ppro->m_bXStatusEnabled) - SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc); - } - if (dat->hEvent) UnhookEvent(dat->hEvent); - SAFE_FREE(&dat->okButtonFormat); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, NULL); - SAFE_FREE((void**)&dat); - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - } - return FALSE; -} - - -void CIcqProto::setXStatusEx(BYTE bXStatus, BYTE bQuiet) -{ - CLISTMENUITEM mi = {0}; - BYTE bOldXStatus = getSettingByte(NULL, DBSETTING_XSTATUS_ID, 0); - - mi.cbSize = sizeof(mi); - - if (!m_bHideXStatusUI) - { - if (bOldXStatus <= XSTATUS_COUNT) - { - mi.flags = CMIM_FLAGS; - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bOldXStatus], (LPARAM)&mi); - } - - mi.flags = CMIM_FLAGS | CMIF_CHECKED; - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bXStatus], (LPARAM)&mi); - } - - if (bXStatus) - { - char szSetting[64]; - char str[MAX_PATH]; - char *szName = NULL, *szMsg = NULL; - - if (m_bXStatusEnabled) - { - null_snprintf(szSetting, 64, "XStatus%dName", bXStatus); - szName = getSettingStringUtf(NULL, szSetting, ICQTranslateUtfStatic(nameXStatus[bXStatus-1], str, MAX_PATH)); - } - null_snprintf(szSetting, 64, "XStatus%dMsg", bXStatus); - szMsg = getSettingStringUtf(NULL, szSetting, ""); - - null_snprintf(szSetting, 64, "XStatus%dStat", bXStatus); - if (!bQuiet && !getSettingByte(NULL, szSetting, 0)) - { - InitXStatusData init; - init.ppro = this; - init.bAction = 0; // set - init.bXStatus = bXStatus; - init.szXStatusName = szName; - init.szXStatusMsg = szMsg; - CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init); - } - else - { - setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus); - if (m_bXStatusEnabled) - setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szName); - setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szMsg); - - updateServerCustomStatus(TRUE); - } - SAFE_FREE(&szName); - SAFE_FREE(&szMsg); - } - else - { - setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus); - deleteSetting(NULL, DBSETTING_XSTATUS_NAME); - deleteSetting(NULL, DBSETTING_XSTATUS_MSG); - - updateServerCustomStatus(TRUE); - } -} - - -INT_PTR CIcqProto::menuXStatus(WPARAM wParam,LPARAM lParam,LPARAM fParam) -{ - setXStatusEx((BYTE)fParam, 0); - return 0; -} - - -void CIcqProto::InitXStatusItems(BOOL bAllowStatus) -{ - CLISTMENUITEM mi; - int i = 0, len = strlennull(m_szModuleName); - char srvFce[MAX_PATH + 64]; - char szItem[MAX_PATH + 64]; - int bXStatusMenuBuilt = 0; - - BYTE bXStatus = getContactXStatus(NULL); - - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return; - - if (!bAllowStatus) return; - - // Custom Status UI is disabled, no need to continue items' init - if (m_bHideXStatusUI || m_bHideXStatusMenu) return; - - null_snprintf(szItem, sizeof(szItem), Translate("%s Custom Status"), m_szModuleName); - mi.cbSize = sizeof(mi); - mi.pszPopupName = szItem; - mi.popupPosition = 500084000; - mi.position = 2000040000; - - for (i = 0; i <= XSTATUS_COUNT; i++) - { - null_snprintf(srvFce, sizeof(srvFce), "%s/menuXStatus%d", m_szModuleName, i); - - mi.position++; - - if (!i) - bXStatusMenuBuilt = ServiceExists(srvFce); - - if (!bXStatusMenuBuilt) - CreateProtoServiceParam(srvFce+len, &CIcqProto::menuXStatus, i); - - mi.flags = (i ? CMIF_ICONFROMICOLIB : 0) | (bXStatus == i?CMIF_CHECKED:0); - mi.icolibItem = i ? hXStatusIcons[i-1]->Handle() : NULL; - mi.pszName = i ? (char*)nameXStatus[i-1] : (char *)LPGEN("None"); - mi.pszService = srvFce; - mi.pszContactOwner = m_szModuleName; - - hXStatusItems[i] = Menu_AddStatusMenuItem(&mi); - - // CMIF_HIDDEN does not work for adding services - CListShowMenuItem(hXStatusItems[i], !(m_bHideXStatusUI || m_bHideXStatusMenu)); - } -} - - -void CIcqProto::InitXStatusIcons() -{ - if (!m_bXStatusEnabled && !m_bMoodsEnabled) - return; - - TCHAR lib[2*MAX_PATH] = {0}; - TCHAR *icon_lib = InitXStatusIconLibrary(lib, SIZEOF(lib)); - - char szSection[MAX_PATH + 64], *szAccountName = tchar_to_utf8(m_tszUserName); - null_snprintf(szSection, sizeof(szSection), "Status Icons/%s/Custom Status", szAccountName); - SAFE_FREE(&szAccountName); - - for (int i = 0; i < XSTATUS_COUNT; i++) - { - char szTemp[64]; - - null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i); - hXStatusIcons[i] = IconLibDefine(nameXStatus[i], szSection, m_szModuleName, szTemp, icon_lib, -(IDI_XSTATUS1+i)); - } - - // initialize arrays for CList custom status icons - memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); - memset(hXStatusCListIcons, -1, sizeof(hXStatusCListIcons)); -} - - -void CIcqProto::UninitXStatusIcons() -{ - for (int i = 0; i < XSTATUS_COUNT; i++) - IconLibRemove(&hXStatusIcons[i]); - - // clear clist icon state indicators - memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); -} - - -INT_PTR CIcqProto::ShowXStatusDetails(WPARAM wParam, LPARAM lParam) -{ - InitXStatusData init; - init.ppro = this; - init.bAction = 1; // retrieve - init.hContact = (HANDLE)wParam; - CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init); - - return 0; -} - -INT_PTR CIcqProto::SetXStatus(WPARAM wParam, LPARAM lParam) -{ // obsolete (TODO: remove in next version) - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; - - if (wParam >= 0 && wParam <= XSTATUS_COUNT) - { - setXStatusEx((BYTE)wParam, 1); - return wParam; - } - return 0; -} - - -INT_PTR CIcqProto::GetXStatus(WPARAM wParam, LPARAM lParam) -{ // obsolete (TODO: remove in next version) - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; - - if (!icqOnline()) return 0; - - BYTE status = getContactXStatus(NULL); - - if (wParam) *((char**)wParam) = m_bXStatusEnabled ? DBSETTING_XSTATUS_NAME : NULL; - if (lParam) *((char**)lParam) = DBSETTING_XSTATUS_MSG; - - return status; -} - - -INT_PTR CIcqProto::SetXStatusEx(WPARAM wParam, LPARAM lParam) -{ - ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; - - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1; - - if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure - - if (pData->flags & CSSF_MASK_STATUS) - { // set custom status - int status = *pData->status; - - if (status >= 0 && status <= XSTATUS_COUNT) - setXStatusEx((BYTE)status, 1); - else - return 1; // Failure - } - - if (pData->flags & (CSSF_MASK_NAME | CSSF_MASK_MESSAGE)) - { - BYTE status = getContactXStatus(NULL); - - if (!status) return 1; // Failure - - if (m_bXStatusEnabled && (pData->flags & CSSF_MASK_NAME)) - { // set custom status name - if (pData->flags & CSSF_UNICODE) - setSettingStringW(NULL, DBSETTING_XSTATUS_NAME, pData->pwszName); - else - setSettingString(NULL, DBSETTING_XSTATUS_NAME, pData->pszName); - } - if (pData->flags & CSSF_MASK_MESSAGE) - { // set custom status message - if (pData->flags & CSSF_UNICODE) - setSettingStringW(NULL, DBSETTING_XSTATUS_MSG, pData->pwszMessage); - else - setSettingString(NULL, DBSETTING_XSTATUS_MSG, pData->pszMessage); - - // update status note if used for custom status message - updateServerCustomStatus(FALSE); - } - } - - if (pData->flags & CSSF_DISABLE_UI) - { // hide menu items + contact menu item - m_bHideXStatusUI = (*pData->wParam) ? 0 : 1; - } - - if (pData->flags & CSSF_DISABLE_MENU) - { // hide menu items only - m_bHideXStatusMenu = (*pData->wParam) ? 0 : 1; - } - - return 0; // Success -} - - -INT_PTR CIcqProto::GetXStatusEx(WPARAM wParam, LPARAM lParam) -{ - ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; - HANDLE hContact = (HANDLE)wParam; - - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1; - - if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure - - if (pData->flags & CSSF_MASK_STATUS) - { // fill status member - *pData->status = getContactXStatus(hContact); - } - - if (pData->flags & CSSF_MASK_NAME) - { // fill status name member - if (pData->flags & CSSF_DEFAULT_NAME) - { - int status = *pData->wParam; - - if (status < 1 || status > XSTATUS_COUNT) return 1; // Failure - - if (pData->flags & CSSF_UNICODE) - { - char *text = (char*)nameXStatus[status -1]; - - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pData->pwszName, MAX_PATH); - } - else - strcpy(pData->pszName, (char*)nameXStatus[status - 1]); - } - else - { // moods does not support status title - if (!m_bXStatusEnabled) return 1; - - if (pData->flags & CSSF_UNICODE) - { - char *str = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ""); - WCHAR *wstr = make_unicode_string(str); - - wcscpy(pData->pwszName, wstr); - SAFE_FREE(&str); - SAFE_FREE(&wstr); - } - else - { - DBVARIANT dbv = {0}; - - if (!getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv) && dbv.pszVal) - strcpy(pData->pszName, dbv.pszVal); - else - strcpy(pData->pszName, ""); - - ICQFreeVariant(&dbv); - } - } - } - - if (pData->flags & CSSF_MASK_MESSAGE) - { // fill status message member - if (pData->flags & CSSF_UNICODE) - { - char *str = getSettingStringUtf(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, ""); - WCHAR *wstr = make_unicode_string(str); - - wcscpy(pData->pwszMessage, wstr); - SAFE_FREE(&str); - SAFE_FREE(&wstr); - } - else - { - DBVARIANT dbv = {0}; - - if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv) && dbv.pszVal) - strcpy(pData->pszMessage, dbv.pszVal); - else - strcpy(pData->pszMessage, ""); - - ICQFreeVariant(&dbv); - } - } - - if (pData->flags & CSSF_DISABLE_UI) - { - if (pData->wParam) *pData->wParam = !m_bHideXStatusUI; - } - - if (pData->flags & CSSF_DISABLE_MENU) - { - if (pData->wParam) *pData->wParam = !m_bHideXStatusMenu; - } - - if (pData->flags & CSSF_STATUSES_COUNT) - { - if (pData->wParam) *pData->wParam = XSTATUS_COUNT; - } - - if (pData->flags & CSSF_STR_SIZES) - { - DBVARIANT dbv = {DBVT_DELETED}; - - if (pData->wParam) - { - if (m_bXStatusEnabled && !getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv)) - *pData->wParam = strlennull(dbv.pszVal); - else - *pData->wParam = 0; - ICQFreeVariant(&dbv); - } - if (pData->lParam) - { - if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv)) - *pData->lParam = strlennull(dbv.pszVal); - else - *pData->lParam = 0; - ICQFreeVariant(&dbv); - } - } - - return 0; // Success -} - - -INT_PTR CIcqProto::GetXStatusIcon(WPARAM wParam, LPARAM lParam) -{ - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; - - if (!wParam) - wParam = getContactXStatus(NULL); - - if (wParam >= 1 && wParam <= XSTATUS_COUNT) - { - return (INT_PTR)getXStatusIcon((BYTE)wParam, lParam); - } - return 0; -} - - -INT_PTR CIcqProto::RequestXStatusDetails(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - - if (!m_bXStatusEnabled) return 0; - - if (hContact && !getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO) && - getContactXStatus(hContact) && CheckContactCapabilities(hContact, CAPF_XSTATUS)) - { // user has xstatus, no auto-retrieve details, valid contact, request details - return requestXStatusDetails(hContact, TRUE); - } - return 0; -} - - -INT_PTR CIcqProto::RequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam) -{ - if (!m_bXStatusEnabled && !m_bMoodsEnabled) return -1; - - BYTE bXStatus = getContactXStatus((HANDLE)wParam); - - if (bXStatus) - { - int idx=-1; - - if (!bXStatusCListIconsValid[bXStatus-1]) - { // adding icon - int idx = hXStatusCListIcons[bXStatus-1]; - HIMAGELIST hCListImageList = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0); - - if (hCListImageList) - { - HICON hXStatusIcon = getXStatusIcon(bXStatus, LR_SHARED); - - if (idx > 0) - ImageList_ReplaceIcon(hCListImageList, idx, hXStatusIcon); - else - hXStatusCListIcons[bXStatus-1] = ImageList_AddIcon(hCListImageList, hXStatusIcon); - // mark icon index in the array as valid - bXStatusCListIconsValid[bXStatus-1] = TRUE; - - releaseXStatusIcon(bXStatus, 0); - } - } - idx = bXStatusCListIconsValid[bXStatus-1] ? hXStatusCListIcons[bXStatus-1] : -1; - - if (idx > 0) - return (idx & 0xFFFF) << 16; - } - return -1; -} diff --git a/protocols/IcqOscarJ/icq_xtraz.cpp b/protocols/IcqOscarJ/icq_xtraz.cpp deleted file mode 100644 index 2b73274365..0000000000 --- a/protocols/IcqOscarJ/icq_xtraz.cpp +++ /dev/null @@ -1,466 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Internal Xtraz API -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) -{ - char *szNotify = strstrnull(szMsg, ""); - char *szQuery = strstrnull(szMsg, ""); - - HANDLE hContact = HContactFromUIN(dwUin, NULL); - if (hContact) // user sent us xtraz, he supports it - SetContactCapabilities(hContact, CAPF_XTRAZ); - - if (szNotify && szQuery) - { // valid request - char *szWork, *szEnd; - int nNotifyLen, nQueryLen; - - szNotify += 8; - szQuery += 7; - szEnd = strstrnull(szMsg, ""); - if (!szEnd) szEnd = szMsg + nMsgLen; - nNotifyLen = (szEnd - szNotify); - szEnd = strstrnull(szMsg, ""); - if (!szEnd) szEnd = szNotify; - szNotify = DemangleXml(szNotify, nNotifyLen); - nQueryLen = (szEnd - szQuery); - szQuery = DemangleXml(szQuery, nQueryLen); - szWork = strstrnull(szQuery, ""); - szEnd = strstrnull(szQuery, ""); -#ifdef _DEBUG - NetLog_Server("Query: %s", szQuery); - NetLog_Server("Notify: %s", szNotify); -#endif - if (szWork && szEnd) - { // this is our plugin - szWork += 10; - *szEnd = '\0'; - - if (!stricmpnull(szWork, "srvMng") && strstrnull(szNotify, "AwayStat")) - { - char *szSender = strstrnull(szNotify, ""); - char *szEndSend = strstrnull(szNotify, ""); - - if (szSender && szEndSend) - { - szSender += 10; - *szEndSend = '\0'; - - if ((DWORD)atoi(szSender) == dwUin) - { - BYTE dwXId = m_bXStatusEnabled ? getContactXStatus(NULL) : 0; - - if (dwXId && validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY)) - { // apply privacy rules - NotifyEventHooks(m_modeMsgsEvent, (WPARAM)MTYPE_SCRIPT_NOTIFY, (LPARAM)dwUin); - - char *tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, ""); - char *szXName = MangleXml(tmp, strlennull(tmp)); - SAFE_FREE(&tmp); - - tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); - char *szXMsg = MangleXml(tmp, strlennull(tmp)); - SAFE_FREE(&tmp); - - int nResponseLen = 212 + strlennull(szXName) + strlennull(szXMsg) + UINMAXLEN + 2; - char *szResponse = (char*)_alloca(nResponseLen + 1); - // send response - null_snprintf(szResponse, nResponseLen, - "" - "cAwaySrv" - "" - "" - "%d" - "%d" - "%s" - "%s", - m_dwLocalUIN, dwXId, szXName, szXMsg); - - SAFE_FREE(&szXName); - SAFE_FREE(&szXMsg); - - struct rates_xstatus_response: public rates_queue_item { - protected: - virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) { - rates_xstatus_response *pDest = (rates_xstatus_response*)aDest; - if (!pDest) - pDest = new rates_xstatus_response(ppro, wGroup); - - pDest->bThruDC = bThruDC; - pDest->dwMsgID1 = dwMsgID1; - pDest->dwMsgID2 = dwMsgID2; - pDest->wCookie = wCookie; - pDest->szResponse = null_strdup(szResponse); - - return rates_queue_item::copyItem(pDest); - }; - public: - rates_xstatus_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup), szResponse(NULL) { }; - virtual ~rates_xstatus_response() { if (bCreated) SAFE_FREE(&szResponse); }; - - virtual void execute() { - ppro->SendXtrazNotifyResponse(dwUin, dwMsgID1, dwMsgID2, wCookie, szResponse, strlennull(szResponse), bThruDC); - }; - - BOOL bThruDC; - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD wCookie; - char *szResponse; - }; - - m_ratesMutex->Enter(); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); - m_ratesMutex->Leave(); - - rates_xstatus_response rr(this, wGroup); - rr.hContact = hContact; - rr.dwUin = dwUin; - rr.bThruDC = bThruDC; - rr.dwMsgID1 = dwMID; - rr.dwMsgID2 = dwMID2; - rr.wCookie = wCookie; - rr.szResponse = szResponse; - - handleRateItem(&rr, RQT_RESPONSE, 0, !bThruDC); - } - else if (dwXId) - NetLog_Server("Privacy: Ignoring XStatus request"); - else - NetLog_Server("Error: We are not in XStatus, skipping"); - } - else - NetLog_Server("Error: Invalid sender information"); - } - else - NetLog_Server("Error: Missing sender information"); - } - else - NetLog_Server("Error: Unknown plugin \"%s\" in Xtraz message", szWork); - } - else - NetLog_Server("Error: Missing PluginID in Xtraz message"); - - SAFE_FREE(&szNotify); - SAFE_FREE(&szQuery); - } - else - NetLog_Server("Error: Invalid Xtraz Notify message"); -} - - -void CIcqProto::handleXtrazNotifyResponse(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szMsg, int nMsgLen) -{ - char *szMem, *szRes, *szEnd; - int nResLen; - -#ifdef _DEBUG - NetLog_Server("Received Xtraz Notify Response"); -#endif - - szRes = strstrnull(szMsg, ""); - szEnd = strstrnull(szMsg, ""); - - if (szRes && szEnd) - { // valid response - char *szNode, *szWork; - - szRes += 5; - nResLen = szEnd - szRes; - - szMem = szRes = DemangleXml(szRes, nResLen); - -#ifdef _DEBUG - NetLog_Server("Response: %s", szRes); -#endif - - BroadcastAck(hContact, ICQACKTYPE_XTRAZNOTIFY_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, (LPARAM)szRes); - -NextVal: - szNode = strstrnull(szRes, ""); else szEnd = NULL; - - if (szNode && szEnd) - { - *(szEnd-1) = '\0'; - szNode += 13; //one more than the length of the string to skip ' or " too - szWork = szEnd + 1; - - if (!stricmpnull(szNode, "cAwaySrv")) - { - int bChanged = FALSE; - - *szEnd = ' '; - szNode = strstrnull(szWork, ""); - szEnd = strstrnull(szWork, ""); - if (szNode && szEnd) - { - szNode += 7; - *szEnd = '\0'; - if (atoi(szNode) != getContactXStatus(hContact)) - { // this is strange - but go on - NetLog_Server("Warning: XStatusIds do not match!"); - } - *szEnd = ' '; - } - szNode = strstrnull(szWork, ""); - szEnd = strstrnull(szWork, ""); - if (szNode && szEnd) - { // we got XStatus title, save it - char *szXName, *szOldXName; - szNode += 7; - *szEnd = '\0'; - szXName = DemangleXml(szNode, strlennull(szNode)); - // check if the name changed - szOldXName = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); - if (strcmpnull(szOldXName, szXName)) - bChanged = TRUE; - SAFE_FREE(&szOldXName); - setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, szXName); - SAFE_FREE(&szXName); - *szEnd = ' '; - } - szNode = strstrnull(szWork, ""); - szEnd = strstrnull(szWork, ""); - if (szNode && szEnd) - { // we got XStatus mode msg, save it - char *szXMsg, *szOldXMsg; - szNode += 6; - *szEnd = '\0'; - szXMsg = DemangleXml(szNode, strlennull(szNode)); - // check if the decription changed - szOldXMsg = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); - if (strcmpnull(szOldXMsg, szXMsg)) - bChanged = TRUE; - SAFE_FREE(&szOldXMsg); - setSettingStringUtf(hContact, DBSETTING_XSTATUS_MSG, szXMsg); - SAFE_FREE(&szXMsg); - } - BroadcastAck(hContact, ICQACKTYPE_XSTATUS_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); - if (bChanged) - NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0); - } - else - { - char *szSrvEnd = strstrnull(szEnd, ""); - - if (szSrvEnd && strstrnull(szSrvEnd, ""); - szEnd = strstrnull(szData, ""); - - if (szPid && szEnd) - { - szPid += 5; - - return DemangleXml(szPid, szEnd - szPid); - } - return NULL; -} - - -void CIcqProto::handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) -{ - HANDLE hContact; - char* szPluginID; - - hContact = HContactFromUIN(dwUin, NULL); - if (hContact) // user sent us xtraz, he supports it - SetContactCapabilities(hContact, CAPF_XTRAZ); - - szPluginID = getXmlPidItem(szMsg, nMsgLen); - if (!strcmpnull(szPluginID, "ICQChatRecv")) - { // it is a invitation to multi-user chat - } - else - { - NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); - } - SAFE_FREE(&szPluginID); -} - - -void CIcqProto::handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) -{ - HANDLE hContact; - char* szPluginID; - - hContact = HContactFromUIN(dwUin, NULL); - if (hContact) // user sent us xtraz, he supports it - SetContactCapabilities(hContact, CAPF_XTRAZ); - - szPluginID = getXmlPidItem(szMsg, nMsgLen); - if (!strcmpnull(szPluginID, "viewCard")) - { // it is a greeting card - char *szWork, *szEnd, *szUrl, *szNum; - - szWork = strstrnull(szMsg, ""); - szEnd = strstrnull(szMsg, ""); - if (szWork && szEnd) - { - int nDataLen = szEnd - szWork; - - szUrl = (char*)_alloca(nDataLen); - memcpy(szUrl, szWork+5, nDataLen); - szUrl[nDataLen - 5] = '\0'; - - if (!_strnicmp(szUrl, "view_", 5)) - { - szNum = szUrl + 5; - szWork = strstrnull(szUrl, ".html"); - if (szWork) - { - strcpy(szWork, ".php"); - strcat(szWork, szWork+5); - } - while (szWork = strstrnull(szUrl, "&")) - { // unescape & code - strcpy(szWork+1, szWork+5); - } - szWork = (char*)SAFE_MALLOC(nDataLen + MAX_PATH); - ICQTranslateUtfStatic(LPGEN("Greeting card:"), szWork, MAX_PATH); - strcat(szWork, "\r\nhttp://www.icq.com/friendship/pages/view_page_"); - strcat(szWork, szNum); - - // Create message to notify user - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - int bAdded; - - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = HContactFromUIN(dwUin, &bAdded); - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = time(NULL); - pre.szMessage = szWork; - pre.flags = PREF_UTF; - - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - SAFE_FREE(&szWork); - } - else - NetLog_Uni(bThruDC, "Error: Non-standard greeting card message"); - } - else - NetLog_Uni(bThruDC, "Error: Malformed greeting card message"); - } - else - { - NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); - } - SAFE_FREE(&szPluginID); -} - - -// Functions really sending Xtraz stuff -DWORD CIcqProto::SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced) -{ - char *szQueryBody; - char *szNotifyBody; - DWORD dwUin; - int nBodyLen; - char *szBody; - DWORD dwCookie; - - if (getContactUid(hContact, &dwUin, NULL)) - return 0; // Invalid contact - - if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && !bForced) - return 0; // Contact does not support xtraz, do not send anything - - szQueryBody = MangleXml(szQuery, strlennull(szQuery)); - szNotifyBody = MangleXml(szNotify, strlennull(szNotify)); - nBodyLen = strlennull(szQueryBody) + strlennull(szNotifyBody) + 41; - szBody = (char*)_alloca(nBodyLen); - nBodyLen = null_snprintf(szBody, nBodyLen, "%s%s", szQueryBody, szNotifyBody); - SAFE_FREE((void**)&szQueryBody); - SAFE_FREE((void**)&szNotifyBody); - - // Set up the ack type - cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_SCRIPT_NOTIFY, ACKTYPE_CLIENT); - dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - // have we a open DC, send through that - if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - icq_sendXtrazRequestDirect(hContact, dwCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); - else - icq_sendXtrazRequestServ(dwUin, dwCookie, szBody, nBodyLen, pCookieData); - - return dwCookie; -} - - -void CIcqProto::SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC) -{ - char *szResBody = MangleXml(szResponse, nResponseLen); - int nBodyLen = strlennull(szResBody) + 21; - char *szBody = (char*)_alloca(nBodyLen); - HANDLE hContact = HContactFromUIN(dwUin, NULL); - - if (hContact != INVALID_HANDLE_VALUE && !CheckContactCapabilities(hContact, CAPF_XTRAZ)) - { - SAFE_FREE(&szResBody); - return; // Contact does not support xtraz, do not send anything - } - - nBodyLen = null_snprintf(szBody, nBodyLen, "%s", szResBody); - SAFE_FREE(&szResBody); - - // Was request received thru DC and have we a open DC, send through that - if (bThruDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) - icq_sendXtrazResponseDirect(hContact, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); - else - icq_sendXtrazResponseServ(dwUin, dwMID, dwMID2, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); -} diff --git a/protocols/IcqOscarJ/icqosc_svcs.cpp b/protocols/IcqOscarJ/icqosc_svcs.cpp deleted file mode 100755 index ee6dd1731c..0000000000 --- a/protocols/IcqOscarJ/icqosc_svcs.cpp +++ /dev/null @@ -1,816 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// High-level code for exported API services -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -INT_PTR CIcqProto::AddServerContact(WPARAM wParam, LPARAM lParam) -{ - DWORD dwUin; - uid_str szUid; - - if (!m_bSsiEnabled) return 0; - - // Does this contact have a UID? - if (!getContactUid((HANDLE)wParam, &dwUin, &szUid) && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0) && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0)) - { /// TODO: remove possible 0x6A TLV in contact server-list data!!! - // Read group from DB - char *pszGroup = getContactCListGroup((HANDLE)wParam); - - servlistAddContact((HANDLE)wParam, pszGroup); - SAFE_FREE((void**)&pszGroup); - } - return 0; -} - - -static int LookupDatabaseSetting(const FieldNamesItem* table, int code, DBVARIANT *dbv, BYTE type) -{ - char *text = LookupFieldName(table, code); - - if (!text) - { - dbv->type = DBVT_DELETED; - return 1; - } - - if (type == DBVT_ASCIIZ) - { - dbv->pszVal = mir_strdup(Translate(text)); - dbv->type = DBVT_ASCIIZ; - } - else if (type == DBVT_UTF8 || !type) - { - char tmp[MAX_PATH]; - - dbv->pszVal = mir_strdup(ICQTranslateUtfStatic(text, tmp, MAX_PATH)); - dbv->type = DBVT_UTF8; - } - else if (type == DBVT_WCHAR) - { - WCHAR* wtext = make_unicode_string(text); - - dbv->pwszVal = mir_wstrdup(TranslateW(wtext)); - dbv->type = DBVT_WCHAR; - - SAFE_FREE((void**)&wtext); - } - return 0; // Success -} - -INT_PTR CIcqProto::GetInfoSetting(WPARAM wParam, LPARAM lParam) -{ - DBCONTACTGETSETTING *cgs = (DBCONTACTGETSETTING*)lParam; - BYTE type = cgs->pValue->type; - - cgs->pValue->type = 0; // original type without conversion - INT_PTR rc = CallService(MS_DB_CONTACT_GETSETTING_STR, wParam, lParam); - - if (!rc) - { // Success - DBVARIANT dbv; - - memcpy(&dbv, cgs->pValue, sizeof(DBVARIANT)); - - if (dbv.type == DBVT_BLOB) - { - cgs->pValue->pbVal = (BYTE*)mir_alloc(dbv.cpbVal); - - memcpy(cgs->pValue->pbVal, dbv.pbVal, dbv.cpbVal); - } - else if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_UTF8) - { // convert to the desired type - if (!type) - type = dbv.type; - - if (dbv.type == type) - { // type is correct, only move it to miranda's heap - cgs->pValue->pszVal = mir_strdup(dbv.pszVal); - } - else if (type == DBVT_WCHAR) - { - if (dbv.type != DBVT_UTF8) - { - int len = MultiByteToWideChar(CP_ACP, 0, dbv.pszVal, -1, NULL, 0); - cgs->pValue->pwszVal = (WCHAR*)mir_alloc((len + 1)*sizeof(WCHAR)); - if (cgs->pValue->pwszVal == NULL) - rc = 1; - else - { - MultiByteToWideChar(CP_ACP, 0, dbv.pszVal, -1, cgs->pValue->pwszVal, len); - cgs->pValue->pwszVal[len] = '\0'; - } - } - else - { - char *savePtr = dbv.pszVal ? strcpy((char*)_alloca(strlennull(dbv.pszVal) + 1), dbv.pszVal) : NULL; - if (!mir_utf8decode(savePtr, &cgs->pValue->pwszVal)) - rc = 1; - } - } - else if (type == DBVT_UTF8) - { - cgs->pValue->pszVal = mir_utf8encode(dbv.pszVal); - if (cgs->pValue->pszVal == NULL) - rc = 1; - } - else if (type == DBVT_ASCIIZ) - { - cgs->pValue->pszVal = mir_strdup(dbv.pszVal); - mir_utf8decode(cgs->pValue->pszVal, NULL); - } - - cgs->pValue->type = type; - } - else if (!strcmpnull(cgs->szModule, m_szModuleName) && (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD)) - { - int code = (dbv.type == DBVT_BYTE) ? dbv.bVal : ((dbv.type == DBVT_WORD) ? dbv.wVal : dbv.dVal); - - if (!strcmpnull(cgs->szSetting, "Language1") || !strcmpnull(cgs->szSetting, "Language2") || !strcmpnull(cgs->szSetting, "Language3")) - rc = LookupDatabaseSetting(languageField, code, cgs->pValue, type); - else if (!strcmpnull(cgs->szSetting, "Country") || !strcmpnull(cgs->szSetting, "OriginCountry") || !strcmpnull(cgs->szSetting, "CompanyCountry")) - { - if (code == 420) code = 42; // conversion of obsolete codes (OMG!) - else if (code == 421) code = 4201; - else if (code == 102) code = 1201; - rc = LookupDatabaseSetting(countryField, code, cgs->pValue, type); - } - else if (!strcmpnull(cgs->szSetting, "Gender")) - rc = LookupDatabaseSetting(genderField, code, cgs->pValue, type); - else if (!strcmpnull(cgs->szSetting, "MaritalStatus")) - rc = LookupDatabaseSetting(maritalField, code, cgs->pValue, type); - else if (!strcmpnull(cgs->szSetting, "StudyLevel")) - rc = LookupDatabaseSetting(studyLevelField, code, cgs->pValue, type); - else if (!strcmpnull(cgs->szSetting, "CompanyIndustry")) - rc = LookupDatabaseSetting(industryField, code, cgs->pValue, type); - else if (!strcmpnull(cgs->szSetting, "Interest0Cat") || !strcmpnull(cgs->szSetting, "Interest1Cat") || !strcmpnull(cgs->szSetting, "Interest2Cat") || !strcmpnull(cgs->szSetting, "Interest3Cat")) - rc = LookupDatabaseSetting(interestsField, code, cgs->pValue, type); - } - // Release database memory - ICQFreeVariant(&dbv); - } - - return rc; -} - - -INT_PTR CIcqProto::ChangeInfoEx(WPARAM wParam, LPARAM lParam) -{ - if (icqOnline() && wParam) - { - PBYTE buf = NULL; - int buflen = 0; - BYTE b; - - // userinfo - ppackTLVWord(&buf, &buflen, 0x1C2, (WORD)GetACP()); - - if (wParam & CIXT_CONTACT) - { // contact information - BYTE *pBlock = NULL; - int cbBlock = 0; - int nItems = 0; - - // Emails - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail0", 0x78, 0x64, 0x00); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail1", 0x78, 0x64, 0x00); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail2", 0x78, 0x64, 0x00); - ppackTLVBlockItems(&buf, &buflen, 0x8C, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); - - // Phones - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Phone", 0x6E, 0x64, 0x01); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "CompanyPhone", 0x6E, 0x64, 0x02); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Cellular", 0x6E, 0x64, 0x03); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Fax", 0x6E, 0x64, 0x04); - nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "CompanyFax", 0x6E, 0x64, 0x05); - ppackTLVBlockItems(&buf, &buflen, 0xC8, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); - - ppackTLVByte(&buf, &buflen, 0x1EA, getSettingByte(NULL, "AllowSpam", 0)); - } - - if (wParam & CIXT_BASIC) - { // upload basic user info - ppackTLVStringUtfFromDB(&buf, &buflen, "Nick", 0x78); - ppackTLVStringUtfFromDB(&buf, &buflen, "FirstName", 0x64); - ppackTLVStringUtfFromDB(&buf, &buflen, "LastName", 0x6E); - ppackTLVStringUtfFromDB(&buf, &buflen, "About", 0x186); - } - - if (wParam & CIXT_MORE) - { - b = getSettingByte(NULL, "Gender", 0); - ppackTLVByte(&buf, &buflen, 0x82, (BYTE)(b ? (b == 'M' ? 2 : 1) : 0)); - - ppackTLVDateFromDB(&buf, &buflen, "BirthYear", "BirthMonth", "BirthDay", 0x1A4); - - ppackTLVWord(&buf, &buflen, 0xAA, getSettingByte(NULL, "Language1", 0)); - ppackTLVWord(&buf, &buflen, 0xB4, getSettingByte(NULL, "Language2", 0)); - ppackTLVWord(&buf, &buflen, 0xBE, getSettingByte(NULL, "Language3", 0)); - - ppackTLVWord(&buf, &buflen, 0x12C, getSettingByte(NULL, "MaritalStatus", 0)); - } - - if (wParam & CIXT_WORK) - { - BYTE *pBlock = NULL; - int cbBlock = 0; - int nItems = 1; - - // Jobs - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyPosition", 0x64); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "Company", 0x6E); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyDepartment", 0x7D); - ppackTLVStringFromDB(&pBlock, &cbBlock, "CompanyHomepage", 0x78); - ppackTLVWord(&pBlock, &cbBlock, 0x82, getSettingWord(NULL, "CompanyIndustry", 0)); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyStreet", 0xAA); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyCity", 0xB4); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyState", 0xBE); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyZIP", 0xC8); - ppackTLVDWord(&pBlock, &cbBlock, 0xD2, getSettingWord(NULL, "CompanyCountry", 0)); - /// TODO: pack unknown data (need to preserve them in Block Items) - ppackTLVBlockItems(&buf, &buflen, 0x118, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); - - // ppackTLVWord(&buf, &buflen, getSettingWord(NULL, "CompanyOccupation", 0), TLV_OCUPATION, 1); // Lost In Conversion - } - - if (wParam & CIXT_EDUCATION) - { - BYTE *pBlock = NULL; - int cbBlock = 0; - int nItems = 1; - - // Studies - ppackTLVWord(&pBlock, &cbBlock, 0x64, getSettingWord(NULL, "StudyLevel", 0)); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "StudyInstitute", 0x6E); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "StudyDegree", 0x78); - ppackTLVWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "StudyYear", 0)); - ppackTLVBlockItems(&buf, &buflen, 0x10E, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); - } - - if (wParam & CIXT_LOCATION) - { - BYTE *pBlock = NULL; - int cbBlock = 0; - int nItems = 1; - - // Home Address - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "Street", 0x64); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "City", 0x6E); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "State", 0x78); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "ZIP", 0x82); - ppackTLVDWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "Country", 0)); - ppackTLVBlockItems(&buf, &buflen, 0x96, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); - - nItems = 1; - // Origin Address - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginStreet", 0x64); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginCity", 0x6E); - ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginState", 0x78); - ppackTLVDWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "OriginCountry", 0)); - ppackTLVBlockItems(&buf, &buflen, 0xA0, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); - - ppackTLVStringFromDB(&buf, &buflen, "Homepage", 0xFA); - - // Timezone - WORD wTimezone = getSettingByte(NULL, "Timezone", 0); - if ((wTimezone & 0x0080) == 0x80) wTimezone |= 0xFF00; // extend signed number - ppackTLVWord(&buf, &buflen, 0x17C, wTimezone); - } - - if (wParam & CIXT_BACKGROUND) - { - BYTE *pBlock = NULL; - int cbBlock = 0; - int nItems = 0; - - // Interests - nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest0Text", 0x6E, 0x64, getSettingWord(NULL, "Interest0Cat", 0)); - nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest1Text", 0x6E, 0x64, getSettingWord(NULL, "Interest1Cat", 0)); - nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest2Text", 0x6E, 0x64, getSettingWord(NULL, "Interest2Cat", 0)); - nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest3Text", 0x6E, 0x64, getSettingWord(NULL, "Interest3Cat", 0)); - ppackTLVBlockItems(&buf, &buflen, 0x122, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); - - - /* WORD w; /// not supported anymore - - w = StringToListItemId("Past0", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past0Text", TLV_PASTINFO); - w = StringToListItemId("Past1", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past1Text", TLV_PASTINFO); - w = StringToListItemId("Past2", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past2Text", TLV_PASTINFO); - - w = StringToListItemId("Affiliation0", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation0Text", TLV_AFFILATIONS); - w = StringToListItemId("Affiliation1", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation1Text", TLV_AFFILATIONS); - w = StringToListItemId("Affiliation2", 0); - ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation2Text", TLV_AFFILATIONS);*/ - } - - DWORD dwCookie = icq_changeUserDirectoryInfoServ(buf, (WORD)buflen, DIRECTORYREQUEST_UPDATEOWNER); - - SAFE_FREE((void**)&buf); - - return dwCookie; - } - - return 0; // Failure -} - - -INT_PTR CIcqProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam) -{ - if (wParam == AF_MAXSIZE) - { - POINT *size = (POINT*)lParam; - - if (size) - { - size->x = 64; - size->y = 64; - - return 0; - } - } - else if (wParam == AF_PROPORTION) - { - return PIP_NONE; - } - else if (wParam == AF_FORMATSUPPORTED) - { - if (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_XML || lParam == PA_FORMAT_BMP) - return 1; - else - return 0; - } - else if (wParam == AF_ENABLED) - { - if (m_bSsiEnabled && m_bAvatarsEnabled) - return 1; - else - return 0; - } - else if (wParam == AF_DONTNEEDDELAYS) - { - return 0; - } - else if (wParam == AF_MAXFILESIZE) - { // server accepts images of 7168 bytees, not bigger - return 7168; - } - else if (wParam == AF_DELAYAFTERFAIL) - { // do not request avatar again if server gave an error - return 1 * 60 * 60 * 1000; // one hour - } - else if (wParam == AF_FETCHALWAYS) - { // avatars can be fetched all the time (server only operation) - return 1; - } - return 0; -} - - -INT_PTR CIcqProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) -{ - PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)lParam; - DWORD dwUIN; - uid_str szUID; - DBVARIANT dbv = {DBVT_DELETED}; - - if (!m_bAvatarsEnabled) return GAIR_NOAVATAR; - - if (getSetting(pai->hContact, "AvatarHash", &dbv) || dbv.type != DBVT_BLOB || (dbv.cpbVal != 0x14 && dbv.cpbVal != 0x09)) - { - ICQFreeVariant(&dbv); - return GAIR_NOAVATAR; // we did not found avatar hash or hash invalid - no avatar available - } - - if (getContactUid(pai->hContact, &dwUIN, &szUID)) - { - ICQFreeVariant(&dbv); - return GAIR_NOAVATAR; // we do not support avatars for invalid contacts - } - - int dwPaFormat = getSettingByte(pai->hContact, "AvatarType", PA_FORMAT_UNKNOWN); - - if (dwPaFormat != PA_FORMAT_UNKNOWN) - { // we know the format, test file - TCHAR tszFile[MAX_PATH * 2 + 4]; - - GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszFile, MAX_PATH * 2); - - lstrcpyn(pai->filename, tszFile, SIZEOF(pai->filename)); // Avatar API does not support unicode :-( - pai->format = dwPaFormat; - - if (!IsAvatarChanged(pai->hContact, dbv.pbVal, dbv.cpbVal)) - { // hashes are the same - if (_taccess(tszFile, 0) == 0) - { - ICQFreeVariant(&dbv); - - return GAIR_SUCCESS; // we have found the avatar file, whoala - } - } - } - - if (IsAvatarChanged(pai->hContact, dbv.pbVal, dbv.cpbVal)) - { // we didn't received the avatar before - this ensures we will not request avatar again and again - if ((wParam & GAIF_FORCE) != 0 && pai->hContact != 0) - { // request avatar data - TCHAR tszFile[MAX_PATH * 2 + 4]; - - GetAvatarFileName(dwUIN, szUID, tszFile, MAX_PATH * 2); - GetAvatarData(pai->hContact, dwUIN, szUID, dbv.pbVal, dbv.cpbVal, tszFile); - lstrcpyn(pai->filename, tszFile, SIZEOF(pai->filename)); // Avatar API does not support unicode :-( - - ICQFreeVariant(&dbv); - - return GAIR_WAITFOR; - } - } - ICQFreeVariant(&dbv); - - return GAIR_NOAVATAR; -} - - -INT_PTR CIcqProto::GetMyAvatar(WPARAM wParam, LPARAM lParam) -{ - if (!m_bAvatarsEnabled) return -2; - - if (!wParam) return -3; - - TCHAR *tszFile = GetOwnAvatarFileName(); - if (tszFile && !_taccess(tszFile, 0)) - { - _tcsncpy((TCHAR*)wParam, tszFile, (int)lParam); - SAFE_FREE(&tszFile); - return 0; - } - - SAFE_FREE(&tszFile); - return -1; -} - - -INT_PTR CIcqProto::GrantAuthorization(WPARAM wParam, LPARAM lParam) -{ - if (icqOnline() && wParam != 0) - { - DWORD dwUin; - uid_str szUid; - - if (getContactUid((HANDLE)wParam, &dwUin, &szUid)) - return 0; // Invalid contact - - // send without reason, do we need any ? - icq_sendGrantAuthServ(dwUin, szUid, NULL); - // auth granted, remove contact menu item - deleteSetting((HANDLE)wParam, "Grant"); - } - - return 0; -} - -int CIcqProto::OnIdleChanged(WPARAM wParam, LPARAM lParam) -{ - int bIdle = (lParam&IDF_ISIDLE); - int bPrivacy = (lParam&IDF_PRIVACY); - - if (bPrivacy) return 0; - - setSettingDword(NULL, "IdleTS", bIdle ? time(0) : 0); - - if (m_bTempVisListEnabled) // remove temporary visible users - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_REMOVETEMPVISIBLE, BUL_TEMPVISIBLE); - - icq_setidle(bIdle ? 1 : 0); - - return 0; -} - -INT_PTR CIcqProto::RevokeAuthorization(WPARAM wParam, LPARAM lParam) -{ - if (icqOnline() && wParam != 0) - { - DWORD dwUin; - uid_str szUid; - - if (getContactUid((HANDLE)wParam, &dwUin, &szUid)) - return 0; // Invalid contact - - if (MessageBoxUtf(NULL, LPGEN("Are you sure you want to revoke user's authorization (this will remove you from his/her list on some clients) ?"), LPGEN("Confirmation"), MB_ICONQUESTION | MB_YESNO) != IDYES) - return 0; - - icq_sendRevokeAuthServ(dwUin, szUid); - } - - return 0; -} - - -INT_PTR CIcqProto::SendSms(WPARAM wParam, LPARAM lParam) -{ - if (icqOnline() && wParam && lParam) - return icq_sendSMSServ((const char *)wParam, (const char *)lParam); - - return 0; // Failure -} - -INT_PTR CIcqProto::SendYouWereAdded(WPARAM wParam, LPARAM lParam) -{ - if (lParam && icqOnline()) - { - CCSDATA* ccs = (CCSDATA*)lParam; - if (ccs->hContact) - { - DWORD dwUin, dwMyUin; - - if (getContactUid(ccs->hContact, &dwUin, NULL)) - return 1; // Invalid contact - - dwMyUin = getContactUin(NULL); - - if (dwUin) - { - icq_sendYouWereAddedServ(dwUin, dwMyUin); - return 0; // Success - } - } - } - - return 1; // Failure -} - -INT_PTR CIcqProto::SetMyAvatar(WPARAM wParam, LPARAM lParam) -{ - TCHAR* tszFile = (TCHAR*)lParam; - int iRet = -1; - - if (!m_bAvatarsEnabled || !m_bSsiEnabled) return -2; - - if (tszFile) - { // set file for avatar - int dwPaFormat = DetectAvatarFormat(tszFile); - if (dwPaFormat != PA_FORMAT_XML) - { - // if it should be image, check if it is valid - HBITMAP avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (WPARAM)tszFile); - if (!avt) return iRet; - DeleteObject(avt); - } - - TCHAR tszMyFile[MAX_PATH+1]; - GetFullAvatarFileName(0, NULL, dwPaFormat, tszMyFile, MAX_PATH); - // if not in our storage, copy - if (lstrcmp(tszFile, tszMyFile) && !CopyFile(tszFile, tszMyFile, FALSE)) - { - NetLog_Server("Failed to copy our avatar to local storage."); - return iRet; - } - - BYTE *hash = calcMD5HashOfFile(tszMyFile); - if (hash) - { - BYTE* ihash = (BYTE*)_alloca(0x14); - // upload hash to server - ihash[0] = 0; //unknown - ihash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; //hash type - ihash[2] = 1; //hash status - ihash[3] = 0x10; //hash len - memcpy(ihash+4, hash, 0x10); - updateServAvatarHash(ihash, 0x14); - - if (setSettingBlob(NULL, "AvatarHash", ihash, 0x14)) - { - NetLog_Server("Failed to save avatar hash."); - } - - TCHAR tmp[MAX_PATH]; - CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)tszMyFile, (LPARAM)tmp); - setSettingStringT(NULL, "AvatarFile", tmp); - - iRet = 0; - - SAFE_FREE((void**)&hash); - } - } - else - { // delete user avatar - deleteSetting(NULL, "AvatarFile"); - setSettingBlob(NULL, "AvatarHash", hashEmptyAvatar, 9); - updateServAvatarHash(hashEmptyAvatar, 9); // set blank avatar - iRet = 0; - } - - return iRet; -} - -INT_PTR CIcqProto::SetNickName(WPARAM wParam, LPARAM lParam) -{ - if (icqOnline()) - { - setSettingString(NULL, "Nick", (char*)lParam); - - return ChangeInfoEx(CIXT_BASIC, 0); - } - - return 0; // Failure -} - -INT_PTR CIcqProto::SetPassword(WPARAM wParam, LPARAM lParam) -{ - char *pwd = (char*)lParam; - int len = strlennull(pwd); - - if (len && len < PASSWORDMAXLEN) - { - strcpy(m_szPassword, pwd); - m_bRememberPwd = TRUE; - } - return 0; -} - - -// TODO: Adding needs some more work in general - -HANDLE CIcqProto::AddToListByUIN(DWORD dwUin, DWORD dwFlags) -{ - int bAdded; - HANDLE hContact = HContactFromUIN(dwUin, &bAdded); - if (hContact) - { - if (!(dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) - { - setContactHidden(hContact, 0); - DBDeleteContactSetting(hContact, "CList", "NotOnList"); - } - - return hContact; // Success - } - - return NULL; // Failure -} - - -HANDLE CIcqProto::AddToListByUID(const char *szUID, DWORD dwFlags) -{ - int bAdded; - HANDLE hContact = HContactFromUID(0, szUID, &bAdded); - if (hContact) - { - if (!(dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) - { - setContactHidden(hContact, 0); - DBDeleteContactSetting(hContact, "CList", "NotOnList"); - } - - return hContact; // Success - } - - return NULL; // Failure -} - - -///////////////////////////////////////////////////////////////////////////////////////// - -void CIcqProto::ICQAddRecvEvent(HANDLE hContact, WORD wType, PROTORECVEVENT* pre, DWORD cbBlob, PBYTE pBlob, DWORD flags) -{ - if (pre->flags & PREF_CREATEREAD) - flags |= DBEF_READ; - - if (pre->flags & PREF_UTF) - flags |= DBEF_UTF; - - if (hContact && DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) - { - DWORD dwUin; - uid_str szUid; - - //setContactHidden(hContact, 0); - - // if the contact was hidden, add to client-list if not in server-list authed - if (!getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) || getSettingByte(hContact, "Auth", 0)) - { - getContactUid(hContact, &dwUin, &szUid); - icq_sendNewContact(dwUin, szUid); /// FIXME - } - } - - AddEvent(hContact, wType, pre->timestamp, flags, cbBlob, pBlob); -} - -INT_PTR __cdecl CIcqProto::IcqAddCapability(WPARAM wParam, LPARAM lParam) -{ - ICQ_CUSTOMCAP *icqCustomCapIn = (ICQ_CUSTOMCAP *)lParam; - ICQ_CUSTOMCAP *icqCustomCap = (ICQ_CUSTOMCAP *)malloc(sizeof(ICQ_CUSTOMCAP)); - memcpy(icqCustomCap, icqCustomCapIn, sizeof(ICQ_CUSTOMCAP)); - CustomCapList.push_back(icqCustomCap); -// MessageBoxA(NULL, ((ICQ_CUSTOMCAP *)(lstCustomCaps->items[lstCustomCaps->realCount-1]))->name, "custom cap", MB_OK); - return 0; -} - - -INT_PTR __cdecl CIcqProto::IcqCheckCapability(WPARAM wParam, LPARAM lParam) -{ - int res = 0; - DBCONTACTGETSETTING dbcgs; - DBVARIANT dbvariant; - HANDLE hContact = (HANDLE)wParam; - ICQ_CUSTOMCAP *icqCustomCap = (ICQ_CUSTOMCAP *)lParam; - dbcgs.pValue = &dbvariant; - dbcgs.szModule = m_szModuleName; - dbcgs.szSetting = "CapBuf"; - - CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); - - if (dbvariant.type == DBVT_BLOB) - { - res = MatchCapability(dbvariant.pbVal, dbvariant.cpbVal, (const capstr*)&icqCustomCap->caps, 0x10)?1:0; // FIXME: Why icqCustomCap->caps is not capstr? - } - - CallService(MS_DB_CONTACT_FREEVARIANT,0,(LPARAM)(DBVARIANT*)&dbvariant); - - return res; -} - - - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR icq_getEventTextMissedMessage(WPARAM wParam, LPARAM lParam) -{ - DBEVENTGETTEXT *pEvent = (DBEVENTGETTEXT *)lParam; - - INT_PTR nRetVal = 0; - char *pszText = NULL; - - if (pEvent->dbei->cbBlob > 1) - { - switch (((WORD*)pEvent->dbei->pBlob)[0]) - { - case 0: - pszText = LPGEN("** This message was blocked by the ICQ server ** The message was invalid."); - break; - - case 1: - pszText = LPGEN("** This message was blocked by the ICQ server ** The message was too long."); - break; - - case 2: - pszText = LPGEN("** This message was blocked by the ICQ server ** The sender has flooded the server."); - break; - - case 4: - pszText = LPGEN("** This message was blocked by the ICQ server ** You are too evil."); - break; - - default: - pszText = LPGEN("** Unknown missed message event."); - break; - } - if (pEvent->datatype == DBVT_WCHAR) - { - WCHAR *pwszText; - int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszText, strlennull(pszText), NULL, 0); - - pwszText = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); - pwszText[wchars] = 0; - - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszText, strlennull(pszText), pwszText, wchars); - - nRetVal = (INT_PTR)mir_wstrdup(TranslateW(pwszText)); - } - else if (pEvent->datatype == DBVT_ASCIIZ) - nRetVal = (INT_PTR)mir_strdup(Translate(pszText)); - } - - return nRetVal; -} diff --git a/protocols/IcqOscarJ/icqosc_svcs.h b/protocols/IcqOscarJ/icqosc_svcs.h deleted file mode 100644 index 844eecee51..0000000000 --- a/protocols/IcqOscarJ/icqosc_svcs.h +++ /dev/null @@ -1,39 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __ICQOSC_SVCS_H -#define __ICQOSC_SVCS_H - - -#define ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE "ICQ/GetEventTextMissedMessage" - -INT_PTR icq_getEventTextMissedMessage(WPARAM wParam, LPARAM lParam); - - -#endif /* __ICQOSC_SVCS_H */ diff --git a/protocols/IcqOscarJ/icqoscar.cpp b/protocols/IcqOscarJ/icqoscar.cpp deleted file mode 100644 index 5ce67145cd..0000000000 --- a/protocols/IcqOscarJ/icqoscar.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001,2002 Jon Keating, Richard Hughes -// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// The only purpose of this file is to make sure that the precompiled headers -// are included and compiled. The Visual Studio settings for this file must be -// 'Create precompiled header file' and all the other .c files must be set to -// 'User precompiled header file'. Remember to check this when adding new -// files to the project... -// -// ----------------------------------------------------------------------------- - - -#include "icqoscar.h" diff --git a/protocols/IcqOscarJ/icqoscar.h b/protocols/IcqOscarJ/icqoscar.h deleted file mode 100755 index ef0e32a6fd..0000000000 --- a/protocols/IcqOscarJ/icqoscar.h +++ /dev/null @@ -1,134 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Includes all header files that should be precompiled to speed up compilation. -// -// ----------------------------------------------------------------------------- -#define MIRANDA_VER 0x0A00 - -#define _WIN32_WINNT 0x0501 -#define _WIN32_IE 0x0501 - -#include - -// Windows includes -#include -#include -#include - -// Standard includes -#include -#include -#include -#include -#include -#include -#include -#include - -//C++ -#include - -#ifndef _DEBUG -#ifdef _MSC_VER - #include -#endif -#endif - -#ifndef AW_VER_POSITIVE -#define AW_VER_POSITIVE 0x00000004 -#endif - -#ifndef _ASSERTE -#define _ASSERTE(x) -#endif - -// Miranda IM SDK includes -#include // This must be included first -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Project resources -#include "resource.h" - -// ICQ plugin includes -#include "version.h" -#include "iconlib.h" -#include "globals.h" -#include "i18n.h" -#include "icq_db.h" -#include "cookies.h" -#include "icq_packet.h" -#include "utilities.h" -#include "oscar_filetransfer.h" -#include "icq_direct.h" -#include "icq_server.h" -#include "icqosc_svcs.h" -#include "icq_servlist.h" -#include "icq_http.h" -#include "icq_fieldnames.h" -#include "icq_constants.h" -#include "capabilities.h" -#include "guids.h" -#include "init.h" -#include "stdpackets.h" -#include "tlv.h" -#include "channels.h" -#include "families.h" -#include "m_icq.h" -#include "m_icqplus.h" -#include "icq_advsearch.h" -#include "log.h" - -#include "icq_rates.h" - -#include "icq_avatar.h" - -#include "changeinfo/changeinfo.h" -#include "icq_popups.h" -#include "icq_proto.h" - -extern LIST g_Instances; diff --git a/protocols/IcqOscarJ/icqoscar8_10.vcxproj b/protocols/IcqOscarJ/icqoscar8_10.vcxproj index 00cbc0213f..b94751a495 100644 --- a/protocols/IcqOscarJ/icqoscar8_10.vcxproj +++ b/protocols/IcqOscarJ/icqoscar8_10.vcxproj @@ -197,106 +197,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create - - - + + + diff --git a/protocols/IcqOscarJ/icqoscar8_10.vcxproj.filters b/protocols/IcqOscarJ/icqoscar8_10.vcxproj.filters index a7310551e1..3917331d49 100644 --- a/protocols/IcqOscarJ/icqoscar8_10.vcxproj.filters +++ b/protocols/IcqOscarJ/icqoscar8_10.vcxproj.filters @@ -33,248 +33,240 @@ - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Changeinfo - - Resource Files - - - Documentation - - - - + Resource Files - + FLAP Channels - + FLAP Channels - + FLAP Channels - + FLAP Channels - + FLAP Channels - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + SNAC Families - + Direct Connection - + Direct Connection - + Direct Connection - + Direct Connection - + Direct Connection - + Miranda Bits - + Miranda Bits - + Miranda Bits - + Miranda Bits - + Miranda Bits - + Miranda Bits - + Miranda Bits - + Miranda Bits - + UI - + UI - + UI - + UI - + UI - + UI - + Changeinfo - + Changeinfo - + Changeinfo - + Changeinfo - + Changeinfo - + Changeinfo - + Changeinfo - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + Miranda Bits diff --git a/protocols/IcqOscarJ/icqoscarj-translation.txt b/protocols/IcqOscarJ/icqoscarj-translation.txt deleted file mode 100644 index 520c8a1ce6..0000000000 --- a/protocols/IcqOscarJ/icqoscarj-translation.txt +++ /dev/null @@ -1,1044 +0,0 @@ -; Common strings that belong to many files -;[%d Files] -;[Add to server list] -;[Arabic] -;[Business] -;[Cancel] -;[Change ICQ Details] -;[Close] -;[Education] -;[Grant authorization] -;[Greek] -;[Hebrew] -;[Homepage] -;[ICQ] -;[ICQ Note] -;[Internet] -;[Japanese] -;[Korean] -;[No description given] -;[OK] -;[Other] -;[Request authorization] -;[Revoke authorization] -;[Thai] -;[Turkish] -;[Vietnamese] -;[Work] -;[Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.] -;[Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.] - -; ../../protocols/IcqOscarJ/UI/askauthentication.cpp -;[Please authorize me to add you to my contact list.] - -; ../../protocols/IcqOscarJ/UI/loginpassword.cpp -;[Enter a password for UIN %u:] - -; ../../protocols/IcqOscarJ/UI/userinfotab.cpp -;[ (DC Established)] -;[%s Details] -;[] -;[Member since:] -;[ScreenName:] - -; ../../protocols/IcqOscarJ/chan_04close.cpp -;[Connection failed.\nSecure (MD5) login is not supported on this account.] -;[Connection failed.\nServer has too many connections from your IP (%d).] -;[Connection failed.\nThe server did not accept this client version.] -;[Connection failed.\nThe server is temporarily unavailable (%d).] -;[Connection failed.\nUnknown error during sign on: 0x%02x] -;[Connection failed.\nYou have connected too quickly,\nplease wait and retry 10 to 20 minutes later (%d).] -;[Connection failed.\nYou were rejected by the server for an unknown reason.\nThis can happen if the UIN is already connected.] -;[Connection failed.\nYour ICQ number or password was rejected (%d).] -;[The server sent warning, this version is getting old.\nTry to look for a new one.] -;[Unable to connect to ICQ communication server] -;[Unable to connect to migrated ICQ communication server] -;[Unknown runtime error: 0x%02x] -;[You could not sign on because the server returned invalid data. Try again.] -;[You have been disconnected from the ICQ network because the current server shut down.] -;[You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number.] - -; ../../protocols/IcqOscarJ/changeinfo/constants.cpp -;[About] -;[Affiliation 1] -;[Affiliation 2] -;[Affiliation 3] -;[Affiliation category 1] -;[Affiliation category 2] -;[Affiliation category 3] -;[Affiliations] -;[Age] -;[April] -;[August] -;[Category 1] -;[Category 2] -;[Category 3] -;[Cellular number] -;[City] -;[Company ZIP/postcode] -;[Company city] -;[Company country] -;[Company department] -;[Company fax] -;[Company homepage] -;[Company industry] -;[Company name] -;[Company occupation] -;[Company phone] -;[Company position] -;[Company state] -;[Company street] -;[Contact] -;[Country] -;[Day of birth] -;[December] -;[Degree] -;[Fax number] -;[February] -;[First name] -;[GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca] -;[GMT+0:30] -;[GMT+10:00 East Australia; Guam; Vladivostok] -;[GMT+10:30] -;[GMT+11:00 Magadan; Solomon Is.; New Caledonia] -;[GMT+11:30] -;[GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is.] -;[GMT+1:00 Central European Time; West Central Africa; Warsaw] -;[GMT+1:30] -;[GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens] -;[GMT+2:30] -;[GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad] -;[GMT+3:30 Tehran] -;[GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat] -;[GMT+4:30 Kabul] -;[GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg] -;[GMT+5:30] -;[GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk; Sri Jayawardenepura] -;[GMT+6:30 Rangoon] -;[GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk] -;[GMT+7:30] -;[GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing] -;[GMT+8:30] -;[GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk] -;[GMT+9:30 Darwin; Adelaide] -;[GMT-0:30] -;[GMT-10:00 Hawaii] -;[GMT-10:30] -;[GMT-11:00 Midway Island; Samoa] -;[GMT-11:30] -;[GMT-12:00 Eniwetok; Kwajalein] -;[GMT-1:00 Cape Verde Islands; Azores] -;[GMT-1:30] -;[GMT-2:00 Mid-Atlantic] -;[GMT-2:30] -;[GMT-3:00 Greenland; Buenos Aires; Georgetown] -;[GMT-3:30 Newfoundland] -;[GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz] -;[GMT-4:30] -;[GMT-5:00 Eastern Time; Bogota; Lima; Quito] -;[GMT-5:30] -;[GMT-6:00 Central Time; Central America; Saskatchewan] -;[GMT-6:30] -;[GMT-7:00 Arizona; Mountain Time] -;[GMT-7:30] -;[GMT-8:00 Pacific Time; Tijuana] -;[GMT-8:30] -;[GMT-9:00 Alaska] -;[GMT-9:30] -;[Gender] -;[Graduation Year] -;[Institute] -;[Interest areas 1] -;[Interest areas 2] -;[Interest areas 3] -;[Interest areas 4] -;[Interest category 1] -;[Interest category 2] -;[Interest category 3] -;[Interest category 4] -;[January] -;[July] -;[June] -;[Last name] -;[Level] -;[March] -;[Marital Status] -;[May] -;[Month of birth] -;[Nickname] -;[November] -;[October] -;[Originally from] -;[Password] -;[Past Background] -;[Past Background 1] -;[Past Background 2] -;[Past Background 3] -;[Personal] -;[Personal Detail] -;[Personal Interests] -;[Phone number] -;[Primary e-mail] -;[Secondary e-mail] -;[September] -;[Spoken language 1] -;[Spoken language 2] -;[Spoken language 3] -;[State] -;[Street] -;[Tertiary e-mail] -;[Timezone] -;[Year of birth] -;[ZIP/postcode] - -; ../../protocols/IcqOscarJ/changeinfo/db.cpp -;[The ICQ server does not support passwords longer than 8 characters. Please use a shorter password.] -;[The password does not match the password you originally entered. Check Caps Lock and try again.] -;[The password does not match your current password. Check Caps Lock and try again.] - -; ../../protocols/IcqOscarJ/changeinfo/dlgproc.cpp -;[] -;[] -;[Unknown value] -;[Unspecified] -;[Upload FAILED] -;[Upload complete] -;[Upload in progress...] -;[You've made some changes to your ICQ details but it has not been saved to the server. Are you sure you want to close this dialog?] - -; ../../protocols/IcqOscarJ/changeinfo/upload.cpp -;[You are not currently connected to the ICQ network. You must be online in order to update your information on the server.] - -; ../../protocols/IcqOscarJ/fam_01service.cpp -;[A server migration has failed because the server returned invalid data. You must reconnect manually.] -;[Failed to request offline messages. They may be received next time you log in.] - -; ../../protocols/IcqOscarJ/fam_03buddy.cpp -;[Contact deleted & further events blocked.] -;[Spambot Detected] - -; ../../protocols/IcqOscarJ/fam_04message.cpp -;[Contact \"%s\" has closed the message window.] -;[Incoming URL:] -;[SNAC(4.1) SENDMSG Error (x%02x)] -;[The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E] -;[The contact does not support receiving offline messages.] -;[The messaging service is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x05] -;[The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09] -;[The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04] -;[The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13] -;[You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x02] -;[You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x03] -;[You sent too long message. The receiving client does not support it.\r\nSNAC(4.1) Error x0A] - -; ../../protocols/IcqOscarJ/fam_13servclist.cpp -;[Adding of contact to server list failed.] -;[Adding of group to server list failed.] -;[Adding of privacy item to server list failed.] -;[Contact \"%s\" lost its authorization in the server list.] -;[Contact \"%s\" was authorized in the server list.] -;[Moving of user to another group on server list failed.] -;[Removing of contact from server list failed.] -;[Removing of group from server list failed.] -;[Removing of privacy item from server list failed.] -;[Renaming of server group failed.] -;[Server contact list is unavailable, Miranda will use local contact list.] -;[Updating of group on server list failed.] -;[Updating of server contact failed.] -;[User \"%s\" was removed from server list.] - -; ../../protocols/IcqOscarJ/fam_17signon.cpp -;[Secure login failed.\nInvalid key length.] -;[Secure login failed.\nInvalid server response.] - -; ../../protocols/IcqOscarJ/icq_avatar.cpp -;[Error uploading avatar to server, server refused to accept the image.] -;[Error uploading avatar to server, server temporarily unavailable.] - -; ../../protocols/IcqOscarJ/icq_fieldnames.cpp -;[50's] -;[60's] -;[60-above] -;[70's] -;[80's] -;[Academic] -;[Administrative] -;[Afghanistan] -;[Afrikaans] -;[Agriculture] -;[Albania] -;[Albanian] -;[Algeria] -;[Alumni Org.] -;[Andorra] -;[Angola] -;[Anguilla] -;[Antigua and Barbuda] -;[Antilles] -;[Argentina] -;[Armenia] -;[Armenian] -;[Art] -;[Art/Entertainment] -;[Arts] -;[Aruba] -;[Ascension Island] -;[Associated degree] -;[Astronomy] -;[Audio and Visual] -;[Australia] -;[Australia, Antarctic Territory] -;[Australia, Christmas Island] -;[Australia, Cocos (Keeling) Islands] -;[Australia, Norfolk Island] -;[Austria] -;[Azerbaijan] -;[Azerbaijani] -;[Bachelor's degree] -;[Bahamas] -;[Bahrain] -;[Bangladesh] -;[Barbados] -;[Barbuda] -;[Belarus] -;[Belgium] -;[Belize] -;[Belorussian] -;[Benin] -;[Bermuda] -;[Bhojpuri] -;[Bhutan] -;[Bolivia] -;[Bosnia and Herzegovina] -;[Bosnian] -;[Botswana] -;[Brazil] -;[British Virgin Islands] -;[Brunei] -;[Bulgaria] -;[Bulgarian] -;[Burkina Faso] -;[Burmese] -;[Burundi] -;[Business Services] -;[Cambodia] -;[Cameroon] -;[Canada] -;[Canary Islands] -;[Cantonese] -;[Cape Verde Islands] -;[Cars] -;[Catalan] -;[Cayman Islands] -;[Celebrity Fans] -;[Central African Republic] -;[Chad] -;[Chamorro] -;[Charity Org.] -;[Chile, Republic of] -;[China] -;[Chinese] -;[Close relationships] -;[Clothing] -;[Club/Social Org.] -;[Cocos (Keeling) Islands] -;[Collections] -;[College] -;[College Student] -;[Colombia] -;[Community & Social] -;[Community Org.] -;[Comoros] -;[Computers] -;[Congo, Democratic Republic of (Zaire)] -;[Congo, Republic of the] -;[Construction] -;[Consumer Goods] -;[Cook Islands] -;[Corporate Services] -;[Costa Rica] -;[Cote d'Ivoire (Ivory Coast)] -;[Croatia] -;[Croatian] -;[Cuba] -;[Cultural Org.] -;[Culture] -;[Curacao] -;[Czech] -;[Czech Republic] -;[Danish] -;[Denmark] -;[Diego Garcia] -;[Divorced] -;[Djibouti] -;[Dominica] -;[Dominican Republic] -;[Dutch] -;[Ecology] -;[Ecuador] -;[Egypt] -;[El Salvador] -;[Elementary] -;[Elementary School] -;[Engaged] -;[Engineering] -;[English] -;[Entertainment] -;[Equatorial Guinea] -;[Eritrea] -;[Esperanto] -;[Estonia] -;[Estonian] -;[Ethiopia] -;[Europe] -;[Faeroe Islands] -;[Falkland Islands] -;[Fan Clubs] -;[Farsi] -;[Female] -;[Fiji] -;[Finance] -;[Finance and Corporate] -;[Financial Services] -;[Finland] -;[Finnish] -;[Fitness] -;[France] -;[Fraternity/Sorority] -;[French] -;[French Antilles] -;[French Guiana] -;[French Polynesia] -;[Gabon] -;[Gaelic] -;[Gambia] -;[Games] -;[Georgia] -;[German] -;[Germany] -;[Ghana] -;[Gibraltar] -;[Government] -;[Greece] -;[Greek, Republic of South Cyprus] -;[Greenland] -;[Grenada] -;[Guadeloupe] -;[Guam, US Territory of] -;[Guatemala] -;[Guinea] -;[Guinea-Bissau] -;[Gujarati] -;[Guyana] -;[Haiti] -;[Health and Beauty] -;[High School] -;[High School Student] -;[High Tech] -;[High-school] -;[Hindi] -;[Hobbies] -;[Hobbyists Org.] -;[Home] -;[Home Automation] -;[Honduras] -;[Hong Kong] -;[Household Products] -;[Hungarian] -;[Hungary] -;[ICQ - Help] -;[ICQ - Providing Help] -;[Iceland] -;[Icelandic] -;[India] -;[Indonesia] -;[Indonesian] -;[International Org.] -;[Iran (Islamic Republic of)] -;[Iraq] -;[Ireland] -;[Israel] -;[Italian] -;[Italy] -;[Jamaica] -;[Japan] -;[Jordan] -;[Kazakhstan] -;[Kenya] -;[Khmer] -;[Kiribati] -;[Korea, North] -;[Korea, South] -;[Kosovo, Republic of] -;[Kurdish] -;[Kuwait] -;[Kyrgyzstan] -;[Lao] -;[Laos] -;[Latvia] -;[Latvian] -;[Law] -;[Lebanon] -;[Legal] -;[Lesotho] -;[Liberia] -;[Libyan Arab Jamahiriya] -;[Liechtenstein] -;[Lifestyle] -;[Lithuania] -;[Lithuanian] -;[Luxembourg] -;[Macau] -;[Macedonia, Republic of] -;[Macedonian] -;[Madagascar] -;[Mail Order Catalog] -;[Malawi] -;[Malay] -;[Malaysia] -;[Maldives] -;[Male] -;[Mali] -;[Malta] -;[Managerial] -;[Mandarin] -;[Manufacturing] -;[Married] -;[Marshall Islands] -;[Martinique] -;[Master's degree] -;[Mauritania] -;[Mauritius] -;[Mayotte Island] -;[Media] -;[Medical & Health Care] -;[Medical/Health] -;[Mexico] -;[Micronesia, Federated States of] -;[Military] -;[Moldova, Republic of] -;[Monaco] -;[Mongolia] -;[Mongolian] -;[Montenegro, Republic of] -;[Montserrat] -;[Morocco] -;[Movies and TV] -;[Mozambique] -;[Music] -;[Myanmar] -;[Mystics] -;[Namibia] -;[Nature and Environment Org.] -;[Nauru] -;[Nepal] -;[Netherlands] -;[Netherlands (Bonaire Island)] -;[Netherlands (Saba Island)] -;[Netherlands (St. Eustatius Island)] -;[Netherlands Antilles] -;[Nevis] -;[New Caledonia] -;[New Zealand] -;[News and Media] -;[Nicaragua] -;[Niger] -;[Nigeria] -;[Niue] -;[Non-Government Organization] -;[Non-Profit Organization Management] -;[Northern Mariana Islands, US Territory of] -;[Norway] -;[Norwegian] -;[Oman] -;[Open relationship] -;[Other Services] -;[Outdoors] -;[Pakistan] -;[Palau] -;[Panama] -;[Papua New Guinea] -;[Paraguay] -;[Parenting] -;[Parties] -;[Past Organization] -;[Past Work Place] -;[Persian] -;[Peru] -;[Pets and Animals] -;[PhD] -;[Philippines] -;[Poland] -;[Polish] -;[Portugal] -;[Portuguese] -;[Postdoctoral] -;[Professional] -;[Professional Org.] -;[Publishing] -;[Puerto Rico] -;[Punjabi] -;[Qatar] -;[Recreation, Travel & Entertainment] -;[Religion] -;[Retail] -;[Retail Stores] -;[Retired] -;[Reunion Island] -;[Romania] -;[Romanian] -;[Rota Island] -;[Russia] -;[Russian] -;[Rwanda] -;[Saint Helena] -;[Saint Kitts] -;[Saint Kitts and Nevis] -;[Saint Lucia] -;[Saint Pierre and Miquelon] -;[Saint Vincent and the Grenadines] -;[Saipan Island] -;[Samoa (USA)] -;[Samoa, Western] -;[San Marino] -;[Sao Tome and Principe] -;[Saudi Arabia] -;[Science] -;[Science & Research] -;[Scientific/Technical Org.] -;[Scotland] -;[Self Improvement Group] -;[Senegal] -;[Separated] -;[Serbia, Republic of] -;[Serbian] -;[Service Industry] -;[Seychelles] -;[Sierra Leone] -;[Sindhi] -;[Singapore] -;[Single] -;[Skills] -;[Slovak] -;[Slovakia] -;[Slovenia] -;[Slovenian] -;[Social science] -;[Solomon Islands] -;[Somali] -;[Somalia] -;[South Africa] -;[Space] -;[Spain] -;[Spain, Canary Islands] -;[Spanish] -;[Spiritual/Religious Org.] -;[Sporting and Athletic] -;[Sports] -;[Sports Org.] -;[Sri Lanka] -;[St. Maarten] -;[Sudan] -;[Support Org.] -;[Suriname] -;[Swahili] -;[Swaziland] -;[Sweden] -;[Swedish] -;[Switzerland] -;[Syrian Arab Republic] -;[Tagalog] -;[Taiwan] -;[Taiwanese] -;[Tajikistan] -;[Tamil] -;[Tanzania] -;[Tatar] -;[Technical] -;[Thailand] -;[Timor, East] -;[Tinian Island] -;[Togo] -;[Tokelau] -;[Tonga] -;[Trade and Business Org.] -;[Transportation] -;[Travel] -;[Trinidad and Tobago] -;[Tunisia] -;[Turkey] -;[Turkey, Republic of Northern Cyprus] -;[Turkmenistan] -;[Turks and Caicos Islands] -;[Tuvalu] -;[USA] -;[Uganda] -;[Ukraine] -;[Ukrainian] -;[Union] -;[United Arab Emirates] -;[United Kingdom] -;[University] -;[University / College] -;[University Student] -;[Urdu] -;[Uruguay] -;[Uzbekistan] -;[Vanuatu] -;[Vatican City] -;[Venezuela] -;[Vietnam] -;[Virgin Islands (UK)] -;[Virgin Islands (USA)] -;[Volunteer Org.] -;[Wales] -;[Wallis and Futuna Islands] -;[Web Building] -;[Web Design] -;[Welsh] -;[Widowed] -;[Women] -;[Yemen] -;[Yiddish] -;[Yoruba] -;[Yugoslavia] -;[Zambia] -;[Zimbabwe] - -; ../../protocols/IcqOscarJ/icq_menu.cpp -;[Open ICQ profile] -;[Show custom status details] - -; ../../protocols/IcqOscarJ/icq_opts.cpp -;[Account] -;[Baltic] -;[Central European] -;[Contacts] -;[Cyrillic] -;[Display all problems] -;[Display explanations for disconnection] -;[Display problems causing possible loss of data] -;[Display problems requiring user intervention] -;[Do not display any problems (not recommended)] -;[Features] -;[Korean (Johab)] -;[Latin I] -;[Network] -;[Popups] -;[Privacy] -;[Simplified Chinese] -;[System default codepage] -;[Traditional Chinese] - -; ../../protocols/IcqOscarJ/icq_popups.cpp -;[Popup Title] -;[Sample Error] -;[Sample Fatal] -;[Sample Note] -;[Sample Spambot] -;[Sample Warning] - -; ../../protocols/IcqOscarJ/icq_proto.cpp -;[%s client-to-client connections] -;[%s server connection] -;[User ID] -;[You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again.] - -; ../../protocols/IcqOscarJ/icq_server.cpp -;[Connection failed.\nLogin sequence failed for unknown reason.\nTry again later.] -;[Miranda was unable to allocate a port to listen for direct peer-to-peer connections between clients. You will be able to use most of the ICQ network without problems but you may be unable to send or receive files.\n\nIf you have a firewall this may be blocking Miranda, in which case you should configure your firewall to leave some ports open and tell Miranda which ports to use in M->Options->ICQ->Network.] -;[Unable to connect to ICQ login server] -;[Unable to connect to ICQ login server, SSL could not be negotiated] -;[Your connection with the ICQ server was abortively closed] - -; ../../protocols/IcqOscarJ/icq_servlist.cpp -;[Failed to create the correct sub-group, the using closest parent group.] -;[The contact's information was too big and was truncated.] - -; ../../protocols/IcqOscarJ/icq_uploadui.cpp -;[** All contacts **] -;[ALREADY EXISTS] -;[Adding %s to invisible list...] -;[Adding %s to visible list...] -;[Adding group \"%s\"...] -;[All operations complete] -;[Cleaning groups] -;[Deleting %s from invisible list...] -;[Deleting %s from visible list...] -;[Deleting %s...] -;[Deleting group \"%s\"...] -;[FAILED] -;[INVALID DATA] -;[LIST FULL] -;[Moving %s to group \"%s\"...] -;[NOT FOUND] -;[No upload group available] -;[Ready...] -;[Select contacts you want to store on server.] -;[Server rate warning -> slowing down the process.] -;[Updating group \"%s\"...] -;[Uploading %s...] -;[You have to be online to sychronize the server-list !] - -; ../../protocols/IcqOscarJ/icq_xstatus.cpp -;[%s Custom Status] -;[@home] -;[@work] -;[Afro] -;[Alien] -;[Angel] -;[Angry] -;[Baby] -;[Basketball] -;[Beetle] -;[Birdie] -;[Birthday] -;[Broken hearted] -;[Candy] -;[Celebrating] -;[Cocktail] -;[Coffee] -;[Cooking] -;[Cool] -;[Crazy Professor] -;[Cupid shot me] -;[Cyclop] -;[Depressed] -;[Dog] -;[Donut] -;[Double Rainbow] -;[Drinking beer] -;[Eating] -;[Evil] -;[Feeling Good] -;[Feeling sick] -;[Free for Chat] -;[Gaming] -;[Having fun] -;[Headmaster] -;[Hot Dog] -;[I'm high] -;[Ice-Cream] -;[Kitty] -;[Laughing] -;[Lips] -;[Listening to music] -;[Lollypop] -;[Love] -;[Mask] -;[Meeting] -;[Money] -;[Monkey] -;[Ninja] -;[None] -;[Oink Oink] -;[On WC] -;[On my mobile] -;[On the phone] -;[Picnic] -;[Pilot] -;[Pink Lady] -;[Pirate] -;[Pizza] -;[Playing] -;[Punch] -;[Rock On] -;[Rough] -;[Scooter] -;[Shooting] -;[Shopping] -;[Sleeping] -;[Smoking] -;[Snoring] -;[Soccer] -;[St. Patrick] -;[Strawberry] -;[Studying] -;[Sumo] -;[Surfing] -;[Sushi] -;[Taking a bath] -;[Thinking] -;[Tired] -;[To be or not to be] -;[Typing] -;[Up yours] -;[Watching TV] -;[Watching pro7 on TV] -;[Working] -;[Writing] - -; ../../protocols/IcqOscarJ/icq_xtraz.cpp -;[Greeting card:] - -; ../../protocols/IcqOscarJ/icqosc_svcs.cpp -;[** This message was blocked by the ICQ server ** The message was invalid.] -;[** This message was blocked by the ICQ server ** The message was too long.] -;[** This message was blocked by the ICQ server ** The sender has flooded the server.] -;[** This message was blocked by the ICQ server ** You are too evil.] -;[** Unknown missed message event.] -;[Are you sure you want to revoke user's authorization (this will remove you from his/her list on some clients) ?] -;[Confirmation] - -; ../../protocols/IcqOscarJ/init.cpp -;[ICQ Plugin] -;[You cannot use Unicode version of ICQ Protocol plug-in with Ansi version of Miranda IM.] - -; ../../protocols/IcqOscarJ/log.cpp -;[ICQ Error] -;[ICQ Fatal] -;[ICQ Warning] -;[Miranda was unable to make a connection with a server. It is likely that the server is down, in which case you should wait for a while and try again later.] -;[Miranda was unable to resolve the name of a server to its numeric address. This is most likely caused by a catastrophic loss of your network connection (for example, your modem has disconnected), but if you are behind a proxy, you may need to use the 'Resolve hostnames through proxy' option in M->Options->Network.] -;[The connection with the server was abortively closed during the connection attempt. You may have lost your local network connection.] -;[The server did not respond to the connection attempt within a reasonable time, it may be temporarily down. Try again later.] -;[The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ.] -;[Your proxy rejected the user name and password that you provided. Please check them in M->Options->Network.] -;[error] - -; ../../protocols/IcqOscarJ/oscar_filetransfer.cpp -;[Connection lost during file transfer.] -;[Failed to Initialize File Transfer. No valid files were specified.] -;[Failed to Initialize File Transfer. Unable to bind local port and File proxy unavailable.] -;[File transfer negotiation failed for unknown reason.] -;[The checksum of file \"%s\" does not match, the file is probably damaged.] -;[The file transfer failed: Invalid request] -;[The file transfer failed: Proxy error] -;[The file transfer failed: Proxy unavailable] -;[The file transfer was aborted by the other user.] -;[The files are too big to be sent at once. Files bigger than 4GB can be sent only separately.] - -; ../../protocols/IcqOscarJ/resources.rc -;[&Cancel] -;[&Save changes] -;[&Send] -;[&Use Windows colors] -;[(*) Timeouts require Popup v. 1.0.1.9 or later] -;[Add contacts to the server's list when I add them to mine] -;[Age:] -;[All users may add me to their Contact List] -;[Allow direct connections only when I authorize or initiate them] -;[Allow direct connections with any user] -;[Allow direct connections with users on my contact list] -;[Allow others to view my Online / Offline status from the web (Web Aware)] -;[Allow others to view my primary e-mail address] -;[Allowing direct connections will expose your IP address but may be necessary for some ICQ features to work properly.] -;[Auto-retrieve Custom status details] -;[Back Color] -;[Background info] -;[Block known Spam Bots] -;[Category:] -;[Check avatar validity before saving *] -;[City:] -;[Closing in %d] -;[Company:] -;[Confirm Password Change] -;[Connection settings] -;[Contact List Authorization] -;[Country:] -;[Create a new ICQ account] -;[Create a new ICQ account using the ICQ website] -;[Custom Status \"%s\" Details] -;[Default] -;[Department:] -;[Direct connections] -;[Display errors using popups] -;[Display popup when spambot is detected] -;[E-mail:] -;[Enable AIM contacts support] -;[Enable Custom status support for moods] -;[Enable Custom status support for xtraz] -;[Enable avatar support] -;[Enable peer-to-peer message connections] -;[Enable popup support] -;[Enable server-side contact lists *] -;[Enable unicode messaging support] -;[Enter ICQ Password] -;[Enter a password for UIN %d:] -;[Enter an authorization request] -;[Enter your current password:] -;[Error] -;[External IP:] -;[Extra Features] -;[Fatal] -;[First name:] -;[Gender:] -;[Hint: If you don't enter your password here, Miranda will ask for the password everytime you try to go online.] -;[Hint: Use port 0 to connect on a random port. Try port 80 or port 443 if you are having problems connecting through a http proxy server.] -;[I want to be asked when someone wants to add me to their Contact List] -;[ICQ Number:] -;[ICQ avatars] -;[ICQ contacts stored on server] -;[ICQ number:] -;[Idle since:] -;[Ignore concurrent error messages] -;[Interests] -;[Internal IP:] -;[Keywords:] -;[Language:] -;[Last name:] -;[Load avatars automatically (like ICQ Lite)] -;[Location] -;[Login Server:] -;[Look && Feel] -;[Make me temporarily visible to contacts I send message to] -;[Manage ICQ Server Contacts] -;[Manage server's list...] -;[Marital status:] -;[Message:] -;[Messaging] -;[Misc Settings] -;[Never use legacy messaging (server acknowledgements)] -;[Nickname:] -;[Note] -;[Note: The options marked with an asterisk have important side-effects or caveats that may not be initially apparent documented in the help.] -;[Notify me when a message delivery has failed (recommended)] -;[Occupation:] -;[Online since:] -;[Only reply to status message request from visible contacts] -;[Only reply to status message requests from users on my contact list] -;[Options] -;[Organisation:] -;[Passive mode, i.e. do not initiate new connections] -;[Password:] -;[Past] -;[Peer-to-peer Messaging] -;[Please re-type your new password:] -;[Port:] -;[Position:] -;[Previe&w] -;[Protocol Version:] -;[Remember this session password] -;[Reset Custom status on status change] -;[Retrieve a lost password or ICQ number] -;[Retrieving custom status details...] -;[Search online users only] -;[Secure (MD5) login] -;[Secure Connection (SSL)] -;[Select contacts to store:] -;[Send 'Keep-alives' (enable this if you use a proxy server and frequently get disconnected)] -;[Send all messages in unicode if possible] -;[Show connection error messages:] -;[Slider1] -;[Some options are greyed out because they can only be changed when you are online.] -;[Spam detected] -;[State:] -;[Status:] -;[Summary] -;[Synchronize] -;[System up since:] -;[Text Color] -;[Timeout (*)] -;[Title:] -;[UIN:] -;[Update contacts' details on the server's list when I change them in mine] -;[Update my contacts' details from the server *] -;[Use system &icons] -;[Use this codepage for Ansi <-> Unicode translation :] -;[User Client:] -;[Warning] -;[You cannot enable/disable the server-side contact list while you are connected to the ICQ network.] -;[You will need to reconnect to the ICQ network for the changes you have made on this page to take effect.] - -; ../../protocols/IcqOscarJ/utilities.cpp -;[] diff --git a/protocols/IcqOscarJ/init.cpp b/protocols/IcqOscarJ/init.cpp deleted file mode 100644 index 450ea73b16..0000000000 --- a/protocols/IcqOscarJ/init.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" -#include "m_extraicons.h" - -HINSTANCE hInst; -int hLangpack; - -HANDLE hStaticServices[1]; -IcqIconHandle hStaticIcons[4]; -HANDLE hStaticHooks[1];; -HANDLE hExtraXStatus = NULL; - -PLUGININFOEX pluginInfo = { - sizeof(PLUGININFOEX), - "IcqOscarJ Protocol", - __VERSION_DWORD, - "Support for ICQ network, enhanced.", - "Joe Kucera, Bio, Martin Öberg, Richard Hughes, Jon Keating, etc", - "jokusoftware@miranda-im.org", - "(C) 2000-2010 M.Öberg, R.Hughes, J.Keating, Bio, Angeli-Ka, G.Hazan, J.Kucera", - "http://miranda-ng.org/", - UNICODE_AWARE, //doesn't replace anything built-in - {0x73a9615c, 0x7d4e, 0x4555, {0xba, 0xdb, 0xee, 0x5, 0xdc, 0x92, 0x8e, 0xff}} // {73A9615C-7D4E-4555-BADB-EE05DC928EFF} -}; - -extern "C" PLUGININFOEX __declspec(dllexport) *MirandaPluginInfoEx(DWORD mirandaVersion) -{ - return &pluginInfo; -} - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - -extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) -{ - hInst = hinstDLL; - return TRUE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static PROTO_INTERFACE* icqProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) -{ - CIcqProto *ppro = new CIcqProto(pszProtoName, tszUserName); - g_Instances.insert(ppro); - return ppro; -} - - -static int icqProtoUninit( PROTO_INTERFACE* ppro ) -{ - g_Instances.remove(( CIcqProto* )ppro); - delete ( CIcqProto* )ppro; - return 0; -} - - -static int OnModulesLoaded( WPARAM, LPARAM ) -{ - hExtraXStatus = ExtraIcon_Register("xstatus", "ICQ XStatus"); - return 0; -} - - -extern "C" int __declspec(dllexport) Load(void) -{ - mir_getLP( &pluginInfo ); - - srand(time(NULL)); - _tzset(); - - // Register the module - PROTOCOLDESCRIPTOR pd = {0}; - pd.cbSize = sizeof(pd); - pd.szName = ICQ_PROTOCOL_NAME; - pd.type = PROTOTYPE_PROTOCOL; - pd.fnInit = icqProtoInit; - pd.fnUninit = icqProtoUninit; - CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); - - // Initialize charset conversion routines - InitI18N(); - - // Register static services - hStaticServices[0] = CreateServiceFunction(ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE, icq_getEventTextMissedMessage); - - { - // Define global icons - char szSectionName[MAX_PATH]; - null_snprintf(szSectionName, sizeof(szSectionName), "Protocols/%s", ICQ_PROTOCOL_NAME); - - TCHAR lib[MAX_PATH]; - GetModuleFileName(hInst, lib, MAX_PATH); - hStaticIcons[ISI_AUTH_REQUEST] = IconLibDefine(LPGEN("Request authorization"), szSectionName, NULL, "req_auth", lib, -IDI_AUTH_ASK); - hStaticIcons[ISI_AUTH_GRANT] = IconLibDefine(LPGEN("Grant authorization"), szSectionName, NULL, "grant_auth", lib, -IDI_AUTH_GRANT); - hStaticIcons[ISI_AUTH_REVOKE] = IconLibDefine(LPGEN("Revoke authorization"), szSectionName, NULL, "revoke_auth", lib, -IDI_AUTH_REVOKE); - hStaticIcons[ISI_ADD_TO_SERVLIST] = IconLibDefine(LPGEN("Add to server list"), szSectionName, NULL, "add_to_server", lib, -IDI_SERVLIST_ADD); - } - - hStaticHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); - - g_MenuInit(); - return 0; -} - - -extern "C" int __declspec(dllexport) Unload(void) -{ - int i; - - // Release static icon handles - for (i = 0; i < SIZEOF(hStaticIcons); i++) - IconLibRemove(&hStaticIcons[i]); - - // Release static event hooks - for (i = 0; i < SIZEOF(hStaticHooks); i++) - if (hStaticHooks[i]) - UnhookEvent(hStaticHooks[i]); - - // destroying contact menu - g_MenuUninit(); - - // Destroy static service functions - for (i = 0; i < SIZEOF(hStaticServices); i++) - if (hStaticServices[i]) - DestroyServiceFunction(hStaticServices[i]); - - g_Instances.destroy(); - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// OnPrebuildContactMenu event - -void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow) -{ - CLISTMENUITEM mi = {0}; - - mi.cbSize = sizeof(mi); - if (bShow) - mi.flags = CMIM_FLAGS; - else - mi.flags = CMIM_FLAGS | CMIF_HIDDEN; - - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItem, (LPARAM)&mi); -} - -static void CListSetMenuItemIcon(HANDLE hMenuItem, HICON hIcon) -{ - CLISTMENUITEM mi = {0}; - - mi.cbSize = sizeof(mi); - mi.flags = CMIM_FLAGS | CMIM_ICON; - - mi.hIcon = hIcon; - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItem, (LPARAM)&mi); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnReloadIcons event - -int CIcqProto::OnReloadIcons(WPARAM wParam, LPARAM lParam) -{ - memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// UpdateGlobalSettings event - -void CIcqProto::UpdateGlobalSettings() -{ - char szServer[MAX_PATH] = ""; - getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH); - - m_bSecureConnection = getSettingByte(NULL, "SecureConnection", DEFAULT_SECURE_CONNECTION); - if (szServer[0]) - { - if (strstr(szServer, "aol.com")) - setSettingString(NULL, "OscarServer", m_bSecureConnection ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); - - if (m_bSecureConnection && !_strnicmp(szServer, "login.", 6)) - { - setSettingString(NULL, "OscarServer", DEFAULT_SERVER_HOST_SSL); - setSettingWord(NULL, "OscarPort", DEFAULT_SERVER_PORT_SSL); - } - } - - if (m_hServerNetlibUser) - { - NETLIBUSERSETTINGS nlus = {0}; - - nlus.cbSize = sizeof(NETLIBUSERSETTINGS); - if (!m_bSecureConnection && CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)m_hServerNetlibUser, (LPARAM)&nlus)) - { - if (nlus.useProxy && nlus.proxyType == PROXYTYPE_HTTP) - m_bGatewayMode = 1; - else - m_bGatewayMode = 0; - } - else - m_bGatewayMode = 0; - } - - m_bSecureLogin = getSettingByte(NULL, "SecureLogin", DEFAULT_SECURE_LOGIN); - m_bAimEnabled = getSettingByte(NULL, "AimEnabled", DEFAULT_AIM_ENABLED); - m_bUtfEnabled = getSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED); - m_wAnsiCodepage = getSettingWord(NULL, "AnsiCodePage", DEFAULT_ANSI_CODEPAGE); - m_bDCMsgEnabled = getSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED); - m_bTempVisListEnabled = getSettingByte(NULL, "TempVisListEnabled", DEFAULT_TEMPVIS_ENABLED); - m_bSsiEnabled = getSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED); - m_bSsiSimpleGroups = FALSE; /// TODO: enable, after server-list revolution is over - m_bAvatarsEnabled = getSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED); - m_bXStatusEnabled = getSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED); - m_bMoodsEnabled = getSettingByte(NULL, "MoodsEnabled", DEFAULT_MOODS_ENABLED); -} diff --git a/protocols/IcqOscarJ/init.h b/protocols/IcqOscarJ/init.h deleted file mode 100644 index 0e93a8a89f..0000000000 --- a/protocols/IcqOscarJ/init.h +++ /dev/null @@ -1,40 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -// Debug defines -#define DBG_CAPHTML -#define DBG_CAPMTN -#define DBG_CAPXTRAZ -#undef DBG_CAPXTRAZ_MUC -#define DBG_NEWCAPS -#define DBG_OSCARFT -#define DBG_AIMCONTACTSEND - -void g_MenuInit(); -void g_MenuUninit(); diff --git a/protocols/IcqOscarJ/log.cpp b/protocols/IcqOscarJ/log.cpp deleted file mode 100644 index 402863a456..0000000000 --- a/protocols/IcqOscarJ/log.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -extern BOOL bPopUpService; - -static const char *szLevelDescr[] = {LPGEN("ICQ Note"), LPGEN("ICQ Warning"), LPGEN("ICQ Error"), LPGEN("ICQ Fatal")}; - -struct LogMessageInfo { - const char *szMsg; - const char *szTitle; - BYTE bLevel; -}; - - -void __cdecl CIcqProto::icq_LogMessageThread(void* arg) -{ - LogMessageInfo *err = (LogMessageInfo*)arg; - if (!err) - return; - - if (bPopUpService && getSettingByte(NULL, "PopupsLogEnabled", DEFAULT_LOG_POPUPS_ENABLED)) - { - ShowPopUpMsg(NULL, err->szTitle, err->szMsg, err->bLevel); - - SAFE_FREE((void**)&err->szMsg); - SAFE_FREE((void**)&err); - - return; - } - - bErrorBoxVisible = TRUE; - if (err->szMsg && err->szTitle) - MessageBoxUtf(NULL, err->szMsg, err->szTitle, MB_OK); - SAFE_FREE((void**)&err->szMsg); - SAFE_FREE((void**)&err); - bErrorBoxVisible = FALSE; -} - - -void CIcqProto::icq_LogMessage(int level, const char *szMsg) -{ - NetLog_Server("%s", szMsg); - - int displayLevel = getSettingByte(NULL, "ShowLogLevel", LOG_WARNING); - if (level >= displayLevel) - { - if (!bErrorBoxVisible || !getSettingByte(NULL, "IgnoreMultiErrorBox", 0)) - { - // error not shown or allowed multi - show messagebox - LogMessageInfo *lmi = (LogMessageInfo*)SAFE_MALLOC(sizeof(LogMessageInfo)); - lmi->bLevel = (BYTE)level; - lmi->szMsg = null_strdup(szMsg); - lmi->szTitle = szLevelDescr[level]; - ForkThread( &CIcqProto::icq_LogMessageThread, lmi); - } - } -} - -void CIcqProto::icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg) -{ - char szBuf[1024]; - char str[1024]; - char str2[64]; - char szErrorMsg[512]; - char *pszErrorMsg = NULL; - int bNeedFree = FALSE; - - switch(dwError) { - case ERROR_TIMEOUT: - case WSAETIMEDOUT: - pszErrorMsg = LPGEN("The server did not respond to the connection attempt within a reasonable time, it may be temporarily down. Try again later."); - break; - - case ERROR_GEN_FAILURE: - pszErrorMsg = LPGEN("The connection with the server was abortively closed during the connection attempt. You may have lost your local network connection."); - break; - - case WSAEHOSTUNREACH: - case WSAENETUNREACH: - pszErrorMsg = LPGEN("Miranda was unable to resolve the name of a server to its numeric address. This is most likely caused by a catastrophic loss of your network connection (for example, your modem has disconnected), but if you are behind a proxy, you may need to use the 'Resolve hostnames through proxy' option in M->Options->Network."); - break; - - case WSAEHOSTDOWN: - case WSAENETDOWN: - case WSAECONNREFUSED: - pszErrorMsg = LPGEN("Miranda was unable to make a connection with a server. It is likely that the server is down, in which case you should wait for a while and try again later."); - break; - - case ERROR_ACCESS_DENIED: - pszErrorMsg = LPGEN("Your proxy rejected the user name and password that you provided. Please check them in M->Options->Network."); - break; - - case WSAHOST_NOT_FOUND: - case WSANO_DATA: - pszErrorMsg = LPGEN("The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ."); - break; - - default: - { - TCHAR err[512]; - - if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, err, SIZEOF(err), NULL)) - { - - pszErrorMsg = make_utf8_string(err); - - bNeedFree = TRUE; - } - break; - } - } - - null_snprintf(szBuf, sizeof(szBuf), "%s%s%s (%s %d)", - szMsg ? ICQTranslateUtfStatic(szMsg, str, 1024) : "", - szMsg ? "\r\n\r\n" : "", - ICQTranslateUtfStatic(pszErrorMsg, szErrorMsg, 512), - ICQTranslateUtfStatic(LPGEN("error"), str2, 64), - dwError); - - if (bNeedFree) - SAFE_FREE(&pszErrorMsg); - - icq_LogMessage(level, szBuf); -} - -void CIcqProto::icq_LogFatalParam(const char *szMsg, WORD wError) -{ - char str[MAX_PATH]; - char buf[MAX_PATH]; - - null_snprintf(buf, MAX_PATH, ICQTranslateUtfStatic(szMsg, str, MAX_PATH), wError); - icq_LogMessage(LOG_FATAL, buf); -} diff --git a/protocols/IcqOscarJ/log.h b/protocols/IcqOscarJ/log.h deleted file mode 100644 index 6da25df0d7..0000000000 --- a/protocols/IcqOscarJ/log.h +++ /dev/null @@ -1,38 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __LOG_H -#define __LOG_H - -#define LOG_NOTE 0 //trivial problems or problems that will already have been reported elsewhere -#define LOG_WARNING 1 //problems that may have caused data loss -#define LOG_ERROR 2 //problems that cause a disconnection from the network -#define LOG_FATAL 3 //problems requiring user intervention: password wrong, rate exceeded, etc. - -#endif /* __LOG_H */ diff --git a/protocols/IcqOscarJ/oscar_filetransfer.cpp b/protocols/IcqOscarJ/oscar_filetransfer.cpp deleted file mode 100644 index 9630abc070..0000000000 --- a/protocols/IcqOscarJ/oscar_filetransfer.cpp +++ /dev/null @@ -1,2447 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// OSCAR File-Transfers implementation -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -struct oscarthreadstartinfo -{ - int type; - int incoming; - HANDLE hContact; - HANDLE hConnection; - DWORD dwRemoteIP; - oscar_filetransfer *ft; - oscar_listener *listener; -}; - - -// small utility function -extern void NormalizeBackslash(char* path); - -// -// Common functions -///////////////////////////// - -char *FindFilePathContainer(const char **files, int iFile, char *szContainer) -{ - const char *szThisFile = files[iFile]; - char *szFileName = (char*)ExtractFileName(szThisFile); - - szContainer[0] = '\0'; - - if (szThisFile != szFileName) - { // find an earlier subdirectory to be used as a container - for (int i = iFile - 1; i >= 0; i--) - { - int len = strlennull(files[i]); - - if (!_strnicmp(files[i], szThisFile, len) && (szThisFile[len] == '\\' || szThisFile[len] == '/')) - { - const char *pszLastBackslash; - - if (((pszLastBackslash = strrchr(files[i], '\\')) == NULL) && - ((pszLastBackslash = strrchr(files[i], '/')) == NULL)) - { - strcpy(szContainer, files[i]); - } - else - { - len = pszLastBackslash - files[i] + 1; - null_strcpy(szContainer, szThisFile + len, szFileName - szThisFile - len); - } - } - } - } - return szFileName; -} - - -// -// Utility functions -///////////////////////////// - -oscar_filetransfer* CIcqProto::CreateOscarTransfer() -{ - oscar_filetransfer* ft = (oscar_filetransfer*)SAFE_MALLOC(sizeof(oscar_filetransfer)); - - ft->ft_magic = FT_MAGIC_OSCAR; // Setup signature - // Init members - ft->fileId = -1; - - icq_lock l(oftMutex); - - fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*(fileTransferCount + 1)); - fileTransferList[fileTransferCount++] = ft; - -#ifdef _DEBUG - NetLog_Direct("OFT: FT struct 0x%x created", ft); -#endif - - return ft; -} - - -filetransfer *CIcqProto::CreateIcqFileTransfer() -{ - filetransfer *ft = (filetransfer*)SAFE_MALLOC(sizeof(filetransfer)); - - ft->ft_magic = FT_MAGIC_ICQ; - - icq_lock l(oftMutex); - - fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*(fileTransferCount + 1)); - fileTransferList[fileTransferCount++] = (basic_filetransfer*)ft; - -#ifdef _DEBUG - NetLog_Direct("FT struct 0x%x created", ft); -#endif - - return ft; -} - - -int CIcqProto::getFileTransferIndex(void *ft) -{ - for (int i = 0; i < fileTransferCount; i++) - { - if (fileTransferList[i] == ft) - return i; - } - return -1; -} - - -void CIcqProto::ReleaseFileTransfer(void *ft) -{ - int i = getFileTransferIndex(ft); - - if (i != -1) - { - fileTransferCount--; - fileTransferList[i] = fileTransferList[fileTransferCount]; - fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*fileTransferCount); - } -} - - -int CIcqProto::IsValidFileTransfer(void *ft) -{ - icq_lock l(oftMutex); - - if (getFileTransferIndex(ft) != -1) return 1; - - return 0; -} - - -int CIcqProto::IsValidOscarTransfer(void *ft) -{ - icq_lock l(oftMutex); - - if (getFileTransferIndex(ft) != -1 && ((basic_filetransfer*)ft)->ft_magic == FT_MAGIC_OSCAR) - return 1; - - return 0; -} - - -oscar_filetransfer* CIcqProto::FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2) -{ - icq_lock l(oftMutex); - - for (int i = 0; i < fileTransferCount; i++) - { - if (fileTransferList[i]->ft_magic == FT_MAGIC_OSCAR) - { - oscar_filetransfer *oft = (oscar_filetransfer*)fileTransferList[i]; - - if (oft->hContact == hContact && oft->pMessage.dwMsgID1 == dwID1 && oft->pMessage.dwMsgID2 == dwID2) - return oft; - } - } - - return NULL; -} - - -// Release file transfer structure -void CIcqProto::SafeReleaseFileTransfer(void **ft) -{ - basic_filetransfer **bft = (basic_filetransfer**)ft; - - icq_lock l(oftMutex); - - // Check for filetransfer validity - if (getFileTransferIndex(*ft) == -1) - return; - - if (*bft) - { - if ((*bft)->ft_magic == FT_MAGIC_ICQ) - { // release ICQ filetransfer structure and its contents - filetransfer *ift = (filetransfer*)(*bft); - - SAFE_FREE(&ift->szFilename); - SAFE_FREE(&ift->szDescription); - SAFE_FREE(&ift->szSavePath); - SAFE_FREE(&ift->szThisFile); - SAFE_FREE(&ift->szThisSubdir); - if (ift->pszFiles) - { - for (int i = 0; i < (int)ift->dwFileCount; i++) - SAFE_FREE(&ift->pszFiles[i]); - SAFE_FREE((void**)&ift->pszFiles); - } - // Invalidate transfer - ReleaseFileTransfer(ift); -#ifdef _DEBUG - NetLog_Direct("FT struct 0x%x released", ft); -#endif - // Release memory - SAFE_FREE((void**)ft); - } - else if ((*bft)->ft_magic == FT_MAGIC_OSCAR) - { // release oscar filetransfer structure and its contents - oscar_filetransfer *oft = (oscar_filetransfer*)(*bft); - // If connected, close connection - if (oft->connection) - CloseOscarConnection(oft->connection); - // Release oscar listener - if (oft->listener) - ReleaseOscarListener((oscar_listener**)&oft->listener); - // Release cookie - if (oft->dwCookie) - FreeCookie(oft->dwCookie); - // Release all dynamic members - SAFE_FREE(&oft->rawFileName); - SAFE_FREE(&oft->szSavePath); - SAFE_FREE(&oft->szThisFile); - SAFE_FREE(&oft->szThisPath); - SAFE_FREE(&oft->szDescription); - if (oft->files) - { - for (int i = 0; i < oft->wFilesCount; i++) - SAFE_FREE(&oft->files[i].szFile); - SAFE_FREE((void**)&oft->files); - } - if (oft->files_list) - { -/* for (int i = 0; i < oft->wFilesCount; i++) - SAFE_FREE(&oft->files_list[i]);*/ - SAFE_FREE((void**)&oft->files_list); - } - if (oft->file_containers) - { - for (int i = 0; i < oft->containerCount; i++) - SAFE_FREE(&oft->file_containers[i]); - SAFE_FREE((void**)&oft->file_containers); - } - if (oft->fileId != -1) - { -#ifdef _DEBUG - NetLog_Direct("OFT: _close(%u)", oft->fileId); -#endif - _close(oft->fileId); - } - // Invalidate transfer - ReleaseFileTransfer(oft); -#ifdef _DEBUG - NetLog_Direct("OFT: FT struct 0x%x released", ft); -#endif - // Release memory - SAFE_FREE((void**)ft); - } - } -} - - -// Calculate oft checksum of buffer -// -------------------------------- -// Information was gathered from Gaim's sources, thanks -// -DWORD oft_calc_checksum(int offset, const BYTE *buffer, int len, DWORD dwChecksum) -{ - DWORD checksum = (dwChecksum >> 16) & 0xffff; - - for (int i = 0; i < len; i++) - { - WORD val = buffer[i]; - DWORD oldchecksum = checksum; - - if (((i + offset) & 1) == 0) - val = val << 8; - - if (checksum < val) - checksum -= val + 1; - else // simulate carry - checksum -= val; - } - checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); - checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); - return checksum << 16; -} - - -DWORD oft_calc_file_checksum(int hFile, __int64 maxSize) -{ - BYTE buf[OFT_BUFFER_SIZE]; - int bytesRead; - __int64 offset = 0; - DWORD dwCheck = 0xFFFF0000; - - _lseek(hFile, 0, SEEK_SET); - bytesRead = _read(hFile, buf, (maxSize < sizeof(buf)) ? maxSize : (unsigned)sizeof(buf)); - if (bytesRead == -1) - return dwCheck; - - while(bytesRead) - { - dwCheck = oft_calc_checksum((int)offset, buf, bytesRead, dwCheck); - offset += bytesRead; - bytesRead = _read(hFile, buf, sizeof(buf)); - if (bytesRead + offset > maxSize) bytesRead = (int)(maxSize - offset); - } - _lseek(hFile, 0, SEEK_SET); // back to beginning - - return dwCheck; -} - - -oscar_listener* CIcqProto::CreateOscarListener(oscar_filetransfer *ft, NETLIBNEWCONNECTIONPROC_V2 handler) -{ - oscar_listener *listener = (oscar_listener*)SAFE_MALLOC(sizeof(oscar_listener)); - - if (listener) - { - listener->ppro = this; - listener->ft = ft; - if (listener->hBoundPort = NetLib_BindPort(handler, listener, &listener->wPort, NULL)) - return listener; // Success - - SAFE_FREE((void**)&listener); - } - - return NULL; // Failure -} - - -void CIcqProto::ReleaseOscarListener(oscar_listener **pListener) -{ - oscar_listener *listener = *pListener; - - if (listener) - { // Close listening port - if (listener->hBoundPort) - NetLib_SafeCloseHandle(&listener->hBoundPort); - - NetLog_Direct("Oscar listener on port %d released.", listener->wPort); - } - SAFE_FREE((void**)pListener); -} - - -// -// Miranda FT interface handlers & services -///////////////////////////// - -void CIcqProto::handleRecvServMsgOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand) -{ - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (wCommand == 0) - { // this is OFT request - oscar_tlv_chain* chain = readIntoTLVChain(&buf, wLen, 0); - - if (chain) - { - WORD wAckType = chain->getWord(0x0A, 1); - - if (wAckType == 1) - { // This is first request in this OFT - oscar_filetransfer *ft = CreateOscarTransfer(); - char *pszFileName = NULL; - char *pszDescription = NULL; - WORD wFilenameLength; - - NetLog_Server("This is a file request"); - - // This TLV chain may contain the following TLVs: - // TLV(A): Acktype 0x0001 - file request / abort request - // 0x0002 - file ack - // TLV(F): Unknown - // TLV(E): Language ? - // TLV(2): Proxy IP - // TLV(16): Proxy IP Check - // TLV(3): External IP - // TLV(4): Internal IP - // TLV(5): Port - // TLV(17): Port Check - // TLV(10): Proxy Flag - // TLV(D): Charset of User Message - // TLV(C): User Message (ICQ_COOL_FT) - // TLV(2711): FT info - // TLV(2712): Charset of file name - - // init filetransfer structure - ft->pMessage.dwMsgID1 = dwID1; - ft->pMessage.dwMsgID2 = dwID2; - ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; - ft->dwProxyIP = chain->getDWord(0x02, 1); - ft->dwRemoteInternalIP = chain->getDWord(0x03, 1); - ft->dwRemoteExternalIP = chain->getDWord(0x04, 1); - ft->wRemotePort = chain->getWord(0x05, 1); - ft->wReqNum = wAckType; - - { // User Message - oscar_tlv* tlv = chain->getTLV(0x0C, 1); - - if (tlv) - { // parse User Message - BYTE* tBuf = tlv->pData; - - pszDescription = (char*)_alloca(tlv->wLen + 2); - unpackString(&tBuf, (char*)pszDescription, tlv->wLen); - pszDescription[tlv->wLen] = '\0'; - pszDescription[tlv->wLen+1] = '\0'; - { // apply User Message encoding - oscar_tlv *charset = chain->getTLV(0x0D, 1); - char *str = pszDescription; - char *bTag,*eTag; - - if (charset) - { // decode charset - char *szEnc = (char*)_alloca(charset->wLen + 1); - - null_strcpy(szEnc, (char*)charset->pData, charset->wLen); - str = ApplyEncoding((char*)pszDescription, szEnc); - } - else - str = null_strdup(str); - // eliminate HTML tags - pszDescription = EliminateHtml(str, strlennull(str)); - - bTag = strstrnull(pszDescription, ""); - if (bTag) - { // take special Description - ICQJ's extension - eTag = strstrnull(bTag, ""); - if (eTag) - { - *eTag = '\0'; - str = null_strdup(bTag + 6); - SAFE_FREE(&pszDescription); - pszDescription = str; - } - } - else - { - bTag = strstrnull(pszDescription, ""); - if (bTag) - { // take only - Description tag if present - eTag = strstrnull(bTag, ""); - if (eTag) - { - *eTag = '\0'; - str = null_strdup(bTag + 4); - SAFE_FREE(&pszDescription); - pszDescription = str; - } - } - } - } - } - if (!strlennull(pszDescription)) - { - SAFE_FREE(&pszDescription); - pszDescription = ICQTranslateUtf(LPGEN("No description given")); - } - } - { // parse File Transfer Info block - oscar_tlv* tlv = chain->getTLV(0x2711, 1); - - // sanity check - if (!tlv || tlv->wLen < 8) - { - NetLog_Server("Error: Malformed file request"); - // release structures - SafeReleaseFileTransfer((void**)&ft); - SAFE_FREE(&pszDescription); - return; - } - - BYTE* tBuf = tlv->pData; - WORD tLen = tlv->wLen; - WORD wFlag; - - unpackWord(&tBuf, &wFlag); // FT flag - unpackWord(&tBuf, &ft->wFilesCount); - unpackDWord(&tBuf, (DWORD*)&ft->qwTotalSize); - tLen -= 8; - // Filename / Directory Name - if (tLen) - { // some filename specified, unpack - wFilenameLength = tLen - 1; - pszFileName = (char*)_alloca(tLen); - unpackString(&tBuf, (char*)pszFileName, wFilenameLength); - pszFileName[wFilenameLength] = '\0'; - } - else if (ft->wFilesCount == 1) // give some generic file name - pszFileName = "unnamed_file"; - else // or empty directory name - pszFileName = ""; - - // apply Filename / Directory Name encoding - oscar_tlv* charset = chain->getTLV(0x2712, 1); - if (charset) { - char* szEnc = (char*)_alloca(charset->wLen + 1); - null_strcpy(szEnc, (char*)charset->pData, charset->wLen); - pszFileName = ApplyEncoding(pszFileName, szEnc); - } - else pszFileName = ansi_to_utf8(pszFileName); - - if (ft->wFilesCount == 1) - { // Filename - use for DB event - char *szFileName = (char*)_alloca(strlennull(pszFileName) + 1); - - strcpy(szFileName, pszFileName); - SAFE_FREE(&pszFileName); - pszFileName = szFileName; - } - else - { // Save Directory name for future use - ft->szThisPath = pszFileName; - // for multi-file transfer we do not display "folder" name, but create only a simple notice - pszFileName = (char*)_alloca(64); - - char tmp[64]; - null_snprintf(pszFileName, 64, ICQTranslateUtfStatic(LPGEN("%d Files"), tmp, SIZEOF(tmp)), ft->wFilesCount); - } - } - // Total Size TLV (ICQ 6 and AIM 6) - { - oscar_tlv *tlv = chain->getTLV(0x2713, 1); - - if (tlv && tlv->wLen >= 8) - { - BYTE *tBuf = tlv->pData; - - unpackQWord(&tBuf, &ft->qwTotalSize); - } - } - int bAdded; - HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded); - - ft->hContact = hContact; - ft->fileId = -1; - - // Send chain event - char *szBlob = (char*)_alloca(sizeof(DWORD) + strlennull(pszFileName) + strlennull(pszDescription) + 2); - *(PDWORD)szBlob = 0; - strcpy(szBlob + sizeof(DWORD), pszFileName); - strcpy(szBlob + sizeof(DWORD) + strlennull(pszFileName) + 1, pszDescription); - - TCHAR* ptszFileName = mir_utf8decodeT(pszFileName); - - PROTORECVFILET pre = {0}; - pre.flags = PREF_TCHAR; - pre.fileCount = 1; - pre.timestamp = time(NULL); - pre.tszDescription = mir_utf8decodeT(pszDescription); - pre.ptszFiles = &ptszFileName; - pre.lParam = (LPARAM)ft; - - CCSDATA ccs; - ccs.szProtoService = PSR_FILE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - mir_free(pre.tszDescription); - mir_free(ptszFileName); - } - else if (wAckType == 2) - { // First attempt failed, reverse requested - oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); - - if (ft) - { - NetLog_Direct("OFT: Redirect received (%d)", wAckType); - - ft->wReqNum = wAckType; - - if (ft->flags & OFTF_SENDING) - { - ReleaseOscarListener((oscar_listener**)&ft->listener); - - ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; - ft->dwProxyIP = chain->getDWord(0x02, 1); - ft->dwRemoteInternalIP = chain->getDWord(0x03, 1); - ft->dwRemoteExternalIP = chain->getDWord(0x04, 1); - ft->wRemotePort = chain->getWord(0x05, 1); - - OpenOscarConnection(hContact, ft, ft->bUseProxy ? OCT_PROXY_RECV: OCT_REVERSE); - } - else - { // Just sanity - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&ft); - } - } - else - NetLog_Server("Error: Invalid request, no such transfer"); - } - else if (wAckType == 3) - { // Transfering thru proxy, join tunnel - oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); - - if (ft) - { // release possible previous listener - NetLog_Direct("OFT: Redirect received (%d)", wAckType); - - ft->wReqNum = wAckType; - - ReleaseOscarListener((oscar_listener**)&ft->listener); - - ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; - ft->dwProxyIP = chain->getDWord(0x02, 1); - ft->wRemotePort = chain->getWord(0x05, 1); - - if (ft->bUseProxy && ft->dwProxyIP) - { // Init proxy connection - OpenOscarConnection(hContact, ft, OCT_PROXY_RECV); - } - else - { // try Stage 4 - OpenOscarConnection(hContact, ft, OCT_PROXY); - } - } - else - NetLog_Server("Error: Invalid request, no such transfer"); - } - else if (wAckType == 4) - { - oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); - - if (ft) - { - NetLog_Direct("OFT: Redirect received (%d)", wAckType); - - ft->wReqNum = wAckType; - ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; - ft->dwProxyIP = chain->getDWord(0x02, 1); - ft->wRemotePort = chain->getWord(0x05, 1); - - if (ft->bUseProxy && ft->dwProxyIP) - { // Init proxy connection - OpenOscarConnection(hContact, ft, OCT_PROXY_RECV); - } - else - NetLog_Server("Error: Invalid request, IP missing."); - } - else - NetLog_Server("Error: Invalid request, no such transfer"); - } - else - NetLog_Server("Error: Uknown Stage %d request", wAckType); - - disposeChain(&chain); - } - else - NetLog_Server("Error: Missing TLV chain in OFT request"); - } - else if (wCommand == 1) - { // transfer cancelled/aborted - oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); - - if (ft) - { - NetLog_Server("OFT: File transfer cancelled by %s", strUID(dwUin, szUID)); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); - // Notify user, that the FT was cancelled // TODO: new ACKRESULT_? - icq_LogMessage(LOG_ERROR, LPGEN("The file transfer was aborted by the other user.")); - // Release transfer - SafeReleaseFileTransfer((void**)&ft); - } - else - NetLog_Server("Error: Invalid request, no such transfer"); - } - else if (wCommand == 2) - { // transfer accepted - connection established - oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); - - if (ft) - { - NetLog_Direct("OFT: Session established."); - // Init connection - if (ft->flags & OFTF_SENDING) - { - if (ft->connection && ft->connection->status == OCS_CONNECTED) - { - if (!(ft->flags & OFTF_FILE_REQUEST_SENT)) - { - ft->flags |= OFTF_FILE_REQUEST_SENT; - // proceed with first file - oft_sendPeerInit(ft->connection); - } - } - ft->flags |= OFTF_INITIALIZED; // accept was received - } - else - NetLog_Server("Warning: Received invalid rendezvous accept"); - } - else - NetLog_Server("Error: Invalid request, no such transfer"); - } - else - { - NetLog_Server("Error: Unknown wCommand=0x%x in OFT request", wCommand); - } -} - - -void CIcqProto::handleRecvServResponseOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, void* ft) -{ - WORD wDataLen; - - if (wLen < 2) return; - - unpackWord(&buf, &wDataLen); - - if (wDataLen == 2) - { - oscar_filetransfer *oft = (oscar_filetransfer*)ft; - WORD wStatus; - - unpackWord(&buf, &wStatus); - - switch (wStatus) - { - case 1: - { // FT denied (icq5) - NetLog_Server("OFT: File transfer denied by %s", strUID(dwUin, szUID)); - - BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)oft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oft); - } - break; - - case 4: // Proxy error - { - icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Proxy error")); - - BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oft); - } - break; - - case 5: // Invalid request - { - icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Invalid request")); - - BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oft); - } - break; - - case 6: // Proxy Failed (IP = 0) - { - icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Proxy unavailable")); - - BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oft); - } - break; - - default: - { - NetLog_Server("OFT: Uknown request response code 0x%x", wStatus); - - BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oft); - } - } - } -} - - -// This function is called from the Netlib when someone is connecting to our oscar_listener -static void oft_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra) -{ - oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo)); - oscar_listener *listener = (oscar_listener*)pExtra; - - otsi->type = listener->ft->flags & OFTF_SENDING ? OCT_NORMAL : OCT_REVERSE; - otsi->incoming = 1; - otsi->hConnection = hNewConnection; - otsi->dwRemoteIP = dwRemoteIP; - otsi->listener = listener; - - // Start a new thread for the incomming connection - listener->ppro->ForkThread(( IcqThreadFunc )&CIcqProto::oft_connectionThread, otsi ); -} - - -static char *oftGetFileContainer(oscar_filetransfer* oft, const char** files, int iFile) -{ - char szPath[MAX_PATH]; - char* szFileName = FindFilePathContainer(files, iFile, szPath); - char *szPathUtf = ansi_to_utf8(szPath); - int i; - - // try to find existing container - for (i = 0; i < oft->containerCount; i++) - if (!strcmpnull(szPathUtf, oft->file_containers[i])) - { - SAFE_FREE((void**)&szPathUtf); - - return oft->file_containers[i]; - } - - // create new container - i = oft->containerCount++; - oft->file_containers = (char**)SAFE_REALLOC(oft->file_containers, (sizeof(char*) * oft->containerCount)); - oft->file_containers[i] = szPathUtf; - - return oft->file_containers[i]; -} - - -HANDLE CIcqProto::oftInitTransfer(HANDLE hContact, DWORD dwUin, char* szUid, const TCHAR** files, const TCHAR* pszDesc) -{ - oscar_filetransfer *ft; - int i, filesCount; - struct _stati64 statbuf; - char ** filesUtf; - - // Initialize filetransfer struct - NetLog_Server("Init file send"); - - ft = CreateOscarTransfer(); - ft->hContact = hContact; - ft->pMessage.bMessageType = MTYPE_FILEREQ; - InitMessageCookie(&ft->pMessage); - - for (filesCount = 0; files[filesCount]; filesCount++); - ft->files = (oft_file_record *)SAFE_MALLOC(sizeof(oft_file_record) * filesCount); - ft->files_list = (char**)SAFE_MALLOC(sizeof(TCHAR *) * filesCount); - ft->qwTotalSize = 0; - - filesUtf = (char**)SAFE_MALLOC(sizeof(char *) * filesCount); - for(i = 0; i < filesCount; i++) filesUtf[i] = FileNameToUtf(files[i]); - - // Prepare files arrays - for (i = 0; i < filesCount; i++) - { - if (_tstati64(files[i], &statbuf)) - NetLog_Server("IcqSendFile() was passed invalid filename \"%s\"", files[i]); - else - { - if (!(statbuf.st_mode&_S_IFDIR)) - { // take only files - ft->files[ft->wFilesCount].szFile = ft->files_list[ft->wFilesCount] = null_strdup(filesUtf[i]); - ft->files[ft->wFilesCount].szContainer = oftGetFileContainer(ft, (LPCSTR*) filesUtf, i); - - ft->wFilesCount++; - ft->qwTotalSize += statbuf.st_size; - } - } - } - - for (i = 0; i < filesCount; i++) - SAFE_FREE(&filesUtf[i]); - SAFE_FREE((void**)&filesUtf); - - if (!ft->wFilesCount) - { // found no valid files to send - icq_LogMessage(LOG_ERROR, LPGEN("Failed to Initialize File Transfer. No valid files were specified.")); - // Notify UI - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&ft); - - return 0; // Failure - } -#ifdef __GNUC__ -#define OSCAR_MAX_SIZE 0x100000000ULL -#else -#define OSCAR_MAX_SIZE 0x100000000 -#endif - if (ft->qwTotalSize >= OSCAR_MAX_SIZE && ft->wFilesCount > 1) - { // file larger than 4GB can be send only as single - icq_LogMessage(LOG_ERROR, LPGEN("The files are too big to be sent at once. Files bigger than 4GB can be sent only separately.")); - // Notify UI - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&ft); - - return 0; // Failure - } - - NetLog_Server("OFT: Found %d files.", ft->wFilesCount); - - ft->szDescription = tchar_to_utf8(pszDesc); - ft->flags = OFTF_SENDING; - ft->fileId = -1; - ft->iCurrentFile = 0; - ft->dwCookie = AllocateCookie(CKT_FILE, ICQ_MSG_SRV_SEND, hContact, ft); - - // Init oscar fields - { - ft->wEncrypt = 0; - ft->wCompress = 0; - ft->wPartsCount = 1; - ft->wPartsLeft = 1; - strcpy(ft->rawIDString, "Cool FileXfer"); - ft->bHeaderFlags = 0x20; - ft->bNameOff = 0x1C; - ft->bSizeOff = 0x11; - ft->dwRecvForkCheck = 0xFFFF0000; - ft->dwThisForkCheck = 0xFFFF0000; - ft->dwRecvFileCheck = 0xFFFF0000; - } - - // Send file transfer request - { - char *pszFiles; - - if (ft->wFilesCount == 1) - { // transfering single file, give filename - pszFiles = (char*)ExtractFileName(ft->files[0].szFile); - } - else - { // check if transfering one directory - char *szFirstDiv, *szFirstDir = ft->file_containers[0]; - int nFirstDirLen; - - // default is no root dir - pszFiles = ""; - - if ((szFirstDiv = strstrnull(szFirstDir, "\\")) || (szFirstDiv = strstrnull(szFirstDir, "/"))) - nFirstDirLen = szFirstDiv - szFirstDir; - else - nFirstDirLen = strlennull(szFirstDir); - - if (nFirstDirLen) - { // got root dir from first container, check if others are only sub-dirs - for (i = 0; i < ft->containerCount; i++) - { - if (_strnicmp((char*)ft->file_containers[i], (char*)szFirstDir, nFirstDirLen)) - { - szFirstDir = NULL; - break; - } - } - if (szFirstDir) - { // fine, we are sending only one directory - pszFiles = szFirstDir; - if (szFirstDiv) szFirstDiv[0] = '\0'; - nFirstDirLen++; // include backslash - // cut all files container by root dir - it is transferred as root separately - for (i = 0; i < ft->wFilesCount; i++) - ft->files[i].szContainer += nFirstDirLen; - } - } - } - - // Create listener - ft->listener = CreateOscarListener(ft, oft_newConnectionReceived); - - // Send packet - if (ft->listener) - { - oft_sendFileRequest(dwUin, szUid, ft, pszFiles, getSettingDword(NULL, "RealIP", 0)); - } - else - { // try stage 1 proxy - ft->szThisFile = null_strdup(pszFiles); - OpenOscarConnection(hContact, ft, OCT_PROXY_INIT); - } - } - - return ft; // Success -} - - -HANDLE CIcqProto::oftFileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR *szPath) -{ - oscar_filetransfer *ft = (oscar_filetransfer*)hTransfer; - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 0; // Invalid contact - - if (!IsValidOscarTransfer(ft)) - return 0; // Invalid transfer - - ft->szSavePath = tchar_to_utf8(szPath); - - if (ft->szThisPath) - { // Append Directory name to the save path, when transfering a directory - ft->szSavePath = (char*)SAFE_REALLOC(ft->szSavePath, strlennull(ft->szSavePath) + strlennull(ft->szThisPath) + 4); - NormalizeBackslash(ft->szSavePath); - strcat(ft->szSavePath, ft->szThisPath); - NormalizeBackslash(ft->szSavePath); - } -#ifdef _DEBUG - NetLog_Direct("OFT: Request accepted, saving to '%s'.", ft->szSavePath); -#endif - - // Create cookie - ft->dwCookie = AllocateCookie(CKT_FILE, ICQ_MSG_SRV_SEND, hContact, ft); - - OpenOscarConnection(hContact, ft, ft->bUseProxy ? OCT_PROXY_RECV: OCT_NORMAL); - return hTransfer; // Success -} - - -DWORD CIcqProto::oftFileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR *szReason) -{ - oscar_filetransfer *ft = (oscar_filetransfer*)hTransfer; - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - if (IsValidOscarTransfer(ft)) - { - if (ft->hContact != hContact) - return 1; // Bad contact or hTransfer - -#ifdef _DEBUG - NetLog_Direct("OFT: Request denied."); -#endif - - oft_sendFileDeny(dwUin, szUid, ft); - - // Release structure - SafeReleaseFileTransfer((void**)&ft); - - return 0; // Success - } - return 1; // Invalid transfer -} - - -DWORD CIcqProto::oftFileCancel(HANDLE hContact, HANDLE hTransfer) -{ - oscar_filetransfer* ft = (oscar_filetransfer*)hTransfer; - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - return 1; // Invalid contact - - if (IsValidOscarTransfer(ft)) - { - if (ft->hContact != hContact) - return 1; // Bad contact or hTransfer - -#ifdef _DEBUG - NetLog_Direct("OFT: Transfer cancelled."); -#endif - - oft_sendFileCancel(dwUin, szUid, ft); - - BroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - - // Release structure - SafeReleaseFileTransfer((void**)&ft); - - return 0; // Success - } - return 1; // Invalid transfer -} - - -void CIcqProto::oftFileResume(oscar_filetransfer *ft, int action, const TCHAR *szFilename) -{ - int openFlags; - - if (ft->connection == NULL) - return; - - oscar_connection *oc = ft->connection; - -#ifdef _DEBUG - NetLog_Direct("OFT: Resume Transfer, Action: %d, FileName: '%s'", action, szFilename); -#endif - - switch (action) - { - case FILERESUME_RESUME: - openFlags = _O_BINARY | _O_RDWR; - break; - - case FILERESUME_OVERWRITE: - openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; - ft->qwFileBytesDone = 0; - break; - - case FILERESUME_SKIP: - openFlags = _O_BINARY | _O_WRONLY; - ft->qwFileBytesDone = ft->qwThisFileSize; - break; - - case FILERESUME_RENAME: - openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; - SAFE_FREE(&ft->szThisFile); - ft->szThisFile = tchar_to_utf8(szFilename); - ft->qwFileBytesDone = 0; - break; - - default: // workaround for bug in Miranda Core - if (ft->resumeAction == FILERESUME_RESUME) - openFlags = _O_BINARY | _O_RDWR; - else - { // default to overwrite - openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; - ft->qwFileBytesDone = 0; - } - } - ft->resumeAction = action; - - ft->fileId = OpenFileUtf(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE); -#ifdef _DEBUG - NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, openFlags, ft->fileId); -#endif - if (ft->fileId == -1) - { -#ifdef _DEBUG - NetLog_Direct("OFT: errno=%d", errno); -#endif - icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oc->ft); - return; - } - - if (action == FILERESUME_RESUME) - ft->qwFileBytesDone = _lseeki64(ft->fileId, 0, SEEK_END); - else - _lseeki64(ft->fileId, ft->qwFileBytesDone, SEEK_SET); - - ft->qwBytesDone += ft->qwFileBytesDone; - - if (action == FILERESUME_RESUME) - { // use smart-resume - oc->status = OCS_RESUME; - ft->dwRecvFileCheck = oft_calc_file_checksum(ft->fileId, ft->qwFileBytesDone); - _lseek(ft->fileId, 0, SEEK_END); - -#ifdef _DEBUG - NetLog_Direct("OFT: Starting Smart-Resume"); -#endif - - sendOFT2FramePacket(oc, OFT_TYPE_RESUMEREQUEST); - - return; - } - else if (action == FILERESUME_SKIP) - { // we are skipping the file, send "we are done" - oc->status = OCS_NEGOTIATION; - } - else - { // Send "we are ready" - oc->status = OCS_DATA; - ft->flags |= OFTF_FILE_RECEIVING; - - sendOFT2FramePacket(oc, OFT_TYPE_READY); - } - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); - - if (!ft->qwThisFileSize || action == FILERESUME_SKIP) - { // if the file is empty we will not receive any data - BYTE buf; - oft_handleFileData(oc, &buf, 0); - } -} - - -static void oft_buildProtoFileTransferStatus(oscar_filetransfer* ft, PROTOFILETRANSFERSTATUS* pfts) -{ - ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS)); - pfts->cbSize = sizeof(PROTOFILETRANSFERSTATUS); - pfts->hContact = ft->hContact; - pfts->flags = PFTS_UTF + ((ft->flags & OFTF_SENDING) ? PFTS_SENDING : PFTS_RECEIVING); - if (ft->flags & OFTF_SENDING) - pfts->pszFiles = ft->files_list; - else - pfts->pszFiles = NULL; /* FIXME */ - pfts->totalFiles = ft->wFilesCount; - pfts->currentFileNumber = ft->iCurrentFile; - pfts->totalBytes = ft->qwTotalSize; - pfts->totalProgress = ft->qwBytesDone; - pfts->szWorkingDir = ft->szThisPath; - pfts->szCurrentFile = ft->szThisFile; - pfts->currentFileSize = ft->qwThisFileSize; - pfts->currentFileTime = ft->dwThisFileDate; - pfts->currentFileProgress = ft->qwFileBytesDone; -} - - -void CIcqProto::CloseOscarConnection(oscar_connection *oc) -{ - icq_lock l(oftMutex); - - if (oc) - { - oc->type = OCT_CLOSING; - - if (oc->hConnection) - { // we need this for Netlib handle consistency - NetLib_CloseConnection(&oc->hConnection, FALSE); - } - } -} - - -///////////////////////////////////////////////////////////////////////////////////////// - -void CIcqProto::OpenOscarConnection(HANDLE hContact, oscar_filetransfer *ft, int type) -{ - oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo)); - - otsi->hContact = hContact; - otsi->type = type; - otsi->ft = ft; - - ForkThread(( IcqThreadFunc )&CIcqProto::oft_connectionThread, otsi ); -} - - -int CIcqProto::CreateOscarProxyConnection(oscar_connection *oc) -{ - NETLIBOPENCONNECTION nloc = {0}; - - // inform UI - BroadcastAck(oc->ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTPROXY, oc->ft, 0); - - nloc.szHost = OSCAR_PROXY_HOST; - nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); - if (nloc.wPort == 0) - nloc.wPort = RandRange(1024, 65535); - if (m_bGatewayMode) - nloc.flags |= NLOCF_HTTPGATEWAY; - - oc->hConnection = NetLib_OpenConnection(m_hServerNetlibUser, "Proxy ", &nloc); - if (!oc->hConnection) - { // proxy connection failed - return 0; - } - oc->type = OCT_PROXY; - oc->status = OCS_PROXY; - oc->ft->connection = oc; - // init proxy - proxy_sendInitTunnel(oc); - - return 1; // Success -} - - -void __cdecl CIcqProto::oft_connectionThread( oscarthreadstartinfo *otsi ) -{ - oscar_connection oc = {0}; - oscar_listener *source; - NETLIBPACKETRECVER packetRecv={0}; - HANDLE hPacketRecver; - - oc.hContact = otsi->hContact; - oc.hConnection = otsi->hConnection; - oc.type = otsi->type; - oc.incoming = otsi->incoming; - oc.ft = otsi->ft; - source = otsi->listener; - if (oc.incoming) - { - if (IsValidOscarTransfer(source->ft)) - { - oc.ft = source->ft; - oc.ft->dwRemoteExternalIP = otsi->dwRemoteIP; - oc.hContact = oc.ft->hContact; - oc.ft->connection = &oc; - oc.status = OCS_CONNECTED; - } - else - { // FT is already over, kill listener - NetLog_Direct("Received unexpected connection, closing."); - - CloseOscarConnection(&oc); - ReleaseOscarListener(&source); - - SAFE_FREE((void**)&otsi); - return; - } - } - SAFE_FREE((void**)&otsi); - - if (oc.hContact) - { // Load contact information - getContactUid(oc.hContact, &oc.dwUin, &oc.szUid); - } - - // Load local IP information - oc.dwLocalExternalIP = getSettingDword(NULL, "IP", 0); - oc.dwLocalInternalIP = getSettingDword(NULL, "RealIP", 0); - - if (!oc.incoming) - { // create outgoing connection - if (oc.type == OCT_NORMAL || oc.type == OCT_REVERSE) - { // create outgoing connection to peer - NETLIBOPENCONNECTION nloc = {0}; - IN_ADDR addr = {0}, addr2 = {0}; - - if (oc.ft->dwRemoteExternalIP == oc.dwLocalExternalIP && oc.ft->dwRemoteInternalIP) - addr.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); - else if (oc.ft->dwRemoteExternalIP) - { - addr.S_un.S_addr = htonl(oc.ft->dwRemoteExternalIP); - // for different internal, try it also (for LANs with multiple external IP, VPNs, etc.) - if (oc.ft->dwRemoteInternalIP != oc.ft->dwRemoteExternalIP) - addr2.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); - } - else // try LAN - addr.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); - - // Inform UI that we will attempt to connect - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, oc.ft, 0); - - if (!addr.S_un.S_addr && oc.type == OCT_NORMAL) - { // IP to connect to is empty, request reverse - oscar_listener* listener = CreateOscarListener(oc.ft, oft_newConnectionReceived); - - if (listener) - { // we got listening port, fine send request - oc.ft->listener = listener; - // notify UI - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0); - - oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE); - return; - } - if (!CreateOscarProxyConnection(&oc)) - { // normal connection failed, notify peer, wait for error or stage 3 proxy - oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); - // stage 3 can follow - return; - } - } - else if (addr.S_un.S_addr && oc.ft->wRemotePort) - { - nloc.szHost = inet_ntoa(addr); - nloc.wPort = oc.ft->wRemotePort; - nloc.timeout = 8; // 8 secs to connect - oc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, oc.type==OCT_REVERSE?"Reverse ":NULL, &nloc); - if (!oc.hConnection && addr2.S_un.S_addr) - { // first address failed, try second one if available - nloc.szHost = inet_ntoa(addr2); - oc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, oc.type==OCT_REVERSE?"Reverse ":NULL, &nloc); - } - if (!oc.hConnection) - { - if (oc.type == OCT_NORMAL) - { // connection failed, try reverse - oscar_listener* listener = CreateOscarListener(oc.ft, oft_newConnectionReceived); - - if (listener) - { // we got listening port, fine send request - oc.ft->listener = listener; - // notify UI that we await connection - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0); - - oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE); - return; - } - } - if (!CreateOscarProxyConnection(&oc)) - { // proxy connection failed, notify peer, wait for error or stage 4 proxy - oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); - // stage 3 or stage 4 can follow - return; - } - } - else - { - oc.status = OCS_CONNECTED; - // ack normal connection - oc.ft->connection = &oc; - // acknowledge OFT - connection is ready - oft_sendFileAccept(oc.dwUin, oc.szUid, oc.ft); - // signal UI - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, oc.ft, 0); - } - } - else - { // try proxy, stage 3 (sending) - if (!CreateOscarProxyConnection(&oc)) - { // proxy connection failed, notify peer, wait for error or stage 4 proxy - oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); - // stage 4 can follow - return; - } - } - } - else if (oc.type == OCT_PROXY_RECV) - { // stage 2 & stage 4 - if (oc.ft->dwProxyIP && oc.ft->wRemotePort) - { // create proxy connection, join tunnel - NETLIBOPENCONNECTION nloc = {0}; - IN_ADDR addr = {0}; - - // inform UI that we will connect to file proxy - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTPROXY, oc.ft, 0); - - addr.S_un.S_addr = htonl(oc.ft->dwProxyIP); - nloc.szHost = inet_ntoa(addr); - nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); - if (nloc.wPort == 0) - nloc.wPort = RandRange(1024, 65535); - if (m_bGatewayMode) - nloc.flags |= NLOCF_HTTPGATEWAY; - oc.hConnection = NetLib_OpenConnection(m_hServerNetlibUser, "Proxy ", &nloc); - if (!oc.hConnection) - { // proxy connection failed, we are out of possibilities - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); - // notify the other side, that we failed - oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x04); - // Release structure - SafeReleaseFileTransfer((void**)&oc.ft); - return; - } - oc.status = OCS_PROXY; - oc.ft->connection = &oc; - // Join proxy tunnel - proxy_sendJoinTunnel(&oc, oc.ft->wRemotePort); - } - else // stage 2 failed (empty IP) - { // try stage 3, or send response error 0x06 - if (!CreateOscarProxyConnection(&oc)) - { - oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x06); - // notify UI - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); - // Release structure - SafeReleaseFileTransfer((void**)&oc.ft); - return; - } - } - } - else if (oc.type == OCT_PROXY) - { // stage 4 - if (!CreateOscarProxyConnection(&oc)) - { // proxy connection failed, we are out of possibilities - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); - // notify the other side, that we failed - oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x06); - // Release structure - SafeReleaseFileTransfer((void**)&oc.ft); - return; - } - } - else if (oc.type == OCT_PROXY_INIT) - { // stage 1 - if (!CreateOscarProxyConnection(&oc)) - { // We failed to init transfer, notify UI - icq_LogMessage(LOG_ERROR, LPGEN("Failed to Initialize File Transfer. Unable to bind local port and File proxy unavailable.")); - // Release transfer - SafeReleaseFileTransfer((void**)&oc.ft); - return; - } - else - oc.type = OCT_PROXY_INIT; - } - } - if (!oc.hConnection) - { // one more sanity check - NetLog_Direct("Error: No OFT connection."); - return; - } - if (oc.status != OCS_PROXY) - { // Connected, notify FT UI - BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, oc.ft, 0); - - // send init OFT frame - just for different order of packets (just like Trillian) - if (oc.status == OCS_CONNECTED && (oc.ft->flags & OFTF_SENDING) && ((oc.ft->flags & OFTF_INITIALIZED) || oc.type == OCT_REVERSE) && !(oc.ft->flags & OFTF_FILE_REQUEST_SENT)) - { - oc.ft->flags |= OFTF_FILE_REQUEST_SENT; - // proceed with first file - oft_sendPeerInit(&oc); - } - } - hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)oc.hConnection, 8192); - packetRecv.cbSize = sizeof(packetRecv); - - // Packet receiving loop - - while (oc.hConnection) - { - int recvResult; - - packetRecv.dwTimeout = oc.wantIdleTime ? 0 : 120000; - - recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); - if (!recvResult) - { - NetLog_Direct("Clean closure of oscar socket (%p)", oc.hConnection); - break; - } - - if (recvResult == SOCKET_ERROR) - { - if (GetLastError() == ERROR_TIMEOUT) - { // TODO: this will not work on some systems - if (oc.wantIdleTime) - { // here we want to send file data packets - oft_sendFileData(&oc); - } - else if (oc.status != OCS_WAITING) - { - NetLog_Direct("Connection timeouted, closing."); - break; - } - } - else if (oc.type != OCT_CLOSING || GetLastError() != 87) - { // log only significant errors, not "connection killed by us" - NetLog_Direct("Abortive closure of oscar socket (%p) (%d)", oc.hConnection, GetLastError()); - break; - } - } - - if (oc.type == OCT_CLOSING) - packetRecv.bytesUsed = packetRecv.bytesAvailable; - else - packetRecv.bytesUsed = oft_handlePackets(&oc, packetRecv.buffer, packetRecv.bytesAvailable); - } - - // End of packet receiving loop - - NetLib_SafeCloseHandle(&hPacketRecver); - - CloseOscarConnection(&oc); - - { // Clean up - icq_lock l(oftMutex); - - if (getFileTransferIndex(oc.ft) != -1) - oc.ft->connection = NULL; // release link - } - // Give server some time for abort/cancel to arrive - SleepEx(1000, TRUE); - // Error handling - if (IsValidOscarTransfer(oc.ft)) - { - if (oc.status == OCS_DATA) - { - BroadcastAck(oc.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); - - icq_LogMessage(LOG_ERROR, LPGEN("Connection lost during file transfer.")); - // Release structure - SafeReleaseFileTransfer((void**)&oc.ft); - } - else if (oc.status == OCS_NEGOTIATION) - { - BroadcastAck(oc.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); - - icq_LogMessage(LOG_ERROR, LPGEN("File transfer negotiation failed for unknown reason.")); - // Release structure - SafeReleaseFileTransfer((void**)&oc.ft); - } - } -} - - -void CIcqProto::sendOscarPacket(oscar_connection *oc, icq_packet *packet) -{ - if (oc->hConnection) - { - int nResult; - - nResult = Netlib_Send(oc->hConnection, (const char*)packet->pData, packet->wLen, 0); - - if (nResult == SOCKET_ERROR) - { - NetLog_Direct("Oscar %p socket error: %d, closing", oc->hConnection, GetLastError()); - CloseOscarConnection(oc); - } - } - - SAFE_FREE((void**)&packet->pData); -} - - -int CIcqProto::oft_handlePackets(oscar_connection *oc, BYTE *buf, int len) -{ - int bytesUsed = 0; - - while (len > 0) - { - if (oc->status == OCS_DATA && (oc->ft->flags & OFTF_FILE_RECEIVING)) - { - return oft_handleFileData(oc, buf, len); - } - else if (oc->status == OCS_PROXY) - { - return oft_handleProxyData(oc, buf, len); - } - if (len < 6) - break; - - BYTE *pBuf = buf; - DWORD dwHead; - unpackDWord(&pBuf, &dwHead); - if (dwHead != 0x4F465432) - { // bad packet - NetLog_Direct("OFT: Received invalid packet (dwHead = 0x%x).", dwHead); - - CloseOscarConnection(oc); - break; - } - - WORD datalen; - unpackWord(&pBuf, &datalen); - - if (len < datalen) // wait for whole packet - break; - - WORD datatype; - unpackWord(&pBuf, &datatype); -#ifdef _DEBUG - NetLog_Direct("OFT2: Type %u, Length %u bytes", datatype, datalen); -#endif - handleOFT2FramePacket(oc, datatype, pBuf, (WORD)(datalen - 8)); - - /* Increase pointers so we can check for more data */ - buf += datalen; - len -= datalen; - bytesUsed += datalen; - } - - return bytesUsed; -} - - -int CIcqProto::oft_handleProxyData(oscar_connection *oc, BYTE *buf, int len) -{ - oscar_filetransfer *ft = oc->ft; - BYTE *pBuf; - WORD datalen; - WORD wCommand; - int bytesUsed = 0; - - - while (len > 2) - { - pBuf = buf; - - unpackWord(&pBuf, &datalen); - datalen += 2; - - if (len < datalen) - break; // packet is not complete - - if (datalen < 12) - { // malformed packet - CloseOscarConnection(oc); - break; - } - pBuf += 2; // packet version - unpackWord(&pBuf, &wCommand); - pBuf += 6; - // handle packet - switch (wCommand) - { - case 0x01: // Error - { - WORD wError; - char* szError; - - unpackWord(&pBuf, &wError); - switch(wError) - { - case 0x0D: - szError = "Bad request"; - break; - case 0x0E: - szError = "Malformed packet"; - break; - case 0x10: - szError = "Initial request timeout"; - break; - case 0x1A: - szError = "Accept period timeout"; - break; - case 0x1C: - szError = "Invalid data"; - break; - - default: - szError = "Unknown"; - } - // Notify peer - oft_sendFileResponse(oc->dwUin, oc->szUid, oc->ft, 0x06); - - NetLog_Server("Proxy Error: %s (0x%x)", szError, wError); - // Notify UI - BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc->ft, 0); - // Release structure - SafeReleaseFileTransfer((void**)&oc->ft); - } - break; - - case 0x03: // Tunnel created - { - WORD wCode; - DWORD dwIP; - - unpackWord(&pBuf, &wCode); - unpackDWord(&pBuf, &dwIP); - - if (oc->type == OCT_PROXY_INIT) - { // Proxy ready, send Stage 1 Request - ft->bUseProxy = 1; - ft->wRemotePort = wCode; - ft->dwProxyIP = dwIP; - oft_sendFileRequest(oc->dwUin, oc->szUid, ft, ft->szThisFile, 0); - SAFE_FREE(&ft->szThisFile); - // Notify UI - BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, oc->ft, 0); - } - else - { - NetLog_Server("Proxy Tunnel ready, notify peer."); - oft_sendFileRedirect(oc->dwUin, oc->szUid, ft, dwIP, wCode, TRUE); - } - } - break; - - case 0x05: // Connection ready - oc->status = OCS_CONNECTED; // connection ready to send packets - // Notify UI - BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, oc->ft, 0); - // signal we are ready - if (oc->type == OCT_PROXY_RECV) - { - oft_sendFileAccept(oc->dwUin, oc->szUid, ft); - if (ft->flags & OFTF_SENDING) // connection is ready for transfer (sending only) - ft->flags |= OFTF_INITIALIZED; - } - - NetLog_Server("Proxy Tunnel established"); - - if ((ft->flags & OFTF_INITIALIZED) && (ft->flags & OFTF_SENDING) && !(ft->flags & OFTF_FILE_REQUEST_SENT)) - { - ft->flags |= OFTF_FILE_REQUEST_SENT; - // proceed with first file - oft_sendPeerInit(ft->connection); - } - break; - - default: - NetLog_Server("Unknown proxy command 0x%x", wCommand); - } - - buf += datalen; - len -= datalen; - bytesUsed += datalen; - } - - return bytesUsed; -} - - -int CIcqProto::oft_handleFileData(oscar_connection *oc, BYTE *buf, int len) -{ - oscar_filetransfer *ft = oc->ft; - DWORD dwLen = len; - int bytesUsed = 0; - - // do not accept more data than expected - if (ft->qwThisFileSize - ft->qwFileBytesDone < dwLen) - dwLen = (int)(ft->qwThisFileSize - ft->qwFileBytesDone); - - if (ft->fileId == -1) - { // something went terribly bad -#ifdef _DEBUG - NetLog_Direct("Error: handleFileData(%u bytes) without fileId!", len); -#endif - CloseOscarConnection(oc); - return 0; - } - _write(ft->fileId, buf, dwLen); - // update checksum - ft->dwRecvFileCheck = oft_calc_checksum((int)ft->qwFileBytesDone, buf, dwLen, ft->dwRecvFileCheck); - bytesUsed += dwLen; - ft->qwBytesDone += dwLen; - ft->qwFileBytesDone += dwLen; - - if (GetTickCount() > ft->dwLastNotify + 700 || ft->qwFileBytesDone == ft->qwThisFileSize) - { // notify FT UI of our progress, at most every 700ms - do not be faster than Miranda - PROTOFILETRANSFERSTATUS pfts; - - oft_buildProtoFileTransferStatus(ft, &pfts); - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&pfts); - ft->dwLastNotify = GetTickCount(); - } - if (ft->qwFileBytesDone == ft->qwThisFileSize) - { - /* EOF */ - ft->flags &= ~OFTF_FILE_RECEIVING; - -#ifdef _DEBUG - NetLog_Direct("OFT: _close(%u)", ft->fileId); -#endif - _close(ft->fileId); - ft->fileId = -1; - - if (ft->resumeAction != FILERESUME_SKIP && ft->dwRecvFileCheck != ft->dwThisFileCheck) - { - NetLog_Direct("Error: File checksums does not match!"); - { // Notify UI - char *pszMsg = ICQTranslateUtf(LPGEN("The checksum of file \"%s\" does not match, the file is probably damaged.")); - char szBuf[MAX_PATH]; - - null_snprintf(szBuf, MAX_PATH, pszMsg, ExtractFileName(ft->szThisFile)); - icq_LogMessage(LOG_ERROR, szBuf); - - SAFE_FREE(&pszMsg); - } - } // keep transfer going (icq6 ignores checksums completely) - else if (ft->resumeAction == FILERESUME_SKIP) - NetLog_Direct("OFT: File receive skipped."); - else - NetLog_Direct("OFT: File received successfully."); - - if ((DWORD)(ft->iCurrentFile + 1) == ft->wFilesCount) - { - ft->bHeaderFlags = 0x01; // the whole process is over - // ack received file - sendOFT2FramePacket(oc, OFT_TYPE_DONE); - oc->type = OCT_CLOSING; - NetLog_Direct("File Transfer completed successfully."); - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&ft); - } - else - { // ack received file - sendOFT2FramePacket(oc, OFT_TYPE_DONE); - oc->status = OCS_NEGOTIATION; - } - - } - return bytesUsed; -} - - -void CIcqProto::handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen) -{ - oscar_filetransfer *ft = oc->ft; - DWORD dwID1; - DWORD dwID2; - - if (wLen < 232) - { // allow shorter packets, but at least with filename - NetLog_Direct("Error: Malformed OFT2 Frame, ignoring."); - return; - } - - unpackLEDWord(&pBuffer, &dwID1); - wLen -= 4; - unpackLEDWord(&pBuffer, &dwID2); - wLen -= 4; - - if (datatype == OFT_TYPE_REQUEST && !(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - { // first request does not contain MsgIDs we need to send them in ready packet - dwID1 = ft->pMessage.dwMsgID1; - dwID2 = ft->pMessage.dwMsgID2; - } - - if (ft->pMessage.dwMsgID1 != dwID1 || ft->pMessage.dwMsgID2 != dwID2) - { // this is not the right packet - bad Message IDs - NetLog_Direct("Error: Invalid Packet Cookie, closing."); - CloseOscarConnection(oc); - - return; - } - - switch (datatype) { - - case OFT_TYPE_REQUEST: - { // Sender ready - if (ft->flags & OFTF_SENDING) - { // just sanity check - this is only for receiving client - NetLog_Direct("Error: Invalid Packet, closing."); - CloseOscarConnection(oc); - return; - } - - // Read Frame data - if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - { - unpackWord(&pBuffer, &ft->wEncrypt); - unpackWord(&pBuffer, &ft->wCompress); - unpackWord(&pBuffer, &ft->wFilesCount); - } - else - pBuffer += 6; - unpackWord(&pBuffer, &ft->wFilesLeft); - ft->iCurrentFile = ft->wFilesCount - ft->wFilesLeft; - if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - unpackWord(&pBuffer, &ft->wPartsCount); - else - pBuffer += 2; - unpackWord(&pBuffer, &ft->wPartsLeft); - if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - { // just check it - DWORD dwSize; - - unpackDWord(&pBuffer, &dwSize); - if (dwSize != (DWORD)ft->qwTotalSize) - { // the 32bits does not match, use them as full size - ft->qwTotalSize = dwSize; - - NetLog_Server("Warning: Invalid total size."); - } - } - else - pBuffer += 4; - { // this allows us to receive single >4GB file correctly - DWORD dwSize; - - unpackDWord(&pBuffer, &dwSize); - if (dwSize == (DWORD)ft->qwTotalSize && ft->wFilesCount == 1) - ft->qwThisFileSize = ft->qwTotalSize; - else - ft->qwThisFileSize = dwSize; - } - unpackDWord(&pBuffer, &ft->dwThisFileDate); - unpackDWord(&pBuffer, &ft->dwThisFileCheck); - unpackDWord(&pBuffer, &ft->dwRecvForkCheck); - unpackDWord(&pBuffer, &ft->dwThisForkSize); - unpackDWord(&pBuffer, &ft->dwThisFileCreation); - unpackDWord(&pBuffer, &ft->dwThisForkCheck); - pBuffer += 4; // File Bytes Done - unpackDWord(&pBuffer, &ft->dwRecvFileCheck); - if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - unpackString(&pBuffer, ft->rawIDString, 32); - else - pBuffer += 32; - unpackByte(&pBuffer, &ft->bHeaderFlags); - unpackByte(&pBuffer, &ft->bNameOff); - unpackByte(&pBuffer, &ft->bSizeOff); - if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) - { - unpackString(&pBuffer, (char*)ft->rawDummy, 69); - unpackString(&pBuffer, (char*)ft->rawMacInfo, 16); - } - else - pBuffer += 85; - unpackWord(&pBuffer, &ft->wEncoding); - unpackWord(&pBuffer, &ft->wSubEncoding); - ft->cbRawFileName = wLen - 176; - SAFE_FREE((void**)&ft->rawFileName); // release previous buffers - SAFE_FREE(&ft->szThisFile); - ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName + 2); - unpackString(&pBuffer, ft->rawFileName, ft->cbRawFileName); - // Prepare file - if (ft->wEncoding == 2) - { // UCS-2 encoding - ft->szThisFile = ApplyEncoding(ft->rawFileName, "unicode-2-0"); - } - else - { - ft->szThisFile = ansi_to_utf8(ft->rawFileName); - } - - { // convert dir markings to normal backslashes - int i; - - for (i = 0; i < strlennull(ft->szThisFile); i++) - { - if (ft->szThisFile[i] == 0x01) ft->szThisFile[i] = '\\'; - } - } - - ft->flags |= OFTF_FILE_REQUEST_RECEIVED; // First Frame Processed - - NetLog_Direct("File '%s', %I64u Bytes", ft->szThisFile, ft->qwThisFileSize); - - { // Prepare Path Information - char *szFile = strrchr(ft->szThisFile, '\\'); - - SAFE_FREE(&ft->szThisPath); // release previous path - if (szFile) - { - ft->szThisPath = ft->szThisFile; - szFile[0] = '\0'; // split that strings - ft->szThisFile = null_strdup(szFile + 1); - // no cheating with paths - if (!IsValidRelativePath(ft->szThisPath)) - { - NetLog_Direct("Invalid path information"); - break; - } - } - else - ft->szThisPath = null_strdup(""); - } - - /* no cheating with paths */ - if (!IsValidRelativePath(ft->szThisFile)) - { - NetLog_Direct("Invalid path information"); - break; - } - char *szFullPath = (char*)SAFE_MALLOC(strlennull(ft->szSavePath)+strlennull(ft->szThisPath)+strlennull(ft->szThisFile)+3); - strcpy(szFullPath, ft->szSavePath); - NormalizeBackslash(szFullPath); - strcat(szFullPath, ft->szThisPath); - NormalizeBackslash(szFullPath); - // make sure the dest dir exists - if (MakeDirUtf(szFullPath)) - NetLog_Direct("Failed to create destination directory!"); - - strcat(szFullPath, ft->szThisFile); - // we joined the full path to dest file - SAFE_FREE(&ft->szThisFile); - ft->szThisFile = szFullPath; - - ft->qwFileBytesDone = 0; - - { - /* file resume */ - PROTOFILETRANSFERSTATUS pfts; - - oft_buildProtoFileTransferStatus(ft, &pfts); - if (BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&pfts)) - { - oc->status = OCS_WAITING; - break; /* UI supports resume: it will call PS_FILERESUME */ - } - - ft->fileId = OpenFileUtf(ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); -#ifdef _DEBUG - NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, ft->fileId); -#endif - if (ft->fileId == -1) - { -#ifdef _DEBUG - NetLog_Direct("OFT: errno=%d", errno); -#endif - icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oc->ft); - return; - } - } - // Send "we are ready" - oc->status = OCS_DATA; - ft->flags |= OFTF_FILE_RECEIVING; - - sendOFT2FramePacket(oc, OFT_TYPE_READY); - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); - if (!ft->qwThisFileSize) - { // if the file is empty we will not receive any data - BYTE buf; - - oft_handleFileData(oc, &buf, 0); - } - return; - } - - case OFT_TYPE_READY: - case OFT_TYPE_RESUMEACK: - { // Receiver is ready - oc->status = OCS_DATA; - oc->wantIdleTime = 1; - ft->flags |= OFTF_FILE_SENDING; - - NetLog_Direct("OFT: Receiver ready."); - } - break; - - case OFT_TYPE_RESUMEREQUEST: - { // Receiver wants to resume file transfer from point - DWORD dwResumeCheck, dwResumeOffset, dwFileCheck; - - if (!(ft->flags & OFTF_SENDING)) - { // just sanity check - this is only for sending client - NetLog_Direct("Error: Invalid Packet, closing."); - CloseOscarConnection(oc); - - return; - } - // Read Resume Frame data - pBuffer += 44; - unpackDWord(&pBuffer, &dwResumeOffset); - unpackDWord(&pBuffer, &dwResumeCheck); - - dwFileCheck = oft_calc_file_checksum(ft->fileId, dwResumeOffset); - if (dwFileCheck == dwResumeCheck && dwResumeOffset <= ft->qwThisFileSize) - { // resume seems ok - ft->qwFileBytesDone = dwResumeOffset; - ft->qwBytesDone += dwResumeOffset; - _lseek(ft->fileId, dwResumeOffset, SEEK_SET); - - NetLog_Direct("OFT: Resume request, ready."); - } - else - NetLog_Direct("OFT: Resume request, restarting."); - - // Ready for resume - sendOFT2FramePacket(oc, OFT_TYPE_RESUMEREADY); - } - break; - - case OFT_TYPE_RESUMEREADY: - { // Process Smart-resume reply - DWORD dwResumeOffset, dwResumeCheck; - - if (ft->flags & OFTF_SENDING) - { // just sanity check - this is only for receiving client - NetLog_Direct("Error: Invalid Packet, closing."); - CloseOscarConnection(oc); - - return; - } - // Read Resume Reply data - pBuffer += 44; - unpackDWord(&pBuffer, &dwResumeOffset); - unpackDWord(&pBuffer, &dwResumeCheck); - - if (ft->qwFileBytesDone != dwResumeOffset) - { - ft->qwBytesDone -= (ft->qwFileBytesDone - dwResumeOffset); - ft->qwFileBytesDone = dwResumeOffset; - if (dwResumeOffset) - ft->dwRecvFileCheck = dwResumeCheck; - else // Restarted resume (data mismatch) - ft->dwRecvFileCheck = 0xFFFF0000; - } - _lseek(ft->fileId, dwResumeOffset, SEEK_SET); - - if (ft->qwThisFileSize != ft->qwFileBytesDone) - NetLog_Direct("OFT: Resuming from offset %u.", dwResumeOffset); - - // Prepare to receive data - oc->status = OCS_DATA; - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); - - // Ready for receive - sendOFT2FramePacket(oc, OFT_TYPE_RESUMEACK); - - if (ft->qwThisFileSize == ft->qwFileBytesDone) - { // all data already processed - BYTE buf; - - oft_handleFileData(oc, &buf, 0); - } - } - break; - - case OFT_TYPE_DONE: - { // File done - oc->status = OCS_NEGOTIATION; - oc->wantIdleTime = 0; - - ft->flags &= ~OFTF_FILE_SENDING; - - NetLog_Direct("OFT: File sent successfully."); - -#ifdef _DEBUG - NetLog_Direct("OFT: _close(%u)", ft->fileId); -#endif - _close(ft->fileId); // FIXME: this needs fix for "skip file" feature - ft->fileId = -1; - ft->iCurrentFile++; - // continue with next file - oft_sendPeerInit(oc); - } - break; - - default: - NetLog_Direct("Error: Uknown OFT frame type 0x%x", datatype); - } -} - - -// -// Proxy packets -///////////////////////////// - -void CIcqProto::proxy_sendInitTunnel(oscar_connection *oc) -{ - icq_packet packet; - WORD wLen = 39 + getUINLen(m_dwLocalUIN); - - packet.wLen = wLen; - init_generic_packet(&packet, 2); - - packWord(&packet, wLen); - packWord(&packet, OSCAR_PROXY_VERSION); - packWord(&packet, 0x02); // wCommand - packDWord(&packet, 0); // Unknown - packWord(&packet, 0); // Flags? - packUIN(&packet, m_dwLocalUIN); - packLEDWord(&packet, oc->ft->pMessage.dwMsgID1); - packLEDWord(&packet, oc->ft->pMessage.dwMsgID2); - packDWord(&packet, 0x00010010); // TLV(1) - packGUID(&packet, MCAP_FILE_TRANSFER); - - sendOscarPacket(oc, &packet); -} - -void CIcqProto::proxy_sendJoinTunnel(oscar_connection *oc, WORD wPort) -{ - icq_packet packet; - WORD wLen = 41 + getUINLen(m_dwLocalUIN); - - packet.wLen = wLen; - init_generic_packet(&packet, 2); - - packWord(&packet, wLen); - packWord(&packet, OSCAR_PROXY_VERSION); - packWord(&packet, 0x04); // wCommand - packDWord(&packet, 0); // Unknown - packWord(&packet, 0); // Flags? - packUIN(&packet, m_dwLocalUIN); - packWord(&packet, wPort); - packLEDWord(&packet, oc->ft->pMessage.dwMsgID1); - packLEDWord(&packet, oc->ft->pMessage.dwMsgID2); - packDWord(&packet, 0x00010010); // TLV(1) - packGUID(&packet, MCAP_FILE_TRANSFER); - - sendOscarPacket(oc, &packet); -} - -// -// Direct packets -///////////////////////////// - -void CIcqProto::oft_sendFileData(oscar_connection *oc) -{ - oscar_filetransfer *ft = oc->ft; - BYTE buf[OFT_BUFFER_SIZE]; - - if (ft->fileId == -1) - return; - - int bytesRead = _read(ft->fileId, buf, sizeof(buf)); - if (bytesRead == -1) - return; - - if (!bytesRead) - { // - oc->wantIdleTime = 0; - return; - } - - if ((DWORD)bytesRead > (ft->qwThisFileSize - ft->qwFileBytesDone)) - { // do not send more than expected, limit to known size - bytesRead = (DWORD)(ft->qwThisFileSize - ft->qwFileBytesDone); - oc->wantIdleTime = 0; - } - - if (bytesRead) - { - icq_packet packet; - - packet.wLen = bytesRead; - init_generic_packet(&packet, 0); - packBuffer(&packet, buf, (WORD)bytesRead); // we are sending raw data - sendOscarPacket(oc, &packet); - - ft->qwBytesDone += bytesRead; - ft->qwFileBytesDone += bytesRead; - } - - if (GetTickCount() > ft->dwLastNotify + 700 || oc->wantIdleTime == 0 || ft->qwFileBytesDone == ft->qwThisFileSize) - { // notify only once a while or after last data packet sent - PROTOFILETRANSFERSTATUS pfts; - - oft_buildProtoFileTransferStatus(ft, &pfts); - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&pfts); - ft->dwLastNotify = GetTickCount(); - } -} - -void CIcqProto::oft_sendPeerInit(oscar_connection *oc) -{ - icq_lock l(oftMutex); - - oscar_filetransfer *ft = oc->ft; - struct _stati64 statbuf; - char *pszThisFileName; - - // prepare init frame - if (ft->iCurrentFile >= (int)ft->wFilesCount) - { // All files done, great! - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oc->ft); - return; - } - - SAFE_FREE(&ft->szThisFile); - ft->szThisFile = null_strdup(ft->files[ft->iCurrentFile].szFile); - if (FileStatUtf(ft->szThisFile, &statbuf)) - { - icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oc->ft); - return; - } - - { // create full relative filename - char* szThisContainer = ft->files[ft->iCurrentFile].szContainer; - - pszThisFileName = (char*)SAFE_MALLOC(strlennull(ft->szThisFile) + strlennull(szThisContainer) + 4); - strcpy(pszThisFileName, szThisContainer); - NormalizeBackslash(pszThisFileName); - strcat(pszThisFileName, ExtractFileName(ft->szThisFile)); - } - { // convert backslashes to dir markings - int i; - for (i = 0; i < strlennull(pszThisFileName); i++) - if (pszThisFileName[i] == '\\' || pszThisFileName[i] == '/') - pszThisFileName[i] = 0x01; - } - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); - - ft->fileId = OpenFileUtf(ft->szThisFile, _O_BINARY | _O_RDONLY, 0); -#ifdef _DEBUG - NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, _O_BINARY | _O_RDONLY, ft->fileId); -#endif - if (ft->fileId == -1) - { -#ifdef _DEBUG - NetLog_Direct("OFT: errno=%d", errno); -#endif - SAFE_FREE((void**)&pszThisFileName); - icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); - // - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - // Release transfer - SafeReleaseFileTransfer((void**)&oc->ft); - return; - } - - ft->qwThisFileSize = statbuf.st_size; - ft->dwThisFileDate = statbuf.st_mtime; - ft->dwThisFileCreation = statbuf.st_ctime; - ft->dwThisFileCheck = oft_calc_file_checksum(ft->fileId, ft->qwThisFileSize); - ft->qwFileBytesDone = 0; - ft->dwRecvFileCheck = 0xFFFF0000; - SAFE_FREE((void**)&ft->rawFileName); - - if (IsUSASCII(pszThisFileName, strlennull(pszThisFileName))) - { - ft->wEncoding = 0; // ascii - ft->cbRawFileName = strlennull(pszThisFileName) + 1; - if (ft->cbRawFileName < 64) ft->cbRawFileName = 64; - ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName); - strcpy(ft->rawFileName, (char*)pszThisFileName); - SAFE_FREE((void**)&pszThisFileName); - } - else - { - ft->wEncoding = 2; // ucs-2 - WCHAR *pwsThisFile = make_unicode_string(pszThisFileName); - SAFE_FREE((void**)&pszThisFileName); - ft->cbRawFileName = strlennull(pwsThisFile) * (int)sizeof(WCHAR) + 2; - if (ft->cbRawFileName < 64) ft->cbRawFileName = 64; - ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName); - // convert to LE ordered string - BYTE *pwsThisFileBuf = (BYTE*)pwsThisFile; // need this - unpackWideString moves the address! - unpackWideString(&pwsThisFileBuf, (WCHAR*)ft->rawFileName, (WORD)(strlennull(pwsThisFile) * sizeof(WCHAR))); - SAFE_FREE((void**)&pwsThisFile); - } - ft->wFilesLeft = (WORD)(ft->wFilesCount - ft->iCurrentFile); - - sendOFT2FramePacket(oc, OFT_TYPE_REQUEST); -} - -void CIcqProto::sendOFT2FramePacket(oscar_connection *oc, WORD datatype) -{ - oscar_filetransfer *ft = oc->ft; - icq_packet packet; - - packet.wLen = 192 + ft->cbRawFileName; - init_generic_packet(&packet, 0); - // Basic Oscar Frame - packDWord(&packet, 0x4F465432); // Magic - packWord(&packet, packet.wLen); - packWord(&packet, datatype); - // Cookie - packLEDWord(&packet, ft->pMessage.dwMsgID1); - packLEDWord(&packet, ft->pMessage.dwMsgID2); - packWord(&packet, ft->wEncrypt); - packWord(&packet, ft->wCompress); - packWord(&packet, ft->wFilesCount); - packWord(&packet, ft->wFilesLeft); - packWord(&packet, ft->wPartsCount); - packWord(&packet, ft->wPartsLeft); - packDWord(&packet, (DWORD)ft->qwTotalSize); - packDWord(&packet, (DWORD)ft->qwThisFileSize); - packDWord(&packet, ft->dwThisFileDate); - packDWord(&packet, ft->dwThisFileCheck); - packDWord(&packet, ft->dwRecvForkCheck); - packDWord(&packet, ft->dwThisForkSize); - packDWord(&packet, ft->dwThisFileCreation); - packDWord(&packet, ft->dwThisForkCheck); - packDWord(&packet, (DWORD)ft->qwFileBytesDone); - packDWord(&packet, ft->dwRecvFileCheck); - packBuffer(&packet, (LPBYTE)ft->rawIDString, 32); - packByte(&packet, ft->bHeaderFlags); - packByte(&packet, ft->bNameOff); - packByte(&packet, ft->bSizeOff); - packBuffer(&packet, ft->rawDummy, 69); - packBuffer(&packet, ft->rawMacInfo, 16); - packWord(&packet, ft->wEncoding); - packWord(&packet, ft->wSubEncoding); - packBuffer(&packet, (LPBYTE)ft->rawFileName, ft->cbRawFileName); - - sendOscarPacket(oc, &packet); -} diff --git a/protocols/IcqOscarJ/oscar_filetransfer.h b/protocols/IcqOscarJ/oscar_filetransfer.h deleted file mode 100644 index fa6ec9169e..0000000000 --- a/protocols/IcqOscarJ/oscar_filetransfer.h +++ /dev/null @@ -1,164 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// OSCAR File-Transfers headers -// -// ----------------------------------------------------------------------------- -#ifndef __OSCAR_FILETRANSFER_H -#define __OSCAR_FILETRANSFER_H - - -#define FT_MAGIC_ICQ 0x00 -#define FT_MAGIC_OSCAR 0x4F - -struct basic_filetransfer -{ - cookie_message_data pMessage; - BYTE ft_magic; -}; - -#define OFT_BUFFER_SIZE 8192 - -struct oft_file_record -{ - char *szContainer; - char *szFile; -}; - -char *FindFilePathContainer(const char **files, int iFile, char *szContainer); - - -// file-transfer status flags -#define OFTF_INITIALIZED 0x0001 // connection established (ack received) -#define OFTF_SENDING 0x0002 // sending files (receiving otherwise) -#define OFTF_FILE_REQUEST_SENT 0x0004 // request sent (sending only) -#define OFTF_FILE_REQUEST_RECEIVED 0x0008 // first request processed (receiving only) -#define OFTF_FILE_SENDING 0x0010 // sending file contents -#define OFTF_FILE_RECEIVING 0x0020 // receiving file contents -#define OFTF_FILE_DONE 0x0040 // file finished - -struct oscar_filetransfer: public basic_filetransfer -{ - HANDLE hContact; - int flags; // combination of OFTF_* - int containerCount; - char **file_containers; - oft_file_record *files; - char **files_list; // sending only - int iCurrentFile; - int currentIsDir; - int bUseProxy; - DWORD dwProxyIP; - DWORD dwRemoteInternalIP; - DWORD dwRemoteExternalIP; - WORD wRemotePort; - char *szSavePath; - char *szDescription; - char *szThisFile; - char *szThisPath; - // Request sequence - DWORD dwCookie; - WORD wReqNum; - // OFT2 header data - WORD wEncrypt, wCompress; - WORD wFilesCount,wFilesLeft; - WORD wPartsCount, wPartsLeft; - DWORD64 qwTotalSize; - DWORD64 qwThisFileSize; - DWORD dwThisFileDate; // modification date - DWORD dwThisFileCheck; - DWORD dwRecvForkCheck, dwThisForkSize; - DWORD dwThisFileCreation; // creation date (not used) - DWORD dwThisForkCheck; - DWORD64 qwBytesDone; - DWORD dwRecvFileCheck; - char rawIDString[32]; - BYTE bHeaderFlags; - BYTE bNameOff, bSizeOff; - BYTE rawDummy[69]; - BYTE rawMacInfo[16]; - WORD wEncoding, wSubEncoding; - WORD cbRawFileName; - char *rawFileName; - // helper data - DWORD64 qwFileBytesDone; - int fileId; - struct oscar_connection *connection; - struct oscar_listener *listener; - DWORD dwLastNotify; - int resumeAction; -}; - -#define OFT_TYPE_REQUEST 0x0101 // I am going to send you this file, is that ok? -#define OFT_TYPE_READY 0x0202 // Yes, it is ok for you to send me that file -#define OFT_TYPE_DONE 0x0204 // I received that file with no problems -#define OFT_TYPE_RESUMEREQUEST 0x0205 // Resume transferring from position -#define OFT_TYPE_RESUMEREADY 0x0106 // Ok, I am ready to send it -#define OFT_TYPE_RESUMEACK 0x0207 // Fine, ready to receive - -void SafeReleaseFileTransfer(void **ft); - -struct oscar_connection -{ - HANDLE hContact; - HANDLE hConnection; - int status; - DWORD dwUin; - uid_str szUid; - DWORD dwLocalInternalIP; - DWORD dwLocalExternalIP; - int type; - int incoming; - oscar_filetransfer *ft; - int wantIdleTime; -}; - -#define OCT_NORMAL 0 -#define OCT_REVERSE 1 -#define OCT_PROXY 2 -#define OCT_PROXY_INIT 3 -#define OCT_PROXY_RECV 4 -#define OCT_CLOSING 10 - -#define OCS_READY 0 -#define OCS_CONNECTED 1 -#define OCS_NEGOTIATION 2 -#define OCS_RESUME 3 -#define OCS_DATA 4 -#define OCS_PROXY 8 -#define OCS_WAITING 10 - -struct oscar_listener -{ - CIcqProto *ppro; - WORD wPort; - HANDLE hBoundPort; - oscar_filetransfer *ft; -}; - - -#endif /* __OSCAR_FILETRANSFER_H */ - diff --git a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.rc b/protocols/IcqOscarJ/proto_icq/Proto_ICQ.rc deleted file mode 100644 index 51337c2e4f..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.rc and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj b/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj index de86e8248c..012196ddaf 100644 --- a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj +++ b/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj @@ -119,10 +119,10 @@ - + - + diff --git a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj.filters b/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj.filters index 12cfc7e376..6f24876932 100644 --- a/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj.filters +++ b/protocols/IcqOscarJ/proto_icq/Proto_ICQ.vcxproj.filters @@ -11,12 +11,12 @@ - + Header Files - + Resource Files diff --git a/protocols/IcqOscarJ/proto_icq/icos/Away.ico b/protocols/IcqOscarJ/proto_icq/icos/Away.ico deleted file mode 100644 index ec77463401..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Away.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/DND.ico b/protocols/IcqOscarJ/proto_icq/icos/DND.ico deleted file mode 100644 index 1e321b41e2..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/DND.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/FFC.ico b/protocols/IcqOscarJ/proto_icq/icos/FFC.ico deleted file mode 100644 index 2bb381d6a3..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/FFC.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/Invisible.ico b/protocols/IcqOscarJ/proto_icq/icos/Invisible.ico deleted file mode 100644 index 9962090108..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Invisible.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/NA.ico b/protocols/IcqOscarJ/proto_icq/icos/NA.ico deleted file mode 100644 index 6cb72f1510..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/NA.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/Occupied.ico b/protocols/IcqOscarJ/proto_icq/icos/Occupied.ico deleted file mode 100644 index 711bcd53e5..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Occupied.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/Offline.ico b/protocols/IcqOscarJ/proto_icq/icos/Offline.ico deleted file mode 100644 index 3684dbc20b..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Offline.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/Online.ico b/protocols/IcqOscarJ/proto_icq/icos/Online.ico deleted file mode 100644 index 8c828871bb..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Online.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/icos/Phone.ico b/protocols/IcqOscarJ/proto_icq/icos/Phone.ico deleted file mode 100644 index 476461a8d0..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/icos/Phone.ico and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Away.ico b/protocols/IcqOscarJ/proto_icq/res/Away.ico new file mode 100644 index 0000000000..ec77463401 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Away.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/DND.ico b/protocols/IcqOscarJ/proto_icq/res/DND.ico new file mode 100644 index 0000000000..1e321b41e2 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/DND.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/FFC.ico b/protocols/IcqOscarJ/proto_icq/res/FFC.ico new file mode 100644 index 0000000000..2bb381d6a3 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/FFC.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Invisible.ico b/protocols/IcqOscarJ/proto_icq/res/Invisible.ico new file mode 100644 index 0000000000..9962090108 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Invisible.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/NA.ico b/protocols/IcqOscarJ/proto_icq/res/NA.ico new file mode 100644 index 0000000000..6cb72f1510 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/NA.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Occupied.ico b/protocols/IcqOscarJ/proto_icq/res/Occupied.ico new file mode 100644 index 0000000000..711bcd53e5 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Occupied.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Offline.ico b/protocols/IcqOscarJ/proto_icq/res/Offline.ico new file mode 100644 index 0000000000..3684dbc20b Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Offline.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Online.ico b/protocols/IcqOscarJ/proto_icq/res/Online.ico new file mode 100644 index 0000000000..8c828871bb Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Online.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Phone.ico b/protocols/IcqOscarJ/proto_icq/res/Phone.ico new file mode 100644 index 0000000000..476461a8d0 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Phone.ico differ diff --git a/protocols/IcqOscarJ/proto_icq/res/Proto_ICQ.rc b/protocols/IcqOscarJ/proto_icq/res/Proto_ICQ.rc new file mode 100644 index 0000000000..64c5e8b7bd Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/res/Proto_ICQ.rc differ diff --git a/protocols/IcqOscarJ/proto_icq/resource.h b/protocols/IcqOscarJ/proto_icq/resource.h deleted file mode 100644 index 51271432b6..0000000000 Binary files a/protocols/IcqOscarJ/proto_icq/resource.h and /dev/null differ diff --git a/protocols/IcqOscarJ/proto_icq/src/resource.h b/protocols/IcqOscarJ/proto_icq/src/resource.h new file mode 100644 index 0000000000..51271432b6 Binary files /dev/null and b/protocols/IcqOscarJ/proto_icq/src/resource.h differ diff --git a/protocols/IcqOscarJ/res/auth_ask.ico b/protocols/IcqOscarJ/res/auth_ask.ico new file mode 100644 index 0000000000..1db6f7f23e Binary files /dev/null and b/protocols/IcqOscarJ/res/auth_ask.ico differ diff --git a/protocols/IcqOscarJ/res/auth_grant.ico b/protocols/IcqOscarJ/res/auth_grant.ico new file mode 100644 index 0000000000..44d5b29a31 Binary files /dev/null and b/protocols/IcqOscarJ/res/auth_grant.ico differ diff --git a/protocols/IcqOscarJ/res/auth_revoke.ico b/protocols/IcqOscarJ/res/auth_revoke.ico new file mode 100644 index 0000000000..e483681727 Binary files /dev/null and b/protocols/IcqOscarJ/res/auth_revoke.ico differ diff --git a/protocols/IcqOscarJ/res/expandst.ico b/protocols/IcqOscarJ/res/expandst.ico new file mode 100644 index 0000000000..17367fe8d3 Binary files /dev/null and b/protocols/IcqOscarJ/res/expandst.ico differ diff --git a/protocols/IcqOscarJ/res/icq.ico b/protocols/IcqOscarJ/res/icq.ico new file mode 100644 index 0000000000..98a99aca1c Binary files /dev/null and b/protocols/IcqOscarJ/res/icq.ico differ diff --git a/protocols/IcqOscarJ/res/resources.rc b/protocols/IcqOscarJ/res/resources.rc new file mode 100644 index 0000000000..d1dc830ab1 --- /dev/null +++ b/protocols/IcqOscarJ/res/resources.rc @@ -0,0 +1,595 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "..\src\version.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICQ ICON "icq.ico" +IDI_AUTH_ASK ICON "auth_ask.ico" +IDI_AUTH_GRANT ICON "auth_grant.ico" +IDI_AUTH_REVOKE ICON "auth_revoke.ico" +IDI_SERVLIST_ADD ICON "srvlist_add.ico" +IDI_EXPANDSTRINGEDIT ICON "expandst.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ICQACCOUNT DIALOGEX 0, 0, 186, 68 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "ICQ Number:",IDC_STATIC,0,0,53,12 + EDITTEXT IDC_UIN,54,0,131,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,0,16,53,12 + EDITTEXT IDC_PW,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Create a new ICQ account",IDC_REGISTER,"Hyperlink",WS_TABSTOP,0,49,174,12 +END + +IDD_ASKAUTH DIALOGEX 0, 0, 186, 95 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter an authorization request" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "&Send",IDOK,34,74,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,98,74,50,14 + EDITTEXT IDC_EDITAUTH,7,7,172,59,ES_AUTOHSCROLL +END + +IDD_LOGINPW DIALOGEX 0, 0, 157, 87 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter ICQ Password" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Enter a password for UIN %d:",IDC_INSTRUCTION,7,7,142,8 + EDITTEXT IDC_LOGINPW,17,16,122,14,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Remember this session password",IDC_SAVEPASS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,54,120,10 + DEFPUSHBUTTON "OK",IDOK,24,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,84,66,50,14 +END + +IDD_OPT_ICQ DIALOGEX 0, 0, 310, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "ICQ",IDC_STICQGROUP,4,0,302,93 + RTEXT "ICQ number:",IDC_STATIC11,12,14,51,8 + EDITTEXT IDC_ICQNUM,68,12,106,12,ES_AUTOHSCROLL + RTEXT "Password:",IDC_STATIC12,12,28,51,8 + EDITTEXT IDC_PASSWORD,68,26,106,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Hint: If you don't enter your password here, Miranda will ask for the password everytime you try to go online.",IDC_STATIC,12,43,286,19 + CONTROL "Retrieve a lost password or ICQ number",IDC_LOOKUPLINK, + "Hyperlink",WS_TABSTOP,12,78,286,8 + CONTROL "Create a new ICQ account using the ICQ website",IDC_NEWUINLINK, + "Hyperlink",WS_TABSTOP,12,66,286,8 + GROUPBOX "Connection settings",IDC_STATIC,4,94,302,136 + LTEXT "Login Server:",IDC_STATIC,12,108,55,8 + EDITTEXT IDC_ICQSERVER,68,106,106,12,ES_AUTOHSCROLL + LTEXT "Port:",IDC_STATIC,182,108,25,8 + EDITTEXT IDC_ICQPORT,208,106,29,12,ES_AUTOHSCROLL + PUSHBUTTON "Default",IDC_RESETSERVER,244,106,50,12 + LTEXT "Hint: Use port 0 to connect on a random port. Try port 80 or port 443 if you are having problems connecting through a http proxy server.",IDC_STATIC,12,123,286,19 + CONTROL "Secure Connection (SSL)",IDC_SSL,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,12,143,286,10 + CONTROL "Secure (MD5) login",IDC_MD5LOGIN,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,12,154,286,10 + CONTROL "Send 'Keep-alives' (enable this if you use a proxy server and frequently get disconnected)",IDC_KEEPALIVE, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,166,286,18 + CONTROL "Ignore concurrent error messages",IDC_NOERRMULTI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,190,286,10 + LTEXT "Show connection error messages:",IDC_STATIC,12,204,238,8 + CONTROL "Slider1",IDC_LOGLEVEL,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,18,214,52,10 + LTEXT "",IDC_LEVELDESCR,72,214,226,8,SS_NOPREFIX +END + +IDD_OPT_ICQCONTACTS DIALOGEX 0, 0, 310, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "ICQ contacts stored on server",IDC_STICQGROUP,4,0,302,97 + PUSHBUTTON "Manage server's list...",IDC_UPLOADNOW,12,77,97,14 + CONTROL "Enable server-side contact lists *",IDC_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,15,288,10 + CONTROL "Add contacts to the server's list when I add them to mine",IDC_ADDSERVER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,33,288,10 + CONTROL "Update my contacts' details from the server *",IDC_LOADFROMSERVER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,46,288,10 + CONTROL "Update contacts' details on the server's list when I change them in mine",IDC_SAVETOSERVER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,59,290,10 + GROUPBOX "ICQ avatars",IDC_STATIC,4,98,302,70 + CONTROL "Enable avatar support",IDC_ENABLEAVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,110,288,10 + CONTROL "Check avatar validity before saving *",IDC_STRICTAVATARCHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,124,288,10 + CONTROL "Load avatars automatically (like ICQ Lite)",IDC_AUTOLOADAVATARS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,138,288,10 + LTEXT "You will need to reconnect to the ICQ network for the changes you have made on this page to take effect.",IDC_RECONNECTREQD,10,172,290,16,NOT WS_VISIBLE + LTEXT "You cannot enable/disable the server-side contact list while you are connected to the ICQ network.",IDC_OFFLINETOENABLE,10,192,290,16,NOT WS_VISIBLE + CTEXT "Note: The options marked with an asterisk have important side-effects or caveats that may not be initially apparent documented in the help.",IDC_STATIC,10,212,290,16 +END + +IDD_OPT_ICQFEATURES DIALOGEX 0, 0, 310, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Messaging",IDC_STATIC,4,0,302,94 + CONTROL "Enable unicode messaging support",IDC_UTFENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,12,288,10 + CONTROL "Send all messages in unicode if possible",IDC_UTFALL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,24,288,10 + RTEXT "Use this codepage for Ansi <-> Unicode translation :",IDC_UTFSTATIC,12,38,174,10 + COMBOBOX IDC_UTFCODEPAGE,190,36,107,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Make me temporarily visible to contacts I send message to",IDC_TEMPVISIBLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,53,288,10 + CONTROL "Notify me when a message delivery has failed (recommended)",IDC_SLOWSEND, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,288,10 + CONTROL "Never use legacy messaging (server acknowledgements)",IDC_ONLYSERVERACKS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,77,288,10 + GROUPBOX "Peer-to-peer Messaging",IDC_STATIC,4,95,302,41 + CONTROL "Enable peer-to-peer message connections",IDC_DCENABLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,107,288,10 + CONTROL "Passive mode, i.e. do not initiate new connections",IDC_DCPASSIVE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,119,288,10 + GROUPBOX "Extra Features",IDC_STATIC,4,137,302,93 + CONTROL "Enable Custom status support for xtraz",IDC_XSTATUSENABLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,149,288,10 + CONTROL "Enable Custom status support for moods",IDC_MOODSENABLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,161,288,10 + CONTROL "Reset Custom status on status change",IDC_XSTATUSRESET, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,175,288,10 + CONTROL "Auto-retrieve Custom status details",IDC_XSTATUSAUTO, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,187,288,10 + CONTROL "Block known Spam Bots",IDC_KILLSPAMBOTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,201,288,10 + CONTROL "Enable AIM contacts support",IDC_AIMENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,215,288,10 +END + +IDD_OPT_ICQPRIVACY DIALOGEX 0, 0, 310, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Direct connections",IDC_STATIC_DC1,4,0,302,78 + LTEXT "Allowing direct connections will expose your IP address but may be necessary for some ICQ features to work properly.",IDC_STATIC_DC2,10,12,292,17 + CONTROL "Allow direct connections with any user",IDC_DCALLOW_ANY, + "Button",BS_AUTORADIOBUTTON,21,34,281,10 + CONTROL "Allow direct connections with users on my contact list",IDC_DCALLOW_CLIST, + "Button",BS_AUTORADIOBUTTON,21,47,281,10 + CONTROL "Allow direct connections only when I authorize or initiate them",IDC_DCALLOW_AUTH, + "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,21,60,281,10 + GROUPBOX "Contact List Authorization",IDC_STATIC_CLIST,4,83,302,45,WS_GROUP + CONTROL "All users may add me to their Contact List",IDC_ADD_ANY, + "Button",BS_AUTORADIOBUTTON,21,97,281,10 + CONTROL "I want to be asked when someone wants to add me to their Contact List",IDC_ADD_AUTH, + "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,21,111,281,10 + GROUPBOX "Misc Settings",IDC_STATIC,4,131,302,78 + CONTROL "Allow others to view my Online / Offline status from the web (Web Aware)",IDC_WEBAWARE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,144,281,10 + CONTROL "Allow others to view my primary e-mail address",IDC_PUBLISHPRIMARY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,160,281,10 + CONTROL "Only reply to status message requests from users on my contact list",IDC_STATUSMSG_CLIST, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,176,281,10 + CONTROL "Only reply to status message request from visible contacts",IDC_STATUSMSG_VISIBLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,192,269,10 + CTEXT "Some options are greyed out because they can only be changed when you are online.",IDC_STATIC_NOTONLINE,4,215,302,8 +END + +IDD_OPT_POPUPS DIALOGEX 0, 0, 314, 251 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Options",IDC_STATIC,4,4,305,71 + CONTROL "Enable popup support",IDC_POPUPS_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,19,216,10 + CONTROL "Display errors using popups",IDC_POPUPS_LOG_ENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,37,216,10 + CONTROL "Display popup when spambot is detected",IDC_POPUPS_SPAM_ENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,50,216,10 + GROUPBOX "Look && Feel",IDC_STATIC,4,80,305,160 + LTEXT "Back Color",IDC_STATIC,80,93,42,8 + LTEXT "Text Color",IDC_STATIC,130,93,40,8 + LTEXT "Timeout (*)",IDC_STATIC,182,93,60,8 + LTEXT "Note",IDC_STATIC,12,105,60,8 + CONTROL "",IDC_POPUP_LOG0_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,104,39,10 + CONTROL "",IDC_POPUP_LOG0_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,104,39,10 + EDITTEXT IDC_POPUP_LOG0_TIMEOUT,182,103,34,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Warning",IDC_STATIC,12,120,60,8 + CONTROL "",IDC_POPUP_LOG1_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,119,39,10 + CONTROL "",IDC_POPUP_LOG1_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,119,39,10 + EDITTEXT IDC_POPUP_LOG1_TIMEOUT,182,118,34,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Error",IDC_STATIC,12,135,60,8 + CONTROL "",IDC_POPUP_LOG2_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,134,39,10 + CONTROL "",IDC_POPUP_LOG2_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,134,39,10 + EDITTEXT IDC_POPUP_LOG2_TIMEOUT,182,133,34,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Fatal",IDC_STATIC,12,150,60,8 + CONTROL "",IDC_POPUP_LOG3_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,149,39,10 + CONTROL "",IDC_POPUP_LOG3_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,149,39,10 + EDITTEXT IDC_POPUP_LOG3_TIMEOUT,182,148,34,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Spam detected",IDC_STATIC,12,165,60,8 + CONTROL "",IDC_POPUP_SPAM_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,164,39,10 + CONTROL "",IDC_POPUP_SPAM_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,164,39,10 + EDITTEXT IDC_POPUP_SPAM_TIMEOUT,182,163,34,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "&Use Windows colors",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,183,220,8 + CONTROL "Use system &icons",IDC_USESYSICONS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,211,220,8 + DEFPUSHBUTTON "Previe&w",IDC_PREVIEW,247,192,52,12 + LTEXT "(*) Timeouts require Popup v. 1.0.1.9 or later",IDC_STATIC,12,225,232,8 + CONTROL "Use default colours",IDC_USEDEFCOLORS,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,196,221,10 +END + +IDD_INFO_ICQ DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "UIN:",IDC_UINSTATIC,5,5,71,8 + EDITTEXT IDC_UIN,74,5,143,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "External IP:",IDC_STATIC,5,18,71,8 + EDITTEXT IDC_IP,74,18,74,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Internal IP:",IDC_STATIC,5,31,71,8 + EDITTEXT IDC_REALIP,74,31,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Port:",IDC_STATIC,5,44,71,8 + EDITTEXT IDC_PORT,74,44,141,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Protocol Version:",IDC_STATIC,5,57,71,8 + EDITTEXT IDC_VERSION,74,57,142,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "User Client:",IDC_STATIC,5,70,71,8 + EDITTEXT IDC_MIRVER,74,70,141,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Online since:",IDC_STATIC,5,83,71,8 + EDITTEXT IDC_ONLINESINCE,74,83,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "System up since:",IDC_SUPTIME,5,96,71,8 + EDITTEXT IDC_SYSTEMUPTIME,74,96,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Idle since:",IDC_STATIC,5,109,71,8 + EDITTEXT IDC_IDLETIME,74,109,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Status:",IDC_STATIC,5,122,71,8 + EDITTEXT IDC_STATUS,74,122,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER +END + +IDD_ICQADVANCEDSEARCH DIALOGEX 0, 0, 335, 247 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Summary",IDC_SUMMARYGROUP,8,3,156,131 + LTEXT "Nickname:",IDC_STATIC,15,14,50,8 + EDITTEXT IDC_NICK,65,12,91,12,ES_AUTOHSCROLL + LTEXT "First name:",IDC_STATIC,15,29,50,8 + EDITTEXT IDC_FIRSTNAME,65,27,91,12,ES_AUTOHSCROLL + LTEXT "Last name:",IDC_STATIC,15,44,50,8 + EDITTEXT IDC_LASTNAME,65,42,91,12,ES_AUTOHSCROLL + LTEXT "E-mail:",IDC_STATIC,15,59,50,8 + EDITTEXT IDC_EMAIL,65,57,91,12,ES_AUTOHSCROLL + LTEXT "Gender:",IDC_STATIC,15,74,50,8 + COMBOBOX IDC_GENDER,65,72,91,51,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Age:",IDC_STATIC,15,89,50,8 + COMBOBOX IDC_AGERANGE,65,87,91,90,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Marital status:",IDC_STATIC,15,104,50,8 + COMBOBOX IDC_MARITALSTATUS,65,102,91,90,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Keywords:",IDC_STATIC,15,119,50,8 + EDITTEXT IDC_KEYWORDS,65,117,91,12,ES_AUTOHSCROLL + GROUPBOX "Work",IDC_WORKGROUP,8,138,156,102 + LTEXT "Occupation:",IDC_STATIC,15,149,50,8 + COMBOBOX IDC_WORKFIELD,65,147,91,93,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Company:",IDC_STATIC,15,164,50,8 + EDITTEXT IDC_COMPANY,65,162,91,12,ES_AUTOHSCROLL + LTEXT "Department:",IDC_STATIC,15,179,50,8 + EDITTEXT IDC_DEPARTMENT,65,177,91,12,ES_AUTOHSCROLL + LTEXT "Position:",IDC_STATIC,15,194,50,8 + EDITTEXT IDC_POSITION,65,192,91,12,ES_AUTOHSCROLL + LTEXT "Organisation:",IDC_STATIC,15,209,50,8 + COMBOBOX IDC_ORGANISATION,65,207,91,99,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Keywords:",IDC_STATIC,24,224,41,8 + EDITTEXT IDC_ORGKEYWORDS,65,222,91,12,ES_AUTOHSCROLL + GROUPBOX "Location",IDC_LOCATIONGROUP,171,3,156,72 + LTEXT "Language:",IDC_STATIC,178,14,50,8 + COMBOBOX IDC_LANGUAGE,228,12,91,113,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Country:",IDC_STATIC,178,29,50,8 + COMBOBOX IDC_COUNTRY,228,27,91,172,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "State:",IDC_STATIC,178,44,50,8 + EDITTEXT IDC_STATE,228,42,91,12,ES_AUTOHSCROLL + LTEXT "City:",IDC_STATIC,178,59,50,8 + EDITTEXT IDC_CITY,228,57,91,12,ES_AUTOHSCROLL + GROUPBOX "Background info",IDC_BACKGROUNDGROUP,171,79,156,116 + LTEXT "Interests",IDC_STATIC,178,90,50,8 + LTEXT "Category:",IDC_STATIC,188,101,40,8 + COMBOBOX IDC_INTERESTSCAT,228,99,91,95,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Keywords:",IDC_STATIC,188,116,40,8 + EDITTEXT IDC_INTERESTSKEY,228,114,91,12,ES_AUTOHSCROLL + LTEXT "Past",IDC_STATIC,178,129,50,8 + LTEXT "Category:",IDC_STATIC,188,140,40,8 + COMBOBOX IDC_PASTCAT,228,138,91,97,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Keywords:",IDC_STATIC,188,155,40,8 + EDITTEXT IDC_PASTKEY,228,153,91,12,ES_AUTOHSCROLL + LTEXT "Homepage",IDC_STATIC,178,168,50,8 + LTEXT "Category:",IDC_STATIC,188,179,40,8,NOT WS_VISIBLE + COMBOBOX IDC_HOMEPAGECAT,228,177,91,56,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + LTEXT "Keywords:",IDC_STATIC,188,179,40,8 + EDITTEXT IDC_HOMEPAGEKEY,228,177,91,12,ES_AUTOHSCROLL + GROUPBOX "Other",IDC_OTHERGROUP,171,199,156,41 + CONTROL "Search online users only",IDC_ONLINEONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,178,217,142,10 +END + +IDD_ICQUPLOADLIST DIALOGEX 0, 0, 358, 241 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Manage ICQ Server Contacts" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Select contacts to store:",IDC_STATIC11,5,5,91,8 + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x2c9,5,14,155,222,WS_EX_CLIENTEDGE + DEFPUSHBUTTON "Synchronize",IDOK,226,222,68,14 + PUSHBUTTON "Cancel",IDCANCEL,298,222,55,14 + LISTBOX IDC_LOG,169,5,184,213,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP +END + +IDD_SETXSTATUS DIALOGEX 0, 0, 189, 98 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Custom Status ""%s"" Details" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Closing in %d",IDOK,62,79,65,14 + LTEXT "Title:",IDC_XTITLE_STATIC,5,0,179,8 + EDITTEXT IDC_XTITLE,5,9,179,13,ES_AUTOHSCROLL + LTEXT "Message:",IDC_XMSG_STATIC,5,22,179,8 + EDITTEXT IDC_XMSG,5,31,179,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + CTEXT "Retrieving custom status details...",IDC_RETRXSTATUS,5,0,179,75,SS_CENTERIMAGE | NOT WS_VISIBLE +END + +IDD_INFO_CHANGEINFO DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,2,218,113 + PUSHBUTTON "&Save changes",IDC_SAVE,140,117,80,13,WS_DISABLED + EDITTEXT IDC_UPLOADING,2,118,127,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER +END + +IDD_PWCONFIRM DIALOGEX 0, 0, 167, 78 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Confirm Password Change" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Please re-type your new password:",IDC_STATIC,5,5,157,9 + EDITTEXT IDC_PASSWORD,5,15,157,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Enter your current password:",IDC_STATIC,5,32,157,9 + EDITTEXT IDC_OLDPASS,5,42,157,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,26,59,50,14 + PUSHBUTTON "Cancel",IDCANCEL,91,59,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ICQACCOUNT, DIALOG + BEGIN + LEFTMARGIN, 7 + TOPMARGIN, 7 + END + + IDD_ASKAUTH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_LOGINPW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 149 + TOPMARGIN, 7 + BOTTOMMARGIN, 80 + END + + IDD_OPT_ICQ, DIALOG + BEGIN + LEFTMARGIN, 4 + VERTGUIDE, 12 + VERTGUIDE, 174 + VERTGUIDE, 302 + TOPMARGIN, 4 + HORZGUIDE, 120 + END + + IDD_OPT_ICQCONTACTS, DIALOG + BEGIN + LEFTMARGIN, 4 + VERTGUIDE, 12 + VERTGUIDE, 302 + TOPMARGIN, 4 + BOTTOMMARGIN, 232 + END + + IDD_OPT_ICQFEATURES, DIALOG + BEGIN + LEFTMARGIN, 4 + VERTGUIDE, 12 + TOPMARGIN, 7 + END + + IDD_OPT_ICQPRIVACY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 307 + TOPMARGIN, 7 + BOTTOMMARGIN, 233 + END + + IDD_OPT_POPUPS, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 309 + VERTGUIDE, 12 + VERTGUIDE, 80 + VERTGUIDE, 130 + VERTGUIDE, 182 + TOPMARGIN, 4 + HORZGUIDE, 19 + HORZGUIDE, 37 + HORZGUIDE, 104 + HORZGUIDE, 203 + END + + IDD_INFO_ICQ, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 217 + VERTGUIDE, 61 + TOPMARGIN, 5 + BOTTOMMARGIN, 129 + HORZGUIDE, 22 + HORZGUIDE, 35 + HORZGUIDE, 48 + HORZGUIDE, 61 + HORZGUIDE, 74 + END + + IDD_ICQADVANCEDSEARCH, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 327 + VERTGUIDE, 15 + VERTGUIDE, 25 + VERTGUIDE, 65 + VERTGUIDE, 156 + VERTGUIDE, 178 + VERTGUIDE, 228 + VERTGUIDE, 319 + TOPMARGIN, 5 + BOTTOMMARGIN, 239 + END + + IDD_ICQUPLOADLIST, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 353 + TOPMARGIN, 5 + BOTTOMMARGIN, 236 + END + + IDD_INFO_CHANGEINFO, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 220 + TOPMARGIN, 2 + BOTTOMMARGIN, 130 + END + + IDD_PWCONFIRM, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 162 + TOPMARGIN, 5 + BOTTOMMARGIN, 73 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" + "#include ""..\\src\\version.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004e4" + BEGIN + VALUE "Comments", "Licensed under the terms of the GNU General Public License" + VALUE "FileDescription", "ICQ protocol plugin for Miranda NG, enhanced" + VALUE "FileVersion", __VERSION_STRING + VALUE "InternalName", "ICQJ protocol plugin for Miranda NG" + VALUE "LegalCopyright", "Copyright (C) 2000-2010 Joe Kucera, Angeli-Ka, Bio, Martin Öberg, Richard Hughes, Jon Keating" + VALUE "OriginalFilename", "ICQ.dll" + VALUE "ProductName", "ICQ Protocol Support" + VALUE "ProductVersion", __VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/IcqOscarJ/res/srvlist_add.ico b/protocols/IcqOscarJ/res/srvlist_add.ico new file mode 100644 index 0000000000..18b12f8c38 Binary files /dev/null and b/protocols/IcqOscarJ/res/srvlist_add.ico differ diff --git a/protocols/IcqOscarJ/resource.h b/protocols/IcqOscarJ/resource.h deleted file mode 100644 index 2bdec69fe0..0000000000 --- a/protocols/IcqOscarJ/resource.h +++ /dev/null @@ -1,262 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by resources.rc -// -#define IDI_ICQ 101 -#define IDS_IDENTIFY 102 -#define IDD_ICQACCOUNT 103 -#define IDD_ASKAUTH 104 -#define IDD_LOGINPW 105 -#define IDD_OPT_ICQ 108 -#define IDD_OPT_ICQCONTACTS 109 -#define IDD_OPT_ICQFEATURES 110 -#define IDD_OPT_ICQPRIVACY 111 -#define IDI_AUTH_ASK 150 -#define IDI_AUTH_GRANT 151 -#define IDI_AUTH_REVOKE 152 -#define IDI_SERVLIST_ADD 160 -#define IDI_XSTATUS1 201 -#define IDI_XSTATUS2 202 -#define IDI_XSTATUS3 203 -#define IDI_XSTATUS4 204 -#define IDI_XSTATUS5 205 -#define IDI_XSTATUS6 206 -#define IDI_XSTATUS7 207 -#define IDI_XSTATUS8 208 -#define IDI_XSTATUS9 209 -#define IDI_XSTATUS10 210 -#define IDI_XSTATUS11 211 -#define IDI_XSTATUS12 212 -#define IDI_XSTATUS13 213 -#define IDI_XSTATUS14 214 -#define IDI_XSTATUS15 215 -#define IDI_XSTATUS16 216 -#define IDI_XSTATUS17 217 -#define IDI_XSTATUS18 218 -#define IDI_XSTATUS19 219 -#define IDI_XSTATUS20 220 -#define IDI_XSTATUS21 221 -#define IDI_XSTATUS22 222 -#define IDI_XSTATUS23 223 -#define IDI_XSTATUS24 224 -#define IDI_XSTATUS25 225 -#define IDI_XSTATUS26 226 -#define IDI_XSTATUS27 227 -#define IDI_XSTATUS28 228 -#define IDI_XSTATUS29 229 -#define IDI_XSTATUS30 230 -#define IDI_XSTATUS31 231 -#define IDI_XSTATUS32 232 -#define IDI_XSTATUS33 233 -#define IDI_XSTATUS34 234 -#define IDI_XSTATUS35 235 -#define IDI_XSTATUS36 236 -#define IDI_XSTATUS37 237 -#define IDI_XSTATUS38 238 -#define IDI_XSTATUS39 239 -#define IDI_XSTATUS40 240 -#define IDI_XSTATUS41 241 -#define IDI_XSTATUS42 242 -#define IDI_XSTATUS43 243 -#define IDI_XSTATUS44 244 -#define IDI_XSTATUS45 245 -#define IDI_XSTATUS46 246 -#define IDI_XSTATUS47 247 -#define IDI_XSTATUS48 248 -#define IDI_XSTATUS49 249 -#define IDI_XSTATUS50 250 -#define IDI_XSTATUS51 251 -#define IDI_XSTATUS52 252 -#define IDI_XSTATUS53 253 -#define IDI_XSTATUS54 254 -#define IDI_XSTATUS55 255 -#define IDI_XSTATUS56 256 -#define IDI_XSTATUS57 257 -#define IDI_XSTATUS58 258 -#define IDI_XSTATUS59 259 -#define IDI_XSTATUS60 260 -#define IDI_XSTATUS61 261 -#define IDI_XSTATUS62 262 -#define IDI_XSTATUS63 263 -#define IDI_XSTATUS64 264 -#define IDI_XSTATUS65 265 -#define IDI_XSTATUS66 266 -#define IDI_XSTATUS67 267 -#define IDI_XSTATUS68 268 -#define IDI_XSTATUS69 269 -#define IDI_XSTATUS70 270 -#define IDI_XSTATUS71 271 -#define IDI_XSTATUS72 272 -#define IDI_XSTATUS73 273 -#define IDI_XSTATUS74 274 -#define IDI_XSTATUS75 275 -#define IDI_XSTATUS76 276 -#define IDI_XSTATUS77 277 -#define IDI_XSTATUS78 278 -#define IDI_XSTATUS79 279 -#define IDI_XSTATUS80 280 -#define IDI_XSTATUS81 281 -#define IDI_XSTATUS82 282 -#define IDI_XSTATUS83 283 -#define IDI_XSTATUS84 284 -#define IDI_XSTATUS85 285 -#define IDI_XSTATUS86 286 -#define IDD_INFO_ICQ 240 -#define IDD_ICQADVANCEDSEARCH 242 -#define IDD_ICQUPLOADLIST 253 -#define IDD_SETXSTATUS 256 -#define IDD_PWCONFIRM 300 -#define IDD_INFO_CHANGEINFO 301 -#define IDD_OPT_POPUPS 400 -#define IDC_POPUPS_ENABLED 410 -#define IDC_POPUPS_LOG_ENABLED 411 -#define IDC_POPUPS_SPAM_ENABLED 412 -#define IDC_POPUP_LOG0_TEXTCOLOR 420 -#define IDC_POPUP_LOG1_TEXTCOLOR 421 -#define IDC_POPUP_LOG2_TEXTCOLOR 422 -#define IDC_POPUP_LOG3_TEXTCOLOR 423 -#define IDC_POPUP_SPAM_TEXTCOLOR 425 -#define IDC_POPUP_LOG0_BACKCOLOR 430 -#define IDC_POPUP_LOG1_BACKCOLOR 431 -#define IDC_POPUP_LOG2_BACKCOLOR 432 -#define IDC_POPUP_LOG3_BACKCOLOR 433 -#define IDC_POPUP_SPAM_BACKCOLOR 435 -#define IDC_POPUP_LOG0_TIMEOUT 440 -#define IDC_POPUP_LOG1_TIMEOUT 441 -#define IDC_POPUP_LOG2_TIMEOUT 442 -#define IDC_POPUP_LOG3_TIMEOUT 443 -#define IDC_POPUP_SPAM_TIMEOUT 444 -#define IDC_USEWINCOLORS 450 -#define IDC_USESYSICONS 451 -#define IDC_PREVIEW 455 -#define IDC_LOG 1001 -#define IDI_EXPANDSTRINGEDIT 1001 -#define IDC_SAVEPASS 1004 -#define IDC_RETRXSTATUS 1005 -#define IDC_XTITLE_STATIC 1006 -#define IDC_XMSG_STATIC 1007 -#define IDC_SSL 1008 -#define IDC_MD5LOGIN 1009 -#define IDC_UTFENABLE 1010 -#define IDC_XTITLE 1010 -#define IDC_KEEPALIVE 1011 -#define IDC_XMSG 1011 -#define IDC_UTFALL 1012 -#define IDC_UTFSTATIC 1013 -#define IDC_UTFCODEPAGE 1014 -#define IDC_PW 1015 -#define IDC_TEMPVISIBLE 1015 -#define IDC_REGISTER 1016 -#define IDC_EDITAUTH 1017 -#define IDC_LOGINPW 1018 -#define IDC_INSTRUCTION 1019 -#define IDC_PASSWORD 1020 -#define IDC_SUPTIME 1020 -#define IDC_DCENABLE 1020 -#define IDC_DCPASSIVE 1021 -#define IDC_OLDPASS 1021 -#define IDC_ICQNUM 1022 -#define IDC_USEPOPUPCOLORS 1023 -#define IDC_USEDEFCOLORS 1024 -#define IDC_AIMENABLE 1030 -#define IDC_CLIST 1035 -#define IDC_XSTATUSENABLE 1040 -#define IDC_XSTATUSAUTO 1041 -#define IDC_XSTATUSRESET 1042 -#define IDC_MOODSENABLE 1043 -#define IDC_KILLSPAMBOTS 1045 -#define IDC_EMAIL 1048 -#define IDC_NICK 1053 -#define IDC_GENDER 1060 -#define IDC_CITY 1061 -#define IDC_STATE 1062 -#define IDC_COUNTRY 1063 -#define IDC_COMPANY 1066 -#define IDC_DEPARTMENT 1067 -#define IDC_POSITION 1069 -#define IDC_IP 1094 -#define IDC_UINSTATIC 1122 -#define IDC_UIN 1123 -#define IDC_STATIC11 1154 -#define IDC_STATIC12 1155 -#define IDC_ICQSERVER 1171 -#define IDC_ICQPORT 1172 -#define IDC_VERSION 1179 -#define IDC_FIRSTNAME 1224 -#define IDC_LASTNAME 1225 -#define IDC_REALIP 1230 -#define IDC_RECONNECTREQD 1239 -#define IDC_OFFLINETOENABLE 1240 -#define IDC_PORT 1249 -#define IDC_MIRVER 1251 -#define IDC_ONLINESINCE 1252 -#define IDC_SYSTEMUPTIME 1253 -#define IDC_IDLETIME 1254 -#define IDC_STATUS 1255 -#define IDC_SLOWSEND 1301 -#define IDC_ONLYSERVERACKS 1302 -#define IDC_LOGLEVEL 1331 -#define IDC_LEVELDESCR 1332 -#define IDC_NOERRMULTI 1333 -#define IDC_STICQGROUP 1374 -#define IDC_AGERANGE 1410 -#define IDC_MARITALSTATUS 1411 -#define IDC_KEYWORDS 1412 -#define IDC_LANGUAGE 1414 -#define IDC_WORKFIELD 1421 -#define IDC_PASTCAT 1422 -#define IDC_PASTKEY 1423 -#define IDC_INTERESTSCAT 1424 -#define IDC_INTERESTSKEY 1425 -#define IDC_ORGANISATION 1426 -#define IDC_ORGKEYWORDS 1427 -#define IDC_OTHERGROUP 1429 -#define IDC_ONLINEONLY 1430 -#define IDC_HOMEPAGECAT 1431 -#define IDC_HOMEPAGEKEY 1432 -#define IDC_SUMMARYGROUP 1434 -#define IDC_WORKGROUP 1435 -#define IDC_LOCATIONGROUP 1436 -#define IDC_BACKGROUNDGROUP 1437 -#define IDC_NEWUINLINK 1438 -#define IDC_LOOKUPLINK 1439 -#define IDC_RESETSERVER 1472 -#define IDC_UPLOADNOW 1521 -#define IDC_GROUPS 1522 -#define IDC_ALLGROUPS 1526 -#define IDC_VISIBILITY 1527 -#define IDC_IGNORE 1528 -#define IDC_ENABLE 1529 -#define IDC_LOADFROMSERVER 1530 -#define IDC_ADDSERVER 1532 -#define IDC_SAVETOSERVER 1533 -#define IDC_ENABLEAVATARS 1536 -#define IDC_AUTOLOADAVATARS 1537 -#define IDC_STRICTAVATARCHECK 1539 -#define IDC_WEBAWARE 1546 -#define IDC_DCALLOW_ANY 1547 -#define IDC_DCALLOW_CLIST 1548 -#define IDC_DCALLOW_AUTH 1549 -#define IDC_PUBLISHPRIMARY 1550 -#define IDC_ADD_ANY 1551 -#define IDC_ADD_AUTH 1552 -#define IDC_STATUSMSG_CLIST 1553 -#define IDC_STATUSMSG_VISIBLE 1554 -#define IDC_STATIC_NOTONLINE 1555 -#define IDC_STATIC_DC2 1556 -#define IDC_STATIC_DC1 1557 -#define IDC_STATIC_CLIST 1558 -#define IDC_SAVE 1600 -#define IDC_LIST 1601 -#define IDC_UPLOADING 1602 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 113 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1026 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/protocols/IcqOscarJ/resources.rc b/protocols/IcqOscarJ/resources.rc deleted file mode 100644 index 563f6eeb5e..0000000000 --- a/protocols/IcqOscarJ/resources.rc +++ /dev/null @@ -1,595 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -#include "version.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICQ ICON "icos/icq.ico" -IDI_AUTH_ASK ICON "icos/auth_ask.ico" -IDI_AUTH_GRANT ICON "icos/auth_grant.ico" -IDI_AUTH_REVOKE ICON "icos/auth_revoke.ico" -IDI_SERVLIST_ADD ICON "icos/srvlist_add.ico" -IDI_EXPANDSTRINGEDIT ICON "changeinfo/expandst.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ICQACCOUNT DIALOGEX 0, 0, 186, 68 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "ICQ Number:",IDC_STATIC,0,0,53,12 - EDITTEXT IDC_UIN,54,0,131,12,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,0,16,53,12 - EDITTEXT IDC_PW,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Create a new ICQ account",IDC_REGISTER,"Hyperlink",WS_TABSTOP,0,49,174,12 -END - -IDD_ASKAUTH DIALOGEX 0, 0, 186, 95 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter an authorization request" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "&Send",IDOK,34,74,50,14 - PUSHBUTTON "&Cancel",IDCANCEL,98,74,50,14 - EDITTEXT IDC_EDITAUTH,7,7,172,59,ES_AUTOHSCROLL -END - -IDD_LOGINPW DIALOGEX 0, 0, 157, 87 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter ICQ Password" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Enter a password for UIN %d:",IDC_INSTRUCTION,7,7,142,8 - EDITTEXT IDC_LOGINPW,17,16,122,14,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Remember this session password",IDC_SAVEPASS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,54,120,10 - DEFPUSHBUTTON "OK",IDOK,24,66,50,14 - PUSHBUTTON "Cancel",IDCANCEL,84,66,50,14 -END - -IDD_OPT_ICQ DIALOGEX 0, 0, 310, 234 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "ICQ",IDC_STICQGROUP,4,0,302,93 - RTEXT "ICQ number:",IDC_STATIC11,12,14,51,8 - EDITTEXT IDC_ICQNUM,68,12,106,12,ES_AUTOHSCROLL - RTEXT "Password:",IDC_STATIC12,12,28,51,8 - EDITTEXT IDC_PASSWORD,68,26,106,12,ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "Hint: If you don't enter your password here, Miranda will ask for the password everytime you try to go online.",IDC_STATIC,12,43,286,19 - CONTROL "Retrieve a lost password or ICQ number",IDC_LOOKUPLINK, - "Hyperlink",WS_TABSTOP,12,78,286,8 - CONTROL "Create a new ICQ account using the ICQ website",IDC_NEWUINLINK, - "Hyperlink",WS_TABSTOP,12,66,286,8 - GROUPBOX "Connection settings",IDC_STATIC,4,94,302,136 - LTEXT "Login Server:",IDC_STATIC,12,108,55,8 - EDITTEXT IDC_ICQSERVER,68,106,106,12,ES_AUTOHSCROLL - LTEXT "Port:",IDC_STATIC,182,108,25,8 - EDITTEXT IDC_ICQPORT,208,106,29,12,ES_AUTOHSCROLL - PUSHBUTTON "Default",IDC_RESETSERVER,244,106,50,12 - LTEXT "Hint: Use port 0 to connect on a random port. Try port 80 or port 443 if you are having problems connecting through a http proxy server.",IDC_STATIC,12,123,286,19 - CONTROL "Secure Connection (SSL)",IDC_SSL,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,12,143,286,10 - CONTROL "Secure (MD5) login",IDC_MD5LOGIN,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,12,154,286,10 - CONTROL "Send 'Keep-alives' (enable this if you use a proxy server and frequently get disconnected)",IDC_KEEPALIVE, - "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,166,286,18 - CONTROL "Ignore concurrent error messages",IDC_NOERRMULTI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,190,286,10 - LTEXT "Show connection error messages:",IDC_STATIC,12,204,238,8 - CONTROL "Slider1",IDC_LOGLEVEL,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,18,214,52,10 - LTEXT "",IDC_LEVELDESCR,72,214,226,8,SS_NOPREFIX -END - -IDD_OPT_ICQCONTACTS DIALOGEX 0, 0, 310, 234 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "ICQ contacts stored on server",IDC_STICQGROUP,4,0,302,97 - PUSHBUTTON "Manage server's list...",IDC_UPLOADNOW,12,77,97,14 - CONTROL "Enable server-side contact lists *",IDC_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,15,288,10 - CONTROL "Add contacts to the server's list when I add them to mine",IDC_ADDSERVER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,33,288,10 - CONTROL "Update my contacts' details from the server *",IDC_LOADFROMSERVER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,46,288,10 - CONTROL "Update contacts' details on the server's list when I change them in mine",IDC_SAVETOSERVER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,59,290,10 - GROUPBOX "ICQ avatars",IDC_STATIC,4,98,302,70 - CONTROL "Enable avatar support",IDC_ENABLEAVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,110,288,10 - CONTROL "Check avatar validity before saving *",IDC_STRICTAVATARCHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,124,288,10 - CONTROL "Load avatars automatically (like ICQ Lite)",IDC_AUTOLOADAVATARS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,138,288,10 - LTEXT "You will need to reconnect to the ICQ network for the changes you have made on this page to take effect.",IDC_RECONNECTREQD,10,172,290,16,NOT WS_VISIBLE - LTEXT "You cannot enable/disable the server-side contact list while you are connected to the ICQ network.",IDC_OFFLINETOENABLE,10,192,290,16,NOT WS_VISIBLE - CTEXT "Note: The options marked with an asterisk have important side-effects or caveats that may not be initially apparent documented in the help.",IDC_STATIC,10,212,290,16 -END - -IDD_OPT_ICQFEATURES DIALOGEX 0, 0, 310, 234 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Messaging",IDC_STATIC,4,0,302,94 - CONTROL "Enable unicode messaging support",IDC_UTFENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,12,288,10 - CONTROL "Send all messages in unicode if possible",IDC_UTFALL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,24,288,10 - RTEXT "Use this codepage for Ansi <-> Unicode translation :",IDC_UTFSTATIC,12,38,174,10 - COMBOBOX IDC_UTFCODEPAGE,190,36,107,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Make me temporarily visible to contacts I send message to",IDC_TEMPVISIBLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,53,288,10 - CONTROL "Notify me when a message delivery has failed (recommended)",IDC_SLOWSEND, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,288,10 - CONTROL "Never use legacy messaging (server acknowledgements)",IDC_ONLYSERVERACKS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,77,288,10 - GROUPBOX "Peer-to-peer Messaging",IDC_STATIC,4,95,302,41 - CONTROL "Enable peer-to-peer message connections",IDC_DCENABLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,107,288,10 - CONTROL "Passive mode, i.e. do not initiate new connections",IDC_DCPASSIVE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,119,288,10 - GROUPBOX "Extra Features",IDC_STATIC,4,137,302,93 - CONTROL "Enable Custom status support for xtraz",IDC_XSTATUSENABLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,149,288,10 - CONTROL "Enable Custom status support for moods",IDC_MOODSENABLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,161,288,10 - CONTROL "Reset Custom status on status change",IDC_XSTATUSRESET, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,175,288,10 - CONTROL "Auto-retrieve Custom status details",IDC_XSTATUSAUTO, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,187,288,10 - CONTROL "Block known Spam Bots",IDC_KILLSPAMBOTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,201,288,10 - CONTROL "Enable AIM contacts support",IDC_AIMENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,215,288,10 -END - -IDD_OPT_ICQPRIVACY DIALOGEX 0, 0, 310, 234 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Direct connections",IDC_STATIC_DC1,4,0,302,78 - LTEXT "Allowing direct connections will expose your IP address but may be necessary for some ICQ features to work properly.",IDC_STATIC_DC2,10,12,292,17 - CONTROL "Allow direct connections with any user",IDC_DCALLOW_ANY, - "Button",BS_AUTORADIOBUTTON,21,34,281,10 - CONTROL "Allow direct connections with users on my contact list",IDC_DCALLOW_CLIST, - "Button",BS_AUTORADIOBUTTON,21,47,281,10 - CONTROL "Allow direct connections only when I authorize or initiate them",IDC_DCALLOW_AUTH, - "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,21,60,281,10 - GROUPBOX "Contact List Authorization",IDC_STATIC_CLIST,4,83,302,45,WS_GROUP - CONTROL "All users may add me to their Contact List",IDC_ADD_ANY, - "Button",BS_AUTORADIOBUTTON,21,97,281,10 - CONTROL "I want to be asked when someone wants to add me to their Contact List",IDC_ADD_AUTH, - "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,21,111,281,10 - GROUPBOX "Misc Settings",IDC_STATIC,4,131,302,78 - CONTROL "Allow others to view my Online / Offline status from the web (Web Aware)",IDC_WEBAWARE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,144,281,10 - CONTROL "Allow others to view my primary e-mail address",IDC_PUBLISHPRIMARY, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,160,281,10 - CONTROL "Only reply to status message requests from users on my contact list",IDC_STATUSMSG_CLIST, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,176,281,10 - CONTROL "Only reply to status message request from visible contacts",IDC_STATUSMSG_VISIBLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,192,269,10 - CTEXT "Some options are greyed out because they can only be changed when you are online.",IDC_STATIC_NOTONLINE,4,215,302,8 -END - -IDD_OPT_POPUPS DIALOGEX 0, 0, 314, 251 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Options",IDC_STATIC,4,4,305,71 - CONTROL "Enable popup support",IDC_POPUPS_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,19,216,10 - CONTROL "Display errors using popups",IDC_POPUPS_LOG_ENABLED, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,37,216,10 - CONTROL "Display popup when spambot is detected",IDC_POPUPS_SPAM_ENABLED, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,50,216,10 - GROUPBOX "Look && Feel",IDC_STATIC,4,80,305,160 - LTEXT "Back Color",IDC_STATIC,80,93,42,8 - LTEXT "Text Color",IDC_STATIC,130,93,40,8 - LTEXT "Timeout (*)",IDC_STATIC,182,93,60,8 - LTEXT "Note",IDC_STATIC,12,105,60,8 - CONTROL "",IDC_POPUP_LOG0_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,104,39,10 - CONTROL "",IDC_POPUP_LOG0_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,104,39,10 - EDITTEXT IDC_POPUP_LOG0_TIMEOUT,182,103,34,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Warning",IDC_STATIC,12,120,60,8 - CONTROL "",IDC_POPUP_LOG1_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,119,39,10 - CONTROL "",IDC_POPUP_LOG1_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,119,39,10 - EDITTEXT IDC_POPUP_LOG1_TIMEOUT,182,118,34,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Error",IDC_STATIC,12,135,60,8 - CONTROL "",IDC_POPUP_LOG2_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,134,39,10 - CONTROL "",IDC_POPUP_LOG2_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,134,39,10 - EDITTEXT IDC_POPUP_LOG2_TIMEOUT,182,133,34,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Fatal",IDC_STATIC,12,150,60,8 - CONTROL "",IDC_POPUP_LOG3_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,149,39,10 - CONTROL "",IDC_POPUP_LOG3_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,149,39,10 - EDITTEXT IDC_POPUP_LOG3_TIMEOUT,182,148,34,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Spam detected",IDC_STATIC,12,165,60,8 - CONTROL "",IDC_POPUP_SPAM_BACKCOLOR,"ColourPicker",WS_TABSTOP,80,164,39,10 - CONTROL "",IDC_POPUP_SPAM_TEXTCOLOR,"ColourPicker",WS_TABSTOP,130,164,39,10 - EDITTEXT IDC_POPUP_SPAM_TIMEOUT,182,163,34,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "&Use Windows colors",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,183,220,8 - CONTROL "Use system &icons",IDC_USESYSICONS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,211,220,8 - DEFPUSHBUTTON "Previe&w",IDC_PREVIEW,247,192,52,12 - LTEXT "(*) Timeouts require Popup v. 1.0.1.9 or later",IDC_STATIC,12,225,232,8 - CONTROL "Use default colours",IDC_USEDEFCOLORS,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,196,221,10 -END - -IDD_INFO_ICQ DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "UIN:",IDC_UINSTATIC,5,5,71,8 - EDITTEXT IDC_UIN,74,5,143,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "External IP:",IDC_STATIC,5,18,71,8 - EDITTEXT IDC_IP,74,18,74,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Internal IP:",IDC_STATIC,5,31,71,8 - EDITTEXT IDC_REALIP,74,31,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Port:",IDC_STATIC,5,44,71,8 - EDITTEXT IDC_PORT,74,44,141,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Protocol Version:",IDC_STATIC,5,57,71,8 - EDITTEXT IDC_VERSION,74,57,142,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "User Client:",IDC_STATIC,5,70,71,8 - EDITTEXT IDC_MIRVER,74,70,141,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Online since:",IDC_STATIC,5,83,71,8 - EDITTEXT IDC_ONLINESINCE,74,83,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "System up since:",IDC_SUPTIME,5,96,71,8 - EDITTEXT IDC_SYSTEMUPTIME,74,96,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Idle since:",IDC_STATIC,5,109,71,8 - EDITTEXT IDC_IDLETIME,74,109,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Status:",IDC_STATIC,5,122,71,8 - EDITTEXT IDC_STATUS,74,122,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER -END - -IDD_ICQADVANCEDSEARCH DIALOGEX 0, 0, 335, 247 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_BORDER -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Summary",IDC_SUMMARYGROUP,8,3,156,131 - LTEXT "Nickname:",IDC_STATIC,15,14,50,8 - EDITTEXT IDC_NICK,65,12,91,12,ES_AUTOHSCROLL - LTEXT "First name:",IDC_STATIC,15,29,50,8 - EDITTEXT IDC_FIRSTNAME,65,27,91,12,ES_AUTOHSCROLL - LTEXT "Last name:",IDC_STATIC,15,44,50,8 - EDITTEXT IDC_LASTNAME,65,42,91,12,ES_AUTOHSCROLL - LTEXT "E-mail:",IDC_STATIC,15,59,50,8 - EDITTEXT IDC_EMAIL,65,57,91,12,ES_AUTOHSCROLL - LTEXT "Gender:",IDC_STATIC,15,74,50,8 - COMBOBOX IDC_GENDER,65,72,91,51,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Age:",IDC_STATIC,15,89,50,8 - COMBOBOX IDC_AGERANGE,65,87,91,90,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Marital status:",IDC_STATIC,15,104,50,8 - COMBOBOX IDC_MARITALSTATUS,65,102,91,90,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Keywords:",IDC_STATIC,15,119,50,8 - EDITTEXT IDC_KEYWORDS,65,117,91,12,ES_AUTOHSCROLL - GROUPBOX "Work",IDC_WORKGROUP,8,138,156,102 - LTEXT "Occupation:",IDC_STATIC,15,149,50,8 - COMBOBOX IDC_WORKFIELD,65,147,91,93,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Company:",IDC_STATIC,15,164,50,8 - EDITTEXT IDC_COMPANY,65,162,91,12,ES_AUTOHSCROLL - LTEXT "Department:",IDC_STATIC,15,179,50,8 - EDITTEXT IDC_DEPARTMENT,65,177,91,12,ES_AUTOHSCROLL - LTEXT "Position:",IDC_STATIC,15,194,50,8 - EDITTEXT IDC_POSITION,65,192,91,12,ES_AUTOHSCROLL - LTEXT "Organisation:",IDC_STATIC,15,209,50,8 - COMBOBOX IDC_ORGANISATION,65,207,91,99,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Keywords:",IDC_STATIC,24,224,41,8 - EDITTEXT IDC_ORGKEYWORDS,65,222,91,12,ES_AUTOHSCROLL - GROUPBOX "Location",IDC_LOCATIONGROUP,171,3,156,72 - LTEXT "Language:",IDC_STATIC,178,14,50,8 - COMBOBOX IDC_LANGUAGE,228,12,91,113,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Country:",IDC_STATIC,178,29,50,8 - COMBOBOX IDC_COUNTRY,228,27,91,172,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "State:",IDC_STATIC,178,44,50,8 - EDITTEXT IDC_STATE,228,42,91,12,ES_AUTOHSCROLL - LTEXT "City:",IDC_STATIC,178,59,50,8 - EDITTEXT IDC_CITY,228,57,91,12,ES_AUTOHSCROLL - GROUPBOX "Background info",IDC_BACKGROUNDGROUP,171,79,156,116 - LTEXT "Interests",IDC_STATIC,178,90,50,8 - LTEXT "Category:",IDC_STATIC,188,101,40,8 - COMBOBOX IDC_INTERESTSCAT,228,99,91,95,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Keywords:",IDC_STATIC,188,116,40,8 - EDITTEXT IDC_INTERESTSKEY,228,114,91,12,ES_AUTOHSCROLL - LTEXT "Past",IDC_STATIC,178,129,50,8 - LTEXT "Category:",IDC_STATIC,188,140,40,8 - COMBOBOX IDC_PASTCAT,228,138,91,97,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Keywords:",IDC_STATIC,188,155,40,8 - EDITTEXT IDC_PASTKEY,228,153,91,12,ES_AUTOHSCROLL - LTEXT "Homepage",IDC_STATIC,178,168,50,8 - LTEXT "Category:",IDC_STATIC,188,179,40,8,NOT WS_VISIBLE - COMBOBOX IDC_HOMEPAGECAT,228,177,91,56,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - LTEXT "Keywords:",IDC_STATIC,188,179,40,8 - EDITTEXT IDC_HOMEPAGEKEY,228,177,91,12,ES_AUTOHSCROLL - GROUPBOX "Other",IDC_OTHERGROUP,171,199,156,41 - CONTROL "Search online users only",IDC_ONLINEONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,178,217,142,10 -END - -IDD_ICQUPLOADLIST DIALOGEX 0, 0, 358, 241 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Manage ICQ Server Contacts" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Select contacts to store:",IDC_STATIC11,5,5,91,8 - CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x2c9,5,14,155,222,WS_EX_CLIENTEDGE - DEFPUSHBUTTON "Synchronize",IDOK,226,222,68,14 - PUSHBUTTON "Cancel",IDCANCEL,298,222,55,14 - LISTBOX IDC_LOG,169,5,184,213,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP -END - -IDD_SETXSTATUS DIALOGEX 0, 0, 189, 98 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Custom Status ""%s"" Details" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Closing in %d",IDOK,62,79,65,14 - LTEXT "Title:",IDC_XTITLE_STATIC,5,0,179,8 - EDITTEXT IDC_XTITLE,5,9,179,13,ES_AUTOHSCROLL - LTEXT "Message:",IDC_XMSG_STATIC,5,22,179,8 - EDITTEXT IDC_XMSG,5,31,179,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL - CTEXT "Retrieving custom status details...",IDC_RETRXSTATUS,5,0,179,75,SS_CENTERIMAGE | NOT WS_VISIBLE -END - -IDD_INFO_CHANGEINFO DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,2,218,113 - PUSHBUTTON "&Save changes",IDC_SAVE,140,117,80,13,WS_DISABLED - EDITTEXT IDC_UPLOADING,2,118,127,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER -END - -IDD_PWCONFIRM DIALOGEX 0, 0, 167, 78 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Confirm Password Change" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Please re-type your new password:",IDC_STATIC,5,5,157,9 - EDITTEXT IDC_PASSWORD,5,15,157,12,ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "Enter your current password:",IDC_STATIC,5,32,157,9 - EDITTEXT IDC_OLDPASS,5,42,157,12,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,26,59,50,14 - PUSHBUTTON "Cancel",IDCANCEL,91,59,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ICQACCOUNT, DIALOG - BEGIN - LEFTMARGIN, 7 - TOPMARGIN, 7 - END - - IDD_ASKAUTH, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 88 - END - - IDD_LOGINPW, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 149 - TOPMARGIN, 7 - BOTTOMMARGIN, 80 - END - - IDD_OPT_ICQ, DIALOG - BEGIN - LEFTMARGIN, 4 - VERTGUIDE, 12 - VERTGUIDE, 174 - VERTGUIDE, 302 - TOPMARGIN, 4 - HORZGUIDE, 120 - END - - IDD_OPT_ICQCONTACTS, DIALOG - BEGIN - LEFTMARGIN, 4 - VERTGUIDE, 12 - VERTGUIDE, 302 - TOPMARGIN, 4 - BOTTOMMARGIN, 232 - END - - IDD_OPT_ICQFEATURES, DIALOG - BEGIN - LEFTMARGIN, 4 - VERTGUIDE, 12 - TOPMARGIN, 7 - END - - IDD_OPT_ICQPRIVACY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 307 - TOPMARGIN, 7 - BOTTOMMARGIN, 233 - END - - IDD_OPT_POPUPS, DIALOG - BEGIN - LEFTMARGIN, 4 - RIGHTMARGIN, 309 - VERTGUIDE, 12 - VERTGUIDE, 80 - VERTGUIDE, 130 - VERTGUIDE, 182 - TOPMARGIN, 4 - HORZGUIDE, 19 - HORZGUIDE, 37 - HORZGUIDE, 104 - HORZGUIDE, 203 - END - - IDD_INFO_ICQ, DIALOG - BEGIN - LEFTMARGIN, 5 - RIGHTMARGIN, 217 - VERTGUIDE, 61 - TOPMARGIN, 5 - BOTTOMMARGIN, 129 - HORZGUIDE, 22 - HORZGUIDE, 35 - HORZGUIDE, 48 - HORZGUIDE, 61 - HORZGUIDE, 74 - END - - IDD_ICQADVANCEDSEARCH, DIALOG - BEGIN - LEFTMARGIN, 8 - RIGHTMARGIN, 327 - VERTGUIDE, 15 - VERTGUIDE, 25 - VERTGUIDE, 65 - VERTGUIDE, 156 - VERTGUIDE, 178 - VERTGUIDE, 228 - VERTGUIDE, 319 - TOPMARGIN, 5 - BOTTOMMARGIN, 239 - END - - IDD_ICQUPLOADLIST, DIALOG - BEGIN - LEFTMARGIN, 5 - RIGHTMARGIN, 353 - TOPMARGIN, 5 - BOTTOMMARGIN, 236 - END - - IDD_INFO_CHANGEINFO, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 220 - TOPMARGIN, 2 - BOTTOMMARGIN, 130 - END - - IDD_PWCONFIRM, DIALOG - BEGIN - LEFTMARGIN, 5 - RIGHTMARGIN, 162 - TOPMARGIN, 5 - BOTTOMMARGIN, 73 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" - "#include ""version.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION __FILEVERSION_STRING - PRODUCTVERSION __FILEVERSION_STRING - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004e4" - BEGIN - VALUE "Comments", "Licensed under the terms of the GNU General Public License" - VALUE "FileDescription", "ICQ protocol plugin for Miranda NG, enhanced" - VALUE "FileVersion", __VERSION_STRING - VALUE "InternalName", "ICQJ protocol plugin for Miranda NG" - VALUE "LegalCopyright", "Copyright (C) 2000-2010 Joe Kucera, Angeli-Ka, Bio, Martin Öberg, Richard Hughes, Jon Keating" - VALUE "OriginalFilename", "ICQ.dll" - VALUE "ProductName", "ICQ Protocol Support" - VALUE "ProductVersion", __VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/protocols/IcqOscarJ/src/UI/askauthentication.cpp b/protocols/IcqOscarJ/src/UI/askauthentication.cpp new file mode 100644 index 0000000000..818d5ce6de --- /dev/null +++ b/protocols/IcqOscarJ/src/UI/askauthentication.cpp @@ -0,0 +1,96 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +struct AskAuthParam +{ + CIcqProto* ppro; + HANDLE hContact; +}; + +static INT_PTR CALLBACK AskAuthProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + AskAuthParam* dat = (AskAuthParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + dat = (AskAuthParam*)lParam; + if (!dat->hContact || !dat->ppro->icqOnline()) + EndDialog(hwndDlg, 0); + + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + SendDlgItemMessage(hwndDlg, IDC_EDITAUTH, EM_LIMITTEXT, (WPARAM)255, 0); + SetDlgItemText(hwndDlg, IDC_EDITAUTH, TranslateT("Please authorize me to add you to my contact list.")); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (dat->ppro->icqOnline()) + { + DWORD dwUin; + uid_str szUid; + if ( dat->ppro->getContactUid(dat->hContact, &dwUin, &szUid)) + return TRUE; // Invalid contact + + char* szReason = GetDlgItemTextUtf(hwndDlg, IDC_EDITAUTH); + dat->ppro->icq_sendAuthReqServ(dwUin, szUid, szReason); + SAFE_FREE((void**)&szReason); + + // auth bug fix (thx Bio) + if (dat->ppro->m_bSsiEnabled && dwUin) + dat->ppro->resetServContactAuthState(dat->hContact, dwUin); + + EndDialog(hwndDlg, 0); + } + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + + break; + + case WM_CLOSE: + EndDialog(hwndDlg,0); + return TRUE; + } + + return FALSE; +} + +INT_PTR CIcqProto::RequestAuthorization(WPARAM wParam, LPARAM lParam) +{ + AskAuthParam param = { this, (HANDLE)wParam }; + DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ASKAUTH), NULL, AskAuthProc, (LPARAM)¶m); + return 0; +} diff --git a/protocols/IcqOscarJ/src/UI/icqoscar.h b/protocols/IcqOscarJ/src/UI/icqoscar.h new file mode 100644 index 0000000000..77283f6f7f --- /dev/null +++ b/protocols/IcqOscarJ/src/UI/icqoscar.h @@ -0,0 +1,2 @@ +/* For MinGW sake */ +#include "../icqoscar.h" diff --git a/protocols/IcqOscarJ/src/UI/loginpassword.cpp b/protocols/IcqOscarJ/src/UI/loginpassword.cpp new file mode 100644 index 0000000000..ab65212331 --- /dev/null +++ b/protocols/IcqOscarJ/src/UI/loginpassword.cpp @@ -0,0 +1,97 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +INT_PTR CALLBACK LoginPasswdDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ppro->m_hIconProtocol->GetIcon(true)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ppro->m_hIconProtocol->GetIcon()); + + DWORD dwUin = ppro->getContactUin(NULL); + + char pszUIN[MAX_PATH], str[MAX_PATH]; + null_snprintf(pszUIN, 128, ICQTranslateUtfStatic(LPGEN("Enter a password for UIN %u:"), str, MAX_PATH), dwUin); + SetDlgItemTextUtf(hwndDlg, IDC_INSTRUCTION, pszUIN); + + SendDlgItemMessage(hwndDlg, IDC_LOGINPW, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); + + CheckDlgButton(hwndDlg, IDC_SAVEPASS, ppro->getSettingByte(NULL, "RememberPass", 0)); + } + break; + + case WM_DESTROY: + ppro->m_hIconProtocol->ReleaseIcon(true); + ppro->m_hIconProtocol->ReleaseIcon(); + break; + + case WM_CLOSE: + EndDialog(hwndDlg, 0); + break; + + case WM_COMMAND: + { + switch (LOWORD(wParam)) { + case IDOK: + ppro->m_bRememberPwd = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SAVEPASS); + ppro->setSettingByte(NULL, "RememberPass", ppro->m_bRememberPwd); + + GetDlgItemTextA(hwndDlg, IDC_LOGINPW, ppro->m_szPassword, sizeof(ppro->m_szPassword)); + + ppro->icq_login(ppro->m_szPassword); + + EndDialog(hwndDlg, IDOK); + break; + + case IDCANCEL: + ppro->SetCurrentStatus(ID_STATUS_OFFLINE); + EndDialog(hwndDlg, IDCANCEL); + break; + } + } + break; + } + + return FALSE; +} + +void CIcqProto::RequestPassword() +{ + DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_LOGINPW), NULL, LoginPasswdDlgProc, LPARAM(this)); +} diff --git a/protocols/IcqOscarJ/src/UI/userinfotab.cpp b/protocols/IcqOscarJ/src/UI/userinfotab.cpp new file mode 100644 index 0000000000..91d28c0e04 --- /dev/null +++ b/protocols/IcqOscarJ/src/UI/userinfotab.cpp @@ -0,0 +1,315 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Code for User details ICQ specific pages +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +#define SVS_NORMAL 0 +#define SVS_ZEROISUNSPEC 2 +#define SVS_IP 3 +#define SVS_SIGNED 6 +#define SVS_ICQVERSION 8 +#define SVS_TIMESTAMP 9 +#define SVS_STATUSID 10 + +char* MirandaVersionToString(char* szStr, int bUnicode, int v, int m); + +extern const char *nameXStatus[]; + + +///////////////////////////////////////////////////////////////////////////////////////// + +static void SetValue(CIcqProto* ppro, HWND hwndDlg, int idCtrl, HANDLE hContact, char* szModule, char* szSetting, int special) +{ + DBVARIANT dbv = {0}; + char str[MAX_PATH]; + char* pstr = NULL; + int unspecified = 0; + int bUtf = 0, bDbv = 0, bAlloc = 0; + + dbv.type = DBVT_DELETED; + + if ((hContact == NULL) && ((int)szModule<0x100)) + { + dbv.type = (BYTE)szModule; + + switch((int)szModule) { + case DBVT_BYTE: + dbv.cVal = (BYTE)szSetting; + break; + case DBVT_WORD: + dbv.wVal = (WORD)szSetting; + break; + case DBVT_DWORD: + dbv.dVal = (DWORD)szSetting; + break; + case DBVT_ASCIIZ: + dbv.pszVal = pstr = szSetting; + break; + default: + unspecified = 1; + dbv.type = DBVT_DELETED; + } + } + else + { + if (szModule == NULL) + unspecified = 1; + else + { + unspecified = DBGetContactSetting(hContact, szModule, szSetting, &dbv); + bDbv = 1; + } + } + + if (!unspecified) + { + switch (dbv.type) { + case DBVT_BYTE: + unspecified = (special == SVS_ZEROISUNSPEC && dbv.bVal == 0); + pstr = _itoa(special == SVS_SIGNED ? dbv.cVal:dbv.bVal, str, 10); + break; + + case DBVT_WORD: + if (special == SVS_ICQVERSION) + { + if (dbv.wVal != 0) + { + char szExtra[80]; + + null_snprintf(str, 250, "%d", dbv.wVal); + pstr = str; + + if (hContact && ppro->IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 1)) + { + ICQTranslateUtfStatic(LPGEN(" (DC Established)"), szExtra, 80); + strcat(str, (char*)szExtra); + bUtf = 1; + } + } + else + unspecified = 1; + } + else if (special == SVS_STATUSID) + { + char *pXName; + char *pszStatus = MirandaStatusToStringUtf(dbv.wVal); + BYTE bXStatus = ppro->getContactXStatus(hContact); + + if (bXStatus) + { + pXName = ppro->getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); + if (!strlennull(pXName)) + { // give default name + pXName = ICQTranslateUtf(nameXStatus[bXStatus-1]); + } + null_snprintf(str, sizeof(str), "%s (%s)", pszStatus, pXName); + SAFE_FREE((void**)&pXName); + } + else + null_snprintf(str, sizeof(str), pszStatus); + + bUtf = 1; + SAFE_FREE(&pszStatus); + pstr = str; + unspecified = 0; + } + else + { + unspecified = (special == SVS_ZEROISUNSPEC && dbv.wVal == 0); + pstr = _itoa(special == SVS_SIGNED ? dbv.sVal:dbv.wVal, str, 10); + } + break; + + case DBVT_DWORD: + unspecified = (special == SVS_ZEROISUNSPEC && dbv.dVal == 0); + if (special == SVS_IP) + { + struct in_addr ia; + ia.S_un.S_addr = htonl(dbv.dVal); + pstr = inet_ntoa(ia); + if (dbv.dVal == 0) + unspecified=1; + } + else if (special == SVS_TIMESTAMP) + { + if (dbv.dVal == 0) + unspecified = 1; + else + pstr = time2text(dbv.dVal); + } + else + pstr = _itoa(special == SVS_SIGNED ? dbv.lVal:dbv.dVal, str, 10); + break; + + case DBVT_ASCIIZ: + case DBVT_WCHAR: + unspecified = (special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); + if (!unspecified && pstr != szSetting) + { + pstr = ppro->getSettingStringUtf(hContact, szModule, szSetting, NULL); + bUtf = 1; + bAlloc = 1; + } + if (idCtrl == IDC_UIN) + SetDlgItemTextUtf(hwndDlg, IDC_UINSTATIC, ICQTranslateUtfStatic(LPGEN("ScreenName:"), str, MAX_PATH)); + break; + + default: + pstr = str; + strcpy(str,"???"); + break; + } + } + + EnableDlgItem(hwndDlg, idCtrl, !unspecified); + if (unspecified) + SetDlgItemTextUtf(hwndDlg, idCtrl, ICQTranslateUtfStatic(LPGEN(""), str, MAX_PATH)); + else if (bUtf) + SetDlgItemTextUtf(hwndDlg, idCtrl, pstr); + else + SetDlgItemTextA(hwndDlg, idCtrl, pstr); + + if (bDbv) + ICQFreeVariant(&dbv); + + if (bAlloc) + SAFE_FREE(&pstr); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static INT_PTR CALLBACK IcqDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (( PSHNOTIFY* )lParam )->lParam ); + break; + + case PSN_INFOCHANGED: + { + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (!ppro) + break; + + char* szProto; + HANDLE hContact = (HANDLE)((LPPSHNOTIFY)lParam)->lParam; + + if (hContact == NULL) + szProto = ppro->m_szModuleName; + else + szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if (!szProto) + break; + + SetValue(ppro, hwndDlg, IDC_UIN, hContact, szProto, UNIQUEIDSETTING, SVS_NORMAL); + SetValue(ppro, hwndDlg, IDC_ONLINESINCE, hContact, szProto, "LogonTS", SVS_TIMESTAMP); + SetValue(ppro, hwndDlg, IDC_IDLETIME, hContact, szProto, "IdleTS", SVS_TIMESTAMP); + SetValue(ppro, hwndDlg, IDC_IP, hContact, szProto, "IP", SVS_IP); + SetValue(ppro, hwndDlg, IDC_REALIP, hContact, szProto, "RealIP", SVS_IP); + + if (hContact) + { + SetValue(ppro, hwndDlg, IDC_PORT, hContact, szProto, "UserPort", SVS_ZEROISUNSPEC); + SetValue(ppro, hwndDlg, IDC_VERSION, hContact, szProto, "Version", SVS_ICQVERSION); + SetValue(ppro, hwndDlg, IDC_MIRVER, hContact, szProto, "MirVer", SVS_ZEROISUNSPEC); + if (ppro->getSettingByte(hContact, "ClientID", 0)) + ppro->setSettingDword(hContact, "TickTS", 0); + SetValue(ppro, hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "TickTS", SVS_TIMESTAMP); + SetValue(ppro, hwndDlg, IDC_STATUS, hContact, szProto, "Status", SVS_STATUSID); + } + else + { + char str[MAX_PATH]; + + SetValue(ppro, hwndDlg, IDC_PORT, hContact, (char*)DBVT_WORD, (char*)ppro->wListenPort, SVS_ZEROISUNSPEC); + SetValue(ppro, hwndDlg, IDC_VERSION, hContact, (char*)DBVT_WORD, (char*)ICQ_VERSION, SVS_ICQVERSION); + SetValue(ppro, hwndDlg, IDC_MIRVER, hContact, (char*)DBVT_ASCIIZ, MirandaVersionToString(str, TRUE, ICQ_PLUG_VERSION, CallService(MS_SYSTEM_GETVERSION,0,0)), SVS_ZEROISUNSPEC); + SetDlgItemTextUtf(hwndDlg, IDC_SUPTIME, ICQTranslateUtfStatic(LPGEN("Member since:"), str, MAX_PATH)); + SetValue(ppro, hwndDlg, IDC_SYSTEMUPTIME, hContact, szProto, "MemberTS", SVS_TIMESTAMP); + SetValue(ppro, hwndDlg, IDC_STATUS, hContact, (char*)DBVT_WORD, (char*)ppro->m_iStatus, SVS_STATUSID); + } + } + break; + } + break; + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + SendMessage(GetParent(hwndDlg),msg,wParam,lParam); + break; + } + break; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CIcqProto::OnUserInfoInit(WPARAM wParam, LPARAM lParam) +{ + if ((!IsICQContact((HANDLE)lParam)) && lParam) + return 0; + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.flags = ODPF_TCHAR | ODPF_DONTTRANSLATE; + odp.hInstance = hInst; + odp.dwInitParam = LPARAM(this); + odp.pfnDlgProc = IcqDlgProc; + odp.position = -1900000000; + odp.ptszTitle = m_tszUserName; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_ICQ); + UserInfo_AddPage(wParam, &odp); + + if (!lParam) + { + TCHAR buf[200]; + null_snprintf(buf, SIZEOF(buf), TranslateT("%s Details"), m_tszUserName); + odp.ptszTitle = buf; + + odp.position = -1899999999; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_CHANGEINFO); + odp.pfnDlgProc = ChangeInfoDlgProc; + UserInfo_AddPage(wParam, &odp); + } + return 0; +} diff --git a/protocols/IcqOscarJ/src/capabilities.cpp b/protocols/IcqOscarJ/src/capabilities.cpp new file mode 100644 index 0000000000..f994f861af --- /dev/null +++ b/protocols/IcqOscarJ/src/capabilities.cpp @@ -0,0 +1,271 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Contains helper functions to handle oscar user capabilities. Scanning and +// adding capabilities are assumed to be more timecritical than looking up +// capabilites. During the login sequence there could possibly be many hundred +// scans but only a few lookups. So when you add or change something in this +// code you must have this in mind, dont do anything that will slow down the +// adding process too much. +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +struct icq_capability +{ + DWORD capID; // A bitmask, we use it in order to save database space + capstr capCLSID; // A binary representation of a oscar capability +}; + +static const icq_capability CapabilityRecord[] = +{ + {CAPF_SRV_RELAY, {CAP_SRV_RELAY }}, + {CAPF_UTF, {CAP_UTF }}, + {CAPF_RTF, {CAP_RTF }}, + {CAPF_CONTACTS, {CAP_CONTACTS }}, + {CAPF_TYPING, {CAP_TYPING }}, + {CAPF_ICQDIRECT, {CAP_ICQDIRECT }}, + {CAPF_XTRAZ, {CAP_XTRAZ }}, + {CAPF_OSCAR_FILE,{CAP_OSCAR_FILE}} +}; + +// Mask of all handled capabilities' flags +#define CapabilityFlagsMask (CAPF_SRV_RELAY | CAPF_UTF | CAPF_RTF | CAPF_CONTACTS | CAPF_TYPING | CAPF_ICQDIRECT | CAPF_XTRAZ | CAPF_OSCAR_FILE) + + +#ifdef _DEBUG +struct icq_capability_name +{ + DWORD capID; + const char* capName; +}; + +static const icq_capability_name CapabilityNames[] = +{ + {CAPF_SRV_RELAY, "ServerRelay"}, + {CAPF_UTF, "UTF8 Messages"}, + {CAPF_RTF, "RTF Messages"}, + {CAPF_CONTACTS, "Contact Transfer"}, + {CAPF_TYPING, "Typing Notifications"}, + {CAPF_ICQDIRECT, "Direct Connections"}, + {CAPF_XTRAZ, "Xtraz"}, + {CAPF_OSCAR_FILE, "File Transfers"}, + {CAPF_STATUS_MESSAGES,"Individual Status Messages"}, + {CAPF_STATUS_MOOD, "Mood"}, + {CAPF_XSTATUS, "Custom Status"} +}; + +void NetLog_CapabilityChange(CIcqProto *ppro, const char *szChange, DWORD fdwCapabilities) +{ + char szBuffer[MAX_PATH] = {0}; + + if (!fdwCapabilities) return; + + for (int nIndex = 0; nIndex < SIZEOF(CapabilityNames); nIndex++) + { + // Check if the current capability is present + if ((fdwCapabilities & CapabilityNames[nIndex].capID) == CapabilityNames[nIndex].capID) + { + if (strlennull(szBuffer)) + strcat(szBuffer, ", "); + strcat(szBuffer, CapabilityNames[nIndex].capName); + } + } + // Log the change + ppro->NetLog_Server("Capabilities: %s %s", szChange, szBuffer); +} +#endif + + +// Deletes all oscar capabilities for a given contact +void CIcqProto::ClearAllContactCapabilities(HANDLE hContact) +{ + setSettingDword(hContact, DBSETTING_CAPABILITIES, 0); +} + + +// Deletes one or many oscar capabilities for a given contact +void CIcqProto::ClearContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) +{ + // Get current capability flags + DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); + + if (fdwContactCaps != (fdwContactCaps & ~fdwCapabilities)) + { +#ifdef _DEBUG + NetLog_CapabilityChange(this, "Removed", fdwCapabilities & fdwContactCaps); +#endif + // Clear unwanted capabilities + fdwContactCaps &= ~fdwCapabilities; + + // And write it back to disk + setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); + } +} + + +// Sets one or many oscar capabilities for a given contact +void CIcqProto::SetContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) +{ + // Get current capability flags + DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); + + if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) + { +#ifdef _DEBUG + NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); +#endif + // Update them + fdwContactCaps |= fdwCapabilities; + + // And write it back to disk + setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); + } +} + + +// Returns true if the given contact supports the requested capabilites +BOOL CIcqProto::CheckContactCapabilities(HANDLE hContact, DWORD fdwCapabilities) +{ + // Get current capability flags + DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); + + // Check if all requested capabilities are supported + if ((fdwContactCaps & fdwCapabilities) == fdwCapabilities) + return TRUE; + + return FALSE; +} + + +// Scan capability against the capability buffer +capstr* MatchCapability(BYTE *buf, int bufsize, const capstr *cap, int capsize) +{ + while (bufsize >= BINARY_CAP_SIZE) // search the buffer for a capability + { + if (!memcmp(buf, cap, capsize)) + { + return (capstr*)buf; // give found capability for version info + } + else + { + buf += BINARY_CAP_SIZE; + bufsize -= BINARY_CAP_SIZE; + } + } + return 0; +} + + +// Scan short capability against the capability buffer +capstr* MatchShortCapability(BYTE *buf, int bufsize, const shortcapstr *cap) +{ + capstr fullCap; + + memcpy(fullCap, capShortCaps, BINARY_CAP_SIZE); + fullCap[2] = (*cap)[0]; + fullCap[3] = (*cap)[1]; + + return MatchCapability(buf, bufsize, &fullCap, BINARY_CAP_SIZE); +} + + +// Scans a binary buffer for OSCAR capabilities. +DWORD GetCapabilitiesFromBuffer(BYTE *pBuffer, int nLength) +{ + DWORD fdwCaps = 0; + + // Calculate the number of records + int nRecordSize = SIZEOF(CapabilityRecord); + + // Loop over all capabilities in the buffer and + // compare them to our own record of capabilities + for (int nIndex = 0; nIndex < nRecordSize; nIndex++) + { + if (MatchCapability(pBuffer, nLength, &CapabilityRecord[nIndex].capCLSID, BINARY_CAP_SIZE)) + { // Match, add capability flag + fdwCaps |= CapabilityRecord[nIndex].capID; + } + } + + return fdwCaps; +} + + +// Scans a binary buffer for oscar capabilities and adds them to the contact. +// You probably want to call ClearAllContactCapabilities() first. +void CIcqProto::AddCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength) +{ + // Get current capability flags + DWORD fdwContactCaps = getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); + // Get capability flags from buffer + DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength); + + if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) + { +#ifdef _DEBUG + NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); +#endif + // Add capability flags from buffer + fdwContactCaps |= fdwCapabilities; + + // And write them back to database + setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); + } +} + + +// Scans a binary buffer for oscar capabilities and adds them to the contact. +// You probably want to call ClearAllContactCapabilities() first. +void CIcqProto::SetCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength, BOOL bReset) +{ + // Get current capability flags + DWORD fdwContactCaps = bReset ? 0 : getSettingDword(hContact, DBSETTING_CAPABILITIES, 0); + // Get capability flags from buffer + DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength); + +#ifdef _DEBUG + if (bReset) + NetLog_CapabilityChange(this, "Set", fdwCapabilities); + else + { + NetLog_CapabilityChange(this, "Removed", fdwContactCaps & ~fdwCapabilities & CapabilityFlagsMask); + NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps); + } +#endif + + if (fdwCapabilities != (fdwContactCaps & ~CapabilityFlagsMask)) + { // Get current unmanaged capability flags + fdwContactCaps &= ~CapabilityFlagsMask; + + // Add capability flags from buffer + fdwContactCaps |= fdwCapabilities; + + // And write them back to database + setSettingDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps); + } +} diff --git a/protocols/IcqOscarJ/src/capabilities.h b/protocols/IcqOscarJ/src/capabilities.h new file mode 100644 index 0000000000..3b6590dd09 --- /dev/null +++ b/protocols/IcqOscarJ/src/capabilities.h @@ -0,0 +1,45 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Contains helper functions to handle OSCAR user capabilities. +// +// ----------------------------------------------------------------------------- + +#ifndef __CAPABILITIES_H +#define __CAPABILITIES_H + + +// capabilities +typedef BYTE capstr[BINARY_CAP_SIZE]; +typedef BYTE shortcapstr[BINARY_SHORT_CAP_SIZE]; + +extern const capstr capShortCaps; + +capstr* MatchCapability(BYTE *buf, int bufsize, const capstr *cap, int capsize = BINARY_CAP_SIZE); +capstr* MatchShortCapability(BYTE *buf, int bufsize, const shortcapstr *cap); + + +#endif /* __CAPABILITIES_H */ diff --git a/protocols/IcqOscarJ/src/chan_01login.cpp b/protocols/IcqOscarJ/src/chan_01login.cpp new file mode 100644 index 0000000000..3c4c4febc6 --- /dev/null +++ b/protocols/IcqOscarJ/src/chan_01login.cpp @@ -0,0 +1,105 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleLoginChannel(BYTE *buf, WORD datalen, serverthread_info *info) +{ + icq_packet packet; + +#ifdef _DEBUG + NetLog_Server("Received SRV_HELLO from %s", info->isLoginServer ? "login server" : "communication server"); +#endif + + // isLoginServer is "1" if we just received SRV_HELLO + if (info->isLoginServer) + { + if (m_bSecureLogin) + { + char szUin[UINMAXLEN]; + WORD wUinLen; + +#ifdef _DEBUG + NetLog_Server("Sending %s to %s", "CLI_HELLO", "login server"); +#endif + packet.wLen = 12; + write_flap(&packet, ICQ_LOGIN_CHAN); + packDWord(&packet, 0x00000001); + packTLVDWord(&packet, 0x8003, 0x00100000); // unknown + sendServPacket(&packet); // greet login server + + wUinLen = strlennull(strUID(m_dwLocalUIN, szUin)); +#ifdef _DEBUG + NetLog_Server("Sending %s to %s", "ICQ_SIGNON_AUTH_REQUEST", "login server"); +#endif + + serverPacketInit(&packet, (WORD)(14 + wUinLen)); + packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_AUTH_REQUEST, 0, 0); + packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin); + sendServPacket(&packet); // request login digest + } + else + { + sendClientAuth((char*)info->szAuthKey, info->wAuthKeyLen, FALSE); +#ifdef _DEBUG + NetLog_Server("Sent CLI_IDENT to %s", "login server"); +#endif + } + + info->isLoginServer = 0; + if (info->cookieDataLen) + { + SAFE_FREE((void**)&info->cookieData); + info->cookieDataLen = 0; + } + } + else + { + if (info->cookieDataLen) + { + wLocalSequence = generate_flap_sequence(); + + serverCookieInit(&packet, info->cookieData, (WORD)info->cookieDataLen); + sendServPacket(&packet); + +#ifdef _DEBUG + NetLog_Server("Sent CLI_IDENT to %s", "communication server"); +#endif + + SAFE_FREE((void**)&info->cookieData); + info->cookieDataLen = 0; + } + else + { + // We need a cookie to identify us to the communication server + NetLog_Server("Error: Connected to %s without a cookie!", "communication server"); + } + } +} diff --git a/protocols/IcqOscarJ/src/chan_02data.cpp b/protocols/IcqOscarJ/src/chan_02data.cpp new file mode 100644 index 0000000000..d55e0262e9 --- /dev/null +++ b/protocols/IcqOscarJ/src/chan_02data.cpp @@ -0,0 +1,222 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handle channel 2 (Data) packets +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleDataChannel(BYTE *pBuffer, WORD wBufferLength, serverthread_info *info) +{ + snac_header snacHeader = {0}; + + if (!unpackSnacHeader(&snacHeader, &pBuffer, &wBufferLength) || !snacHeader.bValid) + { + NetLog_Server("Error: Failed to parse SNAC header"); + } + else + { +#ifdef _DEBUG + if (snacHeader.wFlags & 0x8000) + NetLog_Server(" Received SNAC(x%02X,x%02X), version %u", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wVersion); + else + NetLog_Server(" Received SNAC(x%02X,x%02X)", snacHeader.wFamily, snacHeader.wSubtype); +#endif + + switch (snacHeader.wFamily) { + + case ICQ_SERVICE_FAMILY: + handleServiceFam(pBuffer, wBufferLength, &snacHeader, info); + break; + + case ICQ_LOCATION_FAMILY: + handleLocationFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_BUDDY_FAMILY: + handleBuddyFam(pBuffer, wBufferLength, &snacHeader, info); + break; + + case ICQ_MSG_FAMILY: + handleMsgFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_BOS_FAMILY: + handleBosFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_LOOKUP_FAMILY: + handleLookupFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_STATS_FAMILY: + handleStatusFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_LISTS_FAMILY: + handleServCListFam(pBuffer, wBufferLength, &snacHeader, info); + break; + + case ICQ_EXTENSIONS_FAMILY: + handleIcqExtensionsFam(pBuffer, wBufferLength, &snacHeader); + break; + + case ICQ_AUTHORIZATION_FAMILY: + handleAuthorizationFam(pBuffer, wBufferLength, &snacHeader, info); + break; + + default: + NetLog_Server("Ignoring SNAC(x%02X,x%02X) - FAMILYx%02X not implemented", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wFamily); + break; + + } + } +} + + +int unpackSnacHeader(snac_header *pSnacHeader, BYTE **pBuffer, WORD *pwBufferLength) +{ + WORD wRef1, wRef2; + + // Check header + if (!pSnacHeader) return 0; + + // 10 bytes is the minimum size of a header + if (*pwBufferLength < 10) + { + // Buffer overflow + pSnacHeader->bValid = FALSE; + return 1; + } + + // Unpack all the standard data + unpackWord(pBuffer, &(pSnacHeader->wFamily)); + unpackWord(pBuffer, &(pSnacHeader->wSubtype)); + unpackWord(pBuffer, &(pSnacHeader->wFlags)); + unpackWord(pBuffer, &wRef1); // unpack reference id (sequence) + unpackWord(pBuffer, &wRef2); // command + pSnacHeader->dwRef = wRef1 | (wRef2<<0x10); + + *pwBufferLength -= 10; + + // If flag bit 15 is set, we also have a version tag + // (...at least that is what I think it is) + if (pSnacHeader->wFlags & 0x8000) + { + if (*pwBufferLength >= 2) + { + WORD wExtraBytes = 0; + + unpackWord(pBuffer, &wExtraBytes); + *pwBufferLength -= 2; + + if (*pwBufferLength >= wExtraBytes) + { + if (wExtraBytes == 6) + { + *pBuffer += 4; // TLV type and length? + unpackWord(pBuffer, &(pSnacHeader->wVersion)); + *pwBufferLength -= wExtraBytes; + pSnacHeader->bValid = TRUE; + } + else if (wExtraBytes == 0x0E) + { + *pBuffer += 8; // TLV(2) - unknown + *pBuffer += 4; + unpackWord(pBuffer, &(pSnacHeader->wVersion)); + *pwBufferLength -= wExtraBytes; + pSnacHeader->bValid = TRUE; + } + else + { + *pBuffer += wExtraBytes; + *pwBufferLength -= wExtraBytes; + pSnacHeader->bValid = TRUE; + } + } + else + { + // Buffer overflow + pSnacHeader->bValid = FALSE; + } + } + else + { + // Buffer overflow + pSnacHeader->bValid = FALSE; + } + } + else + { + pSnacHeader->bValid = TRUE; + } + + return 1; +} + + +void CIcqProto::LogFamilyError(WORD wFamily, WORD wError) +{ + char *msg; + + switch(wError) { + case 0x01: msg = "Invalid SNAC header"; break; + case 0x02: msg = "Server rate limit exceeded"; break; + case 0x03: msg = "Client rate limit exceeded"; break; + case 0x04: msg = "Recipient is not logged in"; break; + case 0x05: msg = "Requested service unavailable"; break; + case 0x06: msg = "Requested service not defined"; break; + case 0x07: msg = "You sent obsolete SNAC"; break; + case 0x08: msg = "Not supported by server"; break; + case 0x09: msg = "Not supported by client"; break; + case 0x0A: msg = "Refused by client"; break; + case 0x0B: msg = "Reply too big"; break; + case 0x0C: msg = "Responses lost"; break; + case 0x0D: msg = "Request denied"; break; + case 0x0E: msg = "Incorrect SNAC format"; break; + case 0x0F: msg = "Insufficient rights"; break; + case 0x10: msg = "In local permit/deny (recipient blocked)"; break; + case 0x11: msg = "Sender is too evil"; break; + case 0x12: msg = "Receiver is too evil"; break; + case 0x13: msg = "User temporarily unavailable"; break; + case 0x14: msg = "No match"; break; + case 0x15: msg = "List overflow"; break; + case 0x16: msg = "Request ambiguous"; break; + case 0x17: msg = "Server queue full"; break; + case 0x18: msg = "Not while on AOL"; break; + case 0x19: msg = "Query failed"; break; + case 0x1A: msg = "Timeout"; break; + case 0x1C: msg = "General failure"; break; + case 0x1D: msg = "Progress"; break; + case 0x1E: msg = "In free area"; break; + case 0x1F: msg = "Restricted by parental controls"; break; + case 0x20: msg = "Remote restricted by parental controls"; break; + default: msg = ""; break; + } + + NetLog_Server("SNAC(x%02X,x01) - Error(%u): %s", wFamily, wError, msg); +} diff --git a/protocols/IcqOscarJ/src/chan_03error.cpp b/protocols/IcqOscarJ/src/chan_03error.cpp new file mode 100644 index 0000000000..71c6e2ea7c --- /dev/null +++ b/protocols/IcqOscarJ/src/chan_03error.cpp @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004,2005 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleErrorChannel(unsigned char* buf, WORD datalen) +{ + NetLog_Server("Ignoring server packet on ERROR channel"); +} diff --git a/protocols/IcqOscarJ/src/chan_04close.cpp b/protocols/IcqOscarJ/src/chan_04close.cpp new file mode 100644 index 0000000000..3c9ee46350 --- /dev/null +++ b/protocols/IcqOscarJ/src/chan_04close.cpp @@ -0,0 +1,314 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleCloseChannel(BYTE *buf, WORD datalen, serverthread_info *info) +{ + oscar_tlv_chain *chain = NULL; + + // Parse server reply, prepare reconnection + if (!info->bLoggedIn && datalen && !info->newServerReady) + handleLoginReply(buf, datalen, info); + + if (info->isMigrating) + handleMigration(info); + + if ((!info->bLoggedIn || info->isMigrating) && info->newServerReady) + { + if (!connectNewServer(info)) + { // Connecting failed + if (info->isMigrating) + icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Unable to connect to migrated ICQ communication server")); + else + icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Unable to connect to ICQ communication server")); + + SetCurrentStatus(ID_STATUS_OFFLINE); + + info->isMigrating = 0; + } + info->newServerReady = 0; + + return; + } + + if (chain = readIntoTLVChain(&buf, datalen, 0)) + { + // TLV 9 errors (runtime errors?) + WORD wError = chain->getWord(0x09, 1); + if (wError) + { + SetCurrentStatus(ID_STATUS_OFFLINE); + + handleRuntimeError(wError); + } + + disposeChain(&chain); + } + // Server closed connection on error, or sign off + NetLib_CloseConnection(&hServerConn, TRUE); +} + + +void CIcqProto::handleLoginReply(BYTE *buf, WORD datalen, serverthread_info *info) +{ + oscar_tlv_chain *chain = NULL; + + icq_sendCloseConnection(); // imitate icq5 behaviour + + if (!(chain = readIntoTLVChain(&buf, datalen, 0))) + { + NetLog_Server("Error: Missing chain on close channel"); + NetLib_CloseConnection(&hServerConn, TRUE); + return; // Invalid data + } + + // TLV 8 errors (signon errors?) + WORD wError = chain->getWord(0x08, 1); + if (wError) + { + handleSignonError(wError); + + // we return only if the server did not gave us cookie (possible to connect with soft error) + if (!chain->getLength(0x06, 1)) + { + disposeChain(&chain); + SetCurrentStatus(ID_STATUS_OFFLINE); + icq_serverDisconnect(FALSE); + return; // Failure + } + } + + // We are in the login phase and no errors were reported. + // Extract communication server info. + info->newServer = chain->getString(0x05, 1); + info->newServerSSL = chain->getNumber(0x8E, 1); + info->cookieData = (BYTE*)chain->getString(0x06, 1); + info->cookieDataLen = chain->getLength(0x06, 1); + + // We dont need this anymore + disposeChain(&chain); + + if (!info->newServer || !info->cookieData) + { + icq_LogMessage(LOG_FATAL, LPGEN("You could not sign on because the server returned invalid data. Try again.")); + + SAFE_FREE(&info->newServer); + SAFE_FREE((void**)&info->cookieData); + info->cookieDataLen = 0; + + SetCurrentStatus(ID_STATUS_OFFLINE); + NetLib_CloseConnection(&hServerConn, TRUE); + return; // Failure + } + + NetLog_Server("Authenticated."); + info->newServerReady = 1; + + return; +} + + +int CIcqProto::connectNewServer(serverthread_info *info) +{ + int res = 0; + + /* Get the ip and port */ + WORD wServerPort = info->wServerPort; // prepare default port + parseServerAddress(info->newServer, &wServerPort); + + NETLIBOPENCONNECTION nloc = {0}; + nloc.flags = 0; + nloc.szHost = info->newServer; + nloc.wPort = wServerPort; + + if (!m_bGatewayMode) + { + NetLib_SafeCloseHandle(&info->hPacketRecver); + NetLib_CloseConnection(&hServerConn, TRUE); + + NetLog_Server("Closed connection to login server"); + + hServerConn = NetLib_OpenConnection(m_hServerNetlibUser, NULL, &nloc); + if (hServerConn && info->newServerSSL) + { /* Start SSL session if requested */ + if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hServerConn, 0)) + NetLib_CloseConnection(&hServerConn, FALSE); + } + + if (hServerConn) + { + /* Time to recreate the packet receiver */ + info->hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 0x2400); + if (!info->hPacketRecver) + { + NetLog_Server("Error: Failed to create packet receiver."); + } + else // we need to reset receiving structs + { + info->bReinitRecver = 1; + res = 1; + } + } + } + else + { // TODO: We should really do some checks here + NetLog_Server("Walking in Gateway to %s", info->newServer); + // TODO: This REQUIRES more work (most probably some kind of mid-netlib module) + icq_httpGatewayWalkTo(hServerConn, &nloc); + res = 1; + } + if (!res) SAFE_FREE((void**)&info->cookieData); + + // Free allocated memory + // NOTE: "cookie" will get freed when we have connected to the communication server. + SAFE_FREE(&info->newServer); + + return res; +} + + +void CIcqProto::handleMigration(serverthread_info *info) +{ + // Check the data that was saved when the migration was announced + NetLog_Server("Migrating to %s", info->newServer); + if (!info->newServer || !info->cookieData) + { + icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because the current server shut down.")); + + SAFE_FREE(&info->newServer); + SAFE_FREE((void**)&info->cookieData); + info->newServerReady = 0; + info->isMigrating = 0; + } +} + +void CIcqProto::handleSignonError(WORD wError) +{ + switch (wError) { + + case 0x01: // Unregistered uin + case 0x04: // Incorrect uin or password + case 0x05: // Mismatch uin or password + case 0x06: // Internal Client error (bad input to authorizer) + case 0x07: // Invalid account + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); + ZeroMemory(m_szPassword, sizeof(m_szPassword)); + icq_LogFatalParam(LPGEN("Connection failed.\nYour ICQ number or password was rejected (%d)."), wError); + break; + + case 0x02: // Service temporarily unavailable + case 0x0D: // Bad database status + case 0x10: // Service temporarily offline + case 0x12: // Database send error + case 0x14: // Reservation map error + case 0x15: // Reservation link error + case 0x1A: // Reservation timeout + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER); + icq_LogFatalParam(LPGEN("Connection failed.\nThe server is temporarily unavailable (%d)."), wError); + break; + + case 0x16: // The users num connected from this IP has reached the maximum + case 0x17: // The users num connected from this IP has reached the maximum (reserved) + icq_LogFatalParam(LPGEN("Connection failed.\nServer has too many connections from your IP (%d)."), wError); + break; + + case 0x18: // Reservation rate limit exceeded + case 0x1D: // Rate limit exceeded + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER); + icq_LogFatalParam(LPGEN("Connection failed.\nYou have connected too quickly,\nplease wait and retry 10 to 20 minutes later (%d)."), wError); + break; + + case 0x1B: // You are using an older version of ICQ. Upgrade required + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL); + icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nThe server did not accept this client version.")); + break; + + case 0x1C: // You are using an older version of ICQ. Upgrade recommended + icq_LogMessage(LOG_WARNING, LPGEN("The server sent warning, this version is getting old.\nTry to look for a new one.")); + break; + + case 0x1E: // Can't register on the ICQ network + icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nYou were rejected by the server for an unknown reason.\nThis can happen if the UIN is already connected.")); + break; + + case 0x0C: // Invalid database fields, MD5 login not supported + icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nSecure (MD5) login is not supported on this account.")); + break; + + case 0: // No error + break; + + case 0x08: // Deleted account + case 0x09: // Expired account + case 0x0A: // No access to database + case 0x0B: // No access to resolver + case 0x0E: // Bad resolver status + case 0x0F: // Internal error + case 0x11: // Suspended account + case 0x13: // Database link error + case 0x19: // User too heavily warned + case 0x1F: // Token server timeout + case 0x20: // Invalid SecureID number + case 0x21: // MC error + case 0x22: // Age restriction + case 0x23: // RequireRevalidation + case 0x24: // Link rule rejected + case 0x25: // Missing information or bad SNAC format + case 0x26: // Link broken + case 0x27: // Invalid client IP + case 0x28: // Partner rejected + case 0x29: // SecureID missing + case 0x2A: // Blocked account | Bump user + + default: + icq_LogFatalParam(LPGEN("Connection failed.\nUnknown error during sign on: 0x%02x"), wError); + break; + } +} + + +void CIcqProto::handleRuntimeError(WORD wError) +{ + switch (wError) + { + + case 0x01: + { + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION); + icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number.")); + break; + } + + default: + icq_LogFatalParam(LPGEN("Unknown runtime error: 0x%02x"), wError); + break; + } +} diff --git a/protocols/IcqOscarJ/src/chan_05ping.cpp b/protocols/IcqOscarJ/src/chan_05ping.cpp new file mode 100644 index 0000000000..2a2b843509 --- /dev/null +++ b/protocols/IcqOscarJ/src/chan_05ping.cpp @@ -0,0 +1,89 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handlePingChannel(BYTE *buf, WORD datalen) +{ + NetLog_Server("Warning: Ignoring server packet on PING channel"); +} + + +void __cdecl CIcqProto::KeepAliveThread(void *arg) +{ + serverthread_info *info = (serverthread_info*)arg; + icq_packet packet; + DWORD dwInterval = getSettingDword(NULL, "KeepAliveInterval", KEEPALIVE_INTERVAL); + + NetLog_Server("Keep alive thread starting."); + + info->hKeepAliveEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + for (;;) + { + DWORD dwWait = ICQWaitForSingleObject(info->hKeepAliveEvent, dwInterval); + if (serverThreadHandle == NULL) // connection lost, end + break; + if (dwWait == WAIT_TIMEOUT) + { + // Send a keep alive packet to server + packet.wLen = 0; + write_flap(&packet, ICQ_PING_CHAN); + sendServPacket(&packet); + } + else if (dwWait == WAIT_IO_COMPLETION) + // Possible shutdown in progress + if (Miranda_Terminated()) break; + else + break; + } + + NetLog_Server("Keep alive thread ended."); + + CloseHandle(info->hKeepAliveEvent); + info->hKeepAliveEvent = NULL; +} + + +void CIcqProto::StartKeepAlive(serverthread_info *info) +{ + if (info->hKeepAliveEvent) // start only once + return; + + if (getSettingByte(NULL, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED)) + CloseHandle( ForkThreadEx(&CIcqProto::KeepAliveThread, info)); +} + + +void CIcqProto::StopKeepAlive(serverthread_info *info) +{ // finish keep alive thread + if (info->hKeepAliveEvent) + SetEvent(info->hKeepAliveEvent); +} diff --git a/protocols/IcqOscarJ/src/changeinfo/changeinfo.h b/protocols/IcqOscarJ/src/changeinfo/changeinfo.h new file mode 100644 index 0000000000..ecc4fc3106 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/changeinfo.h @@ -0,0 +1,122 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2010 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- + +#ifndef __CHANGEINFO_H +#define __CHANGEINFO_H + + +#ifndef AW_SLIDE +#define SPI_GETCOMBOBOXANIMATION 0x1004 +#define AW_SLIDE 0x40000 +#define AW_ACTIVATE 0x20000 +#define AW_VER_POSITIVE 0x4 +#define UDM_SETPOS32 (WM_USER+113) +#define UDM_GETPOS32 (WM_USER+114) +#endif + + +#define LI_DIVIDER 0 +#define LI_STRING 1 +#define LI_LIST 2 +#define LI_LONGSTRING 3 +#define LI_NUMBER 4 +#define LIM_TYPE 0x0000FFFF +#define LIF_ZEROISVALID 0x80000000 +#define LIF_SIGNED 0x40000000 +#define LIF_PASSWORD 0x20000000 +#define LIF_CHANGEONLY 0x10000000 + +struct SettingItem +{ + const char *szDescription; + unsigned displayType; //LI_ constant + int dbType; //DBVT_ constant + const char *szDbSetting; + const void *pList; +}; + +struct SettingItemData +{ + LPARAM value; + int changed; +}; + +// contants.c +extern const SettingItem setting[]; +extern const int settingCount; + +//dlgproc.c +struct ChangeInfoData : public MZeroedObject +{ + HWND hwndDlg; + CIcqProto *ppro; + HFONT hListFont; + HWND hwndList; + int editTopIndex; + int iEditItem; + char Password[PASSWORDMAXLEN]; + + SettingItemData *settingData; + + HANDLE hAckHook; + HANDLE hUpload[2]; + + ChangeInfoData() { settingData = (SettingItemData*)SAFE_MALLOC(sizeof(SettingItemData) * settingCount); hAckHook = NULL; hUpload[0] = NULL; hUpload[1] = NULL;} + ~ChangeInfoData() { SAFE_FREE((void**)&settingData); } + + char* GetItemSettingText(int i, char *buf, size_t buf_size); + void PaintItemSetting(HDC hdc, RECT *rc, int i, UINT itemState); + + //db.cpp + void LoadSettingsFromDb(int keepChanged); + void FreeStoredDbSettings(void); + int ChangesMade(void); + void ClearChangeFlags(void); + int SaveSettingsToDb(HWND hwndDlg); + + //upload.cpp + int UploadSettings(void); + + //editstring.cpp + void BeginStringEdit(int iItem,RECT *rc,int i,WORD wVKey); + void EndStringEdit(int save); + //editlist.cpp + void BeginListEdit(int iItem, RECT *rc, int iSetting, WORD wVKey); + void EndListEdit(int save); +}; + +INT_PTR CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//editstring.c +int IsStringEditWindow(HWND hwnd); +char* BinaryToEscapes(char *str); + +//editlist.c +int IsListEditWindow(HWND hwnd); + +#endif /* __CHANGEINFO_H */ diff --git a/protocols/IcqOscarJ/src/changeinfo/constants.cpp b/protocols/IcqOscarJ/src/changeinfo/constants.cpp new file mode 100644 index 0000000000..92403a74f0 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/constants.cpp @@ -0,0 +1,198 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2009 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static FieldNamesItem timezones[]={ + {24 ,LPGEN("GMT-12:00 Eniwetok; Kwajalein")}, + {23 ,LPGEN("GMT-11:30")}, + {22 ,LPGEN("GMT-11:00 Midway Island; Samoa")}, + {21 ,LPGEN("GMT-10:30")}, + {20 ,LPGEN("GMT-10:00 Hawaii")}, + {19 ,LPGEN("GMT-9:30")}, + {18 ,LPGEN("GMT-9:00 Alaska")}, + {17 ,LPGEN("GMT-8:30")}, + {16 ,LPGEN("GMT-8:00 Pacific Time; Tijuana")}, + {15 ,LPGEN("GMT-7:30")}, + {14 ,LPGEN("GMT-7:00 Arizona; Mountain Time")}, + {13 ,LPGEN("GMT-6:30")}, + {12 ,LPGEN("GMT-6:00 Central Time; Central America; Saskatchewan")}, + {11 ,LPGEN("GMT-5:30")}, + {10 ,LPGEN("GMT-5:00 Eastern Time; Bogota; Lima; Quito")}, + {9 ,LPGEN("GMT-4:30")}, + {8 ,LPGEN("GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz")}, + {7 ,LPGEN("GMT-3:30 Newfoundland")}, + {6 ,LPGEN("GMT-3:00 Greenland; Buenos Aires; Georgetown")}, + {5 ,LPGEN("GMT-2:30")}, + {4 ,LPGEN("GMT-2:00 Mid-Atlantic")}, + {3 ,LPGEN("GMT-1:30")}, + {2 ,LPGEN("GMT-1:00 Cape Verde Islands; Azores")}, + {1 ,LPGEN("GMT-0:30")}, + {0 ,LPGEN("GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca")}, + {-1 ,LPGEN("GMT+0:30")}, + {-2 ,LPGEN("GMT+1:00 Central European Time; West Central Africa; Warsaw")}, + {-3 ,LPGEN("GMT+1:30")}, + {-4 ,LPGEN("GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens")}, + {-5 ,LPGEN("GMT+2:30")}, + {-6 ,LPGEN("GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad")}, + {-7 ,LPGEN("GMT+3:30 Tehran")}, + {-8 ,LPGEN("GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat")}, + {-9 ,LPGEN("GMT+4:30 Kabul")}, + {-10 ,LPGEN("GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg")}, + {-11 ,LPGEN("GMT+5:30")}, + {-12 ,LPGEN("GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk; Sri Jayawardenepura")}, + {-13 ,LPGEN("GMT+6:30 Rangoon")}, + {-14 ,LPGEN("GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk")}, + {-15 ,LPGEN("GMT+7:30")}, + {-16 ,LPGEN("GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing")}, + {-17 ,LPGEN("GMT+8:30")}, + {-18 ,LPGEN("GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk")}, + {-19 ,LPGEN("GMT+9:30 Darwin; Adelaide")}, + {-20 ,LPGEN("GMT+10:00 East Australia; Guam; Vladivostok")}, + {-21 ,LPGEN("GMT+10:30")}, + {-22 ,LPGEN("GMT+11:00 Magadan; Solomon Is.; New Caledonia")}, + {-23 ,LPGEN("GMT+11:30")}, + {-24 ,LPGEN("GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is.")}, + {-100,NULL} +}; + + +static FieldNamesItem months[]={ + {1, LPGEN("January")}, + {2, LPGEN("February")}, + {3, LPGEN("March")}, + {4, LPGEN("April")}, + {5, LPGEN("May")}, + {6, LPGEN("June")}, + {7, LPGEN("July")}, + {8, LPGEN("August")}, + {9, LPGEN("September")}, + {10,LPGEN("October")}, + {11,LPGEN("November")}, + {12,LPGEN("December")}, + {0, NULL} +}; + + +const int ageRange[]={13,0x7FFF}; // 14, 130 +const int yearRange[]={1753,0x7FFF}; // 1880, 2000 +const int dayRange[]={1,31}; + + +const SettingItem setting[]={ + //personal + {LPGEN("Personal"), LI_DIVIDER}, + {LPGEN("Nickname"), LI_STRING, DBVT_UTF8, "Nick"}, + {LPGEN("First name"), LI_STRING, DBVT_UTF8, "FirstName"}, + {LPGEN("Last name"), LI_STRING, DBVT_UTF8, "LastName"}, +// {LPGEN("Age"), LI_NUMBER, DBVT_WORD, "Age", ageRange}, + {LPGEN("Gender"), LI_LIST, DBVT_BYTE, "Gender", genderField}, + {LPGEN("About"), LI_LONGSTRING, DBVT_UTF8, "About"}, + //password + {LPGEN("Password"), LI_DIVIDER}, + {LPGEN("Password"), LI_STRING|LIF_PASSWORD,DBVT_ASCIIZ, "Password"}, + //contact + {LPGEN("Contact"), LI_DIVIDER}, + {LPGEN("Primary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail0"}, + {LPGEN("Secondary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail1"}, + {LPGEN("Tertiary e-mail"), LI_STRING, DBVT_ASCIIZ, "e-mail2"}, + {LPGEN("Homepage"), LI_STRING, DBVT_ASCIIZ, "Homepage"}, + {LPGEN("Street"), LI_STRING, DBVT_UTF8, "Street"}, + {LPGEN("City"), LI_STRING, DBVT_UTF8, "City"}, + {LPGEN("State"), LI_STRING, DBVT_UTF8, "State"}, + {LPGEN("ZIP/postcode"), LI_STRING, DBVT_UTF8, "ZIP"}, + {LPGEN("Country"), LI_LIST, DBVT_WORD, "Country", countryField}, + {LPGEN("Phone number"), LI_STRING, DBVT_ASCIIZ, "Phone"}, + {LPGEN("Fax number"), LI_STRING, DBVT_ASCIIZ, "Fax"}, + {LPGEN("Cellular number"),LI_STRING, DBVT_ASCIIZ, "Cellular"}, + //more + {LPGEN("Personal Detail"),LI_DIVIDER}, + {LPGEN("Timezone"), LI_LIST|LIF_ZEROISVALID|LIF_SIGNED,DBVT_BYTE, "Timezone", timezones}, + {LPGEN("Year of birth"), LI_NUMBER, DBVT_WORD, "BirthYear", yearRange}, + {LPGEN("Month of birth"), LI_LIST, DBVT_BYTE, "BirthMonth", months}, + {LPGEN("Day of birth"), LI_NUMBER, DBVT_BYTE, "BirthDay", dayRange}, + {LPGEN("Marital Status"), LI_LIST, DBVT_BYTE, "MaritalStatus", maritalField}, + {LPGEN("Spoken language 1"), LI_LIST, DBVT_BYTE, "Language1", languageField}, + {LPGEN("Spoken language 2"), LI_LIST, DBVT_BYTE, "Language2", languageField}, + {LPGEN("Spoken language 3"), LI_LIST, DBVT_BYTE, "Language3", languageField}, + //more + {LPGEN("Originally from"),LI_DIVIDER}, + {LPGEN("Street"), LI_STRING, DBVT_UTF8, "OriginStreet"}, + {LPGEN("City"), LI_STRING, DBVT_UTF8, "OriginCity"}, + {LPGEN("State"), LI_STRING, DBVT_UTF8, "OriginState"}, + {LPGEN("Country"), LI_LIST, DBVT_WORD, "OriginCountry", countryField}, + //study + {LPGEN("Education"), LI_DIVIDER}, + {LPGEN("Level"), LI_LIST, DBVT_WORD, "StudyLevel", studyLevelField}, + {LPGEN("Institute"), LI_STRING, DBVT_UTF8, "StudyInstitute"}, + {LPGEN("Degree"), LI_STRING, DBVT_UTF8, "StudyDegree"}, + {LPGEN("Graduation Year"),LI_NUMBER, DBVT_WORD, "StudyYear", yearRange}, + //work + {LPGEN("Work"), LI_DIVIDER}, + {LPGEN("Company name"), LI_STRING, DBVT_UTF8, "Company"}, + {LPGEN("Company homepage"),LI_STRING, DBVT_ASCIIZ, "CompanyHomepage"}, + {LPGEN("Company street"), LI_STRING, DBVT_UTF8, "CompanyStreet"}, + {LPGEN("Company city"), LI_STRING, DBVT_UTF8, "CompanyCity"}, + {LPGEN("Company state"), LI_STRING, DBVT_UTF8, "CompanyState"}, + {LPGEN("Company phone"), LI_STRING, DBVT_ASCIIZ, "CompanyPhone"}, + {LPGEN("Company fax"), LI_STRING, DBVT_ASCIIZ, "CompanyFax"}, + {LPGEN("Company ZIP/postcode"),LI_STRING,DBVT_UTF8, "CompanyZIP"}, + {LPGEN("Company country"),LI_LIST, DBVT_WORD, "CompanyCountry", countryField}, + {LPGEN("Company department"),LI_STRING, DBVT_UTF8, "CompanyDepartment"}, + {LPGEN("Company position"),LI_STRING, DBVT_UTF8, "CompanyPosition"}, + {LPGEN("Company industry"),LI_LIST, DBVT_WORD, "CompanyIndustry", industryField}, +// {LPGEN("Company occupation"),LI_LIST, DBVT_WORD, "CompanyOccupation", occupationField}, + //interests + {LPGEN("Personal Interests"), LI_DIVIDER}, + {LPGEN("Interest category 1"),LI_LIST, DBVT_WORD, "Interest0Cat", interestsField}, + {LPGEN("Interest areas 1"),LI_STRING, DBVT_ASCIIZ, "Interest0Text"}, + {LPGEN("Interest category 2"),LI_LIST, DBVT_WORD, "Interest1Cat", interestsField}, + {LPGEN("Interest areas 2"),LI_STRING, DBVT_ASCIIZ, "Interest1Text"}, + {LPGEN("Interest category 3"),LI_LIST, DBVT_WORD, "Interest2Cat", interestsField}, + {LPGEN("Interest areas 3"),LI_STRING, DBVT_ASCIIZ, "Interest2Text"}, + {LPGEN("Interest category 4"),LI_LIST, DBVT_WORD, "Interest3Cat", interestsField}, + {LPGEN("Interest areas 4"),LI_STRING, DBVT_ASCIIZ, "Interest3Text"}, + //pastbackground +// {LPGEN("Past Background"), LI_DIVIDER}, +// {LPGEN("Category 1"), LI_LIST, DBVT_ASCIIZ, "Past0", pastField}, +// {LPGEN("Past Background 1"),LI_STRING, DBVT_ASCIIZ, "Past0Text"}, +// {LPGEN("Category 2"), LI_LIST, DBVT_ASCIIZ, "Past1", pastField}, +// {LPGEN("Past Background 2"),LI_STRING, DBVT_ASCIIZ, "Past1Text"}, +// {LPGEN("Category 3"), LI_LIST, DBVT_ASCIIZ, "Past2", pastField}, +// {LPGEN("Past Background 3"),LI_STRING, DBVT_ASCIIZ, "Past2Text"}, + //affiliation +// {LPGEN("Affiliations"), LI_DIVIDER}, +// {LPGEN("Affiliation category 1"),LI_LIST,DBVT_ASCIIZ, "Affiliation0", affiliationField}, +// {LPGEN("Affiliation 1"), LI_STRING, DBVT_ASCIIZ, "Affiliation0Text"}, +// {LPGEN("Affiliation category 2"),LI_LIST,DBVT_ASCIIZ, "Affiliation1", affiliationField}, +// {LPGEN("Affiliation 2"), LI_STRING, DBVT_ASCIIZ, "Affiliation1Text"}, +// {LPGEN("Affiliation category 3"),LI_LIST,DBVT_ASCIIZ, "Affiliation2", affiliationField}, +// {LPGEN("Affiliation 3"), LI_STRING, DBVT_ASCIIZ, "Affiliation2Text"} +}; + +const int settingCount = SIZEOF(setting); diff --git a/protocols/IcqOscarJ/src/changeinfo/db.cpp b/protocols/IcqOscarJ/src/changeinfo/db.cpp new file mode 100644 index 0000000000..643dcaa034 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/db.cpp @@ -0,0 +1,224 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2009 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void ChangeInfoData::LoadSettingsFromDb(int keepChanged) +{ + for (int i=0; i < settingCount; i++) + { + if (setting[i].displayType == LI_DIVIDER) continue; + if (keepChanged && settingData[i].changed) continue; + if (setting[i].dbType == DBVT_ASCIIZ || setting[i].dbType == DBVT_UTF8) + SAFE_FREE((void**)(char**)&settingData[i].value); + else if (!keepChanged) + settingData[i].value = 0; + + settingData[i].changed = 0; + + if (setting[i].displayType & LIF_PASSWORD) continue; + + DBVARIANT dbv = {DBVT_DELETED}; + if (!ppro->getSetting(NULL, setting[i].szDbSetting, &dbv)) + { + switch(dbv.type) { + case DBVT_ASCIIZ: + settingData[i].value = (LPARAM)ppro->getSettingStringUtf(NULL, setting[i].szDbSetting, NULL); + break; + + case DBVT_UTF8: + settingData[i].value = (LPARAM)null_strdup(dbv.pszVal); + break; + + case DBVT_WORD: + if (setting[i].displayType & LIF_SIGNED) + settingData[i].value = dbv.sVal; + else + settingData[i].value = dbv.wVal; + break; + + case DBVT_BYTE: + if (setting[i].displayType & LIF_SIGNED) + settingData[i].value = dbv.cVal; + else + settingData[i].value = dbv.bVal; + break; + +#ifdef _DEBUG + default: + MessageBoxA(NULL, "That's not supposed to happen either", "Huh?", MB_OK); + break; +#endif + } + ICQFreeVariant(&dbv); + } + + char buf[MAX_PATH]; + TCHAR tbuf[MAX_PATH]; + + if (utf8_to_tchar_static(GetItemSettingText(i, buf, SIZEOF(buf)), tbuf, SIZEOF(tbuf))) + ListView_SetItemText(hwndList, i, 1, tbuf); + } +} + + +void ChangeInfoData::FreeStoredDbSettings(void) +{ + for (int i=0; i < settingCount; i++ ) + if (setting[i].dbType == DBVT_ASCIIZ || setting[i].dbType == DBVT_UTF8) + SAFE_FREE((void**)&settingData[i].value); +} + + +int ChangeInfoData::ChangesMade(void) +{ + for (int i=0; i < settingCount; i++ ) + if (settingData[i].changed) + return 1; + return 0; +} + + +void ChangeInfoData::ClearChangeFlags(void) +{ + for (int i=0; i < settingCount; i++) + settingData[i].changed = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct PwConfirmDlgParam +{ + CIcqProto* ppro; + char* Pass; +}; + +static INT_PTR CALLBACK PwConfirmDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + PwConfirmDlgParam* dat = (PwConfirmDlgParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + SendDlgItemMessage(hwndDlg,IDC_PASSWORD,EM_LIMITTEXT,15,0); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + { + char szTest[16]; + + GetDlgItemTextA(hwndDlg,IDC_OLDPASS,szTest,sizeof(szTest)); + + if (strcmpnull(szTest, dat->ppro->GetUserPassword(TRUE))) + { + MessageBoxUtf(hwndDlg, LPGEN("The password does not match your current password. Check Caps Lock and try again."), LPGEN("Change ICQ Details"), MB_OK); + SendDlgItemMessage(hwndDlg,IDC_OLDPASS,EM_SETSEL,0,(LPARAM)-1); + SetFocus(GetDlgItem(hwndDlg,IDC_OLDPASS)); + break; + } + + GetDlgItemTextA(hwndDlg,IDC_PASSWORD,szTest,sizeof(szTest)); + if(strcmpnull(szTest, dat->Pass)) + { + MessageBoxUtf(hwndDlg, LPGEN("The password does not match the password you originally entered. Check Caps Lock and try again."), LPGEN("Change ICQ Details"), MB_OK); + SendDlgItemMessage(hwndDlg,IDC_PASSWORD,EM_SETSEL,0,(LPARAM)-1); + SetFocus(GetDlgItem(hwndDlg,IDC_PASSWORD)); + break; + } + } + case IDCANCEL: + EndDialog(hwndDlg,wParam); + break; + } + break; + } + return FALSE; +} + + +int ChangeInfoData::SaveSettingsToDb(HWND hwndDlg) +{ + int ret = 1; + + for (int i = 0; i < settingCount; i++) + { + if (!settingData[i].changed) continue; + if (!(setting[i].displayType & LIF_ZEROISVALID) && settingData[i].value==0) + { + ppro->deleteSetting(NULL, setting[i].szDbSetting); + continue; + } + switch(setting[i].dbType) { + case DBVT_ASCIIZ: + if (setting[i].displayType & LIF_PASSWORD) + { + int nSettingLen = strlennull((char*)settingData[i].value); + + if (nSettingLen > 8 || nSettingLen < 1) + { + MessageBoxUtf(hwndDlg, LPGEN("The ICQ server does not support passwords longer than 8 characters. Please use a shorter password."), LPGEN("Change ICQ Details"), MB_OK); + ret=0; + break; + } + PwConfirmDlgParam param = { ppro, (char*)settingData[i].value }; + if (IDOK != DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_PWCONFIRM), hwndDlg, PwConfirmDlgProc, (LPARAM)¶m)) + { + ret = 0; + break; + } + strcpy(ppro->m_szPassword, (char*)settingData[i].value); + } + else { + if (*(char*)settingData[i].value) + ppro->setSettingStringUtf(NULL, setting[i].szDbSetting, (char*)settingData[i].value); + else + ppro->deleteSetting(NULL, setting[i].szDbSetting); + } + break; + + case DBVT_UTF8: + if (*(char*)settingData[i].value) + ppro->setSettingStringUtf(NULL, setting[i].szDbSetting, (char*)settingData[i].value); + else + ppro->deleteSetting(NULL, setting[i].szDbSetting); + break; + + case DBVT_WORD: + ppro->setSettingWord(NULL, setting[i].szDbSetting, (WORD)settingData[i].value); + break; + + case DBVT_BYTE: + ppro->setSettingByte(NULL, setting[i].szDbSetting, (BYTE)settingData[i].value); + break; + } + } + return ret; +} diff --git a/protocols/IcqOscarJ/src/changeinfo/dlgproc.cpp b/protocols/IcqOscarJ/src/changeinfo/dlgproc.cpp new file mode 100644 index 0000000000..404777aa97 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/dlgproc.cpp @@ -0,0 +1,540 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2010 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +#define DM_PROTOACK (WM_USER+10) + +static int DrawTextUtf(HDC hDC, char *text, LPRECT lpRect, UINT uFormat, LPSIZE lpSize) +{ + int res; + + WCHAR *tmp = make_unicode_string(text); + res = DrawTextW(hDC, tmp, -1, lpRect, uFormat); + if (lpSize) + GetTextExtentPoint32W(hDC, tmp, strlennull(tmp), lpSize); + SAFE_FREE((void**)&tmp); + + return res; +} + + +char* ChangeInfoData::GetItemSettingText(int i, char *buf, size_t bufsize) +{ + char *text = buf; + int alloced = 0; + + buf[0] = '\0'; + + if (settingData[i].value == 0 && !(setting[i].displayType & LIF_ZEROISVALID)) + { + if (setting[i].displayType & LIF_CHANGEONLY) + text = ICQTranslateUtfStatic(LPGEN(""), buf, bufsize); + else + text = ICQTranslateUtfStatic(LPGEN(""), buf, bufsize); + } + else + { + switch (setting[i].displayType & LIM_TYPE) { + case LI_STRING: + case LI_LONGSTRING: + text = BinaryToEscapes((char*)settingData[i].value); + alloced = 1; + break; + + case LI_NUMBER: + _itoa(settingData[i].value, text, 10); + break; + + case LI_LIST: + if (setting[i].dbType == DBVT_ASCIIZ) + text = ICQTranslateUtfStatic((char*)settingData[i].value, buf, bufsize); + else + { + text = ICQTranslateUtfStatic(LPGEN("Unknown value"), buf, bufsize); + + FieldNamesItem *list = (FieldNamesItem*)setting[i].pList; + for (int j=0; TRUE; j++) + if (list[j].code == settingData[i].value) + { + text = ICQTranslateUtfStatic(list[j].text, buf, bufsize); + break; + } + else if (!list[j].text) + { + if (list[j].code == settingData[i].value) + text = ICQTranslateUtfStatic("Unspecified", buf, bufsize); + break; + } + } + break; + } + } + if (setting[i].displayType & LIF_PASSWORD) + { + if (settingData[i].changed) + for (int j=0; text[j]; j++) text[j] = '*'; + else + { + if (alloced) + { + SAFE_FREE(&text); + alloced = 0; + } + text = "********"; + } + } + if (text != buf) + { + char *tmp = text; + + text = null_strcpy(buf, text, bufsize - 1); + if (alloced) + SAFE_FREE(&tmp); + } + + return text; +} + + +void ChangeInfoData::PaintItemSetting(HDC hdc, RECT *rc, int i, UINT itemState) +{ + char str[MAX_PATH]; + char *text = GetItemSettingText(i, str, SIZEOF(str)); + + if (settingData[i].value == 0 && !(setting[i].displayType & LIF_ZEROISVALID)) + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + + if ((setting[i].displayType & LIM_TYPE) == LI_LIST && (itemState & CDIS_SELECTED || iEditItem == i)) + { + RECT rcBtn; + + rcBtn = *rc; + rcBtn.left = rcBtn.right - rc->bottom + rc->top; + InflateRect(&rcBtn,-2,-2); + rc->right = rcBtn.left; + DrawFrameControl(hdc, &rcBtn, DFC_SCROLL, iEditItem == i ? DFCS_SCROLLDOWN|DFCS_PUSHED : DFCS_SCROLLDOWN); + } + DrawTextUtf(hdc, text, rc, DT_END_ELLIPSIS|DT_LEFT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, NULL); +} + + +static int ChangeInfoDlg_Resize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc) +{ + switch (urc->wId) { + case IDC_LIST: + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + + case IDC_SAVE: + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + + case IDC_UPLOADING: + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + } + + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; // default +} + + +INT_PTR CALLBACK ChangeInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ChangeInfoData* dat = (ChangeInfoData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + dat = new ChangeInfoData(); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + + dat->hwndDlg = hwndDlg; + dat->ppro = (CIcqProto*)lParam; + dat->hwndList = GetDlgItem(hwndDlg, IDC_LIST); + + ListView_SetExtendedListViewStyle(dat->hwndList, LVS_EX_FULLROWSELECT); + dat->iEditItem = -1; + { + HFONT hFont; + LOGFONT lf; + + dat->hListFont = (HFONT)SendMessage(dat->hwndList, WM_GETFONT, 0, 0); + GetObject(dat->hListFont, sizeof(lf), &lf); + lf.lfHeight -= 5; + hFont = CreateFontIndirect(&lf); + SendMessage(dat->hwndList, WM_SETFONT, (WPARAM)hFont, 0); + } + { // Prepare ListView Columns + LV_COLUMN lvc = {0}; + RECT rc; + + GetClientRect(dat->hwndList, &rc); + rc.right -= GetSystemMetrics(SM_CXVSCROLL); + lvc.mask = LVCF_WIDTH; + lvc.cx = rc.right / 3; + ListView_InsertColumn(dat->hwndList, 0, &lvc); + lvc.cx = rc.right - lvc.cx; + ListView_InsertColumn(dat->hwndList, 1, &lvc); + } + { // Prepare Setting Items + LV_ITEM lvi = {0}; + lvi.mask = LVIF_PARAM | LVIF_TEXT; + + for (lvi.iItem = 0; lvi.iItem < settingCount; lvi.iItem++) + { + TCHAR text[MAX_PATH]; + + lvi.lParam = lvi.iItem; + lvi.pszText = text; + utf8_to_tchar_static(setting[lvi.iItem].szDescription, text, SIZEOF(text)); + ListView_InsertItem(dat->hwndList, &lvi); + } + } + + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + dat->ppro = (CIcqProto*)((PSHNOTIFY*)lParam)->lParam; + dat->LoadSettingsFromDb(0); + { + char *pwd = dat->ppro->GetUserPassword(TRUE); + strcpy(dat->Password, (pwd) ? pwd : "" ); /// FIXME + } + break; + + case PSN_INFOCHANGED: + dat->LoadSettingsFromDb(1); + break; + + case PSN_KILLACTIVE: + dat->EndStringEdit(1); + dat->EndListEdit(1); + break; + + case PSN_APPLY: + if (dat->ChangesMade()) + { + if (IDYES!=MessageBoxUtf(hwndDlg, LPGEN("You've made some changes to your ICQ details but it has not been saved to the server. Are you sure you want to close this dialog?"), LPGEN("Change ICQ Details"), MB_YESNOCANCEL)) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + } + break; + } + break; + + case IDC_LIST: + switch (((LPNMHDR)lParam)->code) { + case LVN_GETDISPINFO: + if (dat->iEditItem != -1) + { + if (dat->editTopIndex != ListView_GetTopIndex(dat->hwndList)) + { + dat->EndStringEdit(1); + dat->EndListEdit(1); + } + } + break; + + case NM_CUSTOMDRAW: + { + LPNMLVCUSTOMDRAW cd=(LPNMLVCUSTOMDRAW)lParam; + + switch(cd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW); + return TRUE; + + case CDDS_ITEMPREPAINT: + { + RECT rcItem; + + if (dat->iEditItem != -1) + { + if (dat->editTopIndex != ListView_GetTopIndex(dat->hwndList)) + { + dat->EndStringEdit(1); + dat->EndListEdit(1); + } + } + + ListView_GetItemRect(dat->hwndList, cd->nmcd.dwItemSpec, &rcItem, LVIR_BOUNDS); + + if (GetWindowLongPtr(dat->hwndList, GWL_STYLE) & WS_DISABLED) + { // Disabled List + SetTextColor(cd->nmcd.hdc, cd->clrText); + FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_3DFACE)); + } + else if ((cd->nmcd.uItemState & CDIS_SELECTED || dat->iEditItem == (int)cd->nmcd.dwItemSpec) + && setting[cd->nmcd.lItemlParam].displayType != LI_DIVIDER) + { // Selected item + SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { // Unselected item + SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_WINDOWTEXT)); + FillRect(cd->nmcd.hdc, &rcItem, GetSysColorBrush(COLOR_WINDOW)); + } + + HFONT hoFont = (HFONT)SelectObject(cd->nmcd.hdc, dat->hListFont); + + if (setting[cd->nmcd.lItemlParam].displayType == LI_DIVIDER) + { + RECT rcLine; + SIZE textSize; + char str[MAX_PATH]; + char *szText = ICQTranslateUtfStatic(setting[cd->nmcd.lItemlParam].szDescription, str, MAX_PATH); + + SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_3DSHADOW)); + DrawTextUtf(cd->nmcd.hdc, szText, &rcItem, DT_CENTER|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, &textSize); + rcLine.top = (rcItem.top + rcItem.bottom) / 2 - 1; + rcLine.bottom = rcLine.top + 2; + rcLine.left = rcItem.left + 3; + rcLine.right = (rcItem.left + rcItem.right - textSize.cx) / 2 - 3; + DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT); + rcLine.left = (rcItem.left + rcItem.right + textSize.cx) / 2 + 3; + rcLine.right = rcItem.right - 3; + DrawEdge(cd->nmcd.hdc, &rcLine, BDR_SUNKENOUTER, BF_RECT); + } + else + { + RECT rcItemDescr, rcItemValue; + char str[MAX_PATH]; + + ListView_GetSubItemRect(dat->hwndList, cd->nmcd.dwItemSpec, 0, LVIR_BOUNDS, &rcItemDescr); + ListView_GetSubItemRect(dat->hwndList, cd->nmcd.dwItemSpec, 1, LVIR_BOUNDS, &rcItemValue); + + rcItemDescr.right = rcItemValue.left; + rcItemDescr.left += 2; + DrawTextUtf(cd->nmcd.hdc, ICQTranslateUtfStatic(setting[cd->nmcd.lItemlParam].szDescription, str, MAX_PATH), &rcItemDescr, DT_END_ELLIPSIS|DT_LEFT|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER, NULL); + + dat->PaintItemSetting(cd->nmcd.hdc, &rcItemValue, cd->nmcd.lItemlParam, cd->nmcd.uItemState); + } + SelectObject(cd->nmcd.hdc, hoFont); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT); + + return TRUE; + } + } + break; + } + case NM_CLICK: + { + LPNMLISTVIEW nm=(LPNMLISTVIEW)lParam; + LV_ITEM lvi; + RECT rc; + + dat->EndStringEdit(1); + dat->EndListEdit(1); + if (nm->iSubItem != 1) break; + lvi.mask = LVIF_PARAM|LVIF_STATE; + lvi.stateMask = 0xFFFFFFFF; + lvi.iItem = nm->iItem; lvi.iSubItem = nm->iSubItem; + ListView_GetItem(dat->hwndList, &lvi); + if (!(lvi.state & LVIS_SELECTED)) break; + ListView_EnsureVisible(dat->hwndList, lvi.iItem, FALSE); + ListView_GetSubItemRect(dat->hwndList, lvi.iItem, lvi.iSubItem, LVIR_BOUNDS, &rc); + dat->editTopIndex = ListView_GetTopIndex(dat->hwndList); + switch (setting[lvi.lParam].displayType & LIM_TYPE) { + case LI_STRING: + case LI_LONGSTRING: + case LI_NUMBER: + dat->BeginStringEdit(nm->iItem, &rc, lvi. lParam, 0); + break; + case LI_LIST: + dat->BeginListEdit(nm->iItem, &rc, lvi. lParam, 0); + break; + } + break; + } + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN nm=(LPNMLVKEYDOWN)lParam; + LV_ITEM lvi; + RECT rc; + + dat->EndStringEdit(1); + dat->EndListEdit(1); + if(nm->wVKey==VK_SPACE || nm->wVKey==VK_RETURN || nm->wVKey==VK_F2) nm->wVKey=0; + if(nm->wVKey && (nm->wVKey<'0' || (nm->wVKey>'9' && nm->wVKey<'A') || (nm->wVKey>'Z' && nm->wVKeywVKey>=VK_F1)) + break; + lvi.mask=LVIF_PARAM|LVIF_STATE; + lvi.stateMask=0xFFFFFFFF; + lvi.iItem = ListView_GetNextItem(dat->hwndList, -1, LVNI_ALL|LVNI_SELECTED); + if (lvi.iItem==-1) break; + lvi.iSubItem=1; + ListView_GetItem(dat->hwndList,&lvi); + ListView_EnsureVisible(dat->hwndList,lvi.iItem,FALSE); + ListView_GetSubItemRect(dat->hwndList,lvi.iItem,lvi.iSubItem,LVIR_BOUNDS,&rc); + dat->editTopIndex = ListView_GetTopIndex(dat->hwndList); + switch(setting[lvi.lParam].displayType & LIM_TYPE) { + case LI_STRING: + case LI_LONGSTRING: + case LI_NUMBER: + dat->BeginStringEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey); + break; + case LI_LIST: + dat->BeginListEdit(lvi.iItem,&rc,lvi.lParam,nm->wVKey); + break; + } + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + case NM_KILLFOCUS: + if (!IsStringEditWindow(GetFocus())) dat->EndStringEdit(1); + if (!IsListEditWindow(GetFocus())) dat->EndListEdit(1); + break; + } + break; + } + break; + case WM_KILLFOCUS: + dat->EndStringEdit(1); + dat->EndListEdit(1); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + SendMessage(GetParent(hwndDlg), msg, wParam, lParam); + break; + + case IDC_SAVE: + if (!dat->SaveSettingsToDb(hwndDlg)) + break; + + EnableDlgItem(hwndDlg, IDC_SAVE, FALSE); + EnableDlgItem(hwndDlg, IDC_LIST, FALSE); + { + char str[MAX_PATH]; + SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload in progress..."), str, MAX_PATH)); + } + EnableDlgItem(hwndDlg, IDC_UPLOADING, TRUE); + ShowDlgItem(hwndDlg, IDC_UPLOADING, SW_SHOW); + dat->hAckHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, DM_PROTOACK); + + if (!dat->UploadSettings()) + { + EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); + EnableDlgItem(hwndDlg, IDC_LIST, TRUE); + ShowDlgItem(hwndDlg, IDC_UPLOADING, SW_HIDE); + UnhookEvent(dat->hAckHook); + dat->hAckHook = NULL; + } + break; + } + break; + + case WM_SIZE: + { // make the dlg resizeable + UTILRESIZEDIALOG urd = {0}; + + if (IsIconic(hwndDlg)) break; + urd.cbSize = sizeof(urd); + urd.hInstance = hInst; + urd.hwndDlg = hwndDlg; + urd.lParam = 0; // user-defined + urd.lpTemplate = MAKEINTRESOURCEA(IDD_INFO_CHANGEINFO); + urd.pfnResizer = ChangeInfoDlg_Resize; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) &urd); + + { // update listview column widths + RECT rc; + + GetClientRect(dat->hwndList, &rc); + rc.right -= GetSystemMetrics(SM_CXVSCROLL); + ListView_SetColumnWidth(dat->hwndList, 0, rc.right / 3); + ListView_SetColumnWidth(dat->hwndList, 1, rc.right - rc.right / 3); + } + break; + } + + case DM_PROTOACK: + { + ACKDATA *ack=(ACKDATA*)lParam; + int i,done; + char str[MAX_PATH]; + char buf[MAX_PATH]; + + if (ack->type != ACKTYPE_SETINFO) break; + if (ack->result == ACKRESULT_SUCCESS) + { + for (i=0; i < SIZEOF(dat->hUpload); i++) + if (dat->hUpload[i] && ack->hProcess == dat->hUpload[i]) break; + + if (i == SIZEOF(dat->hUpload)) break; + dat->hUpload[i] = NULL; + for (done = 0, i = 0; i < SIZEOF(dat->hUpload); i++) + done += dat->hUpload[i] == NULL; + null_snprintf(buf, sizeof(buf), "%s%d%%", ICQTranslateUtfStatic(LPGEN("Upload in progress..."), str, MAX_PATH), 100*done/(SIZEOF(dat->hUpload))); + SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, buf); + if (done < SIZEOF(dat->hUpload)) break; + + dat->ClearChangeFlags(); + UnhookEvent(dat->hAckHook); + dat->hAckHook = NULL; + EnableDlgItem(hwndDlg, IDC_LIST, TRUE); + EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE); + SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload complete"), str, MAX_PATH)); + SendMessage(GetParent(hwndDlg), PSM_FORCECHANGED, 0, 0); + } + else if (ack->result==ACKRESULT_FAILED) + { + UnhookEvent(dat->hAckHook); + dat->hAckHook = NULL; + EnableDlgItem(hwndDlg, IDC_LIST, TRUE); + EnableDlgItem(hwndDlg, IDC_UPLOADING, FALSE); + SetDlgItemTextUtf(hwndDlg, IDC_UPLOADING, ICQTranslateUtfStatic(LPGEN("Upload FAILED"), str, MAX_PATH)); + SendMessage(GetParent(hwndDlg), PSM_FORCECHANGED, 0, 0); + EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); + } + break; + } + case WM_DESTROY: + if (dat->hAckHook) + { + UnhookEvent(dat->hAckHook); + dat->hAckHook = NULL; + } + { + HFONT hFont = (HFONT)SendMessage(dat->hwndList, WM_GETFONT, 0, 0); + DeleteObject(hFont); + } + dat->FreeStoredDbSettings(); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + delete dat; + break; + } + return FALSE; +} diff --git a/protocols/IcqOscarJ/src/changeinfo/editlist.cpp b/protocols/IcqOscarJ/src/changeinfo/editlist.cpp new file mode 100644 index 0000000000..f2a1470fd3 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/editlist.cpp @@ -0,0 +1,201 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2009 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static ChangeInfoData *dataListEdit = NULL; +static HWND hwndListEdit = NULL; +static BOOL (WINAPI *MyAnimateWindow)(HWND,DWORD,DWORD); +static WNDPROC OldListEditProc; + +static LRESULT CALLBACK ListEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_LBUTTONUP: + CallWindowProc(OldListEditProc, hwnd, msg, wParam, lParam); + { + POINT pt; + + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + ClientToScreen(hwnd, &pt); + if (SendMessage(hwnd, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y)) == HTVSCROLL) break; + } + { + int i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + + if (dataListEdit) + dataListEdit->EndListEdit(i != LB_ERR); + } + return 0; + + case WM_CHAR: + if (wParam != '\r') break; + { + int i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + + if (dataListEdit) + dataListEdit->EndListEdit(i != LB_ERR); + } + return 0; + case WM_KILLFOCUS: + if (dataListEdit) + dataListEdit->EndListEdit(1); + return 0; + } + return CallWindowProc(OldListEditProc, hwnd, msg, wParam, lParam); +} + + +void ChangeInfoData::BeginListEdit(int iItem, RECT *rc, int iSetting, WORD wVKey) +{ + int j,n; + POINT pt; + int itemHeight; + char str[MAX_PATH]; + + if (dataListEdit) + dataListEdit->EndListEdit(0); + + pt.x=pt.y=0; + ClientToScreen(hwndList,&pt); + OffsetRect(rc,pt.x,pt.y); + InflateRect(rc,-2,-2); + rc->left-=2; + iEditItem = iItem; + ListView_RedrawItems(hwndList, iEditItem, iEditItem); + UpdateWindow(hwndList); + + dataListEdit = this; + hwndListEdit = CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, _T("LISTBOX"), _T(""), WS_POPUP|WS_BORDER|WS_VSCROLL, rc->left, rc->bottom, rc->right - rc->left, 150, NULL, NULL, hInst, NULL); + SendMessage(hwndListEdit, WM_SETFONT, (WPARAM)hListFont, 0); + itemHeight = SendMessage(hwndListEdit, LB_GETITEMHEIGHT, 0, 0); + + FieldNamesItem *list = (FieldNamesItem*)setting[iSetting].pList; + + if (list == countryField) + { // some country codes were changed leaving old details uknown, convert it for the user + if (settingData[iSetting].value == 420) settingData[iSetting].value = 42; // conversion of obsolete codes (OMG!) + else if (settingData[iSetting].value == 421) settingData[iSetting].value = 4201; + else if (settingData[iSetting].value == 102) settingData[iSetting].value = 1201; + } + + n = ListBoxAddStringUtf(hwndListEdit, "Unspecified"); + for (j=0; ; j++) + if (!list[j].text) + { + SendMessage(hwndListEdit, LB_SETITEMDATA, n, j); + if ((settingData[iSetting].value == 0 && list[j].code == 0) + || (setting[iSetting].dbType != DBVT_ASCIIZ && settingData[iSetting].value == list[j].code)) + SendMessage(hwndListEdit, LB_SETCURSEL, n, 0); + break; + } + + for (j=0; list[j].text; j++) + { + n = ListBoxAddStringUtf(hwndListEdit, list[j].text); + SendMessage(hwndListEdit, LB_SETITEMDATA, n, j); + if ((setting[iSetting].dbType == DBVT_ASCIIZ && (!strcmpnull((char*)settingData[iSetting].value, list[j].text)) + || (setting[iSetting].dbType == DBVT_ASCIIZ && (!strcmpnull((char*)settingData[iSetting].value, ICQTranslateUtfStatic(list[j].text, str, MAX_PATH)))) + || ((char*)settingData[iSetting].value == NULL && list[j].code == 0)) + || (setting[iSetting].dbType != DBVT_ASCIIZ && settingData[iSetting].value == list[j].code)) + SendMessage(hwndListEdit, LB_SETCURSEL, n, 0); + } + SendMessage(hwndListEdit, LB_SETTOPINDEX, SendMessage(hwndListEdit, LB_GETCURSEL, 0, 0) - 3, 0); + int listCount = SendMessage(hwndListEdit, LB_GETCOUNT, 0, 0); + if (itemHeight * listCount < 150) + SetWindowPos(hwndListEdit, 0, 0, 0, rc->right - rc->left, itemHeight * listCount + GetSystemMetrics(SM_CYBORDER) * 2, SWP_NOZORDER|SWP_NOMOVE); + OldListEditProc = (WNDPROC)SetWindowLongPtr(hwndListEdit, GWLP_WNDPROC, (LONG_PTR)ListEditSubclassProc); + if (MyAnimateWindow = (BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("user32"), "AnimateWindow")) + { + BOOL enabled; + + SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &enabled, FALSE); + if (enabled) MyAnimateWindow(hwndListEdit, 200, AW_SLIDE|AW_ACTIVATE|AW_VER_POSITIVE); + } + ShowWindow(hwndListEdit, SW_SHOW); + SetFocus(hwndListEdit); + if (wVKey) + PostMessage(hwndListEdit, WM_KEYDOWN, wVKey, 0); +} + + +void ChangeInfoData::EndListEdit(int save) +{ + if (hwndListEdit == NULL || iEditItem == -1 || this != dataListEdit) return; + if (save) + { + int iItem = SendMessage(hwndListEdit, LB_GETCURSEL, 0, 0); + int i = SendMessage(hwndListEdit, LB_GETITEMDATA, iItem, 0); + + if (setting[iEditItem].dbType == DBVT_ASCIIZ) + { + char *szNewValue = (((FieldNamesItem*)setting[iEditItem].pList)[i].text); + if (((FieldNamesItem*)setting[iEditItem].pList)[i].code || setting[iEditItem].displayType & LIF_ZEROISVALID) + { + settingData[iEditItem].changed = strcmpnull(szNewValue, (char*)settingData[iEditItem].value); + SAFE_FREE((void**)&settingData[iEditItem].value); + settingData[iEditItem].value = (LPARAM)null_strdup(szNewValue); + } + else + { + settingData[iEditItem].changed = (char*)settingData[iEditItem].value!=NULL; + SAFE_FREE((void**)&settingData[iEditItem].value); + } + } + else + { + settingData[iEditItem].changed = ((FieldNamesItem*)setting[iEditItem].pList)[i].code != settingData[iEditItem].value; + settingData[iEditItem].value = ((FieldNamesItem*)setting[iEditItem].pList)[i].code; + } + if (settingData[iEditItem].changed) + { + char buf[MAX_PATH]; + TCHAR tbuf[MAX_PATH]; + + if (utf8_to_tchar_static(ICQTranslateUtfStatic(((FieldNamesItem*)setting[iEditItem].pList)[i].text, buf, SIZEOF(buf)), tbuf, SIZEOF(buf))) + ListView_SetItemText(hwndList, iEditItem, 1, tbuf); + + EnableDlgItem(GetParent(hwndList), IDC_SAVE, TRUE); + + } + } + ListView_RedrawItems(hwndList, iEditItem, iEditItem); + iEditItem = -1; + dataListEdit = NULL; + DestroyWindow(hwndListEdit); + hwndListEdit = NULL; +} + + +int IsListEditWindow(HWND hwnd) +{ + if (hwnd == hwndListEdit) return 1; + return 0; +} diff --git a/protocols/IcqOscarJ/src/changeinfo/editstring.cpp b/protocols/IcqOscarJ/src/changeinfo/editstring.cpp new file mode 100644 index 0000000000..288351e8d3 --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/editstring.cpp @@ -0,0 +1,367 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2009 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static ChangeInfoData *dataStringEdit = NULL; +static WNDPROC OldStringEditProc, OldExpandButtonProc; +static HWND hwndEdit = NULL, hwndExpandButton = NULL, hwndUpDown = NULL; + +static const char escapes[]={'a','\a', +'b','\b', +'e',27, +'f','\f', +'r','\r', +'t','\t', +'v','\v', +'\\','\\'}; + +static void EscapesToMultiline(WCHAR *str,PDWORD selStart,PDWORD selEnd) +{ //converts "\\n" and "\\t" to "\r\n" and "\t" because a multi-line edit box can show them properly + DWORD i; + + for(i=0; *str; str++, i++) + { + if (*str != '\\') continue; + if (str[1] == 'n') + { + *str++ = '\r'; + i++; + *str = '\n'; + } + else if (str[1] == 't') + { + *str = '\t'; + memmove(str+1, str+2, sizeof(WCHAR)*(strlennull(str)-1)); + + if (*selStart>i) --*selStart; + if (*selEnd>i) --*selEnd; + } + } +} + + + +static void EscapesToBinary(char *str) +{ + for (;*str;str++) + { + if (*str!='\\') continue; + if(str[1]=='n') {*str++='\r'; *str='\n'; continue;} + if(str[1]=='0') + { + char *codeend; + *str=(char)strtol(str+1,&codeend,8); + if (*str==0) {*str='\\'; continue;} + memmove(str+1,codeend,strlennull(codeend)+1); + continue; + } + for(int i=0;i=' ') + { + *pout++=*str; + continue; + } + if(str[0]=='\r' && str[1]=='\n') + { + *pout++='\\'; + *pout++='n'; + str++; + continue; + } + if(extra<3) + { + extra+=8; len+=8; + pout=out=(char*)SAFE_REALLOC(out,len); + } + *pout++='\\'; + for(i = 0; i < SIZEOF(escapes); i += 2) + if (*str==escapes[i+1]) + { + *pout++=escapes[i]; + extra--; + break; + } + if(i < SIZEOF(escapes)) continue; + *pout++='0'; extra--; + if (*str>=8) + { + *pout++=(*str>>3)+'0'; + extra--; + } + *pout++=(*str&7)+'0'; extra--; + } + *pout='\0'; + return out; +} + + + +static LRESULT CALLBACK StringEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_KEYDOWN: + if (wParam==VK_ESCAPE) + { + if (dataStringEdit) + dataStringEdit->EndStringEdit(0); + return 0; + } + if (wParam==VK_RETURN) + { + if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_MULTILINE && !(GetKeyState(VK_CONTROL) & 0x8000)) break; + if (dataStringEdit) + dataStringEdit->EndStringEdit(1); + return 0; + } + break; + + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS|CallWindowProc(OldStringEditProc, hwnd, msg, wParam, lParam); + + case WM_KILLFOCUS: + if ((HWND)wParam == hwndExpandButton) break; + if (dataStringEdit) + dataStringEdit->EndStringEdit(1); + return 0; + } + return CallWindowProc(OldStringEditProc, hwnd, msg, wParam, lParam); +} + + + +static LRESULT CALLBACK ExpandButtonSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_LBUTTONUP: + if(GetCapture()==hwnd) + { + //do expand + RECT rcStart,rcEnd; + DWORD selStart,selEnd; + WCHAR *text; + BOOL animEnabled=TRUE; + + GetWindowRect(hwndEdit,&rcStart); + InflateRect(&rcStart,2,2); + + text = GetWindowTextUcs(hwndEdit); + SendMessage(hwndEdit,EM_GETSEL,(WPARAM)&selStart,(LPARAM)&selEnd); + DestroyWindow(hwndEdit); + EscapesToMultiline(text,&selStart,&selEnd); + hwndEdit=CreateWindowExA(WS_EX_TOOLWINDOW,"EDIT","",WS_POPUP|WS_BORDER|WS_VISIBLE|ES_WANTRETURN|ES_AUTOVSCROLL|WS_VSCROLL|ES_MULTILINE,rcStart.left,rcStart.top,rcStart.right-rcStart.left,rcStart.bottom-rcStart.top,NULL,NULL,hInst,NULL); + SetWindowTextUcs(hwndEdit, text); + OldStringEditProc=(WNDPROC)SetWindowLongPtr(hwndEdit,GWLP_WNDPROC,(LONG_PTR)StringEditSubclassProc); + SendMessage(hwndEdit,WM_SETFONT,(WPARAM)dataStringEdit->hListFont,0); + SendMessage(hwndEdit,EM_SETSEL,selStart,selEnd); + SetFocus(hwndEdit); + + rcEnd.left=rcStart.left; rcEnd.top=rcStart.top; + rcEnd.right=rcEnd.left+350; + rcEnd.bottom=rcEnd.top+150; + if (LOBYTE(LOWORD(GetVersion()))>4 || HIBYTE(LOWORD(GetVersion()))>0) + SystemParametersInfo(SPI_GETCOMBOBOXANIMATION,0,&animEnabled,FALSE); + if(animEnabled) + { + DWORD startTime,timeNow; + startTime=GetTickCount(); + for (;;) + { + UpdateWindow(hwndEdit); + timeNow=GetTickCount(); + if(timeNow>startTime+200) break; + SetWindowPos(hwndEdit,0,rcEnd.left,rcEnd.top,(rcEnd.right-rcStart.right)*(timeNow-startTime)/200+rcStart.right-rcEnd.left,(rcEnd.bottom-rcStart.bottom)*(timeNow-startTime)/200+rcStart.bottom-rcEnd.top,SWP_NOZORDER); + } + } + SetWindowPos(hwndEdit,0,rcEnd.left,rcEnd.top,rcEnd.right-rcEnd.left,rcEnd.bottom-rcEnd.top,SWP_NOZORDER); + + DestroyWindow(hwnd); + hwndExpandButton=NULL; + + SAFE_FREE((void**)&text); + } + break; + } + return CallWindowProc(OldExpandButtonProc,hwnd,msg,wParam,lParam); +} + + +void ChangeInfoData::BeginStringEdit(int iItem, RECT *rc, int i, WORD wVKey) +{ + char *szValue; + char str[80]; + int alloced=0; + + EndStringEdit(0); + InflateRect(rc,-2,-2); + rc->left-=2; + if (setting[i].displayType & LIF_PASSWORD && !settingData[i].changed) + szValue = " "; + else if ((setting[i].displayType & LIM_TYPE) == LI_NUMBER) + { + szValue = str; + null_snprintf(str, sizeof(str), "%d", settingData[i].value ); + } + else if (settingData[i].value) + { + szValue = BinaryToEscapes((char*)settingData[i].value); + alloced = 1; + } + else szValue = ""; + + iEditItem = iItem; + + if ((setting[i].displayType & LIM_TYPE)==LI_LONGSTRING) + { + rc->right-=rc->bottom-rc->top; + hwndExpandButton=CreateWindowA("BUTTON","",WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_ICON,rc->right,rc->top,rc->bottom-rc->top,rc->bottom-rc->top,hwndList,NULL,hInst,NULL); + SendMessage(hwndExpandButton,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(hInst,MAKEINTRESOURCE(IDI_EXPANDSTRINGEDIT),IMAGE_ICON,0,0,LR_SHARED)); + OldExpandButtonProc=(WNDPROC)SetWindowLongPtr(hwndExpandButton,GWLP_WNDPROC,(LONG_PTR)ExpandButtonSubclassProc); + } + + dataStringEdit = this; + hwndEdit = CreateWindow(_T("EDIT"),_T(""),WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|((setting[i].displayType&LIM_TYPE)==LI_NUMBER?ES_NUMBER:0)|(setting[i].displayType&LIF_PASSWORD?ES_PASSWORD:0),rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hwndList,NULL,hInst,NULL); + SetWindowTextUtf(hwndEdit, szValue); + if (alloced) SAFE_FREE(&szValue); + OldStringEditProc=(WNDPROC)SetWindowLongPtr(hwndEdit,GWLP_WNDPROC,(LONG_PTR)StringEditSubclassProc); + SendMessage(hwndEdit,WM_SETFONT,(WPARAM)hListFont,0); + if ((setting[i].displayType & LIM_TYPE) == LI_NUMBER) + { + int *range= (int*)setting[i].pList; + RECT rcUpDown; + hwndUpDown=CreateWindow(UPDOWN_CLASS,_T(""),WS_VISIBLE|WS_CHILD|UDS_AUTOBUDDY|UDS_ALIGNRIGHT|UDS_HOTTRACK|UDS_NOTHOUSANDS|UDS_SETBUDDYINT,0,0,0,0,hwndList,NULL,hInst,NULL); + SendMessage(hwndUpDown, UDM_SETRANGE32, range[0], range[1]); + SendMessage(hwndUpDown, UDM_SETPOS32, 0, settingData[i].value); + if (!(setting[i].displayType & LIF_ZEROISVALID) && settingData[i].value==0) + SetWindowTextA(hwndEdit, ""); + GetClientRect(hwndUpDown, &rcUpDown); + rc->right -= rcUpDown.right; + SetWindowPos(hwndEdit,0,0,0,rc->right-rc->left,rc->bottom-rc->top,SWP_NOZORDER|SWP_NOMOVE); + } + SendMessage(hwndEdit,EM_SETSEL,0,(LPARAM)-1); + SetFocus(hwndEdit); + PostMessage(hwndEdit,WM_KEYDOWN,wVKey,0); +} + + +void ChangeInfoData::EndStringEdit(int save) +{ + if (hwndEdit == NULL || iEditItem == -1 || this != dataStringEdit) return; + if (save) + { + char *text = (char*)SAFE_MALLOC(GetWindowTextLength(hwndEdit)+1); + + GetWindowTextA(hwndEdit,(char*)text,GetWindowTextLength(hwndEdit)+1); + EscapesToBinary(text); + if ((setting[iEditItem].displayType&LIM_TYPE)==LI_NUMBER) + { + LPARAM newValue; + int *range=(int*)setting[iEditItem].pList; + newValue = atoi(text); + if (newValue) + { + if (newValuerange[1]) newValue=range[1]; + } + settingData[iEditItem].changed = settingData[iEditItem].value != newValue; + settingData[iEditItem].value = newValue; + SAFE_FREE(&text); + } + else + { + if (!(setting[iEditItem].displayType & LIF_PASSWORD)) + { + SAFE_FREE(&text); + text = GetWindowTextUtf(hwndEdit); + EscapesToBinary(text); + } + if ((setting[iEditItem].displayType & LIF_PASSWORD && strcmpnull(text," ")) || + (!(setting[iEditItem].displayType & LIF_PASSWORD) && strcmpnull(text, (char*)settingData[iEditItem].value) && (strlennull(text) + strlennull((char*)settingData[iEditItem].value)))) + { + SAFE_FREE((void**)&settingData[iEditItem].value); + if (strlennull(text)) + settingData[iEditItem].value = (LPARAM)text; + else + { + settingData[iEditItem].value = 0; + SAFE_FREE(&text); + } + settingData[iEditItem].changed = 1; + } + } + if (settingData[iEditItem].changed) + { + TCHAR tbuf[MAX_PATH]; + + GetWindowText(hwndEdit, tbuf, SIZEOF(tbuf)); + ListView_SetItemText(hwndList, iEditItem, 1, tbuf); + + EnableDlgItem(hwndDlg, IDC_SAVE, TRUE); + } + } + ListView_RedrawItems(hwndList, iEditItem, iEditItem); + iEditItem = -1; + dataStringEdit = NULL; + DestroyWindow(hwndEdit); + hwndEdit = NULL; + if (hwndExpandButton) DestroyWindow(hwndExpandButton); + hwndExpandButton = NULL; + if (hwndUpDown) DestroyWindow(hwndUpDown); + hwndUpDown = NULL; +} + + + +int IsStringEditWindow(HWND hwnd) +{ + if (hwnd == hwndEdit) return 1; + if (hwnd == hwndExpandButton) return 1; + if (hwnd == hwndUpDown) return 1; + return 0; +} diff --git a/protocols/IcqOscarJ/src/changeinfo/icqoscar.h b/protocols/IcqOscarJ/src/changeinfo/icqoscar.h new file mode 100644 index 0000000000..77283f6f7f --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/icqoscar.h @@ -0,0 +1,2 @@ +/* For MinGW sake */ +#include "../icqoscar.h" diff --git a/protocols/IcqOscarJ/src/changeinfo/main.cpp b/protocols/IcqOscarJ/src/changeinfo/main.cpp new file mode 100644 index 0000000000..22669be3aa --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/main.cpp @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2008 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" diff --git a/protocols/IcqOscarJ/src/changeinfo/upload.cpp b/protocols/IcqOscarJ/src/changeinfo/upload.cpp new file mode 100644 index 0000000000..a468dc9f2b --- /dev/null +++ b/protocols/IcqOscarJ/src/changeinfo/upload.cpp @@ -0,0 +1,91 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2001-2004 Richard Hughes, Martin Öberg +// Copyright © 2004-2009 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ChangeInfo Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +int CIcqProto::StringToListItemId(const char *szSetting,int def) +{ + int i; + + for(i=0;iicqOnline()) + { + MessageBoxUtf(hwndDlg, LPGEN("You are not currently connected to the ICQ network. You must be online in order to update your information on the server."), LPGEN("Change ICQ Details"), MB_OK); + return 0; + } + + hUpload[0] = (HANDLE)ppro->ChangeInfoEx(CIXT_FULL, 0); + + //password + char* tmp = ppro->GetUserPassword(TRUE); + if (tmp) + { + if (strlennull(Password) > 0 && strcmpnull(Password, tmp)) + { + hUpload[1] = (HANDLE)ppro->icq_changeUserPasswordServ(tmp); + char szPwd[PASSWORDMAXLEN] = {0}; + + if (ppro->GetUserStoredPassword(szPwd, sizeof(szPwd))) + { // password is stored in DB, update + char ptmp[PASSWORDMAXLEN]; + + strcpy(ptmp, tmp); + + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ptmp), (LPARAM)ptmp); + + ppro->setSettingString(NULL, "Password", ptmp); + } + } + } + + return 1; +} diff --git a/protocols/IcqOscarJ/src/channels.h b/protocols/IcqOscarJ/src/channels.h new file mode 100644 index 0000000000..ba10483b56 --- /dev/null +++ b/protocols/IcqOscarJ/src/channels.h @@ -0,0 +1,47 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Header for FLAP Channel packet handlers +// +// ----------------------------------------------------------------------------- +#ifndef __CHANNELS_H +#define __CHANNELS_H + + +struct snac_header +{ + BOOL bValid; + WORD wFamily; + WORD wSubtype; + WORD wFlags; + DWORD dwRef; + WORD wVersion; +}; + +int unpackSnacHeader(snac_header *pSnacHeader, BYTE **pBuffer, WORD *pwBufferLength); + + +#endif /* __CHANNELS_H */ diff --git a/protocols/IcqOscarJ/src/cookies.cpp b/protocols/IcqOscarJ/src/cookies.cpp new file mode 100644 index 0000000000..87ffb4bc07 --- /dev/null +++ b/protocols/IcqOscarJ/src/cookies.cpp @@ -0,0 +1,301 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handles packet & message cookies +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +#define INVALID_COOKIE_INDEX -1 + +void CIcqProto::RemoveExpiredCookies() +{ + time_t tNow = time(NULL); + + for (int i = cookies.getCount()-1; i >= 0; i--) + { + icq_cookie_info *cookie = cookies[i]; + + if ((cookie->dwTime + COOKIE_TIMEOUT) < tNow) + { + cookies.remove(i); + SAFE_FREE((void**)&cookie); + } + } +} + + +// Generate and allocate cookie +DWORD CIcqProto::AllocateCookie(BYTE bType, WORD wIdent, HANDLE hContact, void *pvExtra) +{ + icq_lock l(cookieMutex); + + DWORD dwThisSeq = wCookieSeq++; + dwThisSeq &= 0x7FFF; + dwThisSeq |= wIdent<<0x10; + + icq_cookie_info* p = (icq_cookie_info*)SAFE_MALLOC(sizeof(icq_cookie_info)); + if (p) + { + p->bType = bType; + p->dwCookie = dwThisSeq; + p->hContact = hContact; + p->pvExtra = pvExtra; + p->dwTime = time(NULL); + cookies.insert(p); + } + return dwThisSeq; +} + + +DWORD CIcqProto::GenerateCookie(WORD wIdent) +{ + icq_lock l(cookieMutex); + + DWORD dwThisSeq = wCookieSeq++; + dwThisSeq &= 0x7FFF; + dwThisSeq |= wIdent<<0x10; + + return dwThisSeq; +} + + +int CIcqProto::GetCookieType(DWORD dwCookie) +{ + icq_lock l(cookieMutex); + + int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); + if ( i != INVALID_COOKIE_INDEX ) + i = cookies[i]->bType; + + return i; +} + + +int CIcqProto::FindCookie(DWORD dwCookie, HANDLE *phContact, void **ppvExtra) +{ + icq_lock l(cookieMutex); + + int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); + if (i != INVALID_COOKIE_INDEX) + { + if (phContact) + *phContact = cookies[i]->hContact; + if (ppvExtra) + *ppvExtra = cookies[i]->pvExtra; + + // Cookie found + return 1; + } + + return 0; +} + + +int CIcqProto::FindCookieByData(void *pvExtra, DWORD *pdwCookie, HANDLE *phContact) +{ + icq_lock l(cookieMutex); + + for (int i = 0; i < cookies.getCount(); i++) + { + if (pvExtra == cookies[i]->pvExtra) + { + if (phContact) + *phContact = cookies[i]->hContact; + if (pdwCookie) + *pdwCookie = cookies[i]->dwCookie; + + // Cookie found + return 1; + } + } + + return 0; +} + + +int CIcqProto::FindCookieByType(BYTE bType, DWORD *pdwCookie, HANDLE *phContact, void** ppvExtra) +{ + icq_lock l(cookieMutex); + + for (int i = 0; i < cookies.getCount(); i++) + { + if (bType == cookies[i]->bType) + { + if (pdwCookie) + *pdwCookie = cookies[i]->dwCookie; + if (phContact) + *phContact = cookies[i]->hContact; + if (ppvExtra) + *ppvExtra = cookies[i]->pvExtra; + + // Cookie found + return 1; + } + } + + return 0; +} + + +int CIcqProto::FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, HANDLE *phContact, cookie_message_data **ppvExtra) +{ + icq_lock l(cookieMutex); + + for (int i = 0; i < cookies.getCount(); i++) + { + if (cookies[i]->bType == CKT_MESSAGE || cookies[i]->bType == CKT_FILE || cookies[i]->bType == CKT_REVERSEDIRECT) + { // message cookie found + cookie_message_data *pCookie = (cookie_message_data*)cookies[i]->pvExtra; + + if (pCookie->dwMsgID1 == dwMsgID1 && pCookie->dwMsgID2 == dwMsgID2) + { + if (phContact) + *phContact = cookies[i]->hContact; + if (pdwCookie) + *pdwCookie = cookies[i]->dwCookie; + if (ppvExtra) + *ppvExtra = pCookie; + + // Cookie found + return 1; + } + } + } + + return 0; +} + + +void CIcqProto::FreeCookie(DWORD dwCookie) +{ + icq_lock l(cookieMutex); + + int i = cookies.getIndex((icq_cookie_info*)&dwCookie); + if (i != INVALID_COOKIE_INDEX) + { // Cookie found, remove from list + icq_cookie_info *cookie = cookies[i]; + + cookies.remove(i); + SAFE_FREE((void**)&cookie); + } + + RemoveExpiredCookies(); +} + + +void CIcqProto::FreeCookieByData(BYTE bType, void *pvExtra) +{ + icq_lock l(cookieMutex); + + for (int i = 0; i < cookies.getCount(); i++) + { + icq_cookie_info *cookie = cookies[i]; + + if (bType == cookie->bType && pvExtra == cookie->pvExtra) + { // Cookie found, remove from list + cookies.remove(i); + SAFE_FREE((void**)&cookie); + break; + } + } + + RemoveExpiredCookies(); +} + + +void CIcqProto::ReleaseCookie(DWORD dwCookie) +{ + icq_lock l(cookieMutex); + + int i = cookies.getIndex(( icq_cookie_info* )&dwCookie ); + if (i != INVALID_COOKIE_INDEX) + { // Cookie found, remove from list + icq_cookie_info *cookie = cookies[i]; + + cookies.remove(i); + SAFE_FREE((void**)&cookie->pvExtra); + SAFE_FREE((void**)&cookie); + } + RemoveExpiredCookies(); +} + + +void CIcqProto::InitMessageCookie(cookie_message_data *pCookie) +{ + DWORD dwMsgID1; + DWORD dwMsgID2; + + do + { // ensure that message ids are unique + dwMsgID1 = time(NULL); + dwMsgID2 = RandRange(0, 0x0FFFF); + } while (FindMessageCookie(dwMsgID1, dwMsgID2, NULL, NULL, NULL)); + + if (pCookie) + { + pCookie->dwMsgID1 = dwMsgID1; + pCookie->dwMsgID2 = dwMsgID2; + } +} + + +cookie_message_data* CIcqProto::CreateMessageCookie(WORD bMsgType, BYTE bAckType) +{ + cookie_message_data *pCookie = (cookie_message_data*)SAFE_MALLOC(sizeof(cookie_message_data)); + if (pCookie) + { + pCookie->bMessageType = bMsgType; + pCookie->nAckType = bAckType; + + InitMessageCookie(pCookie); + } + return pCookie; +} + + +cookie_message_data* CIcqProto::CreateMessageCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin, int bUseSrvRelay) +{ + BYTE bAckType; + WORD wStatus = getContactStatus(hContact); + + if (!getSettingByte(hContact, "SlowSend", getSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND)) || + (!dwUin && wStatus == ID_STATUS_OFFLINE)) + bAckType = ACKTYPE_NONE; + else if (bUseSrvRelay) + bAckType = ACKTYPE_CLIENT; + else + bAckType = ACKTYPE_SERVER; + + cookie_message_data* pCookieData = CreateMessageCookie(bMsgType, bAckType); + + // set flag for offline messages - to allow proper error handling + if (wStatus == ID_STATUS_OFFLINE || wStatus == ID_STATUS_INVISIBLE) + pCookieData->isOffline = TRUE; + + return pCookieData; +} diff --git a/protocols/IcqOscarJ/src/cookies.h b/protocols/IcqOscarJ/src/cookies.h new file mode 100644 index 0000000000..05e0d170eb --- /dev/null +++ b/protocols/IcqOscarJ/src/cookies.h @@ -0,0 +1,148 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __COOKIES_H +#define __COOKIES_H + + +#define CKT_MESSAGE 0x01 +#define CKT_FILE 0x02 +#define CKT_SEARCH 0x04 +#define CKT_SERVERLIST 0x08 +#define CKT_SERVICEREQUEST 0x0A +#define CKT_REVERSEDIRECT 0x0C +#define CKT_FAMILYSPECIAL 0x10 +#define CKT_OFFLINEMESSAGE 0x12 +#define CKT_DIRECTORY_QUERY 0x18 +#define CKT_DIRECTORY_UPDATE 0x19 +#define CKT_AVATAR 0x20 + +struct CIcqProto; + +/* Basic structure used to hold operation cookies list */ +struct icq_cookie_info +{ + DWORD dwCookie; + HANDLE hContact; + void *pvExtra; + time_t dwTime; + BYTE bType; +}; + + +/* Specific structures to hold request specific data - pvExtra */ + +struct cookie_family_request +{ + WORD wFamily; + void (CIcqProto::*familyHandler)(HANDLE hConn, char* cookie, WORD cookieLen); +}; + + +struct cookie_offline_messages +{ + int nMessages; + int nMissed; +}; + + +#define ACKTYPE_NONE 0 +#define ACKTYPE_SERVER 1 +#define ACKTYPE_CLIENT 2 + +struct cookie_message_data +{ + DWORD dwMsgID1; + DWORD dwMsgID2; + WORD bMessageType; + BYTE nAckType; + BYTE isOffline; +}; + +#define REQUESTTYPE_OWNER 0 +#define REQUESTTYPE_USERAUTO 1 +#define REQUESTTYPE_USERMINIMAL 2 +#define REQUESTTYPE_USERDETAILED 3 +#define REQUESTTYPE_PROFILE 4 + +struct cookie_fam15_data +{ + BYTE bRequestType; +}; + + +#define SEARCHTYPE_UID 0 +#define SEARCHTYPE_EMAIL 1 +#define SEARCHTYPE_NAMES 2 +#define SEARCHTYPE_DETAILS 4 + +struct cookie_search +{ + BYTE bSearchType; + char* szObject; + DWORD dwMainId; + DWORD dwStatus; +}; + + +struct cookie_avatar +{ + DWORD dwUin; + HANDLE hContact; + unsigned int hashlen; + BYTE *hash; + unsigned int cbData; + TCHAR *szFile; +}; + + +struct cookie_reverse_connect: public cookie_message_data +{ + HANDLE hContact; + DWORD dwUin; + int type; + void *ft; +}; + + +#define DIRECTORYREQUEST_INFOUSER 0x01 +#define DIRECTORYREQUEST_INFOOWNER 0x02 +#define DIRECTORYREQUEST_INFOMULTI 0x03 +#define DIRECTORYREQUEST_SEARCH 0x08 +#define DIRECTORYREQUEST_UPDATEOWNER 0x10 +#define DIRECTORYREQUEST_UPDATENOTE 0x11 +#define DIRECTORYREQUEST_UPDATEPRIVACY 0x12 + +struct cookie_directory_data +{ + BYTE bRequestType; +}; + + +#endif /* __COOKIES_H */ diff --git a/protocols/IcqOscarJ/src/directpackets.cpp b/protocols/IcqOscarJ/src/directpackets.cpp new file mode 100644 index 0000000000..594f005675 --- /dev/null +++ b/protocols/IcqOscarJ/src/directpackets.cpp @@ -0,0 +1,293 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void EncryptDirectPacket(directconnect* dc, icq_packet* p); + +void packEmptyMsg(icq_packet *packet); + +static void packDirectMsgHeader(icq_packet* packet, WORD wDataLen, WORD wCommand, DWORD dwCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wX1, WORD wX2) +{ + directPacketInit(packet, 29 + wDataLen); + packByte(packet, 2); /* channel */ + packLEDWord(packet, 0); /* space for crypto */ + packLEWord(packet, wCommand); + packLEWord(packet, 14); /* unknown */ + packLEWord(packet, (WORD)dwCookie); + packLEDWord(packet, 0); /* unknown */ + packLEDWord(packet, 0); /* unknown */ + packLEDWord(packet, 0); /* unknown */ + packByte(packet, bMsgType); + packByte(packet, bMsgFlags); + packLEWord(packet, wX1); /* unknown. Is 1 for getawaymsg, 0 otherwise */ + packLEWord(packet, wX2); // this is probably priority +} + + +void CIcqProto::icq_sendDirectMsgAck(directconnect* dc, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, char* szCap) +{ + icq_packet packet; + + packDirectMsgHeader(&packet, (WORD)(bMsgType==MTYPE_PLAIN ? (szCap ? 53 : 11) : 3), DIRECT_ACK, wCookie, bMsgType, bMsgFlags, 0, 0); + packEmptyMsg(&packet); /* empty message */ + + if (bMsgType == MTYPE_PLAIN) + { + packMsgColorInfo(&packet); + + if (szCap) + { + packLEDWord(&packet, 0x26); /* CLSID length */ + packBuffer(&packet, (LPBYTE)szCap, 0x26); /* GUID */ + } + } + EncryptDirectPacket(dc, &packet); + sendDirectPacket(dc, &packet); + + NetLog_Direct("Sent acknowledgement thru direct connection"); +} + + +DWORD CIcqProto::icq_sendGetAwayMsgDirect(HANDLE hContact, int type) +{ + icq_packet packet; + DWORD dwCookie; + cookie_message_data *pCookieData; + + if (getSettingWord(hContact, "Version", 0) == 9) + return 0; // v9 DC protocol does not support this message + + pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); + dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + packDirectMsgHeader(&packet, 3, DIRECT_MESSAGE, dwCookie, (BYTE)type, 3, 1, 0); + packEmptyMsg(&packet); // message + + return (SendDirectMessage(hContact, &packet)) ? dwCookie : 0; +} + + +void CIcqProto::icq_sendAwayMsgReplyDirect(directconnect* dc, WORD wCookie, BYTE msgType, const char** szMsg) +{ + icq_packet packet; + + if (validateStatusMessageRequest(dc->hContact, msgType)) + { + NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dc->dwRemoteUin); + + icq_lock l(m_modeMsgsMutex); + + if (szMsg && *szMsg) + { + // prepare Ansi message - only Ansi supported + WORD wMsgLen = strlennull(*szMsg) + 1; + char *szAnsiMsg = (char*)_alloca(wMsgLen); + + utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); + wMsgLen = strlennull(szAnsiMsg); + packDirectMsgHeader(&packet, (WORD)(3 + wMsgLen), DIRECT_ACK, wCookie, msgType, 3, 0, 0); + packLEWord(&packet, (WORD)(wMsgLen + 1)); + packBuffer(&packet, (LPBYTE)szAnsiMsg, (WORD)(wMsgLen + 1)); + EncryptDirectPacket(dc, &packet); + + sendDirectPacket(dc, &packet); + } + } +} + + +void CIcqProto::icq_sendFileAcceptDirect(HANDLE hContact, filetransfer* ft) +{ + // v7 packet + icq_packet packet; + + packDirectMsgHeader(&packet, 18, DIRECT_ACK, ft->dwCookie, MTYPE_FILEREQ, 0, 0, 0); + packLEWord(&packet, 1); // description + packByte(&packet, 0); + packWord(&packet, wListenPort); + packLEWord(&packet, 0); + packLEWord(&packet, 1); // filename + packByte(&packet, 0); // TODO: really send filename + packLEDWord(&packet, ft->dwTotalSize); // file size + packLEDWord(&packet, wListenPort); // FIXME: ideally we want to open a new port for this + + SendDirectMessage(hContact, &packet); + + NetLog_Direct("Sent file accept direct, port %u", wListenPort); +} + + +void CIcqProto::icq_sendFileDenyDirect(HANDLE hContact, filetransfer *ft, const char *szReason) +{ + // v7 packet + icq_packet packet; + char *szReasonAnsi = NULL; + int cbReasonAnsi = 0; + + if (!utf8_decode(szReason, &szReasonAnsi)) + szReasonAnsi = NULL; + else + cbReasonAnsi = strlennull(szReasonAnsi); + + packDirectMsgHeader(&packet, (WORD)(18 + cbReasonAnsi), DIRECT_ACK, ft->dwCookie, MTYPE_FILEREQ, 0, 1, 0); + packLEWord(&packet, (WORD)(1 + cbReasonAnsi)); // description + if (szReasonAnsi) packBuffer(&packet, (LPBYTE)szReasonAnsi, (WORD)cbReasonAnsi); + packByte(&packet, 0); + packWord(&packet, 0); + packLEWord(&packet, 0); + packLEWord(&packet, 1); // filename + packByte(&packet, 0); // TODO: really send filename + packLEDWord(&packet, 0); // file size + packLEDWord(&packet, 0); + + SAFE_FREE(&szReasonAnsi); + + SendDirectMessage(hContact, &packet); + + NetLog_Direct("Sent file deny direct."); +} + + +int CIcqProto::icq_sendFileSendDirectv7(filetransfer *ft, const char *pszFiles) +{ + icq_packet packet; + char *szFilesAnsi = NULL; + WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = 0; + + if (!utf8_decode(pszFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + else + wFilesLen = strlennull(szFilesAnsi); + + packDirectMsgHeader(&packet, (WORD)(18 + wDescrLen + wFilesLen), DIRECT_MESSAGE, (WORD)ft->dwCookie, MTYPE_FILEREQ, 0, 0, 0); + packLEWord(&packet, (WORD)(wDescrLen + 1)); + packBuffer(&packet, (LPBYTE)ft->szDescription, (WORD)(wDescrLen + 1)); + packLEDWord(&packet, 0); // listen port + packLEWord(&packet, (WORD)(wFilesLen + 1)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packLEDWord(&packet, ft->dwTotalSize); + packLEDWord(&packet, 0); // listen port (again) + + SAFE_FREE(&szFilesAnsi); + + NetLog_Direct("Sending v%u file transfer request direct", 7); + + return SendDirectMessage(ft->hContact, &packet); +} + + +int CIcqProto::icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles) +{ + icq_packet packet; + char *szFilesAnsi = NULL; + WORD wDescrLen = strlennull(ft->szDescription), wFilesLen = 0; + + if (!utf8_decode(pszFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + else + wFilesLen = strlennull(szFilesAnsi); + + packDirectMsgHeader(&packet, (WORD)(0x2E + 22 + wDescrLen + wFilesLen + 1), DIRECT_MESSAGE, (WORD)ft->dwCookie, MTYPE_PLUGIN, 0, 0, 0); + packEmptyMsg(&packet); // message + packPluginTypeId(&packet, MTYPE_FILEREQ); + + packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length + packLEDWord(&packet, wDescrLen); // Description + packBuffer(&packet, (LPBYTE)ft->szDescription, wDescrLen); + packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6 + packWord(&packet, 0x0222); // Unknown, seen 0x2e01 + packLEWord(&packet, (WORD)(wFilesLen + 1)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packLEDWord(&packet, ft->dwTotalSize); + packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000) + + SAFE_FREE(&szFilesAnsi); + + NetLog_Direct("Sending v%u file transfer request direct", 8); + + return SendDirectMessage(ft->hContact, &packet); +} + + +DWORD CIcqProto::icq_SendDirectMessage(HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap) +{ + icq_packet packet; + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + // Pack the standard header + packDirectMsgHeader(&packet, (WORD)(nBodyLength + (szCap ? 53:11)), DIRECT_MESSAGE, dwCookie, (BYTE)pCookieData->bMessageType, 0, 0, 0); + + packLEWord(&packet, (WORD)(nBodyLength+1)); // Length of message + packBuffer(&packet, (LPBYTE)szMessage, (WORD)(nBodyLength+1)); // Message + packMsgColorInfo(&packet); + if (szCap) + { + packLEDWord(&packet, 0x00000026); // length of GUID + packBuffer(&packet, (LPBYTE)szCap, 0x26); // UTF-8 GUID + } + + if (SendDirectMessage(hContact, &packet)) + return dwCookie; // Success + + FreeCookie(dwCookie); // release cookie + return 0; // Failure +} + +void CIcqProto::icq_sendXtrazRequestDirect(HANDLE hContact, DWORD dwCookie, char* szBody, int nBodyLen, WORD wType) +{ + icq_packet packet; + + packDirectMsgHeader(&packet, (WORD)(11 + getPluginTypeIdLen(wType) + nBodyLen), DIRECT_MESSAGE, dwCookie, MTYPE_PLUGIN, 0, 0, 1); + packEmptyMsg(&packet); // message (unused) + packPluginTypeId(&packet, wType); + + packLEDWord(&packet, nBodyLen + 4); + packLEDWord(&packet, nBodyLen); + packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); + + SendDirectMessage(hContact, &packet); +} + +void CIcqProto::icq_sendXtrazResponseDirect(HANDLE hContact, WORD wCookie, char* szBody, int nBodyLen, WORD wType) +{ + icq_packet packet; + + packDirectMsgHeader(&packet, (WORD)(getPluginTypeIdLen(wType) + 11 + nBodyLen), DIRECT_ACK, wCookie, MTYPE_PLUGIN, 0, 0, 0); + // + packEmptyMsg(&packet); // Message (unused) + + packPluginTypeId(&packet, wType); + + packLEDWord(&packet, nBodyLen + 4); + packLEDWord(&packet, nBodyLen); + packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); + + SendDirectMessage(hContact, &packet); +} diff --git a/protocols/IcqOscarJ/src/fam_01service.cpp b/protocols/IcqOscarJ/src/fam_01service.cpp new file mode 100644 index 0000000000..9bc06f19ab --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_01service.cpp @@ -0,0 +1,983 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handles packets from Service family +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" +#include + +extern capstr capXStatus[]; + +void CIcqProto::handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) +{ + icq_packet packet; + + switch (pSnacHeader->wSubtype) { + + case ICQ_SERVER_READY: +#ifdef _DEBUG + NetLog_Server("Server is ready and is requesting my Family versions"); + NetLog_Server("Sending my Families"); +#endif + + // This packet is a response to SRV_FAMILIES SNAC(1,3). + // This tells the server which SNAC families and their corresponding + // versions which the client understands. This also seems to identify + // the client as an ICQ vice AIM client to the server. + // Miranda mimics the behaviour of ICQ 6 + serverPacketInit(&packet, 54); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES); + packDWord(&packet, 0x00220001); + packDWord(&packet, 0x00010004); + packDWord(&packet, 0x00130004); + packDWord(&packet, 0x00020001); + packDWord(&packet, 0x00030001); + packDWord(&packet, 0x00150001); + packDWord(&packet, 0x00040001); + packDWord(&packet, 0x00060001); + packDWord(&packet, 0x00090001); + packDWord(&packet, 0x000a0001); + packDWord(&packet, 0x000b0001); + sendServPacket(&packet); + break; + + case ICQ_SERVER_FAMILIES2: + /* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands. + * We send a rate request packet */ +#ifdef _DEBUG + NetLog_Server("Server told me his Family versions"); + NetLog_Server("Requesting Rate Information"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO); + sendServPacket(&packet); + break; + + case ICQ_SERVER_RATE_INFO: +#ifdef _DEBUG + NetLog_Server("Server sent Rate Info"); +#endif + /* init rates management */ + m_rates = new rates(this, pBuffer, wBufferLength); + /* ack rate levels */ +#ifdef _DEBUG + NetLog_Server("Sending Rate Info Ack"); +#endif + m_rates->initAckPacket(&packet); + sendServPacket(&packet); + + /* CLI_REQINFO - This command requests from the server certain information about the client that is stored on the server. */ +#ifdef _DEBUG + NetLog_Server("Sending CLI_REQINFO"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQINFO); + sendServPacket(&packet); + + if (m_bSsiEnabled) + { + cookie_servlist_action* ack; + DWORD dwCookie; + + DWORD dwLastUpdate = getSettingDword(NULL, "SrvLastUpdate", 0); + WORD wRecordCount = getSettingWord(NULL, "SrvRecordCount", 0); + + // CLI_REQLISTS - we want to use SSI +#ifdef _DEBUG + NetLog_Server("Requesting roster rights"); +#endif + serverPacketInit(&packet, 16); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQLISTS); + packTLVWord(&packet, 0x0B, 0x000F); // mimic ICQ 6 + sendServPacket(&packet); + + if (!wRecordCount) // CLI_REQROSTER + { // we do not have any data - request full list +#ifdef _DEBUG + NetLog_Server("Requesting full roster"); +#endif + serverPacketInit(&packet, 10); + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { // we try to use standalone cookie if available + ack->dwAction = SSA_CHECK_ROSTER; // loading list + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_REQUEST, 0, ack); + } + else // if not use that old fake + dwCookie = ICQ_LISTS_CLI_REQUEST<<0x10; + + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQUEST, 0, dwCookie); + sendServPacket(&packet); + } + else // CLI_CHECKROSTER + { +#ifdef _DEBUG + NetLog_Server("Requesting roster check"); +#endif + serverPacketInit(&packet, 16); + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) // TODO: rewrite - use get list service for empty list + { // we try to use standalone cookie if available + ack->dwAction = SSA_CHECK_ROSTER; // loading list + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_CHECK, 0, ack); + } + else // if not use that old fake + dwCookie = ICQ_LISTS_CLI_CHECK<<0x10; + + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_CHECK, 0, dwCookie); + // check if it was not changed elsewhere (force reload, set that setting to zero) + if (IsServerGroupsDefined()) + { + packDWord(&packet, dwLastUpdate); // last saved time + packWord(&packet, wRecordCount); // number of records saved + } + else + { // we need to get groups info into DB, force receive list + packDWord(&packet, 0); // last saved time + packWord(&packet, 0); // number of records saved + } + sendServPacket(&packet); + } + } + + // CLI_REQLOCATION +#ifdef _DEBUG + NetLog_Server("Requesting Location rights"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_CLI_REQ_RIGHTS); + sendServPacket(&packet); + + // CLI_REQBUDDY +#ifdef _DEBUG + NetLog_Server("Requesting Client-side contactlist rights"); +#endif + serverPacketInit(&packet, 16); + packFNACHeader(&packet, ICQ_BUDDY_FAMILY, ICQ_USER_CLI_REQBUDDY); + // Query flags: 1 = Enable Avatars + // 2 = Enable offline status message notification + // 4 = Enable Avatars for offline contacts + // 8 = Use reject for not authorized contacts + packTLVWord(&packet, 0x05, 0x0007); + sendServPacket(&packet); + + // CLI_REQICBM +#ifdef _DEBUG + NetLog_Server("Sending CLI_REQICBM"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQICBM); + sendServPacket(&packet); + + // CLI_REQBOS +#ifdef _DEBUG + NetLog_Server("Sending CLI_REQBOS"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_BOS_FAMILY, ICQ_PRIVACY_REQ_RIGHTS); + sendServPacket(&packet); + break; + + case ICQ_SERVER_PAUSE: + NetLog_Server("Server is going down in a few seconds... (Flags: %u)", pSnacHeader->wFlags); + // This is the list of groups that we want to have on the next server + serverPacketInit(&packet, 30); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_PAUSE_ACK); + packWord(&packet,ICQ_SERVICE_FAMILY); + packWord(&packet,ICQ_LISTS_FAMILY); + packWord(&packet,ICQ_LOCATION_FAMILY); + packWord(&packet,ICQ_BUDDY_FAMILY); + packWord(&packet,ICQ_EXTENSIONS_FAMILY); + packWord(&packet,ICQ_MSG_FAMILY); + packWord(&packet,0x06); + packWord(&packet,ICQ_BOS_FAMILY); + packWord(&packet,ICQ_LOOKUP_FAMILY); + packWord(&packet,ICQ_STATS_FAMILY); + sendServPacket(&packet); +#ifdef _DEBUG + NetLog_Server("Sent server pause ack"); +#endif + break; + + case ICQ_SERVER_MIGRATIONREQ: + { +#ifdef _DEBUG + NetLog_Server("Server migration requested (Flags: %u)", pSnacHeader->wFlags); +#endif + pBuffer += 2; // Unknown, seen: 0 + wBufferLength -= 2; + + oscar_tlv_chain *chain = readIntoTLVChain(&pBuffer, wBufferLength, 0); + + if (info->cookieDataLen > 0) + SAFE_FREE((void**)&info->cookieData); + + info->newServer = chain->getString(0x05, 1); + info->newServerSSL = chain->getNumber(0x8E, 1); + info->cookieData = (BYTE*)chain->getString(0x06, 1); + info->cookieDataLen = chain->getLength(0x06, 1); + + disposeChain(&chain); + + if (!info->newServer || !info->cookieData) + { + icq_LogMessage(LOG_FATAL, LPGEN("A server migration has failed because the server returned invalid data. You must reconnect manually.")); + SAFE_FREE(&info->newServer); + SAFE_FREE((void**)&info->cookieData); + info->cookieDataLen = 0; + info->newServerReady = 0; + return; + } + + NetLog_Server("Migration has started. New server will be %s", info->newServer); + + m_iDesiredStatus = m_iStatus; + SetCurrentStatus(ID_STATUS_CONNECTING); // revert to connecting state + + info->newServerReady = 1; + info->isMigrating = 1; + } + break; + + case ICQ_SERVER_NAME_INFO: // This is the reply to CLI_REQINFO + { + BYTE bUinLen; + oscar_tlv_chain *chain; + +#ifdef _DEBUG + NetLog_Server("Received self info"); +#endif + unpackByte(&pBuffer, &bUinLen); + pBuffer += bUinLen; + pBuffer += 4; /* warning level & user class */ + wBufferLength -= 5 + bUinLen; + + if (pSnacHeader->dwRef == ICQ_CLIENT_REQINFO<<0x10) + { // This is during the login sequence + DWORD dwValue; + + // TLV(x01) User type? + // TLV(x0C) Empty CLI2CLI Direct connection info + // TLV(x0A) External IP + // TLV(x0F) Number of seconds that user has been online + // TLV(x03) The online since time. + // TLV(x0A) External IP again + // TLV(x22) Unknown + // TLV(x1E) Unknown: empty. + // TLV(x05) Member of ICQ since. + // TLV(x14) Unknown + chain = readIntoTLVChain(&pBuffer, wBufferLength, 0); + + // Save external IP + dwValue = chain->getDWord(0x0A, 1); + setSettingDword(NULL, "IP", dwValue); + + // Save member since timestamp + dwValue = chain->getDWord(0x05, 1); + if (dwValue) setSettingDword(NULL, "MemberTS", dwValue); + + dwValue = chain->getDWord(0x03, 1); + setSettingDword(NULL, "LogonTS", dwValue ? dwValue : time(NULL)); + + disposeChain(&chain); + + // If we are in SSI mode, this is sent after the list is acked instead + // to make sure that we don't set status before seing the visibility code + if (!m_bSsiEnabled || info->isMigrating) + handleServUINSettings(wListenPort, info); + } + else if (m_hNotifyNameInfoEvent) + // Just notify that the set status note & mood process is finished + SetEvent(m_hNotifyNameInfoEvent); + } + break; + + case ICQ_SERVER_RATE_CHANGE: + + if (wBufferLength >= 2) + { + WORD wStatus; + WORD wClass; + DWORD dwLevel; + // We now have global rate management, although controlled are only some + // areas. This should not arrive in most cases. If it does, update our + // local rate levels & issue broadcast. + unpackWord(&pBuffer, &wStatus); + unpackWord(&pBuffer, &wClass); + pBuffer += 20; + unpackDWord(&pBuffer, &dwLevel); + + m_ratesMutex->Enter(); + m_rates->updateLevel(wClass, dwLevel); + m_ratesMutex->Leave(); + + if (wStatus == 2 || wStatus == 3) + { // this is only the simplest solution, needs rate management to every section + BroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus); + if (wStatus == 2) + NetLog_Server("Rates #%u: Alert", wClass); + else + NetLog_Server("Rates #%u: Limit", wClass); + } + else if (wStatus == 4) + { + BroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus); + NetLog_Server("Rates #%u: Clear", wClass); + } + } + + break; + + case ICQ_SERVER_REDIRECT_SERVICE: // reply to family request, got new connection point + { + oscar_tlv_chain *pChain = NULL; + cookie_family_request *pCookieData; + + if (!(pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0))) + { + NetLog_Server("Received Broken Redirect Service SNAC(1,5)."); + break; + } + WORD wFamily = pChain->getWord(0x0D, 1); + + // pick request data + if ((!FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) || (pCookieData->wFamily != wFamily)) + { + disposeChain(&pChain); + NetLog_Server("Received unexpected SNAC(1,5), skipping."); + break; + } + + FreeCookie(pSnacHeader->dwRef); + + { // new family entry point received + char *pServer = pChain->getString(0x05, 1); + BYTE bServerSSL = pChain->getNumber(0x8E, 1); + char *pCookie = pChain->getString(0x06, 1); + WORD wCookieLen = pChain->getLength(0x06, 1); + + if (!pServer || !pCookie) + { + NetLog_Server("Server returned invalid data, family unavailable."); + + SAFE_FREE(&pServer); + SAFE_FREE(&pCookie); + SAFE_FREE((void**)&pCookieData); + disposeChain(&pChain); + break; + } + + // Get new family server ip and port + WORD wPort = info->wServerPort; // get default port + parseServerAddress(pServer, &wPort); + + // establish connection + NETLIBOPENCONNECTION nloc = {0}; + if (m_bGatewayMode) + nloc.flags |= NLOCF_HTTPGATEWAY; + nloc.szHost = pServer; + nloc.wPort = wPort; + + HANDLE hConnection = NetLib_OpenConnection(m_hServerNetlibUser, wFamily == ICQ_AVATAR_FAMILY ? "Avatar " : NULL, &nloc); + + if (hConnection == NULL) + { + NetLog_Server("Unable to connect to ICQ new family server."); + } // we want the handler to be called even if the connecting failed + else if (bServerSSL) + { /* Start SSL session if requested */ +#ifdef _DEBUG + NetLog_Server("(%d) Starting SSL negotiation", CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0)); +#endif + if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hConnection, 0)) + { + NetLog_Server("Unable to connect to ICQ new family server, SSL could not be negotiated"); + NetLib_CloseConnection(&hConnection, FALSE); + } + } + + (this->*pCookieData->familyHandler)(hConnection, pCookie, wCookieLen); + + // Free allocated memory + // NOTE: "cookie" will get freed when we have connected to the avatar server. + disposeChain(&pChain); + SAFE_FREE(&pServer); + SAFE_FREE((void**)&pCookieData); + } + + break; + } + + case ICQ_SERVER_EXTSTATUS: // our session data + { +#ifdef _DEBUG + NetLog_Server("Received owner session data."); +#endif + while (wBufferLength > 4) + { // loop thru all items + WORD itemType = pBuffer[0] * 0x10 | pBuffer[1]; + BYTE itemFlags = pBuffer[2]; + BYTE itemLen = pBuffer[3]; + + if (itemType == AVATAR_HASH_PHOTO) /// TODO: handle photo item + { // skip photo item +#ifdef _DEBUG + NetLog_Server("Photo item recognized"); +#endif + } + else if ((itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH) && (itemLen >= 0x10)) + { +#ifdef _DEBUG + NetLog_Server("Avatar item recognized"); +#endif + if (m_bAvatarsEnabled && !info->bMyAvatarInited) // signal the server after login + { // this refreshes avatar state - it used to work automatically, but now it does not + if (getSettingByte(NULL, "ForceOurAvatar", 0)) + { // keep our avatar + TCHAR *file = GetOwnAvatarFileName(); + SetMyAvatar(0, (LPARAM)file); + SAFE_FREE(&file); + } + else // only change avatar hash to the same one + { + BYTE hash[0x14]; + + memcpy(hash, pBuffer, 0x14); + hash[2] = 1; // update image status + updateServAvatarHash(hash, 0x14); + } + info->bMyAvatarInited = TRUE; + break; + } + // process owner avatar hash changed notification + handleAvatarOwnerHash(itemType, itemFlags, pBuffer, itemLen + 4); + } + else if (itemType == 0x02) + { +#ifdef _DEBUG + NetLog_Server("Status message item recognized"); +#endif + } + else if (itemType == 0x0E) + { +#ifdef _DEBUG + NetLog_Server("Status mood item recognized"); +#endif + } + + // move to next item + if (wBufferLength >= itemLen + 4) + { + wBufferLength -= itemLen + 4; + pBuffer += itemLen + 4; + } + else + { + pBuffer += wBufferLength; + wBufferLength = 0; + } + } + break; + } + + case ICQ_ERROR: + { // Something went wrong, probably the request for avatar family failed + WORD wError; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + LogFamilyError(ICQ_SERVICE_FAMILY, wError); + break; + } + + // Stuff we don't care about + case ICQ_SERVER_MOTD: +#ifdef _DEBUG + NetLog_Server("Server message of the day"); +#endif + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + } +} + + +char* CIcqProto::buildUinList(int subtype, WORD wMaxLen, HANDLE* hContactResume) +{ + char* szList; + HANDLE hContact; + WORD wCurrentLen = 0; + DWORD dwUIN; + uid_str szUID; + char szLen[2]; + int add; + + szList = (char*)SAFE_MALLOC(CallService(MS_DB_CONTACT_GETCOUNT, 0, 0) * UINMAXLEN); + szLen[1] = '\0'; + + if (*hContactResume) + hContact = *hContactResume; + else + hContact = FindFirstContact(); + + while (hContact != NULL) + { + if (!getContactUid(hContact, &dwUIN, &szUID)) + { + szLen[0] = strlennull(strUID(dwUIN, szUID)); + + switch (subtype) + { + + case BUL_VISIBLE: + add = ID_STATUS_ONLINE == getSettingWord(hContact, "ApparentMode", 0); + break; + + case BUL_INVISIBLE: + add = ID_STATUS_OFFLINE == getSettingWord(hContact, "ApparentMode", 0); + break; + + case BUL_TEMPVISIBLE: + add = getSettingByte(hContact, "TemporaryVisible", 0); + // clear temporary flag + // Here we assume that all temporary contacts will be in one packet + setSettingByte(hContact, "TemporaryVisible", 0); + break; + + default: + add = 1; + + // If we are in SS mode, we only add those contacts that are + // not in our SS list, or are awaiting authorization, to our + // client side list + if (m_bSsiEnabled && getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) && + !getSettingByte(hContact, "Auth", 0)) + add = 0; + + // Never add hidden contacts to CS list + if (DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) + add = 0; + + break; + } + + if (add) + { + wCurrentLen += szLen[0] + 1; + if (wCurrentLen > wMaxLen) + { + *hContactResume = hContact; + return szList; + } + + strcat(szList, szLen); + strcat(szList, szUID); + } + } + + hContact = FindNextContact(hContact); + } + *hContactResume = NULL; + + return szList; +} + + +void CIcqProto::sendEntireListServ(WORD wFamily, WORD wSubtype, int listType) +{ + HANDLE hResumeContact = NULL; + + do + { // server doesn't seem to be able to cope with packets larger than 8k + // send only about 100contacts per packet + char *szList = buildUinList(listType, 0x3E8, &hResumeContact); + int nListLen = strlennull(szList); + + if (nListLen) + { + icq_packet packet; + + serverPacketInit(&packet, (WORD)(nListLen + 10)); + packFNACHeader(&packet, wFamily, wSubtype); + packBuffer(&packet, (LPBYTE)szList, (WORD)nListLen); + sendServPacket(&packet); + } + + SAFE_FREE((void**)&szList); + } + while (hResumeContact); +} + + +static void packShortCapability(icq_packet *packet, WORD wCapability) +{ // pack standard capability + DWORD dwQ1 = 0x09460000 | wCapability; + + packDWord(packet, dwQ1); + packDWord(packet, 0x4c7f11d1); + packDWord(packet, 0x82224445); + packDWord(packet, 0x53540000); +} + + +// CLI_SETUSERINFO +void CIcqProto::setUserInfo() +{ + icq_packet packet; + WORD wAdditionalData = 0; + BYTE bXStatus = getContactXStatus(NULL); + + if (m_bAimEnabled) + wAdditionalData += 16; +#ifdef DBG_CAPMTN + wAdditionalData += 16; +#endif + if (m_bUtfEnabled) + wAdditionalData += 16; +#ifdef DBG_NEWCAPS + wAdditionalData += 16; +#endif +#ifdef DBG_CAPXTRAZ + wAdditionalData += 16; +#endif +#ifdef DBG_OSCARFT + wAdditionalData += 16; +#endif + if (m_bAvatarsEnabled) + wAdditionalData += 16; + if (m_bXStatusEnabled && bXStatus != 0) + wAdditionalData += 16; +#ifdef DBG_CAPHTML + wAdditionalData += 16; +#endif +#ifdef DBG_AIMCONTACTSEND + wAdditionalData += 16; +#endif + + wAdditionalData += (WORD)CustomCapList.size() * 16; + + //MIM/PackName + bool bHasPackName = false; + DBVARIANT dbv; + if ( !DBGetContactSettingString(NULL, "ICQCaps", "PackName", &dbv )) { + //MIM/PackName + bHasPackName = true; + wAdditionalData += 16; + } + + serverPacketInit(&packet, (WORD)(62 + wAdditionalData)); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO); + + /* TLV(5): capability data */ + packWord(&packet, 0x0005); + packWord(&packet, (WORD)(48 + wAdditionalData)); + +#ifdef DBG_CAPMTN + { + packDWord(&packet, 0x563FC809); // CAP_TYPING + packDWord(&packet, 0x0B6F41BD); + packDWord(&packet, 0x9F794226); + packDWord(&packet, 0x09DFA2F3); + } +#endif + { + packShortCapability(&packet, 0x1349); // AIM_CAPS_ICQSERVERRELAY + } + if (m_bUtfEnabled) + { + packShortCapability(&packet, 0x134E); // CAP_UTF8MSGS + } // Broadcasts the capability to receive UTF8 encoded messages +#ifdef DBG_NEWCAPS + { + packShortCapability(&packet, 0x0000); // CAP_SHORTCAPS + } // Tells server we understand to new format of caps +#endif +#ifdef DBG_CAPXTRAZ + { + packDWord(&packet, 0x1a093c6c); // CAP_XTRAZ + packDWord(&packet, 0xd7fd4ec5); // Broadcasts the capability to handle + packDWord(&packet, 0x9d51a647); // Xtraz + packDWord(&packet, 0x4e34f5a0); + } +#endif + if (m_bAvatarsEnabled) + { + packShortCapability(&packet, 0x134C); // CAP_DEVILS + } +#ifdef DBG_OSCARFT + { + packShortCapability(&packet, 0x1343); // CAP_AIM_FILE + } // Broadcasts the capability to receive Oscar File Transfers +#endif + if (m_bAimEnabled) + { + packShortCapability(&packet, 0x134D); // CAP_AIM_COMPATIBLE + } // Tells the server we can speak to AIM +#ifdef DBG_AIMCONTACTSEND + { + packShortCapability(&packet, 0x134B); // CAP_SENDBUDDYLIST + } +#endif + if (m_bXStatusEnabled && bXStatus != 0) + { + packBuffer(&packet, capXStatus[bXStatus-1], BINARY_CAP_SIZE); + } + + packShortCapability(&packet, 0x1344); // CAP_ICQDIRECT + +#ifdef DBG_CAPHTML + packShortCapability(&packet, 0x0002); // CAP_HTMLMSGS +#endif + + packDWord(&packet, 0x4D697261); // Miranda Signature + packDWord(&packet, 0x6E64614E); + + int v[4] = { MIRANDA_VERSION_FILEVERSION }; + packWord(&packet, v[0]); + packWord(&packet, v[1]); + packWord(&packet, v[2]); + packWord(&packet, v[3]); + + //MIM/PackName + if ( bHasPackName ) { + packBuffer(&packet, (BYTE*)dbv.pszVal, 0x10); + ICQFreeVariant(&dbv); + } + + if(!CustomCapList.empty()) + { + for(std::list::iterator it = CustomCapList.begin(), end = CustomCapList.end(); it != end; ++it) + packBuffer(&packet, (BYTE*)(*it)->caps, 0x10); + } + + sendServPacket(&packet); +} + + +void CIcqProto::handleServUINSettings(int nPort, serverthread_info *info) +{ + icq_packet packet; + + setUserInfo(); + + /* SNAC 3,4: Tell server who's on our list (deprecated) */ + /* SNAC 3,15: Try to add unauthorised contacts to temporary list */ + sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST, BUL_ALLCONTACTS); + + if (m_iDesiredStatus == ID_STATUS_INVISIBLE) + { + /* Tell server who's on our visible list (deprecated) */ + if (!m_bSsiEnabled) + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE); + else + updateServVisibilityCode(3); + } + + if (m_iDesiredStatus != ID_STATUS_INVISIBLE) + { + /* Tell server who's on our invisible list (deprecated) */ + if (!m_bSsiEnabled) + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE); + else + updateServVisibilityCode(4); + } + + // SNAC 1,1E: Set status + { + DWORD dwDirectCookie = rand() ^ (rand() << 16); + + // Get status + WORD wStatus = MirandaStatusToIcq(m_iDesiredStatus); + + // Get status note & mood + char *szStatusNote = PrepareStatusNote(m_iDesiredStatus); + BYTE bXStatus = getContactXStatus(NULL); + char szMoodData[32]; + + // prepare mood id + if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus-1] != -1) + null_snprintf(szMoodData, SIZEOF(szMoodData), "icqmood%d", moodXStatus[bXStatus-1]); + else + szMoodData[0] = '\0'; + + //! Tricky code, this ensures that the status note will be saved to the directory + SetStatusNote(szStatusNote, m_bGatewayMode ? 5000 : 2500, TRUE); + + WORD wStatusNoteLen = strlennull(szStatusNote); + WORD wStatusMoodLen = strlennull(szMoodData); + WORD wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; + + serverPacketInit(&packet, (WORD)(71 + (wSessionDataLen ? wSessionDataLen + 4 : 0))); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); + packDWord(&packet, 0x00060004); // TLV 6: Status mode and security flags + packWord(&packet, GetMyStatusFlags()); // Status flags + packWord(&packet, wStatus); // Status + packTLVWord(&packet, 0x0008, 0x0A06); // TLV 8: Independent Status Messages + packDWord(&packet, 0x000c0025); // TLV C: Direct connection info + packDWord(&packet, getSettingDword(NULL, "RealIP", 0)); + packDWord(&packet, nPort); + packByte(&packet, DC_TYPE); // TCP/FLAG firewall settings + packWord(&packet, ICQ_VERSION); + packDWord(&packet, dwDirectCookie); // DC Cookie + packDWord(&packet, WEBFRONTPORT); // Web front port + packDWord(&packet, CLIENTFEATURES); // Client features + packDWord(&packet, 0x7fffffff); // Abused timestamp + packDWord(&packet, ICQ_PLUG_VERSION); // Abused timestamp + if (ServiceExists("SecureIM/IsContactSecured")) + packDWord(&packet, 0x5AFEC0DE); // SecureIM Abuse + else + packDWord(&packet, 0x00000000); // Timestamp + packWord(&packet, 0x0000); // Unknown + packTLVWord(&packet, 0x001F, 0x0000); + + if (wSessionDataLen) + { // Pack session data + packWord(&packet, 0x1D); // TLV 1D + packWord(&packet, wSessionDataLen); // TLV length + packWord(&packet, 0x02); // Item Type + if (wStatusNoteLen) + { + packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length + packWord(&packet, wStatusNoteLen); // Text Length + packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen); + packWord(&packet, 0); // Encoding not specified (utf-8 is default) + } + else + packWord(&packet, 0); // Flags + Item Length + packWord(&packet, 0x0E); // Item Type + packWord(&packet, wStatusMoodLen); // Flags + Item Length + if (wStatusMoodLen) + packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood + + // Save current status note & mood + setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, szStatusNote); + setSettingString(NULL, DBSETTING_STATUS_MOOD, szMoodData); + } + // Release memory + SAFE_FREE(&szStatusNote); + + sendServPacket(&packet); + } + + /* SNAC 1,11 */ + serverPacketInit(&packet, 14); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE); + packDWord(&packet, 0x00000000); + + sendServPacket(&packet); + m_bIdleAllow = 0; + + // Change status + SetCurrentStatus(m_iDesiredStatus); + + // Finish Login sequence + serverPacketInit(&packet, 98); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY); + packDWord(&packet, 0x00220001); // imitate ICQ 6 behaviour + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00010004); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00130004); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00020001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00030001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00150001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00040001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00060001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x00090001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x000A0001); + packDWord(&packet, 0x0110164f); + packDWord(&packet, 0x000B0001); + packDWord(&packet, 0x0110164f); + + sendServPacket(&packet); + + NetLog_Server(" *** Yeehah, login sequence complete"); + + // login sequence is complete enter logged-in mode + info->bLoggedIn = 1; + m_bConnectionLost = FALSE; + + // enable auto info-update routine + icq_EnableUserLookup(TRUE); + + if (!info->isMigrating) + { /* Get Offline Messages Reqeust */ + cookie_offline_messages *ack = (cookie_offline_messages*)SAFE_MALLOC(sizeof(cookie_offline_messages)); + if (ack) + { + DWORD dwCookie = AllocateCookie(CKT_OFFLINEMESSAGE, ICQ_MSG_CLI_REQ_OFFLINE, 0, ack); + + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQ_OFFLINE, 0, dwCookie); + + sendServPacket(&packet); + } + else + icq_LogMessage(LOG_WARNING, LPGEN("Failed to request offline messages. They may be received next time you log in.")); + + // Update our information from the server + sendOwnerInfoRequest(); + + // Request info updates on all contacts + icq_RescanInfoUpdate(); + + // Start sending Keep-Alive packets + StartKeepAlive(info); + + if (m_bAvatarsEnabled) + { // Send SNAC 1,4 - request avatar family 0x10 connection + icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread); + + m_avatarsConnectionPending = TRUE; + NetLog_Server("Requesting Avatar family entry point."); + } + } + info->isMigrating = 0; + + if (m_bAimEnabled) + { + char **szAwayMsg = NULL; + icq_lock l(m_modeMsgsMutex); + + szAwayMsg = MirandaStatusToAwayMsg(m_iStatus); + if (szAwayMsg) + icq_sendSetAimAwayMsgServ(*szAwayMsg); + } +} diff --git a/protocols/IcqOscarJ/src/fam_02location.cpp b/protocols/IcqOscarJ/src/fam_02location.cpp new file mode 100644 index 0000000000..2398cf18c6 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_02location.cpp @@ -0,0 +1,312 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handles packets from Location family +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +extern const char* cliSpamBot; + +void CIcqProto::handleLocationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_LOCATION_RIGHTS_REPLY: // Reply to CLI_REQLOCATION + NetLog_Server("Server sent SNAC(x02,x03) - SRV_LOCATION_RIGHTS_REPLY"); + break; + + case ICQ_LOCATION_USR_INFO_REPLY: // AIM user info reply + handleLocationUserInfoReply(pBuffer, wBufferLength, pSnacHeader->dwRef); + break; + + case ICQ_ERROR: + { + WORD wError; + HANDLE hCookieContact; + cookie_fam15_data *pCookieData; + + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + if (wError == 4) + { + if (FindCookie(pSnacHeader->dwRef, &hCookieContact, (void**)&pCookieData) && !getContactUin(hCookieContact) && pCookieData->bRequestType == REQUESTTYPE_PROFILE) + { + BroadcastAck(hCookieContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + + ReleaseCookie(pSnacHeader->dwRef); + } + } + + LogFamilyError(ICQ_LOCATION_FAMILY, wError); + break; + } + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LOCATION_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + +static char* AimApplyEncoding(char* pszStr, const char* pszEncoding) +{ // decode encoding to ANSI only + if (pszStr && pszEncoding) + { + const char *szEnc = strstrnull(pszEncoding, "charset="); + + if (szEnc) + { // decode custom encoding to Utf-8 + char *szStr = ApplyEncoding(pszStr, szEnc + 9); + // decode utf-8 to ansi + char *szRes = NULL; + + SAFE_FREE((void**)&pszStr); + utf8_decode(szStr, &szRes); + SAFE_FREE((void**)&szStr); + + return szRes; + } + } + return pszStr; +} + +void CIcqProto::handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie) +{ + HANDLE hContact; + DWORD dwUIN; + uid_str szUID; + WORD wTLVCount; + WORD wWarningLevel; + HANDLE hCookieContact; + WORD status; + cookie_message_data *pCookieData; + + // Unpack the sender's user ID + if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; + + // Syntax check + if (wLen < 4) + return; + + // Warning level? + unpackWord(&buf, &wWarningLevel); + wLen -= 2; + + // TLV count + unpackWord(&buf, &wTLVCount); + wLen -= 2; + + // Determine contact + hContact = HContactFromUID(dwUIN, szUID, NULL); + + // Ignore away status if the user is not already on our list + if (hContact == INVALID_HANDLE_VALUE) + { +#ifdef _DEBUG + NetLog_Server("Ignoring away reply (%s)", strUID(dwUIN, szUID)); +#endif + return; + } + + if (!FindCookie(dwCookie, &hCookieContact, (void**)&pCookieData)) + { + NetLog_Server("Error: Received unexpected away reply from %s", strUID(dwUIN, szUID)); + return; + } + + if (hContact != hCookieContact) + { + NetLog_Server("Error: Away reply Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); + + ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe + return; + } + + switch (GetCookieType(dwCookie)) + { + case CKT_FAMILYSPECIAL: + { + ReleaseCookie(dwCookie); + + // Read user info TLVs + { + oscar_tlv_chain* pChain; + BYTE *tmp; + char *szMsg = NULL; + + // Syntax check + if (wLen < 4) + return; + + tmp = buf; + // Get general chain + if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) + return; + + disposeChain(&pChain); + + wLen -= (buf - tmp); + + // Get extra chain + if (pChain = readIntoTLVChain(&buf, wLen, 2)) + { + oscar_tlv *pTLV; + char *szEncoding = NULL; + + // Get Profile encoding TLV + + pTLV = pChain->getTLV(0x05, 1); + if (pTLV && (pTLV->wLen > 0)) + { + // store client capabilities + BYTE* capBuf = pTLV->pData; + WORD capLen = pTLV->wLen; + DBCONTACTWRITESETTING dbcws; + dbcws.value.type = DBVT_BLOB; + dbcws.value.cpbVal = capLen; + dbcws.value.pbVal = capBuf; + dbcws.szModule = m_szModuleName; + dbcws.szSetting = "CapBuf"; + CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&dbcws); + } + else + deleteSetting(hContact, "CapBuf"); + + pTLV = pChain->getTLV(0x01, 1); + if (pTLV && (pTLV->wLen >= 1)) + { + szEncoding = (char*)_alloca(pTLV->wLen + 1); + memcpy(szEncoding, pTLV->pData, pTLV->wLen); + szEncoding[pTLV->wLen] = '\0'; + } + // Get Profile info TLV + pTLV = pChain->getTLV(0x02, 1); + if (pTLV && (pTLV->wLen >= 1)) + { + szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); + memcpy(szMsg, pTLV->pData, pTLV->wLen); + szMsg[pTLV->wLen] = '\0'; + szMsg[pTLV->wLen + 1] = '\0'; + szMsg = AimApplyEncoding(szMsg, szEncoding); + szMsg = EliminateHtml(szMsg, pTLV->wLen); + } + // Free TLV chain + disposeChain(&pChain); + } + + setSettingString(hContact, "About", szMsg); + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0); + + SAFE_FREE((void**)&szMsg); + } + break; + } + + default: // away message + { + status = AwayMsgTypeToStatus(pCookieData->nAckType); + if (status == ID_STATUS_OFFLINE) + { + NetLog_Server("SNAC(2.6) Ignoring unknown status message from %s", strUID(dwUIN, szUID)); + + ReleaseCookie(dwCookie); + return; + } + + ReleaseCookie(dwCookie); + + // Read user info TLVs + { + oscar_tlv_chain* pChain; + oscar_tlv* pTLV; + BYTE *tmp; + char *szMsg = NULL; + CCSDATA ccs; + PROTORECVEVENT pre; + + // Syntax check + if (wLen < 4) + return; + + tmp = buf; + // Get general chain + if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) + return; + + disposeChain(&pChain); + + wLen -= (buf - tmp); + + // Get extra chain + if (pChain = readIntoTLVChain(&buf, wLen, 2)) + { + char* szEncoding = NULL; + + // Get Away encoding TLV + pTLV = pChain->getTLV(0x03, 1); + if (pTLV && (pTLV->wLen >= 1)) + { + szEncoding = (char*)_alloca(pTLV->wLen + 1); + memcpy(szEncoding, pTLV->pData, pTLV->wLen); + szEncoding[pTLV->wLen] = '\0'; + } + // Get Away info TLV + pTLV = pChain->getTLV(0x04, 1); + if (pTLV && (pTLV->wLen >= 1)) + { + szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); + memcpy(szMsg, pTLV->pData, pTLV->wLen); + szMsg[pTLV->wLen] = '\0'; + szMsg[pTLV->wLen + 1] = '\0'; + szMsg = AimApplyEncoding(szMsg, szEncoding); + szMsg = EliminateHtml(szMsg, pTLV->wLen); + } + // Free TLV chain + disposeChain(&pChain); + } + + ccs.szProtoService = PSR_AWAYMSG; + ccs.hContact = hContact; + ccs.wParam = status; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.szMessage = szMsg?szMsg:(char *)""; + pre.timestamp = time(NULL); + pre.lParam = dwCookie; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + + SAFE_FREE((void**)&szMsg); + } + break; + } + } +} diff --git a/protocols/IcqOscarJ/src/fam_03buddy.cpp b/protocols/IcqOscarJ/src/fam_03buddy.cpp new file mode 100644 index 0000000000..caa41d966c --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_03buddy.cpp @@ -0,0 +1,787 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handles packets from Buddy family +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +extern const char* cliSpamBot; + +void CIcqProto::handleBuddyFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) +{ + switch (pSnacHeader->wSubtype) + { + case ICQ_USER_ONLINE: + handleUserOnline(pBuffer, wBufferLength, info); + break; + + case ICQ_USER_OFFLINE: + handleUserOffline(pBuffer, wBufferLength); + break; + + case ICQ_USER_SRV_REPLYBUDDY: + handleReplyBuddy(pBuffer, wBufferLength); + break; + + case ICQ_USER_NOTIFY_REJECTED: + handleNotifyRejected(pBuffer, wBufferLength); + break; + + case ICQ_ERROR: + { + WORD wError; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + LogFamilyError(ICQ_BUDDY_FAMILY, wError); + break; + } + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_BUDDY_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + + +void CIcqProto::handleReplyBuddy(BYTE *buf, WORD wPackLen) +{ + oscar_tlv_chain *pChain = readIntoTLVChain(&buf, wPackLen, 0); + + if (pChain) + { + DWORD wMaxUins = pChain->getWord(1, 1); + DWORD wMaxWatchers = pChain->getWord(2, 1); + DWORD wMaxTemporary = pChain->getWord(4, 1); + + NetLog_Server("MaxUINs %u", wMaxUins); + NetLog_Server("MaxWatchers %u", wMaxWatchers); + NetLog_Server("MaxTemporary %u", wMaxTemporary); + + disposeChain(&pChain); + } + else + { + NetLog_Server("Error: Malformed BuddyReply"); + } +} + + +int unpackSessionDataItem(oscar_tlv_chain *pChain, WORD wItemType, BYTE **ppItemData, WORD *pwItemSize, BYTE *pbItemFlags) +{ + oscar_tlv *tlv = pChain->getTLV(0x1D, 1); + int len = 0; + BYTE *data; + + if (tlv) + { + len = tlv->wLen; + data = tlv->pData; + } + + while (len >= 4) + { // parse session data items one by one + WORD itemType; + BYTE itemFlags; + BYTE itemLen; + + unpackWord(&data, &itemType); + unpackByte(&data, &itemFlags); + unpackByte(&data, &itemLen); + len -= 4; + + // just some validity check + if (itemLen > len) + itemLen = len; + + if (itemType == wItemType) + { // found the requested item + if (ppItemData) + *ppItemData = data; + if (pwItemSize) + *pwItemSize = itemLen; + if (pbItemFlags) + *pbItemFlags = itemFlags; + + return 1; // Success + } + data += itemLen; + len -= itemLen; + } + return 0; +} + + +// TLV(1) User class +// TLV(3) Signon time +// TLV(4) Idle time (in minutes) +// TLV(5) Member since +// TLV(6) New status +// TLV(8) Status Capabilities +// TLV(A) External IP +// TLV(C) DC Info +// TLV(D) Capabilities +// TLV(F) Session timer (in seconds) +// TLV(14) Instance number (AIM only) +// TLV(19) Short capabilities +// TLV(1D) Session Data (Avatar, Mood, etc.) +// TLV(1F) User class (upper bytes) +// TLV(26) AIM Profile update time +// TLV(27) AIM Away message update time +// TLV(29) Away status since +// TLV(2B) URL to protocol icon +// TLV(2F) unknown key +// TLV(30) unknown timestamp + +void CIcqProto::handleUserOnline(BYTE *buf, WORD wLen, serverthread_info *info) +{ + DWORD dwPort = 0; + DWORD dwRealIP = 0; + DWORD dwUIN; + uid_str szUID; + DWORD dwDirectConnCookie = 0; + DWORD dwWebPort = 0; + DWORD dwFT1 = 0, dwFT2 = 0, dwFT3 = 0; + const char *szClient = NULL; + BYTE bClientId = 0; + WORD wVersion = 0; + WORD wTLVCount; + WORD wWarningLevel; + WORD wStatusFlags; + WORD wStatus = 0, wOldStatus = 0; + BYTE nTCPFlag = 0; + char szStrBuf[MAX_PATH]; + + // Unpack the sender's user ID + if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; + + // Syntax check + if (wLen < 4) + return; + + // Warning level? + unpackWord(&buf, &wWarningLevel); + wLen -= 2; + + // TLV count + unpackWord(&buf, &wTLVCount); + wLen -= 2; + + // notify that the set status note & mood process is finished + if (m_hNotifyNameInfoEvent) + SetEvent(m_hNotifyNameInfoEvent); + + // Ignore status notification if the user is not already on our list + HANDLE hContact = HContactFromUID(dwUIN, szUID, NULL); + if (hContact == INVALID_HANDLE_VALUE) + { +#ifdef _DEBUG + NetLog_Server("Ignoring user online (%s)", strUID(dwUIN, szUID)); +#endif + return; + } + + // Read user info TLVs + oscar_tlv_chain *pChain; + oscar_tlv *pTLV; + + // Syntax check + if (wLen < 4) + return; + + // Get chain + if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) + return; + + // Get Class word + WORD wClass = pChain->getWord(0x01, 1); + int nIsICQ = wClass & CLASS_ICQ; + + if (dwUIN) + { + // Get DC info TLV + pTLV = pChain->getTLV(0x0C, 1); + if (pTLV && (pTLV->wLen >= 15)) + { + BYTE *pBuffer = pTLV->pData; + + nIsICQ = TRUE; + + unpackDWord(&pBuffer, &dwRealIP); + unpackDWord(&pBuffer, &dwPort); + unpackByte(&pBuffer, &nTCPFlag); + unpackWord(&pBuffer, &wVersion); + unpackDWord(&pBuffer, &dwDirectConnCookie); + unpackDWord(&pBuffer, &dwWebPort); // Web front port + pBuffer += 4; // Client features + + // Get faked time signatures, used to identify clients + if (pTLV->wLen >= 0x23) + { + unpackDWord(&pBuffer, &dwFT1); + unpackDWord(&pBuffer, &dwFT2); + unpackDWord(&pBuffer, &dwFT3); + } + } + else + { + // This client doesnt want DCs + } + + // Get Status info TLV + pTLV = pChain->getTLV(0x06, 1); + if (pTLV && (pTLV->wLen >= 4)) + { + BYTE *pBuffer = pTLV->pData; + + unpackWord(&pBuffer, &wStatusFlags); + unpackWord(&pBuffer, &wStatus); + } + else if (!nIsICQ) + { + // Connected thru AIM client, guess by user class + if (wClass & CLASS_AWAY) + wStatus = ID_STATUS_AWAY; + else if (wClass & CLASS_WIRELESS) + wStatus = ID_STATUS_ONTHEPHONE; + else + wStatus = ID_STATUS_ONLINE; + + wStatusFlags = 0; + } + else + { + // Huh? No status TLV? Lets guess then... + wStatusFlags = 0; + wStatus = ICQ_STATUS_ONLINE; + } + } + else + { + nIsICQ = FALSE; + + if (wClass & CLASS_AWAY) + wStatus = ID_STATUS_AWAY; + else if (wClass & CLASS_WIRELESS) + wStatus = ID_STATUS_ONTHEPHONE; + else + wStatus = ID_STATUS_ONLINE; + + wStatusFlags = 0; + } + +#ifdef _DEBUG + NetLog_Server("Flags are %x", wStatusFlags); + NetLog_Server("Status is %x", wStatus); +#endif + + // Get IP TLV + DWORD dwIP = pChain->getDWord(0x0A, 1); + + // Get Online Since TLV + DWORD dwOnlineSince = pChain->getDWord(0x03, 1); + + // Get Away Since TLV + DWORD dwAwaySince = pChain->getDWord(0x29, 1); + + // Get Member Since TLV + DWORD dwMemberSince = pChain->getDWord(0x05, 1); + + // Get Idle timer TLV + WORD wIdleTimer = pChain->getWord(0x04, 1); + time_t tIdleTS = 0; + if (wIdleTimer) + { + time(&tIdleTS); + tIdleTS -= (wIdleTimer*60); + }; + +#ifdef _DEBUG + if (wIdleTimer) + NetLog_Server("Idle timer is %u.", wIdleTimer); + NetLog_Server("Online since %s", time2text(dwOnlineSince)); + if (dwAwaySince) + NetLog_Server("Status was set on %s", time2text(dwAwaySince)); +#endif + + // Check client capabilities + if (hContact != NULL) + { + wOldStatus = getContactStatus(hContact); + + // Collect all Capability info from TLV chain + BYTE *capBuf = NULL; + WORD capLen = 0; + + // Get Location Capability Info TLVs + oscar_tlv *pFullTLV = pChain->getTLV(0x0D, 1); + oscar_tlv *pShortTLV = pChain->getTLV(0x19, 1); + + if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) + capLen += pFullTLV->wLen; + + if (pShortTLV && (pShortTLV->wLen >= 2)) + capLen += (pShortTLV->wLen * 8); + + capBuf = (BYTE*)_alloca(capLen + BINARY_CAP_SIZE); + + if (capLen) + { + BYTE *pCapability = capBuf; + + capLen = 0; // we need to recount that + + if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) + { // copy classic Capabilities + BYTE *cData = pFullTLV->pData; + int cLen = pFullTLV->wLen; + + while (cLen) + { // be impervious to duplicates (AOL sends them sometimes) + if (!capLen || !MatchCapability(capBuf, capLen, (capstr*)cData, BINARY_CAP_SIZE)) + { // not present, add + memcpy(pCapability, cData, BINARY_CAP_SIZE); + capLen += BINARY_CAP_SIZE; + pCapability += BINARY_CAP_SIZE; + } + cData += BINARY_CAP_SIZE; + cLen -= BINARY_CAP_SIZE; + } + } + + if (pShortTLV && (pShortTLV->wLen >= 2)) + { // copy short Capabilities + capstr tmp; + BYTE *cData = pShortTLV->pData; + int cLen = pShortTLV->wLen; + + memcpy(tmp, capShortCaps, BINARY_CAP_SIZE); + while (cLen) + { // be impervious to duplicates (AOL sends them sometimes) + tmp[2] = cData[0]; + tmp[3] = cData[1]; + + if (!capLen || !MatchCapability(capBuf, capLen, &tmp, BINARY_CAP_SIZE)) + { // not present, add + memcpy(pCapability, tmp, BINARY_CAP_SIZE); + capLen += BINARY_CAP_SIZE; + pCapability += BINARY_CAP_SIZE; + } + cData += 2; + cLen -= 2; + } + } +#ifdef _DEBUG + NetLog_Server("Detected %d capability items.", capLen / BINARY_CAP_SIZE); +#endif + } + + if (capLen) + { // Update the contact's capabilies if present in packet + SetCapabilitiesFromBuffer(hContact, capBuf, capLen, wOldStatus == ID_STATUS_OFFLINE); + + char *szCurrentClient = wOldStatus == ID_STATUS_OFFLINE ? NULL : getSettingStringUtf(hContact, "MirVer", NULL); + + szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, szCurrentClient, wVersion, dwFT1, dwFT2, dwFT3, nTCPFlag, dwDirectConnCookie, dwWebPort, capBuf, capLen, &bClientId, szStrBuf); + // Check if the client changed, if not do not change + if (szCurrentClient && !strcmpnull(szCurrentClient, szClient)) + szClient = (const char*)-1; + SAFE_FREE(&szCurrentClient); + } + else if (wOldStatus == ID_STATUS_OFFLINE) + { + // Remove the contact's capabilities if coming from offline + ClearAllContactCapabilities(hContact); + + // no capability + NetLog_Server("No capability info TLVs"); + + szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, NULL, wVersion, dwFT1, dwFT2, dwFT3, nTCPFlag, dwDirectConnCookie, dwWebPort, NULL, capLen, &bClientId, szStrBuf); + } + else + { + // Capabilities not present in update packet, do not touch + szClient = (const char*)-1; // we don't want to client be overwritten + } + + // handle Xtraz status + char *moodData = NULL; + WORD moodSize = 0; + + unpackSessionDataItem(pChain, 0x0E, (BYTE**)&moodData, &moodSize, NULL); + if (capLen || wOldStatus == ID_STATUS_OFFLINE) + handleXStatusCaps(dwUIN, szUID, hContact, capBuf, capLen, moodData, moodSize); + else + handleXStatusCaps(dwUIN, szUID, hContact, NULL, 0, moodData, moodSize); + + // Determine support for extended status messages + if (pChain->getWord(0x08, 1) == 0x0A06) + SetContactCapabilities(hContact, CAPF_STATUS_MESSAGES); + else if (wOldStatus == ID_STATUS_OFFLINE) + ClearContactCapabilities(hContact, CAPF_STATUS_MESSAGES); + +#ifdef _DEBUG + if (wOldStatus == ID_STATUS_OFFLINE) + { + if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) + NetLog_Server("Supports advanced messages"); + else + NetLog_Server("Does NOT support advanced messages"); + } +#endif + + if (!nIsICQ) + { + // AIM clients does not advertise these, but do support them + SetContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING); + // Server relayed messages are only supported by ICQ clients + ClearContactCapabilities(hContact, CAPF_SRV_RELAY); + + if (dwUIN && wOldStatus == ID_STATUS_OFFLINE) + NetLog_Server("Logged in with AIM client"); + } + + if (nIsICQ && wVersion < 8) + { + ClearContactCapabilities(hContact, CAPF_SRV_RELAY); + if (wOldStatus == ID_STATUS_OFFLINE) + NetLog_Server("Forcing simple messages due to compability issues"); + } + + // Process Avatar Hash + pTLV = pChain->getTLV(0x1D, 1); + if (pTLV) + handleAvatarContactHash(dwUIN, szUID, hContact, pTLV->pData, pTLV->wLen, wOldStatus); + else + handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0, wOldStatus); + + // Process Status Note + parseStatusNote(dwUIN, szUID, hContact, pChain); + } + // Free TLV chain + disposeChain(&pChain); + + // Save contacts details in database + if (hContact != NULL) + { + setSettingDword(hContact, "LogonTS", dwOnlineSince); + setSettingDword(hContact, "AwayTS", dwAwaySince); + setSettingDword(hContact, "IdleTS", tIdleTS); + + if (dwMemberSince) + setSettingDword(hContact, "MemberTS", dwMemberSince); + + if (nIsICQ) + { // on AIM these are not used + setSettingDword(hContact, "DirectCookie", dwDirectConnCookie); + setSettingByte(hContact, "DCType", (BYTE)nTCPFlag); + setSettingWord(hContact, "UserPort", (WORD)(dwPort & 0xffff)); + setSettingWord(hContact, "Version", wVersion); + } + else + { + deleteSetting(hContact, "DirectCookie"); + deleteSetting(hContact, "DCType"); + deleteSetting(hContact, "UserPort"); + deleteSetting(hContact, "Version"); + } + + if (!szClient) + { + // if no detection, set uknown + szClient = (nIsICQ ? "Unknown" : "Unknown AIM"); + } + if (szClient != (char*)-1) + { + setSettingStringUtf(hContact, "MirVer", szClient); + setSettingByte(hContact, "ClientID", bClientId); + } + + if (wOldStatus == ID_STATUS_OFFLINE) + { + setSettingDword(hContact, "IP", dwIP); + setSettingDword(hContact, "RealIP", dwRealIP); + } + else + { // if not first notification only write significant information + if (dwIP) + setSettingDword(hContact, "IP", dwIP); + if (dwRealIP) + setSettingDword(hContact, "RealIP", dwRealIP); + } + setSettingWord(hContact, "Status", (WORD)IcqStatusToMiranda(wStatus)); + + // Update info? + if (dwUIN) + { // check if the local copy of user details is up-to-date + if (IsMetaInfoChanged(hContact)) + icq_QueueUser(hContact); + } + } + + if (wOldStatus != IcqStatusToMiranda(wStatus)) + { // And a small log notice... if status was changed + if (nIsICQ) + NetLog_Server("%u changed status to %s (v%d).", dwUIN, MirandaStatusToString(IcqStatusToMiranda(wStatus)), wVersion); + else + NetLog_Server("%s changed status to %s.", strUID(dwUIN, szUID), MirandaStatusToString(IcqStatusToMiranda(wStatus))); + } +#ifdef _DEBUG + else + { + if (nIsICQ) + NetLog_Server("%u has status %s (v%d).", dwUIN, MirandaStatusToString(IcqStatusToMiranda(wStatus)), wVersion); + else + NetLog_Server("%s has status %s.", strUID(dwUIN, szUID), MirandaStatusToString(IcqStatusToMiranda(wStatus))); + } +#endif + + if (szClient == cliSpamBot) + { + if (getSettingByte(NULL, "KillSpambots", DEFAULT_KILLSPAM_ENABLED) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + { // kill spammer + icq_DequeueUser(dwUIN); + icq_sendRemoveContact(dwUIN, NULL); + AddToSpammerList(dwUIN); + if (getSettingByte(NULL, "PopupsSpamEnabled", DEFAULT_SPAM_POPUPS_ENABLED)) + ShowPopUpMsg(hContact, LPGEN("Spambot Detected"), LPGEN("Contact deleted & further events blocked."), POPTYPE_SPAM); + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + + NetLog_Server("Contact %u deleted", dwUIN); + } + } +} + +void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen) +{ + DWORD dwUIN; + uid_str szUID; + + do { + oscar_tlv_chain *pChain = NULL; + WORD wTLVCount; + DWORD dwAwaySince; + + // Unpack the sender's user ID + if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; + + // Warning level? + buf += 2; + + // TLV Count + unpackWord(&buf, &wTLVCount); + wLen -= 4; + + // Skip the TLV chain + while (wTLVCount && wLen >= 4) + { + WORD wTLVType; + WORD wTLVLen; + + unpackWord(&buf, &wTLVType); + unpackWord(&buf, &wTLVLen); + wLen -= 4; + + // stop parsing overflowed packet + if (wTLVLen > wLen) + { + disposeChain(&pChain); + return; + } + + if (wTLVType == 0x1D) + { // read only TLV with Session data into chain + BYTE *pTLV = buf - 4; + disposeChain(&pChain); + pChain = readIntoTLVChain(&pTLV, wLen + 4, 1); + } + else if (wTLVType == 0x29 && wTLVLen == sizeof(DWORD)) + { // get Away Since value + BYTE *pData = buf; + unpackDWord(&pData, &dwAwaySince); + } + + buf += wTLVLen; + wLen -= wTLVLen; + wTLVCount--; + } + + // Determine contact + HANDLE hContact = HContactFromUID(dwUIN, szUID, NULL); + + // Skip contacts that are not already on our list or are already offline + if (hContact != INVALID_HANDLE_VALUE) + { + WORD wOldStatus = getContactStatus(hContact); + + // Process Avatar Hash + oscar_tlv *pAvatarTLV = pChain ? pChain->getTLV(0x1D, 1) : NULL; + if (pAvatarTLV) + handleAvatarContactHash(dwUIN, szUID, hContact, pAvatarTLV->pData, pAvatarTLV->wLen, wOldStatus); + else + handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0, wOldStatus); + + // Process Status Note (offline status note) + parseStatusNote(dwUIN, szUID, hContact, pChain); + + // Update status times + setSettingDword(hContact, "IdleTS", 0); + setSettingDword(hContact, "AwayTS", dwAwaySince); + + // Clear custom status & mood + char tmp = NULL; + handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0); + + if (wOldStatus != ID_STATUS_OFFLINE) + { + NetLog_Server("%s went offline.", strUID(dwUIN, szUID)); + + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + // close Direct Connections to that user + CloseContactDirectConns(hContact); + // Reset DC status + setSettingByte(hContact, "DCStatus", 0); + } +#ifdef _DEBUG + else + NetLog_Server("%s is offline.", strUID(dwUIN, szUID)); +#endif + } + + // Release memory + disposeChain(&pChain); + } + while (wLen >= 1); +} + + +void CIcqProto::parseStatusNote(DWORD dwUin, char *szUid, HANDLE hContact, oscar_tlv_chain *pChain) +{ + DWORD dwStatusNoteTS = time(NULL); + BYTE *pStatusNoteTS, *pStatusNote; + WORD wStatusNoteTSLen, wStatusNoteLen; + BYTE bStatusNoteFlags; + + if (unpackSessionDataItem(pChain, 0x0D, &pStatusNoteTS, &wStatusNoteTSLen, NULL) && wStatusNoteTSLen == sizeof(DWORD)) + unpackDWord(&pStatusNoteTS, &dwStatusNoteTS); + + // Get Status Note session item + if (unpackSessionDataItem(pChain, 0x02, &pStatusNote, &wStatusNoteLen, &bStatusNoteFlags)) + { + char *szStatusNote = NULL; + + if ((bStatusNoteFlags & 4) == 4 && wStatusNoteLen >= 4) + { + BYTE *buf = pStatusNote; + WORD buflen = wStatusNoteLen - 2; + WORD wTextLen; + + unpackWord(&buf, &wTextLen); + if (wTextLen > buflen) + wTextLen = buflen; + + if (wTextLen > 0) + { + szStatusNote = (char*)_alloca(wStatusNoteLen + 1); + unpackString(&buf, szStatusNote, wTextLen); + szStatusNote[wTextLen] = '\0'; + buflen -= wTextLen; + + WORD wEncodingType = 0; + char *szEncoding = NULL; + + if (buflen >= 2) + unpackWord(&buf, &wEncodingType); + + if (wEncodingType == 1 && buflen > 6) + { // Encoding specified + buf += 2; + buflen -= 2; + unpackWord(&buf, &wTextLen); + if (wTextLen > buflen) + wTextLen = buflen; + szEncoding = (char*)_alloca(wTextLen + 1); + unpackString(&buf, szEncoding, wTextLen); + szEncoding[wTextLen] = '\0'; + } + else if (UTF8_IsValid(szStatusNote)) + szEncoding = "utf-8"; + + szStatusNote = ApplyEncoding(szStatusNote, szEncoding); + } + } + // Check if the status note was changed + if (dwStatusNoteTS > getSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, 0)) + { + DBVARIANT dbv = {DBVT_DELETED}; + + if (strlennull(szStatusNote) || (!getSettingString(hContact, DBSETTING_STATUS_NOTE, &dbv) && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_UTF8) && strlennull(dbv.pszVal))) + NetLog_Server("%s changed status note to \"%s\"", strUID(dwUin, szUid), szStatusNote ? szStatusNote : ""); + + ICQFreeVariant(&dbv); + + if (szStatusNote) + setSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, szStatusNote); + else + deleteSetting(hContact, DBSETTING_STATUS_NOTE); + setSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS); + + if (getContactXStatus(hContact) != 0 || !CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) { + setStatusMsgVar(hContact, szStatusNote, false); + + TCHAR* tszNote = mir_utf8decodeT(szStatusNote); + BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, (LPARAM)tszNote); + mir_free(tszNote); + } + } + SAFE_FREE(&szStatusNote); + } + else + { + if (getContactStatus(hContact) == ID_STATUS_OFFLINE) + { + setStatusMsgVar(hContact, NULL, false); + deleteSetting(hContact, DBSETTING_STATUS_NOTE); + setSettingDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS); + } + } +} + + +void CIcqProto::handleNotifyRejected(BYTE *buf, WORD wPackLen) +{ + DWORD dwUIN; + uid_str szUID; + + while (wPackLen) + if (unpackUID(&buf, &wPackLen, &dwUIN, &szUID)) + NetLog_Server("%s status notification rejected.", strUID(dwUIN, szUID)); +} diff --git a/protocols/IcqOscarJ/src/fam_04message.cpp b/protocols/IcqOscarJ/src/fam_04message.cpp new file mode 100644 index 0000000000..7d1bc6a829 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_04message.cpp @@ -0,0 +1,3043 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Handles packets from Family 4 ICBM Messages +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleMsgFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_MSG_SRV_ERROR: // SNAC(4, 0x01) + handleRecvServMsgError(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_SRV_REPLYICBM: // SNAC(4, 0x05) SRV_REPLYICBM + handleReplyICBM(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_SRV_RECV: // SNAC(4, 0x07) + handleRecvServMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_SRV_MISSED_MESSAGE: // SNAC(4, 0x0A) + handleMissedMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_RESPONSE: // SNAC(4, 0x0B) + handleRecvMsgResponse(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_SRV_ACK: // SNAC(4, 0x0C) Server acknowledgements + handleServerAck(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_MTN: // SNAC(4, 0x14) Typing notifications + handleTypingNotification(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + case ICQ_MSG_SRV_OFFLINE_REPLY: // SNAC(4, 0x17) Offline Messages response + handleOffineMessagesReply(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_MSG_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + + +static void setMsgChannelParams(CIcqProto *ppro, WORD wChan, DWORD dwFlags) +{ + icq_packet packet; + + // Set message parameters for channel wChan (CLI_SET_ICBM_PARAMS) + serverPacketInit(&packet, 26); + packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_SETPARAMS); + packWord(&packet, wChan); // Channel + packDWord(&packet, dwFlags); // Flags + packWord(&packet, MAX_MESSAGESNACSIZE); // Max message snac size + packWord(&packet, 0x03E7); // Max sender warning level + packWord(&packet, 0x03E7); // Max receiver warning level + packWord(&packet, CLIENTRATELIMIT); // Minimum message interval in seconds + packWord(&packet, 0x0000); // Unknown + ppro->sendServPacket(&packet); +} + + +void CIcqProto::handleReplyICBM(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ // we don't care about the stuff, just change the params + DWORD dwFlags = 0x00000303; + +#ifdef DBG_CAPHTML + dwFlags |= 0x00000400; +#endif +#ifdef DBG_CAPMTN + dwFlags |= 0x00000008; +#endif + // Set message parameters for all channels (imitate ICQ 6) + setMsgChannelParams(this, 0x0000, dwFlags); +} + + +void CIcqProto::handleRecvServMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ + DWORD dwUin; + DWORD dwMsgID1; + DWORD dwMsgID2; + WORD wTLVCount; + WORD wMessageFormat; + uid_str szUID; + + if (wLen < 11) + { // just do some basic packet checking + NetLog_Server("Error: Malformed message thru server"); + return; + } + + // These two values are some kind of reference, we need to save + // them to send file request responses for example + unpackLEDWord(&buf, &dwMsgID1); // TODO: msg cookies should be main + wLen -= 4; + unpackLEDWord(&buf, &dwMsgID2); + wLen -= 4; + + // The message type used: + unpackWord(&buf, &wMessageFormat); // 0x0001: Simple message format + wLen -= 2; // 0x0002: Advanced message format + // 0x0004: 'New' message format + // Sender UIN + if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; + + if (dwUin && IsOnSpammerList(dwUin)) + { + NetLog_Server("Ignored Message from known Spammer"); + return; + } + + if (wLen < 4) + { // just do some basic packet checking + NetLog_Server("Error: Malformed message thru server"); + return; + } + + // Warning level? + buf += 2; + wLen -= 2; + + // Number of following TLVs, until msg-format dependant TLVs + unpackWord(&buf, &wTLVCount); + wLen -= 2; + if (wTLVCount > 0) + { + // Save current buffer pointer so we can calculate + // how much data we have left after the chain read. + BYTE *pBufStart = buf; + oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, wTLVCount); + + // This chain contains info that is filled in by the server. + // TLV(1): unknown + // TLV(2): date: on since + // TLV(3): date: on since + // TLV(4): unknown, usually 0000. Not in file-req or auto-msg-req + // TLV(6): sender's status + // TLV(F): a time in seconds, unknown + + disposeChain(&chain); + + // Update wLen + wLen -= buf - pBufStart; + } + + + // This is where the format specific data begins + + switch (wMessageFormat) { + + case 1: // Simple message format + handleRecvServMsgType1(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); + break; + + case 2: // Encapsulated messages + handleRecvServMsgType2(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); + break; + + case 4: // Typed messages + handleRecvServMsgType4(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); + break; + + default: + NetLog_Server("Unknown format message thru server - Ref %u, Type: %u, UID: %s", dwRef, wMessageFormat, strUID(dwUin, szUID)); + break; + + } +} + + +char* CIcqProto::convertMsgToUserSpecificUtf(HANDLE hContact, const char *szMsg) +{ + WORD wCP = getSettingWord(hContact, "CodePage", m_wAnsiCodepage); + char *usMsg = NULL; + + if (wCP != CP_ACP) + usMsg = ansi_to_utf8_codepage(szMsg, wCP); + + return usMsg; +} + + +void CIcqProto::handleRecvServMsgType1(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) +{ + WORD wTLVType; + WORD wTLVLen; + BYTE* pMsgTLV; + + if (wLen < 4) + { // just perform basic structure check + NetLog_Server("Message (format %u) - Ignoring empty message", 1); + return; + } + + // Unpack the first TLV(2) + unpackTypedTLV(buf, wLen, 2, &wTLVType, &wTLVLen, &pMsgTLV); + NetLog_Server("Message (format %u) - UID: %s", 1, strUID(dwUin, szUID)); + + // It must be TLV(2) + if (wTLVType == 2) + { + BYTE *pDataBuf = pMsgTLV; + oscar_tlv_chain *pChain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); + + // TLV(2) contains yet another TLV chain with the following TLVs: + // TLV(1281): Capability + // TLV(257): This TLV contains the actual message (can be fragmented) + + if (pChain) + { + oscar_tlv* pMessageTLV; + oscar_tlv* pCapabilityTLV; + WORD wMsgPart = 1; + + // Find the capability TLV + pCapabilityTLV = pChain->getTLV(0x0501, 1); + if (pCapabilityTLV && (pCapabilityTLV->wLen > 0)) + { + WORD wDataLen; + BYTE *pDataBuf; + + wDataLen = pCapabilityTLV->wLen; + pDataBuf = pCapabilityTLV->pData; + + if (wDataLen > 0) + NetLog_Server("Message (format 1) - Message has %d caps.", wDataLen); + } + else + NetLog_Server("Message (format 1) - No message cap."); + + { // Parse the message parts, usually only one 0x0101 TLV containing the message, + // but in some cases there can be more 0x0101 TLVs containing message parts in + // different encodings (just like the new format of Offline Messages). + DWORD dwRecvTime; + char* szMsg = NULL; + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + int bAdded; + + HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded); + + while (pMessageTLV = pChain->getTLV(0x0101, wMsgPart)) + { // Loop thru all message parts + if (pMessageTLV->wLen > 4) + { + WORD wMsgLen; + BYTE *pMsgBuf; + WORD wEncoding; + WORD wCodePage; + char *szMsgPart = NULL; + int bMsgPartUnicode = FALSE; + + // The message begins with a encoding specification + // The first WORD is believed to have the following meaning: + // 0x00: US-ASCII + // 0x02: Unicode UCS-2 Big Endian encoding + // 0x03: local 8bit encoding + pMsgBuf = pMessageTLV->pData; + unpackWord(&pMsgBuf, &wEncoding); + unpackWord(&pMsgBuf, &wCodePage); + + wMsgLen = pMessageTLV->wLen - 4; + NetLog_Server("Message (format 1) - Part %d: Encoding is 0x%X, page is 0x%X", wMsgPart, wEncoding, wCodePage); + + switch (wEncoding) { + + case 2: // UCS-2 + { + WCHAR* usMsgPart = (WCHAR*)SAFE_MALLOC(wMsgLen + 2); + + unpackWideString(&pMsgBuf, usMsgPart, wMsgLen); + usMsgPart[wMsgLen/sizeof(WCHAR)] = 0; + + szMsgPart = make_utf8_string(usMsgPart); + if (!IsUSASCII(szMsgPart, strlennull(szMsgPart))) + bMsgPartUnicode = TRUE; + SAFE_FREE(&usMsgPart); + + break; + } + + case 0: // us-ascii + case 3: // ANSI + default: + { + // Copy the message text into a new proper string. + szMsgPart = (char*)SAFE_MALLOC(wMsgLen + 1); + memcpy(szMsgPart, pMsgBuf, wMsgLen); + szMsgPart[wMsgLen] = '\0'; + + break; + } + } + // Check if the new part is compatible with the message + if (!pre.flags && bMsgPartUnicode) + { // make the resulting message utf-8 encoded - need to append utf-8 encoded part + if (szMsg) + { // not necessary to convert - appending first part, only set flags + char *szUtfMsg = ansi_to_utf8_codepage(szMsg, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); + + SAFE_FREE(&szMsg); + szMsg = szUtfMsg; + } + pre.flags = PREF_UTF; + } + if (!bMsgPartUnicode && pre.flags == PREF_UTF) + { // convert message part to utf-8 and append + char *szUtfPart = ansi_to_utf8_codepage((char*)szMsgPart, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); + + SAFE_FREE(&szMsgPart); + szMsgPart = szUtfPart; + } + // Append the new message part + szMsg = (char*)SAFE_REALLOC(szMsg, strlennull(szMsg) + strlennull(szMsgPart) + 1); + + strcat(szMsg, szMsgPart); + SAFE_FREE(&szMsgPart); + } + wMsgPart++; + } + if (strlennull(szMsg)) + { + if (_strnicmp(szMsg, "", 6) == 0) + { // strip HTML formating from AIM message + szMsg = EliminateHtml(szMsg, strlennull(szMsg)); + } + + if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) + { // message is Ansi and contains national characters, create Unicode part by codepage + char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); + if (usMsg) + { + SAFE_FREE(&szMsg); + szMsg = usMsg; + pre.flags = PREF_UTF; + } + } + + dwRecvTime = (DWORD)time(NULL); + + { // Check if the message was received as offline + cookie_offline_messages *cookie; + + if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) + { + WORD wTimeTLVType, wTimeTLVLen; + BYTE *pTimeTLV; + + cookie->nMessages++; + + unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); + if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) + { // found Offline timestamp + BYTE *pBuf = pTimeTLV; + + unpackDWord(&pBuf, &dwRecvTime); + NetLog_Server("Message (format %u) - Offline timestamp is %s", 1, time2text(dwRecvTime)); + } + SAFE_FREE((void**)&pTimeTLV); + } + } + // Create and send the message event + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = dwRecvTime; + pre.szMessage = (char *)szMsg; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + NetLog_Server("Message (format 1) received"); + + // Save tick value + setSettingDword(ccs.hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); + } + else + NetLog_Server("Message (format %u) - Ignoring empty message", 1); + + SAFE_FREE(&szMsg); + } + + // Free the chain memory + disposeChain(&pChain); + } + else + NetLog_Server("Failed to read TLV chain in message (format 1)"); + } + else + NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 1); + + SAFE_FREE((void**)&pMsgTLV); +} + + +void CIcqProto::handleRecvServMsgType2(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) +{ + WORD wTLVType; + WORD wTLVLen; + BYTE *pDataBuf = NULL; + BYTE *pBuf; + + if (wLen < 4) + { + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + return; + } + + // Unpack the first TLV(5) + unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); + NetLog_Server("Message (format %u) - UID: %s", 2, strUID(dwUin, szUID)); + pBuf = pDataBuf; + + // It must be TLV(5) + if (wTLVType == 5) + { + WORD wCommand; + oscar_tlv_chain* chain; + oscar_tlv* tlv; + DWORD q1,q2,q3,q4; + + if (wTLVLen < 26) + { // just check if all basic data is there + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + SAFE_FREE((void**)&pBuf); + return; + } + + unpackWord(&pDataBuf, &wCommand); + wTLVLen -= 2; // Command 0x0000 - Normal message/file send request +#ifdef _DEBUG // 0x0001 - Abort request + NetLog_Server("Command is %u", wCommand); // 0x0002 - Acknowledge request +#endif + + // Some stuff we don't use + pDataBuf += 8; // dwID1 and dwID2 again + wTLVLen -= 8; + unpackDWord(&pDataBuf, &q1); + unpackDWord(&pDataBuf, &q2); + unpackDWord(&pDataBuf, &q3); + unpackDWord(&pDataBuf, &q4); // Message Capability + wTLVLen -= 16; + + if (CompareGUIDs(q1,q2,q3,q4, MCAP_SRV_RELAY_FMT)) + { // we surely have at least 4 bytes for TLV chain + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (wCommand == 1) + { + NetLog_Server("Cannot handle abort messages yet... :("); + SAFE_FREE((void**)&pBuf); + return; + } + + if (wTLVLen < 4) + { // just check if at least one tlv is there + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + SAFE_FREE((void**)&pBuf); + return; + } + + // This TLV chain may contain the following TLVs: + // TLV(A): Acktype 0x0000 - normal message + // 0x0001 - file request / abort request + // 0x0002 - file ack + // TLV(F): Unknown + // TLV(3): External IP + // TLV(5): DC port (not to use for filetransfers) + // TLV(0x2711): The next message level + + chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); + if (!chain) + { // sanity check + NetLog_Server("Message (format %u) - Invalid data", 2); + SAFE_FREE((void**)&pBuf); + return; + } + + WORD wAckType = chain->getWord(0x0A, 1); + + // Update the saved DC info (if contact already exists) + if (hContact != INVALID_HANDLE_VALUE) + { + DWORD dwIP, dwExternalIP; + WORD wPort; + + if (dwExternalIP = chain->getDWord(0x03, 1)) + setSettingDword(hContact, "RealIP", dwExternalIP); + if (dwIP = chain->getDWord(0x04, 1)) + setSettingDword(hContact, "IP", dwIP); + if (wPort = chain->getWord(0x05, 1)) + setSettingWord(hContact, "UserPort", wPort); + + // Save tick value + BYTE bClientID = getSettingByte(hContact, "ClientID", 0); + if (bClientID == CLID_GENERIC || bClientID == CLID_ICQ6) + setSettingDword(hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); + else + setSettingDword(hContact, "TickTS", 0); + } + + // Parse the next message level + if (tlv = chain->getTLV(0x2711, 1)) + { + parseServRelayData(tlv->pData, tlv->wLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType); + } + else + { + NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); + } + // Clean up + disposeChain(&chain); + } + else if (CompareGUIDs(q1,q2,q3,q4, MCAP_REVERSE_DC_REQ)) + { // Handle reverse DC request + if (wCommand == 1) + { + NetLog_Server("Cannot handle abort messages yet... :("); + SAFE_FREE((void**)&pBuf); + return; + } + if (wTLVLen < 4) + { // just check if at least one tlv is there + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + SAFE_FREE((void**)&pBuf); + return; + } + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + SAFE_FREE((void**)&pBuf); + return; + } + chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); + if (!chain) + { // Malformed packet + NetLog_Server("Error: Malformed data in packet"); + SAFE_FREE((void**)&pBuf); + return; + } + + WORD wAckType = chain->getWord(0x0A, 1); + // Parse the next message level + if (tlv = chain->getTLV(0x2711, 1)) + { + if (tlv->wLen == 0x1B) + { + BYTE *buf = tlv->pData; + DWORD dwUin; + + unpackLEDWord(&buf, &dwUin); + + HANDLE hContact = HContactFromUIN(dwUin, NULL); + if (hContact == INVALID_HANDLE_VALUE) + { + NetLog_Server("Error: %s from unknown contact %u", "Reverse Connect Request", dwUin); + } + else + { + DWORD dwIp, dwPort; + WORD wVersion; + BYTE bMode; + + unpackDWord(&buf, &dwIp); + unpackLEDWord(&buf, &dwPort); + unpackByte(&buf, &bMode); + buf += 4; // unknown + if (dwPort) + buf += 4; // port, again? + else + unpackLEDWord(&buf, &dwPort); + unpackLEWord(&buf, &wVersion); + + setSettingDword(hContact, "IP", dwIp); + setSettingWord(hContact, "UserPort", (WORD)dwPort); + setSettingByte(hContact, "DCType", bMode); + setSettingWord(hContact, "Version", wVersion); + if (wVersion > 6) + { + cookie_reverse_connect *pCookie = (cookie_reverse_connect*)SAFE_MALLOC(sizeof(cookie_reverse_connect)); + + unpackLEDWord(&buf, (DWORD*)&pCookie->ft); + pCookie->dwMsgID1 = dwMsgID1; + pCookie->dwMsgID2 = dwMsgID2; + + OpenDirectConnection(hContact, DIRECTCONN_REVERSE, (void*)pCookie); + } + else + NetLog_Server("Warning: Unsupported direct protocol version in %s", "Reverse Connect Request"); + } + } + else + { + NetLog_Server("Malformed %s", "Reverse Connect Request"); + } + } + else + { + NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); + } + // Clean up + disposeChain(&chain); + } + else if (CompareGUIDs(q1,q2,q3,q4, MCAP_FILE_TRANSFER)) + { // this is an OFT packet + handleRecvServMsgOFT(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); + } + else if (CompareGUIDs(q1,q2,q3,q4, MCAP_CONTACTS)) + { // this is Contacts Transfer + handleRecvServMsgContacts(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); + } + else // here should be detection of extra data streams (Xtraz) + { + NetLog_Server("Unknown Message Format Capability"); + } + } + else + { + NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 2); + } + + SAFE_FREE((void**)&pBuf); +} + + +void CIcqProto::parseServRelayData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType) +{ + WORD wId; + + if (wLen < 2) + { + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + return; + } + + unpackLEWord(&pDataBuf, &wId); // Incorrect identification, but working + wLen -= 2; + + // Only 0x1B are real messages + if (wId == 0x001B) + { + WORD wVersion; + WORD wCookie; + DWORD dwGuid1,dwGuid2,dwGuid3,dwGuid4; + + if (wLen < 31) + { // just check if we have data to work with + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + return; + } + + unpackLEWord(&pDataBuf, &wVersion); + wLen -= 2; + + if (hContact != INVALID_HANDLE_VALUE) + setSettingWord(hContact, "Version", wVersion); + + unpackDWord(&pDataBuf, &dwGuid1); // plugin type GUID + unpackDWord(&pDataBuf, &dwGuid2); + unpackDWord(&pDataBuf, &dwGuid3); + unpackDWord(&pDataBuf, &dwGuid4); + wLen -= 16; + + // Skip lots of unused stuff + pDataBuf += 9; + wLen -= 9; + + unpackLEWord(&pDataBuf, &wId); + wLen -= 2; + + unpackLEWord(&pDataBuf, &wCookie); + wLen -= 2; + + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) + { // is this a normal message ? + BYTE bMsgType; + BYTE bFlags; + WORD wStatus, wPritority; + WORD wMsgLen; + + if (wLen < 20) + { // check if there is everything that should be there + NetLog_Server("Message (format %u) - Ignoring empty message", 2); + return; + } + + pDataBuf += 12; /* all zeroes */ + wLen -= 12; + unpackByte(&pDataBuf, &bMsgType); + wLen -= 1; + unpackByte(&pDataBuf, &bFlags); + wLen -= 1; + + // Status + unpackLEWord(&pDataBuf, &wStatus); + wLen -= 2; + + // Priority + unpackLEWord(&pDataBuf, &wPritority); + wLen -= 2; + NetLog_Server("Priority: %u", wPritority); + + // Message + unpackLEWord(&pDataBuf, &wMsgLen); + wLen -= 2; + + // HANDLERS + switch (bMsgType) + { + // File messages, handled by the file module + case MTYPE_FILEREQ: + { + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + + char* szMsg = (char *)_alloca(wMsgLen + 1); + memcpy(szMsg, pDataBuf, wMsgLen); + szMsg[wMsgLen] = '\0'; + pDataBuf += wMsgLen; + wLen -= wMsgLen; + + if (wAckType == 0 || wAckType == 1) + { + // File requests 7 + handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 7, FALSE); + } + else if (wAckType == 2) + { + // File reply 7 + handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); + } + else + { + NetLog_Server("Ignored strange file message"); + } + + break; + } + + // Chat messages, handled by the chat module + case MTYPE_CHAT: + { // TODO: this type is deprecated + break; + } + + // Plugin messages, need further parsing + case MTYPE_PLUGIN: + { + if (wLen < wMsgLen) + { // sanity check + NetLog_Server("Error: Malformed server Greeting message"); + return; + } + + parseServRelayPluginData(pDataBuf + wMsgLen, wLen - wMsgLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType, bFlags, wStatus, wCookie, wVersion); + break; + } + + // Everything else + default: + { + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + message_ack_params pMsgAck = {0}; + + pMsgAck.bType = MAT_SERVER_ADVANCED; + pMsgAck.dwUin = dwUin; + pMsgAck.dwMsgID1 = dwMsgID1; + pMsgAck.dwMsgID2 = dwMsgID2; + pMsgAck.wCookie = wCookie; + pMsgAck.msgType = bMsgType; + pMsgAck.bFlags = bFlags; + handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, bMsgType, bFlags, wAckType, wLen, wMsgLen, (char*)pDataBuf, 0, &pMsgAck); + break; + } + } + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_INFO_PLUGIN)) + { // info manager plugin - obsolete + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + + BYTE bMsgType; + BYTE bLevel; + + pDataBuf += 16; /* unused stuff */ + wLen -= 16; + unpackByte(&pDataBuf, &bMsgType); + wLen -= 1; + + pDataBuf += 3; // unknown + wLen -= 3; + unpackByte(&pDataBuf, &bLevel); + if (bLevel != 0 || wLen < 16) + { + NetLog_Server("Invalid %s Manager Plugin message from %u", "Info", dwUin); + return; + } + unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID + unpackDWord(&pDataBuf, &dwGuid2); + unpackDWord(&pDataBuf, &dwGuid3); + unpackDWord(&pDataBuf, &dwGuid4); + wLen -= 16; + + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_INFO)) + { + NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "info"); + } + else + NetLog_Server("Unknown %s Manager message from %u", "Info", dwUin); + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_STATUS_PLUGIN)) + { // status manager plugin - obsolete + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + + BYTE bMsgType; + BYTE bLevel; + + pDataBuf += 16; /* unused stuff */ + wLen -= 16; + unpackByte(&pDataBuf, &bMsgType); + wLen -= 1; + + pDataBuf += 3; // unknown + wLen -= 3; + unpackByte(&pDataBuf, &bLevel); + if (bLevel != 0 || wLen < 16) + { + NetLog_Server("Invalid %s Manager Plugin message from %u", "Status", dwUin); + return; + } + unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID + unpackDWord(&pDataBuf, &dwGuid2); + unpackDWord(&pDataBuf, &dwGuid3); + unpackDWord(&pDataBuf, &dwGuid4); + wLen -= 16; + + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_STATUS)) + NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "status"); + else + NetLog_Server("Unknown %s Manager message from %u", "Status", dwUin); + } + else + NetLog_Server("Unknown signature (%08x-%08x-%08x-%08x) in message (format 2)", dwGuid1, dwGuid2, dwGuid3, dwGuid4); + } + else + NetLog_Server("Unknown wId1 (%u) in message (format 2)", wId); +} + + +void CIcqProto::parseServRelayPluginData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wVersion) +{ + int nTypeId; + WORD wFunction; + + NetLog_Server("Parsing Greeting message through server"); + + // Message plugin identification + if (!unpackPluginTypeId(&pDataBuf, &wLen, &nTypeId, &wFunction, FALSE)) return; + + if (wLen > 8) + { + DWORD dwLengthToEnd; + DWORD dwDataLen; + + // Length of remaining data + unpackLEDWord(&pDataBuf, &dwLengthToEnd); + + // Length of message + unpackLEDWord(&pDataBuf, &dwDataLen); + wLen -= 8; + + if (dwDataLen > wLen) + dwDataLen = wLen; + + if (nTypeId == MTYPE_FILEREQ && wAckType == 2) + { + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + NetLog_Server("This is file ack"); + + char *szMsg = (char *)_alloca(dwDataLen + 1); + memcpy(szMsg, pDataBuf, dwDataLen); + szMsg[dwDataLen] = '\0'; + pDataBuf += dwDataLen; + wLen -= (WORD)dwDataLen; + + handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); + } + else if (nTypeId == MTYPE_FILEREQ && wAckType == 1) + { + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + NetLog_Server("This is a file request"); + + char *szMsg = (char *)_alloca(dwDataLen + 1); + memcpy(szMsg, pDataBuf, dwDataLen); + szMsg[dwDataLen] = '\0'; + pDataBuf += dwDataLen; + wLen -= (WORD)dwDataLen; + + handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8, FALSE); + } + else if (nTypeId == MTYPE_CHAT && wAckType == 1) + { // TODO: this is deprecated + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + NetLog_Server("This is a chat request"); + + char *szMsg = (char *)_alloca(dwDataLen + 1); + memcpy(szMsg, pDataBuf, dwDataLen); + szMsg[dwDataLen] = '\0'; + pDataBuf += dwDataLen; + wLen -= (WORD)dwDataLen; + + // handleChatRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8); + } + else if (nTypeId == MTYPE_STATUSMSGEXT && wFunction >= 1 && wFunction <= 3) + { // handle extended status message request + int nMsgType = 0; + + switch (wFunction) + { + case 1: // Away + if (m_iStatus == ID_STATUS_ONLINE || m_iStatus == ID_STATUS_INVISIBLE) + nMsgType = MTYPE_AUTOONLINE; + else if (m_iStatus == ID_STATUS_AWAY) + nMsgType = MTYPE_AUTOAWAY; + else if (m_iStatus == ID_STATUS_FREECHAT) + nMsgType = MTYPE_AUTOFFC; + break; + + case 2: // Busy + if (m_iStatus == ID_STATUS_OCCUPIED) + nMsgType = MTYPE_AUTOBUSY; + else if (m_iStatus == ID_STATUS_DND) + nMsgType = MTYPE_AUTODND; + break; + + case 3: // N/A + if (m_iStatus == ID_STATUS_NA) + nMsgType = MTYPE_AUTONA; + } + handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, bFlags, wAckType, dwLengthToEnd, 0, (char*)pDataBuf, MTF_PLUGIN | MTF_STATUS_EXTENDED, NULL); + } + else if (nTypeId) + { + if (!dwUin) + { // AIM cannot send this, just sanity + NetLog_Server("Error: Malformed UIN in packet"); + return; + } + message_ack_params pMsgAck = {0}; + + pMsgAck.bType = MAT_SERVER_ADVANCED; + pMsgAck.dwUin = dwUin; + pMsgAck.dwMsgID1 = dwMsgID1; + pMsgAck.dwMsgID2 = dwMsgID2; + pMsgAck.wCookie = wCookie; + pMsgAck.msgType = nTypeId; + pMsgAck.bFlags = bFlags; + handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nTypeId, bFlags, wAckType, dwLengthToEnd, (WORD)dwDataLen, (char*)pDataBuf, MTF_PLUGIN, &pMsgAck); + } + else + { + NetLog_Server("Unsupported plugin message type %d", nTypeId); + } + } + else + NetLog_Server("Error: Malformed server plugin message"); +} + + +void CIcqProto::handleRecvServMsgContacts(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand) +{ + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (wCommand == 0) + { // received contacts + if (wLen < 4) + { // just check if at least one tlv is there + NetLog_Server("Message (format %u) - Ignoring empty contacts message", 2); + return; + } + oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, 0); + if (!chain) + { // sanity check + NetLog_Server("Message (format %u) - Invalid data", 2); + return; + } + + WORD wAckType = chain->getWord(0x0A, 1); + + if (wAckType == 1) + { // it is really message containing contacts, parse them + oscar_tlv *tlvUins = chain->getTLV(0x2711, 1); + oscar_tlv *tlvNames = chain->getTLV(0x2712, 1); + + if (!tlvUins || tlvUins->wLen < 4) + { + NetLog_Server("Malformed '%s' message", "contacts"); + disposeChain(&chain); + return; + } + int nContacts = 0x10, iContact = 0; + ICQSEARCHRESULT **contacts = (ICQSEARCHRESULT**)SAFE_MALLOC(nContacts * sizeof(ICQSEARCHRESULT*)); + WORD wContactsGroup = 0; + int valid = 1; + BYTE *pBuffer = tlvUins->pData; + int nLen = tlvUins->wLen; + + while (nLen > 2) + { // parse UIDs + if (!wContactsGroup) + { + WORD wGroupLen; + + unpackWord(&pBuffer, &wGroupLen); + nLen -= 2; + if (nLen >= wGroupLen + 2) + { + pBuffer += wGroupLen; + unpackWord(&pBuffer, &wContactsGroup); + nLen -= wGroupLen + 2; + } + else + break; + } + else + { // group parsed, UIDs waiting + WORD wUidLen; + + unpackWord(&pBuffer, &wUidLen); + nLen -= 2; + if (nLen >= wUidLen) + { + char *szUid = (char*)SAFE_MALLOC(wUidLen + 1); + unpackString(&pBuffer, szUid, wUidLen); + nLen -= wUidLen; + + if (iContact >= nContacts) + { // the list is too small, resize it + nContacts += 0x10; + contacts = (ICQSEARCHRESULT**)SAFE_REALLOC(contacts, nContacts * sizeof(ICQSEARCHRESULT*)); + } + contacts[iContact] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); + contacts[iContact]->hdr.cbSize = sizeof(ICQSEARCHRESULT); + contacts[iContact]->hdr.flags = PSR_TCHAR; + contacts[iContact]->hdr.nick = null_strdup(_T("")); + contacts[iContact]->hdr.id = ansi_to_tchar(szUid); + + if (IsStringUIN(szUid)) + { // icq contact + contacts[iContact]->uin = atoi(szUid); + if (contacts[iContact]->uin == 0) + valid = 0; + } + else + { // aim contact + if (!strlennull(szUid)) + valid = 0; + } + iContact++; + + SAFE_FREE(&szUid); + } + else + { + if (wContactsGroup) valid = 0; + break; + } + + wContactsGroup--; + } + } + if (!iContact || !valid) + { + NetLog_Server("Malformed '%s' message", "contacts"); + disposeChain(&chain); + for (int i = 0; i < iContact; i++) + { + SAFE_FREE(&contacts[i]->hdr.id); + SAFE_FREE(&contacts[i]->hdr.nick); + SAFE_FREE((void**)&contacts[i]); + } + SAFE_FREE((void**)&contacts); + return; + } + nContacts = iContact; + if (tlvNames && tlvNames->wLen >= 4) + { // parse names, if available + pBuffer = tlvNames->pData; + nLen = tlvNames->wLen; + iContact = 0; + + while (nLen > 2) + { // parse Names + if (!wContactsGroup) + { + WORD wGroupLen; + + unpackWord(&pBuffer, &wGroupLen); + nLen -= 2; + if (nLen >= wGroupLen + 2) + { + pBuffer += wGroupLen; + unpackWord(&pBuffer, &wContactsGroup); + nLen -= wGroupLen + 2; + } + else + break; + } + else + { // group parsed, Names waiting + WORD wNickLen; + + unpackWord(&pBuffer, &wNickLen); + nLen -= 2; + if (nLen >= wNickLen) + { + WORD wNickTLV, wNickTLVLen; + char *pNick = NULL; + + unpackTypedTLV(pBuffer, wNickLen, 0x01, &wNickTLV, &wNickTLVLen, (LPBYTE*)&pNick); + if (wNickTLV == 0x01) + { + SAFE_FREE(&contacts[iContact]->hdr.nick); + contacts[iContact]->hdr.nick = utf8_to_tchar(pNick); + } + else + SAFE_FREE(&pNick); + pBuffer += wNickLen; + nLen -= wNickLen; + + iContact++; + if (iContact >= nContacts) break; + } + else + break; + + wContactsGroup--; + } + } + } + + if (!valid) + { + NetLog_Server("Malformed '%s' message", "contacts"); + } + else + { + int bAdded; + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + + hContact = HContactFromUID(dwUin, szUID, &bAdded); + + // ack the message + icq_sendContactsAck(dwUin, szUID, dwID1, dwID2); + + ccs.szProtoService = PSR_CONTACTS; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = (DWORD)time(NULL); + pre.szMessage = (char *)contacts; + pre.lParam = nContacts; + pre.flags = PREF_TCHAR; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + + for (int i = 0; i < iContact; i++) + { + SAFE_FREE(&contacts[i]->hdr.id); + SAFE_FREE(&contacts[i]->hdr.nick); + SAFE_FREE((void**)&contacts[i]); + } + SAFE_FREE((void**)&contacts); + } + else + NetLog_Server("Error: Received unknown contacts message, ignoring."); + // Clean up + disposeChain(&chain); + } + else if (wCommand == 1) + { + NetLog_Server("Cannot handle abort messages yet... :("); + return; + } + else if (wCommand == 2) + { // acknowledgement + DWORD dwCookie; + HANDLE hCookieContact; + + if (FindMessageCookie(dwID1, dwID2, &dwCookie, &hCookieContact, NULL)) + { + if (hCookieContact != hContact) + NetLog_Server("Warning: Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); + + BroadcastAck(hContact, ACKTYPE_CONTACTS, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); + + ReleaseCookie(dwCookie); + } + else + NetLog_Server("Warning: Unexpected Contact Transfer ack from %s", strUID(dwUin, szUID)); + } +} + + +void CIcqProto::handleRecvServMsgType4(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) +{ + WORD wTLVType; + WORD wTLVLen; + BYTE* pDataBuf; + DWORD dwUin2; + + if (wLen < 2) + { + NetLog_Server("Message (format %u) - Ignoring empty message", 4); + return; + } + + // Unpack the first TLV(5) + unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); + NetLog_Server("Message (format %u) - UID: %s", 4, strUID(dwUin, szUID)); + + // It must be TLV(5) + if (wTLVType == 5) + { + BYTE bMsgType; + BYTE bFlags; + BYTE* pmsg = pDataBuf; + WORD wMsgLen; + + + unpackLEDWord(&pmsg, &dwUin2); + + if (dwUin2 == dwUin) + { + unpackByte(&pmsg, &bMsgType); + unpackByte(&pmsg, &bFlags); + unpackLEWord(&pmsg, &wMsgLen); + + if (bMsgType == 0 && wMsgLen == 1) + { + NetLog_Server("User %u probably checks his ignore state.", dwUin); + } + else + { + cookie_offline_messages *cookie; + DWORD dwRecvTime = (DWORD)time(NULL); + + if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) + { + WORD wTimeTLVType, wTimeTLVLen; + BYTE *pTimeTLV = NULL; + + cookie->nMessages++; + + unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); + if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) + { // found Offline timestamp + BYTE *pBuf = pTimeTLV; + + unpackDWord(&pBuf, &dwRecvTime); + NetLog_Server("Message (format %u) - Offline timestamp is %s", 4, time2text(dwRecvTime)); + } + SAFE_FREE((void**)&pTimeTLV); + } + + if (bMsgType == MTYPE_PLUGIN) + { + WORD wLen = wTLVLen - 8; + int typeId; + + NetLog_Server("Parsing Greeting message through server"); + + pmsg += wMsgLen; + wLen -= wMsgLen; + + if (unpackPluginTypeId(&pmsg, &wLen, &typeId, NULL, FALSE) && wLen > 8) + { + DWORD dwLengthToEnd; + DWORD dwDataLen; + + // Length of remaining data + unpackLEDWord(&pmsg, &dwLengthToEnd); + + // Length of message + unpackLEDWord(&pmsg, &dwDataLen); + wLen -= 8; + + if (dwDataLen > wLen) + dwDataLen = wLen; + + if (typeId) + { + uid_str szUID; + handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, typeId, bFlags, 0, dwLengthToEnd, (WORD)dwDataLen, (char*)pmsg, MTF_PLUGIN, NULL); + } + else + { + NetLog_Server("Unsupported plugin message type %d", typeId); + } + } + } + else + { + uid_str szUID; + handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, bMsgType, bFlags, 0, wTLVLen - 8, wMsgLen, (char*)pmsg, 0, NULL); + } + } + } + else + { + NetLog_Server("Ignoring spoofed TYPE4 message thru server from %d", dwUin); + } + } + else + { + NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 4); + } + + SAFE_FREE((void**)&pDataBuf); +} + + +// +// Helper functions +// + +static int TypeGUIDToTypeId(DWORD dwGuid1, DWORD dwGuid2, DWORD dwGuid3, DWORD dwGuid4, WORD wType) +{ + int nTypeID = MTYPE_UNKNOWN; + + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_STATUSMSGEXT)) + { + nTypeID = MTYPE_STATUSMSGEXT; + } + else if (wType==MGTYPE_UNDEFINED) + { + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) + { // icq6 message ack + nTypeID = MTYPE_PLAIN; + } + } + else if (wType==MGTYPE_STANDARD_SEND) + { + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_WEBURL)) + { + nTypeID = MTYPE_URL; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) + { + nTypeID = MTYPE_CONTACTS; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CHAT)) + { + nTypeID = MTYPE_CHAT; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_FILE)) + { + nTypeID = MTYPE_FILEREQ; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_GREETING_CARD)) + { + nTypeID = MTYPE_GREETINGCARD; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_MESSAGE)) + { + nTypeID = MTYPE_MESSAGE; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_SMS_MESSAGE)) + { + nTypeID = MTYPE_SMS_MESSAGE; + } + } + else if (wType==MGTYPE_CONTACTS_REQUEST) + { + if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) + { + nTypeID = MTYPE_REQUESTCONTACTS; + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) + { + nTypeID = MTYPE_SCRIPT_DATA; + } + } + else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) + { + if (wType==MGTYPE_SCRIPT_INVITATION) + { + nTypeID = MTYPE_SCRIPT_INVITATION; + } + else if (wType==MGTYPE_SCRIPT_NOTIFY) + { + nTypeID = MTYPE_SCRIPT_NOTIFY; + } + } + + return nTypeID; +} + + +int CIcqProto::unpackPluginTypeId(BYTE **pBuffer, WORD *pwLen, int *pTypeId, WORD *pFunctionId, BOOL bThruDC) +{ + WORD wLen = *pwLen; + WORD wInfoLen; + DWORD dwPluginNameLen; + DWORD q1,q2,q3,q4; + WORD qt; + + if (wLen < 24) + return 0; // Failure + + unpackLEWord(pBuffer, &wInfoLen); + + unpackDWord(pBuffer, &q1); // get data GUID & function id + unpackDWord(pBuffer, &q2); + unpackDWord(pBuffer, &q3); + unpackDWord(pBuffer, &q4); + unpackLEWord(pBuffer, &qt); + wLen -= 20; + + if (pFunctionId) *pFunctionId = qt; + + unpackLEDWord(pBuffer, &dwPluginNameLen); + wLen -= 4; + + if (dwPluginNameLen > wLen) + { // check for malformed plugin name + dwPluginNameLen = wLen; + NetLog_Uni(bThruDC, "Warning: malformed size of plugin name."); + } + char *szPluginName = (char *)_alloca(dwPluginNameLen + 1); + memcpy(szPluginName, *pBuffer, dwPluginNameLen); + szPluginName[dwPluginNameLen] = '\0'; + wLen -= (WORD)dwPluginNameLen; + + *pBuffer += dwPluginNameLen; + + int typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt); + if (!typeId) + NetLog_Uni(bThruDC, "Error: Unknown type {%08x-%08x-%08x-%08x:%04x}: %s", q1,q2,q3,q4,qt, szPluginName); + + if (wInfoLen >= 22 + dwPluginNameLen) + { // sanity checking + wInfoLen -= (WORD)(22 + dwPluginNameLen); + + // check if enough data is available - skip remaining bytes of info block + if (wLen >= wInfoLen) + { + *pBuffer += wInfoLen; + wLen -= wInfoLen; + } + } + + *pwLen = wLen; + *pTypeId = typeId; + + return 1; // Success +} + + +int getPluginTypeIdLen(int nTypeID) +{ + switch (nTypeID) + { + case MTYPE_SCRIPT_NOTIFY: + return 0x51; + + case MTYPE_FILEREQ: + return 0x2B; + + case MTYPE_AUTOONLINE: + case MTYPE_AUTOAWAY: + case MTYPE_AUTOBUSY: + case MTYPE_AUTODND: + case MTYPE_AUTOFFC: + return 0x3C; + + case MTYPE_AUTONA: + return 0x3B; + + default: + return 0; + } +} + + +void packPluginTypeId(icq_packet *packet, int nTypeID) +{ + switch (nTypeID) + { + case MTYPE_SCRIPT_NOTIFY: + packLEWord(packet, 0x04f); // Length + + packGUID(packet, MGTYPE_XTRAZ_SCRIPT); // Message Type GUID + packLEWord(packet, MGTYPE_SCRIPT_NOTIFY); // Function ID + packLEDWord(packet, 0x002a); // Request type string + packBuffer(packet, (LPBYTE)"Script Plug-in: Remote Notification Arrive", 0x002a); + + packDWord(packet, 0x00000100); // Unknown binary stuff + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packWord(packet, 0x0000); + packByte(packet, 0x00); + + break; + + case MTYPE_FILEREQ: + packLEWord(packet, 0x029); // Length + + packGUID(packet, MGTYPE_FILE); // Message Type GUID + packWord(packet, 0x0000); // Unknown + packLEDWord(packet, 0x0004); // Request type string + packBuffer(packet, (LPBYTE)"File", 0x0004); + + packDWord(packet, 0x00000100); // More unknown binary stuff + packDWord(packet, 0x00010000); + packDWord(packet, 0x00000000); + packWord(packet, 0x0000); + packByte(packet, 0x00); + + break; + + case MTYPE_AUTOONLINE: + case MTYPE_AUTOAWAY: + case MTYPE_AUTOFFC: + packLEWord(packet, 0x03A); // Length + + packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID + + packLEWord(packet, 1); // Function ID + packLEDWord(packet, 0x13); // Request type string + packBuffer(packet, (LPBYTE)"Away Status Message", 0x13); + + packDWord(packet, 0x01000000); // Unknown binary stuff + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packByte(packet, 0x00); + + break; + + case MTYPE_AUTOBUSY: + case MTYPE_AUTODND: + packLEWord(packet, 0x03A); // Length + + packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID + + packLEWord(packet, 2); // Function ID + packLEDWord(packet, 0x13); // Request type string + packBuffer(packet, (LPBYTE)"Busy Status Message", 0x13); + + packDWord(packet, 0x02000000); // Unknown binary stuff + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packByte(packet, 0x00); + + break; + + case MTYPE_AUTONA: + packLEWord(packet, 0x039); // Length + + packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID + + packLEWord(packet, 3); // Function ID + packLEDWord(packet, 0x12); // Request type string + packBuffer(packet, (LPBYTE)"N/A Status Message", 0x12); + + packDWord(packet, 0x03000000); // Unknown binary stuff + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packDWord(packet, 0x00000000); + packByte(packet, 0x00); + + break; + } +} + + +void CIcqProto::handleStatusMsgReply(const char *szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char *szMsg, int nMsgFlags) +{ + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + + if (hContact == INVALID_HANDLE_VALUE) + { + NetLog_Server("%sIgnoring status message from unknown contact %u", szPrefix, dwUin); + return; + } + + int status = AwayMsgTypeToStatus(bMsgType); + if (status == ID_STATUS_OFFLINE) + { + NetLog_Server("%sIgnoring unknown status message from %u", szPrefix, dwUin); + return; + } + + // it is probably UTF-8 status reply + if (wVersion == 9 || (nMsgFlags & MTF_PLUGIN) && wVersion == 10) + { + if (UTF8_IsValid(szMsg)) pre.flags |= PREF_UTF; + } + + ccs.szProtoService = PSR_AWAYMSG; + ccs.hContact = hContact; + ccs.wParam = status; + ccs.lParam = (LPARAM)⪯ + pre.szMessage = (char*)szMsg; + pre.timestamp = time(NULL); + pre.lParam = wCookie; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); +} + + +HANDLE CIcqProto::handleMessageAck(DWORD dwUin, char *szUID, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags, int nMsgFlags) +{ + if (bFlags == 3) + { + HANDLE hCookieContact; + cookie_message_data *pCookieData = NULL; + + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) + { + NetLog_Server("%sIgnoring unrequested status message from %u", "handleMessageAck: ", dwUin); + + ReleaseCookie(wCookie); + return INVALID_HANDLE_VALUE; + } + + if (hContact != hCookieContact) + { + NetLog_Server("%sAck Contact does not match Cookie Contact(0x%x != 0x%x)", "handleMessageAck: ", hContact, hCookieContact); + + ReleaseCookie(wCookie); + return INVALID_HANDLE_VALUE; + } + ReleaseCookie(wCookie); + + handleStatusMsgReply("handleMessageAck: ", hContact, dwUin, wVersion, type, wCookie, (char*)buf, nMsgFlags); + } + else + { + // Should not happen + NetLog_Server("%sIgnored type %u ack message (this should not happen)", "handleMessageAck: ", type); + } + + return INVALID_HANDLE_VALUE; +} + + +/* this function send all acks from handleMessageTypes */ +void CIcqProto::sendMessageTypesAck(HANDLE hContact, int bUnicode, message_ack_params *pArgs) +{ + if (pArgs) + { + if ((pArgs->msgType == MTYPE_PLAIN && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_MESSAGE)) + || (pArgs->msgType == MTYPE_URL && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_URL)) + || pArgs->msgType == MTYPE_CONTACTS) + { + if (pArgs->bType == MAT_SERVER_ADVANCED) + { // Only ack message packets + icq_sendAdvancedMsgAck(pArgs->dwUin, pArgs->dwMsgID1, pArgs->dwMsgID2, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags); + } + else if (pArgs->bType == MAT_DIRECT) + { // Send acknowledgement + icq_sendDirectMsgAck(pArgs->pDC, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags, bUnicode ? (char *)CAP_UTF8MSGS : NULL); + } + } + } +} + + +/* this function also processes direct packets, so it should be bulletproof */ +/* pMsg points to the beginning of the message */ +void CIcqProto::handleMessageTypes(DWORD dwUin, char *szUID, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, int nMsgFlags, message_ack_params *pAckParams) +{ + HANDLE hContact = INVALID_HANDLE_VALUE; + BOOL bThruDC = (nMsgFlags & MTF_DIRECT) == MTF_DIRECT; + int bAdded; + + + if (dwDataLen < wMsgLen) + { + NetLog_Uni(bThruDC, "Ignoring overflowed message"); + return; + } + + if (wAckType == 2) + { + handleMessageAck(dwUin, szUID, wCookie, wVersion, type, wMsgLen, (LPBYTE)pMsg, (BYTE)flags, nMsgFlags); + return; + } + + char *szMsg = (char *)SAFE_MALLOC(wMsgLen + 1); + if (wMsgLen > 0) + { + memcpy(szMsg, pMsg, wMsgLen); + pMsg += wMsgLen; + dwDataLen -= wMsgLen; + } + szMsg[wMsgLen] = '\0'; + + + char* pszMsgField[2*MAX_CONTACTSSEND+1]; + int nMsgFields = 0; + + pszMsgField[0] = szMsg; + if (type == MTYPE_URL || type == MTYPE_AUTHREQ || type == MTYPE_ADDED || type == MTYPE_CONTACTS || type == MTYPE_EEXPRESS || type == MTYPE_WWP) + { + for (char *pszMsg=szMsg, nMsgFields=1; *pszMsg; pszMsg++) + { + if ((BYTE)*pszMsg == 0xFE) + { + *pszMsg = '\0'; + pszMsgField[nMsgFields++] = pszMsg + 1; + if (nMsgFields >= SIZEOF(pszMsgField)) + break; + } + } + } + + switch (type) { + + case MTYPE_PLAIN: /* plain message */ + { + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + + // Check if this message is marked as UTF8 encoded + if (dwDataLen > 12) + { + DWORD dwGuidLen = 0; + int bDoubleMsg = 0; + + if (bThruDC) + { + DWORD dwExtraLen = *(DWORD*)pMsg; + + if (dwExtraLen < dwDataLen && !strncmp(szMsg, "{\\rtf", 5)) + { // it is icq5 sending us crap, get real message from it + WCHAR* usMsg = (WCHAR*)_alloca((dwExtraLen + 1)*sizeof(WCHAR)); + // make sure it is null-terminated + wcsncpy(usMsg, (WCHAR*)(pMsg + 4), dwExtraLen); + usMsg[dwExtraLen] = '\0'; + SAFE_FREE(&szMsg); + szMsg = (char*)make_utf8_string(usMsg); + + if (!IsUnicodeAscii(usMsg, dwExtraLen)) + pre.flags = PREF_UTF; // only mark real non-ascii messages as unicode + + bDoubleMsg = 1; + } + } + + if (!bDoubleMsg) + { + dwGuidLen = *(DWORD*)(pMsg+8); + dwDataLen -= 12; + pMsg += 12; + } + + while ((dwGuidLen >= 38) && (dwDataLen >= dwGuidLen)) + { + if (!strncmp(pMsg, CAP_UTF8MSGS, 38)) + { // Found UTF8 cap, convert message to ansi + pre.flags = PREF_UTF; + break; + } + else if (!strncmp(pMsg, CAP_RTFMSGS, 38)) + { // Found RichText cap + NetLog_Uni(bThruDC, "Warning: User %u sends us RichText.", dwUin); + break; + } + + dwGuidLen -= 38; + dwDataLen -= 38; + pMsg += 38; + } + } + + hContact = HContactFromUIN(dwUin, &bAdded); + sendMessageTypesAck(hContact, pre.flags & PREF_UTF, pAckParams); + + if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) + { // message is Ansi and contains national characters, create Unicode part by codepage + char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); + if (usMsg) + { + SAFE_FREE(&szMsg); + szMsg = (char*)usMsg; + pre.flags = PREF_UTF; + } + } + + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = dwTimestamp; + pre.szMessage = (char *)szMsg; + + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + break; + + case MTYPE_URL: + { + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + + if (nMsgFields < 2) + { + NetLog_Uni(bThruDC, "Malformed '%s' message", "URL"); + break; + } + + hContact = HContactFromUIN(dwUin, &bAdded); + sendMessageTypesAck(hContact, 0, pAckParams); + + char *szTitle = ICQTranslateUtf(LPGEN("Incoming URL:")); + char *szDataDescr = ansi_to_utf8(pszMsgField[0]); + char *szDataUrl = ansi_to_utf8(pszMsgField[1]); + char *szBlob = (char *)SAFE_MALLOC(strlennull(szTitle) + strlennull(szDataDescr) + strlennull(szDataUrl) + 8); + strcpy(szBlob, szTitle); + strcat(szBlob, " "); + strcat(szBlob, szDataDescr); // Description + strcat(szBlob, "\r\n"); + strcat(szBlob, szDataUrl); // URL + SAFE_FREE(&szTitle); + SAFE_FREE(&szDataDescr); + SAFE_FREE(&szDataUrl); + + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = dwTimestamp; + pre.szMessage = (char *)szBlob; + pre.flags = PREF_UTF; + + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + SAFE_FREE(&szBlob); + } + break; + + case MTYPE_AUTHREQ: /* auth request */ + /* format: nick FE first FE last FE email FE unk-char FE msg 00 */ + { + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + char* szBlob; + char* pCurBlob; + + + if (nMsgFields < 6) + { + NetLog_Server("Malformed '%s' message", "auth req"); + break; + } + + ccs.szProtoService=PSR_AUTH; + ccs.hContact=hContact=HContactFromUIN(dwUin, &bAdded); + ccs.wParam=0; + ccs.lParam=(LPARAM)⪯ + pre.timestamp=dwTimestamp; + pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+5; + + /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/ + pCurBlob=szBlob=(char *)_alloca(pre.lParam); + memcpy(pCurBlob,&dwUin,sizeof(DWORD)); pCurBlob+=sizeof(DWORD); + memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE); + strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[3]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[5]); + pre.szMessage=(char *)szBlob; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + } + break; + + case MTYPE_ADDED: /* 'you were added' */ + /* format: nick FE first FE last FE email 00 */ + { + DWORD cbBlob; + PBYTE pBlob, pCurBlob; + + if (nMsgFields < 4) + { + NetLog_Server("Malformed '%s' message", "you were added"); + break; + } + + hContact = HContactFromUIN(dwUin, &bAdded); + + /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) */ + cbBlob=sizeof(DWORD)*2+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+4; + pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); + *(DWORD*)pCurBlob = dwUin; pCurBlob += sizeof(DWORD); + *(DWORD*)pCurBlob = DWORD(hContact); pCurBlob += sizeof(DWORD); + strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob += strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob += strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob += strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[3]); + + AddEvent(NULL, EVENTTYPE_ADDED, dwTimestamp, 0, cbBlob, pBlob); + } + break; + + case MTYPE_CONTACTS: + { + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + char* pszNContactsEnd; + int nContacts; + int i; + + + if (nMsgFields < 3 + || (nContacts = strtol(pszMsgField[0], &pszNContactsEnd, 10)) == 0 + || pszNContactsEnd - pszMsgField[0] != (int)strlennull(pszMsgField[0]) + || nMsgFields < nContacts * 2 + 1) + { + NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); + break; + } + + int valid = 1; + ICQSEARCHRESULT** isrList = (ICQSEARCHRESULT**)_alloca(nContacts * sizeof(ICQSEARCHRESULT*)); + for (i = 0; i < nContacts; i++) + { + isrList[i] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); + isrList[i]->hdr.cbSize = sizeof(ICQSEARCHRESULT); + isrList[i]->hdr.flags = PSR_TCHAR; + if (IsStringUIN(pszMsgField[1 + i * 2])) + { // icq contact + isrList[i]->uin = atoi(pszMsgField[1 + i * 2]); + if (isrList[i]->uin == 0) + valid = 0; + } + else + { // aim contact + if (!strlennull(pszMsgField[1 + i * 2])) + valid = 0; + } + isrList[i]->hdr.id = ansi_to_tchar(pszMsgField[1 + i * 2]); + isrList[i]->hdr.nick = ansi_to_tchar(pszMsgField[2 + i * 2]); + } + + if (!valid) + { + NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); + } + else + { + hContact = HContactFromUIN(dwUin, &bAdded); + sendMessageTypesAck(hContact, 0, pAckParams); + + ccs.szProtoService = PSR_CONTACTS; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = dwTimestamp; + pre.szMessage = (char *)isrList; + pre.lParam = nContacts; + pre.flags = PREF_TCHAR; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + + for (i = 0; i < nContacts; i++) + { + SAFE_FREE(&isrList[i]->hdr.id); + SAFE_FREE(&isrList[i]->hdr.nick); + SAFE_FREE((void**)&isrList[i]); + } + } + break; + + case MTYPE_PLUGIN: // FIXME: this should be removed - it is never called + hContact = NULL; + + switch(dwUin) + { + case 1111: /* icqmail 'you've got mail' - not processed */ + break; + } + break; + + case MTYPE_SMS_MESSAGE: + /* it's a SMS message from a mobile - broadcast to SMS plugin */ + if (dwUin != 1002) + { + NetLog_Uni(bThruDC, "Malformed '%s' message", "SMS Mobile"); + break; + } + NetLog_Server("Received SMS Mobile message"); + + BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, NULL, (LPARAM)szMsg); + break; + + case MTYPE_STATUSMSGEXT: + /* it's either extended StatusMsg reply from icq2003b or a IcqWebMessage */ + if (dwUin == 1003) + { + NetLog_Server("Received ICQWebMessage - NOT SUPPORTED"); + } + break; + + case MTYPE_WWP: + /* format: fromname FE FE FE fromemail FE unknownbyte FE 'Sender IP: xxx.xxx.xxx.xxx' 0D 0A body */ + { + DWORD cbBlob; + PBYTE pBlob, pCurBlob; + + if (nMsgFields < 6) + { + NetLog_Server("Malformed '%s' message", "web pager"); + break; + } + + /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ + cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; + pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); + strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[3]); + + AddEvent(NULL, ICQEVENTTYPE_WEBPAGER, dwTimestamp, 0, cbBlob, pBlob); + } + break; + + case MTYPE_EEXPRESS: + /* format: fromname FE FE FE fromemail FE unknownbyte FE body */ + { + DWORD cbBlob; + PBYTE pBlob, pCurBlob; + + if (nMsgFields < 6) + { + NetLog_Server("Malformed '%s' message", "e-mail express"); + break; + } + + /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ + cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; + pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); + strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; + strcpy((char *)pCurBlob,pszMsgField[3]); + + AddEvent(NULL, ICQEVENTTYPE_EMAILEXPRESS, dwTimestamp, 0, cbBlob, pBlob); + } + break; + + case MTYPE_REQUESTCONTACTS: + /* it's a contacts-request */ + NetLog_Uni(bThruDC, "Received %s from %u", "Request for Contacts", dwUin); + break; + + case MTYPE_GREETINGCARD: + /* it's a greeting card */ + NetLog_Uni(bThruDC, "Received %s from %u", "Greeting Card", dwUin); + break; + + case MTYPE_SCRIPT_NOTIFY: + /* it's a xtraz notify request */ + NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Notify Request", dwUin); + handleXtrazNotify(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); + break; + + case MTYPE_SCRIPT_INVITATION: + /* it's a xtraz invitation to session */ + NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Invitation", dwUin); + handleXtrazInvitation(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); + break; + + case MTYPE_SCRIPT_DATA: + /* it's a xtraz data packet */ + NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz data packet", dwUin); + handleXtrazData(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); + break; + + case MTYPE_AUTOONLINE: + case MTYPE_AUTOAWAY: + case MTYPE_AUTOBUSY: + case MTYPE_AUTONA: + case MTYPE_AUTODND: + case MTYPE_AUTOFFC: + { + char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(type)); + if (szMsg) + { + struct rates_status_message_response: public rates_queue_item + { + protected: + virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) + { + rates_status_message_response *pDest = (rates_status_message_response*)aDest; + if (!pDest) + pDest = new rates_status_message_response(ppro, wGroup); + + pDest->bExtended = bExtended; + pDest->dwMsgID1 = dwMsgID1; + pDest->dwMsgID2 = dwMsgID2; + pDest->wCookie = wCookie; + pDest->wVersion = wVersion; + pDest->nMsgType = nMsgType; + + return rates_queue_item::copyItem(pDest); + }; + public: + rates_status_message_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { }; + virtual ~rates_status_message_response() { }; + + virtual void execute() + { + char **pszMsg = ppro->MirandaStatusToAwayMsg(AwayMsgTypeToStatus(nMsgType)); + if (bExtended) + ppro->icq_sendAwayMsgReplyServExt(dwUin, szUid, dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, pszMsg); + else if (dwUin) + ppro->icq_sendAwayMsgReplyServ(dwUin, dwMsgID1, dwMsgID2, wCookie, wVersion, (BYTE)nMsgType, pszMsg); + else + ppro->NetLog_Server("Error: Malformed UIN in packet"); + }; + + BOOL bExtended; + DWORD dwMsgID1; + DWORD dwMsgID2; + WORD wCookie; + WORD wVersion; + int nMsgType; + }; + + m_ratesMutex->Enter(); + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); + m_ratesMutex->Leave(); + + rates_status_message_response rr(this, wGroup); + rr.bExtended = (nMsgFlags & MTF_STATUS_EXTENDED) == MTF_STATUS_EXTENDED; + rr.hContact = hContact; + rr.dwUin = dwUin; + rr.szUid = szUID; + rr.dwMsgID1 = dwMsgID; + rr.dwMsgID2 = dwMsgID2; + rr.wCookie = wCookie; + rr.wVersion = wVersion; + rr.nMsgType = type; + + handleRateItem(&rr, RQT_RESPONSE); + } + + break; + } + + case MTYPE_FILEREQ: // Never happens + default: + NetLog_Uni(bThruDC, "Unprocessed message type %d", type); + break; + + } + + SAFE_FREE(&szMsg); +} + + +void CIcqProto::handleRecvMsgResponse(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ + DWORD dwUin; + uid_str szUid; + DWORD dwCookie; + WORD wMessageFormat; + WORD wStatus; + WORD bMsgType = 0; + BYTE bFlags; + WORD wLength; + HANDLE hCookieContact; + DWORD dwMsgID1, dwMsgID2; + WORD wVersion = 0; + cookie_message_data *pCookieData = NULL; + + + unpackLEDWord(&buf, &dwMsgID1); // Message ID + unpackLEDWord(&buf, &dwMsgID2); + wLen -= 8; + + unpackWord(&buf, &wMessageFormat); + wLen -= 2; + if (wMessageFormat != 2) + { + NetLog_Server("SNAC(4.B) Unknown type"); + return; + } + + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); + + buf += 2; // 3. unknown + wLen -= 2; + + if (!FindMessageCookie(dwMsgID1, dwMsgID2, &dwCookie, &hCookieContact, &pCookieData)) + { + NetLog_Server("SNAC(4.B) Received an ack that I did not ask for from (%u)", dwUin); + return; + } + + if (IsValidOscarTransfer(pCookieData)) + { // it is OFT response + handleRecvServResponseOFT(buf, wLen, dwUin, szUid, pCookieData); + return; + } + + if (!dwUin) + { // AIM cannot send this - just sanity + NetLog_Server("Error: Invalid UID in message response."); + return; + } + + // Length of sub chunk? + if (wLen >= 2) + { + unpackLEWord(&buf, &wLength); + wLen -= 2; + } + else + wLength = 0; + + if (wLength == 0x1b && pCookieData->bMessageType != MTYPE_REVERSE_REQUEST) + { // this can be v8 greeting message reply + WORD wCookie; + + unpackLEWord(&buf, &wVersion); + buf += 27; /* unknowns from the msg we sent */ + wLen -= 29; + + // Message sequence (SEQ2) + unpackLEWord(&buf, &wCookie); + wLen -= 2; + + // Unknown (12 bytes) + buf += 12; + wLen -= 12; + + // Message type + unpackByte(&buf, (BYTE*)&bMsgType); + unpackByte(&buf, &bFlags); + wLen -= 2; + + // Status + unpackLEWord(&buf, &wStatus); + wLen -= 2; + + // Priority? + buf += 2; + wLen -= 2; + + if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) + { // use old reliable method + NetLog_Server("Warning: Invalid cookie in %s from (%u)", "message response", dwUin); + + if (pCookieData->bMessageType != MTYPE_AUTOAWAY && bFlags == 3) + { // most probably a broken ack of some kind (e.g. from R&Q), try to fix that + bMsgType = pCookieData->bMessageType; + bFlags = 0; + + NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); + } + } + else if (bMsgType != MTYPE_PLUGIN && pCookieData->bMessageType != MTYPE_AUTOAWAY) + { // just because some clients break it... + dwCookie = wCookie; + + if (bMsgType != pCookieData->bMessageType) + NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); + + bMsgType = pCookieData->bMessageType; + } + else if (pCookieData->bMessageType == MTYPE_AUTOAWAY && bMsgType != MTYPE_PLUGIN) + { + if (bMsgType != pCookieData->nAckType) + NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); + } + } + else + { + bMsgType = pCookieData->bMessageType; + bFlags = 0; + } + + if (hCookieContact != hContact) + { + NetLog_Server("SNAC(4.B) Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); + + ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe + return; + } + + if (bFlags == 3) // A status message reply + { + handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, bMsgType, (WORD)dwCookie, (char*)(buf + 2), 0); + } + else + { // An ack of some kind + int ackType; + + + if (hContact == NULL || hContact == INVALID_HANDLE_VALUE) + { + NetLog_Server("SNAC(4.B) Message from unknown contact (%u)", dwUin); + + ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe + return; + } + + switch (bMsgType) { + + case MTYPE_FILEREQ: + { + char* szMsg; + WORD wMsgLen; + + // Message length + unpackLEWord(&buf, &wMsgLen); + wLen -= 2; + szMsg = (char *)_alloca(wMsgLen + 1); + szMsg[wMsgLen] = '\0'; + if (wMsgLen > 0) + { + memcpy(szMsg, buf, wMsgLen); + buf += wMsgLen; + wLen -= wMsgLen; + } + handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); + // No success protoack will be sent here, since all file requests + // will have been 'sent' when the server returns its ack + return; + } + + case MTYPE_PLUGIN: + { + WORD wMsgLen; + DWORD dwLengthToEnd; + DWORD dwDataLen; + int typeId; + WORD wFunctionId; + + + if (wLength != 0x1B) + { + NetLog_Server("Invalid Greeting %s", "message response"); + + ReleaseCookie(dwCookie); + return; + } + + NetLog_Server("Parsing Greeting %s", "message response"); + + // Message + unpackLEWord(&buf, &wMsgLen); + wLen -= 2; + buf += wMsgLen; + wLen -= wMsgLen; + + // This packet is malformed. Possibly a file accept from Miranda IM 0.1.2.1 + if (wLen < 20) + { + ReleaseCookie(dwCookie); + return; + } + + if (!unpackPluginTypeId(&buf, &wLen, &typeId, &wFunctionId, FALSE)) + { + ReleaseCookie(dwCookie); + return; + } + + if (wLen < 4) + { + NetLog_Server("Error: Invalid greeting %s", "message response"); + + ReleaseCookie(dwCookie); + return; + } + + // Length of remaining data + unpackLEDWord(&buf, &dwLengthToEnd); + wLen -= 4; + + if (wLen >= 4 && dwLengthToEnd > 0) + unpackLEDWord(&buf, &dwDataLen); // Length of message + else + dwDataLen = 0; + + + switch (typeId) + { + case MTYPE_PLAIN: + if (pCookieData && pCookieData->bMessageType == MTYPE_AUTOAWAY && dwLengthToEnd >= 4) + { // ICQ 6 invented this + char *szMsg = (char*)_alloca(dwDataLen + 1); + + if (dwDataLen > 0) + memcpy(szMsg, buf, dwDataLen); + szMsg[dwDataLen] = '\0'; + handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, 0); + + ReleaseCookie(dwCookie); + return; + } + else + ackType = ACKTYPE_MESSAGE; + break; + + case MTYPE_URL: + ackType = ACKTYPE_URL; + break; + + case MTYPE_CONTACTS: + ackType = ACKTYPE_CONTACTS; + break; + + case MTYPE_FILEREQ: + { + NetLog_Server("This is file ack"); + + char *szMsg = (char *)_alloca(dwDataLen + 1); + + if (dwDataLen > 0) + memcpy(szMsg, buf, dwDataLen); + szMsg[dwDataLen] = '\0'; + buf += dwDataLen; + wLen -= (WORD)dwDataLen; + + handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); + // No success protoack will be sent here, since all file requests + // will have been 'sent' when the server returns its ack + } + return; + + case MTYPE_SCRIPT_NOTIFY: + { + char *szMsg = (char*)_alloca(dwDataLen + 1); + + if (dwDataLen > 0) + memcpy(szMsg, buf, dwDataLen); + szMsg[dwDataLen] = '\0'; + + handleXtrazNotifyResponse(dwUin, hContact, (WORD)dwCookie, szMsg, dwDataLen); + + ReleaseCookie(dwCookie); + } + return; + + case MTYPE_STATUSMSGEXT: + { // handle Away Message response (ICQ 6) + char *szMsg = (char*)SAFE_MALLOC(dwDataLen + 1); + + if (dwDataLen > 0) + memcpy(szMsg, buf, dwDataLen); + szMsg[dwDataLen] = '\0'; + szMsg = EliminateHtml(szMsg, dwDataLen); + + handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, MTF_PLUGIN | MTF_STATUS_EXTENDED); + + SAFE_FREE(&szMsg); + + ReleaseCookie(dwCookie); + } + return; + + default: + NetLog_Server("Error: Unknown plugin message response, type %d.", typeId); + return; + } + } + break; + + case MTYPE_PLAIN: + ackType = ACKTYPE_MESSAGE; + break; + + case MTYPE_URL: + ackType = ACKTYPE_URL; + break; + + case MTYPE_AUTHOK: + case MTYPE_AUTHDENY: + ackType = ACKTYPE_AUTHREQ; + break; + + case MTYPE_ADDED: + ackType = ACKTYPE_ADDED; + break; + + case MTYPE_CONTACTS: + ackType = ACKTYPE_CONTACTS; + break; + + case MTYPE_REVERSE_REQUEST: + { + cookie_reverse_connect *pReverse = (cookie_reverse_connect*)pCookieData; + + if (pReverse->ft) + { + filetransfer *ft = (filetransfer*)pReverse->ft; + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + } + NetLog_Server("Reverse Connect request failed"); + // Set DC status to failed + setSettingByte(hContact, "DCStatus", 2); + + ReleaseCookie(dwCookie); + } + return; + + case MTYPE_CHAT: + default: + NetLog_Server("SNAC(4.B) Unknown message type (%u) in switch", bMsgType); + return; + } + + if ((ackType == MTYPE_PLAIN && pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) || ackType != MTYPE_PLAIN) + { + BroadcastAck(hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)(WORD)dwCookie, 0); + } + } + + ReleaseCookie(dwCookie); +} + + +// A response to a CLI_SENDMSG +void CIcqProto::handleRecvServMsgError(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) +{ + WORD wError; + char *pszErrorMessage; + HANDLE hContact; + cookie_message_data *pCookieData = NULL; + int nMessageType; + + + if (wLen < 2) + return; + + if (FindCookie((WORD)dwSequence, &hContact, (void**)&pCookieData)) + { // all packet cookies from msg family has command 0 in the queue + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + { // Invalid contact + FreeCookie((WORD)dwSequence); + return; + } + + // Error code + unpackWord(&buf, &wError); + + if (wError == 9 && pCookieData->bMessageType == MTYPE_AUTOAWAY) + { // we failed to request away message the normal way, try it AIM way + icq_packet packet; + + serverPacketInit(&packet, (WORD)(13 + getUINLen(dwUin))); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, (WORD)dwSequence); + packWord(&packet, 0x03); + packUIN(&packet, dwUin); + + sendServPacket(&packet); + return; + } + + // Not all of these are actually used in family 4 + // This will be moved into a special error handling function later + switch (wError) { + + case 0x0002: // Server rate limit exceeded + pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x02"); + break; + + case 0x0003: // Client rate limit exceeded + pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x03"); + break; + + case 0x0004: // Recipient is not logged in (resend in a offline message) + if (pCookieData->bMessageType == MTYPE_PLAIN) + { + if (pCookieData->isOffline) + { // offline failed - most probably to AIM contact + pszErrorMessage = Translate("The contact does not support receiving offline messages."); + break; + } + // TODO: this needs better solution + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + } + pszErrorMessage = Translate("The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04"); + break; + + case 0x0005: // Requested service unavailable + pszErrorMessage = Translate("The messaging service is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x05"); + break; + + case 0x0009: // Not supported by client (resend in a simpler format) + pszErrorMessage = Translate("The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09"); + break; + + case 0x000A: // Refused by client + pszErrorMessage = Translate("You sent too long message. The receiving client does not support it.\r\nSNAC(4.1) Error x0A"); + break; + + case 0x000E: // Incorrect SNAC format + pszErrorMessage = Translate("The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E"); + break; + + case 0x0013: // User temporarily unavailable + pszErrorMessage = Translate("The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13"); + break; + + case 0x0001: // Invalid SNAC header + case 0x0006: // Requested service not defined + case 0x0007: // You sent obsolete SNAC + case 0x0008: // Not supported by server + case 0x000B: // Reply too big + case 0x000C: // Responses lost + case 0x000D: // Request denied + case 0x000F: // Insufficient rights + case 0x0010: // In local permit/deny (recipient blocked) + case 0x0011: // Sender too evil + case 0x0012: // Receiver too evil + case 0x0014: // No match + case 0x0015: // List overflow + case 0x0016: // Request ambiguous + case 0x0017: // Server queue full + case 0x0018: // Not while on AOL + default: + if (pszErrorMessage = (char*)_alloca(256)) + null_snprintf(pszErrorMessage, 256, Translate("SNAC(4.1) SENDMSG Error (x%02x)"), wError); + break; + } + + + switch (pCookieData->bMessageType) { + + case MTYPE_PLAIN: + nMessageType = ACKTYPE_MESSAGE; + break; + + case MTYPE_CHAT: + nMessageType = ACKTYPE_CHAT; + break; + + case MTYPE_FILEREQ: + nMessageType = ACKTYPE_FILE; + break; + + case MTYPE_URL: + nMessageType = ACKTYPE_URL; + break; + + case MTYPE_CONTACTS: + nMessageType = ACKTYPE_CONTACTS; + break; + + default: + nMessageType = -1; + break; + } + + if (nMessageType != -1) + { + BroadcastAck(hContact, nMessageType, ACKRESULT_FAILED, (HANDLE)(WORD)dwSequence, (LPARAM)pszErrorMessage); + } + else + { + NetLog_Server("Error: Message delivery to %u failed: %s", dwUin, pszErrorMessage); + } + + FreeCookie((WORD)dwSequence); + + if (pCookieData->bMessageType != MTYPE_FILEREQ) + SAFE_FREE((void**)&pCookieData); + } + else + { + unpackWord(&buf, &wError); + + LogFamilyError(ICQ_MSG_FAMILY, wError); + } +} + + +void CIcqProto::handleServerAck(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) +{ + DWORD dwUin; + uid_str szUID; + WORD wChannel; + cookie_message_data *pCookieData; + + + if (wLen < 13) + { + NetLog_Server("Ignoring SNAC(4,C) Packet to short"); + return; + } + + buf += 8; // Skip first 8 bytes + wLen -= 8; + + // Message channel + unpackWord(&buf, &wChannel); + wLen -= 2; + + // Sender + if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; + + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (FindCookie((WORD)dwSequence, NULL, (void**)&pCookieData)) + { + // If the user requested a full ack, the + // server ack should be ignored here. + if (pCookieData && (pCookieData->nAckType == ACKTYPE_SERVER)) + { + if ((hContact != NULL) && (hContact != INVALID_HANDLE_VALUE)) + { + int ackType; + int ackRes = ACKRESULT_SUCCESS; + + switch (pCookieData->bMessageType) { + case MTYPE_PLAIN: + ackType = ACKTYPE_MESSAGE; + break; + + case MTYPE_CONTACTS: + ackType = ACKTYPE_CONTACTS; + break; + + case MTYPE_URL: + ackType = ACKTYPE_URL; + break; + + case MTYPE_FILEREQ: + ackType = ACKTYPE_FILE; + ackRes = ACKRESULT_SENTREQUEST; + // Note 1: We are not allowed to free the cookie here because it + // contains the filetransfer struct that we will need later + // Note 2: The cookiedata is NOT a message_cookie_data*, it is a + // filetransfer*. IMPORTANT! (it's one of those silly things) + break; + + default: + ackType = -1; + NetLog_Server("Error: Unknown message type %d in ack", pCookieData->bMessageType); + break; + } + if (ackType != -1) + BroadcastAck(hContact, ackType, ackRes, (HANDLE)(WORD)dwSequence, 0); + + if (pCookieData->bMessageType != MTYPE_FILEREQ) + SAFE_FREE((void**)&pCookieData); // this could be a bad idea, but I think it is safe + } + FreeCookie((WORD)dwSequence); + } + else if (pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) + NetLog_Server("Received a server ack, waiting for client ack."); + else + NetLog_Server("Ignored a server ack I did not ask for"); + } +} + + +void CIcqProto::handleMissedMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ + DWORD dwUin; + uid_str szUid; + WORD wChannel; + WORD wWarningLevel; + WORD wCount; + WORD wError; + WORD wTLVCount; + + if (wLen < 14) + return; // Too short + + // Message channel? + unpackWord(&buf, &wChannel); + wLen -= 2; + + // Sender + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + if (wLen < 8) + return; // Too short + + // Warning level? + unpackWord(&buf, &wWarningLevel); + wLen -= 2; + + // TLV count + unpackWord(&buf, &wTLVCount); + wLen -= 2; + + // Read past user info TLVs + oscar_tlv_chain *pChain = readIntoTLVChain(&buf, (WORD)(wLen-4), wTLVCount); + if (pChain) + disposeChain(&pChain); + + if (wLen < 4) + return; // Too short + + // Number of missed messages + unpackWord(&buf, &wCount); + wLen -= 2; + + // Error code + unpackWord(&buf, &wError); + wLen -= 2; + + { // offline retrieval process in progress, note that we received missed message notification + cookie_offline_messages *cookie; + + if (FindCookieByType(CKT_OFFLINEMESSAGE, NULL, NULL, (void**)&cookie)) + cookie->nMissed++; + } + + switch (wError) { + + case 0: // The message was invalid + case 1: // The message was too long + case 2: // The sender has flooded the server + case 4: // You are too evil + break; + + default: + // 3 = Sender too evil (sender warn level > your max_msg_sevil) + return; + break; + } + + // Create event to notify user + int bAdded; + + AddEvent(HContactFromUID(dwUin, szUid, &bAdded), ICQEVENTTYPE_MISSEDMESSAGE, time(NULL), 0, sizeof(wError), (PBYTE)&wError); +} + + +void CIcqProto::handleOffineMessagesReply(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ + cookie_offline_messages *cookie; + + if (FindCookie(dwRef, NULL, (void**)&cookie)) + { + NetLog_Server("End of offline msgs, %u received", cookie->nMessages); + if (cookie->nMissed) + { // NASTY WORKAROUND!! + // The ICQ server has a bug that causes offline messages to be received again and again when some + // missed message notification is present (most probably it is not processed correctly and causes + // the server to fail the purging process); try to purge them using the old offline messages + // protocol. 2008/05/21 + NetLog_Server("Warning: Received %u missed message notifications, trying to fix the server.", cookie->nMissed); + + icq_packet packet; + // This will delete the messages stored on server + serverPacketInit(&packet, 24); + packFNACHeader(&packet, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); + packWord(&packet, 1); // TLV Type + packWord(&packet, 10); // TLV Length + packLEWord(&packet, 8); // Data length + packLEDWord(&packet, m_dwLocalUIN); // My UIN + packLEWord(&packet, CLI_DELETE_OFFLINE_MSGS_REQ); // Ack offline msgs + packLEWord(&packet, 0x0000); // Request sequence number (we dont use this for now) + + // Send it + sendServPacket(&packet); + } + + ReleaseCookie(dwRef); + } + else + NetLog_Server("Error: Received unexpected end of offline msgs."); +} + + +void CIcqProto::handleTypingNotification(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) +{ + DWORD dwUin; + uid_str szUid; + WORD wChannel; + WORD wNotification; + + if (wLen < 14) + { + NetLog_Server("Ignoring SNAC(4.x11) Packet to short"); + return; + } + +#ifndef DBG_CAPMTN + { + NetLog_Server("Ignoring unexpected typing notification"); + return; + } +#endif + + // The message ID, unused? + buf += 8; + wLen -= 8; + + // Message channel, unused? + unpackWord(&buf, &wChannel); + wLen -= 2; + + // Sender + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); + + if (hContact == INVALID_HANDLE_VALUE) return; + + // Typing notification code + unpackWord(&buf, &wNotification); + wLen -= 2; + + SetContactCapabilities(hContact, CAPF_TYPING); + + // Notify user + switch (wNotification) { + + case MTN_FINISHED: + case MTN_TYPED: + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); + NetLog_Server("%s has stopped typing (ch %u).", strUID(dwUin, szUid), wChannel); + break; + + case MTN_BEGUN: + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60); + NetLog_Server("%s is typing a message (ch %u).", strUID(dwUin, szUid), wChannel); + break; + + case MTN_WINDOW_CLOSED: + { + char szFormat[MAX_PATH]; + char szMsg[MAX_PATH]; + char *nick = NickFromHandleUtf(hContact); + + null_snprintf(szMsg, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" has closed the message window."), szFormat, MAX_PATH), nick); + ShowPopUpMsg(hContact, ICQTranslateUtfStatic(LPGEN("ICQ Note"), szFormat, MAX_PATH), szMsg, LOG_NOTE); + SAFE_FREE((void**)&nick); + + NetLog_Server("%s has closed the message window.", strUID(dwUin, szUid)); + } + break; + + default: + NetLog_Server("Unknown typing notification from %s, type %u (ch %u)", strUID(dwUin, szUid), wNotification, wChannel); + break; + } +} + + +void CIcqProto::sendTypingNotification(HANDLE hContact, WORD wMTNCode) +{ + _ASSERTE((wMTNCode == MTN_FINISHED) || (wMTNCode == MTN_TYPED) || (wMTNCode == MTN_BEGUN) || (wMTNCode == MTN_WINDOW_CLOSED)); + + DWORD dwUin; + uid_str szUid; + if (getContactUid(hContact, &dwUin, &szUid)) + return; // Invalid contact + + WORD wLen = getUIDLen(dwUin, szUid); + + icq_packet packet; + serverPacketInit(&packet, 23 + wLen); + packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_MTN); + packLEDWord(&packet, 0x0000); // Msg ID + packLEDWord(&packet, 0x0000); // Msg ID + packWord(&packet, 0x01); // Channel + packUID(&packet, dwUin, szUid); // User ID + packWord(&packet, wMTNCode); // Notification type + + sendServPacketAsync(&packet); +} diff --git a/protocols/IcqOscarJ/src/fam_09bos.cpp b/protocols/IcqOscarJ/src/fam_09bos.cpp new file mode 100644 index 0000000000..327e045a96 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_09bos.cpp @@ -0,0 +1,106 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleBosFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_PRIVACY_RIGHTS_REPLY: // Reply to CLI_REQBOS + handlePrivacyRightsReply(pBuffer, wBufferLength); + break; + + case ICQ_ERROR: + { + WORD wError; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + LogFamilyError(ICQ_BOS_FAMILY, wError); + break; + } + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_BOS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + } +} + +void CIcqProto::handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength) +{ + if (wBufferLength >= 12) + { + oscar_tlv_chain* pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0); + if (pChain) + { + WORD wMaxVisibleContacts; + WORD wMaxInvisibleContacts; + WORD wMaxTemporaryVisibleContacts; + + wMaxVisibleContacts = pChain->getWord(0x0001, 1); + wMaxInvisibleContacts = pChain->getWord(0x0002, 1); + wMaxTemporaryVisibleContacts = pChain->getWord(0x0003, 1); + + disposeChain(&pChain); + + NetLog_Server("PRIVACY: Max visible %u, max invisible %u, max temporary visible %u items.", wMaxVisibleContacts, wMaxInvisibleContacts, wMaxTemporaryVisibleContacts); + + // Success + return; + } + } + + // Failure + NetLog_Server("Warning: Malformed SRV_PRIVACY_RIGHTS_REPLY"); +} + +void CIcqProto::makeContactTemporaryVisible(HANDLE hContact) +{ + DWORD dwUin; + uid_str szUid; + + if (getSettingByte(hContact, "TemporaryVisible", 0)) + return; // already there + + if (getContactUid(hContact, &dwUin, &szUid)) + return; // Invalid contact + + icq_sendGenericContact(dwUin, szUid, ICQ_BOS_FAMILY, ICQ_CLI_ADDTEMPVISIBLE); + + setSettingByte(hContact, "TemporaryVisible", 1); + +#ifdef _DEBUG + NetLog_Server("Added contact %s to temporary visible list", strUID(dwUin, szUid)); +#endif +} diff --git a/protocols/IcqOscarJ/src/fam_0alookup.cpp b/protocols/IcqOscarJ/src/fam_0alookup.cpp new file mode 100644 index 0000000000..da77295ecb --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_0alookup.cpp @@ -0,0 +1,130 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleLookupFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_LOOKUP_EMAIL_REPLY: // AIM search reply + handleLookupEmailReply(pBuffer, wBufferLength, pSnacHeader->dwRef); + break; + + case ICQ_ERROR: + { + WORD wError; + cookie_search *pCookie; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookie)) + { + if (wError == 0x14) + NetLog_Server("Lookup: No results"); + + ReleaseLookupCookie(pSnacHeader->dwRef, pCookie); + + if (wError == 0x14) return; + } + + LogFamilyError(ICQ_LOOKUP_FAMILY, wError); + break; + } + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LOOKUP_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + +void CIcqProto::ReleaseLookupCookie(DWORD dwCookie, cookie_search *pCookie) +{ + FreeCookie(dwCookie); + SAFE_FREE(&pCookie->szObject); + + if (pCookie->dwMainId && !pCookie->dwStatus) + { // we need to wait for main search + pCookie->dwStatus = 1; + } + else + { // finish everything + if (pCookie->dwMainId) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)pCookie->dwMainId, 0); + else // we are single + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); + + SAFE_FREE((void**)&pCookie); + } +} + +void CIcqProto::handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie) +{ + ICQSEARCHRESULT sr = {0}; + oscar_tlv_chain *pChain; + cookie_search *pCookie; + + if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) + { + NetLog_Server("Error: Received unexpected lookup reply"); + return; + } + + NetLog_Server("SNAC(0x0A,0x3): Lookup reply"); + + sr.hdr.cbSize = sizeof(sr); + sr.hdr.flags = PSR_TCHAR; + sr.hdr.email = ansi_to_tchar(pCookie->szObject); + + // Syntax check, read chain + if (wLen >= 4 && (pChain = readIntoTLVChain(&buf, wLen, 0))) + { + for (WORD i = 1; TRUE; i++) + { // collect the results + char *szUid = pChain->getString(0x01, i); + if (!szUid) break; + sr.hdr.id = ansi_to_tchar(szUid); + sr.hdr.nick = sr.hdr.id; + // broadcast the result + if (pCookie->dwMainId) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)pCookie->dwMainId, (LPARAM)&sr); + else + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)dwCookie, (LPARAM)&sr); + SAFE_FREE(&sr.hdr.id); + SAFE_FREE(&szUid); + } + disposeChain(&pChain); + } + SAFE_FREE(&sr.hdr.email); + + ReleaseLookupCookie(dwCookie, pCookie); +} diff --git a/protocols/IcqOscarJ/src/fam_0bstatus.cpp b/protocols/IcqOscarJ/src/fam_0bstatus.cpp new file mode 100644 index 0000000000..7a979007e2 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_0bstatus.cpp @@ -0,0 +1,62 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004,2005,2006 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleStatusFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_STATS_MINREPORTINTERVAL: + { + WORD wInterval; + unpackWord(&pBuffer, &wInterval); + NetLog_Server("Server sent SNAC(x0B,x02) - SRV_SET_MINREPORTINTERVAL (Value: %u hours)", wInterval); + } + break; + + case ICQ_ERROR: + { + WORD wError; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + LogFamilyError(ICQ_STATS_FAMILY, wError); + break; + } + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_STATS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} diff --git a/protocols/IcqOscarJ/src/fam_13servclist.cpp b/protocols/IcqOscarJ/src/fam_13servclist.cpp new file mode 100644 index 0000000000..5df30ee5ec --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_13servclist.cpp @@ -0,0 +1,2068 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static int unpackServerListItem(BYTE **pbuf, WORD *pwLen, char *pszRecordName, WORD *pwGroupId, WORD *pwItemId, WORD *pwItemType, WORD *pwTlvLength); + + +void CIcqProto::handleServCListFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_LISTS_ACK: // UPDATE_ACK + if (wBufferLength >= 2) + { + WORD wError; + cookie_servlist_action* sc; + + unpackWord(&pBuffer, &wError); + + if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) + { // look for action cookie +#ifdef _DEBUG + NetLog_Server("Received expected server list ack, action: %d, result: %d", sc->dwAction, wError); +#endif + FreeCookie(pSnacHeader->dwRef); // release cookie + + if (sc->dwAction == SSA_ACTION_GROUP) + { // group cookie, handle sub-items + int i; + +#ifdef _DEBUG + NetLog_Server("Server-List: Grouped action contains %d actions.", sc->dwGroupCount); +#endif + pBuffer -= 2; // revoke unpack + if (wBufferLength != 2*sc->dwGroupCount) + NetLog_Server("Error: Server list ack does not contain expected amount of result codes (%u != %u)", wBufferLength/2, sc->dwGroupCount); + + for (i = 0; i < sc->dwGroupCount; i++) + { + if (wBufferLength >= 2) + { // get proper result code + unpackWord(&pBuffer, &wError); + wBufferLength -= 2; + } + else // missing result code, give some special + wError = -1; + +#ifdef _DEBUG + NetLog_Server("Action: %d, ack result: %d", sc->pGroupItems[i]->dwAction, wError); +#endif + // call normal ack handler + handleServerCListAck(sc->pGroupItems[i], wError); + } + // Release cookie + SAFE_FREE((void**)&sc->pGroupItems); + SAFE_FREE((void**)&sc); + } + else // single ack + handleServerCListAck(sc, wError); + } + else + { + NetLog_Server("Received unexpected server list ack %u", wError); + } + } + break; + + case ICQ_LISTS_SRV_REPLYLISTS: + { /* received server-list rights */ + handleServerCListRightsReply(pBuffer, wBufferLength); + +#ifdef _DEBUG + NetLog_Server("Server sent SNAC(x13,x03) - SRV_REPLYLISTS"); +#endif + } + break; + + case ICQ_LISTS_LIST: // SRV_REPLYROSTER + { + cookie_servlist_action* sc; + BOOL blWork; + + blWork = bIsSyncingCL; + bIsSyncingCL = TRUE; // this is not used if cookie takes place + + if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) + { // we do it by reliable cookie + if (!sc->lParam) + { // is this first packet ? + ResetSettingsOnListReload(); + sc->lParam = 1; + } + handleServerCListReply(pBuffer, wBufferLength, pSnacHeader->wFlags, info); + if (!(pSnacHeader->wFlags & 0x0001)) + { // was that last packet ? + ReleaseCookie(pSnacHeader->dwRef); // yes, release cookie + } + } + else + { // use old fake + if (!blWork) + { // this can fail on some crazy situations + ResetSettingsOnListReload(); + } + handleServerCListReply(pBuffer, wBufferLength, pSnacHeader->wFlags, info); + } + break; + } + + case ICQ_LISTS_UPTODATE: // SRV_REPLYROSTEROK + { + cookie_servlist_action* sc; + + bIsSyncingCL = FALSE; + + if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) + { // we requested servlist check +#ifdef _DEBUG + NetLog_Server("Server stated roster is ok."); +#endif + ReleaseCookie(pSnacHeader->dwRef); + LoadServerIDs(); + } + else + NetLog_Server("Server sent unexpected SNAC(x13,x0F) - SRV_REPLYROSTEROK"); + + // This will activate the server side list + sendRosterAck(); // this must be here, cause of failures during cookie alloc + handleServUINSettings(wListenPort, info); + break; + } + + case ICQ_LISTS_CLI_MODIFYSTART: + NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_CLI_MODIFYSTART, "Server is modifying contact list"); + break; + + case ICQ_LISTS_CLI_MODIFYEND: + NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_CLI_MODIFYEND, "End of server modification"); + break; + + case ICQ_LISTS_ADDTOLIST: + case ICQ_LISTS_UPDATEGROUP: + case ICQ_LISTS_REMOVEFROMLIST: + { + int nItems = 0; + + while (wBufferLength >= 10) + { + WORD wGroupId, wItemId, wItemType, wTlvLen; + uid_str szRecordName; + + if (unpackServerListItem(&pBuffer, &wBufferLength, szRecordName, &wGroupId, &wItemId, &wItemType, &wTlvLen)) + { + BYTE *buf = pBuffer; + oscar_tlv_chain *pChain = NULL; + + nItems++; + + // parse possible item's data + if (wBufferLength >= wTlvLen && wTlvLen > 0) + { + pChain = readIntoTLVChain(&buf, wTlvLen, 0); + pBuffer += wTlvLen; + wBufferLength -= wTlvLen; + } + else if (wTlvLen > 0) + wBufferLength = 0; + + // process item change + if (pSnacHeader->wSubtype == ICQ_LISTS_ADDTOLIST) + handleServerCListItemAdd(szRecordName, wGroupId, wItemId, wItemType, pChain); + else if (pSnacHeader->wSubtype == ICQ_LISTS_UPDATEGROUP) + handleServerCListItemUpdate(szRecordName, wGroupId, wItemId, wItemType, pChain); + else if (pSnacHeader->wSubtype == ICQ_LISTS_REMOVEFROMLIST) + handleServerCListItemDelete(szRecordName, wGroupId, wItemId, wItemType, pChain); + + // release memory + disposeChain(&pChain); + } + } + { // log packet basics + char *szChange; + char szLogText[MAX_PATH]; + + if (pSnacHeader->wSubtype == ICQ_LISTS_ADDTOLIST) + szChange = "Server added %u item(s) to list"; + else if (pSnacHeader->wSubtype == ICQ_LISTS_UPDATEGROUP) + szChange = "Server updated %u item(s) on list"; + else if (pSnacHeader->wSubtype == ICQ_LISTS_REMOVEFROMLIST) + szChange = "Server removed %u item(s) from list"; + + null_snprintf(szLogText, MAX_PATH, szChange, nItems); + NetLog_Server("Server sent SNAC(x13,x%02x) - %s", pSnacHeader->wSubtype, szLogText); + } + } + break; + + case ICQ_LISTS_AUTHREQUEST: + handleRecvAuthRequest(pBuffer, wBufferLength); + break; + + case ICQ_LISTS_SRV_AUTHRESPONSE: + handleRecvAuthResponse(pBuffer, wBufferLength); + break; + + case ICQ_LISTS_AUTHGRANTED: + NetLog_Server("Server sent SNAC(x13,x%02x) - %s", ICQ_LISTS_AUTHGRANTED, "User granted us future authorization"); + break; + + case ICQ_LISTS_YOUWEREADDED: + handleRecvAdded(pBuffer, wBufferLength); + break; + + case ICQ_LISTS_ERROR: + if (wBufferLength >= 2) + { + WORD wError; + cookie_servlist_action* sc; + + unpackWord(&pBuffer, &wError); + + if (FindCookie(pSnacHeader->dwRef, NULL, (void**)&sc)) + { // look for action cookie +#ifdef _DEBUG + NetLog_Server("Received server list error, action: %d, result: %d", sc->dwAction, wError); +#endif + FreeCookie(pSnacHeader->dwRef); // release cookie + + if (sc->dwAction==SSA_CHECK_ROSTER) + { // the serv-list is unavailable turn it off + icq_LogMessage(LOG_ERROR, LPGEN("Server contact list is unavailable, Miranda will use local contact list.")); + m_bSsiEnabled = 0; + handleServUINSettings(wListenPort, info); + } + /// FIXME: properly release pending operations & cookie memory + SAFE_FREE((void**)&sc); + } + else + { + LogFamilyError(ICQ_LISTS_FAMILY, wError); + } + } + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LISTS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + + +static int unpackServerListItem(BYTE **pbuf, WORD *pwLen, char *pszRecordName, WORD *pwGroupId, WORD *pwItemId, WORD *pwItemType, WORD *pwTlvLength) +{ + WORD wRecordNameLen; + + // The name of the entry. If this is a group header, then this + // is the name of the group. If it is a plain contact list entry, + // then it's the UIN of the contact. + unpackWord(pbuf, &wRecordNameLen); + if (*pwLen < 10 + wRecordNameLen || wRecordNameLen >= MAX_PATH) + return 0; // Failure + + unpackString(pbuf, pszRecordName, wRecordNameLen); + if (pszRecordName) + pszRecordName[wRecordNameLen] = '\0'; + + // The group identifier this entry belongs to. If 0, this is meta information or + // a contact without a group + unpackWord(pbuf, pwGroupId); + + // The ID of this entry. Group headers have ID 0. Otherwise, this + // is a random number generated when the user is added to the + // contact list, or when the user is ignored. See CLI_ADDBUDDY. + unpackWord(pbuf, pwItemId); + + // This field indicates what type of entry this is + unpackWord(pbuf, pwItemType); + + // The length in bytes of the following TLV chain + unpackWord(pbuf, pwTlvLength); + + *pwLen -= wRecordNameLen + 10; + + return 1; // Success +} + + +void CIcqProto::handleServerCListRightsReply(BYTE *buf, WORD wLen) +{ /* received list rights, store the item limits for future use */ + oscar_tlv_chain* chain; + + memset(m_wServerListLimits, -1, sizeof(m_wServerListLimits)); + m_wServerListGroupMaxContacts = 0; + m_wServerListRecordNameMaxLength = 0xFFFF; + + if (chain = readIntoTLVChain(&buf, wLen, 0)) + { + oscar_tlv* pTLV; + + // determine max number of contacts in a group + m_wServerListGroupMaxContacts = chain->getWord(0x0C, 1); + // determine length limit for server-list item's name + m_wServerListRecordNameMaxLength = chain->getWord(0x06, 1); + + if (pTLV = chain->getTLV(0x04, 1)) + { // limits for item types + int i; + WORD *pLimits = (WORD*)pTLV->pData; + + for (i = 0; i < pTLV->wLen / 2; i++) + { + m_wServerListLimits[i] = (pLimits[i] & 0xFF) << 8 | (pLimits[i] >> 8); + + if (i + 1 >= SIZEOF(m_wServerListLimits)) break; + } + + NetLog_Server("SSI: Max %d contacts (%d per group), %d groups, %d permit, %d deny, %d ignore items.", m_wServerListLimits[SSI_ITEM_BUDDY], m_wServerListGroupMaxContacts, m_wServerListLimits[SSI_ITEM_GROUP], m_wServerListLimits[SSI_ITEM_PERMIT], m_wServerListLimits[SSI_ITEM_DENY], m_wServerListLimits[SSI_ITEM_IGNORE]); + } + + disposeChain(&chain); + } +} + + +DWORD CIcqProto::updateServerGroupData(WORD wGroupId, void *groupData, int groupSize, DWORD dwOperationFlags) +{ + DWORD dwCookie; + cookie_servlist_action* ack; + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (!ack) + { + NetLog_Server("Updating of group on server list failed (malloc error)"); + return 0; + } + ack->dwAction = SSA_GROUP_UPDATE; + ack->szGroupName = getServListGroupName(wGroupId); + ack->wGroupId = wGroupId; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + + return icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, ack->wGroupId, ack->szGroupName, groupData, groupSize, dwOperationFlags); +} + + +void CIcqProto::handleServerCListAck(cookie_servlist_action* sc, WORD wError) +{ + switch (sc->dwAction) + { + case SSA_VISIBILITY: + { + if (wError) + NetLog_Server("Server visibility update failed, error %d", wError); + break; + } + case SSA_CONTACT_UPDATE: + { + servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, wError ? PENDING_RESULT_FAILED : PENDING_RESULT_SUCCESS); + if (wError) + { + NetLog_Server("Updating of server contact failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Updating of server contact failed.")); + } + break; + } + case SSA_PRIVACY_ADD: + { + if (wError) + { + NetLog_Server("Adding of privacy item to server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Adding of privacy item to server list failed.")); + } + break; + } + case SSA_PRIVACY_REMOVE: + { + if (wError) + { + NetLog_Server("Removing of privacy item from server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Removing of privacy item from server list failed.")); + } + FreeServerID(sc->wContactId, SSIT_ITEM); // release server id + break; + } + case SSA_CONTACT_ADD: + { + if (wError) + { + if (wError == 0xE) // server refused to add contact w/o auth, add with + { + DWORD dwCookie; + + NetLog_Server("Contact could not be added without authorization, add with await auth flag."); + + setSettingByte(sc->hContact, "Auth", 1); // we need auth + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, sc->hContact, sc); + icq_sendServerContact(sc->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, sc->wGroupId, sc->wContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 500, NULL); + + sc = NULL; // we do not want it to be freed now + break; + } + FreeServerID(sc->wContactId, SSIT_ITEM); + + NetLog_Server("Adding of contact to server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Adding of contact to server list failed.")); + + servlistPendingRemoveContact(sc->hContact, 0, sc->wGroupId, PENDING_RESULT_FAILED); + + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here + } + else + { + void* groupData; + int groupSize; + + setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, sc->wContactId); + setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, sc->wGroupId); + + servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, PENDING_RESULT_SUCCESS); + + if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) + { // the group is not empty, just update it + updateServerGroupData(sc->wGroupId, groupData, groupSize, SSOF_END_OPERATION); + SAFE_FREE((void**)&groupData); + } + else + { // this should never happen + NetLog_Server("Group update failed."); + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here + } + } + break; + } + case SSA_GROUP_ADD: + { + if (wError) + { + FreeServerID(sc->wGroupId, SSIT_GROUP); + NetLog_Server("Adding of group to server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Adding of group to server list failed.")); + + servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_FAILED); + } + else // group added, we need to update master group + { + void* groupData; + int groupSize; + cookie_servlist_action* ack; + DWORD dwCookie; + + setServListGroupName(sc->wGroupId, sc->szGroupName); // add group to namelist + { // add group to known + char *szCListGroup = getServListGroupCListPath(sc->wGroupId); + + // create link to the original CList group + setServListGroupLinkID(sc->szGroup, sc->wGroupId); + + servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_SUCCESS); + SAFE_FREE((void**)&szCListGroup); + } + + groupData = collectGroups(&groupSize); + groupData = SAFE_REALLOC(groupData, groupSize+2); + *(((WORD*)groupData)+(groupSize>>1)) = sc->wGroupId; // add this new group id + groupSize += 2; + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { + ack->dwAction = SSA_GROUP_UPDATE; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, SSOF_END_OPERATION); + } + else // end server modifications here + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); + + SAFE_FREE((void**)&groupData); + } + if (sc->szGroup != sc->szGroupName) + SAFE_FREE((void**)&sc->szGroup); + + SAFE_FREE((void**)&sc->szGroupName); + break; + } + case SSA_CONTACT_REMOVE: + { + if (!wError) + { + void* groupData; + int groupSize; + + setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, 0); // clear the values + setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, 0); + + FreeServerID(sc->wContactId, SSIT_ITEM); + + servlistPendingRemoveContact(sc->hContact, 0, sc->wGroupId, PENDING_RESULT_SUCCESS); + + if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) + { // the group is still not empty, just update it + updateServerGroupData(sc->wGroupId, groupData, groupSize, SSOF_END_OPERATION); + } + else // the group is empty, delete it + { + char *szGroup = getServListGroupCListPath(sc->wGroupId); + + servlistRemoveGroup(szGroup, sc->wGroupId); + SAFE_FREE((void**)&szGroup); + } + SAFE_FREE((void**)&groupData); // free the memory + } + else + { + NetLog_Server("Removing of contact from server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Removing of contact from server list failed.")); + + servlistPendingRemoveContact(sc->hContact, sc->wContactId, sc->wGroupId, PENDING_RESULT_FAILED); + + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here + } + break; + } + case SSA_GROUP_UPDATE: + { + if (wError) + { + NetLog_Server("Updating of group on server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Updating of group on server list failed.")); + } + SAFE_FREE((void**)&sc->szGroupName); + break; + } + case SSA_GROUP_REMOVE: + { + SAFE_FREE((void**)&sc->szGroupName); + if (wError) + { + NetLog_Server("Removing of group from server list failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Removing of group from server list failed.")); + + servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_FAILED); + + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here + SAFE_FREE((void**)&sc->szGroup); + } + else // group removed, we need to update master group + { + void* groupData; + int groupSize; + DWORD dwCookie; + + setServListGroupName(sc->wGroupId, NULL); // clear group from namelist + FreeServerID(sc->wGroupId, SSIT_GROUP); + removeGroupPathLinks(sc->wGroupId); + + servlistPendingRemoveGroup(sc->szGroup, 0, PENDING_RESULT_SUCCESS); + SAFE_FREE((void**)&sc->szGroup); + + groupData = collectGroups(&groupSize); + sc->wGroupId = 0; + sc->dwAction = SSA_GROUP_UPDATE; + sc->szGroupName = NULL; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, sc); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, sc->szGroupName, groupData, groupSize, SSOF_END_OPERATION); + // end server modifications here + + sc = NULL; // we do not want to be freed here + + SAFE_FREE((void**)&groupData); + } + break; + } + case SSA_CONTACT_SET_GROUP: + { // we moved contact to another group + if (sc->lParam == -1) + { // the first was an error + break; + } + if (wError) + { + if (wError == 0x0E && sc->lParam == 1) + { // second ack - adding failed with error 0x0E, try to add with AVAIT_AUTH flag + DWORD dwCookie; + + if (!getSettingByte(sc->hContact, "Auth", 0)) + { // we tried without AWAIT_AUTH, try again with it + NetLog_Server("Contact could not be added without authorization, add with await auth flag."); + + setSettingByte(sc->hContact, "Auth", 1); // we need auth + } + else + { // we tried with AWAIT_AUTH, try again without + NetLog_Server("Contact count not be added awaiting authorization, try authorized."); + + setSettingByte(sc->hContact, "Auth", 0); + } + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, sc->hContact, sc); + icq_sendServerContact(sc->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, sc->wNewGroupId, sc->wNewContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 400, NULL); + + sc->lParam = 2; // do not cycle + sc = NULL; // we do not want to be freed here + break; + } + FreeServerID(sc->wNewContactId, SSIT_ITEM); + NetLog_Server("Moving of user to another group on server list failed, error %d", wError); + icq_LogMessage(LOG_ERROR, LPGEN("Moving of user to another group on server list failed.")); + + servlistPendingRemoveContact(sc->hContact, 0, (WORD)(sc->lParam ? sc->wGroupId : sc->wNewGroupId), PENDING_RESULT_FAILED); + + servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); // end server modifications here + + if (!sc->lParam) // is this first ack ? + { + sc->lParam = -1; + sc = NULL; // this can't be freed here + } + break; + } + if (sc->lParam) // is this the second ack ? + { + void* groupData; + int groupSize; + int bEnd = 1; // shall we end the sever modifications + + setSettingWord(sc->hContact, DBSETTING_SERVLIST_ID, sc->wNewContactId); + setSettingWord(sc->hContact, DBSETTING_SERVLIST_GROUP, sc->wNewGroupId); + + servlistPendingRemoveContact(sc->hContact, sc->wNewContactId, sc->wNewGroupId, PENDING_RESULT_SUCCESS); + + if (groupData = collectBuddyGroup(sc->wGroupId, &groupSize)) // update the group we moved from + { // the group is still not empty, just update it + updateServerGroupData(sc->wGroupId, groupData, groupSize, 0); + SAFE_FREE((void**)&groupData); // free the memory + } + else + { // the group is empty, delete it + char* szGroup = getServListGroupCListPath(sc->wGroupId); + + servlistRemoveGroup(szGroup, sc->wGroupId); + SAFE_FREE((void**)&szGroup); + bEnd = 0; // here the modifications go on + } + + groupData = collectBuddyGroup(sc->wNewGroupId, &groupSize); // update the group we moved to + updateServerGroupData(sc->wNewGroupId, groupData, groupSize, bEnd ? SSOF_END_OPERATION : 0); + // end server modifications here + SAFE_FREE((void**)&groupData); + + } + else // contact was deleted from server-list + { + deleteSetting(sc->hContact, DBSETTING_SERVLIST_ID); + deleteSetting(sc->hContact, DBSETTING_SERVLIST_GROUP); + FreeServerID(sc->wContactId, SSIT_ITEM); // release old contact id + sc->lParam = 1; + sc = NULL; // wait for second ack + } + break; + } + case SSA_CONTACT_FIX_AUTH: + { + if (wError) + { // FIXME: something failed, we should handle it properly + } + break; + } + case SSA_GROUP_RENAME: + { + if (wError) + { + NetLog_Server("Renaming of server group failed, error %d", wError); + icq_LogMessage(LOG_WARNING, LPGEN("Renaming of server group failed.")); + + servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_FAILED); + } + else + { + setServListGroupName(sc->wGroupId, sc->szGroupName); + removeGroupPathLinks(sc->wGroupId); + { // add group to known + char *szCListGroup = getServListGroupCListPath(sc->wGroupId); + + /// FIXME: need to create link to the new group name before unique item name correction as well + setServListGroupLinkID(szCListGroup, sc->wGroupId); + SAFE_FREE((void**)&szCListGroup); + } + servlistPendingRemoveGroup(sc->szGroup, sc->wGroupId, PENDING_RESULT_SUCCESS); + } + SAFE_FREE((void**)&sc->szGroupName); + SAFE_FREE((void**)&sc->szGroup); + break; + } + case SSA_SETAVATAR: + { + if (wError) + { + NetLog_Server("Uploading of avatar hash failed."); + if (sc->wGroupId) // is avatar added or updated? + { + FreeServerID(sc->wContactId, SSIT_ITEM); + deleteSetting(NULL, DBSETTING_SERVLIST_AVATAR); // to fix old versions + } + } + else + { + setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, sc->wContactId); + } + break; + } + case SSA_REMOVEAVATAR: + { + if (wError) + NetLog_Server("Removing of avatar hash failed."); + else + { + FreeServerID(sc->wContactId, SSIT_ITEM); + deleteSetting(NULL, DBSETTING_SERVLIST_AVATAR); + } + break; + } + case SSA_SERVLIST_ACK: + { + BroadcastAck(sc->hContact, ICQACKTYPE_SERVERCLIST, wError?ACKRESULT_FAILED:ACKRESULT_SUCCESS, (HANDLE)sc->lParam, wError); + break; + } + case SSA_IMPORT: + { + if (wError) + NetLog_Server("Re-starting import sequence failed, error %d", wError); + else + { + setSettingWord(NULL, "SrvImportID", 0); + deleteSetting(NULL, "ImportTS"); + } + break; + } + default: + NetLog_Server("Server ack cookie type (%d) not recognized.", sc->dwAction); + } + SAFE_FREE((void**)&sc); // free the memory + + return; +} + + +HANDLE CIcqProto::HContactFromRecordName(const char* szRecordName, int *bAdded) +{ + HANDLE hContact = INVALID_HANDLE_VALUE; + + if (!IsStringUIN(szRecordName)) + { // probably AIM contact + hContact = HContactFromUID(0, szRecordName, bAdded); + } + else + { // this should be ICQ number + DWORD dwUin = atoi(szRecordName); + + hContact = HContactFromUIN(dwUin, bAdded); + } + return hContact; +} + + +int CIcqProto::getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf) /// FIXME: need to keep original order +{ // get server-list item's TLV data + oscar_tlv_chain* list = pChain; + int datalen = 0; + icq_packet pBuf; + + // Initialize our handy data buffer + pBuf.wPlace = 0; + pBuf.pData = buf; + + while (list) + { // collect non-standard TLVs and save them to DB + if (list->tlv.wType != SSI_TLV_AWAITING_AUTH && + list->tlv.wType != SSI_TLV_NAME && + list->tlv.wType != SSI_TLV_COMMENT && + list->tlv.wType != SSI_TLV_METAINFO_TOKEN && + list->tlv.wType != SSI_TLV_METAINFO_TIME) + { // only TLVs which we do not handle on our own + packTLV(&pBuf, list->tlv.wType, list->tlv.wLen, list->tlv.pData); + + datalen += list->tlv.wLen + 4; + } + list = list->next; + } + return datalen; +} + + +void CIcqProto::handleServerCListReply(BYTE *buf, WORD wLen, WORD wFlags, serverthread_info *info) +{ + BYTE bySSIVersion; + WORD wRecordCount; + WORD wRecord; + WORD wGroupId; + WORD wItemId; + WORD wTlvType; + WORD wTlvLength; + BOOL bIsLastPacket; + uid_str szRecordName; + oscar_tlv_chain* pChain = NULL; + oscar_tlv* pTLV = NULL; + char *szActiveSrvGroup = NULL; + WORD wActiveSrvGroupId = -1; + + + // If flag bit 1 is set, this is not the last + // packet. If it is 0, this is the last packet + // and there will be a timestamp at the end. + if (wFlags & 0x0001) + bIsLastPacket = FALSE; + else + bIsLastPacket = TRUE; + + if (wLen < 3) + return; + + // Version number of SSI protocol? + unpackByte(&buf, &bySSIVersion); + wLen -= 1; + + // Total count of following entries. This is the size of the server + // side contact list and should be saved and sent with CLI_CHECKROSTER. + // NOTE: When the entries are split up in several packets, each packet + // has it's own count and they must be added to get the total size of + // server list. + unpackWord(&buf, &wRecordCount); + wLen -= 2; + NetLog_Server("SSI: number of entries is %u, version is %u", wRecordCount, bySSIVersion); + + + // Loop over all items in the packet + for (wRecord = 0; wRecord < wRecordCount; wRecord++) + { + NetLog_Server("SSI: parsing record %u", wRecord + 1); + + if (wLen < 10) + { // minimum: name length (zero), group ID, item ID, empty TLV + NetLog_Server("Warning: SSI parsing error (%d)", 0); + break; + } + + if (!unpackServerListItem(&buf, &wLen, szRecordName, &wGroupId, &wItemId, &wTlvType, &wTlvLength)) + { // unpack basic structure + NetLog_Server("Warning: SSI parsing error (%d)", 1); + break; + } + + NetLog_Server("Name: '%s', GroupID: %u, EntryID: %u, EntryType: %u, TLVlength: %u", + szRecordName, wGroupId, wItemId, wTlvType, wTlvLength); + + if (wLen < wTlvLength) + { + NetLog_Server("Warning: SSI parsing error (%d)", 2); + break; + } + + // Initialize the tlv chain + if (wTlvLength > 0) + { + pChain = readIntoTLVChain(&buf, wTlvLength, 0); + wLen -= wTlvLength; + } + else + { + pChain = NULL; + } + + + switch (wTlvType) + { + + case SSI_ITEM_BUDDY: + { + /* this is a contact */ + HANDLE hContact; + int bAdded; + + hContact = HContactFromRecordName(szRecordName, &bAdded); + + if (hContact != INVALID_HANDLE_VALUE) + { + int bRegroup = 0; + int bNicked = 0; + + if (bAdded) + { // Not already on list: added + NetLog_Server("SSI added new %s contact '%s'", "ICQ", szRecordName); + + AddJustAddedContact(hContact); + } + else + { // we should add new contacts and this contact was just added, show it + if (IsContactJustAdded(hContact)) + { + setContactHidden(hContact, 0); + bAdded = 1; // we want details for new contacts + } + else + NetLog_Server("SSI ignoring existing contact '%s'", szRecordName); + // Contact on server is always on list + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 0); + } + + // Save group and item ID + setSettingWord(hContact, DBSETTING_SERVLIST_ID, wItemId); + setSettingWord(hContact, DBSETTING_SERVLIST_GROUP, wGroupId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + if (!bAdded && getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD)) + { // check if the contact has been moved on the server + if (wActiveSrvGroupId != wGroupId || !szActiveSrvGroup) + { + SAFE_FREE(&szActiveSrvGroup); + szActiveSrvGroup = getServListGroupCListPath(wGroupId); + wActiveSrvGroupId = wGroupId; + } + char *szLocalGroup = getContactCListGroup(hContact); + + if (!strlennull(szLocalGroup)) + { // no CListGroup + SAFE_FREE(&szLocalGroup); + + szLocalGroup = null_strdup(DEFAULT_SS_GROUP); + } + + if (strcmpnull(szActiveSrvGroup, szLocalGroup) && + (strlennull(szActiveSrvGroup) >= strlennull(szLocalGroup) || _strnicmp(szActiveSrvGroup, szLocalGroup, strlennull(szLocalGroup)))) + { // contact moved to new group or sub-group or not to master group + bRegroup = 1; + } + if (bRegroup && !stricmpnull(DEFAULT_SS_GROUP, szActiveSrvGroup)) /// TODO: invent something more clever for "root" group + { // is it the default "General" group ? + bRegroup = 0; // if yes, do not move to it - cause it would hide the contact + } + SAFE_FREE(&szLocalGroup); + } + + if (bRegroup || bAdded) + { // if we should load server details or contact was just added, update its group + if (wActiveSrvGroupId != wGroupId || !szActiveSrvGroup) + { + SAFE_FREE(&szActiveSrvGroup); + szActiveSrvGroup = getServListGroupCListPath(wGroupId); + wActiveSrvGroupId = wGroupId; + } + + if (szActiveSrvGroup) + { // try to get Miranda Group path from groupid, if succeeded save to db + moveContactToCListGroup(hContact, szActiveSrvGroup); + } + } + + if (pChain) + { // Look for nickname TLV and copy it to the db if necessary + if (pTLV = pChain->getTLV(SSI_TLV_NAME, 1)) + { + if (pTLV->pData && (pTLV->wLen > 0)) + { + char *pszNick; + WORD wNickLength; + + wNickLength = pTLV->wLen; + + pszNick = (char*)SAFE_MALLOC(wNickLength + 1); + // Copy buffer to utf-8 buffer + memcpy(pszNick, pTLV->pData, wNickLength); + pszNick[wNickLength] = 0; // Terminate string + + NetLog_Server("Nickname is '%s'", pszNick); + + bNicked = 1; + + // Write nickname to database + if (getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded) + { // if just added contact, save details always - does no harm + char *szOldNick; + + if (szOldNick = getSettingStringUtf(hContact, "CList", "MyHandle", NULL)) + { + if ((strcmpnull(szOldNick, pszNick)) && (strlennull(pszNick) > 0)) + { // check if the truncated nick changed, i.e. do not overwrite locally stored longer nick + if (strlennull(szOldNick) <= strlennull(pszNick) || strncmp(szOldNick, pszNick, null_strcut(szOldNick, MAX_SSI_TLV_NAME_SIZE))) + { + // Yes, we really do need to delete it first. Otherwise the CLUI nick + // cache isn't updated (I'll look into it) + DBDeleteContactSetting(hContact,"CList","MyHandle"); + setSettingStringUtf(hContact, "CList", "MyHandle", pszNick); + } + } + SAFE_FREE(&szOldNick); + } + else if (strlennull(pszNick) > 0) + { + DBDeleteContactSetting(hContact,"CList","MyHandle"); + setSettingStringUtf(hContact, "CList", "MyHandle", pszNick); + } + } + SAFE_FREE(&pszNick); + } + else + { + NetLog_Server("Invalid nickname"); + } + } + if (bAdded && !bNicked) + icq_QueueUser(hContact); // queue user without nick for fast auto info update + + // Look for comment TLV and copy it to the db if necessary + if (pTLV = pChain->getTLV(SSI_TLV_COMMENT, 1)) + { + if (pTLV->pData && (pTLV->wLen > 0)) + { + char *pszComment; + WORD wCommentLength; + + + wCommentLength = pTLV->wLen; + + pszComment = (char*)SAFE_MALLOC(wCommentLength + 1); + // Copy buffer to utf-8 buffer + memcpy(pszComment, pTLV->pData, wCommentLength); + pszComment[wCommentLength] = 0; // Terminate string + + NetLog_Server("Comment is '%s'", pszComment); + + // Write comment to database + if (getSettingByte(NULL, "LoadServerDetails", DEFAULT_SS_LOAD) || bAdded) + { // if just added contact, save details always - does no harm + char *szOldComment; + + if (szOldComment = getSettingStringUtf(hContact, "UserInfo", "MyNotes", NULL)) + { + if ((strcmpnull(szOldComment, pszComment)) && (strlennull(pszComment) > 0)) + { // check if the truncated comment changed, i.e. do not overwrite locally stored longer comment + if (strlennull(szOldComment) <= strlennull(pszComment) || strncmp((char*)szOldComment, (char*)pszComment, null_strcut(szOldComment, MAX_SSI_TLV_COMMENT_SIZE))) + { + setSettingStringUtf(hContact, "UserInfo", "MyNotes", pszComment); + } + } + SAFE_FREE((void**)&szOldComment); + } + else if (strlennull(pszComment) > 0) + { + setSettingStringUtf(hContact, "UserInfo", "MyNotes", pszComment); + } + } + SAFE_FREE((void**)&pszComment); + } + else + { + NetLog_Server("Invalid comment"); + } + } + + // Look for need-authorization TLV + if (pChain->getTLV(SSI_TLV_AWAITING_AUTH, 1)) + { + setSettingByte(hContact, "Auth", 1); + NetLog_Server("SSI contact need authorization"); + } + else + { + setSettingByte(hContact, "Auth", 0); + } + + if (pTLV = pChain->getTLV(SSI_TLV_METAINFO_TOKEN, 1)) + { + setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pTLV->pData, pTLV->wLen); + if (pChain->getTLV(SSI_TLV_METAINFO_TIME, 1)) + setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pChain->getDouble(SSI_TLV_METAINFO_TIME, 1)); + NetLog_Server("SSI contact has meta info token"); + } + else + { + deleteSetting(hContact, DBSETTING_METAINFO_TOKEN); + deleteSetting(hContact, DBSETTING_METAINFO_TIME); + } + + { // store server-list item's TLV data + BYTE* data = (BYTE*)SAFE_MALLOC(wTlvLength); + int datalen = getServerDataFromItemTLV(pChain, data); + + if (datalen > 0) + setSettingBlob(hContact, DBSETTING_SERVLIST_DATA, data, datalen); + else + deleteSetting(hContact, DBSETTING_SERVLIST_DATA); + + SAFE_FREE((void**)&data); + } + } + } + else + { // failed to add or other error + NetLog_Server("SSI failed to handle %s Item '%s'", "Buddy", szRecordName); + } + } + break; + + case SSI_ITEM_GROUP: + if ((wGroupId == 0) && (wItemId == 0)) + { + /* list of groups. wTlvType=1, data is TLV(C8) containing list of WORDs which */ + /* is the group ids + /* we don't need to use this. Our processing is on-the-fly */ + /* this record is always sent first in the first packet only, */ + } + else if (wGroupId != 0) + { + /* wGroupId != 0: a group record */ + if (wItemId == 0) + { /* no item ID: this is a group */ + /* pszRecordName is the name of the group */ + ReserveServerID(wGroupId, SSIT_GROUP, 0); + + setServListGroupName(wGroupId, szRecordName); + + NetLog_Server("Group %s added to known groups.", szRecordName); + + /* demangle full grouppath, set it to known */ + SAFE_FREE(&szActiveSrvGroup); + szActiveSrvGroup = getServListGroupCListPath(wGroupId); + wActiveSrvGroupId = wGroupId; + + /* TLV contains a TLV(C8) with a list of WORDs of contained contact IDs */ + /* our processing is good enough that we don't need this duplication */ + } + else + { + NetLog_Server("Unhandled type 0x01, wItemID != 0"); + } + } + else + { + NetLog_Server("Unhandled type 0x01"); + } + break; + + case SSI_ITEM_PERMIT: + { + /* item on visible list */ + /* wItemId not related to contact ID */ + /* pszRecordName is the UIN */ + HANDLE hContact; + int bAdded; + + hContact = HContactFromRecordName(szRecordName, &bAdded); + + if (hContact != INVALID_HANDLE_VALUE) + { + if (bAdded) + { + NetLog_Server("SSI added new %s contact '%s'", "Permit", szRecordName); + // It wasn't previously in the list, we hide it so it only appears in the visible list + setContactHidden(hContact, 1); + // Add it to the list, so it can be added properly if proper contact + AddJustAddedContact(hContact); + } + else + NetLog_Server("SSI %s contact already exists '%s'", "Permit", szRecordName); + + // Save permit ID + setSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + // Set apparent mode + setSettingWord(hContact, "ApparentMode", ID_STATUS_ONLINE); + NetLog_Server("Visible-contact (%s)", szRecordName); + } + else + { // failed to add or other error + NetLog_Server("SSI failed to handle %s Item '%s'", "Permit", szRecordName); + + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + } + } + break; + + case SSI_ITEM_DENY: + { + /* Item on invisible list */ + /* wItemId not related to contact ID */ + /* pszRecordName is the UIN */ + HANDLE hContact; + int bAdded; + + hContact = HContactFromRecordName(szRecordName, &bAdded); + + if (hContact != INVALID_HANDLE_VALUE) + { + if (bAdded) + { + /* not already on list: added */ + NetLog_Server("SSI added new %s contact '%s'", "Deny", szRecordName); + // It wasn't previously in the list, we hide it so it only appears in the visible list + setContactHidden(hContact, 1); + // Add it to the list, so it can be added properly if proper contact + AddJustAddedContact(hContact); + } + else + NetLog_Server("SSI %s contact already exists '%s'", "Deny", szRecordName); + + // Save Deny ID + setSettingWord(hContact, DBSETTING_SERVLIST_DENY, wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + // Set apparent mode + setSettingWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); + NetLog_Server("Invisible-contact (%s)", szRecordName); + } + else + { // failed to add or other error + NetLog_Server("SSI failed to handle %s Item '%s'", "Deny", szRecordName); + + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + } + } + break; + + case SSI_ITEM_VISIBILITY: /* My visibility settings */ + { + BYTE bVisibility; + + // Look for visibility TLV + if (bVisibility = pChain->getByte(SSI_TLV_VISIBILITY, 1)) + { // found it, store the id, we do not need current visibility - we do not rely on it + setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + NetLog_Server("Visibility is %u", bVisibility); + } + else + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + } + break; + + case SSI_ITEM_IGNORE: + { + /* item on ignore list */ + /* wItemId not related to contact ID */ + /* pszRecordName is the UIN */ + HANDLE hContact; + int bAdded; + + hContact = HContactFromRecordName(szRecordName, &bAdded); + + if (hContact != INVALID_HANDLE_VALUE) + { + if (bAdded) + { + /* not already on list: add */ + NetLog_Server("SSI added new %s contact '%s'", "Ignore", szRecordName); + // It wasn't previously in the list, we hide it + setContactHidden(hContact, 1); + // Add it to the list, so it can be added properly if proper contact + AddJustAddedContact(hContact); + } + else + NetLog_Server("SSI %s contact already exists '%s'", "Ignore", szRecordName); + + // Save Ignore ID + setSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + // Set apparent mode & ignore + setSettingWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); + // set ignore all events + CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, IGNOREEVENT_ALL); + NetLog_Server("Ignore-contact (%s)", szRecordName); + } + else + { // failed to add or other error + NetLog_Server("SSI failed to handle %s Item '%s'", "Ignore", szRecordName); + + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + } + } + break; + + case SSI_ITEM_UNKNOWN2: + NetLog_Server("SSI unknown type 0x11"); + + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + break; + + case SSI_ITEM_IMPORTTIME: + if (wGroupId == 0) + { + /* time our list was first imported */ + /* pszRecordName is "Import Time" */ + /* data is TLV(13) {TLV(D4) {time_t importTime}} */ + setSettingDword(NULL, "ImportTS", pChain->getDWord(SSI_TLV_TIMESTAMP, 1)); + setSettingWord(NULL, "SrvImportID", wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + NetLog_Server("SSI %s item recognized", "first import"); + } + break; + + case SSI_ITEM_BUDDYICON: + if (wGroupId == 0) + { + /* our avatar MD5-hash */ + /* pszRecordName is "1" */ + /* data is TLV(D5) hash */ + /* we ignore this, just save the id */ + /* cause we get the hash again after login */ + if (!strcmpnull(szRecordName, "12")) + { // need to handle Photo Item separately + setSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, wItemId); + NetLog_Server("SSI %s item recognized", "Photo"); + } + else + { + setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, wItemId); + NetLog_Server("SSI %s item recognized", "Avatar"); + } + ReserveServerID(wItemId, SSIT_ITEM, 0); + } + break; + + case SSI_ITEM_METAINFO: + if (wGroupId == 0) + { + /* our meta info token & last update time */ + /* pszRecordName is "ICQ-MDIR" */ + /* data is TLV(15C) and TLV(15D) */ + oscar_tlv* pToken = pChain->getTLV(SSI_TLV_METAINFO_TOKEN, 1); + oscar_tlv* pTime = pChain->getTLV(SSI_TLV_METAINFO_TIME, 1); + if (pToken) + setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); + if (pTime) + setSettingDouble(NULL, DBSETTING_METAINFO_TIME, pChain->getDouble(SSI_TLV_METAINFO_TIME, 1)); + + setSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + NetLog_Server("SSI %s item recognized", "Meta info"); + } + break; + + case SSI_ITEM_CLIENTDATA: + if (wGroupId == 0) + { + /* ICQ2k ShortcutBar Items */ + /* data is TLV(CD) text */ + if (wItemId) + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + } + + case SSI_ITEM_SAVED: + case SSI_ITEM_PREAUTH: + break; + + default: + NetLog_Server("SSI unhandled item %2x", wTlvType); + + if (wItemId) + ReserveServerID(wItemId, SSIT_ITEM, SSIF_UNHANDLED); + break; + } + + disposeChain(&pChain); + } // end for + + // Release Memory + SAFE_FREE(&szActiveSrvGroup); + + NetLog_Server("Bytes left: %u", wLen); + + setSettingWord(NULL, "SrvRecordCount", (WORD)(wRecord + getSettingWord(NULL, "SrvRecordCount", 0))); + + if (bIsLastPacket) + { + // No contacts left to sync + bIsSyncingCL = FALSE; + + StoreServerIDs(); + + icq_RescanInfoUpdate(); + + if (wLen >= 4) + { + DWORD dwLastUpdateTime; + + /* finally we get a time_t of the last update time */ + unpackDWord(&buf, &dwLastUpdateTime); + setSettingDword(NULL, "SrvLastUpdate", dwLastUpdateTime); + NetLog_Server("Last update of server list was (%u) %s", dwLastUpdateTime, time2text(dwLastUpdateTime)); + + sendRosterAck(); + handleServUINSettings(wListenPort, info); + + servlistProcessLogin(); + } + else + { + NetLog_Server("Last packet missed update time..."); + } + if (getSettingWord(NULL, "SrvRecordCount", 0) == 0) + { // we got empty serv-list, create master group + cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { + DWORD dwCookie; + + ack->dwAction = SSA_GROUP_UPDATE; + ack->szGroupName = null_strdup(""); + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); + icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, 0, ack->szGroupName, NULL, 0, 0); + } + } + // serv-list sync finished, clear just added contacts + FlushJustAddedContacts(); + } + else + { + NetLog_Server("Waiting for more packets"); + } +} + + +void CIcqProto::handleServerCListItemAdd(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) +{ + if (wItemType == SSI_ITEM_IMPORTTIME) + { + if (pItemData) + { + setSettingDword(NULL, "ImportTS", pItemData->getDWord(SSI_TLV_TIMESTAMP, 1)); + setSettingWord(NULL, "SrvImportID", wItemId); + ReserveServerID(wItemId, SSIT_ITEM, 0); + + NetLog_Server("Server added Import timestamp to list"); + + return; + } + } + // Reserve server-list ID + ReserveServerID(wItemId, wItemType == SSI_ITEM_GROUP ? SSIT_GROUP : SSIT_ITEM, SSIF_UNHANDLED); +} + + +void CIcqProto::handleServerCListItemUpdate(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) +{ + HANDLE hContact = (wItemType == SSI_ITEM_BUDDY || wItemType == SSI_ITEM_DENY || wItemType == SSI_ITEM_PERMIT || wItemType == SSI_ITEM_IGNORE) ? HContactFromRecordName(szRecordName, NULL) : NULL; + + if (hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY) + { // a contact was updated on server + if (pItemData) + { + oscar_tlv* pAuth = pItemData->getTLV(SSI_TLV_AWAITING_AUTH, 1); + BYTE bAuth = getSettingByte(hContact, "Auth", 0); + + if (bAuth && !pAuth) + { // server authorized our contact + char str[MAX_PATH]; + char msg[MAX_PATH]; + char *nick = NickFromHandleUtf(hContact); + + setSettingByte(hContact, "Auth", 0); + null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" was authorized in the server list."), msg, MAX_PATH), nick); + icq_LogMessage(LOG_WARNING, str); + SAFE_FREE(&nick); + } + else if (!bAuth && pAuth) + { // server took away authorization of our contact + char str[MAX_PATH]; + char msg[MAX_PATH]; + char *nick = NickFromHandleUtf(hContact); + + setSettingByte(hContact, "Auth", 1); + null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" lost its authorization in the server list."), msg, MAX_PATH), nick); + icq_LogMessage(LOG_WARNING, str); + SAFE_FREE(&nick); + } + + { // update metainfo data + DBVARIANT dbv = {0}; + oscar_tlv *pToken = pItemData->getTLV(SSI_TLV_METAINFO_TOKEN, 1); + oscar_tlv *pTime = pItemData->getTLV(SSI_TLV_METAINFO_TIME, 1); + + if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) + { + if (!pToken || dbv.cpbVal != pToken->wLen || memcmp(dbv.pbVal, pToken->pData, dbv.cpbVal)) + { + if (!pToken) + NetLog_Server("Contact %s, meta info token removed", szRecordName); + else + NetLog_Server("Contact %s, meta info token changed", szRecordName); + + // user info was changed, refresh + if (IsMetaInfoChanged(hContact)) + icq_QueueUser(hContact); + } + + ICQFreeVariant(&dbv); + } + else if (pToken) + { + NetLog_Server("Contact %s, meta info token added", szRecordName); + + // user info was changed, refresh + if (IsMetaInfoChanged(hContact)) + icq_QueueUser(hContact); + } + + if (pToken) + setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); + if (pTime) + setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pItemData->getDouble(SSI_TLV_METAINFO_TIME, 1)); + } + + { // update server's data - otherwise consequent operations can fail with 0x0E + BYTE *data = (BYTE*)_alloca(pItemData->getChainLength()); + int datalen = getServerDataFromItemTLV(pItemData, data); + + if (datalen > 0) + setSettingBlob(hContact, DBSETTING_SERVLIST_DATA, data, datalen); + else + deleteSetting(hContact, DBSETTING_SERVLIST_DATA); + } + } + } + else if (wItemType == SSI_ITEM_METAINFO) + { // owner MetaInfo data updated + if (pItemData) + { + DBVARIANT dbv = {0}; + oscar_tlv *pToken = pItemData->getTLV(SSI_TLV_METAINFO_TOKEN, 1); + oscar_tlv *pTime = pItemData->getTLV(SSI_TLV_METAINFO_TIME, 1); + + if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) + { + if (!pToken || dbv.cpbVal != pToken->wLen || memcmp(dbv.pbVal, pToken->pData, dbv.cpbVal)) + { + if (!pToken) + NetLog_Server("Owner meta info token removed"); + else + NetLog_Server("Owner meta info token changed"); + } + + ICQFreeVariant(&dbv); + } + + if (pToken) + setSettingBlob(hContact, DBSETTING_METAINFO_TOKEN, pToken->pData, pToken->wLen); + if (pTime) + setSettingDouble(hContact, DBSETTING_METAINFO_TIME, pItemData->getDouble(SSI_TLV_METAINFO_TIME, 1)); + } + } + else if (wItemType == SSI_ITEM_GROUP) + { // group updated + NetLog_Server("Server updated our group \"%s\" on list", szRecordName); + } +} + + +void CIcqProto::handleServerCListItemDelete(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData) +{ + HANDLE hContact = (wItemType == SSI_ITEM_BUDDY || wItemType == SSI_ITEM_DENY || wItemType == SSI_ITEM_PERMIT || wItemType == SSI_ITEM_IGNORE) ? HContactFromRecordName(szRecordName, NULL) : NULL; + + if (hContact != INVALID_HANDLE_VALUE && wItemType == SSI_ITEM_BUDDY) + { // a contact was removed from our list + if (getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) == wItemId) + { + deleteSetting(hContact, DBSETTING_SERVLIST_ID); + deleteSetting(hContact, DBSETTING_SERVLIST_GROUP); + deleteSetting(hContact, "Auth"); + + { + char str[MAX_PATH]; + char msg[MAX_PATH]; + char *nick = NickFromHandleUtf(hContact); + + null_snprintf(str, MAX_PATH, ICQTranslateUtfStatic(LPGEN("User \"%s\" was removed from server list."), msg, MAX_PATH), nick); + icq_LogMessage(LOG_WARNING, str); + SAFE_FREE(&nick); + } + } + } + // Release server-list ID + FreeServerID(wItemId, wItemType == SSI_ITEM_GROUP ? SSIT_GROUP : SSIT_ITEM); +} + + +void CIcqProto::handleRecvAuthRequest(unsigned char *buf, WORD wLen) +{ + DWORD dwUin; + uid_str szUid; + int bAdded; + + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + if (dwUin && IsOnSpammerList(dwUin)) + { + NetLog_Server("Ignored Message from known Spammer"); + return; + } + + WORD wReasonLen; + unpackWord(&buf, &wReasonLen); + wLen -= 2; + if (wReasonLen > wLen) + return; + + HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); + CCSDATA ccs; + PROTORECVEVENT pre; + + ccs.szProtoService = PSR_AUTH; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.timestamp = time(NULL); + pre.lParam = sizeof(DWORD) + sizeof(HANDLE) + 5; + // Prepare reason + char *szReason = (char*)SAFE_MALLOC(wReasonLen + 1); + int nReasonLen = 0; + if (szReason) + { + memcpy(szReason, buf, wReasonLen); + szReason[wReasonLen] = '\0'; + nReasonLen = strlennull(szReason); + + char *temp = (char*)_alloca(nReasonLen + 2); + if (!IsUSASCII(szReason, nReasonLen) && UTF8_IsValid(szReason) && utf8_decode_static(szReason, temp, nReasonLen + 1)) + pre.flags |= PREF_UTF; + } + // Read nick name from DB + char *szNick = NULL; + if (dwUin) + { + DBVARIANT dbv = { 0 }; + if (pre.flags & PREF_UTF) + szNick = getSettingStringUtf(hContact, "Nick", NULL); + else if (!getSettingString(hContact, "Nick", &dbv)) + { + szNick = null_strdup(dbv.pszVal); + ICQFreeVariant(&dbv); + } + } + else + szNick = null_strdup(szUid); + int nNickLen = strlennull(szNick); + + pre.lParam += nNickLen + nReasonLen; + + setSettingByte(ccs.hContact, "Grant", 1); + + /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/ + char *szBlob = (char *)_alloca(pre.lParam); + char *pCurBlob = szBlob; + memcpy(pCurBlob, &dwUin, sizeof(DWORD)); pCurBlob += sizeof(DWORD); + memcpy(pCurBlob, &hContact, sizeof(HANDLE)); pCurBlob += sizeof(HANDLE); + if (nNickLen) + { // if we have nick we add it, otherwise keep trailing zero + memcpy(pCurBlob, szNick, nNickLen); + pCurBlob += nNickLen; + } + *pCurBlob = 0; pCurBlob++; // Nick + *pCurBlob = 0; pCurBlob++; // FirstName + *pCurBlob = 0; pCurBlob++; // LastName + *pCurBlob = 0; pCurBlob++; // email + if (nReasonLen) + { + memcpy(pCurBlob, szReason, nReasonLen); + pCurBlob += nReasonLen; + } + *pCurBlob = 0; // Reason + pre.szMessage = szBlob; + + // TODO: Change for new auth system, include all known informations + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + + SAFE_FREE(&szNick); + SAFE_FREE(&szReason); + return; +} + + +void CIcqProto::handleRecvAdded(unsigned char *buf, WORD wLen) +{ + DWORD dwUin; + uid_str szUid; + DWORD cbBlob; + PBYTE pBlob,pCurBlob; + int bAdded; + char* szNick; + int nNickLen; + DBVARIANT dbv = {0}; + + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + if (dwUin && IsOnSpammerList(dwUin)) + { + NetLog_Server("Ignored Message from known Spammer"); + return; + } + + HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); + + cbBlob=sizeof(DWORD)*2+4; + + if (dwUin) + { + if (getSettingString(hContact, "Nick", &dbv)) + nNickLen = 0; + else + { + szNick = dbv.pszVal; + nNickLen = strlennull(szNick); + } + } + else + nNickLen = strlennull(szUid); + + cbBlob += nNickLen; + + pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); + /*blob is: uin(DWORD), hContact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) */ + *(DWORD*)pCurBlob = dwUin; pCurBlob += sizeof(DWORD); + *(DWORD*)pCurBlob = DWORD(hContact); pCurBlob += sizeof(DWORD); + if (nNickLen && dwUin) + { // if we have nick we add it, otherwise keep trailing zero + memcpy(pCurBlob, szNick, nNickLen); + pCurBlob+=nNickLen; + } + else + { + memcpy(pCurBlob, szUid, nNickLen); + pCurBlob+=nNickLen; + } + *(char *)pCurBlob = 0; pCurBlob++; + *(char *)pCurBlob = 0; pCurBlob++; + *(char *)pCurBlob = 0; pCurBlob++; + *(char *)pCurBlob = 0; + // TODO: Change for new auth system + + AddEvent(NULL, EVENTTYPE_ADDED, time(NULL), 0, cbBlob, pBlob); +} + + +void CIcqProto::handleRecvAuthResponse(unsigned char *buf, WORD wLen) +{ + DWORD dwUin; + uid_str szUid; + char* szNick = NULL; + WORD nReasonLen; + char* szReason; + int bAdded; + + BYTE bResponse = 0xFF; + + if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; + + if (dwUin && IsOnSpammerList(dwUin)) + { + NetLog_Server("Ignored Message from known Spammer"); + return; + } + + HANDLE hContact = HContactFromUID(dwUin, szUid, &bAdded); + + if (hContact != INVALID_HANDLE_VALUE) szNick = NickFromHandle(hContact); + + if (wLen > 0) + { + unpackByte(&buf, &bResponse); + wLen -= 1; + } + if (wLen >= 2) + { + unpackWord(&buf, &nReasonLen); + wLen -= 2; + if (wLen >= nReasonLen) + { + szReason = (char*)_alloca(nReasonLen+1); + unpackString(&buf, szReason, nReasonLen); + szReason[nReasonLen] = '\0'; + } + } + + switch (bResponse) + { + + case 0: + NetLog_Server("Authorization request %s by %s", "denied", strUID(dwUin, szUid)); + // TODO: Add to system history as soon as new auth system is ready + break; + + case 1: + setSettingByte(hContact, "Auth", 0); + NetLog_Server("Authorization request %s by %s", "granted", strUID(dwUin, szUid)); + // TODO: Add to system history as soon as new auth system is ready + break; + + default: + NetLog_Server("Unknown Authorization request response (%u) from %s", bResponse, strUID(dwUin, szUid)); + break; + + } + SAFE_FREE(&szNick); +} + + +// Updates the visibility code used while in SSI mode. If a server ID is +// not stored in the local DB, a new ID will be added to the server list. +// +// Possible values are: +// 01 - Allow all users to see you +// 02 - Block all users from seeing you +// 03 - Allow only users in the permit list to see you +// 04 - Block only users in the invisible list from seeing you +// 05 - Allow only users in the buddy list to see you +// +void CIcqProto::updateServVisibilityCode(BYTE bCode) +{ + icq_packet packet; + WORD wVisibilityID; + WORD wCommand; + + if ((bCode > 0) && (bCode < 6)) + { + cookie_servlist_action* ack; + DWORD dwCookie; + BYTE bVisibility = getSettingByte(NULL, "SrvVisibility", 0); + + if (bVisibility == bCode) // if no change was made, not necescary to update that + return; + setSettingByte(NULL, "SrvVisibility", bCode); + + // Do we have a known server visibility ID? We should, unless we just subscribed to the serv-list for the first time + if ((wVisibilityID = getSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0)) == 0) + { + // No, create a new random ID + wVisibilityID = GenerateServerID(SSIT_ITEM, 0); + setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, wVisibilityID); + wCommand = ICQ_LISTS_ADDTOLIST; +#ifdef _DEBUG + NetLog_Server("Made new srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode); +#endif + } + else + { +#ifdef _DEBUG + NetLog_Server("Reused srvVisibilityID, id is %u, code is %u", wVisibilityID, bCode); +#endif + wCommand = ICQ_LISTS_UPDATEGROUP; + } + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (!ack) + { + NetLog_Server("Cookie alloc failure."); + return; // out of memory, go away + } + ack->dwAction = SSA_VISIBILITY; // update visibility + dwCookie = AllocateCookie(CKT_SERVERLIST, wCommand, 0, ack); // take cookie + + // Build and send packet + serverPacketInit(&packet, 25); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, wCommand, 0, dwCookie); + packWord(&packet, 0); // Name (null) + packWord(&packet, 0); // GroupID (0 if not relevant) + packWord(&packet, wVisibilityID); // EntryID + packWord(&packet, SSI_ITEM_VISIBILITY); // EntryType + packWord(&packet, 5); // Length in bytes of following TLV + packTLV(&packet, SSI_TLV_VISIBILITY, 1, &bCode); // TLV (Visibility) + sendServPacket(&packet); + // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or + // ICQ_LISTS_CLI_MODIFYEND when modifying the visibility code + } +} + +// Updates the avatar hash used while in SSI mode. If a server ID is +// not stored in the local DB, a new ID will be added to the server list. +void CIcqProto::updateServAvatarHash(BYTE *pHash, int size) +{ + void** pDoubleObject = NULL; + void* doubleObject = NULL; + DWORD dwOperationFlags = 0; + WORD wAvatarID; + WORD wCommand; + DBVARIANT dbvHash; + int bResetHash = 0; + char szItemName[2] = {0, 0}; + + if (!getSetting(NULL, "AvatarHash", &dbvHash)) + { + szItemName[0] = 0x30 + dbvHash.pbVal[1]; + + if (memcmp(pHash, dbvHash.pbVal, 2) != 0) + { + /** add code to remove old hash from server */ + bResetHash = 1; + } + ICQFreeVariant(&dbvHash); + } + + if (bResetHash) // start update session + { // pair the packets (need to be send in the correct order + dwOperationFlags |= SSOF_BEGIN_OPERATION | SSOF_END_OPERATION; + pDoubleObject = &doubleObject; + } + + if (bResetHash || !pHash) + { + cookie_servlist_action* ack; + DWORD dwCookie; + + // Do we have a known server avatar ID? + if (wAvatarID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) + { + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (!ack) + { + NetLog_Server("Cookie alloc failure."); + return; // out of memory, go away + } + ack->dwAction = SSA_REMOVEAVATAR; // update avatar hash + ack->wContactId = wAvatarID; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); // take cookie + + icq_sendServerItem(dwCookie, ICQ_LISTS_REMOVEFROMLIST, 0, wAvatarID, szItemName, NULL, 0, SSI_ITEM_BUDDYICON, SSOP_ITEM_ACTION | dwOperationFlags, 400, pDoubleObject); + } + } + + if (pHash) + { + cookie_servlist_action* ack; + DWORD dwCookie; + WORD wTLVlen; + icq_packet pBuffer; + WORD hashsize = size - 2; + + // Do we have a known server avatar ID? We should, unless we just subscribed to the serv-list for the first time + if (bResetHash || (wAvatarID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) == 0) + { + // No, create a new random ID + wAvatarID = GenerateServerID(SSIT_ITEM, 0); + wCommand = ICQ_LISTS_ADDTOLIST; +#ifdef _DEBUG + NetLog_Server("Made new srvAvatarID, id is %u", wAvatarID); +#endif + } + else + { +#ifdef _DEBUG + NetLog_Server("Reused srvAvatarID, id is %u", wAvatarID); +#endif + wCommand = ICQ_LISTS_UPDATEGROUP; + } + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (!ack) + { + NetLog_Server("Cookie alloc failure."); + return; // out of memory, go away + } + ack->dwAction = SSA_SETAVATAR; // update avatar hash + ack->wContactId = wAvatarID; + dwCookie = AllocateCookie(CKT_SERVERLIST, wCommand, 0, ack); // take cookie + + szItemName[0] = 0x30 + pHash[1]; + + // Build the packet + wTLVlen = 8 + hashsize; + + // Initialize our handy data buffer + pBuffer.wPlace = 0; + pBuffer.pData = (BYTE *)_alloca(wTLVlen); + pBuffer.wLen = wTLVlen; + + packTLV(&pBuffer, SSI_TLV_NAME, 0, NULL); // TLV (Name) + packTLV(&pBuffer, SSI_TLV_AVATARHASH, hashsize, pHash + 2); // TLV (Hash) + + icq_sendServerItem(dwCookie, wCommand, 0, wAvatarID, szItemName, pBuffer.pData, wTLVlen, SSI_ITEM_BUDDYICON, SSOP_ITEM_ACTION | dwOperationFlags, 400, pDoubleObject); + // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or + // ICQ_LISTS_CLI_MODIFYEND when modifying the avatar hash + } +} + +// Should be called before the server list is modified. When all +// modifications are done, call icq_sendServerEndOperation(). +// Called automatically thru server-list update board! +void CIcqProto::icq_sendServerBeginOperation(int bImport) +{ + icq_packet packet; + WORD wImportID = getSettingWord(NULL, "SrvImportID", 0); + + if (bImport && wImportID) + { // we should be importing, check if already have import item + if (getSettingDword(NULL, "ImportTS", 0) + 604800 < getSettingDword(NULL, "LogonTS", 0)) + { // is the timestamp week older, clear it and begin new import + DWORD dwCookie; + cookie_servlist_action* ack; + + if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) + { // we have cookie good, go on + ack->dwAction = SSA_IMPORT; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); + + icq_sendSimpleItem(dwCookie, ICQ_LISTS_REMOVEFROMLIST, 0, "ImportTime", 0, wImportID, SSI_ITEM_IMPORTTIME, SSOP_ITEM_ACTION | SSOF_SEND_DIRECTLY, 100); + } + } + } + + serverPacketInit(&packet, (WORD)(bImport?14:10)); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_MODIFYSTART); + if (bImport) packDWord(&packet, 1<<0x10); + sendServPacket(&packet); +} + +// Should be called after the server list has been modified to inform +// the server that we are done. +// Called automatically thru server-list update board! +void CIcqProto::icq_sendServerEndOperation() +{ + icq_packet packet; + + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_MODIFYEND); + sendServPacket(&packet); +} + +// Sent when the last roster packet has been received +void CIcqProto::sendRosterAck(void) +{ + icq_packet packet; + + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_GOTLIST); + sendServPacket(&packet); + +#ifdef _DEBUG + NetLog_Server("Sent SNAC(x13,x07) - CLI_ROSTERACK"); +#endif +} diff --git a/protocols/IcqOscarJ/src/fam_15icqserver.cpp b/protocols/IcqOscarJ/src/fam_15icqserver.cpp new file mode 100644 index 0000000000..3f332e4f27 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_15icqserver.cpp @@ -0,0 +1,1201 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleIcqExtensionsFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_META_ERROR: + handleExtensionError(pBuffer, wBufferLength); + break; + + case ICQ_META_SRV_REPLY: + handleExtensionServerInfo(pBuffer, wBufferLength, pSnacHeader->wFlags); + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_EXTENSIONS_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + + +void CIcqProto::handleExtensionError(BYTE *buf, WORD wPackLen) +{ + WORD wErrorCode; + + if (wPackLen < 2) + wErrorCode = 0; + + if (wPackLen >= 2 && wPackLen <= 6) + unpackWord(&buf, &wErrorCode); + else + { // TODO: cookies need to be handled and freed here on error + oscar_tlv_chain *chain = NULL; + + unpackWord(&buf, &wErrorCode); + wPackLen -= 2; + chain = readIntoTLVChain(&buf, wPackLen, 0); + if (chain) + { + oscar_tlv* pTLV; + + pTLV = chain->getTLV(0x21, 1); // get meta error data + if (pTLV && pTLV->wLen >= 8) + { + BYTE *pBuffer = pTLV->pData; + WORD wData; + pBuffer += 6; + unpackLEWord(&pBuffer, &wData); // get request type + switch (wData) + { + case CLI_META_INFO_REQ: + if (pTLV->wLen >= 12) + { + WORD wSubType; + WORD wCookie; + + unpackWord(&pBuffer, &wCookie); + unpackLEWord(&pBuffer, &wSubType); + // more sofisticated detection, send ack + if (wSubType == META_REQUEST_FULL_INFO) + { + HANDLE hContact; + cookie_fam15_data *pCookieData = NULL; + int foundCookie; + + foundCookie = FindCookie(wCookie, &hContact, (void**)&pCookieData); + if (foundCookie && pCookieData) + { + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + + ReleaseCookie(wCookie); // we do not leak cookie and memory + } + + NetLog_Server("Full info request error 0x%02x received", wErrorCode); + } + else if (wSubType == META_SET_PASSWORD_REQ) + { // failed to change user password, report to UI + BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); + + NetLog_Server("Meta change password request failed, error 0x%02x", wErrorCode); + } + else + NetLog_Server("Meta request error 0x%02x received", wErrorCode); + } + else + NetLog_Server("Meta request error 0x%02x received", wErrorCode); + + break; + + default: + NetLog_Server("Unknown request 0x%02x error 0x%02x received", wData, wErrorCode); + } + disposeChain(&chain); + return; + } + disposeChain(&chain); + } + } + LogFamilyError(ICQ_EXTENSIONS_FAMILY, wErrorCode); +} + + +void CIcqProto::handleExtensionServerInfo(BYTE *buf, WORD wPackLen, WORD wFlags) +{ + oscar_tlv_chain *chain; + oscar_tlv *dataTlv; + + // The entire packet is encapsulated in a TLV type 1 + chain = readIntoTLVChain(&buf, wPackLen, 0); + if (chain == NULL) + { + NetLog_Server("Error: Broken snac 15/3 %d", 1); + return; + } + + dataTlv = chain->getTLV(0x0001, 1); + if (dataTlv == NULL) + { + disposeChain(&chain); + NetLog_Server("Error: Broken snac 15/3 %d", 2); + return; + } + BYTE *databuf = dataTlv->pData; + wPackLen -= 4; + + _ASSERTE(dataTlv->wLen == wPackLen); + _ASSERTE(wPackLen >= 10); + + if ((dataTlv->wLen == wPackLen) && (wPackLen >= 10)) + { + WORD wBytesRemaining; + WORD wRequestType; + WORD wCookie; + DWORD dwMyUin; + + unpackLEWord(&databuf, &wBytesRemaining); + unpackLEDWord(&databuf, &dwMyUin); + unpackLEWord(&databuf, &wRequestType); + unpackWord(&databuf, &wCookie); + + _ASSERTE(wBytesRemaining == (wPackLen - 2)); + if (wBytesRemaining == (wPackLen - 2)) + { + wPackLen -= 10; + switch (wRequestType) + { + case SRV_META_INFO_REPLY: // SRV_META request replies + handleExtensionMetaResponse(databuf, wPackLen, wCookie, wFlags); + break; + + default: + NetLog_Server("Warning: Ignoring Meta response - Unknown type %d", wRequestType); + break; + } + } + } + else + NetLog_Server("Error: Broken snac 15/3 %d", 3); + + if (chain) + disposeChain(&chain); +} + + +void CIcqProto::handleExtensionMetaResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags) +{ + WORD wReplySubtype; + BYTE bResultCode; + + _ASSERTE(wPacketLen >= 3); + if (wPacketLen >= 3) + { + // Reply subtype + unpackLEWord(&databuf, &wReplySubtype); + wPacketLen -= 2; + + // Success byte + unpackByte(&databuf, &bResultCode); + wPacketLen -= 1; + + switch (wReplySubtype) + { + case META_SET_PASSWORD_ACK: + parseUserInfoUpdateAck(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); + break; + + case SRV_RANDOM_FOUND: + case SRV_USER_FOUND: + case SRV_LAST_USER_FOUND: + parseSearchReplies(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); + break; + + case META_PROCESSING_ERROR: // Meta processing error server reply + // Todo: We only use this as an SMS ack, that will have to change + { + // Terminate buffer + char *pszInfo = (char *)_alloca(wPacketLen + 1); + if (wPacketLen > 0) + memcpy(pszInfo, databuf, wPacketLen); + pszInfo[wPacketLen] = 0; + + BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_FAILED, (HANDLE)wCookie, (LPARAM)pszInfo); + FreeCookie(wCookie); + break; + } + break; + + case META_SMS_DELIVERY_RECEIPT: + // Todo: This overlaps with META_SET_AFFINFO_ACK. + // Todo: Check what happens if result != A + if (wPacketLen > 8) + { + WORD wNetworkNameLen; + WORD wAckLen; + char *pszInfo; + + + databuf += 6; // Some unknowns + wPacketLen -= 6; + + unpackWord(&databuf, &wNetworkNameLen); + if (wPacketLen >= (wNetworkNameLen + 2)) + { + databuf += wNetworkNameLen; + wPacketLen -= wNetworkNameLen; + + unpackWord(&databuf, &wAckLen); + if (pszInfo = (char *)_alloca(wAckLen + 1)) + { + // Terminate buffer + if (wAckLen > 0) + memcpy(pszInfo, databuf, wAckLen); + pszInfo[wAckLen] = 0; + + BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SENTREQUEST, (HANDLE)wCookie, (LPARAM)pszInfo); + FreeCookie(wCookie); + + // Parsing success + break; + } + } + } + + // Parsing failure + NetLog_Server("Error: Failure parsing META_SMS_DELIVERY_RECEIPT"); + break; + + case META_DIRECTORY_DATA: + case META_DIRECTORY_RESPONSE: + if (bResultCode == 0x0A) + handleDirectoryQueryResponse(databuf, wPacketLen, wCookie, wReplySubtype, wFlags); + else + NetLog_Server("Error: Directory request failed, code %u", bResultCode); + break; + + case META_DIRECTORY_UPDATE_ACK: + if (bResultCode == 0x0A) + handleDirectoryUpdateResponse(databuf, wPacketLen, wCookie, wReplySubtype); + else + NetLog_Server("Error: Directory request failed, code %u", bResultCode); + break; + + default: + NetLog_Server("Warning: Ignored 15/03 replysubtype x%x", wReplySubtype); + // _ASSERTE(0); + break; + } + + // Success + return; + } + + // Failure + NetLog_Server("Warning: Broken 15/03 ExtensionMetaResponse"); +} + + +void CIcqProto::ReleaseSearchCookie(DWORD dwCookie, cookie_search *pCookie) +{ + if (pCookie) + { + FreeCookie(dwCookie); + if (pCookie->dwMainId) + { + if (pCookie->dwStatus) + { + SAFE_FREE((void**)&pCookie); + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); + } + else + pCookie->dwStatus = 1; + } + else + { + SAFE_FREE((void**)&pCookie); + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); + } + } + else + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); +} + + +void CIcqProto::parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode) +{ + BYTE bParsingOK = FALSE; // For debugging purposes only + BOOL bLastUser = FALSE; + cookie_search *pCookie; + + if (!FindCookie(wCookie, NULL, (void**)&pCookie)) + { + NetLog_Server("Warning: Received unexpected search reply"); + pCookie = NULL; + } + + switch (wReplySubtype) + { + + case SRV_LAST_USER_FOUND: // Search: last user found reply + bLastUser = TRUE; + + case SRV_USER_FOUND: // Search: user found reply + if (bLastUser) + NetLog_Server("SNAC(0x15,0x3): Last search reply"); + else + NetLog_Server("SNAC(0x15,0x3): Search reply"); + + if (bResultCode == 0xA) + { + ICQSEARCHRESULT sr = {0}; + DWORD dwUin; + char szUin[UINMAXLEN]; + WORD wLen; + + sr.hdr.cbSize = sizeof(sr); + + // Remaining bytes + if (wPacketLen < 2) + break; + unpackLEWord(&databuf, &wLen); + wPacketLen -= 2; + + _ASSERTE(wLen <= wPacketLen); + if (wLen > wPacketLen) + break; + + // Uin + if (wPacketLen < 4) + break; + unpackLEDWord(&databuf, &dwUin); // Uin + wPacketLen -= 4; + sr.uin = dwUin; + _itoa(dwUin, szUin, 10); + sr.hdr.id = (FNAMECHAR*)szUin; + + // Nick + if (wPacketLen < 2) + break; + unpackLEWord(&databuf, &wLen); + wPacketLen -= 2; + if (wLen > 0) + { + if (wPacketLen < wLen || (databuf[wLen-1] != 0)) + break; + sr.hdr.nick = (FNAMECHAR*)databuf; + databuf += wLen; + } + else + { + sr.hdr.nick = NULL; + } + + // First name + if (wPacketLen < 2) + break; + unpackLEWord(&databuf, &wLen); + wPacketLen -= 2; + if (wLen > 0) + { + if (wPacketLen < wLen || (databuf[wLen-1] != 0)) + break; + sr.hdr.firstName = (FNAMECHAR*)databuf; + databuf += wLen; + } + else + { + sr.hdr.firstName = NULL; + } + + // Last name + if (wPacketLen < 2) + break; + unpackLEWord(&databuf, &wLen); + wPacketLen -= 2; + if (wLen > 0) + { + if (wPacketLen < wLen || (databuf[wLen-1] != 0)) + break; + sr.hdr.lastName = (FNAMECHAR*)databuf; + databuf += wLen; + } + else + { + sr.hdr.lastName = NULL; + } + + // E-mail name + if (wPacketLen < 2) + break; + unpackLEWord(&databuf, &wLen); + wPacketLen -= 2; + if (wLen > 0) + { + if (wPacketLen < wLen || (databuf[wLen-1] != 0)) + break; + sr.hdr.email = (FNAMECHAR*)databuf; + databuf += wLen; + } + else + { + sr.hdr.email = NULL; + } + + // Authentication needed flag + if (wPacketLen < 1) + break; + unpackByte(&databuf, &sr.auth); + + // Finally, broadcast the result + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)wCookie, (LPARAM)&sr); + + // Broadcast "Last result" ack if this was the last user found + if (wReplySubtype == SRV_LAST_USER_FOUND) + { + if (wPacketLen>=10) + { + DWORD dwLeft; + + databuf += 5; + unpackLEDWord(&databuf, &dwLeft); + if (dwLeft) + NetLog_Server("Warning: %d search results omitted", dwLeft); + } + ReleaseSearchCookie(wCookie, pCookie); + } + bParsingOK = TRUE; + } + else + { + // Failed search + NetLog_Server("SNAC(0x15,0x3): Search error %u", bResultCode); + + ReleaseSearchCookie(wCookie, pCookie); + + bParsingOK = TRUE; + } + break; + + case SRV_RANDOM_FOUND: // Random search server reply + default: + if (pCookie) + ReleaseCookie(wCookie); + break; + } + + // For debugging purposes only + if (!bParsingOK) + { + NetLog_Server("Warning: Parsing error in 15/03 search reply type x%x", wReplySubtype); + _ASSERTE(!bParsingOK); + } +} + + +void CIcqProto::parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode) +{ + switch (wReplySubtype) { + case META_SET_PASSWORD_ACK: // Set user password server ack + + if (bResultCode == 0xA) + BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + else + BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); + + FreeCookie(wCookie); + break; + + default: + NetLog_Server("Warning: Ignored 15/03 user info update ack type x%x", wReplySubtype); + break; + } +} + + +UserInfoRecordItem rEmail[] = { + {0x64, DBVT_ASCIIZ, "e-mail%u"} +}; + +UserInfoRecordItem rAddress[] = { + {0x64, DBVT_UTF8, "Street"}, + {0x6E, DBVT_UTF8, "City"}, + {0x78, DBVT_UTF8, "State"}, + {0x82, DBVT_UTF8, "ZIP"}, + {0x8C, DBVT_WORD, "Country"} +}; + +UserInfoRecordItem rOriginAddress[] = { + {0x64, DBVT_UTF8, "OriginStreet"}, + {0x6E, DBVT_UTF8, "OriginCity"}, + {0x78, DBVT_UTF8, "OriginState"}, + {0x8C, DBVT_WORD, "OriginCountry"} +}; + +UserInfoRecordItem rCompany[] = { + {0x64, DBVT_UTF8, "CompanyPosition"}, + {0x6E, DBVT_UTF8, "Company"}, + {0x7D, DBVT_UTF8, "CompanyDepartment"}, + {0x78, DBVT_ASCIIZ, "CompanyHomepage"}, + {0x82, DBVT_WORD, "CompanyIndustry"}, + {0xAA, DBVT_UTF8, "CompanyStreet"}, + {0xB4, DBVT_UTF8, "CompanyCity"}, + {0xBE, DBVT_UTF8, "CompanyState"}, + {0xC8, DBVT_UTF8, "CompanyZIP"}, + {0xD2, DBVT_WORD, "CompanyCountry"} +}; + +UserInfoRecordItem rEducation[] = { + {0x64, DBVT_WORD, "StudyLevel"}, + {0x6E, DBVT_UTF8, "StudyInstitute"}, + {0x78, DBVT_UTF8, "StudyDegree"}, + {0x8C, DBVT_WORD, "StudyYear"} +}; + +UserInfoRecordItem rInterest[] = { + {0x64, DBVT_UTF8, "Interest%uText"}, + {0x6E, DBVT_WORD, "Interest%uCat"} +}; + + +int CIcqProto::parseUserInfoRecord(HANDLE hContact, oscar_tlv *pData, UserInfoRecordItem pRecordDef[], int nRecordDef, int nMaxRecords) +{ + int nRecords = 0; + + if (pData && pData->wLen >= 2) + { + BYTE *pRecords = pData->pData; + WORD wRecordCount; + unpackWord(&pRecords, &wRecordCount); + oscar_tlv_record_list *cData = readIntoTLVRecordList(&pRecords, pData->wLen - 2, nMaxRecords > wRecordCount ? wRecordCount : nMaxRecords); + oscar_tlv_record_list *cDataItem = cData; + while (cDataItem) + { + oscar_tlv_chain *cItem = cDataItem->item; + + for (int i = 0; i < nRecordDef; i++) + { + char szItemKey[MAX_PATH]; + + null_snprintf(szItemKey, MAX_PATH, pRecordDef[i].szDbSetting, nRecords); + + switch (pRecordDef[i].dbType) + { + case DBVT_ASCIIZ: + writeDbInfoSettingTLVString(hContact, szItemKey, cItem, pRecordDef[i].wTLV); + break; + + case DBVT_UTF8: + writeDbInfoSettingTLVStringUtf(hContact, szItemKey, cItem, pRecordDef[i].wTLV); + break; + + case DBVT_WORD: + writeDbInfoSettingTLVWord(hContact, szItemKey, cItem, pRecordDef[i].wTLV); + break; + } + } + nRecords++; + + cDataItem = cDataItem->next; + } + // release memory + disposeRecordList(&cData); + } + // remove old data from database + if (!nRecords || nMaxRecords > 1) + for (int i = nRecords; i <= nMaxRecords; i++) + for (int j = 0; j < nRecordDef; j++) + { + char szItemKey[MAX_PATH]; + + null_snprintf(szItemKey, MAX_PATH, pRecordDef[j].szDbSetting, i); + + deleteSetting(hContact, szItemKey); + } + + return nRecords; +} + + +void CIcqProto::handleDirectoryQueryResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, WORD wFlags) +{ + WORD wBytesRemaining = 0; + snac_header requestSnac = {0}; + BYTE requestResult; + +#ifdef _DEBUG + NetLog_Server("Received directory query response"); +#endif + if (wPacketLen >= 2) + unpackLEWord(&databuf, &wBytesRemaining); + wPacketLen -= 2; + _ASSERTE(wPacketLen == wBytesRemaining); + + if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) + { + NetLog_Server("Error: Failed to parse directory response"); + return; + } + + cookie_directory_data *pCookieData; + HANDLE hContact; + // check request cookie + if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) + { + NetLog_Server("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); + return; + } + /// FIXME: we should really check the snac contents according to cookie data here ?? + + // Check if this is the last packet for this request + BOOL bMoreDataFollows = wFlags&0x0001 && requestSnac.wFlags&0x0001; + + if (wPacketLen >= 3) + unpackByte(&databuf, &requestResult); + else + { + NetLog_Server("Error: Malformed directory response"); + if (!bMoreDataFollows) + ReleaseCookie(wCookie); + return; + } + if (requestResult != 1 && requestResult != 4) + { + NetLog_Server("Error: Directory request failed, status %u", requestResult); + + if (!bMoreDataFollows) + { + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that + ReleaseCookie(wCookie); + } + return; + } + WORD wLen; + + unpackWord(&databuf, &wLen); + wPacketLen -= 3; + if (wLen) + NetLog_Server("Warning: Data in error message present!"); + + if (wPacketLen <= 0x16) + { // sanity check + NetLog_Server("Error: Malformed directory response"); + + if (!bMoreDataFollows) + { + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that + ReleaseCookie(wCookie); + } + return; + } + databuf += 0x10; // unknown stuff + wPacketLen -= 0x10; + + DWORD dwItemCount; + WORD wPageCount; + + /// FIXME: check itemcount, pagecount against the cookie data ??? + + unpackDWord(&databuf, &dwItemCount); + unpackWord(&databuf, &wPageCount); + wPacketLen -= 6; + + if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH && !bMoreDataFollows) + NetLog_Server("Directory Search: %d contacts found (%u pages)", dwItemCount, wPageCount); + + if (wPacketLen <= 2) + { // sanity check, block expected + NetLog_Server("Error: Malformed directory response"); + + if (!bMoreDataFollows) + { + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that + ReleaseCookie(wCookie); + } + return; + } + WORD wData; + + unpackWord(&databuf, &wData); // This probably the count of items following (a block) + wPacketLen -= 2; + if (wPacketLen >= 2 && wData >= 1) + { + unpackWord(&databuf, &wLen); // This is the size of the first item + wPacketLen -= 2; + } + + if (wData == 0 && pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) + { + NetLog_Server("Directory Search: No contacts found"); + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + ReleaseCookie(wCookie); + return; + } + + _ASSERTE(wData == 1 && wPacketLen == wLen); + if (wData != 1 || wPacketLen != wLen) + { + NetLog_Server("Error: Malformed directory response (missing data)"); + + if (!bMoreDataFollows) + { + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); + else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that + ReleaseCookie(wCookie); + } + return; + } + oscar_tlv_chain *pDirectoryData = readIntoTLVChain(&databuf, wLen, -1); + if (pDirectoryData) + { + switch (pCookieData->bRequestType) + { + case DIRECTORYREQUEST_INFOOWNER: + parseDirectoryUserDetailsData(NULL, pDirectoryData, wCookie, pCookieData, wReplySubtype); + break; + + case DIRECTORYREQUEST_INFOUSER: + { + DWORD dwUin = 0; + char *szUid = pDirectoryData->getString(0x32, 1); + if (!szUid) + { + NetLog_Server("Error: Received unrecognized data from the directory"); + break; + } + + if (IsStringUIN(szUid)) + dwUin = atoi(szUid); + + if (hContact != HContactFromUID(dwUin, szUid, NULL)) + { + NetLog_Server("Error: Received data does not match cookie contact, ignoring."); + SAFE_FREE(&szUid); + break; + } + else + SAFE_FREE(&szUid); + } + + case DIRECTORYREQUEST_INFOMULTI: + parseDirectoryUserDetailsData(hContact, pDirectoryData, wCookie, pCookieData, wReplySubtype); + break; + + case DIRECTORYREQUEST_SEARCH: + parseDirectorySearchData(pDirectoryData, wCookie, pCookieData, wReplySubtype); + break; + + default: + NetLog_Server("Error: Unknown cookie type %x for directory response!", pCookieData->bRequestType); + } + disposeChain(&pDirectoryData); + } + else + NetLog_Server("Error: Failed parsing directory response"); + + // Release Memory + if (!bMoreDataFollows) + ReleaseCookie(wCookie); +} + + +static int calcAgeFromBirthDate(double dDate) +{ + if (dDate > 0) + { // date is stored as double with unit equal to a day, incrementing since 1/1/1900 0:00 GMT + SYSTEMTIME sDate = {0}; + if (VariantTimeToSystemTime(dDate + 2, &sDate)) + { + SYSTEMTIME sToday = {0}; + + GetLocalTime(&sToday); + + int nAge = sToday.wYear - sDate.wYear; + + if (sToday.wMonth < sDate.wMonth || (sToday.wMonth == sDate.wMonth && sToday.wDay < sDate.wDay)) + nAge--; + + return nAge; + } + } + return 0; +} + + +void CIcqProto::parseDirectoryUserDetailsData(HANDLE hContact, oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType) +{ + oscar_tlv *pTLV; + WORD wRecordCount; + + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOMULTI && !hContact) + { + DWORD dwUin = 0; + char *szUid = cDetails->getString(0x32, 1); + if (!szUid) + { + NetLog_Server("Error: Received unrecognized data from the directory"); + return; + } + + if (IsStringUIN(szUid)) + dwUin = atoi(szUid); + + hContact = HContactFromUID(dwUin, szUid, NULL); + if (hContact == INVALID_HANDLE_VALUE) + { + NetLog_Server("Error: Received details for unknown contact \"%s\"", szUid); + SAFE_FREE(&szUid); + return; + } +#ifdef _DEBUG + else + NetLog_Server("Received user info for %s from directory", szUid); +#endif + SAFE_FREE(&szUid); + } +#ifdef _DEBUG + else + { + char *szUid = cDetails->getString(0x32, 1); + + if (!hContact) + NetLog_Server("Received owner user info from directory"); + else + NetLog_Server("Received user info for %s from directory", szUid); + SAFE_FREE(&szUid); + } +#endif + + pTLV = cDetails->getTLV(0x50, 1); + if (pTLV && pTLV->wLen > 0) + writeDbInfoSettingTLVString(hContact, "e-mail", cDetails, 0x50); // Verified e-mail + else + writeDbInfoSettingTLVString(hContact, "e-mail", cDetails, 0x55); // Pending e-mail + + writeDbInfoSettingTLVStringUtf(hContact, "FirstName", cDetails, 0x64); + writeDbInfoSettingTLVStringUtf(hContact, "LastName", cDetails, 0x6E); + writeDbInfoSettingTLVStringUtf(hContact, "Nick", cDetails, 0x78); + // Home Address + parseUserInfoRecord(hContact, cDetails->getTLV(0x96, 1), rAddress, SIZEOF(rAddress), 1); + // Origin Address + parseUserInfoRecord(hContact, cDetails->getTLV(0xA0, 1), rOriginAddress, SIZEOF(rOriginAddress), 1); + // Phones + pTLV = cDetails->getTLV(0xC8, 1); + if (pTLV && pTLV->wLen >= 2) + { + BYTE *pRecords = pTLV->pData; + unpackWord(&pRecords, &wRecordCount); + oscar_tlv_record_list *cPhones = readIntoTLVRecordList(&pRecords, pTLV->wLen - 2, wRecordCount); + if (cPhones) + { + oscar_tlv_chain *cPhone; + cPhone = cPhones->getRecordByTLV(0x6E, 1); + writeDbInfoSettingTLVString(hContact, "Phone", cPhone, 0x64); + cPhone = cPhones->getRecordByTLV(0x6E, 2); + writeDbInfoSettingTLVString(hContact, "CompanyPhone", cPhone, 0x64); + cPhone = cPhones->getRecordByTLV(0x6E, 3); + writeDbInfoSettingTLVString(hContact, "Cellular", cPhone, 0x64); + cPhone = cPhones->getRecordByTLV(0x6E, 4); + writeDbInfoSettingTLVString(hContact, "Fax", cPhone, 0x64); + cPhone = cPhones->getRecordByTLV(0x6E, 5); + writeDbInfoSettingTLVString(hContact, "CompanyFax", cPhone, 0x64); + + disposeRecordList(&cPhones); + } + else + { // Remove old data when phones not available + deleteSetting(hContact, "Phone"); + deleteSetting(hContact, "CompanyPhone"); + deleteSetting(hContact, "Cellular"); + deleteSetting(hContact, "Fax"); + deleteSetting(hContact, "CompanyFax"); + } + } + else + { // Remove old data when phones not available + deleteSetting(hContact, "Phone"); + deleteSetting(hContact, "CompanyPhone"); + deleteSetting(hContact, "Cellular"); + deleteSetting(hContact, "Fax"); + deleteSetting(hContact, "CompanyFax"); + } + // Emails + parseUserInfoRecord(hContact, cDetails->getTLV(0x8C, 1), rEmail, SIZEOF(rEmail), 4); + + writeDbInfoSettingTLVByte(hContact, "Timezone", cDetails, 0x17C); + // Company + parseUserInfoRecord(hContact, cDetails->getTLV(0x118, 1), rCompany, SIZEOF(rCompany), 1); + // Education + parseUserInfoRecord(hContact, cDetails->getTLV(0x10E, 1), rEducation, SIZEOF(rEducation), 1); + + switch (cDetails->getNumber(0x82, 1)) + { + case 1: + setSettingByte(hContact, "Gender", 'F'); + break; + case 2: + setSettingByte(hContact, "Gender", 'M'); + break; + default: + deleteSetting(hContact, "Gender"); + } + + writeDbInfoSettingTLVString(hContact, "Homepage", cDetails, 0xFA); + writeDbInfoSettingTLVDate(hContact, "BirthYear", "BirthMonth", "BirthDay", cDetails, 0x1A4); + + writeDbInfoSettingTLVByte(hContact, "Language1", cDetails, 0xAA); + writeDbInfoSettingTLVByte(hContact, "Language2", cDetails, 0xB4); + writeDbInfoSettingTLVByte(hContact, "Language3", cDetails, 0xBE); + + writeDbInfoSettingTLVByte(hContact, "MaritalStatus", cDetails, 0x12C); + // Interests + parseUserInfoRecord(hContact, cDetails->getTLV(0x122, 1), rInterest, SIZEOF(rInterest), 4); + + writeDbInfoSettingTLVStringUtf(hContact, "About", cDetails, 0x186); + +// if (hContact) +// writeDbInfoSettingTLVStringUtf(hContact, DBSETTING_STATUS_NOTE, cDetails, 0x226); +// else + if (!hContact) + { // Owner contact needs special processing, in the database is current status note for the client + // We just received the last status note set on directory, if it differs call SetStatusNote() to + // ensure the directory will be updated (it should be in process anyway) + char *szClientStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, NULL); + char *szDirectoryStatusNote = cDetails->getString(0x226, 1); + + if (strcmpnull(szClientStatusNote, szDirectoryStatusNote)) + SetStatusNote(szClientStatusNote, 1000, TRUE); + + // Release memory + SAFE_FREE(&szDirectoryStatusNote); + SAFE_FREE(&szClientStatusNote); + } + + writeDbInfoSettingTLVByte(hContact, "PrivacyLevel", cDetails, 0x1F9); + + if (!hContact) + { + setSettingByte(hContact, "Auth", !cDetails->getByte(0x19A, 1)); + writeDbInfoSettingTLVByte(hContact, "WebAware", cDetails, 0x212); + writeDbInfoSettingTLVByte(hContact, "AllowSpam", cDetails, 0x1EA); + } + + writeDbInfoSettingTLVWord(hContact, "InfoCP", cDetails, 0x1C2); + + if (hContact) + { // Handle deprecated setting (Age & Birthdate are not separate fields anymore) + int nAge = calcAgeFromBirthDate(cDetails->getDouble(0x1A4, 1)); + + if (nAge) + setSettingWord(hContact, "Age", nAge); + else + deleteSetting(hContact, "Age"); + } + else // we do not need to calculate age for owner + deleteSetting(hContact, "Age"); + + { // Save user info last update time and privacy token + double dInfoTime; + BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int bHasMetaToken = FALSE; + + // Check if the details arrived with privacy token! + if ((pTLV = cDetails->getTLV(0x3C, 1)) && pTLV->wLen == 0x10 && memcmp(pTLV->pData, pbEmptyMetaToken, 0x10)) + bHasMetaToken = TRUE; + + // !Important, we need to save the MDir server-item time - it can be newer than the one from the directory + if ((dInfoTime = getSettingDouble(hContact, DBSETTING_METAINFO_TIME, 0)) > 0) + setSettingDouble(hContact, DBSETTING_METAINFO_SAVED, dInfoTime); + else if (bHasMetaToken || !hContact) + writeDbInfoSettingTLVDouble(hContact, DBSETTING_METAINFO_SAVED, cDetails, 0x1CC); + else + setSettingDword(hContact, DBSETTING_METAINFO_SAVED, time(NULL)); + } + + if (wReplySubType == META_DIRECTORY_RESPONSE) + if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) + BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0); + + // Remove user from info update queue. Removing is fast so we always call this + // even if it is likely that the user is not queued at all. + if (hContact) + icq_DequeueUser(getContactUin(hContact)); +} + + +void CIcqProto::parseDirectorySearchData(oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType) +{ + ICQSEARCHRESULT isr = {0}; + char *szUid = cDetails->getString(0x32, 1); // User ID + +#ifdef _DEBUG + NetLog_Server("Directory Search: Found user %s", szUid); +#endif + isr.hdr.cbSize = sizeof(ICQSEARCHRESULT); + isr.hdr.flags = PSR_TCHAR; + isr.hdr.id = ansi_to_tchar(szUid); + + if (IsStringUIN(szUid)) + isr.uin = atoi(szUid); + else + isr.uin = 0; + + SAFE_FREE(&szUid); + + oscar_tlv *pTLV = cDetails->getTLV(0x50, 1); + char *szData = NULL; + + if (pTLV && pTLV->wLen > 0) + szData = cDetails->getString(0x50, 1); // Verified e-mail + else + szData = cDetails->getString(0x55, 1); // Pending e-mail + if (strlennull(szData)) + isr.hdr.email = ansi_to_tchar(szData); + SAFE_FREE(&szData); + + szData = cDetails->getString(0x64, 1); // First Name + if (strlennull(szData)) + isr.hdr.firstName = utf8_to_tchar(szData); + SAFE_FREE(&szData); + + szData = cDetails->getString(0x6E, 1); // Last Name + if (strlennull(szData)) + isr.hdr.lastName = utf8_to_tchar(szData); + SAFE_FREE(&szData); + + szData = cDetails->getString(0x78, 1); // Nick + if (strlennull(szData)) + isr.hdr.nick = utf8_to_tchar(szData); + SAFE_FREE(&szData); + + switch (cDetails->getNumber(0x82, 1)) // Gender + { + case 1: + isr.gender = 'F'; + break; + case 2: + isr.gender = 'M'; + break; + } + + pTLV = cDetails->getTLV(0x96, 1); + if (pTLV && pTLV->wLen >= 4) + { + BYTE *buf = pTLV->pData; + oscar_tlv_chain *chain = readIntoTLVChain(&buf, pTLV->wLen, 0); + if (chain) + isr.country = chain->getDWord(0x8C, 1); // Home Country + disposeChain(&chain); + } + + isr.auth = !cDetails->getByte(0x19A, 1); // Require Authorization + isr.maritalStatus = cDetails->getNumber(0x12C, 1); // Marital Status + + // calculate Age if Birthdate is available + isr.age = calcAgeFromBirthDate(cDetails->getDouble(0x1A4, 1)); + + // Finally, broadcast the result + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)dwCookie, (LPARAM)&isr); + + // Release memory + SAFE_FREE(&isr.hdr.id); + SAFE_FREE(&isr.hdr.nick); + SAFE_FREE(&isr.hdr.firstName); + SAFE_FREE(&isr.hdr.lastName); + SAFE_FREE(&isr.hdr.email); + + // Search is over, broadcast final ack + if (wReplySubType == META_DIRECTORY_RESPONSE) + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); +} + + +void CIcqProto::handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype) +{ + WORD wBytesRemaining = 0; + snac_header requestSnac = {0}; + BYTE requestResult; + +#ifdef _DEBUG + NetLog_Server("Received directory update response"); +#endif + if (wPacketLen >= 2) + unpackLEWord(&databuf, &wBytesRemaining); + wPacketLen -= 2; + _ASSERTE(wPacketLen == wBytesRemaining); + + if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) + { + NetLog_Server("Error: Failed to parse directory response"); + return; + } + + cookie_directory_data *pCookieData; + HANDLE hContact; + // check request cookie + if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) + { + NetLog_Server("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); + return; + } + /// FIXME: we should really check the snac contents according to cookie data here ?? + + if (wPacketLen >= 3) + unpackByte(&databuf, &requestResult); + else + { + NetLog_Server("Error: Malformed directory response"); + ReleaseCookie(wCookie); + return; + } + if (requestResult != 1 && requestResult != 4) + { + NetLog_Server("Error: Directory request failed, status %u", requestResult); + + if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) + BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); + + ReleaseCookie(wCookie); + return; + } + WORD wLen; + + unpackWord(&databuf, &wLen); + wPacketLen -= 3; + if (wLen) + NetLog_Server("Warning: Data in error message present!"); + + if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) + BroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + if (wPacketLen == 0x18) + { + DWORD64 qwMetaTime; + BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + unpackQWord(&databuf, &qwMetaTime); + setSettingBlob(NULL, DBSETTING_METAINFO_TIME, (BYTE*)&qwMetaTime, 8); + + if (memcmp(databuf, pbEmptyMetaToken, 0x10)) + setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, databuf, 0x10); + } + ReleaseCookie(wCookie); +} diff --git a/protocols/IcqOscarJ/src/fam_17signon.cpp b/protocols/IcqOscarJ/src/fam_17signon.cpp new file mode 100644 index 0000000000..b35a432a48 --- /dev/null +++ b/protocols/IcqOscarJ/src/fam_17signon.cpp @@ -0,0 +1,175 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleAuthorizationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_SIGNON_ERROR: + { + WORD wError; + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + LogFamilyError(ICQ_AUTHORIZATION_FAMILY, wError); + break; + } + + case ICQ_SIGNON_AUTH_KEY: + handleAuthKeyResponse(pBuffer, wBufferLength, info); + break; + + case ICQ_SIGNON_LOGIN_REPLY: + handleLoginReply(pBuffer, wBufferLength, info); + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_AUTHORIZATION_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + +static void icq_encryptPassword(const char *szPassword, BYTE *encrypted) +{ + BYTE table[] = + { + 0xf3, 0x26, 0x81, 0xc4, + 0x39, 0x86, 0xdb, 0x92, + 0x71, 0xa3, 0xb9, 0xe6, + 0x53, 0x7a, 0x95, 0x7c + }; + + for (int i = 0; szPassword[i]; i++) + encrypted[i] = (szPassword[i] ^ table[i % 16]); +} + +void CIcqProto::sendClientAuth(const char *szKey, WORD wKeyLen, BOOL bSecure) +{ + char szUin[UINMAXLEN]; + WORD wUinLen; + icq_packet packet; + + wUinLen = strlennull(strUID(m_dwLocalUIN, szUin)); + + packet.wLen = 70 + sizeof(CLIENT_ID_STRING) + wUinLen + wKeyLen + (m_bSecureConnection ? 4 : 0); + + if (bSecure) + { + serverPacketInit(&packet, (WORD)(packet.wLen + 10)); + packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_LOGIN_REQUEST, 0, 0); + } + else + { + write_flap(&packet, ICQ_LOGIN_CHAN); + packDWord(&packet, 0x00000001); + } + packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin); + + if (bSecure) + { // Pack MD5 auth digest + packTLV(&packet, 0x0025, wKeyLen, (BYTE*)szKey); + packDWord(&packet, 0x004C0000); // empty TLV(0x4C): unknown + } + else + { // Pack old style password hash + BYTE hash[20]; + + icq_encryptPassword(szKey, hash); + packTLV(&packet, 0x0002, wKeyLen, hash); + } + + // Pack client identification details. + packTLV(&packet, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, (LPBYTE)CLIENT_ID_STRING); + packTLVWord(&packet, 0x0017, CLIENT_VERSION_MAJOR); + packTLVWord(&packet, 0x0018, CLIENT_VERSION_MINOR); + packTLVWord(&packet, 0x0019, CLIENT_VERSION_LESSER); + packTLVWord(&packet, 0x001a, CLIENT_VERSION_BUILD); + packTLVWord(&packet, 0x0016, CLIENT_ID_CODE); + packTLVDWord(&packet, 0x0014, CLIENT_DISTRIBUTION); + packTLV(&packet, 0x000f, 0x0002, (LPBYTE)CLIENT_LANGUAGE); + packTLV(&packet, 0x000e, 0x0002, (LPBYTE)CLIENT_COUNTRY); + packTLV(&packet, 0x0094, 0x0001, &m_bConnectionLost); // CLIENT_RECONNECT flag + if (m_bSecureConnection) + packDWord(&packet, 0x008C0000); // empty TLV(0x8C): use SSL + + sendServPacket(&packet); +} + +void CIcqProto::handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info) +{ + WORD wKeyLen; + char szKey[64] = {0}; + mir_md5_state_t state; + mir_md5_byte_t digest[16]; + +#ifdef _DEBUG + NetLog_Server("Received %s", "ICQ_SIGNON_AUTH_KEY"); +#endif + + if (wPacketLen < 2) + { + NetLog_Server("Malformed %s", "ICQ_SIGNON_AUTH_KEY"); + icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid server response.")); + SetCurrentStatus(ID_STATUS_OFFLINE); + return; + } + + unpackWord(&buf, &wKeyLen); + wPacketLen -= 2; + + if (!wKeyLen || wKeyLen > wPacketLen || wKeyLen > sizeof(szKey)) + { + NetLog_Server("Invalid length in %s: %u", "ICQ_SIGNON_AUTH_KEY", wKeyLen); + icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid key length.")); + SetCurrentStatus(ID_STATUS_OFFLINE); + return; + } + + unpackString(&buf, szKey, wKeyLen); + + mir_md5_init(&state); + mir_md5_append(&state, info->szAuthKey, info->wAuthKeyLen); + mir_md5_finish(&state, digest); + + mir_md5_init(&state); + mir_md5_append(&state, (LPBYTE)szKey, wKeyLen); + mir_md5_append(&state, digest, 16); + mir_md5_append(&state, (LPBYTE)CLIENT_MD5_STRING, sizeof(CLIENT_MD5_STRING)-1); + mir_md5_finish(&state, digest); + +#ifdef _DEBUG + NetLog_Server("Sending ICQ_SIGNON_LOGIN_REQUEST to login server"); +#endif + sendClientAuth((char*)digest, 0x10, TRUE); +} diff --git a/protocols/IcqOscarJ/src/families.h b/protocols/IcqOscarJ/src/families.h new file mode 100644 index 0000000000..61ac38f17a --- /dev/null +++ b/protocols/IcqOscarJ/src/families.h @@ -0,0 +1,74 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Declaration for handlers of Channel 2 SNAC Families +// +// ----------------------------------------------------------------------------- +#ifndef __FAMILIES_H +#define __FAMILIES_H + + +struct message_ack_params +{ + BYTE bType; + DWORD dwUin; + DWORD dwMsgID1; + DWORD dwMsgID2; + directconnect *pDC; + WORD wCookie; + int msgType; + BYTE bFlags; +}; + +#define MAT_SERVER_ADVANCED 0 +#define MAT_DIRECT 1 + + +/* handleMessageTypes(): mMsgFlags constants */ +#define MTF_DIRECT 1 +#define MTF_PLUGIN 2 +#define MTF_STATUS_EXTENDED 4 + + +struct UserInfoRecordItem +{ + WORD wTLV; + int dbType; + char *szDbSetting; +}; + +/*---------* Functions *---------------*/ + +int getPluginTypeIdLen(int nTypeID); +void packPluginTypeId(icq_packet *packet, int nTypeID); + +#define BUL_ALLCONTACTS 0 +#define BUL_VISIBLE 1 +#define BUL_INVISIBLE 2 +#define BUL_TEMPVISIBLE 4 + + +#endif /* __FAMILIES_H */ diff --git a/protocols/IcqOscarJ/src/globals.h b/protocols/IcqOscarJ/src/globals.h new file mode 100644 index 0000000000..c0d8326689 --- /dev/null +++ b/protocols/IcqOscarJ/src/globals.h @@ -0,0 +1,57 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Contains global types & variables declarations. +// +// ----------------------------------------------------------------------------- + +#ifndef __GLOBALS_H +#define __GLOBALS_H + + +typedef char uid_str[MAX_PATH]; + +// from init.cpp +extern HINSTANCE hInst; +extern DWORD MIRANDA_VERSION; + +extern IcqIconHandle hStaticIcons[]; + +extern const int moodXStatus[]; + +// from fam_04message.cpp +struct icq_mode_messages +{ + char *szOnline; + char *szAway; + char *szNa; + char *szDnd; + char *szOccupied; + char *szFfc; +}; + + +#endif /* __GLOBALS_H */ diff --git a/protocols/IcqOscarJ/src/guids.h b/protocols/IcqOscarJ/src/guids.h new file mode 100644 index 0000000000..24073deec4 --- /dev/null +++ b/protocols/IcqOscarJ/src/guids.h @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Contains helper functions to handle oscar message GUIDs. +// +// ----------------------------------------------------------------------------- + +#ifndef __GUIDS_H +#define __GUIDS_H + + +typedef DWORD plugin_guid[4]; + +// Message Capability GUIDs +static const plugin_guid MCAP_SRV_RELAY_FMT = {MCAP_SRV_RELAY_FMT_s}; +static const plugin_guid MCAP_REVERSE_DC_REQ = {MCAP_REVERSE_DC_REQ_s}; +static const plugin_guid MCAP_FILE_TRANSFER = {MCAP_FILE_TRANSFER_s}; +static const plugin_guid MCAP_CONTACTS = {MCAP_CONTACTS_s}; + +// Plugin GUIDs +static const plugin_guid PSIG_MESSAGE = {PSIG_MESSAGE_s}; +static const plugin_guid PSIG_INFO_PLUGIN = {PSIG_INFO_PLUGIN_s}; +static const plugin_guid PSIG_STATUS_PLUGIN = {PSIG_STATUS_PLUGIN_s}; + +// Plugin Message GUIDs +static const plugin_guid PMSG_QUERY_INFO = {PMSG_QUERY_INFO_s}; +static const plugin_guid PMSG_QUERY_STATUS = {PMSG_QUERY_STATUS_s}; + +// Message GUIDs +static const plugin_guid MGTYPE_MESSAGE = {MGTYPE_MESSAGE_s}; +static const plugin_guid MGTYPE_STATUSMSGEXT = {MGTYPE_STATUSMSGEXT_s}; +static const plugin_guid MGTYPE_FILE = {MGTYPE_FILE_s}; +static const plugin_guid MGTYPE_WEBURL = {MGTYPE_WEBURL_s}; +static const plugin_guid MGTYPE_CONTACTS = {MGTYPE_CONTACTS_s}; +static const plugin_guid MGTYPE_GREETING_CARD = {MGTYPE_GREETING_CARD_s}; +static const plugin_guid MGTYPE_CHAT = {MGTYPE_CHAT_s}; +static const plugin_guid MGTYPE_SMS_MESSAGE = {MGTYPE_SMS_MESSAGE_s}; +static const plugin_guid MGTYPE_XTRAZ_SCRIPT = {MGTYPE_XTRAZ_SCRIPT_s}; + + +// make GUID checks easy +static BOOL CompareGUIDs(DWORD q1,DWORD q2,DWORD q3,DWORD q4, const plugin_guid guid) +{ + return ((q1 == guid[0]) && (q2 == guid[1]) && (q3 == guid[2]) && (q4 == guid[3]))?TRUE:FALSE; +} + + +// pack entire GUID into icq packet +static __inline void packGUID(icq_packet *packet, const plugin_guid guid) +{ + packDWord(packet, guid[0]); + packDWord(packet, guid[1]); + packDWord(packet, guid[2]); + packDWord(packet, guid[3]); +} + + +#endif /* __GUIDS_H */ diff --git a/protocols/IcqOscarJ/src/i18n.cpp b/protocols/IcqOscarJ/src/i18n.cpp new file mode 100644 index 0000000000..535feebcdf --- /dev/null +++ b/protocols/IcqOscarJ/src/i18n.cpp @@ -0,0 +1,541 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Contains helper functions to convert text messages between different +// character sets. +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static BOOL bHasCP_UTF8 = FALSE; + + +void InitI18N(void) +{ + CPINFO CPInfo; + + + bHasCP_UTF8 = GetCPInfo(CP_UTF8, &CPInfo); +} + + + +// Returns true if the buffer only contains 7-bit characters. +BOOL __stdcall IsUSASCII(const char *pBuffer, int nSize) +{ + for (int nIndex = 0; nIndex < nSize; nIndex++) + if (BYTE(pBuffer[nIndex]) > 0x7F) + return FALSE; + + return TRUE; +} + +// Returns true if the unicode buffer only contains 7-bit characters. +BOOL __stdcall IsUnicodeAscii(const WCHAR *pBuffer, int nSize) +{ + for (int nIndex = 0; nIndex < nSize; nIndex++) + if (WORD(pBuffer[nIndex]) > 0x7F) + return FALSE; + + return TRUE; +} + + +// Scans a string encoded in UTF-8 to verify that it contains +// only valid sequences. It will return 1 if the string contains +// only legitimate encoding sequences; otherwise it will return 0; +// From 'Secure Programming Cookbook', John Viega & Matt Messier, 2003 +int __stdcall UTF8_IsValid(const char *pszInput) +{ + int nb; + if (!pszInput) + return 0; + + for ( BYTE* c = ( BYTE*)pszInput; *c; c += (nb + 1)) + { + if (!(*c & 0x80)) + nb = 0; + else if ((*c & 0xc0) == 0x80) return 0; + else if ((*c & 0xe0) == 0xc0) nb = 1; + else if ((*c & 0xf0) == 0xe0) nb = 2; + else if ((*c & 0xf8) == 0xf0) nb = 3; + else if ((*c & 0xfc) == 0xf8) nb = 4; + else if ((*c & 0xfe) == 0xfc) nb = 5; + else nb = 0; + + for (int i = 1; i<=nb; i++) // we this forward, do not cross end of string + if ((*(c + i) & 0xc0) != 0x80) + return 0; + } + + return 1; +} + + +int __stdcall get_utf8_size(const WCHAR *unicode) +{ + int size = 0; + int index = 0; + /* calculate the size of the utf-8 string */ + WCHAR c = unicode[index++]; + while (c) + { + if (c < 0x0080) + size += 1; + else if (c < 0x0800) + size += 2; + else + size += 3; + c = unicode[index++]; + } + return size; +} + + +// returns ansi string in all cases +char* __stdcall detect_decode_utf8(const char *from) +{ + char *temp = NULL; + + if (IsUSASCII(from, strlennull(from)) || !UTF8_IsValid(from) || !utf8_decode(from, &temp)) return (char*)from; + SAFE_FREE((void**)&from); + + return temp; +} + + +/* +* The following UTF8 routines are +* +* Copyright (C) 2001 Peter Harris +* Copyright (C) 2001 Edmund Grimley Evans +* +* under a GPL license +* +* -------------------------------------------------------------- +* Convert a string between UTF-8 and the locale's charset. +* Invalid bytes are replaced by '#', and characters that are +* not available in the target encoding are replaced by '?'. +* +* If the locale's charset is not set explicitly then it is +* obtained using nl_langinfo(CODESET), where available, the +* environment variable CHARSET, or assumed to be US-ASCII. +* +* Return value of conversion functions: +* +* -1 : memory allocation failed +* 0 : data was converted exactly +* 1 : valid data was converted approximately (using '?') +* 2 : input was invalid (but still converted, using '#') +* 3 : unknown encoding (but still converted, using '?') +*/ + + + +/* +* Convert a string between UTF-8 and the locale's charset. +*/ +char* __stdcall make_utf8_string_static(const WCHAR *unicode, char *utf8, size_t utf_size) +{ + int index = 0; + unsigned int out_index = 0; + unsigned short c; + + c = unicode[index++]; + while (c) + { + if (c < 0x080) + { + if (out_index + 1 >= utf_size) break; + utf8[out_index++] = (unsigned char)c; + } + else if (c < 0x800) + { + if (out_index + 2 >= utf_size) break; + utf8[out_index++] = 0xc0 | (c >> 6); + utf8[out_index++] = 0x80 | (c & 0x3f); + } + else + { + if (out_index + 3 >= utf_size) break; + utf8[out_index++] = 0xe0 | (c >> 12); + utf8[out_index++] = 0x80 | ((c >> 6) & 0x3f); + utf8[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + utf8[out_index] = 0x00; + + return utf8; +} + + +char* __stdcall make_utf8_string(const WCHAR *unicode) +{ + if (!unicode) return NULL; + + /* first calculate the size of the target string */ + size_t size = get_utf8_size(unicode); + + char *out = (char*)SAFE_MALLOC(size + 1); + if (!out) + return NULL; + + return make_utf8_string_static(unicode, out, size + 1); +} + + +WCHAR* __stdcall make_unicode_string_static(const char *utf8, WCHAR *unicode, size_t unicode_size) +{ + unsigned int out_index = 0; + + if (utf8) + { + unsigned int index = 0; + unsigned char c = utf8[index++]; + + while (c) + { + if (out_index + 1 >= unicode_size) break; + if ((c & 0x80) == 0) + { + unicode[out_index++] = c; + } + else if ((c & 0xe0) == 0xe0) + { + unicode[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + unicode[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + unicode[out_index++] |= (c & 0x3F); + } + else + { + unicode[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + unicode[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + } + unicode[out_index] = 0; + + return unicode; +} + + +WCHAR* __stdcall make_unicode_string(const char *utf8) +{ + int size = 0, index = 0; + + if (!utf8) return NULL; + + /* first calculate the size of the target string */ + unsigned char c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + index += 0; + } + else if ((c & 0xe0) == 0xe0) + { + index += 2; + } + else + { + index += 1; + } + size += 1; + c = utf8[index++]; + } + + WCHAR *out = (WCHAR*)SAFE_MALLOC((size + 1) * sizeof(WCHAR)); + if (!out) + return NULL; + else + return make_unicode_string_static(utf8, out, size + 1); +} + + +int __stdcall utf8_encode(const char *from, char **to) +{ + int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlennull(from), NULL, 0); + + if (wchars == 0) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return -1; + } + + WCHAR *unicode = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); + ZeroMemory(unicode, (wchars + 1) * sizeof(WCHAR)); + + int err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlennull(from), unicode, wchars); + if (err != wchars) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return -1; + } + + /* On NT-based windows systems, we could use WideCharToMultiByte(), but + * MS doesn't actually have a consistent API across win32. + */ + *to = make_utf8_string(unicode); + return 0; +} + + +char* __stdcall ansi_to_utf8(const char *ansi) +{ + char *szUtf = NULL; + + if (strlennull(ansi)) + { + utf8_encode(ansi, &szUtf); + return szUtf; + } + + return null_strdup(""); +} + + +char* __stdcall ansi_to_utf8_codepage(const char *ansi, WORD wCp) +{ + int wchars = strlennull(ansi); + WCHAR *unicode = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); + ZeroMemory(unicode, (wchars + 1) * sizeof(WCHAR)); + + MultiByteToWideChar(wCp, MB_PRECOMPOSED, ansi, wchars, unicode, wchars); + + return make_utf8_string(unicode); +} + + +// Returns 0 on error, 1 on success +int __stdcall utf8_decode_codepage(const char *from, char **to, WORD wCp) +{ + int nResult = 0; + + _ASSERTE(!(*to)); // You passed a non-zero pointer, make sure it doesnt point to unfreed memory + + // Validate the string + if (!UTF8_IsValid(from)) + return 0; + + // Use the native conversion routines when available + if (bHasCP_UTF8) + { + int inlen = strlennull(from) + 1; + WCHAR *wszTemp = (WCHAR *)_alloca(inlen * sizeof(WCHAR)); + ZeroMemory(wszTemp, inlen * sizeof(WCHAR)); + + // Convert the UTF-8 string to UCS + if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen)) + { + // Convert the UCS string to local ANSI codepage + *to = (char*)SAFE_MALLOC(inlen); + if (WideCharToMultiByte(wCp, 0, wszTemp, -1, *to, inlen, NULL, NULL)) + { + nResult = 1; + } + else + { + SAFE_FREE(to); + } + } + } + else + { + int chars = strlennull(from) + 1; + WCHAR *unicode = (WCHAR*)_alloca(chars * sizeof(WCHAR)); + make_unicode_string_static(from, unicode, chars); + + chars = WideCharToMultiByte(wCp, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); + + if (chars == 0) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return 0; + } + + *to = (char*)SAFE_MALLOC((chars + 1)*sizeof(char)); + if (*to == NULL) + { +#ifdef _DEBUG + fprintf(stderr, "Out of memory processing string to local charset\n"); +#endif + return 0; + } + + int err = WideCharToMultiByte(wCp, WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL); + if (err != chars) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + SAFE_FREE(to); + return 0; + } + + nResult = 1; + } + + return nResult; +} + + +// Standard version with current codepage +int __stdcall utf8_decode(const char *from, char **to) +{ + return utf8_decode_codepage(from, to, CP_ACP); +} + + +// Returns 0 on error, 1 on success +int __stdcall utf8_decode_static(const char *from, char *to, int to_size) +{ + int nResult = 0; + + _ASSERTE(to); // You passed a zero pointer + + // Validate the string + if (!UTF8_IsValid(from)) + return 0; + + // Clear target + ZeroMemory(to, to_size); + + // Use the native conversion routines when available + if (bHasCP_UTF8) + { + int inlen = strlennull(from) + 1; + WCHAR *wszTemp = (WCHAR*)_alloca(inlen * sizeof(WCHAR)); + ZeroMemory(wszTemp, inlen * sizeof(WCHAR)); + + // Convert the UTF-8 string to UCS + if (MultiByteToWideChar(CP_UTF8, 0, from, -1, wszTemp, inlen)) + { + // Convert the UCS string to local ANSI codepage + if (WideCharToMultiByte(CP_ACP, 0, wszTemp, -1, to, to_size, NULL, NULL)) + { + nResult = 1; + } + } + } + else + { + size_t chars = strlennull(from) + 1; + WCHAR *unicode = (WCHAR*)_alloca(chars * sizeof(WCHAR)); + + make_unicode_string_static(from, unicode, chars); + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, to, to_size, NULL, NULL); + + nResult = 1; + } + + return nResult; +} + + +WCHAR* __stdcall ansi_to_unicode(const char *ansi) +{ + int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ansi, strlennull(ansi), NULL, 0); + + if (wchars == 0) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return NULL; + } + + WCHAR *unicode = (WCHAR*)SAFE_MALLOC((wchars + 1) * sizeof(WCHAR)); + + int err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ansi, strlennull(ansi), unicode, wchars); + if (err != wchars) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + SAFE_FREE(&unicode); + return NULL; + } + return unicode; +} + + +char* __stdcall unicode_to_ansi_static(const WCHAR *unicode, char *ansi, int ansi_size) +{ + ZeroMemory(ansi, ansi_size); + + if (WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), ansi, ansi_size, NULL, NULL) > 1) + return ansi; + + return NULL; +} + + +char* __stdcall unicode_to_ansi(const WCHAR *unicode) +{ + int chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), NULL, 0, NULL, NULL); + + if (chars == 0) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return NULL; + } + + char* ansi = (char*)SAFE_MALLOC((chars + 1)*sizeof(char)); + if (ansi == NULL) + { +#ifdef _DEBUG + fprintf(stderr, "Out of memory processing string to local charset\n"); +#endif + return NULL; + } + + int err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, strlennull(unicode), ansi, chars, NULL, NULL); + if (err != chars) + { +#ifdef _DEBUG + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); +#endif + return NULL; + } + + return ansi; +} diff --git a/protocols/IcqOscarJ/src/i18n.h b/protocols/IcqOscarJ/src/i18n.h new file mode 100644 index 0000000000..eaeaad54f3 --- /dev/null +++ b/protocols/IcqOscarJ/src/i18n.h @@ -0,0 +1,70 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Helper functions to convert text messages between different character sets. +// +// ----------------------------------------------------------------------------- + +#ifndef __I18N_H +#define __I18N_H + + +BOOL __stdcall IsUSASCII(const char *pBuffer, int nSize); +BOOL __stdcall IsUnicodeAscii(const WCHAR *pBuffer, int nSize); +int __stdcall UTF8_IsValid(const char *pszInput); + +int __stdcall get_utf8_size(const WCHAR *unicode); + +char* __stdcall detect_decode_utf8(const char *from); + +WCHAR* __stdcall make_unicode_string(const char *utf8); +WCHAR* __stdcall make_unicode_string_static(const char *utf8, WCHAR *unicode, size_t unicode_size); + +char* __stdcall make_utf8_string(const WCHAR *unicode); +char* __stdcall make_utf8_string_static(const WCHAR *unicode, char *utf8, size_t utf_size); + +char* __stdcall ansi_to_utf8(const char *ansi); +char* __stdcall ansi_to_utf8_codepage(const char *ansi, WORD wCp); + +WCHAR* __stdcall ansi_to_unicode(const char *ansi); +char* __stdcall unicode_to_ansi(const WCHAR *unicode); +char* __stdcall unicode_to_ansi_static(const WCHAR *unicode, char *ansi, int ansi_size); + +int __stdcall utf8_encode(const char *from, char **to); +int __stdcall utf8_decode(const char *from, char **to); +int __stdcall utf8_decode_codepage(const char *from, char **to, WORD wCp); +int __stdcall utf8_decode_static(const char *from, char *to, int to_size); + +#define tchar_to_utf8 make_utf8_string +#define utf8_to_tchar_static make_unicode_string_static +#define utf8_to_tchar make_unicode_string +#define ansi_to_tchar ansi_to_unicode +#define tchar_to_ansi unicode_to_ansi + +void InitI18N(void); + + +#endif /* __I18N_H */ diff --git a/protocols/IcqOscarJ/src/iconlib.cpp b/protocols/IcqOscarJ/src/iconlib.cpp new file mode 100644 index 0000000000..7c93bae17a --- /dev/null +++ b/protocols/IcqOscarJ/src/iconlib.cpp @@ -0,0 +1,92 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Support for IcoLib plug-in +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" +#include "m_icolib.h" + +IcqIconHandle IconLibDefine(const char *desc, const char *section, const char *module, const char *ident, const TCHAR *def_file, int def_idx) +{ + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(sid); + sid.pwszSection = make_unicode_string(section); + sid.pwszDescription = make_unicode_string(desc); + sid.flags = SIDF_ALL_TCHAR; + + char szName[MAX_PATH + 128]; + null_snprintf(szName, sizeof(szName), "%s_%s", module ? module : ICQ_PROTOCOL_NAME, ident); + sid.pszName = szName; + sid.ptszDefaultFile = (TCHAR*)def_file; + sid.iDefaultIndex = def_idx; + + IcqIconHandle hIcon = (IcqIconHandle)SAFE_MALLOC(sizeof(IcqIconHandle_s)); + hIcon->szName = null_strdup(sid.pszName); + hIcon->hIcoLib = Skin_AddIcon(&sid); + + SAFE_FREE(&sid.pwszSection); + SAFE_FREE(&sid.pwszDescription); + + return hIcon; +} + + +void IconLibRemove(IcqIconHandle *phIcon) +{ + if (phIcon && *phIcon) + { + IcqIconHandle hIcon = *phIcon; + + CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)hIcon->szName); + SAFE_FREE(&hIcon->szName); + SAFE_FREE((void**)phIcon); + } +} + + +HANDLE IcqIconHandle_s::Handle() +{ + if (this) + return hIcoLib; + + return NULL; +} + + +HICON IcqIconHandle_s::GetIcon(bool big) +{ + if (this) + return (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)hIcoLib); + + return NULL; +} + +void IcqIconHandle_s::ReleaseIcon(bool big) +{ + CallService(big ? MS_SKIN2_RELEASEICONBIG : MS_SKIN2_RELEASEICON, 0, (LPARAM)szName); +} + diff --git a/protocols/IcqOscarJ/src/iconlib.h b/protocols/IcqOscarJ/src/iconlib.h new file mode 100644 index 0000000000..3a7482f872 --- /dev/null +++ b/protocols/IcqOscarJ/src/iconlib.h @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Headers for IconLib Plugin / module support +// +// ----------------------------------------------------------------------------- +#ifndef __ICONLIB_H +#define __ICONLIB_H + + +struct IcqIconHandle_s +{ + char *szName; + HANDLE hIcoLib; + + HANDLE Handle(); + HICON GetIcon(bool big = false); + void ReleaseIcon(bool big = false); +}; + +typedef IcqIconHandle_s *IcqIconHandle; + + +IcqIconHandle IconLibDefine(const char *desc, const char *section, const char *module, const char *ident, const TCHAR *def_file, int def_idx); +void IconLibRemove(IcqIconHandle *phIcon); + + + +#endif /* __ICONLIB_H */ diff --git a/protocols/IcqOscarJ/src/icq_advsearch.cpp b/protocols/IcqOscarJ/src/icq_advsearch.cpp new file mode 100644 index 0000000000..6c3a3ffa89 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_advsearch.cpp @@ -0,0 +1,185 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +static void InitComboBox(HWND hwndCombo, const FieldNamesItem *names) +{ + int iItem; + int i; + + iItem = ComboBoxAddStringUtf(hwndCombo, NULL, 0); + SendMessage(hwndCombo, CB_SETCURSEL, iItem, 0); + + if (names){ + for (i = 0; names[i].text; i++) { + iItem = ComboBoxAddStringUtf(hwndCombo, names[i].text, names[i].code); + } + } + else { + int ctryCount; + struct CountryListEntry *countries; + CallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM )&ctryCount, ( LPARAM )&countries ); + for (i = 0; i < ctryCount; i++) { + if (countries[i].id != 0xFFFF && countries[i].id != 0) + iItem = ComboBoxAddStringUtf(hwndCombo, LPGEN(countries[i].szName), countries[i].id); + } + } +} + +INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + InitComboBox(GetDlgItem(hwndDlg, IDC_GENDER), genderField); + InitComboBox(GetDlgItem(hwndDlg, IDC_AGERANGE), agesField); + InitComboBox(GetDlgItem(hwndDlg, IDC_MARITALSTATUS), maritalField); + InitComboBox(GetDlgItem(hwndDlg, IDC_WORKFIELD), occupationField); + InitComboBox(GetDlgItem(hwndDlg, IDC_ORGANISATION), affiliationField); + InitComboBox(GetDlgItem(hwndDlg, IDC_LANGUAGE), languageField); + InitComboBox(GetDlgItem(hwndDlg, IDC_COUNTRY), countryField); + InitComboBox(GetDlgItem(hwndDlg, IDC_INTERESTSCAT), interestsField); + InitComboBox(GetDlgItem(hwndDlg, IDC_PASTCAT), pastField); + + return TRUE; + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + + case IDOK: + SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(GetParent(hwndDlg), IDOK)); + break; + + case IDCANCEL: + // CheckDlgButton(GetParent(hwndDlg),IDC_ADVANCED,BST_UNCHECKED); + // SendMessage(GetParent(hwndDlg),WM_COMMAND,MAKEWPARAM(IDC_ADVANCED,BN_CLICKED),(LPARAM)GetDlgItem(GetParent(hwndDlg),IDC_ADVANCED)); + break; + + default: + break; + + } + break; + } + + default: + break; + } + + return FALSE; +} + +static DWORD getCurItemData(HWND hwndDlg, UINT iCtrl) +{ + return SendDlgItemMessage(hwndDlg, iCtrl, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, iCtrl, CB_GETCURSEL, 0, 0), 0); +} + +static void searchPackTLVLNTS(PBYTE *buf, int *buflen, HWND hwndDlg, UINT idControl, WORD wType) +{ + char str[512]; + + GetDlgItemTextA(hwndDlg, idControl, str, sizeof(str)); + + ppackLETLVLNTS(buf, buflen, str, wType, 0); +} + +static void searchPackTLVWordLNTS(PBYTE *buf, int *buflen, HWND hwndDlg, UINT idControl, WORD w, WORD wType) +{ + char str[512]; + + GetDlgItemTextA(hwndDlg, idControl, str, sizeof(str)); + + ppackLETLVWordLNTS(buf, buflen, w, str, wType, 0); +} + +static PBYTE createAdvancedSearchStructureTLV(HWND hwndDlg, int *length) +{ + PBYTE buf = NULL; + int buflen = 0; + + ppackLEWord(&buf, &buflen, META_SEARCH_GENERIC); /* subtype: full search */ + + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_FIRSTNAME, TLV_FIRSTNAME); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_LASTNAME, TLV_LASTNAME); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_NICK, TLV_NICKNAME); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_EMAIL, TLV_EMAIL); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_CITY, TLV_CITY); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_STATE, TLV_STATE); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_COMPANY, TLV_COMPANY); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_DEPARTMENT, TLV_DEPARTMENT); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_POSITION, TLV_POSITION); + searchPackTLVLNTS(&buf, &buflen, hwndDlg, IDC_KEYWORDS, TLV_KEYWORDS); + + ppackLETLVDWord(&buf, &buflen, (DWORD)getCurItemData(hwndDlg, IDC_AGERANGE), TLV_AGERANGE, 0); + + BYTE b = (BYTE)getCurItemData(hwndDlg, IDC_GENDER); + switch (b) { + case 'F': b = 1; break; + case 'M': b = 2; break; + default: b = 0; + }; + ppackLETLVByte(&buf, &buflen, b, TLV_GENDER, 0); + ppackLETLVByte(&buf, &buflen, (BYTE)getCurItemData(hwndDlg, IDC_MARITALSTATUS), TLV_MARITAL, 0); + ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_LANGUAGE), TLV_LANGUAGE, 0); + ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_COUNTRY), TLV_COUNTRY, 0); + ppackLETLVWord(&buf, &buflen, (WORD)getCurItemData(hwndDlg, IDC_WORKFIELD), TLV_OCUPATION, 0); + + WORD w = (WORD)getCurItemData(hwndDlg, IDC_PASTCAT); + searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_PASTKEY, w, TLV_PASTINFO); + + w = (WORD)getCurItemData(hwndDlg, IDC_INTERESTSCAT); + searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_INTERESTSKEY, w, TLV_INTERESTS); + + w = (WORD)getCurItemData(hwndDlg, IDC_ORGANISATION); + searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_ORGKEYWORDS, w, TLV_AFFILATIONS); + + w = (WORD)getCurItemData(hwndDlg, IDC_HOMEPAGECAT); + if (w != 0xFFFF) + searchPackTLVWordLNTS(&buf, &buflen, hwndDlg, IDC_HOMEPAGEKEY, w, TLV_HOMEPAGE); + + if (IsDlgButtonChecked(hwndDlg, IDC_ONLINEONLY)) + ppackLETLVByte(&buf, &buflen, 1, TLV_ONLINEONLY, 1); + + if (length) + *length = buflen; + + return buf; +} + +PBYTE createAdvancedSearchStructure(HWND hwndDlg, int *length) +{ + if (!hwndDlg) + return NULL; + + return createAdvancedSearchStructureTLV(hwndDlg, length); +} diff --git a/protocols/IcqOscarJ/src/icq_advsearch.h b/protocols/IcqOscarJ/src/icq_advsearch.h new file mode 100644 index 0000000000..83bf35af93 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_advsearch.h @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- + + +INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam); +PBYTE createAdvancedSearchStructure(HWND hwndDlg,int *length); diff --git a/protocols/IcqOscarJ/src/icq_avatar.cpp b/protocols/IcqOscarJ/src/icq_avatar.cpp new file mode 100644 index 0000000000..6e61f2bc0d --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_avatar.cpp @@ -0,0 +1,1814 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Manages Avatar connection, provides internal service for handling avatars +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" +#include "m_folders.h" + + +BYTE hashEmptyAvatar[9] = {0x00, 0x01, 0x00, 0x05, 0x02, 0x01, 0xD2, 0x04, 0x72}; + + +avatars_request::avatars_request(int type) +{ + this->type = type; +} + + +avatars_request::~avatars_request() +{ + if (this) + { + switch (type) + { + case ART_UPLOAD: + SAFE_FREE((void**)&pData); + break; + case ART_GET: + SAFE_FREE((void**)&hash); + SAFE_FREE(&szFile); + break; + case ART_BLOCK: + break; + } + } +} + + +avatars_request* CIcqProto::ReleaseAvatarRequestInQueue(avatars_request *request) +{ + avatars_request *pNext = request->pNext; + + avatars_request **par = &m_avatarsQueue; + avatars_request *ar = m_avatarsQueue; + + while (ar) + { + if (ar == request) + { // found it, remove + *par = ar->pNext; + break; + } + par = &ar->pNext; + ar = ar->pNext; + } + + delete request; + return pNext; +} + + +void CIcqProto::InitAvatars() +{ + if (!bAvatarsFolderInited) + { // do it only once + bAvatarsFolderInited = TRUE; + + if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) + { // check if it does make sense + TCHAR tszPath[MAX_PATH * 2]; + null_snprintf(tszPath, MAX_PATH * 2, _T("%%miranda_avatarcache%%\\") _T(TCHAR_STR_PARAM) _T("\\"), m_szModuleName); + + hAvatarsFolder = FoldersRegisterCustomPathT(m_szModuleName, "Avatars Cache", tszPath); + } + } +} + + +TCHAR* CIcqProto::GetOwnAvatarFileName() +{ + DBVARIANT dbvFile = {DBVT_DELETED}; + + if (!getSettingStringT(NULL, "AvatarFile", &dbvFile)) + { + TCHAR tmp[MAX_PATH * 2]; + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)dbvFile.ptszVal, (LPARAM)tmp); + ICQFreeVariant(&dbvFile); + + return null_strdup(tmp); + } + return NULL; +} + + +void CIcqProto::GetFullAvatarFileName(int dwUin, const char *szUid, int dwFormat, TCHAR *pszDest, int cbLen) +{ + GetAvatarFileName(dwUin, szUid, pszDest, cbLen); + AddAvatarExt(dwFormat, pszDest); +} + + +void CIcqProto::GetAvatarFileName(int dwUin, const char *szUid, TCHAR *pszDest, int cbLen) +{ + TCHAR szPath[MAX_PATH * 2]; + FOLDERSGETDATA fgd = {0}; + + InitAvatars(); + + fgd.cbSize = sizeof(FOLDERSGETDATA); + fgd.nMaxPathSize = MAX_PATH * 2; + fgd.szPathT = szPath; + fgd.flags = FF_TCHAR; + if (CallService(MS_FOLDERS_GET_PATH, (WPARAM)hAvatarsFolder, (LPARAM)&fgd)) + { + TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_avatarcache%")); + null_snprintf(szPath, MAX_PATH * 2, _T("%s\\") _T(TCHAR_STR_PARAM) _T("\\"), tmpPath, m_szModuleName); + mir_free(tmpPath); + } + else + _tcscat(szPath, _T("\\")); + + // fill the destination + lstrcpyn(pszDest, szPath, cbLen - 1); + int tPathLen = strlennull(pszDest); + + // make sure the avatar cache directory exists + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)szPath); + + if (dwUin != 0) + { + _ltot(dwUin, pszDest + tPathLen, 10); + } + else if (szUid) + { + TCHAR* p = mir_a2t(szUid); + _tcscpy(pszDest + tPathLen, p); + mir_free( p ); + } + else + { + TCHAR szBuf[MAX_PATH]; + + if (CallService(MS_DB_GETPROFILENAMET, MAX_PATH, (LPARAM)szBuf)) + _tcscpy(pszDest + tPathLen, _T("avatar")); + else + { + TCHAR *szLastDot = _tcsrchr(szBuf, '.'); + if (szLastDot) szLastDot[0] = '\0'; + + _tcscpy(pszDest + tPathLen, szBuf); + _tcscat(pszDest + tPathLen, _T("_avt")); + } + } +} + + +void AddAvatarExt(int dwFormat, TCHAR *pszDest) +{ + if (dwFormat == PA_FORMAT_JPEG) + _tcscat(pszDest, _T(".jpg")); + else if (dwFormat == PA_FORMAT_GIF) + _tcscat(pszDest, _T(".gif")); + else if (dwFormat == PA_FORMAT_PNG) + _tcscat(pszDest, _T(".png")); + else if (dwFormat == PA_FORMAT_BMP) + _tcscat(pszDest, _T(".bmp")); + else if (dwFormat == PA_FORMAT_XML) + _tcscat(pszDest, _T(".xml")); + else if (dwFormat == PA_FORMAT_SWF) + _tcscat(pszDest, _T(".swf")); + else + _tcscat(pszDest, _T(".dat")); +} + + +int DetectAvatarFormatBuffer(const char *pBuffer) +{ + if (!strncmp(pBuffer, "%PNG", 4)) + return PA_FORMAT_PNG; + + if (!strncmp(pBuffer, "GIF8", 4)) + return PA_FORMAT_GIF; + + if (!_strnicmp(pBuffer, "isPending()) + { + NetLog_Server("Avatar, Multiple start thread attempt, ignored."); + SAFE_FREE((void**)&cookie); + return; + } + NetLog_Server("Avatars: Connection failed"); + + m_avatarsConnectionPending = FALSE; + + { // check if any upload request are waiting in the queue + avatars_request *ar = m_avatarsQueue; + int bYet = 0; + + while (ar) + { + if (ar->type == ART_UPLOAD) + { // we found it, return error + if (!bYet) + { + icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server temporarily unavailable.")); + bYet = 1; + } + // remove upload request from queue + ar = ReleaseAvatarRequestInQueue(ar); + continue; + } + ar = ar->pNext; + } + } + SAFE_FREE((void**)&cookie); + + return; + } + + icq_lock l(m_avatarsMutex); + + if (m_avatarsConnection && m_avatarsConnection->isPending()) + { + NetLog_Server("Avatar, Multiple start thread attempt, ignored."); + + NetLib_CloseConnection(&hConn, FALSE); + + SAFE_FREE((void**)&cookie); + + return; + } + else if (m_avatarsConnection) + m_avatarsConnection->closeConnection(); + + m_avatarsConnection = new avatars_server_connection(this, hConn, cookie, cookieLen); // the old connection should not be used anymore + + // connection object created, remove the connection request pending flag + m_avatarsConnectionPending = FALSE; +} + + +void CIcqProto::StopAvatarThread() +{ + icq_lock l(m_avatarsMutex); // the connection is about to close + + if (m_avatarsConnection) + { + m_avatarsConnection->shutdownConnection(); // make the thread stop + } + + return; +} + + +#ifdef _DEBUG +static void NetLog_Hash(CIcqProto *ppro, const char *pszIdent, const BYTE *pHash, int nHashLen) +{ + if (nHashLen == 0x14) + ppro->NetLog_Server("Avatars: %s hash: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", pszIdent, pHash[0], pHash[1], pHash[2], pHash[3], pHash[4], pHash[5], pHash[6], pHash[7], pHash[8], pHash[9], pHash[10], pHash[11], pHash[12], pHash[13], pHash[14], pHash[15], pHash[16], pHash[17], pHash[18], pHash[19]); + else if (nHashLen == 0x09) + ppro->NetLog_Server("Avatars: %s hash: %02X%02X%02X%02X%02X%02X%02X%02X%02X", pszIdent, pHash[0], pHash[1], pHash[2], pHash[3], pHash[4], pHash[5], pHash[6], pHash[7], pHash[8]); + else + ppro->NetLog_Server("Avatars: %s hash: Unknown hash format.", pszIdent); +} +#endif + + +// handle Owner's avatar hash changes +void CIcqProto::handleAvatarOwnerHash(WORD wItemID, BYTE bFlags, BYTE *pData, BYTE nDataLen) +{ + if ((nDataLen >= 0x14) && m_bAvatarsEnabled) + { + switch (bFlags) + { + case 1: // our avatar is on the server + { + setSettingBlob(NULL, "AvatarHash", pData, 0x14); /// TODO: properly handle multiple avatar items (more formats) + + setUserInfo(); + // here we need to find a file, check its hash, if invalid get avatar from server + TCHAR *file = GetOwnAvatarFileName(); + if (!file) + { // we have no avatar file, download from server + TCHAR szFile[MAX_PATH * 2 + 4]; +#ifdef _DEBUG + NetLog_Server("We have no avatar, requesting from server."); +#endif + GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2); + GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile); + } + else + { // we know avatar filename + BYTE *hash = calcMD5HashOfFile(file); + + if (!hash) + { // hash could not be calculated - probably missing file, get avatar from server + TCHAR szFile[MAX_PATH * 2 + 4]; +#ifdef _DEBUG + NetLog_Server("We have no avatar, requesting from server."); +#endif + GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2); + GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile); + } // check if we had set any avatar if yes set our, if not download from server + else if (memcmp(hash, pData + 4, 0x10)) + { // we have different avatar, sync that + if (m_bSsiEnabled && getSettingByte(NULL, "ForceOurAvatar", 1)) + { // we want our avatar, update hash + DWORD dwPaFormat = DetectAvatarFormat(file); + BYTE *pHash = (BYTE*)_alloca(0x14); + + NetLog_Server("Our avatar is different, setting our new hash."); + + pHash[0] = 0; + pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; + pHash[2] = 1; // state of the hash + pHash[3] = 0x10; // len of the hash + memcpy(pHash + 4, hash, 0x10); + updateServAvatarHash(pHash, 0x14); + } + else + { // get avatar from server + TCHAR tszFile[MAX_PATH * 2 + 4]; +#ifdef _DEBUG + NetLog_Server("We have different avatar, requesting new from server."); +#endif + GetAvatarFileName(0, NULL, tszFile, MAX_PATH * 2); + GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, tszFile); + } + } + SAFE_FREE((void**)&hash); + SAFE_FREE(&file); + } + break; + } + case 0x41: // request to upload avatar data + case 0x81: + { // request to re-upload avatar data + if (!m_bSsiEnabled) break; // we could not change serv-list if it is disabled... + + TCHAR *file = GetOwnAvatarFileName(); + if (!file) + { // we have no file to upload, remove hash from server + NetLog_Server("We do not have avatar, removing hash."); + SetMyAvatar(0, 0); + break; + } + DWORD dwPaFormat = DetectAvatarFormat(file); + BYTE *hash = calcMD5HashOfFile(file); + + if (!hash) + { // the hash could not be calculated, remove from server + NetLog_Server("We could not obtain hash, removing hash."); + SetMyAvatar(0, 0); + } + else if (!memcmp(hash, pData + 4, 0x10)) + { // we have the right file + HANDLE hFile = NULL, hMap = NULL; + BYTE *ppMap = NULL; + long cbFileSize = 0; + + NetLog_Server("Uploading our avatar data."); + + if ((hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE) + if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) + if ((ppMap = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) + cbFileSize = GetFileSize(hFile, NULL); + + if (cbFileSize != 0) + { + SetAvatarData(NULL, (WORD)(dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC), ppMap, cbFileSize); + } + + if (ppMap != NULL) UnmapViewOfFile(ppMap); + if (hMap != NULL) CloseHandle(hMap); + if (hFile != NULL) CloseHandle(hFile); + SAFE_FREE((void**)&hash); + } + else + { + BYTE *pHash = (BYTE*)_alloca(0x14); + + NetLog_Server("Our file is different, set our new hash."); + + pHash[0] = 0; + pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; + pHash[2] = 1; // state of the hash + pHash[3] = 0x10; // len of the hash + memcpy(pHash + 4, hash, 0x10); + updateServAvatarHash(pHash, 0x14); + + SAFE_FREE((void**)&hash); + } + + SAFE_FREE(&file); + break; + } + default: + NetLog_Server("Received UNKNOWN Avatar Status."); + } + } +} + + +// handle Contact's avatar hash +void CIcqProto::handleAvatarContactHash(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *pHash, int nHashLen, WORD wOldStatus) +{ + int bJob = FALSE; + BOOL avatarInfoPresent = FALSE; + int avatarType = -1; + BYTE *pAvatarHash = NULL; + int cbAvatarHash; + BYTE emptyItem[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + if (!m_bAvatarsEnabled) return; // only if enabled + + if (nHashLen < 4) return; // nothing to work with + + while (nHashLen >= 4) + { // parse online message items one by one + WORD itemType = pHash[0] << 8 | pHash[1]; + BYTE itemLen = pHash[3]; + BYTE itemFlags = pHash[2]; + + // just some validity check + if (itemLen + 4 > nHashLen) + itemLen = nHashLen - 4; + + if (itemLen && memcmp(pHash + 4, emptyItem, itemLen > 0x10 ? 0x10 : itemLen)) + { // Item types + // 0000: AIM mini avatar + // 0001: AIM/ICQ avatar ID/hash (len 5 or 16 bytes) + // 0002: iChat online message + // 0008: ICQ Flash avatar hash (16 bytes) + // 0009: iTunes music store link + // 000C: ICQ contact photo (16 bytes) + // 000D: Last update time of online message + // 000E: Status mood + if (itemType == AVATAR_HASH_MINI && itemLen == 0x05 && avatarType == -1) + { // mini avatar + pAvatarHash = pHash; + cbAvatarHash = itemLen + 4; + avatarType = itemType; + } + else if (itemType == AVATAR_HASH_STATIC && (itemLen == 0x05 || itemLen == 0x10) && (avatarType == -1 || avatarType == AVATAR_HASH_MINI)) + { // normal avatar + pAvatarHash = pHash; + cbAvatarHash = itemLen + 4; + avatarType = itemType; + } + else if (itemType == AVATAR_HASH_FLASH && itemLen == 0x10 && (avatarType == -1 || avatarType == AVATAR_HASH_MINI || avatarType == AVATAR_HASH_STATIC)) + { // flash avatar + pAvatarHash = pHash; + cbAvatarHash = itemLen + 4; + avatarType = itemType; + } + else if (itemType == AVATAR_HASH_PHOTO && itemLen == 0x10) + { // big avatar (ICQ 6+) + pAvatarHash = pHash; + cbAvatarHash = itemLen + 4; + avatarType = itemType; + } + } + else if ((itemLen == 0) && (itemType == AVATAR_HASH_MINI || itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH || itemType == AVATAR_HASH_PHOTO)) + { // empty item - indicating that avatar of that type was removed + avatarInfoPresent = TRUE; + } + + pHash += itemLen + 4; + nHashLen -= itemLen + 4; + } + + if (avatarType != -1) + { // check settings, should we request avatar immediatelly? + DBVARIANT dbv = {DBVT_DELETED}; + TCHAR tszAvatar[MAX_PATH * 2 +4]; + BYTE bAutoLoad = getSettingByte(NULL, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS); + + if ((avatarType == AVATAR_HASH_STATIC || avatarType == AVATAR_HASH_MINI) && cbAvatarHash == 0x09 && !memcmp(pAvatarHash + 4, hashEmptyAvatar + 4, 0x05)) + { // empty avatar - unlink image, clear hash + if (!getSetting(hContact, "AvatarHash", &dbv)) + { // contact had avatar, clear hash, notify UI +#ifdef _DEBUG + NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); +#endif + ICQFreeVariant(&dbv); + NetLog_Server("%s has removed Avatar.", strUID(dwUIN, szUID)); + + deleteSetting(hContact, "AvatarHash"); + BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); + } +#ifdef _DEBUG + else + NetLog_Server("%s has empty Avatar.", strUID(dwUIN, szUID)); +#endif + return; + } + + if (getSetting(hContact, "AvatarHash", &dbv)) + { // we did not find old avatar hash, i.e. get new avatar + int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash); + + // check saved hash and file, if equal only store hash + if (!avatarState) + { // hashes are the same + int dwPaFormat = getSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN); + + GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2); + if (_taccess(tszAvatar, 0) == 0) + { // the file is there, link to contactphoto, save hash + NetLog_Server("%s has published Avatar. Image was found in the cache.", strUID(dwUIN, szUID)); +#ifdef _DEBUG + NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); +#endif + setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash); + BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); + } + else + { // the file was lost, request avatar again + NetLog_Server("%s has published Avatar.", strUID(dwUIN, szUID)); +#ifdef _DEBUG + NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); +#endif + bJob = TRUE; + } + } + else + { // the hash is not the one we want, request avatar + NetLog_Server("%s has published a new Avatar.", strUID(dwUIN, szUID)); +#ifdef _DEBUG + NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); +#endif + bJob = TRUE; + } + } + else + { // we found hash check if it changed or not + if ((dbv.cpbVal != cbAvatarHash) || memcmp(dbv.pbVal, pAvatarHash, cbAvatarHash)) + { // the hash is different, request new avatar +#ifdef _DEBUG + NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); +#endif + NetLog_Server("%s has changed Avatar.", strUID(dwUIN, szUID)); +#ifdef _DEBUG + NetLog_Hash(this, "new", pAvatarHash, cbAvatarHash); +#endif + bJob = TRUE; + } + else + { // the hash was not changed, check if we have the correct file + int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash); + + // we should have file, check if the file really exists + if (!avatarState) + { + int dwPaFormat = getSettingByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN); + if (dwPaFormat == PA_FORMAT_UNKNOWN) + { // we do not know the format, get avatar again +#ifdef _DEBUG + NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); +#endif + NetLog_Server("%s has Avatar. Image is missing.", strUID(dwUIN, szUID)); + bJob = 2; + } + else + { + GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2); + if (_taccess(tszAvatar, 0) != 0) + { // the file was lost, get it again +#ifdef _DEBUG + NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); +#endif + NetLog_Server("%s has Avatar. Image is missing.", strUID(dwUIN, szUID)); + bJob = 2; + } +#ifdef _DEBUG + else + { + NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); + + NetLog_Server("%s has Avatar. Image was found in the cache.", strUID(dwUIN, szUID)); + } +#endif + } + } + else + { // the hash is not the one we want, request avatar +#ifdef _DEBUG + NetLog_Hash(this, "current", dbv.pbVal, dbv.cpbVal); +#endif + NetLog_Server("%s has Avatar. Image was not retrieved yet.", strUID(dwUIN, szUID)); + bJob = 2; + } + } + ICQFreeVariant(&dbv); + } + + if (bJob) + { + if (bJob == TRUE) + { // Remove possible block - hash changed, try again. + icq_lock l(m_avatarsMutex); + + avatars_request *ar = m_avatarsQueue; + + while (ar) + { + if (ar->hContact == hContact && ar->type == ART_BLOCK) + { // found one, remove + ReleaseAvatarRequestInQueue(ar); + break; + } + ar = ar->pNext; + } + } + + setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash); + + BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); + + if (bAutoLoad) + { // auto-load is on, so request the avatar now, otherwise we are done + GetAvatarFileName(dwUIN, szUID, tszAvatar, MAX_PATH * 2); + GetAvatarData(hContact, dwUIN, szUID, pAvatarHash, cbAvatarHash, tszAvatar); + } // avatar request sent or added to queue + } + } + else if (avatarInfoPresent) + { // hash was not found, clear the hash + DBVARIANT dbv = {DBVT_DELETED}; + + if (!getSetting(hContact, "AvatarHash", &dbv)) + { // contact had avatar, clear hash, notify UI +#ifdef _DEBUG + NetLog_Hash(this, "old", dbv.pbVal, dbv.cpbVal); +#endif + ICQFreeVariant(&dbv); + NetLog_Server("%s has removed Avatar.", strUID(dwUIN, szUID)); + + deleteSetting(hContact, "AvatarHash"); + BroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, (LPARAM)NULL); + } +#ifdef _DEBUG + else + NetLog_Server("%s has no Avatar.", strUID(dwUIN, szUID)); +#endif + } +} + + +// request avatar data from server +int CIcqProto::GetAvatarData(HANDLE hContact, DWORD dwUin, const char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file) +{ + uid_str szUidData; + char *pszUid = NULL; + if (!dwUin && szUid) + { // create a copy in local writable buffer + strcpy(szUidData, szUid); + pszUid = szUidData; + } + + m_avatarsMutex->Enter(); + + if (m_avatarsConnection && m_avatarsConnection->isReady()) // check if we are ready + { // check if requests for this user are not blocked + DWORD dwNow = GetTickCount(); + avatars_request *ar = m_avatarsQueue; + + while (ar) + { + if (ar->hContact == hContact && ar->type == ART_BLOCK) + { // found a block item + if (GetTickCount() > ar->timeOut) + { // remove timeouted block + ar = ReleaseAvatarRequestInQueue(ar); + continue; + } + m_avatarsMutex->Leave(); + NetLog_Server("Avatars: Requests for %s avatar are blocked.", strUID(dwUin, pszUid)); + return 0; + } + ar = ar->pNext; + } + + avatars_server_connection *pConnection = m_avatarsConnection; + + pConnection->_Lock(); + m_avatarsMutex->Leave(); + + DWORD dwCookie = pConnection->sendGetAvatarRequest(hContact, dwUin, pszUid, hash, hashlen, file); + + m_avatarsMutex->Enter(); + pConnection->_Release(); + + if (dwCookie) + { // return now if the request was sent successfully + m_avatarsMutex->Leave(); + return dwCookie; + } + } + // we failed to send request, or avatar thread not ready + + // check if any request for this user is not already in the queue + avatars_request *ar = m_avatarsQueue; + + while (ar) + { + if (ar->hContact == hContact) + { // we found it, return error + if (ar->type == ART_BLOCK && GetTickCount() > ar->timeOut) + { // remove timeouted block + ar = ReleaseAvatarRequestInQueue(ar); + continue; + } + m_avatarsMutex->Leave(); + NetLog_Server("Avatars: Ignoring duplicate get %s avatar request.", strUID(dwUin, pszUid)); + + // make sure avatar connection is in progress + requestAvatarConnection(); + return 0; + } + ar = ar->pNext; + } + // add request to queue, processed after successful login + ar = new avatars_request(ART_GET); // get avatar + if (!ar) + { // out of memory, go away + m_avatarsMutex->Leave(); + return 0; + } + ar->hContact = hContact; + ar->dwUin = dwUin; + if (!dwUin) + strcpy(ar->szUid, szUid); + ar->hash = (BYTE*)SAFE_MALLOC(hashlen); + if (!ar->hash) + { // alloc failed + m_avatarsMutex->Leave(); + delete ar; + return 0; + } + memcpy(ar->hash, hash, hashlen); // copy the data + ar->hashlen = hashlen; + ar->szFile = null_strdup(file); // duplicate the string + ar->pNext = m_avatarsQueue; + m_avatarsQueue = ar; + m_avatarsMutex->Leave(); + + NetLog_Server("Avatars: Request to get %s image added to queue.", strUID(dwUin, pszUid)); + + // make sure avatar connection is in progress + requestAvatarConnection(); + + return -1; // we added to queue +} + + +// upload avatar data to server +int CIcqProto::SetAvatarData(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen) +{ + m_avatarsMutex->Enter(); + + if (m_avatarsConnection && m_avatarsConnection->isReady()) // check if we are ready + { + avatars_server_connection *pConnection = m_avatarsConnection; + + pConnection->_Lock(); + m_avatarsMutex->Leave(); + + DWORD dwCookie = pConnection->sendUploadAvatarRequest(hContact, wRef, data, datalen); + + m_avatarsMutex->Enter(); + pConnection->_Release(); + + if (dwCookie) + { // return now if the request was sent successfully + m_avatarsMutex->Leave(); + return dwCookie; + } + } + // we failed to send request, or avatar thread not ready + + // check if any request for this user is not already in the queue + avatars_request *ar = m_avatarsQueue; + int bYet = 0; + + while (ar) + { + if (ar->hContact == hContact && ar->type == ART_UPLOAD) + { // we found it, return error + m_avatarsMutex->Leave(); + NetLog_Server("Avatars: Ignoring duplicate upload avatar request."); + + // make sure avatar connection is in progress + requestAvatarConnection(); + return 0; + } + ar = ar->pNext; + } + // add request to queue, processed after successful login + ar = new avatars_request(ART_UPLOAD); // upload avatar + if (!ar) + { // out of memory, go away + m_avatarsMutex->Leave(); + return 0; + } + ar->hContact = hContact; + ar->pData = (BYTE*)SAFE_MALLOC(datalen); + if (!ar->pData) + { // alloc failed + m_avatarsMutex->Leave(); + delete ar; + return 0; + } + memcpy(ar->pData, data, datalen); // copy the data + ar->cbData = datalen; + ar->wRef = wRef; + ar->pNext = m_avatarsQueue; + m_avatarsQueue = ar; + m_avatarsMutex->Leave(); + + NetLog_Server("Avatars: Request to upload image added to queue."); + + // make sure avatar connection is in progress + requestAvatarConnection(); + + return -1; // we added to queue +} + + +void CIcqProto::requestAvatarConnection() +{ + m_avatarsMutex->Enter(); + if (!m_avatarsConnectionPending && (!m_avatarsConnection || (!m_avatarsConnection->isPending() && !m_avatarsConnection->isReady()))) + { // avatar connection is not pending, request new one + m_avatarsConnectionPending = TRUE; + m_avatarsMutex->Leave(); + + icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread); + } + else + m_avatarsMutex->Leave(); +} + + +void __cdecl CIcqProto::AvatarThread(avatars_server_connection *pInfo) +{ + NetLog_Server("%s thread started.", "Avatar"); + + // Execute connection handler + pInfo->connectionThread(); + + { // Remove connection reference + icq_lock l(m_avatarsMutex); + if (m_avatarsConnection == pInfo) + m_avatarsConnection = NULL; + } + + { // Release connection handler + icq_lock l(m_avatarsMutex); + delete pInfo; + } + + NetLog_Server("%s thread ended.", "Avatar"); +} + + +avatars_server_connection::avatars_server_connection(CIcqProto *ppro, HANDLE hConnection, char *pCookie, WORD wCookieLen): +isLoggedIn(FALSE), stopThread(FALSE), isActive(FALSE) +{ + this->ppro = ppro; + this->hConnection = hConnection; + this->pCookie = pCookie; + this->wCookieLen = wCookieLen; + + // Initialize packet sequence + localSeqMutex = new icq_critical_section(); + wLocalSequence = generate_flap_sequence(); + + // Initialize rates + m_ratesMutex = new icq_critical_section(); + + // Create connection thread + ppro->ForkThread(( IcqThreadFunc )&CIcqProto::AvatarThread, this); +} + + +avatars_server_connection::~avatars_server_connection() +{ + delete m_ratesMutex; + delete localSeqMutex; +} + + +int avatars_server_connection::NetLog_Server(const char *fmt,...) +{ + va_list va; + char szText[1024 + 9]; + + strcpy(szText, "Avatars: "); + va_start(va, fmt); + mir_vsnprintf(szText + 9, sizeof(szText) - 9, fmt, va); + va_end(va); + return CallService(MS_NETLIB_LOG,(WPARAM)ppro->m_hServerNetlibUser,(LPARAM)szText); +} + + +void avatars_server_connection::closeConnection() +{ + stopThread = TRUE; + + icq_lock l(localSeqMutex); + if (hConnection) + NetLib_SafeCloseHandle(&hConnection); +} + + +void avatars_server_connection::shutdownConnection() +{ + stopThread = TRUE; + + icq_lock l(localSeqMutex); + if (hConnection) + Netlib_Shutdown(hConnection); +} + +DWORD avatars_server_connection::sendGetAvatarRequest(HANDLE hContact, DWORD dwUin, char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file) +{ + int i; + DWORD dwNow = GetTickCount(); + + ppro->m_avatarsMutex->Enter(); + + for(i = 0; i < runCount;) + { // look for timeouted requests + if (runTime[i] < dwNow) + { // found outdated, remove + runContact[i] = runContact[runCount - 1]; + runTime[i] = runTime[runCount - 1]; + runCount--; + } + else + i++; + } + + for(i = 0; i < runCount; i++) + { + if (runContact[i] == hContact) + { + ppro->m_avatarsMutex->Leave(); + NetLog_Server("Ignoring duplicate get %s image request.", strUID(dwUin, szUid)); + + return -1; // Success: request ignored + } + } + + if (runCount < 4) + { // 4 concurent requests at most + int bSendNow = TRUE; + + { // rate management + icq_lock l(m_ratesMutex); + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST); + + if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT)) + { // we will be over quota if we send the request now, add to queue instead + bSendNow = FALSE; +#ifdef _DEBUG + NetLog_Server("Rates: Delay avatar request."); +#endif + } + } + + if (bSendNow) + { + runContact[runCount] = hContact; + runTime[runCount] = GetTickCount() + 30000; // 30sec to complete request + runCount++; + + ppro->m_avatarsMutex->Leave(); + + int nUinLen = getUIDLen(dwUin, szUid); + + cookie_avatar *ack = (cookie_avatar*)SAFE_MALLOC(sizeof(cookie_avatar)); + if (!ack) return 0; // Failure: out of memory + + ack->dwUin = 1; //dwUin; // I should be damned for this - only to identify get request + ack->hContact = hContact; + ack->hash = (BYTE*)SAFE_MALLOC(hashlen); + memcpy(ack->hash, hash, hashlen); // copy the data + ack->hashlen = hashlen; + ack->szFile = null_strdup(file); // duplicate the string + + DWORD dwCookie = ppro->AllocateCookie(CKT_AVATAR, ICQ_AVATAR_GET_REQUEST, hContact, ack); + icq_packet packet; + + serverPacketInit(&packet, (WORD)(12 + nUinLen + hashlen)); + packFNACHeader(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST, 0, dwCookie); + packUID(&packet, dwUin, szUid); + packByte(&packet, 1); // unknown, probably type of request: 1 = get icon :) + packBuffer(&packet, hash, (WORD)hashlen); + + if (sendServerPacket(&packet)) + { + NetLog_Server("Request to get %s image sent.", strUID(dwUin, szUid)); + + return dwCookie; + } + ppro->FreeCookie(dwCookie); // sending failed, free resources + SAFE_FREE(&ack->szFile); + SAFE_FREE((void**)&ack->hash); + SAFE_FREE((void**)&ack); + } + else + ppro->m_avatarsMutex->Leave(); + } + else + ppro->m_avatarsMutex->Leave(); + + return 0; // Failure +} + + +DWORD avatars_server_connection::sendUploadAvatarRequest(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen) +{ + cookie_avatar *ack = (cookie_avatar*)SAFE_MALLOC(sizeof(cookie_avatar)); + if (!ack) return 0; // Failure: out of memory + + ack->hContact = hContact; + + DWORD dwCookie = ppro->AllocateCookie(CKT_AVATAR, ICQ_AVATAR_UPLOAD_REQUEST, 0, ack); + icq_packet packet; + + serverPacketInit(&packet, (WORD)(14 + datalen)); + packFNACHeader(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_UPLOAD_REQUEST, 0, dwCookie); + packWord(&packet, wRef); // unknown, probably reference + packWord(&packet, (WORD)datalen); + packBuffer(&packet, data, (WORD)datalen); + + if (sendServerPacket(&packet)) + { + NetLog_Server("Upload image packet sent."); + + return dwCookie; + } + ppro->ReleaseCookie(dwCookie); // failed to send, free resources + + return 0; +} + + +void avatars_server_connection::checkRequestQueue() +{ +#ifdef _DEBUG + NetLog_Server("Checking request queue..."); +#endif + + ppro->m_avatarsMutex->Enter(); + + while (ppro->m_avatarsQueue && runCount < 3) // pick up an request and send it - happens immediatelly after login + { // do not fill queue to top, leave one place free + avatars_request *pRequest = ppro->m_avatarsQueue; + + { // rate management + icq_lock l(m_ratesMutex); + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, (WORD)(pRequest->type == ART_UPLOAD ? ICQ_AVATAR_GET_REQUEST : ICQ_AVATAR_UPLOAD_REQUEST)); + + if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT)) + { // we are over rate, leave queue and wait +#ifdef _DEBUG + NetLog_Server("Rates: Leaving avatar queue processing"); +#endif + break; + } + } + + if (pRequest->type == ART_BLOCK) + { // block contact processing + avatars_request **ppRequest = &ppro->m_avatarsQueue; + + while (pRequest) + { + if (GetTickCount() > pRequest->timeOut) + { // expired contact block, remove + *ppRequest = pRequest->pNext; + delete pRequest; + } + else // it is not time, move to next request + ppRequest = &pRequest->pNext; + + pRequest = *ppRequest; + } + // end queue processing (only block requests follows) + break; + } + else + ppro->m_avatarsQueue = pRequest->pNext; + + ppro->m_avatarsMutex->Leave(); + +#ifdef _DEBUG + NetLog_Server("Picked up the %s request from queue.", strUID(pRequest->dwUin, pRequest->szUid)); +#endif + switch (pRequest->type) + { + case ART_GET: // get avatar + sendGetAvatarRequest(pRequest->hContact, pRequest->dwUin, pRequest->szUid, pRequest->hash, pRequest->hashlen, pRequest->szFile); + break; + + case ART_UPLOAD: // set avatar + sendUploadAvatarRequest(pRequest->hContact, pRequest->wRef, pRequest->pData, pRequest->cbData); + break; + } + delete pRequest; + + ppro->m_avatarsMutex->Enter(); + } + + ppro->m_avatarsMutex->Leave(); +} + + +void avatars_server_connection::connectionThread() +{ + // This is the "infinite" loop that receives the packets from the ICQ avatar server + NETLIBPACKETRECVER packetRecv = {0}; + DWORD wLastKeepAlive = 0; // we send keep-alive at most one per 30secs + DWORD dwKeepAliveInterval = ppro->getSettingDword(NULL, "KeepAliveInterval", KEEPALIVE_INTERVAL); + + hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hConnection, 65536); + packetRecv.cbSize = sizeof(packetRecv); + packetRecv.dwTimeout = dwKeepAliveInterval < KEEPALIVE_INTERVAL ? dwKeepAliveInterval: KEEPALIVE_INTERVAL; // timeout - for stopThread to work + while (!stopThread) + { + int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); + + if (recvResult == 0) + { + NetLog_Server("Clean closure of server socket"); + break; + } + + if (recvResult == SOCKET_ERROR) + { + if (GetLastError() == ERROR_TIMEOUT) + { // timeout, check if we should be still running + if (Miranda_Terminated()) + { // we must stop here, cause due to a hack in netlib, we always get timeout, even if the connection is already dead + stopThread = 1; + continue; + } +#ifdef _DEBUG + else + NetLog_Server("Thread is Idle."); +#endif + if (GetTickCount() > wLastKeepAlive) + { // limit frequency (HACK: on some systems select() does not work well) + if (!ppro->m_bGatewayMode && ppro->getSettingByte(NULL, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED)) + { // send keep-alive packet + icq_packet packet; + + packet.wLen = 0; + write_flap(&packet, ICQ_PING_CHAN); + sendServerPacket(&packet); + } + wLastKeepAlive = GetTickCount() + dwKeepAliveInterval; + } + else + { // this is bad, the system does not handle select() properly +#ifdef _DEBUG + NetLog_Server("Thread is Forcing Idle."); +#endif + SleepEx(500, TRUE); // wait some time, can we do anything else ?? + if (Miranda_Terminated()) + { + stopThread = 1; + continue; + } + } + // check if we got something to request + checkRequestQueue(); + continue; + } + if (!stopThread) + NetLog_Server("Abortive closure of server socket, error: %d", GetLastError()); + else + NetLog_Server("Connection closed."); + break; + } + + // Deal with the packet + packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable); + + if (isActive && (packetRecv.bytesAvailable == packetRecv.bytesUsed)) // no packets pending + { // process request queue + checkRequestQueue(); + } + } + { // release connection + icq_lock l(localSeqMutex); + NetLib_SafeCloseHandle(&hPacketRecver); // Close the packet receiver + NetLib_CloseConnection(&hConnection, FALSE); // Close the connection + } + + { // release rates + icq_lock l(m_ratesMutex); + SAFE_DELETE((MZeroedObject**)&m_rates); + } + + SAFE_FREE((void**)&pCookie); +} + + +int avatars_server_connection::sendServerPacket(icq_packet *pPacket) +{ + int lResult = 0; + + // This critsec makes sure that the sequence order doesn't get screwed up + localSeqMutex->Enter(); + + if (hConnection) + { + int nRetries; + int nSendResult; + + // :IMPORTANT: + // The FLAP sequence must be a WORD. When it reaches 0xFFFF it should wrap to + // 0x0000, otherwise we'll get kicked by server. + wLocalSequence++; + + // Pack sequence number + pPacket->pData[2] = ((wLocalSequence & 0xff00) >> 8); + pPacket->pData[3] = (wLocalSequence & 0x00ff); + + for (nRetries = 3; nRetries >= 0; nRetries--) + { + nSendResult = Netlib_Send(hConnection, (const char *)pPacket->pData, pPacket->wLen, 0); + + if (nSendResult != SOCKET_ERROR) + break; + + Sleep(1000); + } + + // Send error + if (nSendResult == SOCKET_ERROR) + { // thread stops automatically + NetLog_Server("Your connection with the ICQ avatar server was abortively closed"); + } + else + { + lResult = 1; // packet sent successfully + + icq_lock l(m_ratesMutex); + if (m_rates) + m_rates->packetSent(pPacket); + } + } + else + { + NetLog_Server("Error: Failed to send packet (no connection)"); + } + + localSeqMutex->Leave(); + + SAFE_FREE((void**)&pPacket->pData); + + return lResult; +} + + +int avatars_server_connection::handleServerPackets(BYTE *buf, int buflen) +{ + BYTE channel; + WORD sequence; + WORD datalen; + int bytesUsed = 0; + + while (buflen > 0) + { + // All FLAPS begin with 0x2a + if (*buf++ != FLAP_MARKER) + break; + + if (buflen < 6) + break; + + unpackByte(&buf, &channel); + unpackWord(&buf, &sequence); + unpackWord(&buf, &datalen); + + if (buflen < 6 + datalen) + break; + +#ifdef _DEBUG + NetLog_Server("Server FLAP: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); +#endif + + switch (channel) + { + case ICQ_LOGIN_CHAN: + handleLoginChannel(buf, datalen); + break; + + case ICQ_DATA_CHAN: + handleDataChannel(buf, datalen); + break; + + default: + NetLog_Server("Warning: Unhandled Server FLAP Channel: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); + break; + } + + /* Increase pointers so we can check for more FLAPs */ + buf += datalen; + buflen -= (datalen + 6); + bytesUsed += (datalen + 6); + } + + return bytesUsed; +} + + +void avatars_server_connection::handleLoginChannel(BYTE *buf, WORD datalen) +{ + icq_packet packet; + + if (*(DWORD*)buf == 0x1000000) + { // here check if we received SRV_HELLO + wLocalSequence = generate_flap_sequence(); + + serverCookieInit(&packet, (LPBYTE)pCookie, wCookieLen); + sendServerPacket(&packet); + +#ifdef _DEBUG + NetLog_Server("Sent CLI_IDENT to %s", "avatar server"); +#endif + + SAFE_FREE((void**)&pCookie); + wCookieLen = 0; + } + else + { + NetLog_Server("Invalid Server response, Channel 1."); + } +} + + +void avatars_server_connection::handleDataChannel(BYTE *buf, WORD datalen) +{ + snac_header snacHeader = {0}; + + if (!unpackSnacHeader(&snacHeader, &buf, &datalen) || !snacHeader.bValid) + { + NetLog_Server("Error: Failed to parse SNAC header"); + } + else + { +#ifdef _DEBUG + if (snacHeader.wFlags & 0x8000) + NetLog_Server(" Received SNAC(x%02X,x%02X), version %u", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wVersion); + else + NetLog_Server(" Received SNAC(x%02X,x%02X)", snacHeader.wFamily, snacHeader.wSubtype); +#endif + + switch (snacHeader.wFamily) + { + + case ICQ_SERVICE_FAMILY: + handleServiceFam(buf, datalen, &snacHeader); + break; + + case ICQ_AVATAR_FAMILY: + handleAvatarFam(buf, datalen, &snacHeader); + break; + + default: + NetLog_Server("Ignoring SNAC(x%02X,x%02X) - FAMILYx%02X not implemented", snacHeader.wFamily, snacHeader.wSubtype, snacHeader.wFamily); + break; + } + } +} + + +void avatars_server_connection::handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) +{ + icq_packet packet; + + switch (pSnacHeader->wSubtype) + { + + case ICQ_SERVER_READY: +#ifdef _DEBUG + NetLog_Server("Server is ready and is requesting my Family versions"); + NetLog_Server("Sending my Families"); +#endif + + // Miranda mimics the behaviour of Icq5 + serverPacketInit(&packet, 18); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES); + packDWord(&packet, 0x00010004); + packDWord(&packet, 0x00100001); + sendServerPacket(&packet); + break; + + case ICQ_SERVER_FAMILIES2: + /* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands. + * We send a rate request packet */ +#ifdef _DEBUG + NetLog_Server("Server told me his Family versions"); + NetLog_Server("Requesting Rate Information"); +#endif + serverPacketInit(&packet, 10); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO); + sendServerPacket(&packet); + break; + + case ICQ_SERVER_RATE_INFO: +#ifdef _DEBUG + NetLog_Server("Server sent Rate Info"); +#endif + /* init rates management */ + m_rates = new rates(ppro, pBuffer, wBufferLength); + /* ack rate levels */ +#ifdef _DEBUG + NetLog_Server("Sending Rate Info Ack"); +#endif + m_rates->initAckPacket(&packet); + sendServerPacket(&packet); + + // send cli_ready + serverPacketInit(&packet, 26); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY); + packDWord(&packet, 0x00010004); // mimic ICQ 6 + packDWord(&packet, 0x0010164f); + packDWord(&packet, 0x00100001); + packDWord(&packet, 0x0010164f); + sendServerPacket(&packet); + + isActive = TRUE; // we are ready to process requests + isLoggedIn = TRUE; + + NetLog_Server(" *** Yeehah, login sequence complete"); + break; + + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + } +} + + +void avatars_server_connection::handleAvatarFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) +{ + switch (pSnacHeader->wSubtype) { + + case ICQ_AVATAR_GET_REPLY: // received avatar data, store to file + { // handle new avatar, notify + cookie_avatar *pCookieData; + + if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) + { + PROTO_AVATAR_INFORMATIONT ai = {0}; + BYTE bResult; + + { // remove from active request list + icq_lock l(ppro->m_avatarsMutex); + for(int i = 0; i < runCount; i++) + { // look for our record + if (runContact[i] == pCookieData->hContact) + { // found, remove + runContact[i] = runContact[runCount - 1]; + runTime[i] = runTime[runCount - 1]; + runCount--; + break; + } + } + } + + ai.cbSize = sizeof(PROTO_AVATAR_INFORMATIONT); + ai.format = PA_FORMAT_JPEG; // this is for error only + ai.hContact = pCookieData->hContact; + lstrcpyn(ai.filename, pCookieData->szFile, SIZEOF(ai.filename)); + AddAvatarExt(PA_FORMAT_JPEG, ai.filename); + + ppro->FreeCookie(pSnacHeader->dwRef); + + BYTE len; + WORD datalen; + + unpackByte(&pBuffer, &len); + if (wBufferLength < ((pCookieData->hashlen)<<1)+4+len) + { + NetLog_Server("Received invalid avatar reply."); + + ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); + + SAFE_FREE(&pCookieData->szFile); + SAFE_FREE((void**)&pCookieData->hash); + SAFE_FREE((void**)&pCookieData); + + break; + } + + pBuffer += len; + pBuffer += pCookieData->hashlen; + unpackByte(&pBuffer, &bResult); + pBuffer += pCookieData->hashlen; + unpackWord(&pBuffer, &datalen); + + wBufferLength -= 4 + len + (pCookieData->hashlen<<1); + if (datalen > wBufferLength) + { + datalen = wBufferLength; + NetLog_Server("Avatar reply broken, trying to do my best."); + } + + if (datalen > 4) + { // store to file... + int aValid = 1; + + if (pCookieData->hashlen == 0x14 && pCookieData->hash[3] == 0x10 && ppro->getSettingByte(NULL, "StrictAvatarCheck", DEFAULT_AVATARS_CHECK)) + { // check only standard hashes + mir_md5_state_t state; + mir_md5_byte_t digest[16]; + + mir_md5_init(&state); + mir_md5_append(&state, (const mir_md5_byte_t *)pBuffer, datalen); + mir_md5_finish(&state, digest); + // check if received data corresponds to specified hash + if (memcmp(pCookieData->hash+4, digest, 0x10)) aValid = 0; + } + + if (aValid) + { + NetLog_Server("Received user avatar, storing (%d bytes).", datalen); + + int dwPaFormat = DetectAvatarFormatBuffer((char*)pBuffer); + TCHAR *tszImageFile = (TCHAR*)_alloca(sizeof(TCHAR)*(strlennull(pCookieData->szFile) + 6)); + + _tcscpy(tszImageFile, pCookieData->szFile); + AddAvatarExt(dwPaFormat, tszImageFile); + + ppro->setSettingByte(pCookieData->hContact, "AvatarType", (BYTE)dwPaFormat); + ai.format = dwPaFormat; // set the format + lstrcpyn(ai.filename, tszImageFile, SIZEOF(ai.filename)); + + int out = _topen(tszImageFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); + if (out != -1) + { + DBVARIANT dbv = {DBVT_DELETED}; + + _write(out, pBuffer, datalen); + _close(out); + + if (!pCookieData->hContact) // our avatar, set filename + { + TCHAR tmp[MAX_PATH * 2]; + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)tszImageFile, (LPARAM)tmp); + ppro->setSettingStringT(NULL, "AvatarFile", tmp); + } + else + { // contact's avatar set hash + if (!ppro->getSetting(pCookieData->hContact, "AvatarHash", &dbv)) + { + if (ppro->setSettingBlob(pCookieData->hContact, "AvatarSaved", dbv.pbVal, dbv.cpbVal)) + NetLog_Server("Failed to set file hash."); + + ICQFreeVariant(&dbv); + } + else + { + NetLog_Server("Warning: DB error (no hash in DB)."); + // the hash was lost, try to fix that + if (ppro->setSettingBlob(pCookieData->hContact, "AvatarSaved", pCookieData->hash, pCookieData->hashlen) || + ppro->setSettingBlob(pCookieData->hContact, "AvatarHash", pCookieData->hash, pCookieData->hashlen)) + { + NetLog_Server("Failed to save avatar hash to DB"); + } + } + } + + ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, 0); + } + } + else + { // avatar is broken + NetLog_Server("Error: Avatar data does not match avatar hash, ignoring."); + + if (pCookieData->hContact) + { + avatars_request *ar = new avatars_request(ART_BLOCK); + + icq_lock l(ppro->m_avatarsMutex); + + if (ar) + { + avatars_request *last = ppro->m_avatarsQueue; + + ar->hContact = pCookieData->hContact; + ar->timeOut = GetTickCount() + 14400000; // do not allow re-request four hours + + // add it to the end of queue, i.e. do not block other requests + while (last && last->pNext) last = last->pNext; + if (last) + last->pNext = ar; + else + ppro->m_avatarsQueue = ar; + } + } + ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); + } + } + else + { // the avatar is empty + NetLog_Server("Received empty avatar, nothing written (error 0x%x).", bResult); + + ppro->BroadcastAck(pCookieData->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0); + } + SAFE_FREE(&pCookieData->szFile); + SAFE_FREE((void**)&pCookieData->hash); + SAFE_FREE((void**)&pCookieData); + } + else + { + NetLog_Server("Warning: Received unexpected Avatar Reply SNAC(x10,x07)."); + } + + break; + } + case ICQ_AVATAR_UPLOAD_ACK: + { + // upload completed, notify + BYTE res; + unpackByte(&pBuffer, &res); + if (!res && (wBufferLength == 0x15)) + { + cookie_avatar *pCookieData; + if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) + { + // here we store the local hash + ppro->ReleaseCookie(pSnacHeader->dwRef); + } + else + { + NetLog_Server("Warning: Received unexpected Upload Avatar Reply SNAC(x10,x03)."); + } + } + else if (res) + { + NetLog_Server("Error uploading avatar to server, #%d", res); + + ppro->icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server refused to accept the image.")); + } + else + NetLog_Server("Received invalid upload avatar ack."); + + break; + } + case ICQ_ERROR: + { + WORD wError; + cookie_avatar *pCookieData; + + if (ppro->FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) + { + if (pCookieData->dwUin) + { + NetLog_Server("Error: Avatar request failed"); + SAFE_FREE(&pCookieData->szFile); + SAFE_FREE((void**)&pCookieData->hash); + } + else + { + NetLog_Server("Error: Avatar upload failed"); + } + ppro->ReleaseCookie(pSnacHeader->dwRef); + } + + if (wBufferLength >= 2) + unpackWord(&pBuffer, &wError); + else + wError = 0; + + ppro->LogFamilyError(ICQ_AVATAR_FAMILY, wError); + break; + } + default: + NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_AVATAR_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); + break; + + } +} diff --git a/protocols/IcqOscarJ/src/icq_avatar.h b/protocols/IcqOscarJ/src/icq_avatar.h new file mode 100644 index 0000000000..6bfcb65c45 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_avatar.h @@ -0,0 +1,127 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Avatars connection support declarations +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_AVATAR_H +#define __ICQ_AVATAR_H + + +extern BYTE hashEmptyAvatar[9]; + +#define AVATAR_HASH_MINI 0x00 +#define AVATAR_HASH_STATIC 0x01 +#define AVATAR_HASH_FLASH 0x08 +#define AVATAR_HASH_PHOTO 0x0C + +struct CIcqProto; + +struct avatars_server_connection : public lockable_struct +{ +protected: + CIcqProto *ppro; + HANDLE hConnection; // handle to the connection + HANDLE hPacketRecver; + WORD wLocalSequence; + icq_critical_section *localSeqMutex; + + BOOL isLoggedIn; + BOOL isActive; + BOOL stopThread; // horrible, but simple - signal for thread to stop + + char *pCookie; // auth to server + WORD wCookieLen; + + int sendServerPacket(icq_packet *pPacket); + + int handleServerPackets(BYTE *buf, int buflen); + + void handleLoginChannel(BYTE *buf, WORD datalen); + void handleDataChannel(BYTE *buf, WORD datalen); + + void handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); + void handleAvatarFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); + + rates *m_rates; + icq_critical_section *m_ratesMutex; + + int NetLog_Server(const char *fmt,...); + + HANDLE runContact[4]; + DWORD runTime[4]; + int runCount; + void checkRequestQueue(); +public: + avatars_server_connection(CIcqProto *ppro, HANDLE hConnection, char *pCookie, WORD wCookieLen); + virtual ~avatars_server_connection(); + + void connectionThread(); + void closeConnection(); + void shutdownConnection(); + + __inline BOOL isPending() { return !isLoggedIn; }; + __inline BOOL isReady() { return isLoggedIn && isActive && !stopThread; }; + + DWORD sendGetAvatarRequest(HANDLE hContact, DWORD dwUin, char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file); + DWORD sendUploadAvatarRequest(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen); +}; + +__inline static void SAFE_DELETE(avatars_server_connection **p) { SAFE_DELETE((lockable_struct**)p); }; + + +struct avatars_request : public MZeroedObject +{ + int type; + HANDLE hContact; + DWORD dwUin; + uid_str szUid; + BYTE *hash; + unsigned int hashlen; + TCHAR *szFile; + BYTE *pData; + unsigned int cbData; + WORD wRef; + DWORD timeOut; + avatars_request *pNext; +public: + avatars_request(int type); + virtual ~avatars_request(); +}; + +__inline static void SAFE_DELETE(avatars_request **p) { SAFE_DELETE((MZeroedObject**)p); }; + +#define ART_GET 1 +#define ART_UPLOAD 2 +#define ART_BLOCK 4 + + +int DetectAvatarFormat(const TCHAR *szFile); +void AddAvatarExt(int dwFormat, TCHAR *pszDest); + +BYTE* calcMD5HashOfFile(const TCHAR *szFile); + +#endif /* __ICQ_AVATAR_H */ diff --git a/protocols/IcqOscarJ/src/icq_clients.cpp b/protocols/IcqOscarJ/src/icq_clients.cpp new file mode 100644 index 0000000000..bb1ebb5621 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_clients.cpp @@ -0,0 +1,1155 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Provides capability & signature based client detection +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +const capstr capShortCaps = {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; // CAP_AIM_BUDDYICON + +static const char* makeClientVersion(char *szBuf, const char *szClient, unsigned v1, unsigned v2, unsigned v3, unsigned v4) +{ + if (v4) + null_snprintf(szBuf, 64, "%s%u.%u.%u.%u", szClient, v1, v2, v3, v4); + else if (v3) + null_snprintf(szBuf, 64, "%s%u.%u.%u", szClient, v1, v2, v3); + else + null_snprintf(szBuf, 64, "%s%u.%u", szClient, v1, v2); + + return szBuf; +} + +static void verToStr(char *szStr, int v) +{ + char szVer[64]; + + makeClientVersion(szVer, "", (v>>24)&0x7F, (v>>16)&0xFF, (v>>8)&0xFF, v&0xFF); + strcat(szStr, szVer); + if (v&0x80000000) strcat(szStr, " alpha"); +} + +static char* MirandaVersionToStringEx(char* szStr, int bUnicode, const char* szPlug, int v, int m) +{ + if (!v) // this is not Miranda + return NULL; + + strcpy(szStr, "Miranda IM "); + + if (!m && v == 1) + verToStr(szStr, 0x80010200); + else if (!m && (v&0x7FFFFFFF) <= 0x030301) + verToStr(szStr, v); + else { + if (m) { + verToStr(szStr, m); + strcat(szStr, " "); + } + if (bUnicode) + strcat(szStr, "Unicode "); + + strcat(szStr, "("); + strcat(szStr, szPlug); + strcat(szStr, " v"); + verToStr(szStr, v); + strcat(szStr, ")"); + } + + return szStr; +} + +char* MirandaVersionToString(char* szStr, int bUnicode, int v, int m) +{ + return MirandaVersionToStringEx(szStr, bUnicode, "ICQ", v, m); +} + +char* MirandaModToString(char* szStr, capstr* capId, int bUnicode, const char* szModName) +{ // decode icqj mod version + char* szClient; + DWORD mver = (*capId)[0x4] << 0x18 | (*capId)[0x5] << 0x10 | (*capId)[0x6] << 8 | (*capId)[0x7]; + DWORD iver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; + DWORD scode = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; + + szClient = MirandaVersionToStringEx(szStr, bUnicode, szModName, iver, mver); + if (scode == 0x5AFEC0DE) + { + strcat(szClient, " + SecureIM"); + } + return szClient; +} + +const capstr capMirandaIm = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capMirandaNg = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'N', 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capIcqJs7 = {'i', 'c', 'q', 'j', ' ', 'S', 'e', 'c', 'u', 'r', 'e', ' ', 'I', 'M', 0, 0}; +const capstr capIcqJSin = {'s', 'i', 'n', 'j', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Miranda ICQJ S!N +const capstr capIcqJp = {'i', 'c', 'q', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capAimOscar = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'A', 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capMimMobile = {'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', 'o', 'b', 'i', 'l', 'e', 0, 0, 0}; +const capstr capMimPack = {'M', 'I', 'M', '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Custom Miranda Pack +const capstr capTrillian = {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}; +const capstr capTrilCrypt = {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb, 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}; +const capstr capSim = {'S', 'I', 'M', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', ' ', 0, 0, 0, 0}; +const capstr capSimOld = {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x00}; +const capstr capLicq = {'L', 'i', 'c', 'q', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', 0, 0, 0, 0}; +const capstr capKopete = {'K', 'o', 'p', 'e', 't', 'e', ' ', 'I', 'C', 'Q', ' ', ' ', 0, 0, 0, 0}; +const capstr capmIcq = {'m', 'I', 'C', 'Q', ' ', 0xA9, ' ', 'R', '.', 'K', '.', ' ', 0, 0, 0, 0}; +const capstr capClimm = {'c', 'l', 'i', 'm', 'm', 0xA9, ' ', 'R', '.', 'K', '.', ' ', 0, 0, 0, 0}; +const capstr capAndRQ = {'&', 'R', 'Q', 'i', 'n', 's', 'i', 'd', 'e', 0, 0, 0, 0, 0, 0, 0}; +const capstr capRAndQ = {'R', '&', 'Q', 'i', 'n', 's', 'i', 'd', 'e', 0, 0, 0, 0, 0, 0, 0}; +const capstr capIMadering = {'I', 'M', 'a', 'd', 'e', 'r', 'i', 'n', 'g', ' ', 'C', 'l', 'i', 'e', 'n', 't'}; +const capstr capmChat = {'m', 'C', 'h', 'a', 't', ' ', 'i', 'c', 'q', ' ', 0, 0, 0, 0, 0, 0}; +const capstr capJimm = {'J', 'i', 'm', 'm', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capCorePager = {'C', 'O', 'R', 'E', ' ', 'P', 'a', 'g', 'e', 'r', 0, 0, 0, 0, 0, 0}; +const capstr capDiChat = {'D', '[', 'i', ']', 'C', 'h', 'a', 't', ' ', 0, 0, 0, 0, 0, 0, 0}; +const capstr capVmIcq = {'V', 'm', 'I', 'C', 'Q', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capSmapeR = {'S', 'm', 'a', 'p', 'e', 'r', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capAnastasia = {0x44, 0xE5, 0xBF, 0xCE, 0xB0, 0x96, 0xE5, 0x47, 0xBD, 0x65, 0xEF, 0xD6, 0xA3, 0x7E, 0x36, 0x02}; +const capstr capPalmJicq = {'J', 'I', 'C', 'Q', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capInluxMsgr = {0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0, 0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4, 0x67, 0xC5, 0x6B, 0x1F}; +const capstr capYapp = {'Y', 'a', 'p', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capMipClient = {0x4d, 0x49, 0x50, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x00, 0x00, 0x00, 0x00}; +const capstr capPigeon = {'P', 'I', 'G', 'E', 'O', 'N', '!', 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capDigsbyBeta= {0x09, 0x46, 0x01, 0x05, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}; +const capstr capDigsby = {'d', 'i', 'g', 's', 'b', 'y', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capJapp = {0x6a, 0x61, 0x70, 0x70, 0xa9, 0x20, 0x62, 0x79, 0x20, 0x53, 0x65, 0x72, 0x67, 0x6f, 0x00, 0x00}; +const capstr capNaim = {0xFF, 0xFF, 0xFF, 0xFF, 'n', 'a', 'i', 'm', 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capCitron = {0x09, 0x19, 0x19, 0x82, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; +const capstr capQip = {0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F, 0x41, 'Q', 'I', 'P', ' ', '2', '0', '0', '5', 'a'}; +const capstr capQipPDA = {0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F, 0x41, 'Q', 'I', 'P', ' ', ' ', ' ', ' ', ' ', '!'}; +const capstr capQipSymbian= {0x51, 0xAD, 0xD1, 0x90, 0x72, 0x04, 0x47, 0x3D, 0xA1, 0xA1, 0x49, 0xF4, 0xA3, 0x97, 0xA4, 0x1F}; +const capstr capQipIphone = {0x60, 0xDE, 0x5C, 0x8A, 0xDF, 0x8C, 0x4E, 0x1D, 0xA4, 0xC8, 0xBC, 0x3B, 0xD9, 0x79, 0x4D, 0xD8}; +const capstr capQipMobile = {0xB0, 0x82, 0x62, 0xF6, 0x7F, 0x7C, 0x45, 0x61, 0xAD, 0xC1, 0x1C, 0x6D, 0x75, 0x70, 0x5E, 0xC5}; +const capstr capQipInfium = {0x7C, 0x73, 0x75, 0x02, 0xC3, 0xBE, 0x4F, 0x3E, 0xA6, 0x9F, 0x01, 0x53, 0x13, 0x43, 0x1E, 0x1A}; +const capstr capQip2010 = {0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x0A, 0x03, 0x0B, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, 0x00}; +const capstr capQip2012 = {0x7F, 0x7F, 0x7C, 0x7D, 0x7E, 0x7F, 0x0A, 0x03, 0x0B, 0x04, 0x01, 0x53, 0x13, 0x43, 0x1E, 0x1A}; +const capstr capIm2 = {0x74, 0xED, 0xC3, 0x36, 0x44, 0xDF, 0x48, 0x5B, 0x8B, 0x1C, 0x67, 0x1A, 0x1F, 0x86, 0x09, 0x9F}; // IM2 Ext Msg +const capstr capQutIm = {'q', 'u', 't', 'i', 'm', 0x30, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const capstr capBayan = {'b', 'a', 'y', 'a', 'n', 'I', 'C', 'Q', 0, 0, 0, 0, 0, 0, 0, 0}; +const capstr capJabberJIT = {'J', 'I', 'T', ' ', 0x76, 0x2E, 0x31, 0x2E, 0x78, 0x2E, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00}; +const capstr capIcqKid2 = {'I', 'c', 'q', 'K', 'i', 'd', '2', 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const capstr capWebIcqPro = {'W', 'e', 'b', 'I', 'c', 'q', 'P', 'r', 'o', ' ', 0, 0, 0, 0, 0, 0}; +const capstr capMraJava = {0x4a, 0x32, 0x4d, 0x45, 0x20, 0x6d, 0x40, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00}; +const capstr capMacIcq = {0xdd, 0x16, 0xf2, 0x02, 0x84, 0xe6, 0x11, 0xd4, 0x90, 0xdb, 0x00, 0x10, 0x4b, 0x9b, 0x4b, 0x7d}; +const capstr capIs2001 = {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}; +const capstr capIs2002 = {0x10, 0xcf, 0x40, 0xd1, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; +const capstr capComm20012 = {0xa0, 0xe9, 0x3f, 0x37, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; +const capstr capStrIcq = {0xa0, 0xe9, 0x3f, 0x37, 0x4f, 0xe9, 0xd3, 0x11, 0xbc, 0xd2, 0x00, 0x04, 0xac, 0x96, 0xdd, 0x96}; +const shortcapstr capAimIcon = {0x13, 0x46}; // CAP_AIM_BUDDYICON +const shortcapstr capAimDirect = {0x13, 0x45}; // CAP_AIM_DIRECTIM +const shortcapstr capAimFileShare = {0x13, 0x48}; // CAP_AIM_FILE_SHARE +const shortcapstr capIcqDevils = {0x13, 0x4C}; // CAP_DEVILS +const shortcapstr capAimSmartCaps = {0x01, 0xFF}; +const shortcapstr capAimLiveVideo = {0x01, 0x01}; // CAP_AIM_LIVE_VIDEO +const shortcapstr capAimLiveAudio = {0x01, 0x04}; // CAP_AIM_LIVE_AUDIO +const shortcapstr capStatusTextAware = {0x01, 0x0A}; // CAP_HOST_STATUS_TEXT_AWARE +const capstr capIcqLiteNew= {0xc8, 0x95, 0x3a, 0x9f, 0x21, 0xf1, 0x4f, 0xaa, 0xb0, 0xb2, 0x6d, 0xe6, 0x63, 0xab, 0xf5, 0xb7}; +const capstr capXtrazVideo= {0x17, 0x8C, 0x2D, 0x9B, 0xDA, 0xA5, 0x45, 0xBB, 0x8D, 0xDB, 0xF3, 0xBD, 0xBD, 0x53, 0xA1, 0x0A}; +const capstr capOscarChat = {0x74, 0x8F, 0x24, 0x20, 0x62, 0x87, 0x11, 0xD1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}; +const capstr capUim = {0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0, 0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4, 0x67, 0xC5, 0x6B, 0x1F}; +const capstr capRambler = {0x7E, 0x11, 0xB7, 0x78, 0xA3, 0x53, 0x49, 0x26, 0xA8, 0x02, 0x44, 0x73, 0x52, 0x08, 0xC4, 0x2A}; +const capstr capAbv = {0x00, 0xE7, 0xE0, 0xDF, 0xA9, 0xD0, 0x4F, 0xe1, 0x91, 0x62, 0xC8, 0x90, 0x9A, 0x13, 0x2A, 0x1B}; +const capstr capNetvigator= {0x4C, 0x6B, 0x90, 0xA3, 0x3D, 0x2D, 0x48, 0x0E, 0x89, 0xD6, 0x2E, 0x4B, 0x2C, 0x10, 0xD9, 0x9F}; +const capstr captZers = {0xb2, 0xec, 0x8f, 0x16, 0x7c, 0x6f, 0x45, 0x1b, 0xbd, 0x79, 0xdc, 0x58, 0x49, 0x78, 0x88, 0xb9}; // CAP_TZERS +const capstr capSimpLite = {0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50}; +const capstr capSimpPro = {0x53, 0x49, 0x4D, 0x50, 0x5F, 0x50, 0x52, 0x4F, 0x53, 0x49, 0x4D, 0x50, 0x5F, 0x50, 0x52, 0x4F}; +const capstr capIMsecure = {'I', 'M', 's', 'e', 'c', 'u', 'r', 'e', 'C', 'p', 'h', 'r', 0x00, 0x00, 0x06, 0x01}; // ZoneLabs +const capstr capIMSecKey1 = {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ZoneLabs +const capstr capIMSecKey2 = {2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ZoneLabs +const capstr capFakeHtml = {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15, 0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}; + +const char* cliLibicq2k = "libicq2000"; +const char* cliLicqVer = "Licq "; +const char* cliCentericq = "Centericq"; +const char* cliLibicqUTF = "libicq2000 (Unicode)"; +const char* cliTrillian = "Trillian"; +const char* cliTrillian4 = "Trillian Astra"; +const char* cliQip = "QIP %s"; +const char* cliIM2 = "IM2"; +const char* cliSpamBot = "Spam Bot"; + +const char* CIcqProto::detectUserClient(HANDLE hContact, int nIsICQ, WORD wUserClass, DWORD dwOnlineSince, const char *szCurrentClient, + WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, BYTE bDirectFlag, DWORD dwDirectCookie, DWORD dwWebPort, /* ICQ specific */ + BYTE *caps, WORD wLen, /* Client capabilities */ + BYTE *bClientId, /* Output: detected client-type */ + char *szClientBuf) +{ + LPCSTR szClient = NULL; + int bMirandaIM = FALSE; + + *bClientId = CLID_ALTERNATIVE; // Most clients does not tick as MsgIDs + + // Is this a Miranda IM client? + if (dwFT1 == 0xffffffff) + { + if (dwFT2 == 0xffffffff) + { // This is Gaim not Miranda + szClient = "Gaim"; + } + else if (!dwFT2 && wVersion == 7) + { // This is WebICQ not Miranda + szClient = "WebICQ"; + } + else if (!dwFT2 && dwFT3 == 0x3B7248ED) + { // And this is most probably Spam Bot + szClient = cliSpamBot; + } + else + { // Yes this is most probably Miranda, get the version info + szClient = MirandaVersionToString(szClientBuf, 0, dwFT2, 0); + *bClientId = CLID_MIRANDA; + bMirandaIM = TRUE; + } + } + else if (dwFT1 == 0x7fffffff) + { // This is Miranda with unicode core + szClient = MirandaVersionToString(szClientBuf, 1, dwFT2, 0); + *bClientId = CLID_MIRANDA; + bMirandaIM = TRUE; + } + else if ((dwFT1 & 0xFF7F0000) == 0x7D000000) + { // This is probably an Licq client + DWORD ver = dwFT1 & 0xFFFF; + + szClient = makeClientVersion(szClientBuf, cliLicqVer, ver / 1000, (ver / 10) % 100, ver % 10, 0); + if (dwFT1 & 0x00800000) + strcat(szClientBuf, "/SSL"); + } + else if (dwFT1 == 0xffffff8f) + { + szClient = "StrICQ"; + } + else if (dwFT1 == 0xffffff42) + { + szClient = "mICQ"; + } + else if (dwFT1 == 0xffffffbe) + { + unsigned ver1 = (dwFT2>>24)&0xFF; + unsigned ver2 = (dwFT2>>16)&0xFF; + unsigned ver3 = (dwFT2>>8)&0xFF; + + szClient = makeClientVersion(szClientBuf, "Alicq ", ver1, ver2, ver3, 0); + } + else if (dwFT1 == 0xFFFFFF7F) + { + szClient = "&RQ"; + } + else if (dwFT1 == 0xFFFFFFAB) + { + szClient = "YSM"; + } + else if (dwFT1 == 0x04031980) + { + szClient = "vICQ"; + } + else if ((dwFT1 == 0x3AA773EE) && (dwFT2 == 0x3AA66380)) + { + szClient = cliLibicq2k; + } + else if (dwFT1 == 0x3B75AC09) + { + szClient = cliTrillian; + } + else if (dwFT1 == 0x3BA8DBAF) // FT2: 0x3BEB5373; FT3: 0x3BEB5262; + { + if (wVersion == 2) + szClient = "stICQ"; + } + else if (dwFT1 == 0xFFFFFFFE && dwFT3 == 0xFFFFFFFE) + { + szClient = "Jimm"; + } + else if (dwFT1 == 0x3FF19BEB && dwFT3 == 0x3FF19BEB) + { + szClient = cliIM2; + } + else if (dwFT1 == 0xDDDDEEFF && !dwFT2 && !dwFT3) + { + szClient = "SmartICQ"; + } + else if ((dwFT1 & 0xFFFFFFF0) == 0x494D2B00 && !dwFT2 && !dwFT3) + { // last byte of FT1: (5 = Win32, 3 = SmartPhone, Pocket PC) + szClient = "IM+"; + } + else if (dwFT1 == 0x3B4C4C0C && !dwFT2 && dwFT3 == 0x3B7248ed) + { + szClient = "KXicq2"; + } + else if (dwFT1 == 0xFFFFF666 && !dwFT3) + { // this is R&Q (Rapid Edition) + null_snprintf(szClientBuf, 64, "R&Q %u", (unsigned)dwFT2); + szClient = szClientBuf; + } + else if (dwFT1 == 0x66666666 && dwFT3 == 0x66666666) + { // http://darkjimm.ucoz.ru/ + if (dwFT2 == 0x10000) + { + strcpy(szClientBuf, "D[i]Chat v."); + strcat(szClientBuf, "0.1a"); + } + else + { + makeClientVersion(szClientBuf, "D[i]Chat v.", (dwFT2 >> 8) & 0x0F, (dwFT2 >> 4) & 0x0F, 0, 0); + if ((dwFT2 & 0x0F) == 1) + strcat(szClientBuf, " alpha"); + else if ((dwFT2 & 0x0F) == 2) + strcat(szClientBuf, " beta"); + else if ((dwFT2 & 0x0F) == 3) + strcat(szClientBuf, " final"); + } + szClient = szClientBuf; + } + else if (dwFT1 == dwFT2 && dwFT2 == dwFT3 && wVersion == 8) + { + if ((dwFT1 < dwOnlineSince + 3600) && (dwFT1 > (dwOnlineSince - 3600))) + { + szClient = cliSpamBot; + } + } + else if (!dwFT1 && !dwFT2 && !dwFT3 && !wVersion && !wLen && dwWebPort == 0x75BB) + { + szClient = cliSpamBot; + } + else if (dwFT1 == 0x44F523B0 && dwFT2 == 0x44F523A6 && dwFT3 == 0x44F523A6 && wVersion == 8) + { + szClient = "Virus"; + } + + { // capabilities based detection + capstr* capId; + + if (nIsICQ && caps) + { + // check capabilities for client identification + if (capId = MatchCapability(caps, wLen, &capMirandaIm, 8)) { + // new Miranda Signature + DWORD iver = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; + DWORD mver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; + + szClient = MirandaVersionToString(szClientBuf, dwFT1 == 0x7fffffff, iver, mver); + + if (MatchCapability(caps, wLen, &capIcqJs7, 0x4)) { + // detect mod + strcat(szClientBuf, " (s7 & sss)"); + if (MatchCapability(caps, wLen, &capIcqJs7, 0xE)) + strcat(szClientBuf, " + SecureIM"); + } + else if ((dwFT1 & 0x7FFFFFFF) == 0x7FFFFFFF) + { + if (MatchCapability(caps, wLen, &capMimMobile)) + strcat(szClientBuf, " (Mobile)"); + + if (dwFT3 == 0x5AFEC0DE) + strcat(szClientBuf, " + SecureIM"); + } + *bClientId = CLID_MIRANDA; + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capMirandaNg, 8)) { + WORD v[4]; + BYTE *buf = *capId + 8; + unpackWord(&buf, &v[0]); unpackWord(&buf, &v[1]); unpackWord(&buf, &v[2]); unpackWord(&buf, &v[3]); + mir_snprintf(szClientBuf, MAX_PATH, "Miranda NG ICQ %d.%d.%d.%d", v[0], v[1], v[2], v[3]); + + szClient = szClientBuf; + if ((dwFT1 & 0x7FFFFFFF) == 0x7FFFFFFF && dwFT3 == 0x5AFEC0DE) + strcat(szClientBuf, " + SecureIM"); + + *bClientId = CLID_MIRANDA; + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capIcqJs7, 4)) + { // detect newer icqj mod + szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ S7 & SSS"); + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capIcqJSin, 4)) + { // detect newer icqj mod + szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ S!N"); + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capIcqJp, 4)) + { // detect icqj plus mod + szClient = MirandaModToString(szClientBuf, capId, dwFT3 == 0x80000000, "ICQ Plus"); + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capMraJava, 12)) + { + unsigned ver1 = (*capId)[13]; + unsigned ver2 = (*capId)[14]; + + szClient = makeClientVersion(szClientBuf, "Mail.ru Agent (Java) v", ver1, ver2, 0, 0); + } + else if (MatchCapability(caps, wLen, &capTrillian) || MatchCapability(caps, wLen, &capTrilCrypt)) + { // this is Trillian, check for new versions + if (CheckContactCapabilities(hContact, CAPF_RTF)) + { + if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) + szClient = cliTrillian4; + else + { // workaroud for a bug in Trillian - make it receive msgs, other features will not work! + ClearContactCapabilities(hContact, CAPF_SRV_RELAY); + szClient = "Trillian v3"; + } + } + else if (MatchCapability(caps, wLen, &capFakeHtml) || CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) + szClient = cliTrillian4; + else + szClient = cliTrillian; + } + else if ((capId = MatchCapability(caps, wLen, &capSimOld, 0xF)) && ((*capId)[0xF] != 0x92 && (*capId)[0xF] >= 0x20 || (*capId)[0xF] == 0)) + { + int hiVer = (((*capId)[0xF]) >> 6) - 1; + unsigned loVer = (*capId)[0xF] & 0x1F; + + if ((hiVer < 0) || ((hiVer == 0) && (loVer == 0))) + szClient = "Kopete"; + else + szClient = makeClientVersion(szClientBuf, "SIM ", (unsigned)hiVer, loVer, 0, 0); + } + else if (capId = MatchCapability(caps, wLen, &capSim, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, ver4 & 0x0F); + if (ver4 & 0x80) + strcat(szClientBuf,"/Win32"); + else if (ver4 & 0x40) + strcat(szClientBuf,"/MacOS X"); + } + else if (capId = MatchCapability(caps, wLen, &capLicq, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD] % 100; + unsigned ver3 = (*capId)[0xE]; + + szClient = makeClientVersion(szClientBuf, cliLicqVer, ver1, ver2, ver3, 0); + if ((*capId)[0xF]) + strcat(szClientBuf,"/SSL"); + } + else if (capId = MatchCapability(caps, wLen, &capKopete, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4); + } + else if (capId = MatchCapability(caps, wLen, &capClimm, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "climm ", ver1, ver2, ver3, ver4); + if ((ver1 & 0x80) == 0x80) + strcat(szClientBuf, " alpha"); + if (dwFT3 == 0x02000020) + strcat(szClientBuf, "/Win32"); + else if (dwFT3 == 0x03000800) + strcat(szClientBuf, "/MacOS X"); + } + else if (capId = MatchCapability(caps, wLen, &capmIcq, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "mICQ ", ver1, ver2, ver3, ver4); + if ((ver1 & 0x80) == 0x80) + strcat(szClientBuf, " alpha"); + } + else if (MatchCapability(caps, wLen, &capIm2)) + { // IM2 v2 provides also Aim Icon cap + szClient = cliIM2; + } + else if (capId = MatchCapability(caps, wLen, &capAndRQ, 9)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xB]; + unsigned ver3 = (*capId)[0xA]; + unsigned ver4 = (*capId)[9]; + + szClient = makeClientVersion(szClientBuf, "&RQ ", ver1, ver2, ver3, ver4); + } + else if (capId = MatchCapability(caps, wLen, &capRAndQ, 9)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xB]; + unsigned ver3 = (*capId)[0xA]; + unsigned ver4 = (*capId)[9]; + + szClient = makeClientVersion(szClientBuf, "R&Q ", ver1, ver2, ver3, ver4); + } + else if (MatchCapability(caps, wLen, &capIMadering)) + { // http://imadering.com + szClient = "IMadering"; + } + else if (MatchCapability(caps, wLen, &capQipPDA)) + { + szClient = "QIP PDA (Windows)"; + } + else if (MatchCapability(caps, wLen, &capQipSymbian)) + { + szClient = "QIP PDA (Symbian)"; + } + else if (MatchCapability(caps, wLen, &capQipIphone)) + { + szClient = "QIP Mobile (IPhone)"; + } + else if (MatchCapability(caps, wLen, &capQipMobile)) + { + szClient = "QIP Mobile (Java)"; + } + else if (MatchCapability(caps, wLen, &capQipInfium)) + { + char ver[10]; + + strcpy(szClientBuf, "QIP Infium"); + if (dwFT1) + { // add build + null_snprintf(ver, 10, " (%d)", dwFT1); + strcat(szClientBuf, ver); + } + if (dwFT2 == 0x0B) + strcat(szClientBuf, " Beta"); + + szClient = szClientBuf; + } + else if (MatchCapability(caps, wLen, &capQip2010, 12)) + { + char ver[10]; + + strcpy(szClientBuf, "QIP 2010"); + if (dwFT1) + { // add build + null_snprintf(ver, 10, " (%d)", dwFT1); + strcat(szClientBuf, ver); + } + + szClient = szClientBuf; + } + else if (MatchCapability(caps, wLen, &capQip2012, 12)) + { + char ver[10]; + + strcpy(szClientBuf, "QIP 2012"); + if (dwFT1) + { // add build + null_snprintf(ver, 10, " (%d)", dwFT1); + strcat(szClientBuf, ver); + } + + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capQip, 0xE)) + { + char ver[10]; + + if (dwFT3 == 0x0F) + strcpy(ver, "2005"); + else + null_strcpy(ver, (char*)(*capId) + 11, 5); + + null_snprintf(szClientBuf, 64, cliQip, ver); + if (dwFT1 && dwFT2 == 0x0E) + { // add QIP build + null_snprintf(ver, 10, " (%d%d%d%d)", dwFT1 >> 0x18, (dwFT1 >> 0x10) & 0xFF, (dwFT1 >> 0x08) & 0xFF, dwFT1 & 0xFF); + strcat(szClientBuf, ver); + } + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capmChat, 0xA)) + { + strcpy(szClientBuf, "mChat "); + strncat(szClientBuf, (char*)(*capId) + 0xA, 6); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capJimm, 5)) + { + strcpy(szClientBuf, "Jimm "); + strncat(szClientBuf, (char*)(*capId) + 5, 11); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capCorePager, 0xA)) + { // http://corepager.net.ru/index/0-2 + strcpy(szClientBuf, "CORE Pager"); + if (dwFT2 == 0x0FFFF0011 && dwFT3 == 0x1100FFFF && (dwFT1 >> 0x18)) + { + char ver[16]; + + null_snprintf(ver, 10, " %d.%d", dwFT1 >> 0x18, (dwFT1 >> 0x10) & 0xFF); + if ((dwFT1 & 0xFF) == 0x0B) + strcat(ver, " Beta"); + strcat(szClientBuf, ver); + } + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capDiChat, 9)) + { // http://darkjimm.ucoz.ru/ + strcpy(szClientBuf, "D[i]Chat"); + strncat(szClientBuf, (char*)(*capId) + 8, 8); + szClient = szClientBuf; + } + else if (MatchCapability(caps, wLen, &capMacIcq)) + { + szClient = "ICQ for Mac"; + } + else if (MatchCapability(caps, wLen, &capUim)) + { + szClient = "uIM"; + } + else if (MatchCapability(caps, wLen, &capAnastasia)) + { // http://chis.nnov.ru/anastasia + szClient = "Anastasia"; + } + else if (capId = MatchCapability(caps, wLen, &capPalmJicq, 0xC)) + { // http://www.jsoft.ru + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "JICQ ", ver1, ver2, ver3, ver4); + } + else if (MatchCapability(caps, wLen, &capInluxMsgr)) + { // http://www.inlusoft.com + szClient = "Inlux Messenger"; + } + else if (capId = MatchCapability(caps, wLen, &capMipClient, 0xC)) + { // http://mip.rufon.net + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + if (ver1 < 30) + { + makeClientVersion(szClientBuf, "MIP ", ver1, ver2, ver3, ver4); + } + else + { + strcpy(szClientBuf, "MIP "); + strncat(szClientBuf, (char*)(*capId) + 11, 5); + } + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capMipClient, 0x04)) + { //http://mip.rufon.net - new signature + strcpy(szClientBuf, "MIP "); + strncat(szClientBuf, (char*)(*capId) + 4, 12); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capVmIcq, 0x06)) + { + strcpy(szClientBuf, "VmICQ"); + strncat(szClientBuf, (char*)(*capId) + 5, 11); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capSmapeR, 0x07)) + { // http://www.smape.com/smaper + strcpy(szClientBuf, "SmapeR"); + strncat(szClientBuf, (char*)(*capId) + 6, 10); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capYapp, 0x04)) + { // http://yapp.ru + strcpy(szClientBuf, "Yapp! v"); + strncat(szClientBuf, (char*)(*capId) + 8, 5); + szClient = szClientBuf; + } + else if (MatchCapability(caps, wLen, &capDigsby, 0x06)) + { // http://www.dibsby.com (newer builds) + szClient = "Digsby"; + } + else if (MatchCapability(caps, wLen, &capDigsbyBeta)) + { // http://www.digsby.com - probably by mistake (feature detection as well) + szClient = "Digsby"; + } + else if (MatchCapability(caps, wLen, &capJapp)) + { // http://www.japp.org.ua + szClient = "japp"; + } + else if (MatchCapability(caps, wLen, &capPigeon, 0x07)) + { // http://pigeon.vpro.ru + szClient = "PIGEON!"; + } + else if (capId = MatchCapability(caps, wLen, &capQutIm, 0x05)) + { // http://www.qutim.org + if ((*capId)[0x6] == 0x2E) + { // old qutim id + unsigned ver1 = (*capId)[0x5] - 0x30; + unsigned ver2 = (*capId)[0x7] - 0x30; + + makeClientVersion(szClientBuf, "qutIM ", ver1, ver2, 0, 0); + } + else + { // new qutim id + unsigned ver1 = (*capId)[0x6]; + unsigned ver2 = (*capId)[0x7]; + unsigned ver3 = (*capId)[0x8]; + unsigned ver4 = ((*capId)[0x9] << 8) || (*capId)[0xA]; + + makeClientVersion(szClientBuf, "qutIM ", ver1, ver2, ver3, ver4); + + switch ((*capId)[0x5]) + { + case 'l': + strcat(szClientBuf, "/Linux"); + break; + case 'w': + strcat(szClientBuf, "/Win32"); + break; + case 'm': + strcat(szClientBuf, "/MacOS X"); + break; + } + } + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capBayan, 8)) + { // http://www.barobin.com/bayanICQ.html + strcpy(szClientBuf, "bayanICQ "); + strncat(szClientBuf, (char*)(*capId) + 8, 5); + szClient = szClientBuf; + } + else if (capId = MatchCapability(caps, wLen, &capJabberJIT, 0x04)) + { + szClient = "Jabber ICQ Transport"; + } + else if (capId = MatchCapability(caps, wLen, &capIcqKid2, 0x07)) + { // http://sourceforge.net/projects/icqkid2 + unsigned ver1 = (*capId)[0x7]; + unsigned ver2 = (*capId)[0x8]; + unsigned ver3 = (*capId)[0x9]; + unsigned ver4 = (*capId)[0xA]; + + szClient = makeClientVersion(szClientBuf, "IcqKid2 v", ver1, ver2, ver3, ver4); + } + else if (capId = MatchCapability(caps, wLen, &capWebIcqPro, 0x0A)) + { // http://intrigue.ru/workshop/webicqpro/webicqpro.html + szClient = "WebIcqPro"; + } + else if (capId = MatchCapability(caps, wLen, &capCitron)) + { // http://www.citron-im.com + szClient = "Citron IM"; + } + else if (szClient == cliLibicq2k) + { // try to determine which client is behind libicq2000 + if (CheckContactCapabilities(hContact, CAPF_RTF)) + szClient = cliCentericq; // centericq added rtf capability to libicq2000 + else if (CheckContactCapabilities(hContact, CAPF_UTF)) + szClient = cliLibicqUTF; // IcyJuice added unicode capability to libicq2000 + // others - like jabber transport uses unmodified library, thus cannot be detected + } + else if (szClient == NULL) // HERE ENDS THE SIGNATURE DETECTION, after this only feature default will be detected + { + if (wVersion == 8 && CheckContactCapabilities(hContact, CAPF_XTRAZ) && (MatchCapability(caps, wLen, &capIMSecKey1, 6) || MatchCapability(caps, wLen, &capIMSecKey2, 6))) + { // ZA mangled the version, OMG! + wVersion = 9; + } + if (wVersion == 8 && (MatchCapability(caps, wLen, &capComm20012) || CheckContactCapabilities(hContact, CAPF_SRV_RELAY))) + { // try to determine 2001-2003 versions + if (MatchCapability(caps, wLen, &capIs2001)) + { + if (!dwFT1 && !dwFT2 && !dwFT3) + if (CheckContactCapabilities(hContact, CAPF_RTF)) + szClient = "TICQClient"; // possibly also older GnomeICU + else + szClient = "ICQ for Pocket PC"; + else + { + *bClientId = CLID_GENERIC; + szClient = "ICQ 2001"; + } + } + else if (MatchCapability(caps, wLen, &capIs2002)) + { + *bClientId = CLID_GENERIC; + szClient = "ICQ 2002"; + } + else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_RTF)) + { + if (!dwFT1 && !dwFT2 && !dwFT3) + { + if (!dwWebPort) + szClient = "GnomeICU 0.99.5+"; // no other way + else + szClient = "IC@"; + } + else + { + *bClientId = CLID_GENERIC; + szClient = "ICQ 2002/2003a"; + } + } + else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && + MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && + MatchCapability(caps, wLen, &capFakeHtml)) + { // libpurple (e.g. Pidgin 2.7.x) + if (MatchShortCapability(caps, wLen, &capAimDirect)) + szClient = "libpurple"; + else + szClient = "Meebo"; + } + else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING)) + { + if (!dwFT1 && !dwFT2 && !dwFT3) + { + szClient = "PreludeICQ"; + } + } + } + else if (wVersion == 8) + { + if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect)) + szClient = "imo.im"; //https://imo.im/ - Web IM + } + else if (wVersion == 9) + { // try to determine lite versions + if (CheckContactCapabilities(hContact, CAPF_XTRAZ)) + { + *bClientId = CLID_GENERIC; + if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) + { + if (MatchCapability(caps, wLen, &captZers)) + { // capable of tZers ? + if (MatchCapability(caps, wLen, &capIcqLiteNew) && MatchShortCapability(caps, wLen, &capStatusTextAware) && + MatchShortCapability(caps, wLen, &capAimLiveVideo) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) + { + strcpy(szClientBuf, "ICQ 7"); + } + else if (MatchCapability(caps, wLen, &capFakeHtml)) + { + if (MatchShortCapability(caps, wLen, &capAimLiveVideo) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) + { + strcpy(szClientBuf, "ICQ 6"); + *bClientId = CLID_ICQ6; + } + else if (CheckContactCapabilities(hContact, CAPF_RTF) && !CheckContactCapabilities(hContact, CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capIcqDevils)) + { + strcpy(szClientBuf, "Qnext v4"); // finally handles SRV_RELAY correctly + *bClientId = CLID_ALTERNATIVE; + } + } + else + { + strcpy(szClientBuf, "icq5.1"); + } + } + else + { + strcpy(szClientBuf, "icq5"); + } + + if (MatchCapability(caps, wLen, &capRambler)) + { + strcat(szClientBuf, " (Rambler)"); + } + else if (MatchCapability(caps, wLen, &capAbv)) + { + strcat(szClientBuf, " (Abv)"); + } + else if (MatchCapability(caps, wLen, &capNetvigator)) + { + strcat(szClientBuf, " (Netvigator)"); + } + szClient = szClientBuf; + } + else if (!CheckContactCapabilities(hContact, CAPF_ICQDIRECT)) + { + *bClientId = CLID_ALTERNATIVE; + if (CheckContactCapabilities(hContact, CAPF_RTF)) + { + // most probably Qnext - try to make that shit at least receiving our msgs + ClearContactCapabilities(hContact, CAPF_SRV_RELAY); + NetLog_Server("Forcing simple messages (QNext client)."); + szClient = "Qnext"; + } + else if (CheckContactCapabilities(hContact, CAPF_TYPING) && MatchCapability(caps, wLen, &captZers) && MatchCapability(caps, wLen, &capFakeHtml)) + { + if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF) && MatchShortCapability(caps, wLen, &capAimLiveAudio)) + szClient = "Mail.ru Agent (PC)"; + else + szClient = "Fring"; + } + else + szClient = "pyICQ"; + } + else + szClient = "ICQ Lite v4"; + } + else if (MatchCapability(caps, wLen, &capIcqLiteNew)) + szClient = "ICQ Lite"; // the new ICQ Lite based on ICQ6 + else if (!CheckContactCapabilities(hContact, CAPF_ICQDIRECT)) + { + if (MatchCapability(caps, wLen, &capFakeHtml) && MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimSmartCaps)) + szClient = cliTrillian4; + else if (CheckContactCapabilities(hContact, CAPF_UTF) && !CheckContactCapabilities(hContact, CAPF_RTF)) + szClient = "pyICQ"; + } + } + else if (wVersion == 7) + { + if (CheckContactCapabilities(hContact, CAPF_RTF)) + szClient = "GnomeICU"; // this is an exception + else if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) + { + if (!dwFT1 && !dwFT2 && !dwFT3) + szClient = "&RQ"; + else + { + *bClientId = CLID_GENERIC; + szClient = "ICQ 2000"; + } + } + else if (CheckContactCapabilities(hContact, CAPF_UTF)) + { + if (CheckContactCapabilities(hContact, CAPF_TYPING)) + szClient = "Icq2Go! (Java)"; + else if (wUserClass & CLASS_WIRELESS) + szClient = "Pocket Web 1&1"; + else + szClient = "Icq2Go!"; + } + } + else if (wVersion == 0xA) + { + if (!CheckContactCapabilities(hContact, CAPF_RTF) && !CheckContactCapabilities(hContact, CAPF_UTF)) + { // this is bad, but we must do it - try to detect QNext + ClearContactCapabilities(hContact, CAPF_SRV_RELAY); + NetLog_Server("Forcing simple messages (QNext client)."); + szClient = "Qnext"; + } + else if (!CheckContactCapabilities(hContact, CAPF_RTF) && CheckContactCapabilities(hContact, CAPF_UTF) && !dwFT1 && !dwFT2 && !dwFT3) + { // not really good, but no other option + szClient = "NanoICQ"; + } + } + else if (wVersion == 0xB) + { + if (CheckContactCapabilities(hContact, CAPF_XTRAZ | CAPF_SRV_RELAY | CAPF_TYPING | CAPF_UTF) && MatchShortCapability(caps, wLen, &capIcqDevils)) + { + szClient = "Mail.ru Agent (Symbian)"; + } + } + else if (wVersion == 0) + { // capability footprint based detection - not really reliable + if (!dwFT1 && !dwFT2 && !dwFT3 && !dwWebPort && !dwDirectCookie) + { // DC info is empty + if (CheckContactCapabilities(hContact, CAPF_TYPING) && MatchCapability(caps, wLen, &capIs2001) && + MatchCapability(caps, wLen, &capIs2002) && MatchCapability(caps, wLen, &capComm20012)) + szClient = cliSpamBot; + else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && + CheckContactCapabilities(hContact, CAPF_OSCAR_FILE | CAPF_UTF)) + { // detect libgaim/libpurple versions + if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) + szClient = "Adium X"; // yeah, AFAIK only Adium has this fixed + else if (CheckContactCapabilities(hContact, CAPF_TYPING)) + szClient = "libpurple"; + else + szClient = "libgaim"; + } + else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && + MatchCapability(caps, wLen, &capOscarChat) && CheckContactCapabilities(hContact, CAPF_OSCAR_FILE) && wLen == 0x40) + szClient = "libgaim"; // Gaim 1.5.1 most probably + else if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE) && MatchCapability(caps, wLen, &capOscarChat) && wLen == 0x20) + szClient = "Easy Message"; + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capOscarChat) && wLen == 0x40) + szClient = "Meebo"; + else if (CheckContactCapabilities(hContact, CAPF_UTF) && MatchShortCapability(caps, wLen, &capAimIcon) && wLen == 0x20) + szClient = "PyICQ-t Jabber Transport"; + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_XTRAZ) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capXtrazVideo)) + szClient = "PyICQ-t Jabber Transport"; + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_ICQDIRECT | CAPF_TYPING) && wLen == 0x40) + szClient = "Agile Messenger"; // Smartphone 2002 + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_ICQDIRECT | CAPF_OSCAR_FILE) && MatchShortCapability(caps, wLen, &capAimFileShare)) + szClient = "Slick"; // http://lonelycatgames.com/?app=slick + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_OSCAR_FILE | CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capAimFileShare) && MatchShortCapability(caps, wLen, &capAimIcon)) + szClient = "Digsby"; // http://www.digsby.com + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_SRV_RELAY | CAPF_CONTACTS) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capFakeHtml)) + szClient = "mundu IM"; // http://messenger.mundu.com + else if (CheckContactCapabilities(hContact, CAPF_UTF | CAPF_OSCAR_FILE) && MatchCapability(caps, wLen, &capOscarChat)) + szClient = "eBuddy"; //http://www.ebuddy.com + else if (CheckContactCapabilities(hContact, CAPF_CONTACTS | CAPF_OSCAR_FILE) && MatchShortCapability(caps, wLen, &capAimIcon) && MatchShortCapability(caps, wLen, &capAimDirect) && MatchCapability(caps, wLen, &capOscarChat)) + szClient = "IloveIM"; //http://www.iloveim.com/ + + } + } + } + } + else if (!nIsICQ) + { // detect AIM clients + if (caps) + { + if (capId = MatchCapability(caps, wLen, &capAimOscar, 8)) + { // AimOscar Signature + DWORD aver = (*capId)[0xC] << 0x18 | (*capId)[0xD] << 0x10 | (*capId)[0xE] << 8 | (*capId)[0xF]; + DWORD mver = (*capId)[0x8] << 0x18 | (*capId)[0x9] << 0x10 | (*capId)[0xA] << 8 | (*capId)[0xB]; + + szClient = MirandaVersionToStringEx(szClientBuf, 0, "AimOscar", aver, mver); + bMirandaIM = TRUE; + } + else if (capId = MatchCapability(caps, wLen, &capSim, 0xC)) + { // Sim is universal + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + + szClient = makeClientVersion(szClientBuf, "SIM ", ver1, ver2, ver3, 0); + if ((*capId)[0xF] & 0x80) + strcat(szClientBuf,"/Win32"); + else if ((*capId)[0xF] & 0x40) + strcat(szClientBuf,"/MacOS X"); + } + else if (capId = MatchCapability(caps, wLen, &capKopete, 0xC)) + { + unsigned ver1 = (*capId)[0xC]; + unsigned ver2 = (*capId)[0xD]; + unsigned ver3 = (*capId)[0xE]; + unsigned ver4 = (*capId)[0xF]; + + szClient = makeClientVersion(szClientBuf, "Kopete ", ver1, ver2, ver3, ver4); + } + else if (MatchCapability(caps, wLen, &capIm2)) + { // IM2 extensions + szClient = cliIM2; + } + else if (MatchCapability(caps, wLen, &capNaim, 0x8)) + { + szClient = "naim"; + } + else if (MatchCapability(caps, wLen, &capDigsby, 0x06) || MatchCapability(caps, wLen, &capDigsbyBeta)) + { // http://www.dibsby.com + szClient = "Digsby"; + } + else if (MatchShortCapability(caps, wLen, &capAimIcon) && MatchCapability(caps, wLen, &capOscarChat) && + CheckContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING) && wLen == 0x40) + szClient = "Meebo"; + else if (wLen == 0x90 && CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && + MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && + MatchShortCapability(caps, wLen, &capAimDirect) && MatchCapability(caps, wLen, &capFakeHtml)) + { // libpurple (e.g. Pidgin 2.7.x) + szClient = "libpurple"; + } + else if (wLen == 0x70 && CheckContactCapabilities(hContact, CAPF_SRV_RELAY | CAPF_UTF | CAPF_TYPING | CAPF_XTRAZ) && + MatchCapability(caps, wLen, &capOscarChat) && MatchShortCapability(caps, wLen, &capAimIcon) && + MatchCapability(caps, wLen, &capFakeHtml)) + { // libpurple - Meebo (without DirectIM and OFT) + szClient = "Meebo"; + } + else + szClient = "AIM"; + } + else if(wUserClass & CLASS_WIRELESS) + szClient = "AIM (Mobile)"; + else + szClient = "AIM"; + } + } + if (caps && bMirandaIM) + { // custom miranda packs + capstr* capId; + + if (capId = MatchCapability(caps, wLen, &capMimPack, 4)) + { + char szPack[16]; + + null_snprintf(szPack, 16, " [%.12s]", (*capId)+4); + + if (szClient != szClientBuf) + { // make sure client string is not constant + strcpy(szClientBuf, szClient); + szClient = szClientBuf; + } + + strcat(szClientBuf, szPack); + } + } + + BOOL bClientDetected = (szClient != NULL); + + if (!szClient) + { + *bClientId = CLID_GENERIC; + + switch (wVersion) + { // client detection failed, provide default clients + case 6: + szClient = "ICQ99"; + break; + case 7: + szClient = "ICQ 2000/Icq2Go"; + break; + case 8: + szClient = "ICQ 2001-2003a"; + break; + case 9: + szClient = "ICQ Lite"; + break; + case 0xA: + szClient = "ICQ 2003b"; + } + } + + if (szClient) + { + char *szExtra = NULL; + + if (MatchCapability(caps, wLen, &capSimpLite)) + szExtra = " + SimpLite"; + else if (MatchCapability(caps, wLen, &capSimpPro)) + szExtra = " + SimpPro"; + else if (MatchCapability(caps, wLen, &capIMsecure) || MatchCapability(caps, wLen, &capIMSecKey1, 6) || MatchCapability(caps, wLen, &capIMSecKey2, 6)) + szExtra = " + IMsecure"; + + if (szExtra) + { + if (szClient != szClientBuf) + { + strcpy(szClientBuf, szClient); + szClient = szClientBuf; + } + strcat(szClientBuf, szExtra); + } + } + + if (!szCurrentClient || strcmpnull(szCurrentClient, szClient)) + { // Log the detection result if it has changed or contact just logged on... + if (bClientDetected) + NetLog_Server("Client identified as %s", szClient); + else + NetLog_Server("No client identification, put default ICQ client for protocol."); + } + + return szClient; +} diff --git a/protocols/IcqOscarJ/src/icq_constants.h b/protocols/IcqOscarJ/src/icq_constants.h new file mode 100644 index 0000000000..4da90f1bc0 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_constants.h @@ -0,0 +1,652 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Global constants and default settings are defined here +// +// ----------------------------------------------------------------------------- +// Most of the protocol constants follow the naming conventions of the +// Oscar documentation at http://iserverd.khstu.ru/oscar/index.html +// BIG THANKS to Alexandr for maintaining this site and to everyone +// in the ICQ devel community who have helped to collect the data. + +#ifndef __ICQ_CONSTANTS_H +#define __ICQ_CONSTANTS_H + + +/* Static icon indexes */ +#define ISI_AUTH_REQUEST 0 +#define ISI_AUTH_GRANT 1 +#define ISI_AUTH_REVOKE 2 +#define ISI_ADD_TO_SERVLIST 3 + +/* Contact menu item indexes */ +#define ICMI_AUTH_REQUEST 0 +#define ICMI_AUTH_GRANT 1 +#define ICMI_AUTH_REVOKE 2 +#define ICMI_ADD_TO_SERVLIST 3 +#define ICMI_XSTATUS_DETAILS 4 +#define ICMI_OPEN_PROFILE 5 + +/* Some default settings */ +#define DEFAULT_SERVER_PORT 5190 +#define DEFAULT_SERVER_PORT_SSL 443 +#define DEFAULT_SERVER_HOST "login.icq.com" +#define DEFAULT_SERVER_HOST_SSL "slogin.icq.com" +#define DEFAULT_SS_ENABLED 1 +#define DEFAULT_SS_ADDSERVER 1 +#define DEFAULT_SS_LOAD 0 +#define DEFAULT_SS_STORE 1 +#define DEFAULT_SS_GROUP "General" + +#define DEFAULT_SECURE_LOGIN 1 +#define DEFAULT_SECURE_CONNECTION 1 +#define DEFAULT_KEEPALIVE_ENABLED 1 +#define DEFAULT_AIM_ENABLED 1 +#define DEFAULT_UTF_ENABLED 2 // everything unicode is default +#define DEFAULT_ANSI_CODEPAGE CP_ACP +#define DEFAULT_DCMSG_ENABLED 1 // passive dc messaging is default +#define DEFAULT_TEMPVIS_ENABLED 1 // temporary visible is enabled by default +#define DEFAULT_MTN_ENABLED 1 +#define DEFAULT_AVATARS_ENABLED 1 +#define DEFAULT_LOAD_AVATARS 1 +#define DEFAULT_BIGGER_AVATARS 0 +#define DEFAULT_AVATARS_CHECK 1 +#define DEFAULT_XSTATUS_ENABLED 0 +#define DEFAULT_XSTATUS_AUTO 1 +#define DEFAULT_XSTATUS_RESET 0 +#define DEFAULT_MOODS_ENABLED 1 +#define DEFAULT_KILLSPAM_ENABLED 1 + +#define DEFAULT_SLOWSEND 1 +#define DEFAULT_ONLYSERVERACKS 1 + +#define DEFAULT_POPUPS_ENABLED 1 +#define DEFAULT_SPAM_POPUPS_ENABLED 1 +#define DEFAULT_LOG_POPUPS_ENABLED 1 +#define DEFAULT_POPUPS_SYS_ICONS 1 +#define DEFAULT_LOG0_TEXT_COLORS RGB(0,0,0) // LOG_NOTE +#define DEFAULT_LOG0_BACK_COLORS RGB(255,255,255) +#define DEFAULT_LOG0_TIMEOUT 0 +#define DEFAULT_LOG1_TEXT_COLORS RGB(0,0,0) // LOG_WARNING +#define DEFAULT_LOG1_BACK_COLORS RGB(255,255,255) +#define DEFAULT_LOG1_TIMEOUT 0 +#define DEFAULT_LOG2_TEXT_COLORS RGB(0,0,0) // LOG_ERROR +#define DEFAULT_LOG2_BACK_COLORS RGB(255,255,255) +#define DEFAULT_LOG2_TIMEOUT 0 +#define DEFAULT_LOG3_TEXT_COLORS RGB(0,0,0) // LOG_FATAL +#define DEFAULT_LOG3_BACK_COLORS RGB(255,255,255) +#define DEFAULT_LOG3_TIMEOUT 0 +#define DEFAULT_SPAM_TEXT_COLORS RGB(193,0,38) +#define DEFAULT_SPAM_BACK_COLORS RGB(213,209,208) +#define DEFAULT_SPAM_TIMEOUT 0 +#define DEFAULT_POPUPS_WIN_COLORS 0 +#define DEFAULT_POPUPS_DEF_COLORS (BYTE)!DEFAULT_POPUPS_WIN_COLORS + +/* Database setting names */ +#define DBSETTING_CAPABILITIES "caps" +// Contact's server-list items +#define DBSETTING_SERVLIST_ID "ServerId" +#define DBSETTING_SERVLIST_GROUP "SrvGroupId" +#define DBSETTING_SERVLIST_PERMIT "SrvPermitId" +#define DBSETTING_SERVLIST_DENY "SrvDenyId" +#define DBSETTING_SERVLIST_IGNORE "SrvIgnoreId" +// Owner's server-list items +#define DBSETTING_SERVLIST_PRIVACY "SrvVisibilityID" +#define DBSETTING_SERVLIST_PHOTO "SrvPhotoID" +#define DBSETTING_SERVLIST_AVATAR "SrvAvatarID" +#define DBSETTING_SERVLIST_METAINFO "SrvMetaInfoID" +#define DBSETTING_SERVLIST_UNHANDLED "SrvUnhandledIDList" +// Contact's data from server-list +#define DBSETTING_SERVLIST_DATA "ServerData" +// User Details +#define DBSETTING_METAINFO_TOKEN "MetaInfoToken" +#define DBSETTING_METAINFO_TIME "MetaInfoTime" +#define DBSETTING_METAINFO_SAVED "InfoTS" +// Status Note & Mood +#define DBSETTING_STATUS_NOTE "StatusNote" +#define DBSETTING_STATUS_NOTE_TIME "StatusNoteTS" +#define DBSETTING_STATUS_MOOD "StatusMood" +// Custom Status +#define DBSETTING_XSTATUS_ID "XStatusId" +#define DBSETTING_XSTATUS_NAME "XStatusName" +#define DBSETTING_XSTATUS_MSG "XStatusMsg" + + +// Status FLAGS (used to determine status of other users) +#define ICQ_STATUSF_ONLINE 0x0000 +#define ICQ_STATUSF_AWAY 0x0001 +#define ICQ_STATUSF_DND 0x0002 +#define ICQ_STATUSF_NA 0x0004 +#define ICQ_STATUSF_OCCUPIED 0x0010 +#define ICQ_STATUSF_FFC 0x0020 +#define ICQ_STATUSF_INVISIBLE 0x0100 + +// Status values (used to set own status) +#define ICQ_STATUS_ONLINE 0x0000 +#define ICQ_STATUS_AWAY 0x0001 +#define ICQ_STATUS_NA 0x0005 +#define ICQ_STATUS_OCCUPIED 0x0011 +#define ICQ_STATUS_DND 0x0013 +#define ICQ_STATUS_FFC 0x0020 +#define ICQ_STATUS_INVISIBLE 0x0100 + +#define STATUS_WEBAWARE 0x0001 // Status webaware flag +#define STATUS_SHOWIP 0x0002 // Status show ip flag +#define STATUS_BIRTHDAY 0x0008 // User birthday flag +#define STATUS_WEBFRONT 0x0020 // User active webfront flag +#define STATUS_DCDISABLED 0x0100 // Direct connection not supported +#define STATUS_DCAUTH 0x1000 // Direct connection upon authorization +#define STATUS_DCCONT 0x2000 // DC only with contact users + + + +// Typing notification statuses +#define MTN_FINISHED 0x0000 +#define MTN_TYPED 0x0001 +#define MTN_BEGUN 0x0002 +#define MTN_WINDOW_CLOSED 0x000F + + + +// Ascii Capability IDs +#define CAP_RTFMSGS "{97B12751-243C-4334-AD22-D6ABF73F1492}" +#define CAP_UTF8MSGS "{0946134E-4C7F-11D1-8222-444553540000}" + +// Binary Capability Sizes +#define BINARY_CAP_SIZE 16 +#define BINARY_SHORT_CAP_SIZE 2 + +// Binary Capability IDs +#define CAP_SRV_RELAY 0x09, 0x46, 0x13, 0x49, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 +#define CAP_UTF 0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 +#define CAP_RTF 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92 +#define CAP_CONTACTS 0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 +#define CAP_TYPING 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3 +#define CAP_ICQDIRECT 0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 +#define CAP_XTRAZ 0x1A, 0x09, 0x3C, 0x6C, 0xD7, 0xFD, 0x4E, 0xC5, 0x9D, 0x51, 0xA6, 0x47, 0x4E, 0x34, 0xF5, 0xA0 +#define CAP_OSCAR_FILE 0x09, 0x46, 0x13, 0x43, 0x4C, 0x7F, 0x11, 0xD1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 + +// Miranda IM Capability bitmask +#define CAPF_SRV_RELAY 0x00000001 +#define CAPF_UTF 0x00000002 +#define CAPF_RTF 0x00000004 +#define CAPF_CONTACTS 0x00000010 +#define CAPF_TYPING 0x00000020 +#define CAPF_ICQDIRECT 0x00000080 +#define CAPF_XTRAZ 0x00000100 +#define CAPF_OSCAR_FILE 0x00000400 +#define CAPF_STATUS_MESSAGES 0x10000000 +#define CAPF_STATUS_MOOD 0x40000000 +#define CAPF_XSTATUS 0x80000000 + + +// Message Capability IDs +#define MCAP_SRV_RELAY_FMT_s 0x09461349, 0x4c7f11d1, 0x82224445, 0x53540000 +#define MCAP_REVERSE_DC_REQ_s 0x09461344, 0x4c7f11d1, 0x82224445, 0x53540000 +#define MCAP_FILE_TRANSFER_s 0x09461343, 0x4c7f11d1, 0x82224445, 0x53540000 +#define MCAP_CONTACTS_s 0x0946134b, 0x4c7f11d1, 0x82224445, 0x53540000 + +// Plugin Type GUIDs +#define PSIG_MESSAGE_s 0x00000000, 0x00000000, 0x00000000, 0x00000000 +#define PSIG_INFO_PLUGIN_s 0xa0e93f37, 0x4fe9d311, 0xbcd20004, 0xac96dd96 +#define PSIG_STATUS_PLUGIN_s 0x10cf40d1, 0x4fe9d311, 0xbcd20004, 0xac96dd96 + +// Plugin Message GUIDs +#define PMSG_QUERY_INFO_s 0xF002BF71, 0x4371D311, 0x8DD20010, 0x4B06462E +#define PMSG_QUERY_STATUS_s 0x10180670, 0x5471D311, 0x8DD20010, 0x4B06462E + + + +// Message types +#define MTYPE_PLAIN 0x01 // Plain text (simple) message +#define MTYPE_CHAT 0x02 // Chat request message +#define MTYPE_FILEREQ 0x03 // File request / file ok message +#define MTYPE_URL 0x04 // URL message (0xFE formatted) +#define MTYPE_AUTHREQ 0x06 // Authorization request message (0xFE formatted) +#define MTYPE_AUTHDENY 0x07 // Authorization denied message (0xFE formatted) +#define MTYPE_AUTHOK 0x08 // Authorization given message (empty) +#define MTYPE_SERVER 0x09 // Message from OSCAR server (0xFE formatted) +#define MTYPE_ADDED 0x0C // "You-were-added" message (0xFE formatted) +#define MTYPE_WWP 0x0D // Web pager message (0xFE formatted) +#define MTYPE_EEXPRESS 0x0E // Email express message (0xFE formatted) +#define MTYPE_CONTACTS 0x13 // Contact list message +#define MTYPE_PLUGIN 0x1A // Plugin message described by text string +#define MTYPE_AUTOONLINE 0xE7 // Auto online message (internal only) +#define MTYPE_AUTOAWAY 0xE8 // Auto away message +#define MTYPE_AUTOBUSY 0xE9 // Auto occupied message +#define MTYPE_AUTONA 0xEA // Auto not available message +#define MTYPE_AUTODND 0xEB // Auto do not disturb message +#define MTYPE_AUTOFFC 0xEC // Auto free for chat message +// Internal Message types +#define MTYPE_UNKNOWN 0x00 // Unknown message + +#define MTYPE_GREETINGCARD 0x101 // Greeting Card +#define MTYPE_REQUESTCONTACTS 0x102 // Request for Contacts +#define MTYPE_MESSAGE 0x103 // Message+ +#define MTYPE_STATUSMSGEXT 0x104 // StatusMsgExt (2003b) +#define MTYPE_SMS_MESSAGE 0x110 // SMS message from Mobile +#define MTYPE_SCRIPT_INVITATION 0x201 // Xtraz Invitation +#define MTYPE_SCRIPT_DATA 0x202 // Xtraz Message +#define MTYPE_SCRIPT_NOTIFY 0x208 // Xtraz Response +#define MTYPE_REVERSE_REQUEST 0x401 // Reverse DC request + +// Message Plugin Type GUIDs +#define MGTYPE_MESSAGE_s 0xBE6B7305, 0x0FC2104F, 0xA6DE4DB1, 0xE3564B0E +#define MGTYPE_STATUSMSGEXT_s 0x811a18bc, 0x0e6c1847, 0xa5916f18, 0xdcc76f1a +#define MGTYPE_FILE_s 0xF02D12D9, 0x3091D311, 0x8DD70010, 0x4B06462E +#define MGTYPE_WEBURL_s 0x371C5872, 0xE987D411, 0xA4C100D0, 0xB759B1D9 +#define MGTYPE_CONTACTS_s 0x2A0E7D46, 0x7676D411, 0xBCE60004, 0xAC961EA6 +#define MGTYPE_GREETING_CARD_s 0x01E53B48, 0x2AE4D111, 0xB6790060, 0x97E1E294 +#define MGTYPE_CHAT_s 0xBFF720B2, 0x378ED411, 0xBD280004, 0xAC96D905 +#define MGTYPE_SMS_MESSAGE_s 0x0e28f600, 0x11e7d311, 0xbcf30004, 0xac969dc2 +#define MGTYPE_XTRAZ_SCRIPT_s 0x3b60b3ef, 0xd82a6c45, 0xa4e09c5a, 0x5e67e865 + +// Message Plugin Sub-Type IDs +#define MGTYPE_STANDARD_SEND 0x0000 +#define MGTYPE_CONTACTS_REQUEST 0x0002 +#define MGTYPE_SCRIPT_INVITATION 0x0001 +#define MGTYPE_SCRIPT_DATA 0x0002 +#define MGTYPE_SCRIPT_USER_REMOVE 0x0004 +#define MGTYPE_SCRIPT_NOTIFY 0x0008 +#define MGTYPE_UNDEFINED 0xFFFF + + + +/* Channels */ +#define ICQ_LOGIN_CHAN 0x01 +#define ICQ_DATA_CHAN 0x02 +#define ICQ_ERROR_CHAN 0x03 +#define ICQ_CLOSE_CHAN 0x04 +#define ICQ_PING_CHAN 0x05 + +/* Families */ +#define ICQ_SERVICE_FAMILY 0x0001 +#define ICQ_LOCATION_FAMILY 0x0002 +#define ICQ_BUDDY_FAMILY 0x0003 +#define ICQ_MSG_FAMILY 0x0004 +#define ICQ_BOS_FAMILY 0x0009 +#define ICQ_LOOKUP_FAMILY 0x000a +#define ICQ_STATS_FAMILY 0x000b +#define ICQ_CHAT_NAVIGATION_FAMILY 0x000d +#define ICQ_CHAT_FAMILY 0x000e +#define ICQ_AVATAR_FAMILY 0x0010 +#define ICQ_LISTS_FAMILY 0x0013 +#define ICQ_EXTENSIONS_FAMILY 0x0015 +#define ICQ_AUTHORIZATION_FAMILY 0x0017 +#define ICQ_DIRECTORY_FAMILY 0x0025 + +/* Subtypes for Service Family 0x0001 */ +#define ICQ_ERROR 0x0001 +#define ICQ_CLIENT_READY 0x0002 +#define ICQ_SERVER_READY 0x0003 +#define ICQ_CLIENT_NEW_SERVICE 0x0004 +#define ICQ_SERVER_REDIRECT_SERVICE 0x0005 +#define ICQ_CLIENT_REQ_RATE_INFO 0x0006 +#define ICQ_SERVER_RATE_INFO 0x0007 +#define ICQ_CLIENT_RATE_ACK 0x0008 +#define ICQ_SERVER_RATE_CHANGE 0x000a +#define ICQ_SERVER_PAUSE 0x000b +#define ICQ_CLIENT_PAUSE_ACK 0x000c +#define ICQ_SERVER_RESUME 0x000d +#define ICQ_CLIENT_REQINFO 0x000e +#define ICQ_SERVER_NAME_INFO 0x000f +#define ICQ_SERVER_EVIL_NOTICE 0x0010 +#define ICQ_CLIENT_SET_IDLE 0x0011 +#define ICQ_SERVER_MIGRATIONREQ 0x0012 +#define ICQ_SERVER_MOTD 0x0013 +#define ICQ_CLIENT_FAMILIES 0x0017 +#define ICQ_SERVER_FAMILIES2 0x0018 +#define ICQ_CLIENT_SET_STATUS 0x001e +#define ICQ_SERVER_EXTSTATUS 0x0021 + +/* Subtypes for Location Family 0x0002 */ +#define ICQ_LOCATION_CLI_REQ_RIGHTS 0x0002 +#define ICQ_LOCATION_RIGHTS_REPLY 0x0003 +#define ICQ_LOCATION_SET_USER_INFO 0x0004 +#define ICQ_LOCATION_REQ_USER_INFO 0x0005 +#define ICQ_LOCATION_USR_INFO_REPLY 0x0006 +#define ICQ_LOCATION_QRY_USER_INFO 0x0015 + +/* Subtypes for Buddy Family 0x0003 */ +#define ICQ_USER_CLI_REQBUDDY 0x0002 +#define ICQ_USER_SRV_REPLYBUDDY 0x0003 +#define ICQ_USER_ADDTOLIST 0x0004 /* deprecated */ +#define ICQ_USER_REMOVEFROMLIST 0x0005 /* deprecated */ +#define ICQ_USER_NOTIFY_REJECTED 0x000a +#define ICQ_USER_ONLINE 0x000b +#define ICQ_USER_OFFLINE 0x000c +#define ICQ_USER_ADDTOTEMPLIST 0x000f +#define ICQ_USER_REMOVEFROMTEMPLIST 0x0010 + +/* Subtypes for Message Family 0x0004 */ +#define ICQ_MSG_SRV_ERROR 0x0001 +#define ICQ_MSG_CLI_SETPARAMS 0x0002 +#define ICQ_MSG_CLI_RESETPARAMS 0x0003 +#define ICQ_MSG_CLI_REQICBM 0x0004 +#define ICQ_MSG_SRV_REPLYICBM 0x0005 +#define ICQ_MSG_SRV_SEND 0x0006 +#define ICQ_MSG_SRV_RECV 0x0007 +#define ICQ_MSG_SRV_MISSED_MESSAGE 0x000A +#define ICQ_MSG_RESPONSE 0x000B +#define ICQ_MSG_SRV_ACK 0x000C +#define ICQ_MSG_CLI_REQ_OFFLINE 0x0010 +#define ICQ_MSG_MTN 0x0014 +#define ICQ_MSG_SRV_OFFLINE_REPLY 0x0017 + +/* Subtypes for Privacy Family 0x0009 */ +#define ICQ_PRIVACY_REQ_RIGHTS 0x0002 +#define ICQ_PRIVACY_RIGHTS_REPLY 0x0003 +#define ICQ_CLI_ADDVISIBLE 0x0005 +#define ICQ_CLI_REMOVEVISIBLE 0x0006 +#define ICQ_CLI_ADDINVISIBLE 0x0007 +#define ICQ_CLI_REMOVEINVISIBLE 0x0008 +#define ICQ_PRIVACY_SERVICE_ERROR 0x0009 +#define ICQ_CLI_ADDTEMPVISIBLE 0x000A +#define ICQ_CLI_REMOVETEMPVISIBLE 0x000B + +/* Subtypes for Lookup Family 0x000a */ +#define ICQ_LOOKUP_REQUEST 0x0002 +#define ICQ_LOOKUP_EMAIL_REPLY 0x0003 + +/* Subtypes for Stats Family 0x000b */ +#define ICQ_STATS_MINREPORTINTERVAL 0x0002 + +/* Subtypes for Avatar Family 0x0010 */ +#define ICQ_AVATAR_ERROR 0x0001 +#define ICQ_AVATAR_UPLOAD_REQUEST 0x0002 +#define ICQ_AVATAR_UPLOAD_ACK 0x0003 +#define ICQ_AVATAR_GET_REQUEST 0x0006 +#define ICQ_AVATAR_GET_REPLY 0x0007 + +/* Subtypes for Server Lists Family 0x0013 */ +#define ICQ_LISTS_ERROR 0x0001 +#define ICQ_LISTS_CLI_REQLISTS 0x0002 +#define ICQ_LISTS_SRV_REPLYLISTS 0x0003 +#define ICQ_LISTS_CLI_REQUEST 0x0004 +#define ICQ_LISTS_CLI_CHECK 0x0005 +#define ICQ_LISTS_LIST 0x0006 +#define ICQ_LISTS_GOTLIST 0x0007 +#define ICQ_LISTS_ADDTOLIST 0x0008 +#define ICQ_LISTS_UPDATEGROUP 0x0009 +#define ICQ_LISTS_REMOVEFROMLIST 0x000A +#define ICQ_LISTS_ACK 0x000E +#define ICQ_LISTS_UPTODATE 0x000F +#define ICQ_LISTS_CLI_MODIFYSTART 0x0011 +#define ICQ_LISTS_CLI_MODIFYEND 0x0012 +#define ICQ_LISTS_GRANTAUTH 0x0014 +#define ICQ_LISTS_AUTHGRANTED 0x0015 +#define ICQ_LISTS_REVOKEAUTH 0x0016 +#define ICQ_LISTS_REQUESTAUTH 0x0018 +#define ICQ_LISTS_AUTHREQUEST 0x0019 +#define ICQ_LISTS_CLI_AUTHRESPONSE 0x001A +#define ICQ_LISTS_SRV_AUTHRESPONSE 0x001B +#define ICQ_LISTS_YOUWEREADDED 0x001C + +/* Subtypes for ICQ Extensions Family 0x0015 */ +#define ICQ_META_ERROR 0x0001 +#define ICQ_META_CLI_REQUEST 0x0002 +#define ICQ_META_SRV_REPLY 0x0003 +#define ICQ_META_SRV_UPDATE 0x0004 + +/* Subtypes for Authorization Family 0x0017 */ +#define ICQ_SIGNON_ERROR 0x0001 +#define ICQ_SIGNON_LOGIN_REQUEST 0x0002 +#define ICQ_SIGNON_LOGIN_REPLY 0x0003 +#define ICQ_SIGNON_REGISTRATION_REQ 0x0004 +#define ICQ_SIGNON_NEW_UIN 0x0005 +#define ICQ_SIGNON_AUTH_REQUEST 0x0006 +#define ICQ_SIGNON_AUTH_KEY 0x0007 +#define ICQ_SIGNON_REQUEST_IMAGE 0x000C +#define ICQ_SIGNON_REG_AUTH_IMAGE 0x000D + +// Class constants +#define CLASS_UNCONFIRMED 0x0001 +#define CLASS_ADMINISTRATOR 0x0002 +#define CLASS_AOL 0x0004 +#define CLASS_COMMERCIAL 0x0008 +#define CLASS_FREE 0x0010 +#define CLASS_AWAY 0x0020 +#define CLASS_ICQ 0x0040 +#define CLASS_WIRELESS 0x0080 +#define CLASS_FORWARDING 0x0200 +#define CLASS_BOT 0x0400 + +// Reply types for SNAC 15/02 & 15/03 +#define CLI_DELETE_OFFLINE_MSGS_REQ 0x003E +#define CLI_META_INFO_REQ 0x07D0 +#define SRV_META_INFO_REPLY 0x07DA + +// Reply subtypes for SNAC 15/02 & 15/03 +#define META_PROCESSING_ERROR 0x0001 // Meta processing error server reply +#define META_SMS_DELIVERY_RECEIPT 0x0096 // Server SMS response (delivery receipt) +#define META_SET_PASSWORD_ACK 0x00AA // Set user password server ack +#define META_UNREGISTER_ACK 0x00B4 // Unregister account server ack +#define META_BASIC_USERINFO 0x00C8 // User basic info reply +#define META_WORK_USERINFO 0x00D2 // User work info reply +#define META_MORE_USERINFO 0x00DC // User more info reply +#define META_NOTES_USERINFO 0x00E6 // User notes (about) info reply +#define META_EMAIL_USERINFO 0x00EB // User extended email info reply +#define META_INTERESTS_USERINFO 0x00F0 // User interests info reply +#define META_AFFILATIONS_USERINFO 0x00FA // User past/affilations info reply +#define META_SHORT_USERINFO 0x0104 // Short user information reply +#define META_HPAGECAT_USERINFO 0x010E // User homepage category information reply +#define SRV_USER_FOUND 0x01A4 // Search: user found reply +#define SRV_LAST_USER_FOUND 0x01AE // Search: last user found reply +#define META_REGISTRATION_STATS_ACK 0x0302 // Registration stats ack +#define SRV_RANDOM_FOUND 0x0366 // Random search server reply +#define META_SET_PASSWORD_REQ 0x042E // Set user password request +#define META_REQUEST_FULL_INFO 0x04B2 // Request full user info +#define META_REQUEST_SHORT_INFO 0x04BA // Request short user info +#define META_REQUEST_SELF_INFO 0x04D0 // Request full self user info +#define META_SEARCH_GENERIC 0x055F // Search user by details (TLV) +#define META_SEARCH_UIN 0x0569 // Search user by UIN (TLV) +#define META_SEARCH_EMAIL 0x0573 // Search user by E-mail (TLV) +#define META_DIRECTORY_QUERY 0x0FA0 +#define META_DIRECTORY_DATA 0x0FAA +#define META_DIRECTORY_RESPONSE 0x0FB4 +#define META_DIRECTORY_UPDATE 0x0FD2 +#define META_DIRECTORY_UPDATE_ACK 0x0FDC + +#define META_XML_INFO 0x08A2 // Server variable requested via xml +#define META_SET_FULLINFO_REQ 0x0C3A // Set full user info request +#define META_SET_FULLINFO_ACK 0x0C3F // Server ack for set fullinfo command +#define META_SPAM_REPORT_ACK 0x2012 // Server ack for user spam report + +// Subtypes for Directory meta requests (family 0x5b9) +#define DIRECTORY_QUERY_INFO 0x0002 +#define DIRECTORY_SET_INFO 0x0003 +#define DIRECTORY_QUERY_MULTI_INFO 0x0006 +#define DIRECTORY_QUERY_INFO_ACK 0x0009 +#define DIRECTORY_SET_INFO_ACK 0x000A + +// TLV types + +// SECURITY flags +#define TLV_AUTH 0x02F8 // uint8 User authorization permissions +#define TLV_WEBAWARE 0x030C // uint8 User 'show web status' permissions + + +// SEARCH only TLVs +#define TLV_AGERANGE 0x0168 // acombo Age range to search +#define TLV_KEYWORDS 0x0226 // sstring Whitepages search keywords string +#define TLV_ONLINEONLY 0x0230 // uint8 Search only online users flag +#define TLV_UIN 0x0136 // uint32 User uin + +// common +#define TLV_FIRSTNAME 0x0140 // sstring User firstname +#define TLV_LASTNAME 0x014A // sstring User lastname +#define TLV_NICKNAME 0x0154 // sstring User nickname +#define TLV_EMAIL 0x015E // ecombo User email +#define TLV_GENDER 0x017C // uint8 User gender +#define TLV_MARITAL 0x033E // uint8 User marital status +#define TLV_LANGUAGE 0x0186 // uint16 User spoken language +#define TLV_CITY 0x0190 // sstring User home city name +#define TLV_STATE 0x019A // sstring User home state abbr +#define TLV_COUNTRY 0x01A4 // uint16 User home country code +#define TLV_COMPANY 0x01AE // sstring User work company name +#define TLV_DEPARTMENT 0x01B8 // sstring User work department name +#define TLV_POSITION 0x01C2 // sstring User work position (title) +#define TLV_OCUPATION 0x01CC // uint16 User work ocupation code +#define TLV_PASTINFO 0x01D6 // icombo User affilations node +#define TLV_AFFILATIONS 0x01FE // icombo User past info node +#define TLV_INTERESTS 0x01EA // icombo User interests node +#define TLV_HOMEPAGE 0x0212 // sstring User homepage category/keywords + +// changeinfo +#define TLV_AGE 0x0172 // uint16 User age +#define TLV_URL 0x0213 // sstring User homepage url +#define TLV_BIRTH 0x023A // bcombo User birthday info (year, month, day) +#define TLV_ABOUT 0x0258 // sstring User notes (about) text +#define TLV_STREET 0x0262 // sstring User home street address +#define TLV_ZIPCODE 0x026D // sstring User home zip code +#define TLV_PHONE 0x0276 // sstring User home phone number +#define TLV_FAX 0x0280 // sstring User home fax number +#define TLV_MOBILE 0x028A // sstring User home cellular phone number +#define TLV_WORKSTREET 0x0294 // sstring User work street address +#define TLV_WORKCITY 0x029E // sstring User work city name +#define TLV_WORKSTATE 0x02A8 // sstring User work state name +#define TLV_WORKCOUNTRY 0x02B2 // uint16 User work country code +#define TLV_WORKZIPCODE 0x02BD // sstring User work zip code +#define TLV_WORKPHONE 0x02C6 // sstring User work phone number +#define TLV_WORKFAX 0x02D0 // sstring User work fax number +#define TLV_WORKURL 0x02DA // sstring User work webpage url +#define TLV_TIMEZONE 0x0316 // uint8 User GMT offset +#define TLV_ORGCITY 0x0320 // sstring User originally from city +#define TLV_ORGSTATE 0x032A // sstring User originally from state +#define TLV_ORGCOUNTRY 0x0334 // uint16 User originally from country (code) +#define TLV_ALLOWSPAM 0x0348 // uint8 +#define TLV_CODEPAGE 0x0352 // uint16 Codepage used for details + + +/* Direct packet types */ +#define PEER_INIT 0xFF +#define PEER_INIT_ACK 0x01 +#define PEER_MSG_INIT 0x03 +#define PEER_MSG 0x02 +#define PEER_FILE_INIT 0x00 +#define PEER_FILE_INIT_ACK 0x01 +#define PEER_FILE_NEXTFILE 0x02 +#define PEER_FILE_RESUME 0x03 +#define PEER_FILE_STOP 0x04 +#define PEER_FILE_SPEED 0x05 +#define PEER_FILE_DATA 0x06 + +/* Direct command types */ +#define DIRECT_CANCEL 0x07D0 /* 2000 TCP cancel previous file/chat request */ +#define DIRECT_ACK 0x07DA /* 2010 TCP acknowledge message packet */ +#define DIRECT_MESSAGE 0x07EE /* 2030 TCP message */ + +// DC types +#define DC_DISABLED 0x0000 // Direct connection disabled / auth required +#define DC_HTTPS 0x0001 // Direct connection thru firewall or https proxy +#define DC_SOCKS 0x0002 // Direct connection thru socks4/5 proxy server +#define DC_NORMAL 0x0004 // Normal direct connection (without proxy/firewall) +#define DC_WEB 0x0006 // Web client - no direct connection + +// Message flags +#define MFLAG_NORMAL 0x01 // Normal message +#define MFLAG_AUTO 0x03 // Auto-message flag +#define MFLAG_MULTI 0x80 // This is multiple recipients message + +// Some SSI constants +#define SSI_ITEM_BUDDY 0x0000 // Buddy record (name: uin for ICQ and screenname for AIM) +#define SSI_ITEM_GROUP 0x0001 // Group record +#define SSI_ITEM_PERMIT 0x0002 // Permit record ("Allow" list in AIM, and "Visible" list in ICQ) +#define SSI_ITEM_DENY 0x0003 // Deny record ("Block" list in AIM, and "Invisible" list in ICQ) +#define SSI_ITEM_VISIBILITY 0x0004 // Permit/deny settings or/and bitmask of the AIM classes +#define SSI_ITEM_PRESENCE 0x0005 // Presence info (if others can see your idle status, etc) +#define SSI_ITEM_CLIENTDATA 0x0009 // Client specific, e.g. ICQ2k shortcut bar items +#define SSI_ITEM_IGNORE 0x000e // Ignore list record. +#define SSI_ITEM_LASTUPDATE 0x000f // Item that contain roster update time (name: "LastUpdateDate") +#define SSI_ITEM_NONICQ 0x0010 // Non-ICQ contact (to send SMS). Name: 1#EXT, 2#EXT, etc +#define SSI_ITEM_UNKNOWN2 0x0011 // Unknown. +#define SSI_ITEM_IMPORTTIME 0x0013 // Item that contain roster import time (name: "Import time") +#define SSI_ITEM_BUDDYICON 0x0014 // Buddy icon info. (names: "1", "8", etc. according ot the icon type) +#define SSI_ITEM_SAVED 0x0019 +#define SSI_ITEM_PREAUTH 0x001B +#define SSI_ITEM_METAINFO 0x0020 // Owner Details' token & last update time + +#define SSI_TLV_AWAITING_AUTH 0x0066 // Contact not authorized in list +#define SSI_TLV_NOT_IN_LIST 0x006A // Always empty +#define SSI_TLV_UNKNOWN 0x006D // WTF ? +#define SSI_TLV_SUBITEMS 0x00C8 // List of sub-items IDs +#define SSI_TLV_VISIBILITY 0x00CA +#define SSI_TLV_SHORTCUT 0x00CD +#define SSI_TLV_TIMESTAMP 0x00D4 // Import Timestamp +#define SSI_TLV_AVATARHASH 0x00D5 +#define SSI_TLV_NAME 0x0131 // Custom contact nickname +#define SSI_TLV_GROUP_OPENNED 0x0134 +#define SSI_TLV_EMAIL 0x0137 // Custom contact email +#define SSI_TLV_PHONE 0x0138 // Custom contact phone number +#define SSI_TLV_PHONE_CELLULAR 0x0139 // Custom contact cellphone number +#define SSI_TLV_PHONE_SMS 0x013A // Custom contact SMS number +#define SSI_TLV_COMMENT 0x013C // User comment +#define SSI_TLV_METAINFO_TOKEN 0x015C // Privacy token for Contact's details +#define SSI_TLV_METAINFO_TIME 0x015D // Contact's details last update time + +#define MAX_SSI_TLV_NAME_SIZE 0x40 +#define MAX_SSI_TLV_COMMENT_SIZE 0x50 + +// Client ID constants (internal) +#define CLID_GENERIC 0x00 // Generic clients (eg. older official clients) +#define CLID_ALTERNATIVE 0x01 // Clients not using tick for MsgID (most third-party clients) +#define CLID_MIRANDA 0x02 // Hey, that's mate! +#define CLID_ICQ6 0x10 // Mark ICQ6 as it has some non obvious limitations! + + +// Internal Constants +#define ICQ_PROTOCOL_NAME LPGEN("ICQ") +#define ICQ_PLUG_VERSION __VERSION_DWORD +#define ICQ_VERSION 8 // Protocol version +#define DC_TYPE DC_NORMAL // Used for DC settings +#define MAX_CONTACTSSEND 15 +#define MAX_MESSAGESNACSIZE 8000 +#define CLIENTRATELIMIT 0 +#define COOKIE_TIMEOUT 3600 // One hour +#define KEEPALIVE_INTERVAL 57000 // One minute +#define WEBFRONTPORT 0x50 +#define CLIENTFEATURES 0x3 +#define URL_FORGOT_PASSWORD "https://www.icq.com/password/" +#define URL_REGISTER "https://www.icq.com/register/" +#define FLAP_MARKER 0x2a +#define CLIENT_MD5_STRING "AOL Instant Messenger (SM)" +#define UNIQUEIDSETTING "UIN" +#define UINMAXLEN 11 // DWORD string max len + 1 +#define PASSWORDMAXLEN 128 +#define OSCAR_PROXY_HOST "ars.icq.com" +#define OSCAR_PROXY_VERSION 0x044A + +#define CLIENT_ID_STRING "ICQ Client" // Client identification, mimic ICQ 6.5 +#define CLIENT_ID_CODE 0x010a +#define CLIENT_VERSION_MAJOR 0x0014 +#define CLIENT_VERSION_MINOR 0x0034 +#define CLIENT_VERSION_LESSER 0x0000 +#define CLIENT_VERSION_BUILD 0x0c18 +#define CLIENT_DISTRIBUTION 0x00000611 +#define CLIENT_LANGUAGE "en" +#define CLIENT_COUNTRY "us" + +#endif /* __ICQ_CONSTANTS_H */ diff --git a/protocols/IcqOscarJ/src/icq_db.cpp b/protocols/IcqOscarJ/src/icq_db.cpp new file mode 100644 index 0000000000..f199860df8 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_db.cpp @@ -0,0 +1,399 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Internal Database API +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::CreateResidentSetting(const char *szSetting) +{ + char pszSetting[2*MAX_PATH]; + + strcpy(pszSetting, m_szModuleName); + strcat(pszSetting, "/"); + strcat(pszSetting, szSetting); + CallService(MS_DB_SETSETTINGRESIDENT, 1, (WPARAM)pszSetting); +} + + +int CIcqProto::getSetting(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) +{ + return DBGetContactSettingW(hContact, m_szModuleName, szSetting, dbv); +} + + +BYTE CIcqProto::getSettingByte(HANDLE hContact, const char *szSetting, BYTE byDef) +{ + return DBGetContactSettingByte(hContact, m_szModuleName, szSetting, byDef); +} + + +WORD CIcqProto::getSettingWord(HANDLE hContact, const char *szSetting, WORD wDef) +{ + return DBGetContactSettingWord(hContact, m_szModuleName, szSetting, wDef); +} + + +DWORD CIcqProto::getSettingDword(HANDLE hContact, const char *szSetting, DWORD dwDef) +{ + DBVARIANT dbv = {DBVT_DELETED}; + DWORD dwRes; + + if (getSetting(hContact, szSetting, &dbv)) + return dwDef; // not found, give default + + if (dbv.type != DBVT_DWORD) + dwRes = dwDef; // invalid type, give default + else // found and valid, give result + dwRes = dbv.dVal; + + ICQFreeVariant(&dbv); + return dwRes; +} + + +double CIcqProto::getSettingDouble(HANDLE hContact, const char *szSetting, double dDef) +{ + DBVARIANT dbv = {DBVT_DELETED}; + double dRes; + + if (getSetting(hContact, szSetting, &dbv)) + return dDef; // not found, give default + + if (dbv.type != DBVT_BLOB || dbv.cpbVal != sizeof(double)) + dRes = dDef; + else + dRes = *(double*)dbv.pbVal; + + ICQFreeVariant(&dbv); + return dRes; +} + + +DWORD CIcqProto::getContactUin(HANDLE hContact) +{ + return getSettingDword(hContact, UNIQUEIDSETTING, 0); +} + + +int CIcqProto::getContactUid(HANDLE hContact, DWORD *pdwUin, uid_str *ppszUid) +{ + DBVARIANT dbv = {DBVT_DELETED}; + int iRes = 1; + + *pdwUin = 0; + if (ppszUid) *ppszUid[0] = '\0'; + + if (!getSetting(hContact, UNIQUEIDSETTING, &dbv)) + { + if (dbv.type == DBVT_DWORD) + { + *pdwUin = dbv.dVal; + iRes = 0; + } + else if (dbv.type == DBVT_ASCIIZ) + { + if (ppszUid && m_bAimEnabled) + { + strcpy(*ppszUid, dbv.pszVal); + iRes = 0; + } + else + NetLog_Server("AOL screennames not accepted"); + } + ICQFreeVariant(&dbv); + } + return iRes; +} + + +int CIcqProto::getSettingString(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) +{ + int res = DBGetContactSettingString(hContact, m_szModuleName, szSetting, dbv); + + if (res) + ICQFreeVariant(dbv); + + return res; +} + + +int CIcqProto::getSettingStringW(HANDLE hContact, const char *szSetting, DBVARIANT *dbv) +{ + int res = DBGetContactSettingWString(hContact, m_szModuleName, szSetting, dbv); + + if (res) + ICQFreeVariant(dbv); + + return res; +} + + +char* CIcqProto::getSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, char *szDef) +{ + DBVARIANT dbv = {DBVT_DELETED}; + + if (DBGetContactSettingUTF8String(hContact, szModule, szSetting, &dbv)) + { + ICQFreeVariant(&dbv); // for a setting with invalid contents/type + return null_strdup(szDef); + } + + char *szRes = null_strdup(dbv.pszVal); + ICQFreeVariant(&dbv); + return szRes; +} + + +char* CIcqProto::getSettingStringUtf(HANDLE hContact, const char *szSetting, char *szDef) +{ + return getSettingStringUtf(hContact, m_szModuleName, szSetting, szDef); +} + + +WORD CIcqProto::getContactStatus(HANDLE hContact) +{ + return getSettingWord(hContact, "Status", ID_STATUS_OFFLINE); +} + + +int CIcqProto::getSettingStringStatic(HANDLE hContact, const char *szSetting, char *dest, int dest_len) +{ + DBVARIANT dbv = {DBVT_DELETED}; + DBCONTACTGETSETTING sVal = {0}; + + dbv.pszVal = dest; + dbv.cchVal = dest_len; + dbv.type = DBVT_ASCIIZ; + + sVal.pValue = &dbv; + sVal.szModule = m_szModuleName; + sVal.szSetting = szSetting; + + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0) + { // due to MS_DB_CONTACT_GETSETTINGSTATIC setting type check, we need to request UTF8 as well + dbv.pszVal = dest; + dbv.cchVal = dest_len; + dbv.type = DBVT_UTF8; + + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&sVal) != 0) + return 1; // nothing found + } + + return (dbv.type != DBVT_ASCIIZ); +} + + +int CIcqProto::deleteSetting(HANDLE hContact, const char *szSetting) +{ + return DBDeleteContactSetting(hContact, m_szModuleName, szSetting); +} + + +int CIcqProto::setSettingByte(HANDLE hContact, const char *szSetting, BYTE byValue) +{ + return DBWriteContactSettingByte(hContact, m_szModuleName, szSetting, byValue); +} + + +int CIcqProto::setSettingWord(HANDLE hContact, const char *szSetting, WORD wValue) +{ + return DBWriteContactSettingWord(hContact, m_szModuleName, szSetting, wValue); +} + + +int CIcqProto::setSettingDword(HANDLE hContact, const char *szSetting, DWORD dwValue) +{ + return DBWriteContactSettingDword(hContact, m_szModuleName, szSetting, dwValue); +} + + +int CIcqProto::setSettingDouble(HANDLE hContact, const char *szSetting, double dValue) +{ + return setSettingBlob(hContact, szSetting, (BYTE*)&dValue, sizeof(double)); +} + + +int CIcqProto::setSettingString(HANDLE hContact, const char *szSetting, const char *szValue) +{ + return DBWriteContactSettingString(hContact, m_szModuleName, szSetting, szValue); +} + + +int CIcqProto::setSettingStringW(HANDLE hContact, const char *szSetting, const WCHAR *wszValue) +{ + return DBWriteContactSettingWString(hContact, m_szModuleName, szSetting, wszValue); +} + + +int CIcqProto::setSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, const char *szValue) +{ + return DBWriteContactSettingUTF8String(hContact, szModule, szSetting, (char*)szValue); +} + + +int CIcqProto::setSettingStringUtf(HANDLE hContact, const char *szSetting, const char *szValue) +{ + return setSettingStringUtf(hContact, m_szModuleName, szSetting, szValue); +} + + +int CIcqProto::setSettingBlob(HANDLE hContact, const char *szSetting, const BYTE *pValue, const int cbValue) +{ + return DBWriteContactSettingBlob(hContact, m_szModuleName, szSetting, (void*)pValue, cbValue); +} + + +int CIcqProto::setContactHidden(HANDLE hContact, BYTE bHidden) +{ + int nResult = DBWriteContactSettingByte(hContact, "CList", "Hidden", bHidden); + + if (!bHidden) // clear zero setting + DBDeleteContactSetting(hContact, "CList", "Hidden"); + + return nResult; +} + +void CIcqProto::setStatusMsgVar(HANDLE hContact, char* szStatusMsg, bool isAnsi) +{ + if (szStatusMsg && szStatusMsg[0]) + { + if (isAnsi) + { + char* szStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, ""); + wchar_t* szStatusNoteW = make_unicode_string(szStatusNote); + int len = (int)wcslen(szStatusNoteW) * 3 + 1; + char* szStatusNoteAnsi = (char*)alloca(len); + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, szStatusNoteW, -1, szStatusNoteAnsi, len, NULL, NULL); + bool notmatch = false; + for (int i=0; ;++i) + { + if (szStatusNoteAnsi[i] != szStatusMsg[i] && szStatusNoteAnsi[i] != '?' && szStatusMsg[i] != '?') + { + notmatch = true; + break; + } + if (!szStatusNoteAnsi[i] || !szStatusMsg[i]) + break; + } + szStatusMsg = notmatch ? ansi_to_utf8(szStatusMsg) : szStatusNote; + SAFE_FREE(&szStatusNoteW); + if (notmatch) SAFE_FREE(&szStatusNote); + } + + char* oldStatusMsg = NULL; + DBVARIANT dbv; + if (!DBGetContactSetting(hContact, "CList", "StatusMsg", &dbv)) + { + switch (dbv.type) + { + case DBVT_UTF8: + oldStatusMsg = null_strdup(dbv.pszVal); + break; + + case DBVT_WCHAR: + oldStatusMsg = make_utf8_string(dbv.pwszVal); + break; + } + ICQFreeVariant(&dbv); + } + + if (!oldStatusMsg || strcmp(oldStatusMsg, szStatusMsg)) + setSettingStringUtf(hContact, "CList", "StatusMsg", szStatusMsg); + SAFE_FREE(&oldStatusMsg); + if (isAnsi) SAFE_FREE(&szStatusMsg); + } + else + DBDeleteContactSetting(hContact, "CList", "StatusMsg"); +} + +int __fastcall ICQFreeVariant(DBVARIANT *dbv) +{ + return DBFreeVariant(dbv); +} + + +int CIcqProto::IsICQContact(HANDLE hContact) +{ + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + return !strcmpnull(szProto, m_szModuleName); +} + + +HANDLE CIcqProto::AddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob) +{ + DBEVENTINFO dbei = {0}; + + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.timestamp = dwTime; + dbei.flags = flags; + dbei.eventType = wType; + dbei.cbBlob = cbBlob; + dbei.pBlob = pBlob; + + return (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); +} + + +HANDLE CIcqProto::FindFirstContact() +{ + HANDLE hContact = db_find_first(m_szModuleName); + + if (IsICQContact(hContact)) + return hContact; + + return FindNextContact(hContact); +} + + +HANDLE CIcqProto::FindNextContact(HANDLE hContact) +{ + hContact = db_find_next(hContact, m_szModuleName); + while (hContact != NULL) + { + if (IsICQContact(hContact)) + return hContact; + hContact = db_find_next(hContact, m_szModuleName); + } + return hContact; +} + + +char* CIcqProto::getContactCListGroup(HANDLE hContact) +{ + return getSettingStringUtf(hContact, "CList", "Group", NULL); +} + + +int __stdcall ICQSetContactCListGroup(HANDLE hContact, const char *szGroup) +{ + /// TODO + return 0; +} diff --git a/protocols/IcqOscarJ/src/icq_db.h b/protocols/IcqOscarJ/src/icq_db.h new file mode 100644 index 0000000000..5bfc22d58b --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_db.h @@ -0,0 +1,44 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_DB_H +#define __ICQ_DB_H + + +#ifdef _UNICODE + #define getSettingStringT getSettingStringW + #define setSettingStringT setSettingStringW +#else + #define getSettingStringT getSettingString + #define setSettingStringT setSettingString +#endif + +int __fastcall ICQFreeVariant(DBVARIANT* dbv); + +#endif /* __ICQ_DB_H */ diff --git a/protocols/IcqOscarJ/src/icq_direct.cpp b/protocols/IcqOscarJ/src/icq_direct.cpp new file mode 100644 index 0000000000..7779f1bad7 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_direct.cpp @@ -0,0 +1,1171 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +struct directthreadstartinfo +{ + int type; // Only valid for outgoing connections + int incoming; // 1=incoming, 0=outgoing + HANDLE hConnection; // only valid for incoming connections, handle to the connection + HANDLE hContact; // Only valid for outgoing connections + void* pvExtra; // Only valid for outgoing connections +}; + +static char client_check_data[] = { + "As part of this software beta version Mirabilis is " + "granting a limited access to the ICQ network, " + "servers, directories, listings, information and databases (\"" + "ICQ Services and Information\"). The " + "ICQ Service and Information may databases (\"" + "ICQ Services and Information\"). The " + "ICQ Service and Information may\0" +}; + +void CIcqProto::CloseContactDirectConns(HANDLE hContact) +{ + icq_lock l(directConnListMutex); + + for ( int i = 0; i < directConns.getCount(); i++) + { + if (!hContact || directConns[i]->hContact == hContact) + { + HANDLE hConnection = directConns[i]->hConnection; + + directConns[i]->hConnection = NULL; // do not allow reuse + NetLib_CloseConnection(&hConnection, FALSE); + } + } +} + + +directconnect* CIcqProto::FindFileTransferDC(filetransfer* ft) +{ + directconnect* dc = NULL; + icq_lock l(directConnListMutex); + + for (int i = 0; i < directConns.getCount(); i++) + { + if ( directConns[i]->ft == ft ) + { + dc = directConns[i]; + break; + } + } + + return dc; +} + + +filetransfer* CIcqProto::FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize) +{ + filetransfer* pFt = NULL; + icq_lock l(expectedFileRecvMutex); + + for (int i = 0; i < expectedFileRecvs.getCount(); i++) + { + if (expectedFileRecvs[i]->dwUin == dwUin && expectedFileRecvs[i]->dwTotalSize == dwTotalSize) + { + pFt = expectedFileRecvs[i]; + expectedFileRecvs.remove( i ); + break; + } + } + + return pFt; +} + + +int CIcqProto::sendDirectPacket(directconnect* dc, icq_packet* pkt) +{ + int nResult = Netlib_Send(dc->hConnection, (const char*)pkt->pData, pkt->wLen + 2, 0); + if (nResult == SOCKET_ERROR) + { + NetLog_Direct("Direct %p socket error: %d, closing", dc->hConnection, GetLastError()); + CloseDirectConnection(dc); + } + + SAFE_FREE((void**)&pkt->pData); + + return nResult; +} + +directthreadstartinfo* CreateDTSI(HANDLE hContact, HANDLE hConnection, int type) +{ + directthreadstartinfo* dtsi = (directthreadstartinfo*)SAFE_MALLOC(sizeof(directthreadstartinfo)); + dtsi->hContact = hContact; + dtsi->hConnection = hConnection; + if (type == -1) + dtsi->incoming = 1; + else + dtsi->type = type; + + return dtsi; +} + +// Check if we have an open and initialized DC with type +// 'type' to the specified contact +BOOL CIcqProto::IsDirectConnectionOpen(HANDLE hContact, int type, int bPassive) +{ + BOOL bIsOpen = FALSE, bIsCreated = FALSE; + + { + icq_lock l(directConnListMutex); + + for (int i = 0; i < directConns.getCount(); i++) + { + if (directConns[i] && (directConns[i]->type == type)) + { + if (directConns[i]->hContact == hContact) + if (directConns[i]->initialised) + { + // Connection is OK + bIsOpen = TRUE; + // we are going to use the conn, so prevent timeout + directConns[i]->packetPending = 1; + break; + } + else + bIsCreated = TRUE; // we found pending connection + } + } + } + + if (!bPassive && !bIsCreated && !bIsOpen && type == DIRECTCONN_STANDARD && m_bDCMsgEnabled == 2) + { // do not try to open DC to offline contact + if (getContactStatus(hContact) == ID_STATUS_OFFLINE) return FALSE; + // do not try to open DC if previous attempt was not successfull + if (getSettingByte(hContact, "DCStatus", 0)) return FALSE; + + // Set DC status as tried + setSettingByte(hContact, "DCStatus", 1); + // Create a new connection + OpenDirectConnection(hContact, DIRECTCONN_STANDARD, NULL); + } + + return bIsOpen; +} + +// This function is called from the Netlib when someone is connecting to +// one of our incomming DC ports +void icq_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra) +{ + // Start a new thread for the incomming connection + CIcqProto* ppro = (CIcqProto*)pExtra; + ppro->ForkThread(( IcqThreadFunc )&CIcqProto::icq_directThread, CreateDTSI(NULL, hNewConnection, -1)); +} + +// Opens direct connection of specified type to specified contact +void CIcqProto::OpenDirectConnection(HANDLE hContact, int type, void* pvExtra) +{ + // Create a new connection + directthreadstartinfo* dtsi = CreateDTSI(hContact, NULL, type); + dtsi->pvExtra = pvExtra; + ForkThread(( IcqThreadFunc )&CIcqProto::icq_directThread, dtsi); +} + +// Safely close NetLib connection - do not corrupt direct connection list +void CIcqProto::CloseDirectConnection(directconnect *dc) +{ + icq_lock l(directConnListMutex); + + NetLib_CloseConnection(&dc->hConnection, FALSE); +#ifdef _DEBUG + if (dc->hConnection) + NetLog_Direct("Direct conn closed (%p)", dc->hConnection); +#endif +} + +// Called from icq_newConnectionReceived when a new incomming dc is done +// Called from OpenDirectConnection when a new outgoing dc is done +// Called from SendDirectMessage when a new outgoing dc is done + +void __cdecl CIcqProto::icq_directThread( directthreadstartinfo *dtsi ) +{ + directconnect dc = {0}; + NETLIBPACKETRECVER packetRecv={0}; + HANDLE hPacketRecver; + BOOL bFirstPacket = TRUE; + int nSkipPacketBytes = 0; + DWORD dwReqMsgID1; + DWORD dwReqMsgID2; + + srand(time(NULL)); + + { // add to DC connection list + icq_lock l(directConnListMutex); + directConns.insert( &dc ); + } + + // Initialize DC struct + dc.hContact = dtsi->hContact; + dc.dwThreadId = GetCurrentThreadId(); + dc.incoming = dtsi->incoming; + dc.hConnection = dtsi->hConnection; + dc.ft = NULL; + + if (!dc.incoming) + { + dc.type = dtsi->type; + dc.dwRemoteExternalIP = getSettingDword(dtsi->hContact, "IP", 0); + dc.dwRemoteInternalIP = getSettingDword(dtsi->hContact, "RealIP", 0); + dc.dwRemotePort = getSettingWord(dtsi->hContact, "UserPort", 0); + dc.dwRemoteUin = getContactUin(dtsi->hContact); + dc.dwConnectionCookie = getSettingDword(dtsi->hContact, "DirectCookie", 0); + dc.wVersion = getSettingWord(dtsi->hContact, "Version", 0); + + if (!dc.dwRemoteExternalIP && !dc.dwRemoteInternalIP) + { // we do not have any ip, do not try to connect + SAFE_FREE((void**)&dtsi); + goto LBL_Exit; + } + if (!dc.dwRemotePort) + { // we do not have port, do not try to connect + SAFE_FREE((void**)&dtsi); + goto LBL_Exit; + } + + if (dc.type == DIRECTCONN_STANDARD) + { + // do nothing - some specific init for msg sessions + } + else if (dc.type == DIRECTCONN_FILE) + { + dc.ft = (filetransfer*)dtsi->pvExtra; + dc.dwRemotePort = dc.ft->dwRemotePort; + } + else if (dc.type == DIRECTCONN_REVERSE) + { + cookie_reverse_connect *pCookie = (cookie_reverse_connect*)dtsi->pvExtra; + + dwReqMsgID1 = pCookie->dwMsgID1; + dwReqMsgID2 = pCookie->dwMsgID2; + dc.dwReqId = (DWORD)pCookie->ft; + SAFE_FREE((void**)&pCookie); + } + } + else + { + dc.type = DIRECTCONN_STANDARD; + } + + SAFE_FREE((void**)&dtsi); + + // Load local IP information + dc.dwLocalExternalIP = getSettingDword(NULL, "IP", 0); + dc.dwLocalInternalIP = getSettingDword(NULL, "RealIP", 0); + + // Create outgoing DC + if (!dc.incoming) + { + NETLIBOPENCONNECTION nloc = {0}; + IN_ADDR addr = {0}, addr2 = {0}; + + if (dc.dwRemoteExternalIP == dc.dwLocalExternalIP && dc.dwRemoteInternalIP) + addr.S_un.S_addr = htonl(dc.dwRemoteInternalIP); + else + { + addr.S_un.S_addr = htonl(dc.dwRemoteExternalIP); + // for different internal, try it also (for LANs with multiple external IP, VPNs, etc.) + if (dc.dwRemoteInternalIP != dc.dwRemoteExternalIP) + addr2.S_un.S_addr = htonl(dc.dwRemoteInternalIP); + } + + // IP to connect to is empty, go away + if (!addr.S_un.S_addr) + goto LBL_Exit; + + nloc.szHost = inet_ntoa(addr); + nloc.wPort = (WORD)dc.dwRemotePort; + nloc.timeout = 8; // 8 secs to connect + dc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, dc.type==DIRECTCONN_REVERSE?"Reverse ":NULL, &nloc); + if (!dc.hConnection && addr2.S_un.S_addr) + { // first address failed, try second one if available + nloc.szHost = inet_ntoa(addr2); + dc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, dc.type==DIRECTCONN_REVERSE?"Reverse ":NULL, &nloc); + } + if (!dc.hConnection) + { + if (CheckContactCapabilities(dc.hContact, CAPF_ICQDIRECT)) + { // only if the contact support ICQ DC connections + if (dc.type != DIRECTCONN_REVERSE) + { // try reverse connect + cookie_reverse_connect *pCookie = (cookie_reverse_connect*)SAFE_MALLOC(sizeof(cookie_reverse_connect)); + DWORD dwCookie; + + NetLog_Direct("connect() failed (%d), trying reverse.", GetLastError()); + + if (pCookie) + { // init cookie + InitMessageCookie(pCookie); + pCookie->bMessageType = MTYPE_REVERSE_REQUEST; + pCookie->hContact = dc.hContact; + pCookie->dwUin = dc.dwRemoteUin; + pCookie->type = dc.type; + pCookie->ft = dc.ft; + dwCookie = AllocateCookie(CKT_REVERSEDIRECT, 0, dc.hContact, pCookie); + icq_sendReverseReq(&dc, dwCookie, (cookie_message_data*)pCookie); + goto LBL_Exit; + } + + NetLog_Direct("Reverse failed (%s)", "malloc failed"); + } + } + else // Set DC status to failed + setSettingByte(dc.hContact, "DCStatus", 2); + + if (dc.type == DIRECTCONN_REVERSE) // failed reverse connection + { // announce we failed + icq_sendReverseFailed(&dc, dwReqMsgID1, dwReqMsgID2, dc.dwReqId); + } + NetLog_Direct("connect() failed (%d)", GetLastError()); + if (dc.type == DIRECTCONN_FILE) + { + BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&dc.ft); + } + goto LBL_Exit; + } + + if (dc.type == DIRECTCONN_FILE) + dc.ft->hConnection = dc.hConnection; + + if (dc.wVersion > 6) + { + sendPeerInit_v78(&dc); + } + else + { + NetLog_Direct("Error: Unsupported direct protocol: %d, closing.", dc.wVersion); + CloseDirectConnection(&dc); + goto LBL_Exit; + } + } + + hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)dc.hConnection, 8192); + packetRecv.cbSize = sizeof(packetRecv); + packetRecv.bytesUsed = 0; + + // Packet receiving loop + + while (dc.hConnection) + { + int recvResult; + + packetRecv.dwTimeout = dc.wantIdleTime ? 0 : 600000; + + recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); + if (recvResult == 0) + { + NetLog_Direct("Clean closure of direct socket (%p)", dc.hConnection); + break; + } + + if (recvResult == SOCKET_ERROR) + { + if (GetLastError() == ERROR_TIMEOUT) + { // TODO: this will not work on some systems + if (dc.wantIdleTime) + { + switch (dc.type) + { + case DIRECTCONN_FILE: + handleFileTransferIdle(&dc); + break; + } + } + else if (dc.packetPending) + { // do we expect packet soon? + NetLog_Direct("Keeping connection, packet pending."); + } + else + { + NetLog_Direct("Connection inactive for 10 minutes, closing."); + break; + } + } + else + { + NetLog_Direct("Abortive closure of direct socket (%p) (%d)", dc.hConnection, GetLastError()); + break; + } + } + + if (dc.type == DIRECTCONN_CLOSING) + packetRecv.bytesUsed = packetRecv.bytesAvailable; + else if (packetRecv.bytesAvailable < nSkipPacketBytes) + { // the whole buffer needs to be skipped + nSkipPacketBytes -= packetRecv.bytesAvailable; + packetRecv.bytesUsed = packetRecv.bytesAvailable; + } + else + { + int i; + + for (i = nSkipPacketBytes, nSkipPacketBytes = 0; i + 2 <= packetRecv.bytesAvailable;) + { + WORD wLen = *(WORD*)(packetRecv.buffer + i); + + if (bFirstPacket) + { + if (wLen > 64) + { // roughly check first packet size + NetLog_Direct("Error: Overflowed packet, closing connection."); + CloseDirectConnection(&dc); + break; + } + bFirstPacket = FALSE; + } + else + { + if (packetRecv.bytesAvailable >= i + 2 && wLen > 8190) + { // check for too big packages + NetLog_Direct("Error: Package too big: %d bytes, skipping."); + nSkipPacketBytes = wLen; + packetRecv.bytesUsed = i + 2; + break; + } + } + + if (wLen + 2 + i > packetRecv.bytesAvailable) + break; + + if (dc.type == DIRECTCONN_STANDARD && wLen && packetRecv.buffer[i + 2] == 2) + { + if (!DecryptDirectPacket(&dc, packetRecv.buffer + i + 3, (WORD)(wLen - 1))) + { + NetLog_Direct("Error: Corrupted packet encryption, ignoring packet"); + i += wLen + 2; + continue; + } + } +#ifdef _DEBUG + NetLog_Direct("New direct package"); +#endif + if (dc.type == DIRECTCONN_FILE && dc.initialised) + handleFileTransferPacket(&dc, packetRecv.buffer + i + 2, wLen); + else + handleDirectPacket(&dc, packetRecv.buffer + i + 2, wLen); + + i += wLen + 2; + } + packetRecv.bytesUsed = i; + } + } + + // End of packet receiving loop + + NetLib_SafeCloseHandle(&hPacketRecver); + CloseDirectConnection(&dc); + + if (dc.ft) + { + if (dc.ft->fileId != -1) + { + _close(dc.ft->fileId); + BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, dc.ft->dwBytesDone==dc.ft->dwTotalSize ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, dc.ft, 0); + } + else if (dc.ft->hConnection) + BroadcastAck(dc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, dc.ft, 0); + + SafeReleaseFileTransfer((void**)&dc.ft); + _chdir("\\"); /* so we don't leave a subdir handle open so it can't be deleted */ + } + +LBL_Exit: + { // remove from DC connection list + icq_lock l(directConnListMutex); + directConns.remove( &dc ); + } +} + + +void CIcqProto::handleDirectPacket(directconnect* dc, PBYTE buf, WORD wLen) +{ + if (wLen < 1) + return; + + switch (buf[0]) + { + case PEER_FILE_INIT: // first packet of a file transfer +#ifdef _DEBUG + NetLog_Direct("Received PEER_FILE_INIT from %u",dc->dwRemoteUin); +#endif + if (dc->handshake) + handleFileTransferPacket(dc, buf, wLen); + else + NetLog_Direct("Received %s on uninitialised DC, ignoring.", "PEER_FILE_INIT"); + + break; + + case PEER_INIT_ACK: // This is sent as a response to our PEER_INIT packet + if (wLen != 4) + { + NetLog_Direct("Error: Received malformed PEER_INITACK from %u", dc->dwRemoteUin); + break; + } +#ifdef _DEBUG + NetLog_Direct("Received PEER_INITACK from %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); +#endif + if (dc->incoming) dc->handshake = 1; + + if (dc->incoming && dc->type == DIRECTCONN_REVERSE) + { + cookie_reverse_connect *pCookie; + + dc->incoming = 0; + + if (FindCookie(dc->dwReqId, NULL, (void**)&pCookie) && pCookie) + { // valid reverse DC, check and init session + FreeCookie(dc->dwReqId); + if (pCookie->dwUin == dc->dwRemoteUin) + { // valid connection + dc->type = pCookie->type; + dc->ft = (filetransfer*)pCookie->ft; + dc->hContact = pCookie->hContact; + if (dc->type == DIRECTCONN_STANDARD) + { // init message session + sendPeerMsgInit(dc, 0); + } + else if (dc->type == DIRECTCONN_FILE) + { // init file session + sendPeerFileInit(dc); + dc->initialised = 1; + } + SAFE_FREE((void**)&pCookie); + break; + } + else + { + SAFE_FREE((void**)&pCookie); + NetLog_Direct("Error: Invalid connection (UINs does not match)."); + CloseDirectConnection(dc); + return; + } + } + else + { + NetLog_Direct("Error: Received unexpected reverse DC, closing."); + CloseDirectConnection(dc); + return; + } + } + break; + + case PEER_INIT: /* connect packet */ +#ifdef _DEBUG + NetLog_Direct("Received PEER_INIT"); +#endif + buf++; + + if (wLen < 3) + return; + + unpackLEWord(&buf, &dc->wVersion); + + if (dc->wVersion > 6) + { // we support only versions 7 and up + WORD wSecondLen; + DWORD dwUin; + DWORD dwPort; + DWORD dwCookie; + HANDLE hContact; + + if (wLen != 0x30) + { + NetLog_Direct("Error: Received malformed PEER_INIT"); + return; + } + + unpackLEWord(&buf, &wSecondLen); + if (wSecondLen && wSecondLen != 0x2b) + { // OMG? GnomeICU sets this to zero + NetLog_Direct("Error: Received malformed PEER_INIT"); + return; + } + + unpackLEDWord(&buf, &dwUin); + if (dwUin != m_dwLocalUIN) + { + NetLog_Direct("Error: Received PEER_INIT targeted to %u", dwUin); + CloseDirectConnection(dc); + return; + } + + buf += 2; /* 00 00 */ + unpackLEDWord(&buf, &dc->dwRemotePort); + unpackLEDWord(&buf, &dc->dwRemoteUin); + unpackDWord(&buf, &dc->dwRemoteExternalIP); + unpackDWord(&buf, &dc->dwRemoteInternalIP); + buf ++; /* 04: accept direct connections */ + unpackLEDWord(&buf, &dwPort); + if (dwPort != dc->dwRemotePort) + { + NetLog_Direct("Error: Received malformed PEER_INIT (invalid port)"); + return; + } + unpackLEDWord(&buf, &dwCookie); + + buf += 8; // Unknown stuff + unpackLEDWord(&buf, &dc->dwReqId); + + if (dc->dwRemoteUin || !dc->dwReqId) + { // OMG! Licq sends on reverse connection empty uin + hContact = HContactFromUIN(dc->dwRemoteUin, NULL); + if (hContact == INVALID_HANDLE_VALUE) + { + NetLog_Direct("Error: Received PEER_INIT from %u not on my list", dwUin); + CloseDirectConnection(dc); + return; /* don't allow direct connection with people not on my clist */ + } + + if (dc->incoming) + { // this is the first PEER_INIT with our cookie + if (dwCookie != getSettingDword(hContact, "DirectCookie", 0)) + { + NetLog_Direct("Error: Received PEER_INIT with broken cookie"); + CloseDirectConnection(dc); + return; + } + } + else + { // this is the second PEER_INIT with peer cookie + if (dwCookie != dc->dwConnectionCookie) + { + NetLog_Direct("Error: Received PEER_INIT with broken cookie"); + CloseDirectConnection(dc); + return; + } + } + } + + if (dc->incoming && dc->dwReqId) + { // this is reverse connection + dc->type = DIRECTCONN_REVERSE; + if (!dc->dwRemoteUin) + { // we need to load cookie (licq) + cookie_reverse_connect *pCookie; + + if (FindCookie(dc->dwReqId, NULL, (void**)&pCookie) && pCookie) + { // valid reverse DC, check and init session + dc->dwRemoteUin = pCookie->dwUin; + dc->hContact = pCookie->hContact; + } + else + { + NetLog_Direct("Error: Received unexpected reverse DC, closing."); + CloseDirectConnection(dc); + return; + } + } + } + + sendPeerInitAck(dc); // ack good PEER_INIT packet + + if (dc->incoming) + { // store good IP info + dc->hContact = hContact; + dc->dwConnectionCookie = dwCookie; + setSettingDword(dc->hContact, "IP", dc->dwRemoteExternalIP); + setSettingDword(dc->hContact, "RealIP", dc->dwRemoteInternalIP); + sendPeerInit_v78(dc); // reply with our PEER_INIT + } + else // outgoing + { + dc->handshake = 1; + + if (dc->type == DIRECTCONN_REVERSE) + { + dc->incoming = 1; // this is incoming reverse connection + dc->type = DIRECTCONN_STANDARD; // we still do not know type + } + else if (dc->type == DIRECTCONN_STANDARD) + { // send PEER_MSGINIT + sendPeerMsgInit(dc, 0); + } + else if (dc->type == DIRECTCONN_FILE) + { + sendPeerFileInit(dc); + dc->initialised = 1; + } + } + // Set DC Status to successful + setSettingByte(dc->hContact, "DCStatus", 0); + } + else + { + NetLog_Direct("Unsupported direct protocol: %d, closing connection", dc->wVersion); + CloseDirectConnection(dc); + } + break; + + case PEER_MSG: /* messaging packets */ +#ifdef _DEBUG + NetLog_Direct("Received PEER_MSG from %u", dc->dwRemoteUin); +#endif + if (dc->initialised) + handleDirectMessage(dc, buf + 1, (WORD)(wLen - 1)); + else + NetLog_Direct("Received %s on uninitialised DC, ignoring.", "PEER_MSG"); + + break; + + case PEER_MSG_INIT: /* init message connection */ + { // it is sent by both contains GUID of message channel + DWORD q1,q2,q3,q4; + + if (!m_bDCMsgEnabled) + { // DC messaging disabled, close connection + NetLog_Direct("Messaging DC requested, denied"); + CloseDirectConnection(dc); + break; + } + +#ifdef _DEBUG + NetLog_Direct("Received PEER_MSG_INIT from %u",dc->dwRemoteUin); +#endif + buf++; + if (wLen != 0x21) + break; + + if (!dc->handshake) + { + NetLog_Direct("Received %s on unitialised DC, ignoring.", "PEER_MSG_INIT"); + break; + } + + buf += 4; /* always 10 */ + buf += 4; /* some id */ + buf += 4; /* sequence - always 0 on incoming */ + unpackDWord(&buf, &q1); // session type GUID + unpackDWord(&buf, &q2); + if (!dc->incoming) + { // skip marker on sequence 1 + buf += 4; + } + unpackDWord(&buf, &q3); + unpackDWord(&buf, &q4); + if (!CompareGUIDs(q1,q2,q3,q4,PSIG_MESSAGE)) + { // This is not for normal messages, useless so kill. + if (CompareGUIDs(q1,q2,q3,q4,PSIG_STATUS_PLUGIN)) + { + NetLog_Direct("Status Manager Plugin connections not supported, closing."); + } + else if (CompareGUIDs(q1,q2,q3,q4,PSIG_INFO_PLUGIN)) + { + NetLog_Direct("Info Manager Plugin connection not supported, closing."); + } + else + { + NetLog_Direct("Unknown connection type init, closing."); + } + CloseDirectConnection(dc); + break; + } + + if (dc->incoming) + { // reply with our PEER_MSG_INIT + sendPeerMsgInit(dc, 1); + } + else + { // connection initialized, ready to send message packet + } + NetLog_Direct("Direct message session ready."); + dc->initialised = 1; + } + break; + + default: + NetLog_Direct("Unknown direct packet ignored."); + break; + } +} + +void EncryptDirectPacket(directconnect* dc, icq_packet* p) +{ + unsigned long B1; + unsigned long M1; + unsigned long check; + unsigned int i; + unsigned char X1; + unsigned char X2; + unsigned char X3; + unsigned char* buf = (unsigned char*)(p->pData + 3); + unsigned char bak[6]; + unsigned long offset; + unsigned long key; + unsigned long hex; + unsigned long size = p->wLen - 1; + + + if (dc->wVersion < 4) + return; // no encryption necessary. + + + switch (dc->wVersion) + { + case 4: + case 5: + offset = 6; + break; + + case 6: + case 7: + case 8: + case 9: + case 10: + default: + offset = 0; + } + + // calculate verification data + M1 = (rand() % ((size < 255 ? size : 255)-10))+10; + X1 = buf[M1] ^ 0xFF; + X2 = rand() % 220; + X3 = client_check_data[X2] ^ 0xFF; + if (offset) + { + memcpy(bak, buf, sizeof(bak)); + B1 = (buf[offset+4]<<24) | (buf[offset+6]<<16) | (buf[2]<<8) | buf[0]; + } + else + { + B1 = (buf[4]<<24) | (buf[6]<<16) | (buf[4]<<8) | (buf[6]); + } + + // calculate checkcode + check = (M1<<24) | (X1<<16) | (X2<<8) | X3; + check ^= B1; + + // main XOR key + key = 0x67657268 * size + check; + + // XORing the actual data + for (i = 0; i<(size+3)/4; i+=4) + { + hex = key + client_check_data[i&0xFF]; + *(PDWORD)(buf + i) ^= hex; + } + + // in TCPv4 are the first 6 bytes unencrypted + // so restore them + if (offset) + memcpy(buf, bak, sizeof(bak)); + + // storing the checkcode + *(PDWORD)(buf + offset) = check; +} + +int DecryptDirectPacket(directconnect* dc, PBYTE buf, WORD wLen) +{ + unsigned long hex; + unsigned long key; + unsigned long B1; + unsigned long M1; + unsigned long check; + unsigned int i; + unsigned char X1; + unsigned char X2; + unsigned char X3; + unsigned char bak[6]; + unsigned long size = wLen; + unsigned long offset; + + + if (dc->wVersion < 4) + return 1; // no decryption necessary. + + if (size < 4) + return 1; + + if (dc->wVersion < 4) + return 1; + + if (dc->wVersion == 4 || dc->wVersion == 5) + { + offset = 6; + } + else + { + offset = 0; + } + + // backup the first 6 bytes + if (offset) + memcpy(bak, buf, sizeof(bak)); + + // retrieve checkcode + check = *(PDWORD)(buf+offset); + + // main XOR key + key = 0x67657268 * size + check; + + for (i=4; i<(size+3)/4; i+=4) + { + hex = key + client_check_data[i&0xFF]; + *(PDWORD)(buf + i) ^= hex; + } + + // retrive validate data + if (offset) + { + // in TCPv4 are the first 6 bytes unencrypted + // so restore them + memcpy(buf, bak, sizeof(bak)); + B1 = (buf[offset+4]<<24) | (buf[offset+6]<<16) | (buf[2]<<8) | buf[0]; + } + else + { + B1 = (buf[4]<<24) | (buf[6]<<16) | (buf[4]<<8) | (buf[6]<<0); + } + + // special decryption + B1 ^= check; + + // validate packet + M1 = (B1>>24) & 0xFF; + if (M1 < 10 || M1 >= size) + { + return 0; + } + + X1 = buf[M1] ^ 0xFF; + if (((B1 >> 16) & 0xFF) != X1) + { + return 0; + } + + X2 = (BYTE)((B1 >> 8) & 0xFF); + if (X2 < 220) + { + X3 = client_check_data[X2] ^ 0xFF; + if ((B1 & 0xFF) != X3) + { + return 0; + } + } +#ifdef _DEBUG + { // log decrypted data + char szTitleLine[128]; + char* szBuf; + int titleLineLen; + int line; + int col; + int colsInLine; + char* pszBuf; + + + titleLineLen = null_snprintf(szTitleLine, 128, "DECRYPTED\n"); + szBuf = (char*)_alloca(titleLineLen + ((wLen+15)>>4) * 76 + 1); + CopyMemory(szBuf, szTitleLine, titleLineLen); + pszBuf = szBuf + titleLineLen; + + for (line = 0; ; line += 16) + { + colsInLine = min(16, wLen - line); + pszBuf += wsprintfA(pszBuf, "%08X: ", line); + + for (col = 0; colhContact == hContact) + { + if (directConns[i]->initialised) + { + // This connection can be reused, send packet and exit + NetLog_Direct("Sending direct message"); + + if (pkt->pData[2] == 2) + EncryptDirectPacket(directConns[i], pkt); + + sendDirectPacket(directConns[i], pkt); + directConns[i]->packetPending = 0; // packet done + + return TRUE; // Success + } + break; // connection not ready, use server instead + } + } + + return FALSE; // connection pending, we failed, use server instead +} + +// Sends a PEER_INIT packet through a DC +// ----------------------------------------------------------------------- +// This packet is sent during direct connection initialization between two +// ICQ clients. It is sent by the originator of the connection to start +// the handshake and by the receiver directly after it has sent the +// PEER_ACK packet as a reply to the originator's PEER_INIT. The values +// after the COOKIE field have been added for v7. + +void CIcqProto::sendPeerInit_v78(directconnect* dc) +{ + icq_packet packet; + + directPacketInit(&packet, 48); // Full packet length + packByte(&packet, PEER_INIT); // Command + packLEWord(&packet, dc->wVersion); // Version + packLEWord(&packet, 43); // Data length + packLEDWord(&packet, dc->dwRemoteUin); // UIN of remote user + packWord(&packet, 0); // Unknown + packLEDWord(&packet, wListenPort); // Our port + packLEDWord(&packet, m_dwLocalUIN); // Our UIN + packDWord(&packet, dc->dwLocalExternalIP); // Our external IP + packDWord(&packet, dc->dwLocalInternalIP); // Our internal IP + packByte(&packet, DC_TYPE); // TCP connection flags + packLEDWord(&packet, wListenPort); // Our port + packLEDWord(&packet, dc->dwConnectionCookie); // DC cookie + packLEDWord(&packet, WEBFRONTPORT); // Unknown + packLEDWord(&packet, CLIENTFEATURES); // Unknown + if (dc->type == DIRECTCONN_REVERSE) + packLEDWord(&packet, dc->dwReqId); // Reverse Request Cookie + else + packDWord(&packet, 0); // Unknown + + sendDirectPacket(dc, &packet); +#ifdef _DEBUG + NetLog_Direct("Sent PEER_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); +#endif +} + +// Sends a PEER_INIT packet through a DC +// ----------------------------------------------------------------------- +// This is sent to acknowledge a PEER_INIT packet. + +void CIcqProto::sendPeerInitAck(directconnect* dc) +{ + icq_packet packet; + + directPacketInit(&packet, 4); // Packet length + packLEDWord(&packet, PEER_INIT_ACK); // + + sendDirectPacket(dc, &packet); +#ifdef _DEBUG + NetLog_Direct("Sent PEER_INIT_ACK to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); +#endif +} + +// Sends a PEER_MSG_INIT packet through a DC +// ----------------------------------------------------------------------- +// This packet starts message session. + +void CIcqProto::sendPeerMsgInit(directconnect* dc, DWORD dwSeq) +{ + icq_packet packet; + + directPacketInit(&packet, 33); + packByte(&packet, PEER_MSG_INIT); + packLEDWord(&packet, 10); // unknown + packLEDWord(&packet, 1); // message connection + packLEDWord(&packet, dwSeq); // sequence is 0,1 + if (!dwSeq) + { + packGUID(&packet, PSIG_MESSAGE); // message type GUID + packLEWord(&packet, 1); // delimiter + packLEWord(&packet, 4); + } + else + { + packDWord(&packet, 0); // first part of Message GUID + packDWord(&packet, 0); + packLEWord(&packet, 1); // delimiter + packLEWord(&packet, 4); + packDWord(&packet, 0); // second part of Message GUID + packDWord(&packet, 0); + } + sendDirectPacket(dc, &packet); +#ifdef _DEBUG + NetLog_Direct("Sent PEER_MSG_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); +#endif +} + +// Sends a PEER_FILE_INIT packet through a DC +// ----------------------------------------------------------------------- +// This packet configures file-transfer session. + +void CIcqProto::sendPeerFileInit(directconnect* dc) +{ + icq_packet packet; + DBVARIANT dbv; + char* szNick; + int nNickLen; + + dbv.type = DBVT_DELETED; + if (getSettingString(NULL, "Nick", &dbv)) + szNick = ""; + else + szNick = dbv.pszVal; + nNickLen = strlennull(szNick); + + directPacketInit(&packet, (WORD)(20 + nNickLen)); + packByte(&packet, PEER_FILE_INIT); /* packet type */ + packLEDWord(&packet, 0); /* unknown */ + packLEDWord(&packet, dc->ft->dwFileCount); + packLEDWord(&packet, dc->ft->dwTotalSize); + packLEDWord(&packet, dc->ft->dwTransferSpeed); + packLEWord(&packet, (WORD)(nNickLen + 1)); + packBuffer(&packet, (LPBYTE)szNick, (WORD)(nNickLen + 1)); + sendDirectPacket(dc, &packet); +#ifdef _DEBUG + NetLog_Direct("Sent PEER_FILE_INIT to %u on %s DC", dc->dwRemoteUin, dc->incoming?"incoming":"outgoing"); +#endif + ICQFreeVariant(&dbv); +} diff --git a/protocols/IcqOscarJ/src/icq_direct.h b/protocols/IcqOscarJ/src/icq_direct.h new file mode 100644 index 0000000000..3cf91cb493 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_direct.h @@ -0,0 +1,94 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_DIRECT_H +#define __ICQ_DIRECT_H + +struct filetransfer: public basic_filetransfer +{ + int status; + int sending; + int iCurrentFile; + int currentIsDir; + DWORD dwCookie; + DWORD dwUin; + DWORD dwRemotePort; + HANDLE hContact; + char *szFilename; + char *szDescription; + char *szSavePath; + char *szThisFile; + char *szThisSubdir; + char **pszFiles; + DWORD dwThisFileSize; + DWORD dwThisFileDate; + DWORD dwTotalSize; + DWORD dwFileCount; + DWORD dwTransferSpeed; + DWORD dwBytesDone, dwFileBytesDone; + int fileId; + HANDLE hConnection; + DWORD dwLastNotify; + int nVersion; // Was this sent with a v7 or a v8 packet? + BOOL bDC; // Was this received over a DC or through server? + BOOL bEmptyDesc; // Was the description empty ? +}; + +#define DIRECTCONN_STANDARD 0 +#define DIRECTCONN_FILE 1 +#define DIRECTCONN_CHAT 2 +#define DIRECTCONN_REVERSE 10 +#define DIRECTCONN_CLOSING 15 + +struct directconnect +{ + HANDLE hContact; + HANDLE hConnection; + DWORD dwConnectionCookie; + int type; + WORD wVersion; + int incoming; + int wantIdleTime; + int packetPending; + DWORD dwRemotePort; + DWORD dwRemoteUin; + DWORD dwRemoteExternalIP; + DWORD dwRemoteInternalIP; + DWORD dwLocalExternalIP; + DWORD dwLocalInternalIP; + int initialised; + int handshake; + DWORD dwThreadId; + filetransfer *ft; + DWORD dwReqId; // Reverse Connect request cookie +}; + +int DecryptDirectPacket(directconnect* dc, PBYTE buf, WORD wLen); + +#endif /* __ICQ_DIRECT_H */ diff --git a/protocols/IcqOscarJ/src/icq_directmsg.cpp b/protocols/IcqOscarJ/src/icq_directmsg.cpp new file mode 100644 index 0000000000..89fbb7cea5 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_directmsg.cpp @@ -0,0 +1,361 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleDirectMessage(directconnect* dc, PBYTE buf, WORD wLen) +{ + WORD wCommand; + WORD wCookie; + BYTE bMsgType,bMsgFlags; + WORD wStatus; + WORD wFlags; + WORD wTextLen; + char* pszText = NULL; + + + // The first part of the packet should always be at least 31 bytes + if (wLen < 31) + { + NetLog_Direct("Error during parsing of DC packet 2 PEER_MSG (too short)"); + return; + } + + // Skip packet checksum + buf += 4; + wLen -= 4; + + // Command: + // 0x07d0 = 2000 - cancel given message. + // 0x07da = 2010 - acknowledge message. + // 0x07ee = 2030 - normal message/request. + unpackLEWord(&buf, &wCommand); + wLen -= 2; + + // Unknown, always 0xe (14) + buf += 2; + wLen -= 2; + + // Sequence number + unpackLEWord(&buf, &wCookie); + wLen -=2; + + // Unknown, always zeroes + buf += 12; + wLen -= 12; + + // Peer message type + unpackByte(&buf, &bMsgType); + // Peer message flags + unpackByte(&buf, &bMsgFlags); + wLen -= 2; + + // The current status of the user, or whether the message was accepted or not. + // 0x00 - user is online, or message was receipt, or file transfer accepted + // 0x01 - refused + // 0x04 - auto-refused, because of away + // 0x09 - auto-refused, because of occupied + // 0x0a - auto-refused, because of dnd + // 0x0e - auto-refused, because of na + unpackLEWord(&buf, &wStatus); + wLen -= 2; + + // Flags, or priority + // Seen: 1 - Chat request + // 0 - File auto accept (type 3) + // 33 - priority ? + unpackLEWord(&buf, &wFlags); + wLen -= 2; + + // Messagetext. This is either the status message or the actual message + // when this is a PEER_MSG_MSG packet + unpackLEWord(&buf, &wTextLen); + if (wTextLen > 0) + { + pszText = (char*)_alloca(wTextLen+1); + unpackString(&buf, pszText, wTextLen); + pszText[wTextLen] = '\0'; + } + wLen = (wLen - 2) - wTextLen; + +#ifdef _DEBUG + NetLog_Direct("Handling PEER_MSG '%s', command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", pszText, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); +#else + NetLog_Direct("Message through direct - UID: %u", dc->dwRemoteUin); +#endif + + // The remaining actual message is handled either as a status message request, + // a greeting message, a acknowledge or a normal (text, url, file) message + if (wCommand == DIRECT_MESSAGE) + switch (bMsgType) + { + case MTYPE_FILEREQ: // File inits + handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, pszText, 7, TRUE); + break; + + case MTYPE_AUTOAWAY: + case MTYPE_AUTOBUSY: + case MTYPE_AUTONA: + case MTYPE_AUTODND: + case MTYPE_AUTOFFC: + { + char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(bMsgType)); + if (szMsg) + icq_sendAwayMsgReplyDirect(dc, wCookie, bMsgType, ( const char** )szMsg); + } + break; + + case MTYPE_PLUGIN: // Greeting + handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); + break; + + default: + { + message_ack_params pMsgAck = {0}; + uid_str szUID; + + buf -= wTextLen; + wLen += wTextLen; + + pMsgAck.bType = MAT_DIRECT; + pMsgAck.pDC = dc; + pMsgAck.wCookie = wCookie; + pMsgAck.msgType = bMsgType; + pMsgAck.bFlags = bMsgFlags; + handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 0, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, &pMsgAck); + break; + } + } + else if (wCommand == DIRECT_ACK) + { + if (bMsgFlags == 3) + { // this is status reply + uid_str szUID; + + buf -= wTextLen; + wLen += wTextLen; + + handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 2, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, NULL); + } + else + { + HANDLE hCookieContact; + cookie_message_data *pCookieData = NULL; + + if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) + { + NetLog_Direct("Received an unexpected direct ack"); + } + else if (hCookieContact != dc->hContact) + { + NetLog_Direct("Direct Contact does not match Cookie Contact(0x%x != 0x%x)", dc->hContact, hCookieContact); + ReleaseCookie(wCookie); // This could be a bad idea, but I think it is safe + } + else + { // the ack is correct + int ackType = -1; + + switch (bMsgType) + { + case MTYPE_PLAIN: + ackType = ACKTYPE_MESSAGE; + break; + case MTYPE_URL: + ackType = ACKTYPE_URL; + break; + case MTYPE_CONTACTS: + ackType = ACKTYPE_CONTACTS; + break; + + case MTYPE_FILEREQ: // File acks + handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, pszText); + break; + + case MTYPE_PLUGIN: // Greeting + handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); + break; + + default: + NetLog_Direct("Skipped packet from direct connection"); + break; + } + if (ackType != -1) + { // was a good ack to broadcast ? + BroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + ReleaseCookie(wCookie); + } + } + } + } + else if (wCommand == DIRECT_CANCEL) + { + NetLog_Direct("Cannot handle abort messages yet... :("); + } + else + NetLog_Direct("Unknown wCommand, packet skipped"); +} + +void CIcqProto::handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText) +{ + DWORD dwLengthToEnd; + DWORD dwDataLength; + char* pszFileName = NULL; + int typeId; + WORD qt; + +#ifdef _DEBUG + NetLog_Direct("Handling PEER_MSG_GREETING, command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); +#endif + + NetLog_Direct("Parsing Greeting message through direct"); + + if (!unpackPluginTypeId(&buf, &wLen, &typeId, &qt, TRUE)) return; + + // Length of remaining data + unpackLEDWord(&buf, &dwLengthToEnd); + if (dwLengthToEnd < 4 || dwLengthToEnd > wLen) + { + NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 2, dwLengthToEnd, wLen); + return; + } + + // Length of message/reason + unpackLEDWord(&buf, &dwDataLength); + wLen -= 4; + if (dwDataLength > wLen) + { + NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 3, dwDataLength, wLen); + return; + } + + if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_MESSAGE) + { + char* szMsg; + + NetLog_Direct("This is file request"); + szMsg = (char*)_alloca(dwDataLength+1); + unpackString(&buf, szMsg, (WORD)dwDataLength); + szMsg[dwDataLength] = '\0'; + wLen = wLen - (WORD)dwDataLength; + + handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, szMsg, 8, TRUE); + } + else if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_ACK) + { + char* szMsg; + + NetLog_Direct("This is file ack"); + szMsg = (char*)_alloca(dwDataLength+1); + unpackString(&buf, szMsg, (WORD)dwDataLength); + szMsg[dwDataLength] = '\0'; + wLen = wLen - (WORD)dwDataLength; + + // 50 - file request granted/refused + handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, szMsg); + } + else if (typeId && wCommand == DIRECT_MESSAGE) + { + uid_str szUID; + message_ack_params pMsgAck = {0}; + + pMsgAck.bType = MAT_DIRECT; + pMsgAck.pDC = dc; + pMsgAck.wCookie = wCookie; + pMsgAck.msgType = typeId; + handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, typeId, 0, 0, dwLengthToEnd, (WORD)dwDataLength, (char*)buf, MTF_PLUGIN | MTF_DIRECT, &pMsgAck); + } + else if (typeId == MTYPE_STATUSMSGEXT && wCommand == DIRECT_ACK) + { // especially for icq2003b + NetLog_Direct("This is extended status reply"); + + char *szMsg = (char*)_alloca(dwDataLength+1); + uid_str szUID; + unpackString(&buf, szMsg, (WORD)dwDataLength); + szMsg[dwDataLength] = '\0'; + + handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)(qt + 0xE7), 3, 2, (DWORD)wLen, (WORD)dwDataLength, szMsg, MTF_PLUGIN | MTF_DIRECT, NULL); + } + else if (typeId && wCommand == DIRECT_ACK) + { + HANDLE hCookieContact; + cookie_message_data *pCookieData = NULL; + + if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) + { + NetLog_Direct("Received an unexpected direct ack"); + } + else if (hCookieContact != dc->hContact) + { + NetLog_Direct("Direct Contact does not match Cookie Contact(0x%x != 0x%x)", dc->hContact, hCookieContact); + ReleaseCookie(wCookie); // This could be a bad idea, but I think it is safe + } + else + { + int ackType = -1; + + switch (typeId) + { + case MTYPE_MESSAGE: + ackType = ACKTYPE_MESSAGE; + break; + case MTYPE_URL: + ackType = ACKTYPE_URL; + break; + case MTYPE_CONTACTS: + ackType = ACKTYPE_CONTACTS; + break; + case MTYPE_SCRIPT_NOTIFY: + { + char *szMsg; + + szMsg = (char*)_alloca(dwDataLength + 1); + if (dwDataLength > 0) + memcpy(szMsg, buf, dwDataLength); + szMsg[dwDataLength] = '\0'; + + handleXtrazNotifyResponse(dc->dwRemoteUin, dc->hContact, wCookie, szMsg, dwDataLength); + } + break; + + default: + NetLog_Direct("Skipped packet from direct connection"); + break; + } + + if (ackType != -1) + { // was a good ack to broadcast ? + BroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + } + // Release cookie + ReleaseCookie(wCookie); + } + } + else + NetLog_Direct("Unsupported plugin message type %s", typeId); +} diff --git a/protocols/IcqOscarJ/src/icq_fieldnames.cpp b/protocols/IcqOscarJ/src/icq_fieldnames.cpp new file mode 100644 index 0000000000..d953a081cf --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_fieldnames.cpp @@ -0,0 +1,595 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +const FieldNamesItem countryField[]={ + {9999, LPGEN("Other")}, + {93, LPGEN("Afghanistan")}, + {355, LPGEN("Albania")}, + {213, LPGEN("Algeria")}, + {376, LPGEN("Andorra")}, + {244, LPGEN("Angola")}, + {1264, LPGEN("Anguilla")}, + {1268, LPGEN("Antigua and Barbuda")}, +//{5902, LPGEN("Antilles")}, /* removed: it is not a country, it's a group of islands from diffrent countries (all are included in the list)*/ + {54, LPGEN("Argentina")}, + {374, LPGEN("Armenia")}, + {297, LPGEN("Aruba")}, + {247, LPGEN("Ascension Island")}, + {61, LPGEN("Australia")}, + {6720, LPGEN("Australia, Antarctic Territory")}, /* added country code 672(0)*/ + {614, LPGEN("Australia, Christmas Island")}, /* rename (from Christmas Island) and change to official county code 61(4) (from 672) */ + {61891, LPGEN("Australia, Cocos (Keeling) Islands")}, /* rename and change to official county code 61(891) (from 6102) */ + {6723 , LPGEN("Australia, Norfolk Island")}, /* rename (from Norfolk Island) and change to official county code 672(3) (from 6722) */ + {43, LPGEN("Austria")}, + {994, LPGEN("Azerbaijan")}, + {1242, LPGEN("Bahamas")}, + {973, LPGEN("Bahrain")}, + {880, LPGEN("Bangladesh")}, + {1246, LPGEN("Barbados")}, +//{120, LPGEN("Barbuda")}, /* removed: it is not a country and no special island, see Antigua and Barbuda*/ + {375, LPGEN("Belarus")}, + {32, LPGEN("Belgium")}, + {501, LPGEN("Belize")}, + {229, LPGEN("Benin")}, + {1441, LPGEN("Bermuda")}, + {975, LPGEN("Bhutan")}, + {591, LPGEN("Bolivia")}, + {387, LPGEN("Bosnia and Herzegovina")}, + {267, LPGEN("Botswana")}, + {55, LPGEN("Brazil")}, + {106, LPGEN("British Virgin Islands")}, + {673, LPGEN("Brunei")}, + {359, LPGEN("Bulgaria")}, + {226, LPGEN("Burkina Faso")}, + {257, LPGEN("Burundi")}, + {855, LPGEN("Cambodia")}, + {237, LPGEN("Cameroon")}, + {1002, LPGEN("Canada")}, + {178, LPGEN("Canary Islands")}, + {238, LPGEN("Cape Verde Islands")}, + {1345, LPGEN("Cayman Islands")}, + {236, LPGEN("Central African Republic")}, + {235, LPGEN("Chad")}, + {56, LPGEN("Chile, Republic of")}, + {86, LPGEN("China")}, +//{6101, LPGEN("Cocos (Keeling) Islands")}, /* removed (double): see Australia, Cocos (Keeling) Islands */ + {57, LPGEN("Colombia")}, + {269, LPGEN("Comoros")}, + {243, LPGEN("Congo, Democratic Republic of (Zaire)")}, + {242, LPGEN("Congo, Republic of the")}, + {682, LPGEN("Cook Islands")}, + {506, LPGEN("Costa Rica")}, + {225, LPGEN("Cote d'Ivoire (Ivory Coast)")}, + {385, LPGEN("Croatia")}, + {53, LPGEN("Cuba")}, + {357, LPGEN("Greek, Republic of South Cyprus")}, /* rename coz Turkey, Republic of Northern Cyprus */ + {420, LPGEN("Czech Republic")}, + {45, LPGEN("Denmark")}, + {246, LPGEN("Diego Garcia")}, + {253, LPGEN("Djibouti")}, + {1767, LPGEN("Dominica")}, + {1809, LPGEN("Dominican Republic")}, + {593, LPGEN("Ecuador")}, + {20, LPGEN("Egypt")}, + {503, LPGEN("El Salvador")}, + {240, LPGEN("Equatorial Guinea")}, + {291, LPGEN("Eritrea")}, + {372, LPGEN("Estonia")}, + {251, LPGEN("Ethiopia")}, + {3883,LPGEN("Europe")}, /* add county code +388 3 official European Telephony Numbering Space*/ + {298, LPGEN("Faeroe Islands")}, + {500, LPGEN("Falkland Islands")}, + {679, LPGEN("Fiji")}, + {358, LPGEN("Finland")}, + {33, LPGEN("France")}, + {5901, LPGEN("French Antilles")}, + {594, LPGEN("French Guiana")}, + {689, LPGEN("French Polynesia")}, + {241, LPGEN("Gabon")}, + {220, LPGEN("Gambia")}, + {995, LPGEN("Georgia")}, + {49, LPGEN("Germany")}, + {233, LPGEN("Ghana")}, + {350, LPGEN("Gibraltar")}, + {30, LPGEN("Greece")}, + {299, LPGEN("Greenland")}, + {1473, LPGEN("Grenada")}, + {590, LPGEN("Guadeloupe")}, + {1671, LPGEN("Guam, US Territory of")}, + {502, LPGEN("Guatemala")}, + {224, LPGEN("Guinea")}, + {245, LPGEN("Guinea-Bissau")}, + {592, LPGEN("Guyana")}, + {509, LPGEN("Haiti")}, + {504, LPGEN("Honduras")}, + {852, LPGEN("Hong Kong")}, + {36, LPGEN("Hungary")}, + {354, LPGEN("Iceland")}, + {91, LPGEN("India")}, + {62, LPGEN("Indonesia")}, + {98, LPGEN("Iran (Islamic Republic of)")}, + {964, LPGEN("Iraq")}, + {353, LPGEN("Ireland")}, + {972, LPGEN("Israel")}, + {39, LPGEN("Italy")}, + {1876, LPGEN("Jamaica")}, + {81, LPGEN("Japan")}, + {962, LPGEN("Jordan")}, + {705, LPGEN("Kazakhstan")}, + {254, LPGEN("Kenya")}, + {686, LPGEN("Kiribati")}, + {850, LPGEN("Korea, North")}, + {82, LPGEN("Korea, South")}, + {965, LPGEN("Kuwait")}, + {996, LPGEN("Kyrgyzstan")}, + {856, LPGEN("Laos")}, + {371, LPGEN("Latvia")}, + {961, LPGEN("Lebanon")}, + {266, LPGEN("Lesotho")}, + {231, LPGEN("Liberia")}, + {218, LPGEN("Libyan Arab Jamahiriya")}, + {423, LPGEN("Liechtenstein")}, + {370, LPGEN("Lithuania")}, + {352, LPGEN("Luxembourg")}, + {853, LPGEN("Macau")}, + {389, LPGEN("Macedonia, Republic of")}, + {261, LPGEN("Madagascar")}, + {265, LPGEN("Malawi")}, + {60, LPGEN("Malaysia")}, + {960, LPGEN("Maldives")}, + {223, LPGEN("Mali")}, + {356, LPGEN("Malta")}, + {692, LPGEN("Marshall Islands")}, + {596, LPGEN("Martinique")}, + {222, LPGEN("Mauritania")}, + {230, LPGEN("Mauritius")}, + {262, LPGEN("Mayotte Island")}, + {52, LPGEN("Mexico")}, + {691, LPGEN("Micronesia, Federated States of")}, + {373, LPGEN("Moldova, Republic of")}, + {377, LPGEN("Monaco")}, + {976, LPGEN("Mongolia")}, + {1664, LPGEN("Montserrat")}, + {212, LPGEN("Morocco")}, + {258, LPGEN("Mozambique")}, + {95, LPGEN("Myanmar")}, + {264, LPGEN("Namibia")}, + {674, LPGEN("Nauru")}, + {977, LPGEN("Nepal")}, + {31, LPGEN("Netherlands")}, + {599, LPGEN("Netherlands Antilles")}, /* dissolved 2010 */ + {5995, LPGEN("St. Maarten")}, /* add new country in 2010 (from Netherlands Antilles) */ + {5999, LPGEN("Curacao")}, /* add new country in 2010 (from Netherlands Antilles) */ + {5997, LPGEN("Netherlands (Bonaire Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ + {59946, LPGEN("Netherlands (Saba Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ + {59938, LPGEN("Netherlands (St. Eustatius Island)")}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */ +//{114, LPGEN("Nevis")}, /* removed: it is not a country, it's part of Saint Kitts and Nevis*/ + {687, LPGEN("New Caledonia")}, + {64, LPGEN("New Zealand")}, + {505, LPGEN("Nicaragua")}, + {227, LPGEN("Niger")}, + {234, LPGEN("Nigeria")}, + {683, LPGEN("Niue")}, + {1670, LPGEN("Northern Mariana Islands, US Territory of")}, /* added NANP */ + {47, LPGEN("Norway")}, + {968, LPGEN("Oman")}, + {92, LPGEN("Pakistan")}, + {680, LPGEN("Palau")}, + {507, LPGEN("Panama")}, + {675, LPGEN("Papua New Guinea")}, + {595, LPGEN("Paraguay")}, + {51, LPGEN("Peru")}, + {63, LPGEN("Philippines")}, + {48, LPGEN("Poland")}, + {351, LPGEN("Portugal")}, + {1939, LPGEN("Puerto Rico")}, + {974, LPGEN("Qatar")}, + {262, LPGEN("Reunion Island")}, + {40, LPGEN("Romania")}, +//{6701, LPGEN("Rota Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ + {7, LPGEN("Russia")}, + {250, LPGEN("Rwanda")}, + {1684, LPGEN("Samoa (USA)")}, /* rename (from American Samoa) change county code to NANP (from 684) */ + {685, LPGEN("Samoa, Western")}, /* rename (from Western Samoa) */ + {290, LPGEN("Saint Helena")}, +//{115, LPGEN("Saint Kitts")}, /* removed: it is not a country it is part of Saint Kitts and Nevis*/ + {1869, LPGEN("Saint Kitts and Nevis")}, + {1758, LPGEN("Saint Lucia")}, + {508, LPGEN("Saint Pierre and Miquelon")}, + {1784, LPGEN("Saint Vincent and the Grenadines")}, +//{670, LPGEN("Saipan Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ + {378, LPGEN("San Marino")}, + {239, LPGEN("Sao Tome and Principe")}, + {966, LPGEN("Saudi Arabia")}, + {442, LPGEN("Scotland")}, + {221, LPGEN("Senegal")}, + {248, LPGEN("Seychelles")}, + {232, LPGEN("Sierra Leone")}, + {65, LPGEN("Singapore")}, + {421, LPGEN("Slovakia")}, + {386, LPGEN("Slovenia")}, + {677, LPGEN("Solomon Islands")}, + {252, LPGEN("Somalia")}, + {27, LPGEN("South Africa")}, + {34, LPGEN("Spain")}, + {3492, LPGEN("Spain, Canary Islands")}, /*rename and change county code to 34(92) spain + canary code*/ + {94, LPGEN("Sri Lanka")}, + {249, LPGEN("Sudan")}, + {597, LPGEN("Suriname")}, + {268, LPGEN("Swaziland")}, + {46, LPGEN("Sweden")}, + {41, LPGEN("Switzerland")}, + {963, LPGEN("Syrian Arab Republic")}, + {886, LPGEN("Taiwan")}, + {992, LPGEN("Tajikistan")}, + {255, LPGEN("Tanzania")}, + {66, LPGEN("Thailand")}, +//{6702, LPGEN("Tinian Island")}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */ + {670 , LPGEN("Timor, East")}, /* added (is part off Northern Mariana Islands but not US Territory*/ + {228, LPGEN("Togo")}, + {690, LPGEN("Tokelau")}, + {676, LPGEN("Tonga")}, + {1868, LPGEN("Trinidad and Tobago")}, + {216, LPGEN("Tunisia")}, + {90, LPGEN("Turkey")}, + {90392, LPGEN("Turkey, Republic of Northern Cyprus")}, /* added (is diffrent from Greek part)*/ + {993, LPGEN("Turkmenistan")}, + {1649, LPGEN("Turks and Caicos Islands")}, + {688, LPGEN("Tuvalu")}, + {256, LPGEN("Uganda")}, + {380, LPGEN("Ukraine")}, + {971, LPGEN("United Arab Emirates")}, + {44, LPGEN("United Kingdom")}, + {598, LPGEN("Uruguay")}, + {1, LPGEN("USA")}, + {998, LPGEN("Uzbekistan")}, + {678, LPGEN("Vanuatu")}, + {379, LPGEN("Vatican City")}, + {58, LPGEN("Venezuela")}, + {84, LPGEN("Vietnam")}, + {1284, LPGEN("Virgin Islands (UK)")}, /* change county code to NANP (from 105) - rename coz Virgin Islands (USA) */ + {1340, LPGEN("Virgin Islands (USA)")}, /* change county code to NANP (from 123) */ + {441, LPGEN("Wales")}, + {681, LPGEN("Wallis and Futuna Islands")}, + {967, LPGEN("Yemen")}, + {38, LPGEN("Yugoslavia")}, + {381, LPGEN("Serbia, Republic of")}, /* rename need (from Yugoslavia)*/ + {383, LPGEN("Kosovo, Republic of")}, /*change country code (from 3811), rename need (from Yugoslavia - Serbia) */ + {382, LPGEN("Montenegro, Republic of")}, /* rename need (from Yugoslavia - Montenegro) */ + {260, LPGEN("Zambia")}, + {263, LPGEN("Zimbabwe")}, + {0, NULL} +}; + + +const FieldNamesItem interestsField[]={ + {137, LPGEN("50's")}, + {134, LPGEN("60's")}, + {135, LPGEN("70's")}, + {136, LPGEN("80's")}, + {100, LPGEN("Art")}, + {128, LPGEN("Astronomy")}, + {147, LPGEN("Audio and Visual")}, + {125, LPGEN("Business")}, + {146, LPGEN("Business Services")}, + {101, LPGEN("Cars")}, + {102, LPGEN("Celebrity Fans")}, + {130, LPGEN("Clothing")}, + {103, LPGEN("Collections")}, + {104, LPGEN("Computers")}, + {105, LPGEN("Culture")}, + {122, LPGEN("Ecology")}, + {139, LPGEN("Entertainment")}, + {138, LPGEN("Finance and Corporate")}, + {106, LPGEN("Fitness")}, + {142, LPGEN("Health and Beauty")}, + {108, LPGEN("Hobbies")}, + {150, LPGEN("Home Automation")}, + {144, LPGEN("Household Products")}, + {107, LPGEN("Games")}, + {124, LPGEN("Government")}, + {109, LPGEN("ICQ - Help")}, + {110, LPGEN("Internet")}, + {111, LPGEN("Lifestyle")}, + {145, LPGEN("Mail Order Catalog")}, + {143, LPGEN("Media")}, + {112, LPGEN("Movies and TV")}, + {113, LPGEN("Music")}, + {126, LPGEN("Mystics")}, + {123, LPGEN("News and Media")}, + {114, LPGEN("Outdoors")}, + {115, LPGEN("Parenting")}, + {131, LPGEN("Parties")}, + {116, LPGEN("Pets and Animals")}, + {149, LPGEN("Publishing")}, + {117, LPGEN("Religion")}, + {141, LPGEN("Retail Stores")}, + {118, LPGEN("Science")}, + {119, LPGEN("Skills")}, + {133, LPGEN("Social science")}, + {129, LPGEN("Space")}, + {148, LPGEN("Sporting and Athletic")}, + {120, LPGEN("Sports")}, + {127, LPGEN("Travel")}, + {121, LPGEN("Web Design")}, + {132, LPGEN("Women")}, + {-1, NULL} +}; + + +const FieldNamesItem languageField[]={ + {55, LPGEN("Afrikaans")}, + {58, LPGEN("Albanian")}, + {1, LPGEN("Arabic")}, + {59, LPGEN("Armenian")}, + {68, LPGEN("Azerbaijani")}, + {72, LPGEN("Belorussian")}, + {2, LPGEN("Bhojpuri")}, + {56, LPGEN("Bosnian")}, + {3, LPGEN("Bulgarian")}, + {4, LPGEN("Burmese")}, + {5, LPGEN("Cantonese")}, + {6, LPGEN("Catalan")}, + {61, LPGEN("Chamorro")}, + {7, LPGEN("Chinese")}, + {8, LPGEN("Croatian")}, + {9, LPGEN("Czech")}, + {10, LPGEN("Danish")}, + {11, LPGEN("Dutch")}, + {12, LPGEN("English")}, + {13, LPGEN("Esperanto")}, + {14, LPGEN("Estonian")}, + {15, LPGEN("Farsi")}, + {16, LPGEN("Finnish")}, + {17, LPGEN("French")}, + {18, LPGEN("Gaelic")}, + {19, LPGEN("German")}, + {20, LPGEN("Greek")}, + {70, LPGEN("Gujarati")}, + {21, LPGEN("Hebrew")}, + {22, LPGEN("Hindi")}, + {23, LPGEN("Hungarian")}, + {24, LPGEN("Icelandic")}, + {25, LPGEN("Indonesian")}, + {26, LPGEN("Italian")}, + {27, LPGEN("Japanese")}, + {28, LPGEN("Khmer")}, + {29, LPGEN("Korean")}, + {69, LPGEN("Kurdish")}, + {30, LPGEN("Lao")}, + {31, LPGEN("Latvian")}, + {32, LPGEN("Lithuanian")}, + {65, LPGEN("Macedonian")}, + {33, LPGEN("Malay")}, + {63, LPGEN("Mandarin")}, + {62, LPGEN("Mongolian")}, + {34, LPGEN("Norwegian")}, + {57, LPGEN("Persian")}, + {35, LPGEN("Polish")}, + {36, LPGEN("Portuguese")}, + {60, LPGEN("Punjabi")}, + {37, LPGEN("Romanian")}, + {38, LPGEN("Russian")}, + {39, LPGEN("Serbian")}, + {66, LPGEN("Sindhi")}, + {40, LPGEN("Slovak")}, + {41, LPGEN("Slovenian")}, + {42, LPGEN("Somali")}, + {43, LPGEN("Spanish")}, + {44, LPGEN("Swahili")}, + {45, LPGEN("Swedish")}, + {46, LPGEN("Tagalog")}, + {64, LPGEN("Taiwanese")}, + {71, LPGEN("Tamil")}, + {47, LPGEN("Tatar")}, + {48, LPGEN("Thai")}, + {49, LPGEN("Turkish")}, + {50, LPGEN("Ukrainian")}, + {51, LPGEN("Urdu")}, + {52, LPGEN("Vietnamese")}, + {67, LPGEN("Welsh")}, + {53, LPGEN("Yiddish")}, + {54, LPGEN("Yoruba")}, + {0, NULL} +}; + + +const FieldNamesItem pastField[]={ + {300, LPGEN("Elementary School")}, + {301, LPGEN("High School")}, + {302, LPGEN("College")}, + {303, LPGEN("University")}, + {304, LPGEN("Military")}, + {305, LPGEN("Past Work Place")}, + {306, LPGEN("Past Organization")}, + {399, LPGEN("Other")}, + {0, NULL} +}; + + +const FieldNamesItem genderField[]={ + {'F', LPGEN("Female")}, + {'M', LPGEN("Male")}, + {0, NULL} +}; + + +const FieldNamesItem studyLevelField[]={ + {4, LPGEN("Associated degree")}, + {5, LPGEN("Bachelor's degree")}, + {1, LPGEN("Elementary")}, + {2, LPGEN("High-school")}, + {6, LPGEN("Master's degree")}, + {7, LPGEN("PhD")}, + {8, LPGEN("Postdoctoral")}, + {3, LPGEN("University / College")}, + {0, NULL} +}; + + +const FieldNamesItem industryField[]={ + {2, LPGEN("Agriculture")}, + {3, LPGEN("Arts")}, + {4, LPGEN("Construction")}, + {5, LPGEN("Consumer Goods")}, + {6, LPGEN("Corporate Services")}, + {7, LPGEN("Education")}, + {8, LPGEN("Finance")}, + {9, LPGEN("Government")}, + {10, LPGEN("High Tech")}, + {11, LPGEN("Legal")}, + {12, LPGEN("Manufacturing")}, + {13, LPGEN("Media")}, + {14, LPGEN("Medical & Health Care")}, + {15, LPGEN("Non-Profit Organization Management")}, + {19, LPGEN("Other")}, + {16, LPGEN("Recreation, Travel & Entertainment")}, + {17, LPGEN("Service Industry")}, + {18, LPGEN("Transportation")}, + {0, NULL} +}; + + +const FieldNamesItem occupationField[]={ + {1, LPGEN("Academic")}, + {2, LPGEN("Administrative")}, + {3, LPGEN("Art/Entertainment")}, + {4, LPGEN("College Student")}, + {5, LPGEN("Computers")}, + {6, LPGEN("Community & Social")}, + {7, LPGEN("Education")}, + {8, LPGEN("Engineering")}, + {9, LPGEN("Financial Services")}, + {10, LPGEN("Government")}, + {11, LPGEN("High School Student")}, + {12, LPGEN("Home")}, + {13, LPGEN("ICQ - Providing Help")}, + {14, LPGEN("Law")}, + {15, LPGEN("Managerial")}, + {16, LPGEN("Manufacturing")}, + {17, LPGEN("Medical/Health")}, + {18, LPGEN("Military")}, + {19, LPGEN("Non-Government Organization")}, + {20, LPGEN("Professional")}, + {21, LPGEN("Retail")}, + {22, LPGEN("Retired")}, + {23, LPGEN("Science & Research")}, + {24, LPGEN("Sports")}, + {25, LPGEN("Technical")}, + {26, LPGEN("University Student")}, + {27, LPGEN("Web Building")}, + {99, LPGEN("Other Services")}, + {0, NULL} +}; + + +const FieldNamesItem affiliationField[]={ + {200, LPGEN("Alumni Org.")}, + {201, LPGEN("Charity Org.")}, + {202, LPGEN("Club/Social Org.")}, + {203, LPGEN("Community Org.")}, + {204, LPGEN("Cultural Org.")}, + {205, LPGEN("Fan Clubs")}, + {206, LPGEN("Fraternity/Sorority")}, + {207, LPGEN("Hobbyists Org.")}, + {208, LPGEN("International Org.")}, + {209, LPGEN("Nature and Environment Org.")}, + {210, LPGEN("Professional Org.")}, + {211, LPGEN("Scientific/Technical Org.")}, + {212, LPGEN("Self Improvement Group")}, + {213, LPGEN("Spiritual/Religious Org.")}, + {214, LPGEN("Sports Org.")}, + {215, LPGEN("Support Org.")}, + {216, LPGEN("Trade and Business Org.")}, + {217, LPGEN("Union")}, + {218, LPGEN("Volunteer Org.")}, + {299, LPGEN("Other")}, + {0, NULL} +}; + + +const FieldNamesItem agesField[]={ + {0x0011000D, LPGEN("13-17")}, + {0x00160012, LPGEN("18-22")}, + {0x001D0017, LPGEN("23-29")}, + {0x0027001E, LPGEN("30-39")}, + {0x00310028, LPGEN("40-49")}, + {0x003B0032, LPGEN("50-59")}, + {0x2710003C, LPGEN("60-above")}, + {-1, NULL} +}; + + +const FieldNamesItem maritalField[]={ + {10, LPGEN("Single")}, + {11, LPGEN("Close relationships")}, + {12, LPGEN("Engaged")}, + {20, LPGEN("Married")}, + {30, LPGEN("Divorced")}, + {31, LPGEN("Separated")}, + {40, LPGEN("Widowed")}, + {50, LPGEN("Open relationship")}, + {255, LPGEN("Other")}, + {0, NULL} +}; + + +char *LookupFieldName(const FieldNamesItem *table, int code) +{ + int i; + + if (code != 0) + { + for(i = 0; table[i].text; i++) + { + if (table[i].code == code) + return table[i].text; + } + + // Tried to get unexisting field name, you have an + // error in the data or in the table + _ASSERT(FALSE); + } + + return NULL; +} + + +char *LookupFieldNameUtf(const FieldNamesItem *table, int code, char *str, size_t strsize) +{ + char *szText = LookupFieldName(table, code); + + if (szText) + return ICQTranslateUtfStatic(szText, str, strsize); + + return NULL; +} diff --git a/protocols/IcqOscarJ/src/icq_fieldnames.h b/protocols/IcqOscarJ/src/icq_fieldnames.h new file mode 100644 index 0000000000..cf15475299 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_fieldnames.h @@ -0,0 +1,49 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +struct FieldNamesItem +{ + int code; + char *text; +}; + +extern const FieldNamesItem countryField[]; +extern const FieldNamesItem interestsField[]; +extern const FieldNamesItem languageField[]; +extern const FieldNamesItem pastField[]; +extern const FieldNamesItem genderField[]; +extern const FieldNamesItem agesField[]; +extern const FieldNamesItem studyLevelField[]; +extern const FieldNamesItem industryField[]; +extern const FieldNamesItem occupationField[]; +extern const FieldNamesItem affiliationField[]; +extern const FieldNamesItem maritalField[]; + +char *LookupFieldName(const FieldNamesItem *table, int code); +char *LookupFieldNameUtf(const FieldNamesItem *table, int code, char *str, size_t strsize); diff --git a/protocols/IcqOscarJ/src/icq_filerequests.cpp b/protocols/IcqOscarJ/src/icq_filerequests.cpp new file mode 100644 index 0000000000..d85de72580 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_filerequests.cpp @@ -0,0 +1,218 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +void CIcqProto::handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText) +{ + char* pszFileName = NULL; + DWORD dwFileSize; + HANDLE hCookieContact; + WORD wPort; + WORD wFilenameLength; + filetransfer* ft; + + + // Find the filetransfer that belongs to this response + if (!FindCookie(dwCookie, &hCookieContact, (void**)&ft)) + { + NetLog_Direct("Error: Received unexpected file transfer request response"); + return; + } + + FreeCookie(dwCookie); + + if (hCookieContact != HContactFromUIN(dwUin, NULL)) + { + NetLog_Direct("Error: UINs do not match in file transfer request response"); + return; + } + + // If status != 0, a request has been denied + if (wStatus != 0) + { + NetLog_Direct("File transfer denied by %u.", dwUin); + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)ft, 0); + + FreeCookie(dwCookie); + + return; + } + + if (wLen < 6) + { // sanity check + NetLog_Direct("Ignoring malformed file transfer request response"); + return; + } + + // Port to connect to + unpackWord(&buf, &wPort); + ft->dwRemotePort = wPort; + wLen -= 2; + + // Unknown + buf += 2; + wLen -= 2; + + // Filename + unpackLEWord(&buf, &wFilenameLength); + if (wFilenameLength > 0) + { + if (wFilenameLength > wLen - 2) + wFilenameLength = wLen - 2; + pszFileName = (char*)_alloca(wFilenameLength+1); + unpackString(&buf, pszFileName, wFilenameLength); + pszFileName[wFilenameLength] = '\0'; + } + wLen = wLen - 2 - wFilenameLength; + + if (wLen >= 4) + { // Total filesize + unpackLEDWord(&buf, &dwFileSize); + wLen -= 4; + } + else + dwFileSize = 0; + + NetLog_Direct("File transfer ack from %u, port %u, name %s, size %u", dwUin, ft->dwRemotePort, pszFileName, dwFileSize); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft, 0); + + OpenDirectConnection(ft->hContact, DIRECTCONN_FILE, ft); +} + +filetransfer* CIcqProto::CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion) +{ + filetransfer *ft = CreateIcqFileTransfer(); + + ft->dwUin = dwUin; + ft->hContact = hContact; + ft->nVersion = nVersion; + ft->pMessage.bMessageType = MTYPE_FILEREQ; + InitMessageCookie(&ft->pMessage); + + return ft; +} + +// pszDescription points to a string with the reason +// buf points to the first data after the string +void CIcqProto::handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC) +{ + BOOL bEmptyDesc = FALSE; + if (strlennull(pszDescription) == 0) { + pszDescription = Translate("No description given"); + bEmptyDesc = TRUE; + } + + // Empty port+pad + buf += 4; + wLen -= 4; + + // Filename + WORD wFilenameLength; + unpackLEWord(&buf, &wFilenameLength); + if (!wFilenameLength) { + NetLog_Direct("Ignoring malformed file send request"); + return; + } + + char *pszFileName = (char*)_alloca(wFilenameLength + 1); + unpackString(&buf, pszFileName, wFilenameLength); + pszFileName[wFilenameLength] = '\0'; + + wLen = wLen - 2 - wFilenameLength; + + // Total filesize + DWORD dwFileSize; + unpackLEDWord(&buf, &dwFileSize); + wLen -= 4; + + int bAdded; + HANDLE hContact = HContactFromUIN(dwUin, &bAdded); + + // Initialize a filetransfer struct + filetransfer *ft = CreateFileTransfer(hContact, dwUin, nVersion); + ft->dwCookie = dwCookie; + ft->szFilename = mir_strdup(pszFileName); + ft->szDescription = 0; + ft->fileId = -1; + ft->dwTotalSize = dwFileSize; + ft->pMessage.dwMsgID1 = dwID1; + ft->pMessage.dwMsgID2 = dwID2; + ft->bDC = bDC; + ft->bEmptyDesc = bEmptyDesc; + + // Send chain event + TCHAR* ptszFileName = mir_utf8decodeT(pszFileName); + + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time(NULL); + pre.tszDescription = mir_utf8decodeT(pszDescription); + pre.ptszFiles = &ptszFileName; + pre.lParam = (LPARAM)ft; + + CCSDATA ccs; + ccs.szProtoService = PSR_FILE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + mir_free(pre.tszDescription); + mir_free(ptszFileName); +} + +void CIcqProto::handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText) +{ + NetLog_Direct("handleDirectCancel: Unhandled cancel"); +} + +// ******************************************************************************* + +void CIcqProto::icq_CancelFileTransfer(HANDLE hContact, filetransfer* ft) +{ + DWORD dwCookie; + + if (FindCookieByData(ft, &dwCookie, NULL)) + FreeCookie(dwCookie); /* this bit stops a send that's waiting for acceptance */ + + if (IsValidFileTransfer(ft)) + { // Transfer still out there, end it + NetLib_CloseConnection(&ft->hConnection, FALSE); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + + if (!FindFileTransferDC(ft)) + { // Release orphan structure only + SafeReleaseFileTransfer((void**)&ft); + } + } +} diff --git a/protocols/IcqOscarJ/src/icq_filetransfer.cpp b/protocols/IcqOscarJ/src/icq_filetransfer.cpp new file mode 100644 index 0000000000..61484c3987 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_filetransfer.cpp @@ -0,0 +1,515 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static void file_buildProtoFileTransferStatus(filetransfer* ft, PROTOFILETRANSFERSTATUS* pfts) +{ + ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS)); + pfts->cbSize = sizeof(PROTOFILETRANSFERSTATUS); + pfts->hContact = ft->hContact; + pfts->flags = PFTS_UTF | (ft->sending ? PFTS_SENDING : PFTS_RECEIVING); /* Standard FT is Ansi only */ + if (ft->sending) + pfts->pszFiles = ft->pszFiles; + else + pfts->pszFiles = NULL; /* FIXME */ + pfts->totalFiles = ft->dwFileCount; + pfts->currentFileNumber = ft->iCurrentFile; + pfts->totalBytes = ft->dwTotalSize; + pfts->totalProgress = ft->dwBytesDone; + pfts->szWorkingDir = ft->szSavePath; + pfts->szCurrentFile = ft->szThisFile; + pfts->currentFileSize = ft->dwThisFileSize; + pfts->currentFileTime = ft->dwThisFileDate; + pfts->currentFileProgress = ft->dwFileBytesDone; +} + + +static void file_sendTransferSpeed(CIcqProto* ppro, directconnect* dc) +{ + icq_packet packet; + + directPacketInit(&packet, 5); + packByte(&packet, PEER_FILE_SPEED); /* Ident */ + packLEDWord(&packet, dc->ft->dwTransferSpeed); + ppro->sendDirectPacket(dc, &packet); +} + + +static void file_sendNick(CIcqProto* ppro, directconnect* dc) +{ + icq_packet packet; + char* szNick; + WORD wNickLen; + DBVARIANT dbv = {DBVT_DELETED}; + + if (ppro->getSettingString(NULL, "Nick", &dbv)) + szNick = ""; + else + szNick = dbv.pszVal; + + wNickLen = strlennull(szNick); + + directPacketInit(&packet, (WORD)(8 + wNickLen)); + packByte(&packet, PEER_FILE_INIT_ACK); /* Ident */ + packLEDWord(&packet, dc->ft->dwTransferSpeed); + packLEWord(&packet, (WORD)(wNickLen + 1)); + packBuffer(&packet, (LPBYTE)szNick, (WORD)(wNickLen + 1)); + ppro->sendDirectPacket(dc, &packet); + ICQFreeVariant(&dbv); +} + + +static void file_sendNextFile(CIcqProto* ppro, directconnect* dc) +{ + icq_packet packet; + struct _stati64 statbuf; + char szThisSubDir[MAX_PATH]; + + if (dc->ft->iCurrentFile >= (int)dc->ft->dwFileCount) + { + ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0); + ppro->CloseDirectConnection(dc); + dc->ft->hConnection = NULL; + return; + } + + dc->ft->szThisFile = dc->ft->pszFiles[dc->ft->iCurrentFile]; + if (FileStatUtf(dc->ft->szThisFile, &statbuf)) + { + ppro->icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); + ppro->CloseDirectConnection(dc); + dc->ft->hConnection = NULL; + return; + } + + char *pszThisFileName = FindFilePathContainer((LPCSTR*)dc->ft->pszFiles, dc->ft->iCurrentFile, szThisSubDir); + + if (statbuf.st_mode&_S_IFDIR) + { + dc->ft->currentIsDir = 1; + } + else + { + dc->ft->currentIsDir = 0; + dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_RDONLY, _S_IREAD); + if (dc->ft->fileId == -1) + { + ppro->icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); + ppro->CloseDirectConnection(dc); + dc->ft->hConnection = NULL; + return; + } + + } + dc->ft->dwThisFileSize = statbuf.st_size; + dc->ft->dwThisFileDate = statbuf.st_mtime; + dc->ft->dwFileBytesDone = 0; + + char *szThisFileNameAnsi = NULL, *szThisSubDirAnsi = NULL; + if (!utf8_decode(pszThisFileName, &szThisFileNameAnsi)) + szThisFileNameAnsi = NULL; + if (!utf8_decode(szThisSubDir, &szThisSubDirAnsi)) + szThisSubDirAnsi = NULL; + WORD wThisFileNameLen = strlennull(szThisFileNameAnsi); + WORD wThisSubDirLen = strlennull(szThisSubDirAnsi); + + directPacketInit(&packet, (WORD)(20 + wThisFileNameLen + wThisSubDirLen)); + packByte(&packet, PEER_FILE_NEXTFILE); /* Ident */ + packByte(&packet, (BYTE)((statbuf.st_mode & _S_IFDIR) != 0)); // Is subdir + packLEWord(&packet, (WORD)(wThisFileNameLen + 1)); + packBuffer(&packet, (LPBYTE)szThisFileNameAnsi, (WORD)(wThisFileNameLen + 1)); + packLEWord(&packet, (WORD)(wThisSubDirLen + 1)); + packBuffer(&packet, (LPBYTE)szThisSubDirAnsi, (WORD)(wThisSubDirLen + 1)); + packLEDWord(&packet, dc->ft->dwThisFileSize); + packLEDWord(&packet, statbuf.st_mtime); + packLEDWord(&packet, dc->ft->dwTransferSpeed); + SAFE_FREE(&szThisFileNameAnsi); + SAFE_FREE(&szThisSubDirAnsi); + ppro->sendDirectPacket(dc, &packet); + + ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0); +} + + +static void file_sendResume(CIcqProto* ppro, directconnect* dc) +{ + icq_packet packet; + + directPacketInit(&packet, 17); + packByte(&packet, PEER_FILE_RESUME); /* Ident */ + packLEDWord(&packet, dc->ft->dwFileBytesDone); /* file resume */ + packLEDWord(&packet, 0); /* unknown */ + packLEDWord(&packet, dc->ft->dwTransferSpeed); + packLEDWord(&packet, dc->ft->iCurrentFile + 1); /* file number */ + ppro->sendDirectPacket(dc, &packet); +} + + +static void file_sendData(CIcqProto* ppro, directconnect* dc) +{ + BYTE buf[2048]; + int bytesRead = 0; + + if (!dc->ft->currentIsDir) + { + icq_packet packet; + + if (dc->ft->fileId == -1) + return; + bytesRead = _read(dc->ft->fileId, buf, sizeof(buf)); + if (bytesRead == -1) + return; + + directPacketInit(&packet, (WORD)(1 + bytesRead)); + packByte(&packet, PEER_FILE_DATA); /* Ident */ + packBuffer(&packet, buf, (WORD)bytesRead); + ppro->sendDirectPacket(dc, &packet); + } + + dc->ft->dwBytesDone += bytesRead; + dc->ft->dwFileBytesDone += bytesRead; + + if (GetTickCount() > dc->ft->dwLastNotify + 500 || bytesRead == 0) + { + PROTOFILETRANSFERSTATUS pfts; + + file_buildProtoFileTransferStatus(dc->ft, &pfts); + ppro->BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts); + + dc->ft->dwLastNotify = GetTickCount(); + } + + if (bytesRead == 0) + { + if (!dc->ft->currentIsDir) _close(dc->ft->fileId); + dc->ft->fileId = -1; + dc->wantIdleTime = 0; + dc->ft->iCurrentFile++; + file_sendNextFile(ppro, dc); /* this will close the socket if no more files */ + } +} + + +void CIcqProto::handleFileTransferIdle(directconnect* dc) +{ + file_sendData(this, dc); +} + + +void CIcqProto::icq_sendFileResume(filetransfer *ft, int action, const char *szFilename) +{ + if (ft->hConnection == NULL) + return; + + directconnect *dc = FindFileTransferDC(ft); + if (!dc) return; // something is broken... + + int openFlags; + + switch (action) + { + case FILERESUME_RESUME: + openFlags = _O_BINARY | _O_WRONLY; + break; + + case FILERESUME_OVERWRITE: + openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; + ft->dwFileBytesDone = 0; + break; + + case FILERESUME_SKIP: + openFlags = _O_BINARY | _O_WRONLY; + ft->dwFileBytesDone = ft->dwThisFileSize; + break; + + case FILERESUME_RENAME: + openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; + SAFE_FREE(&ft->szThisFile); + ft->szThisFile = null_strdup(szFilename); + ft->dwFileBytesDone = 0; + break; + } + + ft->fileId = OpenFileUtf(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE); + if (ft->fileId == -1) + { + icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); + NetLib_CloseConnection(&ft->hConnection, FALSE); + return; + } + + if (action == FILERESUME_RESUME) + ft->dwFileBytesDone = _lseek(ft->fileId, 0, SEEK_END); + else + _lseek(ft->fileId, ft->dwFileBytesDone, SEEK_SET); + + ft->dwBytesDone += ft->dwFileBytesDone; + + file_sendResume(this, dc); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); +} + + +// small utility function +void NormalizeBackslash(char* path) +{ + int len = strlennull(path); + + if (len && path[len-1] != '\\') strcat(path, "\\"); +} + +/* a file transfer looks like this: +S: 0 +R: 5 +R: 1 +S: 2 +R: 3 +S: 6 * many +(for more files, send 2, 3, 6*many) +*/ + +void CIcqProto::handleFileTransferPacket(directconnect* dc, PBYTE buf, WORD wLen) +{ + if (wLen < 1) + return; + + NetLog_Direct("Handling file packet"); + + switch (buf[0]) + { + case PEER_FILE_INIT: /* first packet of a file transfer */ + if (dc->initialised) + return; + if (wLen < 19) + return; + buf += 5; /* id, and unknown 0 */ + dc->type = DIRECTCONN_FILE; + { + DWORD dwFileCount; + DWORD dwTotalSize; + DWORD dwTransferSpeed; + WORD wNickLength; + int bAdded; + + unpackLEDWord(&buf, &dwFileCount); + unpackLEDWord(&buf, &dwTotalSize); + unpackLEDWord(&buf, &dwTransferSpeed); + unpackLEWord(&buf, &wNickLength); + + dc->ft = FindExpectedFileRecv(dc->dwRemoteUin, dwTotalSize); + if (dc->ft == NULL) + { + NetLog_Direct("Unexpected file receive"); + CloseDirectConnection(dc); + return; + } + dc->ft->dwFileCount = dwFileCount; + dc->ft->dwTransferSpeed = dwTransferSpeed; + dc->ft->hContact = HContactFromUIN(dc->ft->dwUin, &bAdded); + dc->ft->dwBytesDone = 0; + dc->ft->iCurrentFile = -1; + dc->ft->fileId = -1; + dc->ft->hConnection = dc->hConnection; + dc->ft->dwLastNotify = GetTickCount(); + + dc->initialised = 1; + + file_sendTransferSpeed(this, dc); + file_sendNick(this, dc); + } + BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, dc->ft, 0); + break; + + case PEER_FILE_INIT_ACK: + if (wLen < 8) + return; + buf++; + unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); + /* followed by nick */ + file_sendNextFile(this, dc); + break; + + case PEER_FILE_NEXTFILE: + if (wLen < 20) + return; + buf++; /* id */ + { + char *szAnsi; + WORD wThisFilenameLen, wSubdirLen; + BYTE isDirectory; + + unpackByte(&buf, &isDirectory); + unpackLEWord(&buf, &wThisFilenameLen); + if (wLen < 19 + wThisFilenameLen) + return; + SAFE_FREE(&dc->ft->szThisFile); + szAnsi = (char *)_alloca(wThisFilenameLen + 1); + memcpy(szAnsi, buf, wThisFilenameLen); + szAnsi[wThisFilenameLen] = '\0'; + dc->ft->szThisFile = ansi_to_utf8(szAnsi); + buf += wThisFilenameLen; + + unpackLEWord(&buf, &wSubdirLen); + if (wLen < 18 + wThisFilenameLen + wSubdirLen) + return; + SAFE_FREE(&dc->ft->szThisSubdir); + szAnsi = (char *)_alloca(wSubdirLen + 1); + memcpy(szAnsi, buf, wSubdirLen); + szAnsi[wSubdirLen] = '\0'; + dc->ft->szThisSubdir = ansi_to_utf8(szAnsi); + buf += wSubdirLen; + + unpackLEDWord(&buf, &dc->ft->dwThisFileSize); + unpackLEDWord(&buf, &dc->ft->dwThisFileDate); + unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); + + /* no cheating with paths */ + if (!IsValidRelativePath(dc->ft->szThisFile) || !IsValidRelativePath(dc->ft->szThisSubdir)) + { + NetLog_Direct("Invalid path information"); + break; + } + + char *szFullPath = (char*)SAFE_MALLOC(strlennull(dc->ft->szSavePath)+strlennull(dc->ft->szThisSubdir)+strlennull(dc->ft->szThisFile)+3); + strcpy(szFullPath, dc->ft->szSavePath); + NormalizeBackslash(szFullPath); + strcat(szFullPath, dc->ft->szThisSubdir); + NormalizeBackslash(szFullPath); +// _chdir(szFullPath); // set current dir - not very useful + strcat(szFullPath, dc->ft->szThisFile); + // we joined the full path to dest file + SAFE_FREE(&dc->ft->szThisFile); + dc->ft->szThisFile = szFullPath; + + dc->ft->dwFileBytesDone = 0; + dc->ft->iCurrentFile++; + + if (isDirectory) + { + MakeDirUtf(dc->ft->szThisFile); + dc->ft->fileId = -1; + } + else + { + /* file resume */ + PROTOFILETRANSFERSTATUS pfts = {0}; + + file_buildProtoFileTransferStatus(dc->ft, &pfts); + if (BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, dc->ft, (LPARAM)&pfts)) + break; /* UI supports resume: it will call PS_FILERESUME */ + + dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); + if (dc->ft->fileId == -1) + { + icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); + CloseDirectConnection(dc); + dc->ft->hConnection = NULL; + break; + } + } + } + file_sendResume(this, dc); + BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0); + break; + + case PEER_FILE_RESUME: + if (dc->ft->fileId == -1 && !dc->ft->currentIsDir) + return; + if (wLen < 13) + return; + if (wLen < 17) + NetLog_Direct("Warning: Received short PEER_FILE_RESUME"); + buf++; + { + DWORD dwRestartFrom; + + unpackLEDWord(&buf, &dwRestartFrom); + if (dwRestartFrom > dc->ft->dwThisFileSize) + return; + buf += 4; /* unknown. 0 */ + unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); + buf += 4; /* unknown. 1 */ + if (!dc->ft->currentIsDir) + _lseek(dc->ft->fileId, dwRestartFrom, 0); + dc->wantIdleTime = 1; + dc->ft->dwBytesDone += dwRestartFrom; + dc->ft->dwFileBytesDone += dwRestartFrom; + } + break; + + case PEER_FILE_SPEED: + if (wLen < 5) + return; + buf++; + unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); + dc->ft->dwLastNotify = GetTickCount(); + break; + + case PEER_FILE_DATA: + if (!dc->ft->currentIsDir) + { + if (dc->ft->fileId == -1) + break; + buf++; wLen--; + _write(dc->ft->fileId, buf, wLen); + } + else + wLen = 0; + dc->ft->dwBytesDone += wLen; + dc->ft->dwFileBytesDone += wLen; + if (GetTickCount() > dc->ft->dwLastNotify + 500 || wLen < 2048) + { + PROTOFILETRANSFERSTATUS pfts; + + file_buildProtoFileTransferStatus(dc->ft, &pfts); + BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts); + dc->ft->dwLastNotify = GetTickCount(); + } + if (wLen < 2048) + { + /* EOF */ + if (!dc->ft->currentIsDir) + _close(dc->ft->fileId); + dc->ft->fileId = -1; + if ((DWORD)dc->ft->iCurrentFile == dc->ft->dwFileCount - 1) + { + dc->type = DIRECTCONN_CLOSING; /* this guarantees that we won't accept any more data but that the sender is still free to closesocket() neatly */ + BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0); + } + } + break; + + default: + NetLog_Direct("Unknown file transfer packet ignored."); + break; + } +} diff --git a/protocols/IcqOscarJ/src/icq_firstrun.cpp b/protocols/IcqOscarJ/src/icq_firstrun.cpp new file mode 100644 index 0000000000..1208d6d0ec --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_firstrun.cpp @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +static void accountLoadDetails(CIcqProto *ppro, HWND hwndDlg) +{ + char pszUIN[20]; + DWORD dwUIN = ppro->getContactUin(NULL); + if (dwUIN) + { + null_snprintf(pszUIN, 20, "%u", dwUIN); + SetDlgItemTextA(hwndDlg, IDC_UIN, pszUIN); + } + + char pszPwd[PASSWORDMAXLEN]; + if (ppro->GetUserStoredPassword(pszPwd, PASSWORDMAXLEN)) + SetDlgItemTextA(hwndDlg, IDC_PW, pszPwd); +} + + +INT_PTR CALLBACK icq_FirstRunDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ppro->m_hIconProtocol->GetIcon(true)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ppro->m_hIconProtocol->GetIcon()); + + SendDlgItemMessage(hwndDlg, IDC_PW, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); + + accountLoadDetails(ppro, hwndDlg); + } + return TRUE; + + case WM_DESTROY: + ppro->m_hIconProtocol->ReleaseIcon(true); + ppro->m_hIconProtocol->ReleaseIcon(); + break; + + case WM_CLOSE: + EndDialog(hwndDlg, 0); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_REGISTER: + CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_REGISTER); + break; + + case IDC_UIN: + case IDC_PW: + if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + char str[128]; + GetDlgItemTextA(hwndDlg, IDC_UIN, str, sizeof(str)); + ppro->setSettingDword(NULL, UNIQUEIDSETTING, atoi(str)); + GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(ppro->m_szPassword)); + strcpy(ppro->m_szPassword, str); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ppro->m_szPassword), (LPARAM) str); + ppro->setSettingString(NULL, "Password", str); + } + break; + + case PSN_RESET: + accountLoadDetails(ppro, hwndDlg); + break; + } + break; + } + + return FALSE; +} + + +INT_PTR CIcqProto::OnCreateAccMgrUI(WPARAM wParam, LPARAM lParam) +{ + return (INT_PTR)CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ICQACCOUNT), (HWND)lParam, icq_FirstRunDlgProc, LPARAM(this)); +} diff --git a/protocols/IcqOscarJ/src/icq_http.cpp b/protocols/IcqOscarJ/src/icq_http.cpp new file mode 100644 index 0000000000..3e50db43ed --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_http.cpp @@ -0,0 +1,212 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004,2005,2006 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// HTTP Gateway Handling routines +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +int icq_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr) +{ + // initial response from ICQ http gateway + WORD wLen, wVersion, wType; + WORD wIpLen; + DWORD dwSid1, dwSid2, dwSid3, dwSid4; + BYTE *buf; + char szSid[33], szHttpServer[256], szHttpGetUrl[300], szHttpPostUrl[300]; + NETLIBHTTPPROXYINFO nlhpi = {0}; + + if (nlhr->dataLength < 31) + { + SetLastError(ERROR_INVALID_DATA); + return 0; + } + + buf = (PBYTE)nlhr->pData; + unpackWord(&buf, &wLen); + unpackWord(&buf, &wVersion); /* always 0x0443 */ + unpackWord(&buf, &wType); /* hello reply */ + buf += 6; /* dunno */ + unpackDWord(&buf, &dwSid1); + unpackDWord(&buf, &dwSid2); + unpackDWord(&buf, &dwSid3); + unpackDWord(&buf, &dwSid4); + null_snprintf(szSid, 33, "%08x%08x%08x%08x", dwSid1, dwSid2, dwSid3, dwSid4); + unpackWord(&buf, &wIpLen); + + if(nlhr->dataLength < 30 + wIpLen || wIpLen == 0 || wIpLen > sizeof(szHttpServer) - 1) + { + SetLastError(ERROR_INVALID_DATA); + return 0; + } + + SetGatewayIndex(hConn, 1); // new master connection begins here + + memcpy(szHttpServer, buf, wIpLen); + szHttpServer[wIpLen] = '\0'; + + nlhpi.cbSize = sizeof(nlhpi); + nlhpi.flags = NLHPIF_USEPOSTSEQUENCE; + nlhpi.szHttpGetUrl = szHttpGetUrl; + nlhpi.szHttpPostUrl = szHttpPostUrl; + nlhpi.firstPostSequence = 1; + null_snprintf(szHttpGetUrl, 300, "http://%s/monitor?sid=%s", szHttpServer, szSid); + null_snprintf(szHttpPostUrl, 300, "http://%s/data?sid=%s&seq=", szHttpServer, szSid); + + return CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi); +} + + + +int icq_httpGatewayBegin(HANDLE hConn, NETLIBOPENCONNECTION* nloc) +{ // open our "virual data connection" + icq_packet packet; + size_t serverNameLen; + + serverNameLen = strlennull(nloc->szHost); + + packet.wLen = (WORD)(serverNameLen + 4); + write_httphdr(&packet, HTTP_PACKETTYPE_LOGIN, GetGatewayIndex(hConn)); + packWord(&packet, (WORD)serverNameLen); + packBuffer(&packet, (LPBYTE)nloc->szHost, (WORD)serverNameLen); + packWord(&packet, nloc->wPort); + INT_PTR res = Netlib_Send(hConn, (char*)packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP); + SAFE_FREE((void**)&packet.pData); + + return res != SOCKET_ERROR; +} + + + +int icq_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend) +{ + PBYTE sendBuf = buf; + int sendLen = len; + int sendResult = 0; + + while (sendLen > 0) + { // imitate polite behaviour of icq5.1 and split large packets + icq_packet packet; + WORD curLen; + int curResult; + + if (sendLen > 512) curLen = 512; else curLen = (WORD)sendLen; + // send wrapped data + packet.wLen = curLen; + write_httphdr(&packet, HTTP_PACKETTYPE_FLAP, GetGatewayIndex(hConn)); + packBuffer(&packet, sendBuf, (WORD)curLen); + + NETLIBBUFFER nlb={ (char*)packet.pData, packet.wLen, flags }; + curResult = pfnNetlibSend((WPARAM)hConn, (LPARAM)&nlb); + + SAFE_FREE((void**)&packet.pData); + + // sending failed, end loop + if (curResult <= 0) + return curResult; + // calculare real number of data bytes sent + if (curResult > 14) sendResult += curResult - 14; + // move on + sendLen -= curLen; + sendBuf += curLen; + } + + return sendResult; +} + + + +PBYTE icq_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST* nlhr, PBYTE buf, int len, int* outBufLen, void *(*NetlibRealloc)(void *, size_t)) +{ + WORD wLen, wType; + DWORD dwPackSeq; + PBYTE tbuf; + int i, copyBytes; + + + tbuf = buf; + for(i = 0;;) + { + if (tbuf - buf + 2 > len) + break; + unpackWord(&tbuf, &wLen); + if (wLen < 12) + break; + if (tbuf - buf + wLen > len) + break; + tbuf += 2; /* version */ + unpackWord(&tbuf, &wType); + tbuf += 4; /* flags */ + unpackDWord(&tbuf, &dwPackSeq); + if (wType == HTTP_PACKETTYPE_FLAP) + { // it is normal data packet + copyBytes = wLen - 12; + if (copyBytes > len - i) + { + /* invalid data - do our best to get something out of it */ + copyBytes = len - i; + } + memcpy(buf + i, tbuf, copyBytes); + i += copyBytes; + } + else if (wType == HTTP_PACKETTYPE_LOGINREPLY) + { // our "virtual connection" was established, good + BYTE bRes; + + unpackByte(&tbuf, &bRes); + wLen -= 1; + if (!bRes) + Netlib_Logf( NULL, "Gateway Connection #%d Established.", dwPackSeq); + else + Netlib_Logf( NULL, "Gateway Connection #%d Failed, error: %d", dwPackSeq, bRes); + } + else if (wType == HTTP_PACKETTYPE_CLOSEREPLY) + { // "virtual connection" closed - only received if any other "virual connection" still active + Netlib_Logf( NULL, "Gateway Connection #%d Closed.", dwPackSeq); + } + tbuf += wLen - 12; + } + *outBufLen = i; + + return buf; +} + + + +int icq_httpGatewayWalkTo(HANDLE hConn, NETLIBOPENCONNECTION* nloc) +{ // this is bad simplification - for avatars to work we need to handle + // two "virtual connections" at the same time + icq_packet packet; + DWORD dwGatewaySeq = GetGatewayIndex(hConn); + + packet.wLen = 0; + write_httphdr(&packet, HTTP_PACKETTYPE_CLOSE, dwGatewaySeq); + Netlib_Send(hConn, (char*)packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP); + // we closed virtual connection, open new one + dwGatewaySeq++; + SetGatewayIndex(hConn, dwGatewaySeq); + return icq_httpGatewayBegin(hConn, nloc); +} diff --git a/protocols/IcqOscarJ/src/icq_http.h b/protocols/IcqOscarJ/src/icq_http.h new file mode 100644 index 0000000000..017a5ea5fc --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_http.h @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004,2005 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_HTTP_H +#define __ICQ_HTTP_H + +#define HTTP_PROXY_VERSION 0x0443 + +#define HTTP_PACKETTYPE_HELLOREPLY 2 +#define HTTP_PACKETTYPE_LOGIN 3 +#define HTTP_PACKETTYPE_LOGINREPLY 4 /* contains 1 byte: 0 */ +#define HTTP_PACKETTYPE_FLAP 5 +#define HTTP_PACKETTYPE_CLOSE 6 /* contains no data */ +#define HTTP_PACKETTYPE_CLOSEREPLY 7 /* contains 1 byte: 0 */ + +int icq_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr); +int icq_httpGatewayBegin(HANDLE hConn, NETLIBOPENCONNECTION *nloc); +int icq_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend); +PBYTE icq_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr, PBYTE buf, int bufLen, int *outBufLen, void *(*NetlibRealloc)(void *, size_t)); +int icq_httpGatewayWalkTo(HANDLE hConn, NETLIBOPENCONNECTION* nloc); + +#endif /* __ICQ_HTTP_H */ diff --git a/protocols/IcqOscarJ/src/icq_infoupdate.cpp b/protocols/IcqOscarJ/src/icq_infoupdate.cpp new file mode 100644 index 0000000000..014df20e01 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_infoupdate.cpp @@ -0,0 +1,401 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Background thread for automatic update of user details +// +// ----------------------------------------------------------------------------- + +#include "icqoscar.h" + +// Retrieve users' info +void CIcqProto::icq_InitInfoUpdate(void) +{ + // Create wait objects + hInfoQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (hInfoQueueEvent) { + // Init mutexes + infoUpdateMutex = new icq_critical_section(); + + // Init list + for (int i = 0; iEnter(); + + // Check if in list + for (i = 0; (iLeave(); + + return TRUE; + } + + return FALSE; +} + + +void CIcqProto::icq_DequeueUser(DWORD dwUin) +{ + if (nInfoUserCount > 0) + { + int nChecked = 0; + // Check if in list + infoUpdateMutex->Enter(); + for (int i = 0; (i < LISTSIZE && nChecked < nInfoUserCount); i++) + { + if (m_infoUpdateList[i].dwUin) + { + nChecked++; + // Remove from list + if (m_infoUpdateList[i].dwUin == dwUin) + { +#ifdef _DEBUG + NetLog_Server("Dequeued user %u", m_infoUpdateList[i].dwUin); +#endif + m_infoUpdateList[i].dwUin = 0; + m_infoUpdateList[i].hContact = NULL; + m_infoUpdateList[i].queued = 0; + nInfoUserCount--; + break; + } + } + } + infoUpdateMutex->Leave(); + } +} + + +void CIcqProto::icq_RescanInfoUpdate() +{ + bInfoPendingUsers = 0; + /* This is here, cause we do not want to emit large number of reuqest at once, + fill queue, and let thread deal with it */ + bInfoUpdateEnabled = 0; // freeze thread + + // Queue all outdated users + HANDLE hContact = FindFirstContact(); + while (hContact != NULL) + { + if (IsMetaInfoChanged(hContact)) + { // Queue user + if (!icq_QueueUser(hContact)) + { // The queue is full, pause queuing contacts + bInfoPendingUsers = 1; + break; + } + } + hContact = FindNextContact(hContact); + } + + bInfoUpdateEnabled = TRUE; +} + + +void CIcqProto::icq_EnableUserLookup(BOOL bEnable) +{ + bInfoUpdateEnabled = bEnable; + + // Notify worker thread + if (bInfoUpdateEnabled && hInfoQueueEvent) + SetEvent(hInfoQueueEvent); +} + + +void __cdecl CIcqProto::InfoUpdateThread( void* ) +{ + int i; + DWORD dwWait = WAIT_OBJECT_0; + + NetLog_Server("%s thread starting.", "Info-Update"); + + bInfoUpdateRunning = TRUE; + + while (bInfoUpdateRunning) + { + if (!nInfoUserCount && bInfoPendingUsers) // whole queue processed, check if more users needs updating + icq_RescanInfoUpdate(); + + if (!nInfoUserCount || !bInfoUpdateEnabled || !icqOnline()) + { + dwWait = WAIT_TIMEOUT; + while (bInfoUpdateRunning && dwWait == WAIT_TIMEOUT) + { // wait for new work or until we should end + dwWait = ICQWaitForSingleObject(hInfoQueueEvent, 10000); + } + } + if (!bInfoUpdateRunning) break; + + switch (dwWait) { + case WAIT_IO_COMPLETION: + // Possible shutdown in progress + break; + + case WAIT_OBJECT_0: + case WAIT_TIMEOUT: + // Time to check for new users + if (!bInfoUpdateEnabled) continue; // we can't send requests now + + if (nInfoUserCount && icqOnline()) + { + time_t now = time(NULL); + BOOL bNotReady = FALSE, bTimeOuted = FALSE; + + // Check the list, take only users that were there for at least 5sec + // wait if any user is there shorter than 5sec and not a single user is there longer than 20sec + infoUpdateMutex->Enter(); + for (i = 0; i= now) + bNotReady = TRUE; + } + } + infoUpdateMutex->Leave(); + + if (!bTimeOuted && bNotReady) + { + SleepEx(1000, TRUE); + if (!bInfoUpdateRunning) + { // need to end as fast as possible + NetLog_Server("%s thread ended.", "Info-Update"); + goto LBL_Exit; + } + continue; + } + + if (FindCookie(dwInfoActiveRequest, NULL, NULL)) + { // only send another request, when the previous is completed +#ifdef _DEBUG + NetLog_Server("Info-Update: Request 0x%x still in progress.", dwInfoActiveRequest); +#endif + SleepEx(1000, TRUE); + if (!bInfoUpdateRunning) + { // need to end as fast as possible + NetLog_Server("%s thread ended.", "Info-Update"); + goto LBL_Exit; + } + continue; + } + +#ifdef _DEBUG + NetLog_Server("Info-Update: Users %u in queue.", nInfoUserCount); +#endif + // Either some user is waiting long enough, or all users are ready (waited at least the minimum time) + m_ratesMutex->Enter(); + if (!m_rates) + { // we cannot send info request - icq is offline + m_ratesMutex->Leave(); + break; + } + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); + while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_IDLE_30)) + { // we are over rate, need to wait before sending + int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_50); + + m_ratesMutex->Leave(); +#ifdef _DEBUG + NetLog_Server("Rates: InfoUpdate delayed %dms", nDelay); +#endif + SleepEx(nDelay, TRUE); // do not keep things locked during sleep + if (!bInfoUpdateRunning) + { // need to end as fast as possible + NetLog_Server("%s thread ended.", "Info-Update"); + goto LBL_Exit; + } + m_ratesMutex->Enter(); + if (!m_rates) // we lost connection when we slept, go away + break; + } + if (!m_rates) + { // we cannot send info request - icq is offline + m_ratesMutex->Leave(); + break; + } + m_ratesMutex->Leave(); + + userinfo *hContactList[LISTSIZE]; + int nListIndex = 0; + BYTE *pRequestData = NULL; + int nRequestSize = 0; + + infoUpdateMutex->Enter(); + for (i = 0; iLeave(); + break; + } + if (!(dwInfoActiveRequest = sendUserInfoMultiRequest(pRequestData, nRequestSize, nListIndex))) + { // sending data packet failed + SAFE_FREE((void**)&pRequestData); + infoUpdateMutex->Leave(); + break; + } + SAFE_FREE((void**)&pRequestData); + + for (i = 0; idwUin = 0; + hContactList[i]->hContact = NULL; + hContactList[i]->queued = 0; + nInfoUserCount--; + } + infoUpdateMutex->Leave(); + } + break; + + default: + // Something strange happened. Exit + bInfoUpdateRunning = FALSE; + break; + } + } + + NetLog_Server("%s thread ended.", "Info-Update"); + +LBL_Exit: + SAFE_DELETE(&infoUpdateMutex); + CloseHandle(hInfoQueueEvent); +} + +// Clean up before exit +void CIcqProto::icq_InfoUpdateCleanup(void) +{ + NetLog_Server("%s must die.", "Info-Update"); + bInfoUpdateRunning = FALSE; + if (hInfoQueueEvent) + SetEvent(hInfoQueueEvent); // break queue loop +} diff --git a/protocols/IcqOscarJ/src/icq_menu.cpp b/protocols/IcqOscarJ/src/icq_menu.cpp new file mode 100644 index 0000000000..f3dd072cde --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_menu.cpp @@ -0,0 +1,263 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +#include + +static HANDLE hPrebuildMenuHook; + +HANDLE g_hContactMenuItems[6]; +HANDLE g_hContactMenuSvc[6]; + +static int sttCompareProtocols(const CIcqProto *p1, const CIcqProto *p2) +{ + return strcmp(p1->m_szModuleName, p2->m_szModuleName); +} + +LIST g_Instances(1, sttCompareProtocols); + +static CIcqProto* IcqGetInstanceByHContact(HANDLE hContact) +{ + char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return NULL; + + for (int i = 0; i < g_Instances.getCount(); i++) + if (!strcmp(szProto, g_Instances[i]->m_szModuleName)) + return g_Instances[i]; + + return NULL; +} + +static INT_PTR IcqMenuHandleRequestAuth(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->RequestAuthorization(wParam, lParam) : 0; +} + +static INT_PTR IcqMenuHandleGrantAuth(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->GrantAuthorization(wParam, lParam) : 0; +} + +static INT_PTR IcqMenuHandleRevokeAuth(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->RevokeAuthorization(wParam, lParam) : 0; +} + +static INT_PTR IcqMenuHandleAddServContact(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->AddServerContact(wParam, lParam) : 0; +} + +static INT_PTR IcqMenuHandleXStatusDetails(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->ShowXStatusDetails(wParam, lParam) : 0; +} + +static INT_PTR IcqMenuHandleOpenProfile(WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OpenWebProfile(wParam, lParam) : 0; +} + +static void sttEnableMenuItem( HANDLE hMenuItem, bool bEnable ) +{ + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS; + if ( !bEnable ) + clmi.flags |= CMIF_HIDDEN; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi ); +} + +static int IcqPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) +{ + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REQUEST], FALSE); + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_GRANT], FALSE); + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REVOKE], FALSE); + sttEnableMenuItem(g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], FALSE); + sttEnableMenuItem(g_hContactMenuItems[ICMI_XSTATUS_DETAILS], FALSE); + sttEnableMenuItem(g_hContactMenuItems[ICMI_OPEN_PROFILE], FALSE); + + CIcqProto* ppro = IcqGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnPreBuildContactMenu(wParam, lParam) : 0; +} + +void g_MenuInit(void) +{ + /////////////// + // Contact menu + + hPrebuildMenuHook = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, IcqPrebuildContactMenu); + + // Contact menu initialization + + char str[MAXMODULELABELLENGTH], *pszDest = str + 3; + strcpy( str, "ICQ" ); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(CLISTMENUITEM); + mi.pszService = str; + mi.flags = CMIF_ICONFROMICOLIB; + + // "Request authorization" + mi.pszName = LPGEN("Request authorization"); + mi.position = 1000030000; + mi.icolibItem = hStaticIcons[ISI_AUTH_REQUEST]->Handle(); + strcpy(pszDest, MS_REQ_AUTH); + g_hContactMenuItems[ICMI_AUTH_REQUEST] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_AUTH_REQUEST] = CreateServiceFunction( str, IcqMenuHandleRequestAuth ); + + // "Grant authorization" + mi.pszName = LPGEN("Grant authorization"); + mi.position = 1000029999; + mi.icolibItem = hStaticIcons[ISI_AUTH_GRANT]->Handle(); + strcpy(pszDest, MS_GRANT_AUTH); + g_hContactMenuItems[ICMI_AUTH_GRANT] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_AUTH_GRANT] = CreateServiceFunction(mi.pszService, IcqMenuHandleGrantAuth); + + // "Revoke authorization" + mi.pszName = LPGEN("Revoke authorization"); + mi.position = 1000029998; + mi.icolibItem = hStaticIcons[ISI_AUTH_REVOKE]->Handle(); + strcpy(pszDest, MS_REVOKE_AUTH); + g_hContactMenuItems[ICMI_AUTH_REVOKE] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_AUTH_REVOKE] = CreateServiceFunction(mi.pszService, IcqMenuHandleRevokeAuth); + + // "Add to server list" + mi.pszName = LPGEN("Add to server list"); + mi.position = -2049999999; + mi.icolibItem = hStaticIcons[ISI_ADD_TO_SERVLIST]->Handle(); + strcpy(pszDest, MS_ICQ_ADDSERVCONTACT); + g_hContactMenuItems[ICMI_ADD_TO_SERVLIST] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_ADD_TO_SERVLIST] = CreateServiceFunction(mi.pszService, IcqMenuHandleAddServContact); + + // "Show custom status details" + mi.pszName = LPGEN("Show custom status details"); + mi.position = -2000004999; + mi.flags = 0; + strcpy(pszDest, MS_XSTATUS_SHOWDETAILS); + g_hContactMenuItems[ICMI_XSTATUS_DETAILS] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_XSTATUS_DETAILS] = CreateServiceFunction(mi.pszService, IcqMenuHandleXStatusDetails); + + // "Open ICQ profile" + mi.pszName = LPGEN("Open ICQ profile"); + mi.position = 1000029997; + strcpy(pszDest, MS_OPEN_PROFILE); + g_hContactMenuItems[ICMI_OPEN_PROFILE] = Menu_AddContactMenuItem(&mi); + g_hContactMenuSvc[ICMI_OPEN_PROFILE] = CreateServiceFunction(mi.pszService, IcqMenuHandleOpenProfile); +} + +void g_MenuUninit(void) +{ + UnhookEvent(hPrebuildMenuHook); + + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_REQUEST], 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_GRANT], 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_AUTH_REVOKE], 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_XSTATUS_DETAILS], 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_OPEN_PROFILE], 0); + + DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_REQUEST]); + DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_GRANT]); + DestroyServiceFunction(g_hContactMenuSvc[ICMI_AUTH_REVOKE]); + DestroyServiceFunction(g_hContactMenuSvc[ICMI_ADD_TO_SERVLIST]); + DestroyServiceFunction(g_hContactMenuSvc[ICMI_XSTATUS_DETAILS]); + DestroyServiceFunction(g_hContactMenuSvc[ICMI_OPEN_PROFILE]); +} + + +INT_PTR CIcqProto::OpenWebProfile(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + DWORD dwUin = getContactUin(hContact); + char url[256]; + mir_snprintf(url, sizeof(url), "http://www.icq.com/people/%d",dwUin); + return CallService(MS_UTILS_OPENURL, 1, (LPARAM)url); +} + + +int CIcqProto::OnPreBuildContactMenu(WPARAM wParam, LPARAM) +{ + HANDLE hContact = (HANDLE)wParam; + if (hContact == NULL) + return 0; + + if (icqOnline()) + { + BOOL bCtrlPressed = (GetKeyState(VK_CONTROL)&0x8000 ) != 0; + + DWORD dwUin = getContactUin(hContact); + + + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REQUEST], + dwUin && (bCtrlPressed || (getSettingByte((HANDLE)wParam, "Auth", 0) && getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0)))); + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_GRANT], dwUin && (bCtrlPressed || getSettingByte((HANDLE)wParam, "Grant", 0))); + sttEnableMenuItem(g_hContactMenuItems[ICMI_AUTH_REVOKE], + dwUin && (bCtrlPressed || (getSettingByte(NULL, "PrivacyItems", 0) && !getSettingByte((HANDLE)wParam, "Grant", 0)))); + sttEnableMenuItem(g_hContactMenuItems[ICMI_ADD_TO_SERVLIST], + m_bSsiEnabled && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0) && + !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0) && + !DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)); + } + + sttEnableMenuItem(g_hContactMenuItems[ICMI_OPEN_PROFILE],getContactUin(hContact) != 0); + BYTE bXStatus = getContactXStatus((HANDLE)wParam); + + sttEnableMenuItem(g_hContactMenuItems[ICMI_XSTATUS_DETAILS], m_bHideXStatusUI ? 0 : bXStatus != 0); + if (bXStatus && !m_bHideXStatusUI) { + CLISTMENUITEM clmi = {0}; + + clmi.cbSize = sizeof(clmi); + clmi.flags = CMIM_ICON; + + if (bXStatus > 0 && bXStatus <= XSTATUS_COUNT) + clmi.hIcon = getXStatusIcon(bXStatus, LR_SHARED); + else + clmi.hIcon = LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hContactMenuItems[ICMI_XSTATUS_DETAILS], (LPARAM)&clmi); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnPreBuildStatusMenu event + +int CIcqProto::OnPreBuildStatusMenu(WPARAM wParam, LPARAM lParam) +{ + InitXStatusItems(TRUE); + return 0; +} diff --git a/protocols/IcqOscarJ/src/icq_opts.cpp b/protocols/IcqOscarJ/src/icq_opts.cpp new file mode 100644 index 0000000000..44c1881d14 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_opts.cpp @@ -0,0 +1,617 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +#include + +extern BOOL bPopUpService; + +static const char* szLogLevelDescr[] = { + LPGEN("Display all problems"), + LPGEN("Display problems causing possible loss of data"), + LPGEN("Display explanations for disconnection"), + LPGEN("Display problems requiring user intervention"), + LPGEN("Do not display any problems (not recommended)") +}; + +static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0; + +static void LoadDBCheckState(CIcqProto* ppro, HWND hwndDlg, int idCtrl, const char* szSetting, BYTE bDef) +{ + CheckDlgButton(hwndDlg, idCtrl, ppro->getSettingByte(NULL, szSetting, bDef)); +} + +static void StoreDBCheckState(CIcqProto* ppro, HWND hwndDlg, int idCtrl, const char* szSetting) +{ + ppro->setSettingByte(NULL, szSetting, (BYTE)IsDlgButtonChecked(hwndDlg, idCtrl)); +} + +static void OptDlgChanged(HWND hwndDlg) +{ + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// standalone option pages + +static INT_PTR CALLBACK DlgProcIcqOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + { + DWORD dwUin = ppro->getContactUin(NULL); + if (dwUin) + SetDlgItemInt(hwndDlg, IDC_ICQNUM, dwUin, FALSE); + else // keep it empty when no UIN entered + SetDlgItemTextA(hwndDlg, IDC_ICQNUM, ""); + + SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_LIMITTEXT, PASSWORDMAXLEN - 1, 0); + + char pszPwd[PASSWORDMAXLEN]; + if (ppro->GetUserStoredPassword(pszPwd, sizeof(pszPwd))) + { + //bit of a security hole here, since it's easy to extract a password from an edit box + SetDlgItemTextA(hwndDlg, IDC_PASSWORD, pszPwd); + } + + LoadDBCheckState(ppro, hwndDlg, IDC_SSL, "SecureConnection", DEFAULT_SECURE_CONNECTION); + LoadDBCheckState(ppro, hwndDlg, IDC_MD5LOGIN, "SecureLogin", DEFAULT_SECURE_LOGIN); + + char szServer[MAX_PATH]; + if (!ppro->getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH)) + SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, szServer); + else + SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); + + SetDlgItemInt(hwndDlg, IDC_ICQPORT, ppro->getSettingWord(NULL, "OscarPort", IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT), FALSE); + LoadDBCheckState(ppro, hwndDlg, IDC_KEEPALIVE, "KeepAlive", DEFAULT_KEEPALIVE_ENABLED); + SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETRANGE, FALSE, MAKELONG(0, 4)); + SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_SETPOS, TRUE, 4-ppro->getSettingByte(NULL, "ShowLogLevel", LOG_WARNING)); + { + char buf[MAX_PATH]; + SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_GETPOS, 0, 0)], buf, MAX_PATH)); + } + ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_HIDE); + LoadDBCheckState(ppro, hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox", 0); + } + return TRUE; + + case WM_HSCROLL: + { + char str[MAX_PATH]; + + SetDlgItemTextUtf(hwndDlg, IDC_LEVELDESCR, ICQTranslateUtfStatic(szLogLevelDescr[4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL,TBM_GETPOS, 0, 0)], str, MAX_PATH)); + OptDlgChanged(hwndDlg); + } + break; + + case WM_COMMAND: + { + switch (LOWORD(wParam)) { + case IDC_LOOKUPLINK: + CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_FORGOT_PASSWORD); + return TRUE; + + case IDC_NEWUINLINK: + CallService(MS_UTILS_OPENURL, 1, (LPARAM)URL_REGISTER); + return TRUE; + + case IDC_RESETSERVER: + SetDlgItemInt(hwndDlg, IDC_ICQPORT, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT, FALSE); + + case IDC_SSL: + SetDlgItemTextA(hwndDlg, IDC_ICQSERVER, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); + SetDlgItemInt(hwndDlg, IDC_ICQPORT, IsDlgButtonChecked(hwndDlg, IDC_SSL) ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT, FALSE); + OptDlgChanged(hwndDlg); + return TRUE; + } + + if (ppro->icqOnline() && LOWORD(wParam) != IDC_NOERRMULTI) + { + char szClass[80]; + GetClassNameA((HWND)lParam, szClass, sizeof(szClass)); + + if (stricmpnull(szClass, "EDIT") || HIWORD(wParam) == EN_CHANGE) + ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_SHOW); + } + + if ((LOWORD(wParam)==IDC_ICQNUM || LOWORD(wParam)==IDC_PASSWORD || LOWORD(wParam)==IDC_ICQSERVER || LOWORD(wParam)==IDC_ICQPORT) && + (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) + { + return 0; + } + + OptDlgChanged(hwndDlg); + break; + } + + case WM_NOTIFY: + { + switch (((LPNMHDR)lParam)->code) + { + + case PSN_APPLY: + { + char str[128]; + + ppro->setSettingDword(NULL, UNIQUEIDSETTING, GetDlgItemInt(hwndDlg, IDC_ICQNUM, NULL, FALSE)); + GetDlgItemTextA(hwndDlg, IDC_PASSWORD, str, sizeof(ppro->m_szPassword)); + if (strlennull(str)) + { + strcpy(ppro->m_szPassword, str); + ppro->m_bRememberPwd = TRUE; + } + else + ppro->m_bRememberPwd = ppro->getSettingByte(NULL, "RememberPass", 0); + + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(ppro->m_szPassword), (LPARAM)str); + ppro->setSettingString(NULL, "Password", str); + GetDlgItemTextA(hwndDlg,IDC_ICQSERVER, str, sizeof(str)); + ppro->setSettingString(NULL, "OscarServer", str); + ppro->setSettingWord(NULL, "OscarPort", (WORD)GetDlgItemInt(hwndDlg, IDC_ICQPORT, NULL, FALSE)); + StoreDBCheckState(ppro, hwndDlg, IDC_KEEPALIVE, "KeepAlive"); + StoreDBCheckState(ppro, hwndDlg, IDC_SSL, "SecureConnection"); + StoreDBCheckState(ppro, hwndDlg, IDC_MD5LOGIN, "SecureLogin"); + StoreDBCheckState(ppro, hwndDlg, IDC_NOERRMULTI, "IgnoreMultiErrorBox"); + ppro->setSettingByte(NULL, "ShowLogLevel", (BYTE)(4-SendDlgItemMessage(hwndDlg, IDC_LOGLEVEL, TBM_GETPOS, 0, 0))); + + return TRUE; + } + } + } + break; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static const UINT icqPrivacyControls[] = { + IDC_DCALLOW_ANY, IDC_DCALLOW_CLIST, IDC_DCALLOW_AUTH, IDC_ADD_ANY, IDC_ADD_AUTH, + IDC_WEBAWARE, IDC_PUBLISHPRIMARY, IDC_STATIC_DC1, IDC_STATIC_DC2, IDC_STATIC_CLIST +}; + +static INT_PTR CALLBACK DlgProcIcqPrivacyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + { + int nDcType = ppro->getSettingByte(NULL, "DCType", 0); + int nAddAuth = ppro->getSettingByte(NULL, "Auth", 1); + + if (!ppro->icqOnline()) + { + icq_EnableMultipleControls(hwndDlg, icqPrivacyControls, SIZEOF(icqPrivacyControls), FALSE); + ShowDlgItem(hwndDlg, IDC_STATIC_NOTONLINE, SW_SHOW); + } + else + ShowDlgItem(hwndDlg, IDC_STATIC_NOTONLINE, SW_HIDE); + + CheckDlgButton(hwndDlg, IDC_DCALLOW_ANY, (nDcType == 0)); + CheckDlgButton(hwndDlg, IDC_DCALLOW_CLIST, (nDcType == 1)); + CheckDlgButton(hwndDlg, IDC_DCALLOW_AUTH, (nDcType == 2)); + CheckDlgButton(hwndDlg, IDC_ADD_ANY, (nAddAuth == 0)); + CheckDlgButton(hwndDlg, IDC_ADD_AUTH, (nAddAuth == 1)); + LoadDBCheckState(ppro, hwndDlg, IDC_WEBAWARE, "WebAware", 0); + LoadDBCheckState(ppro, hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail", 0); + LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList", 0); + LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible", 0); + if (!ppro->getSettingByte(NULL, "StatusMsgReplyCList", 0)) + EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_DCALLOW_ANY: + case IDC_DCALLOW_CLIST: + case IDC_DCALLOW_AUTH: + case IDC_ADD_ANY: + case IDC_ADD_AUTH: + case IDC_WEBAWARE: + case IDC_PUBLISHPRIMARY: + case IDC_STATUSMSG_VISIBLE: + if ((HWND)lParam != GetFocus()) return 0; + break; + case IDC_STATUSMSG_CLIST: + if (IsDlgButtonChecked(hwndDlg, IDC_STATUSMSG_CLIST)) + { + EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, TRUE); + LoadDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible", 0); + } + else + { + EnableDlgItem(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); + CheckDlgButton(hwndDlg, IDC_STATUSMSG_VISIBLE, FALSE); + } + break; + default: + return 0; + } + OptDlgChanged(hwndDlg); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + StoreDBCheckState(ppro, hwndDlg, IDC_WEBAWARE, "WebAware"); + StoreDBCheckState(ppro, hwndDlg, IDC_PUBLISHPRIMARY, "PublishPrimaryEmail"); + StoreDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_CLIST, "StatusMsgReplyCList"); + StoreDBCheckState(ppro, hwndDlg, IDC_STATUSMSG_VISIBLE, "StatusMsgReplyVisible"); + if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_AUTH)) + ppro->setSettingByte(NULL, "DCType", 2); + else if (IsDlgButtonChecked(hwndDlg, IDC_DCALLOW_CLIST)) + ppro->setSettingByte(NULL, "DCType", 1); + else + ppro->setSettingByte(NULL, "DCType", 0); + StoreDBCheckState(ppro, hwndDlg, IDC_ADD_AUTH, "Auth"); + + if (ppro->icqOnline()) + { + PBYTE buf=NULL; + int buflen=0; + + ppackTLVWord(&buf, &buflen, 0x19A, !ppro->getSettingByte(NULL, "Auth", 1)); + ppackTLVByte(&buf, &buflen, 0x212, ppro->getSettingByte(NULL, "WebAware", 0)); + ppackTLVWord(&buf, &buflen, 0x1F9, ppro->getSettingByte(NULL, "PrivacyLevel", 1)); + + ppro->icq_changeUserDirectoryInfoServ(buf, (WORD)buflen, DIRECTORYREQUEST_UPDATEPRIVACY); + + SAFE_FREE((void**)&buf); + + // Send a status packet to notify the server about the webaware setting + { + WORD wStatus = MirandaStatusToIcq(ppro->m_iStatus); + + if (ppro->m_iStatus == ID_STATUS_INVISIBLE) + { + if (ppro->m_bSsiEnabled) + ppro->updateServVisibilityCode(3); + ppro->icq_setstatus(wStatus, NULL); + } + else + { + ppro->icq_setstatus(wStatus, NULL); + if (ppro->m_bSsiEnabled) + ppro->updateServVisibilityCode(4); + } + } + } + return TRUE; + } + break; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static HWND hCpCombo; + +struct CPTABLE { + WORD cpId; + char *cpName; +}; + +struct CPTABLE cpTable[] = { + { 874, LPGEN("Thai") }, + { 932, LPGEN("Japanese") }, + { 936, LPGEN("Simplified Chinese") }, + { 949, LPGEN("Korean") }, + { 950, LPGEN("Traditional Chinese") }, + { 1250, LPGEN("Central European") }, + { 1251, LPGEN("Cyrillic") }, + { 1252, LPGEN("Latin I") }, + { 1253, LPGEN("Greek") }, + { 1254, LPGEN("Turkish") }, + { 1255, LPGEN("Hebrew") }, + { 1256, LPGEN("Arabic") }, + { 1257, LPGEN("Baltic") }, + { 1258, LPGEN("Vietnamese") }, + { 1361, LPGEN("Korean (Johab)") }, + { -1, NULL} +}; + +static BOOL CALLBACK FillCpCombo(LPSTR str) +{ + int i; + UINT cp; + + cp = atoi(str); + for (i=0; cpTable[i].cpName != NULL && cpTable[i].cpId!=cp; i++); + if (cpTable[i].cpName) + ComboBoxAddStringUtf(hCpCombo, cpTable[i].cpName, cpTable[i].cpId); + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static const UINT icqUnicodeControls[] = {IDC_UTFALL,IDC_UTFSTATIC,IDC_UTFCODEPAGE}; +static const UINT icqDCMsgControls[] = {IDC_DCPASSIVE}; +static const UINT icqXStatusControls[] = {IDC_XSTATUSAUTO}; +static const UINT icqCustomStatusControls[] = {IDC_XSTATUSRESET}; +static const UINT icqAimControls[] = {IDC_AIMENABLE}; + +static INT_PTR CALLBACK DlgProcIcqFeaturesOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + { + BYTE byData = ppro->getSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED); + CheckDlgButton(hwndDlg, IDC_UTFENABLE, byData?TRUE:FALSE); + CheckDlgButton(hwndDlg, IDC_UTFALL, byData==2?TRUE:FALSE); + icq_EnableMultipleControls(hwndDlg, icqUnicodeControls, SIZEOF(icqUnicodeControls), byData?TRUE:FALSE); + LoadDBCheckState(ppro, hwndDlg, IDC_TEMPVISIBLE, "TempVisListEnabled",DEFAULT_TEMPVIS_ENABLED); + LoadDBCheckState(ppro, hwndDlg, IDC_SLOWSEND, "SlowSend", DEFAULT_SLOWSEND); + LoadDBCheckState(ppro, hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS); + byData = ppro->getSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED); + CheckDlgButton(hwndDlg, IDC_DCENABLE, byData?TRUE:FALSE); + CheckDlgButton(hwndDlg, IDC_DCPASSIVE, byData==1?TRUE:FALSE); + icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, SIZEOF(icqDCMsgControls), byData?TRUE:FALSE); + BYTE byXStatusEnabled = ppro->getSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED); + CheckDlgButton(hwndDlg, IDC_XSTATUSENABLE, byXStatusEnabled); + BYTE byMoodsEnabled = ppro->getSettingByte(NULL, "MoodsEnabled", DEFAULT_MOODS_ENABLED); + CheckDlgButton(hwndDlg, IDC_MOODSENABLE, byMoodsEnabled); + icq_EnableMultipleControls(hwndDlg, icqXStatusControls, SIZEOF(icqXStatusControls), byXStatusEnabled); + icq_EnableMultipleControls(hwndDlg, icqCustomStatusControls, SIZEOF(icqCustomStatusControls), byXStatusEnabled || byMoodsEnabled); + LoadDBCheckState(ppro, hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto", DEFAULT_XSTATUS_AUTO); + LoadDBCheckState(ppro, hwndDlg, IDC_XSTATUSRESET, "XStatusReset", DEFAULT_XSTATUS_RESET); + LoadDBCheckState(ppro, hwndDlg, IDC_KILLSPAMBOTS, "KillSpambots", DEFAULT_KILLSPAM_ENABLED); + LoadDBCheckState(ppro, hwndDlg, IDC_AIMENABLE, "AimEnabled", DEFAULT_AIM_ENABLED); + icq_EnableMultipleControls(hwndDlg, icqAimControls, SIZEOF(icqAimControls), ppro->icqOnline()?FALSE:TRUE); + + hCpCombo = GetDlgItem(hwndDlg, IDC_UTFCODEPAGE); + int sCodePage = ppro->getSettingWord(NULL, "AnsiCodePage", CP_ACP); + ComboBoxAddStringUtf(GetDlgItem(hwndDlg, IDC_UTFCODEPAGE), LPGEN("System default codepage"), 0); + EnumSystemCodePagesA(FillCpCombo, CP_INSTALLED); + if(sCodePage == 0) + SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_SETCURSEL, (WPARAM)0, 0); + else + { + for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETCOUNT, 0, 0); i++) + { + if (SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETITEMDATA, (WPARAM)i, 0) == sCodePage) + { + SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_SETCURSEL, (WPARAM)i, 0); + break; + } + } + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_UTFENABLE: + icq_EnableMultipleControls(hwndDlg, icqUnicodeControls, SIZEOF(icqUnicodeControls), IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE)); + OptDlgChanged(hwndDlg); + break; + case IDC_UTFCODEPAGE: + if(HIWORD(wParam)==CBN_SELCHANGE) + OptDlgChanged(hwndDlg); + break; + case IDC_DCENABLE: + icq_EnableMultipleControls(hwndDlg, icqDCMsgControls, SIZEOF(icqDCMsgControls), IsDlgButtonChecked(hwndDlg, IDC_DCENABLE)); + OptDlgChanged(hwndDlg); + break; + case IDC_XSTATUSENABLE: + icq_EnableMultipleControls(hwndDlg, icqXStatusControls, SIZEOF(icqXStatusControls), IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE)); + case IDC_MOODSENABLE: + icq_EnableMultipleControls(hwndDlg, icqCustomStatusControls, SIZEOF(icqCustomStatusControls), IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE) || IsDlgButtonChecked(hwndDlg, IDC_MOODSENABLE)); + default: + OptDlgChanged(hwndDlg); + break; + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + if (IsDlgButtonChecked(hwndDlg, IDC_UTFENABLE)) + ppro->m_bUtfEnabled = IsDlgButtonChecked(hwndDlg, IDC_UTFALL)?2:1; + else + ppro->m_bUtfEnabled = 0; + { + int i = SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETCURSEL, 0, 0); + ppro->m_wAnsiCodepage = (WORD)SendDlgItemMessage(hwndDlg, IDC_UTFCODEPAGE, CB_GETITEMDATA, (WPARAM)i, 0); + ppro->setSettingWord(NULL, "AnsiCodePage", ppro->m_wAnsiCodepage); + } + ppro->setSettingByte(NULL, "UtfEnabled", ppro->m_bUtfEnabled); + ppro->m_bTempVisListEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_TEMPVISIBLE); + ppro->setSettingByte(NULL, "TempVisListEnabled", ppro->m_bTempVisListEnabled); + StoreDBCheckState(ppro, hwndDlg, IDC_SLOWSEND, "SlowSend"); + StoreDBCheckState(ppro, hwndDlg, IDC_ONLYSERVERACKS, "OnlyServerAcks"); + if (IsDlgButtonChecked(hwndDlg, IDC_DCENABLE)) + ppro->m_bDCMsgEnabled = IsDlgButtonChecked(hwndDlg, IDC_DCPASSIVE)?1:2; + else + ppro->m_bDCMsgEnabled = 0; + ppro->setSettingByte(NULL, "DirectMessaging", ppro->m_bDCMsgEnabled); + ppro->m_bXStatusEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_XSTATUSENABLE); + ppro->setSettingByte(NULL, "XStatusEnabled", ppro->m_bXStatusEnabled); + ppro->m_bMoodsEnabled = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_MOODSENABLE); + ppro->setSettingByte(NULL, "MoodsEnabled", ppro->m_bMoodsEnabled); + StoreDBCheckState(ppro, hwndDlg, IDC_XSTATUSAUTO, "XStatusAuto"); + StoreDBCheckState(ppro, hwndDlg, IDC_XSTATUSRESET, "XStatusReset"); + StoreDBCheckState(ppro, hwndDlg, IDC_KILLSPAMBOTS , "KillSpambots"); + StoreDBCheckState(ppro, hwndDlg, IDC_AIMENABLE, "AimEnabled"); + return TRUE; + } + break; + } + return FALSE; +} + +static const UINT icqContactsControls[] = {IDC_ADDSERVER,IDC_LOADFROMSERVER,IDC_SAVETOSERVER,IDC_UPLOADNOW}; +static const UINT icqAvatarControls[] = {IDC_AUTOLOADAVATARS,IDC_STRICTAVATARCHECK}; + +static INT_PTR CALLBACK DlgProcIcqContactsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + LoadDBCheckState(ppro, hwndDlg, IDC_ENABLE, "UseServerCList", DEFAULT_SS_ENABLED); + LoadDBCheckState(ppro, hwndDlg, IDC_ADDSERVER, "ServerAddRemove", DEFAULT_SS_ADDSERVER); + LoadDBCheckState(ppro, hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails", DEFAULT_SS_LOAD); + LoadDBCheckState(ppro, hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails", DEFAULT_SS_STORE); + LoadDBCheckState(ppro, hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED); + LoadDBCheckState(ppro, hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad", DEFAULT_LOAD_AVATARS); + LoadDBCheckState(ppro, hwndDlg, IDC_STRICTAVATARCHECK, "StrictAvatarCheck", DEFAULT_AVATARS_CHECK); + + icq_EnableMultipleControls(hwndDlg, icqContactsControls, SIZEOF(icqContactsControls), + ppro->getSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED)?TRUE:FALSE); + icq_EnableMultipleControls(hwndDlg, icqAvatarControls, SIZEOF(icqAvatarControls), + ppro->getSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED)?TRUE:FALSE); + + if (ppro->icqOnline()) + { + ShowDlgItem(hwndDlg, IDC_OFFLINETOENABLE, SW_SHOW); + EnableDlgItem(hwndDlg, IDC_ENABLE, FALSE); + EnableDlgItem(hwndDlg, IDC_ENABLEAVATARS, FALSE); + } + else + EnableDlgItem(hwndDlg, IDC_UPLOADNOW, FALSE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_UPLOADNOW: + ppro->ShowUploadContactsDialog(); + return TRUE; + case IDC_ENABLE: + icq_EnableMultipleControls(hwndDlg, icqContactsControls, SIZEOF(icqContactsControls), IsDlgButtonChecked(hwndDlg, IDC_ENABLE)); + if (ppro->icqOnline()) + ShowDlgItem(hwndDlg, IDC_RECONNECTREQD, SW_SHOW); + else + EnableDlgItem(hwndDlg, IDC_UPLOADNOW, FALSE); + break; + case IDC_ENABLEAVATARS: + icq_EnableMultipleControls(hwndDlg, icqAvatarControls, SIZEOF(icqAvatarControls), IsDlgButtonChecked(hwndDlg, IDC_ENABLEAVATARS)); + break; + } + OptDlgChanged(hwndDlg); + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == PSN_APPLY ) + { + StoreDBCheckState(ppro, hwndDlg, IDC_ENABLE, "UseServerCList"); + StoreDBCheckState(ppro, hwndDlg, IDC_ADDSERVER, "ServerAddRemove"); + StoreDBCheckState(ppro, hwndDlg, IDC_LOADFROMSERVER, "LoadServerDetails"); + StoreDBCheckState(ppro, hwndDlg, IDC_SAVETOSERVER, "StoreServerDetails"); + StoreDBCheckState(ppro, hwndDlg, IDC_ENABLEAVATARS, "AvatarsEnabled"); + StoreDBCheckState(ppro, hwndDlg, IDC_AUTOLOADAVATARS, "AvatarsAutoLoad"); + StoreDBCheckState(ppro, hwndDlg, IDC_STRICTAVATARCHECK, "StrictAvatarCheck"); + return TRUE; + } + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +int CIcqProto::OnOptionsInit(WPARAM wParam, LPARAM lParam) +{ + if (IsWinVerXPPlus()) { + HMODULE hUxTheme = GetModuleHandleA("uxtheme.dll"); + if (hUxTheme) + pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); + } + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.position = -800000000; + odp.hInstance = hInst; + odp.ptszGroup = LPGENT("Network"); + odp.dwInitParam = LPARAM(this); + odp.ptszTitle = m_tszUserName; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; + + odp.ptszTab = LPGENT("Account"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQ); + odp.pfnDlgProc = DlgProcIcqOpts; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Contacts"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQCONTACTS); + odp.pfnDlgProc = DlgProcIcqContactsOpts; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Features"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQFEATURES); + odp.pfnDlgProc = DlgProcIcqFeaturesOpts; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Privacy"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQPRIVACY); + odp.pfnDlgProc = DlgProcIcqPrivacyOpts; + Options_AddPage(wParam, &odp); + + if (bPopUpService) { + odp.position = 100000000; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUPS); + odp.groupPosition = 900000000; + odp.pfnDlgProc = DlgProcIcqPopupOpts; + odp.ptszGroup = LPGENT("Popups"); + odp.ptszTab = NULL; + Options_AddPage(wParam, &odp); + } + return 0; +} diff --git a/protocols/IcqOscarJ/src/icq_packet.cpp b/protocols/IcqOscarJ/src/icq_packet.cpp new file mode 100644 index 0000000000..79241cf297 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_packet.cpp @@ -0,0 +1,898 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +WORD generate_flap_sequence() +{ + DWORD n = rand(), s = 0; + + for (DWORD i = n; i >>= 3; s += i); + + return (((0 - s) ^ (BYTE)n) & 7 ^ n) + 2; +} + +void __fastcall init_generic_packet(icq_packet *pPacket, WORD wHeaderLen) +{ + pPacket->wPlace = 0; + pPacket->wLen += wHeaderLen; + pPacket->pData = (BYTE*)SAFE_MALLOC(pPacket->wLen); +} + +void write_httphdr(icq_packet *pPacket, WORD wType, DWORD dwSeq) +{ + init_generic_packet(pPacket, 14); + + packWord(pPacket, (WORD)(pPacket->wLen - 2)); + packWord(pPacket, HTTP_PROXY_VERSION); + packWord(pPacket, wType); + packDWord(pPacket, 0); // Flags? + packDWord(pPacket, dwSeq); // Connection sequence ? +} + +void __fastcall write_flap(icq_packet *pPacket, BYTE byFlapChannel) +{ + init_generic_packet(pPacket, 6); + + pPacket->nChannel = byFlapChannel; + + packByte(pPacket, FLAP_MARKER); + packByte(pPacket, byFlapChannel); + packWord(pPacket, 0); // This is the sequence ID, it is filled in during the actual sending + packWord(pPacket, (WORD)(pPacket->wLen - 6)); // This counter should not include the flap header (thus the -6) +} + +void __fastcall serverPacketInit(icq_packet *pPacket, WORD wSize) +{ + pPacket->wLen = wSize; + write_flap(pPacket, ICQ_DATA_CHAN); +} + +void __fastcall directPacketInit(icq_packet *pPacket, DWORD dwSize) +{ + pPacket->wPlace = 0; + pPacket->wLen = (WORD)dwSize; + pPacket->pData = (BYTE *)SAFE_MALLOC(dwSize + 2); + + packLEWord(pPacket, pPacket->wLen); +} + +void __fastcall serverCookieInit(icq_packet *pPacket, BYTE *pCookie, WORD wCookieSize) +{ + pPacket->wLen = (WORD)(wCookieSize + 8 + sizeof(CLIENT_ID_STRING) + 66); + + write_flap(pPacket, ICQ_LOGIN_CHAN); + packDWord(pPacket, 0x00000001); + packTLV(pPacket, 0x06, wCookieSize, pCookie); + + // Pack client identification details. + packTLV(pPacket, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, (LPBYTE)CLIENT_ID_STRING); + packTLVWord(pPacket, 0x0017, CLIENT_VERSION_MAJOR); + packTLVWord(pPacket, 0x0018, CLIENT_VERSION_MINOR); + packTLVWord(pPacket, 0x0019, CLIENT_VERSION_LESSER); + packTLVWord(pPacket, 0x001a, CLIENT_VERSION_BUILD); + packTLVWord(pPacket, 0x0016, CLIENT_ID_CODE); + packTLVDWord(pPacket, 0x0014, CLIENT_DISTRIBUTION); + packTLV(pPacket, 0x000f, 0x0002, (LPBYTE)CLIENT_LANGUAGE); + packTLV(pPacket, 0x000e, 0x0002, (LPBYTE)CLIENT_COUNTRY); + packDWord(pPacket, 0x00940001); // reconnect flag + packByte(pPacket, 0); + packTLVDWord(pPacket, 0x8003, 0x00100000); // Unknown +} + +void __fastcall packByte(icq_packet *pPacket, BYTE byValue) +{ + pPacket->pData[pPacket->wPlace++] = byValue; +} + +void __fastcall packWord(icq_packet *pPacket, WORD wValue) +{ + pPacket->pData[pPacket->wPlace++] = ((wValue & 0xff00) >> 8); + pPacket->pData[pPacket->wPlace++] = (wValue & 0x00ff); +} + +void __fastcall packDWord(icq_packet *pPacket, DWORD dwValue) +{ + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0xff000000) >> 24); + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x00ff0000) >> 16); + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x0000ff00) >> 8); + pPacket->pData[pPacket->wPlace++] = (BYTE) (dwValue & 0x000000ff); +} + +void __fastcall packQWord(icq_packet *pPacket, DWORD64 qwValue) +{ + packDWord(pPacket, (DWORD)(qwValue >> 32)); + packDWord(pPacket, (DWORD)(qwValue & 0xffffffff)); +} + +void packTLV(icq_packet *pPacket, WORD wType, WORD wLength, const BYTE *pbyValue) +{ + packWord(pPacket, wType); + packWord(pPacket, wLength); + packBuffer(pPacket, pbyValue, wLength); +} + +void packTLVWord(icq_packet *pPacket, WORD wType, WORD wValue) +{ + packWord(pPacket, wType); + packWord(pPacket, 0x02); + packWord(pPacket, wValue); +} + +void packTLVDWord(icq_packet *pPacket, WORD wType, DWORD dwValue) +{ + packWord(pPacket, wType); + packWord(pPacket, 0x04); + packDWord(pPacket, dwValue); +} + + +void packTLVUID(icq_packet *pPacket, WORD wType, DWORD dwUin, const char *szUid) +{ + if (dwUin) + { + char szUin[UINMAXLEN]; + + _ltoa(dwUin, szUin, 10); + + packTLV(pPacket, wType, getUINLen(dwUin), (BYTE*)szUin); + } + else if (szUid) + packTLV(pPacket, wType, strlennull(szUid), (BYTE*)szUid); +} + + +// Pack a preformatted buffer. +// This can be used to pack strings or any type of raw data. +void packBuffer(icq_packet *pPacket, const BYTE* pbyBuffer, WORD wLength) +{ + while (wLength) + { + pPacket->pData[pPacket->wPlace++] = *pbyBuffer++; + wLength--; + } +} + +// Pack a buffer and prepend it with the size as a LE WORD. +// Commented out since its not actually used anywhere right now. +//void packLEWordSizedBuffer(icq_packet* pPacket, const BYTE* pbyBuffer, WORD wLength) +//{ +// +// packLEWord(pPacket, wLength); +// packBuffer(pPacket, pbyBuffer, wLength); +// +//} + +int __fastcall getUINLen(DWORD dwUin) +{ + BYTE dwUinLen = 0; + + while(dwUin) { + dwUin /= 10; + dwUinLen += 1; + } + return dwUinLen; +} + +int __fastcall getUIDLen(DWORD dwUin, const char *szUid) +{ + if (dwUin) + return getUINLen(dwUin); + else + return strlennull(szUid); +} + +void __fastcall packUIN(icq_packet *pPacket, DWORD dwUin) +{ + char pszUin[UINMAXLEN]; + BYTE nUinLen = getUINLen(dwUin); + + _ltoa(dwUin, pszUin, 10); + + packByte(pPacket, nUinLen); // Length of user id + packBuffer(pPacket, (LPBYTE)pszUin, nUinLen); // Receiving user's id +} + +void __fastcall packUID(icq_packet *pPacket, DWORD dwUin, const char *szUid) +{ + if (dwUin) + packUIN(pPacket, dwUin); + else + { + BYTE nLen = strlennull(szUid); + packByte(pPacket, nLen); + packBuffer(pPacket, (LPBYTE)szUid, nLen); + } +} + + +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype) +{ + packFNACHeader(pPacket, wFamily, wSubtype, 0, wSubtype << 0x10); +} + + +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence) +{ + WORD wSequence = (WORD)dwSequence & 0x7FFF; // this is necessary, if that bit is there we get disconnected + + packWord(pPacket, wFamily); // Family type + packWord(pPacket, wSubtype); // Family subtype + packWord(pPacket, wFlags); // SNAC flags + packWord(pPacket, wSequence); // SNAC request id (sequence) + packWord(pPacket, (WORD)(dwSequence >> 0x10)); // SNAC request id (command) +} + + +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence, WORD wVersion) +{ + packFNACHeader(pPacket, wFamily, wSubtype, wFlags | 0x8000, dwSequence); + packWord(pPacket, 0x06); + packTLVWord(pPacket, 0x01, wVersion); +} + + +void __fastcall packLEWord(icq_packet *pPacket, WORD wValue) +{ + pPacket->pData[pPacket->wPlace++] = (wValue & 0x00ff); + pPacket->pData[pPacket->wPlace++] = ((wValue & 0xff00) >> 8); +} + +void __fastcall packLEDWord(icq_packet *pPacket, DWORD dwValue) +{ + pPacket->pData[pPacket->wPlace++] = (BYTE) (dwValue & 0x000000ff); + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x0000ff00) >> 8); + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0x00ff0000) >> 16); + pPacket->pData[pPacket->wPlace++] = (BYTE)((dwValue & 0xff000000) >> 24); +} + + +/* helper function to place numerics to buffer */ +static void packWord(PBYTE buf, WORD wValue) +{ + *(buf) = ((wValue & 0xff00) >> 8); + *(buf + 1) = (wValue & 0x00ff); +} + + +static void packDWord(PBYTE buf, DWORD dwValue) +{ + *(buf) = (BYTE)((dwValue & 0xff000000) >> 24); + *(buf + 1) = (BYTE)((dwValue & 0x00ff0000) >> 16); + *(buf + 2) = (BYTE)((dwValue & 0x0000ff00) >> 8); + *(buf + 3) = (BYTE) (dwValue & 0x000000ff); +} + + +static void packQWord(PBYTE buf, DWORD64 qwValue) +{ + packDWord(buf, (DWORD)(qwValue >> 32)); + packDWord(buf + 4, (DWORD)(qwValue & 0xffffffff)); +} + + +void ppackByte(PBYTE *buf, int *buflen, BYTE byValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 1 + *buflen); + *(*buf + *buflen) = byValue; + ++*buflen; +} + + +void ppackWord(PBYTE *buf, int *buflen, WORD wValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 2 + *buflen); + packWord(*buf + *buflen, wValue); + *buflen += 2; +} + + +void ppackLEWord(PBYTE *buf, int *buflen, WORD wValue) +{ + *buf=(PBYTE)SAFE_REALLOC(*buf, 2 + *buflen); + *(PWORD)(*buf + *buflen) = wValue; + *buflen+=2; +} + + +void ppackLEDWord(PBYTE *buf, int *buflen, DWORD dwValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 4 + *buflen); + *(PDWORD)(*buf + *buflen) = dwValue; + *buflen += 4; +} + + +void ppackLELNTS(PBYTE *buf, int *buflen, const char *str) +{ + WORD len = strlennull(str); + ppackLEWord(buf, buflen, len); + *buf = (PBYTE)SAFE_REALLOC(*buf, *buflen + len); + memcpy(*buf + *buflen, str, len); + *buflen += len; +} + + +void ppackBuffer(PBYTE *buf, int *buflen, WORD wLength, const BYTE *pbyValue) +{ + if (wLength) + { + *buf = (PBYTE)SAFE_REALLOC(*buf, wLength + *buflen); + memcpy(*buf + *buflen, pbyValue, wLength); + *buflen += wLength; + } +} + + +void ppackTLV(PBYTE *buf, int *buflen, WORD wType, WORD wLength, const BYTE *pbyValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 4 + wLength + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, wLength); + if (wLength) + memcpy(*buf + *buflen + 4, pbyValue, wLength); + *buflen += 4 + wLength; +} + + +void ppackTLVByte(PBYTE *buf, int *buflen, WORD wType, BYTE byValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 5 + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 1); + *(*buf + *buflen + 4) = byValue; + *buflen += 5; +} + + +void ppackTLVWord(PBYTE *buf, int *buflen, WORD wType, WORD wValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 2); + packWord(*buf + *buflen + 4, wValue); + *buflen += 6; +} + + +void ppackTLVDWord(PBYTE *buf, int *buflen, WORD wType, DWORD dwValue) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 4); + packDWord(*buf + *buflen + 4, dwValue); + *buflen += 8; +} + + +void ppackTLVDouble(PBYTE *buf, int *buflen, WORD wType, double dValue) +{ + DWORD64 qwValue; + + memcpy(&qwValue, &dValue, 8); + + *buf = (PBYTE)SAFE_REALLOC(*buf, 12 + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 8); + packQWord(*buf + *buflen + 4, qwValue); + *buflen += 12; +} + + +void ppackTLVUID(PBYTE *buf, int *buflen, WORD wType, DWORD dwUin, const char *szUid) +{ + if (dwUin) + { + char szUin[UINMAXLEN]; + + _ltoa(dwUin, szUin, 10); + + ppackTLV(buf, buflen, wType, getUINLen(dwUin), (BYTE*)szUin); + } + else if (szUid) + ppackTLV(buf, buflen, wType, strlennull(szUid), (BYTE*)szUid); +} + + +// *** TLV based (!!! WORDs and DWORDs are LE !!!) +void ppackLETLVByte(PBYTE *buf, int *buflen, BYTE byValue, WORD wType, BYTE always) +{ + if (!always && !byValue) return; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 5 + *buflen); + *(PWORD)(*buf + *buflen) = wType; + *(PWORD)(*buf + *buflen + 2) = 1; + *(*buf + *buflen + 4) = byValue; + *buflen += 5; +} + + +void ppackLETLVWord(PBYTE *buf, int *buflen, WORD wValue, WORD wType, BYTE always) +{ + if (!always && !wValue) return; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); + *(PWORD)(*buf + *buflen) = wType; + *(PWORD)(*buf + *buflen + 2) = 2; + *(PWORD)(*buf + *buflen + 4) = wValue; + *buflen += 6; +} + + +void ppackLETLVDWord(PBYTE *buf, int *buflen, DWORD dwValue, WORD wType, BYTE always) +{ + if (!always && !dwValue) return; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen); + *(PWORD)(*buf + *buflen) = wType; + *(PWORD)(*buf + *buflen + 2) = 4; + *(PDWORD)(*buf + *buflen + 4) = dwValue; + *buflen += 8; +} + + +void packLETLVLNTS(PBYTE *buf, int *bufpos, const char *str, WORD wType) +{ + int len = strlennull(str) + 1; + + *(PWORD)(*buf + *bufpos) = wType; + *(PWORD)(*buf + *bufpos + 2) = len + 2; + *(PWORD)(*buf + *bufpos + 4) = len; + memcpy(*buf + *bufpos + 6, str, len); + *bufpos += len + 6; +} + + +void ppackLETLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always) +{ + int len = strlennull(str) + 1; + + if (!always && len < 2) return; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen + len); + packLETLVLNTS(buf, buflen, str, wType); +} + + +void ppackLETLVWordLNTS(PBYTE *buf, int *buflen, WORD w, const char *str, WORD wType, BYTE always) +{ + int len = strlennull(str) + 1; + + if (!always && len < 2 && !w) return; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + len); + *(PWORD)(*buf + *buflen) = wType; + *(PWORD)(*buf + *buflen + 2) = len + 4; + *(PWORD)(*buf + *buflen + 4) = w; + *(PWORD)(*buf + *buflen + 6) = len; + memcpy(*buf + *buflen + 8, str, len); + *buflen += len + 8; +} + + +void ppackLETLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType) +{ + int len = strlennull(str) + 1; + + *buf = (PBYTE)SAFE_REALLOC(*buf, 7 + *buflen + len); + *(PWORD)(*buf + *buflen) = wType; + *(PWORD)(*buf + *buflen + 2) = len + 3; + *(PWORD)(*buf + *buflen + 4) = len; + memcpy(*buf + *buflen + 6, str, len); + *(*buf + *buflen + 6 + len) = b; + *buflen += len + 7; +} + + +void CIcqProto::ppackLETLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) +{ + char szTmp[1024]; + char *str = ""; + + if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) + str = szTmp; + + ppackLETLVLNTS(buf, buflen, str, wType, 1); +} + +void CIcqProto::ppackLETLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType) +{ + char szTmp[1024]; + char *str = ""; + + if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) + str = szTmp; + + ppackLETLVWordLNTS(buf, buflen, w, str, wType, 1); +} + +void CIcqProto::ppackLETLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType) +{ + char szTmp[1024]; + char *str = ""; + + if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) + str = szTmp; + + ppackLETLVLNTSByte(buf, buflen, str, b, wType); +} + + +void CIcqProto::ppackTLVStringFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) +{ + char szTmp[1024]; + char *str = ""; + + if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) + str = szTmp; + + ppackTLV(buf, buflen, wType, strlennull(str), (PBYTE)str); +} + + +void CIcqProto::ppackTLVStringUtfFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType) +{ + char *str = getSettingStringUtf(NULL, szSetting, NULL); + + ppackTLV(buf, buflen, wType, strlennull(str), (PBYTE)str); + + SAFE_FREE((void**)&str); +} + + +void CIcqProto::ppackTLVDateFromDB(PBYTE *buf, int *buflen, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, WORD wType) +{ + SYSTEMTIME sTime = {0}; + double time = 0; + + sTime.wYear = getSettingWord(NULL, szSettingYear, 0); + sTime.wMonth = getSettingByte(NULL, szSettingMonth, 0); + sTime.wDay = getSettingByte(NULL, szSettingDay, 0); + if (sTime.wYear || sTime.wMonth || sTime.wDay) + { + SystemTimeToVariantTime(&sTime, &time); + time -= 2; + } + + ppackTLVDouble(buf, buflen, wType, time); +} + + +int CIcqProto::ppackTLVWordStringItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID) +{ + char szTmp[1024]; + char *str = NULL; + + if (!getSettingStringStatic(NULL, szSetting, szTmp, sizeof(szTmp))) + str = szTmp; + + if (str) + { + WORD wLen = strlennull(str); + + ppackWord(buf, buflen, wLen + 0x0A); + ppackTLVWord(buf, buflen, wTypeID, wID); + ppackTLV(buf, buflen, wTypeData, wLen, (PBYTE)str); + + return 1; // Success + } + + return 0; // No data +} + + +int CIcqProto::ppackTLVWordStringUtfItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID) +{ + char *str = getSettingStringUtf(NULL, szSetting, NULL); + + if (str) + { + WORD wLen = strlennull(str); + + ppackWord(buf, buflen, wLen + 0x0A); + ppackTLVWord(buf, buflen, wTypeID, wID); + ppackTLV(buf, buflen, wTypeData, wLen, (PBYTE)str); + + SAFE_FREE(&str); + + return 1; // Success + } + + return 0; // No data +} + + +void ppackTLVBlockItems(PBYTE *buf, int *buflen, WORD wType, int *nItems, PBYTE *pBlock, WORD *wLength, BOOL bSingleItem) +{ + *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + *wLength); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, (bSingleItem ? 4 : 2) + *wLength); + packWord(*buf + *buflen + 4, *nItems); + if (bSingleItem) + packWord(*buf + *buflen + 6, *wLength); + if (*wLength) + memcpy(*buf + *buflen + (bSingleItem ? 8 : 6), *pBlock, *wLength); + *buflen += (bSingleItem ? 8 : 6) + *wLength; + + SAFE_FREE((void**)pBlock); + *wLength = 0; + *nItems = 0; +} + + +void ppackTLVBlockItem(PBYTE *buf, int *buflen, WORD wType, PBYTE *pItem, WORD *wLength) +{ + if (wLength) + { + *buf = (PBYTE)SAFE_REALLOC(*buf, 8 + *buflen + *wLength); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 4 + *wLength); + packWord(*buf + *buflen + 4, 1); + packWord(*buf + *buflen + 6, *wLength); + memcpy(*buf + *buflen + 8, *pItem, *wLength); + *buflen += 8 + *wLength; + } + else + { + *buf = (PBYTE)SAFE_REALLOC(*buf, 6 + *buflen); + packWord(*buf + *buflen, wType); + packWord(*buf + *buflen + 2, 0x02); + packWord(*buf + *buflen + 4, 0); + *buflen += 6; + } + + SAFE_FREE((void**)pItem); + *wLength = 0; +} + + +void __fastcall unpackByte(BYTE **pSource, BYTE *byDestination) +{ + if (byDestination) + *byDestination = *(*pSource)++; + else + *pSource += 1; +} + +void __fastcall unpackWord(BYTE **pSource, WORD *wDestination) +{ + BYTE *tmp = *pSource; + + if (wDestination) + { + *wDestination = *tmp++ << 8; + *wDestination |= *tmp++; + + *pSource = tmp; + } + else + *pSource += 2; +} + +void __fastcall unpackDWord(BYTE **pSource, DWORD *dwDestination) +{ + BYTE *tmp = *pSource; + + if (dwDestination) + { + *dwDestination = *tmp++ << 24; + *dwDestination |= *tmp++ << 16; + *dwDestination |= *tmp++ << 8; + *dwDestination |= *tmp++; + + *pSource = tmp; + } + else + *pSource += 4; +} + +void __fastcall unpackQWord(BYTE **pSource, DWORD64 *qwDestination) +{ + DWORD dwData; + + if (qwDestination) + { + unpackDWord(pSource, &dwData); + *qwDestination = ((DWORD64)dwData) << 32; + unpackDWord(pSource, &dwData); + *qwDestination |= dwData; + } + else + *pSource += 8; +} + +void __fastcall unpackLEWord(BYTE **buf, WORD *w) +{ + BYTE *tmp = *buf; + + if (w) + { + *w = (*tmp++); + *w |= ((*tmp++) << 8); + } + else + tmp += 2; + + *buf = tmp; +} + +void __fastcall unpackLEDWord(BYTE **buf, DWORD *dw) +{ + BYTE *tmp = *buf; + + if (dw) + { + *dw = (*tmp++); + *dw |= ((*tmp++) << 8); + *dw |= ((*tmp++) << 16); + *dw |= ((*tmp++) << 24); + } + else + tmp += 4; + + *buf = tmp; +} + +void unpackString(BYTE **buf, char *string, WORD len) +{ + BYTE *tmp = *buf; + + if (string) + { + while (len) /* Can have 0x00 so go by len */ + { + *string++ = *tmp++; + len--; + } + } + else + tmp += len; + + *buf = tmp; +} + +void unpackWideString(BYTE **buf, WCHAR *string, WORD len) +{ + BYTE *tmp = *buf; + + while (len > 1) + { + *string = (*tmp++ << 8); + *string |= *tmp++; + + string++; + len -= 2; + } + + // We have a stray byte at the end, this means that the buffer had an odd length + // which indicates an error. + _ASSERTE(len == 0); + if (len != 0) + { + // We dont copy the last byte but we still need to increase the buffer pointer + // (we assume that 'len' was correct) since the calling function expects + // that it is increased 'len' bytes. + *tmp += len; + } + + *buf = tmp; +} + +void unpackTypedTLV(BYTE *buf, int buflen, WORD type, WORD *ttype, WORD *tlen, BYTE **ttlv) +{ + WORD wType, wLen; + +NextTLV: + // Unpack type and length + unpackWord(&buf, &wType); + unpackWord(&buf, &wLen); + buflen -= 4; + + if (wType != type && buflen >= wLen + 4) + { // Not the right TLV, try next + buflen -= wLen; + buf += wLen; + goto NextTLV; + } + // Check buffer size + if (wLen > buflen) wLen = buflen; + + // Make sure we have a good pointer + if (ttlv) + { + if (wLen) + { // Unpack and save value + *ttlv = (BYTE*)SAFE_MALLOC(wLen + 1); // Add 1 for \0 + unpackString(&buf, (char*)*ttlv, wLen); + *(*ttlv + wLen) = '\0'; + } + else + *ttlv = NULL; + } + + // Save type and length + if (ttype) + *ttype = wType; + if (tlen) + *tlen = wLen; +} + + +BOOL CIcqProto::unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID) +{ + BYTE nUIDLen; + + // sanity check + if (!ppBuf || !pwLen || *pwLen < 1) + return FALSE; + + // Sender UIN + unpackByte(ppBuf, &nUIDLen); + *pwLen -= 1; + + if ((nUIDLen > *pwLen) || (nUIDLen == 0)) + return FALSE; + + if (nUIDLen <= UINMAXLEN) + { // it can be uin, check + char szUIN[UINMAXLEN+1]; + + unpackString(ppBuf, szUIN, nUIDLen); + szUIN[nUIDLen] = '\0'; + *pwLen -= nUIDLen; + + if (IsStringUIN(szUIN)) + { + *pdwUIN = atoi(szUIN); + return TRUE; + } + else + { // go back + *ppBuf -= nUIDLen; + *pwLen += nUIDLen; + } + } + if (!m_bAimEnabled || !ppszUID || !(*ppszUID)) + { // skip the UID data + *ppBuf += nUIDLen; + *pwLen -= nUIDLen; + + NetLog_Server("Malformed UIN in packet"); + return FALSE; + } + + unpackString(ppBuf, *ppszUID, nUIDLen); + *pwLen -= nUIDLen; + (*ppszUID)[nUIDLen] = '\0'; + + *pdwUIN = 0; // this is how we determine aim contacts internally + + return TRUE; +} diff --git a/protocols/IcqOscarJ/src/icq_packet.h b/protocols/IcqOscarJ/src/icq_packet.h new file mode 100644 index 0000000000..ccaeb91fcc --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_packet.h @@ -0,0 +1,120 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, Bio +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_PACKET_H +#define __ICQ_PACKET_H + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +/*---------* Structures *--------------*/ + +struct icq_packet +{ + WORD wPlace; + BYTE nChannel; + WORD wLen; + BYTE *pData; +}; + +/*---------* Functions *---------------*/ + +WORD generate_flap_sequence(); + +void __fastcall init_generic_packet(icq_packet *pPacket, WORD wHeaderLen); +void write_httphdr(icq_packet *pPacket, WORD wType, DWORD dwSeq); +void __fastcall write_flap(icq_packet *pPacket, BYTE byFlapChannel); +void __fastcall serverPacketInit(icq_packet *pPacket, WORD wSize); +void __fastcall directPacketInit(icq_packet *pPacket, DWORD dwSize); + +void __fastcall serverCookieInit(icq_packet *pPacket, BYTE *pCookie, WORD wCookieSize); + +void __fastcall packByte(icq_packet *pPacket, BYTE byValue); +void __fastcall packWord(icq_packet *pPacket, WORD wValue); +void __fastcall packDWord(icq_packet *pPacket, DWORD dwValue); +void __fastcall packQWord(icq_packet *pPacket, DWORD64 qwValue); +void packTLV(icq_packet *pPacket, WORD wType, WORD wLength, const BYTE *pbyValue); +void packTLVWord(icq_packet *pPacket, WORD wType, WORD wData); +void packTLVDWord(icq_packet *pPacket, WORD wType, DWORD dwData); +void packTLVUID(icq_packet *pPacket, WORD wType, DWORD dwUin, const char *szUid); + +void packBuffer(icq_packet *pPacket, const BYTE *pbyBuffer, WORD wLength); +//void packLEWordSizedBuffer(icq_packet* pPacket, const BYTE* pbyBuffer, WORD wLength); +int __fastcall getUINLen(DWORD dwUin); +int __fastcall getUIDLen(DWORD dwUin, const char *szUid); +void __fastcall packUIN(icq_packet *pPacket, DWORD dwUin); +void __fastcall packUID(icq_packet *pPacket, DWORD dwUin, const char *szUid); + +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype); +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence); +void packFNACHeader(icq_packet *pPacket, WORD wFamily, WORD wSubtype, WORD wFlags, DWORD dwSequence, WORD wVersion); + +void __fastcall packLEWord(icq_packet *pPacket, WORD wValue); +void __fastcall packLEDWord(icq_packet *pPacket, DWORD dwValue); + +void packLETLVLNTS(PBYTE *buf, int *bufpos, const char *str, WORD wType); + +void ppackByte(PBYTE *buf, int *buflen, BYTE byValue); +void ppackWord(PBYTE *buf, int *buflen, WORD wValue); +void ppackLEWord(PBYTE *buf, int *buflen, WORD wValue); +void ppackLEDWord(PBYTE *buf, int *buflen, DWORD dwValue); +void ppackLELNTS(PBYTE *buf, int *buflen, const char *str); +void ppackBuffer(PBYTE *buf, int *buflen, WORD wLength, const BYTE *pbyValue); + +void ppackTLV(PBYTE *buf, int *buflen, WORD wType, WORD wLength, const BYTE *pbyValue); +void ppackTLVByte(PBYTE *buf, int *buflen, WORD wType, BYTE byValue); +void ppackTLVWord(PBYTE *buf, int *buflen, WORD wType, WORD wValue); +void ppackTLVDWord(PBYTE *buf, int *buflen, WORD wType, DWORD dwValue); +void ppackTLVDouble(PBYTE *buf, int *buflen, WORD wType, double dValue); +void ppackTLVUID(PBYTE *buf, int *buflen, WORD wType, DWORD dwUin, const char *szUid); + +void ppackLETLVByte(PBYTE *buf, int *buflen, BYTE byValue, WORD wType, BYTE always); +void ppackLETLVWord(PBYTE *buf, int *buflen, WORD wValue, WORD wType, BYTE always); +void ppackLETLVDWord(PBYTE *buf, int *buflen, DWORD dwValue, WORD wType, BYTE always); +void ppackLETLVLNTS(PBYTE *buf, int *buflen, const char *str, WORD wType, BYTE always); +void ppackLETLVWordLNTS(PBYTE *buf, int *buflen, WORD w, const char *str, WORD wType, BYTE always); +void ppackLETLVLNTSByte(PBYTE *buf, int *buflen, const char *str, BYTE b, WORD wType); + +void ppackTLVBlockItems(PBYTE *buf, int *buflen, WORD wType, int *nItems, PBYTE *pBlock, WORD *wLength, BOOL bSingleItem); +void ppackTLVBlockItem(PBYTE *buf, int *buflen, WORD wType, PBYTE *pItem, WORD *wLength); + +void __fastcall unpackByte(BYTE **pSource, BYTE *byDestination); +void __fastcall unpackWord(BYTE **pSource, WORD *wDestination); +void __fastcall unpackDWord(BYTE **pSource, DWORD *dwDestination); +void __fastcall unpackQWord(BYTE **pSource, DWORD64 *qwDestination); +void unpackString(BYTE **buf, char *string, WORD len); +void unpackWideString(BYTE **buf, WCHAR *string, WORD len); +void unpackTypedTLV(BYTE *buf, int buflen, WORD type, WORD *ttype, WORD *tlen, BYTE **ttlv); +BOOL unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID); + +void __fastcall unpackLEWord(BYTE **buf, WORD *w); +void __fastcall unpackLEDWord(BYTE **buf, DWORD *dw); + +#endif /* __ICQ_PACKET_H */ diff --git a/protocols/IcqOscarJ/src/icq_popups.cpp b/protocols/IcqOscarJ/src/icq_popups.cpp new file mode 100644 index 0000000000..21ca36348d --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_popups.cpp @@ -0,0 +1,323 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// PopUp Plugin stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +BOOL bPopUpService = FALSE; + +void InitPopUps() +{ + if (ServiceExists(MS_POPUP_ADDPOPUPEX)) + { + bPopUpService = TRUE; + } +} + +static const UINT icqPopupsControls[] = { + IDC_POPUPS_LOG_ENABLED, IDC_POPUPS_SPAM_ENABLED, IDC_PREVIEW, IDC_USESYSICONS, IDC_POPUP_LOG0_TIMEOUT, + IDC_POPUP_LOG1_TIMEOUT, IDC_POPUP_LOG2_TIMEOUT, IDC_POPUP_LOG3_TIMEOUT, IDC_POPUP_SPAM_TIMEOUT +}; + +static const UINT icqPopupColorControls[] = { + IDC_POPUP_LOG0_TEXTCOLOR, IDC_POPUP_LOG1_TEXTCOLOR, IDC_POPUP_LOG2_TEXTCOLOR, IDC_POPUP_LOG3_TEXTCOLOR, IDC_POPUP_SPAM_TEXTCOLOR, + IDC_POPUP_LOG0_BACKCOLOR, IDC_POPUP_LOG1_BACKCOLOR, IDC_POPUP_LOG2_BACKCOLOR, IDC_POPUP_LOG3_BACKCOLOR, IDC_POPUP_SPAM_BACKCOLOR +}; + +INT_PTR CALLBACK DlgProcIcqPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static bool bInitDone = true; + BYTE bEnabled; + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + bInitDone = false; + TranslateDialogDefault(hwndDlg); + + ppro = (CIcqProto*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + + CheckDlgButton(hwndDlg, IDC_POPUPS_LOG_ENABLED, ppro->getSettingByte(NULL,"PopupsLogEnabled",DEFAULT_LOG_POPUPS_ENABLED)); + CheckDlgButton(hwndDlg, IDC_POPUPS_SPAM_ENABLED, ppro->getSettingByte(NULL,"PopupsSpamEnabled",DEFAULT_SPAM_POPUPS_ENABLED)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups0TextColor",DEFAULT_LOG0_TEXT_COLORS)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG0_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups0BackColor",DEFAULT_LOG0_BACK_COLORS)); + SetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, ppro->getSettingDword(NULL,"Popups0Timeout",DEFAULT_LOG0_TIMEOUT),FALSE); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups1TextColor",DEFAULT_LOG1_TEXT_COLORS)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG1_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups1BackColor",DEFAULT_LOG1_BACK_COLORS)); + SetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, ppro->getSettingDword(NULL,"Popups1Timeout",DEFAULT_LOG1_TIMEOUT),FALSE); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups2TextColor",DEFAULT_LOG2_TEXT_COLORS)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG2_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups2BackColor",DEFAULT_LOG2_BACK_COLORS)); + SetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, ppro->getSettingDword(NULL,"Popups2Timeout",DEFAULT_LOG2_TIMEOUT),FALSE); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups3TextColor",DEFAULT_LOG3_TEXT_COLORS)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_LOG3_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"Popups3BackColor",DEFAULT_LOG3_BACK_COLORS)); + SetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, ppro->getSettingDword(NULL,"Popups3Timeout",DEFAULT_LOG3_TIMEOUT),FALSE); + SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_TEXTCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"PopupsSpamTextColor",DEFAULT_SPAM_TEXT_COLORS)); + SendDlgItemMessage(hwndDlg, IDC_POPUP_SPAM_BACKCOLOR, CPM_SETCOLOUR, 0, ppro->getSettingDword(NULL,"PopupsSpamBackColor",DEFAULT_SPAM_BACK_COLORS)); + SetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, ppro->getSettingDword(NULL,"PopupsSpamTimeout",DEFAULT_SPAM_TIMEOUT),FALSE); + bEnabled = ppro->getSettingByte(NULL,"PopupsWinColors",DEFAULT_POPUPS_WIN_COLORS); + CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, bEnabled); + bEnabled |= ppro->getSettingByte(NULL,"PopupsDefColors",DEFAULT_POPUPS_DEF_COLORS); + CheckDlgButton(hwndDlg, IDC_USEDEFCOLORS, bEnabled); + icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled); + CheckDlgButton(hwndDlg, IDC_USESYSICONS, ppro->getSettingByte(NULL,"PopupsSysIcons",DEFAULT_POPUPS_SYS_ICONS)); + bEnabled = ppro->getSettingByte(NULL,"PopupsEnabled",DEFAULT_POPUPS_ENABLED); + CheckDlgButton(hwndDlg, IDC_POPUPS_ENABLED, bEnabled); + icq_EnableMultipleControls(hwndDlg, icqPopupsControls, SIZEOF(icqPopupsControls), bEnabled); + if (bEnabled) + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); + } + } + icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & (!IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS) && !IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS))); + bInitDone = true; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_PREVIEW: + { + ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Note"), LOG_NOTE); + ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Warning"), LOG_WARNING); + ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Error"), LOG_ERROR); + ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Fatal"), LOG_FATAL); + ppro->ShowPopUpMsg(NULL, LPGEN("Popup Title"), LPGEN("Sample Spambot"), POPTYPE_SPAM); + } + return FALSE; + + case IDC_POPUPS_ENABLED: + bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); + if (bEnabled) + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); + } + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); + } + icq_EnableMultipleControls(hwndDlg, icqPopupsControls, SIZEOF(icqPopupsControls), bEnabled); + + case IDC_USEWINCOLORS: + bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); + if (bEnabled) + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEWINCOLORS)) + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), !WM_ENABLE); + else + EnableWindow(GetDlgItem(hwndDlg, IDC_USEDEFCOLORS), WM_ENABLE); + } + icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & !IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS)); + + case IDC_USEDEFCOLORS: + bEnabled = IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED); + if (bEnabled) + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEDEFCOLORS)) + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), !WM_ENABLE); + else + EnableWindow(GetDlgItem(hwndDlg, IDC_USEWINCOLORS), WM_ENABLE); + } + icq_EnableMultipleControls(hwndDlg, icqPopupColorControls, SIZEOF(icqPopupColorControls), bEnabled & !IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS)); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + case IDC_POPUP_LOG0_TIMEOUT: + case IDC_POPUP_LOG1_TIMEOUT: + case IDC_POPUP_LOG2_TIMEOUT: + case IDC_POPUP_LOG3_TIMEOUT: + case IDC_POPUP_SPAM_TIMEOUT: + if ((HIWORD(wParam) == EN_CHANGE) && bInitDone) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + default: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + ppro->setSettingByte(NULL,"PopupsEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_ENABLED)); + ppro->setSettingByte(NULL,"PopupsLogEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_LOG_ENABLED)); + ppro->setSettingByte(NULL,"PopupsSpamEnabled",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_POPUPS_SPAM_ENABLED)); + ppro->setSettingDword(NULL,"Popups0TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_TEXTCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups0BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG0_BACKCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups0Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG0_TIMEOUT, NULL, FALSE)); + ppro->setSettingDword(NULL,"Popups1TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_TEXTCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups1BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG1_BACKCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups1Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG1_TIMEOUT, NULL, FALSE)); + ppro->setSettingDword(NULL,"Popups2TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_TEXTCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups2BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG2_BACKCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups2Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG2_TIMEOUT, NULL, FALSE)); + ppro->setSettingDword(NULL,"Popups3TextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_TEXTCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups3BackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_LOG3_BACKCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"Popups3Timeout",GetDlgItemInt(hwndDlg, IDC_POPUP_LOG3_TIMEOUT, NULL, FALSE)); + ppro->setSettingDword(NULL,"PopupsSpamTextColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_TEXTCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"PopupsSpamBackColor",SendDlgItemMessage(hwndDlg,IDC_POPUP_SPAM_BACKCOLOR,CPM_GETCOLOUR,0,0)); + ppro->setSettingDword(NULL,"PopupsSpamTimeout",GetDlgItemInt(hwndDlg, IDC_POPUP_SPAM_TIMEOUT, NULL, FALSE)); + ppro->setSettingByte(NULL,"PopupsWinColors",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USEWINCOLORS)); + ppro->setSettingByte(NULL,"PopupsDefColors",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USEDEFCOLORS)); + ppro->setSettingByte(NULL,"PopupsSysIcons",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_USESYSICONS)); + return TRUE; + } + break; + } + return FALSE; +} + +int CIcqProto::ShowPopUpMsg(HANDLE hContact, const char *szTitle, const char *szMsg, BYTE bType) +{ + if (bPopUpService && getSettingByte(NULL, "PopupsEnabled", DEFAULT_POPUPS_ENABLED)) + { + POPUPDATAEX ppd = {0}; + POPUPDATAW ppdw = {0}; + LPCTSTR rsIcon; + char szPrefix[32], szSetting[32]; + + strcpy(szPrefix, "Popups"); + ppd.iSeconds = 0; + + switch(bType) { + case LOG_NOTE: + rsIcon = MAKEINTRESOURCE(IDI_INFORMATION); + ppd.colorBack = DEFAULT_LOG0_BACK_COLORS; + ppd.colorText = DEFAULT_LOG0_TEXT_COLORS; + strcat(szPrefix, "0"); + break; + + case LOG_WARNING: + rsIcon = MAKEINTRESOURCE(IDI_WARNING); + ppd.colorBack = DEFAULT_LOG1_BACK_COLORS; + ppd.colorText = DEFAULT_LOG1_TEXT_COLORS; + strcat(szPrefix, "1"); + break; + + case LOG_ERROR: + rsIcon = MAKEINTRESOURCE(IDI_ERROR); + ppd.colorBack = DEFAULT_LOG2_BACK_COLORS; + ppd.colorText = DEFAULT_LOG2_TEXT_COLORS; + strcat(szPrefix, "2"); + break; + + case LOG_FATAL: + rsIcon = MAKEINTRESOURCE(IDI_ERROR); + ppd.colorBack = DEFAULT_LOG3_BACK_COLORS; + ppd.colorText = DEFAULT_LOG3_TEXT_COLORS; + strcat(szPrefix, "3"); + break; + + case POPTYPE_SPAM: + rsIcon = MAKEINTRESOURCE(IDI_WARNING); + ppd.colorBack = DEFAULT_SPAM_BACK_COLORS; + ppd.colorText = DEFAULT_SPAM_TEXT_COLORS; + strcat(szPrefix, "Spam"); + break; + default: + return -1; + } + if (!getSettingByte(NULL, "PopupsSysIcons", DEFAULT_POPUPS_SYS_ICONS)) + ppd.lchIcon = m_hIconProtocol->GetIcon(); + else + ppd.lchIcon = (HICON)LoadImage( NULL, rsIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); + if (getSettingByte(NULL, "PopupsWinColors", DEFAULT_POPUPS_WIN_COLORS)) + { + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + ppd.colorBack = GetSysColor(COLOR_WINDOW); + } + else + { + if (getSettingByte(NULL, "PopupsDefColors", DEFAULT_POPUPS_DEF_COLORS)) + { + ppd.colorText = NULL; + ppd.colorBack = NULL; + } + else + { + strcpy(szSetting, szPrefix); + strcat(szSetting, "TextColor"); + ppd.colorText = getSettingDword(NULL, szSetting, ppd.colorText); + strcpy(szSetting, szPrefix); + strcat(szSetting, "BackColor"); + ppd.colorBack = getSettingDword(NULL, szSetting, ppd.colorBack); + } + } + strcpy(szSetting, szPrefix); + strcat(szSetting, "Timeout"); + ppd.iSeconds = getSettingDword(NULL, szSetting, ppd.iSeconds); + + // call unicode popup module - only on unicode OS otherwise it will not work properly :( + // due to Popup Plug bug in ADDPOPUPW implementation + if ( ServiceExists( MS_POPUP_ADDPOPUPW )) + { + char str[4096]; + + make_unicode_string_static(ICQTranslateUtfStatic(szTitle, str, sizeof(str)), ppdw.lpwzContactName, MAX_CONTACTNAME); + make_unicode_string_static(ICQTranslateUtfStatic(szMsg, str, sizeof(str)), ppdw.lpwzText, MAX_SECONDLINE); + ppdw.lchContact = hContact; + ppdw.lchIcon = ppd.lchIcon; + ppdw.colorBack = ppd.colorBack; + ppdw.colorText = ppd.colorText; + ppdw.PluginWindowProc = NULL; + ppdw.PluginData = NULL; + ppdw.iSeconds = ppd.iSeconds; + return CallService(MS_POPUP_ADDPOPUPW, (WPARAM)&ppdw, 0); + } + else + + { + char str[MAX_PATH]; + + utf8_decode_static(ICQTranslateUtfStatic(szTitle, str, MAX_PATH), ppd.lpzContactName, MAX_CONTACTNAME); + utf8_decode_static(ICQTranslateUtfStatic(szMsg, str, MAX_PATH), ppd.lpzText, MAX_SECONDLINE); + ppd.lchContact = hContact; + ppd.PluginWindowProc = NULL; + ppd.PluginData = NULL; + + return CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0); + } + } + return -1; // Failure +} diff --git a/protocols/IcqOscarJ/src/icq_popups.h b/protocols/IcqOscarJ/src/icq_popups.h new file mode 100644 index 0000000000..a42c230634 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_popups.h @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Headers for PopUp Plugin support +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_POPUPS_H +#define __ICQ_POPUPS_H + + +#define POPTYPE_SPAM 254 // this is for spambots + + +void InitPopUps(); +void InitPopupOpts(WPARAM wParam); + + +#endif /* __ICQ_POPUPS_H */ diff --git a/protocols/IcqOscarJ/src/icq_proto.cpp b/protocols/IcqOscarJ/src/icq_proto.cpp new file mode 100644 index 0000000000..d1490fac2e --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_proto.cpp @@ -0,0 +1,2375 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, George Hazan +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Protocol Interface Implementation +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +#include "m_icolib.h" + +extern PLUGININFOEX pluginInfo; +extern HANDLE hExtraXStatus; + +#pragma warning(disable:4355) + +static int CompareConns(const directconnect* p1, const directconnect* p2) +{ + if (p1 < p2) + return -1; + + return (p1 == p2) ? 0 : 1; +} + +static int CompareCookies( const icq_cookie_info* p1, const icq_cookie_info* p2 ) +{ + if ( p1->dwCookie < p2->dwCookie ) + return -1; + + return ( p1->dwCookie == p2->dwCookie ) ? 0 : 1; +} + +static int CompareFT( const filetransfer* p1, const filetransfer* p2 ) +{ + if ( p1->dwCookie < p2->dwCookie ) + return -1; + + return ( p1->dwCookie == p2->dwCookie ) ? 0 : 1; +} + +static int CompareContactsCache(const icq_contacts_cache *p1, const icq_contacts_cache *p2) +{ + if (p1->dwUin < p2->dwUin) + return -1; + + if (p1->dwUin > p2->dwUin) + return 1; + + return stricmpnull(p1->szUid, p2->szUid); +} + +CIcqProto::CIcqProto( const char* aProtoName, const TCHAR* aUserName ) : +cookies(10, CompareCookies), +directConns(10, CompareConns), +expectedFileRecvs(10, CompareFT), +contactsCache(10, CompareContactsCache), +cheekySearchId( -1 ) +{ + m_iVersion = 2; + m_iStatus = ID_STATUS_OFFLINE; + m_tszUserName = mir_tstrdup( aUserName ); + m_szModuleName = mir_strdup( aProtoName ); + m_szProtoName = mir_strdup( aProtoName ); + _strlwr( m_szProtoName ); + m_szProtoName[0] = toupper( m_szProtoName[0] ); + NetLog_Server( "Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName ); + + oftMutex = new icq_critical_section(); + + // Initialize direct connections + directConnListMutex = new icq_critical_section(); + expectedFileRecvMutex = new icq_critical_section(); + + // Initialize server lists + servlistMutex = new icq_critical_section(); + servlistQueueMutex = new icq_critical_section(); + HookProtoEvent(ME_CLIST_GROUPCHANGE, &CIcqProto::ServListCListGroupChange); + + // Initialize status message struct + ZeroMemory(&m_modeMsgs, sizeof(icq_mode_messages)); + m_modeMsgsMutex = new icq_critical_section(); + connectionHandleMutex = new icq_critical_section(); + localSeqMutex = new icq_critical_section(); + + m_modeMsgsEvent = CreateProtoEvent(ME_ICQ_STATUSMSGREQ); + hxstatuschanged = CreateProtoEvent(ME_ICQ_CUSTOMSTATUS_CHANGED); + hxstatusiconchanged = CreateProtoEvent(ME_ICQ_CUSTOMSTATUS_EXTRAICON_CHANGED); + + // Initialize cookies + cookieMutex = new icq_critical_section(); + wCookieSeq = 2; + + // Initialize rates + m_ratesMutex = new icq_critical_section(); + + // Initialize avatars + m_avatarsMutex = new icq_critical_section(); + + // Initialize temporary DB settings + CreateResidentSetting("Status"); // NOTE: XStatus cannot be temporary + CreateResidentSetting("TemporaryVisible"); + CreateResidentSetting("TickTS"); + CreateResidentSetting("IdleTS"); + CreateResidentSetting("AwayTS"); + CreateResidentSetting("LogonTS"); + CreateResidentSetting("DCStatus"); + CreateResidentSetting("CapBuf"); //capabilities bufer + CreateResidentSetting(DBSETTING_STATUS_NOTE_TIME); + CreateResidentSetting(DBSETTING_STATUS_MOOD); + + // Setup services + CreateProtoService(PS_CREATEACCMGRUI, &CIcqProto::OnCreateAccMgrUI ); + CreateProtoService(MS_ICQ_SENDSMS, &CIcqProto::SendSms); + CreateProtoService(PS_SET_NICKNAME, &CIcqProto::SetNickName); + + CreateProtoService(PS_GETMYAWAYMSG, &CIcqProto::GetMyAwayMsg); + + CreateProtoService(PS_GETINFOSETTING, &CIcqProto::GetInfoSetting); + + CreateProtoService(PSS_ADDED, &CIcqProto::SendYouWereAdded); + // Session password API + CreateProtoService(PS_ICQ_SETPASSWORD, &CIcqProto::SetPassword); + // ChangeInfo API + CreateProtoService(PS_CHANGEINFOEX, &CIcqProto::ChangeInfoEx); + // Avatar API + CreateProtoService(PS_GETAVATARINFOT, &CIcqProto::GetAvatarInfo); + CreateProtoService(PS_GETAVATARCAPS, &CIcqProto::GetAvatarCaps); + CreateProtoService(PS_GETMYAVATART, &CIcqProto::GetMyAvatar); + CreateProtoService(PS_SETMYAVATART, &CIcqProto::SetMyAvatar); + // Custom Status API + CreateProtoService(PS_ICQ_SETCUSTOMSTATUS, &CIcqProto::SetXStatus); + CreateProtoService(PS_ICQ_GETCUSTOMSTATUS, &CIcqProto::GetXStatus); + CreateProtoService(PS_ICQ_SETCUSTOMSTATUSEX, &CIcqProto::SetXStatusEx); + CreateProtoService(PS_ICQ_GETCUSTOMSTATUSEX, &CIcqProto::GetXStatusEx); + CreateProtoService(PS_ICQ_GETCUSTOMSTATUSICON, &CIcqProto::GetXStatusIcon); + CreateProtoService(PS_ICQ_REQUESTCUSTOMSTATUS, &CIcqProto::RequestXStatusDetails); + CreateProtoService(PS_ICQ_GETADVANCEDSTATUSICON, &CIcqProto::RequestAdvStatusIconIdx); + + CreateProtoService(MS_ICQ_ADDSERVCONTACT, &CIcqProto::AddServerContact); + + CreateProtoService(MS_REQ_AUTH, &CIcqProto::RequestAuthorization); + CreateProtoService(MS_GRANT_AUTH, &CIcqProto::GrantAuthorization); + CreateProtoService(MS_REVOKE_AUTH, &CIcqProto::RevokeAuthorization); + + CreateProtoService(MS_XSTATUS_SHOWDETAILS, &CIcqProto::ShowXStatusDetails); + + // Custom caps + CreateProtoService(PS_ICQ_ADDCAPABILITY, &CIcqProto::IcqAddCapability); + CreateProtoService(PS_ICQ_CHECKCAPABILITY, &CIcqProto::IcqCheckCapability); + + + HookProtoEvent(ME_SKIN2_ICONSCHANGED, &CIcqProto::OnReloadIcons); + + { + // Initialize IconLib icons + char szSectionName[MAX_PATH], *szAccountName = tchar_to_utf8(m_tszUserName); + null_snprintf(szSectionName, sizeof(szSectionName), "Protocols/%s/Accounts", ICQ_PROTOCOL_NAME); + + TCHAR lib[MAX_PATH]; + GetModuleFileName(hInst, lib, MAX_PATH); + + m_hIconProtocol = IconLibDefine(szAccountName, szSectionName, m_szModuleName, "main", lib, -IDI_ICQ); + SAFE_FREE(&szAccountName); + } + + // Reset a bunch of session specific settings + UpdateGlobalSettings(); + ResetSettingsOnLoad(); + + // Initialize Contacts Cache + InitContactsCache(); + + // Startup Auto Info-Update thread + icq_InitInfoUpdate(); + + // Init extra statuses + InitXStatusIcons(); + + HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &CIcqProto::OnPreBuildStatusMenu); + + // Register netlib users + NETLIBUSER nlu = {0}; + TCHAR szBuffer[MAX_PATH + 64]; + null_snprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s server connection"), m_tszUserName); + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; + nlu.ptszDescriptiveName = szBuffer; + nlu.szSettingsModule = m_szModuleName; + nlu.szHttpGatewayHello = "http://http.proxy.icq.com/hello"; + nlu.szHttpGatewayUserAgent = "Mozilla/4.08 [en] (WinNT; U ;Nav)"; + nlu.pfnHttpGatewayInit = icq_httpGatewayInit; + nlu.pfnHttpGatewayBegin = icq_httpGatewayBegin; + nlu.pfnHttpGatewayWrapSend = icq_httpGatewayWrapSend; + nlu.pfnHttpGatewayUnwrapRecv = icq_httpGatewayUnwrapRecv; + m_hServerNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + char szP2PModuleName[MAX_PATH]; + null_snprintf(szP2PModuleName, SIZEOF(szP2PModuleName), "%sP2P", m_szModuleName); + null_snprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s client-to-client connections"), m_tszUserName); + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_TCHAR; + nlu.ptszDescriptiveName = szBuffer; + nlu.szSettingsModule = szP2PModuleName; + nlu.minIncomingPorts = 1; + m_hDirectNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + // Register custom database events + DBEVENTTYPEDESCR eventType = {0}; + eventType.cbSize = DBEVENTTYPEDESCR_SIZE; + eventType.eventType = ICQEVENTTYPE_MISSEDMESSAGE; + eventType.module = m_szModuleName; + eventType.descr = "Missed message notifications"; + eventType.textService = ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE; + eventType.flags = DETF_HISTORY | DETF_MSGWINDOW; + // for now keep default "message" icon + CallService(MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&eventType); + + // Protocol instance is ready + NetLog_Server("%s: Protocol instance '%s' created.", ICQ_PROTOCOL_NAME, m_szModuleName); +} + + +CIcqProto::~CIcqProto() +{ + m_bXStatusEnabled = 10; // block clist changing + m_bMoodsEnabled = 10; + + // Serv-list update board clean-up + FlushServerIDs(); + /// TODO: make sure server-list handler thread is not running + /// TODO: save state of server-list update board to DB + servlistPendingFlushOperations(); + SAFE_FREE((void**)&servlistQueueList); + + // Finalize avatars + /// TODO: cleanup remaining avatar requests + SAFE_DELETE(&m_avatarsMutex); + + // NetLib clean-up + NetLib_SafeCloseHandle(&m_hDirectNetlibUser); + NetLib_SafeCloseHandle(&m_hServerNetlibUser); + + // Destroy hookable events + if (m_modeMsgsEvent) + DestroyHookableEvent(m_modeMsgsEvent); + + if (hxstatuschanged) + DestroyHookableEvent(hxstatuschanged); + + if (hxstatusiconchanged) + DestroyHookableEvent(hxstatusiconchanged); + + // Clean-up remaining protocol instance members + cookies.destroy(); + + UninitContactsCache(); + + CustomCapList.clear(); + + SAFE_DELETE(&m_ratesMutex); + + SAFE_DELETE(&servlistMutex); + SAFE_DELETE(&servlistQueueMutex); + + SAFE_DELETE(&m_modeMsgsMutex); + SAFE_DELETE(&localSeqMutex); + SAFE_DELETE(&connectionHandleMutex); + SAFE_DELETE(&oftMutex); + SAFE_DELETE(&directConnListMutex); + SAFE_DELETE(&expectedFileRecvMutex); + SAFE_DELETE(&cookieMutex); + + SAFE_FREE(&m_modeMsgs.szOnline); + SAFE_FREE(&m_modeMsgs.szAway); + SAFE_FREE(&m_modeMsgs.szNa); + SAFE_FREE(&m_modeMsgs.szOccupied); + SAFE_FREE(&m_modeMsgs.szDnd); + SAFE_FREE(&m_modeMsgs.szFfc); + + // Remove account icons + UninitXStatusIcons(); + + IconLibRemove(&m_hIconProtocol); + + NetLog_Server("%s: Protocol instance '%s' destroyed.", ICQ_PROTOCOL_NAME, m_szModuleName); + + mir_free( m_szProtoName ); + mir_free( m_szModuleName ); + mir_free( m_tszUserName ); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoadedEx - performs hook registration + + +int CIcqProto::OnModulesLoaded( WPARAM wParam, LPARAM lParam ) +{ + char pszP2PName[MAX_PATH]; + char pszGroupsName[MAX_PATH]; + char pszSrvGroupsName[MAX_PATH]; + char* modules[5] = {0,0,0,0,0}; + + null_snprintf(pszP2PName, SIZEOF(pszP2PName), "%sP2P", m_szModuleName); + null_snprintf(pszGroupsName, SIZEOF(pszGroupsName), "%sGroups", m_szModuleName); + null_snprintf(pszSrvGroupsName, SIZEOF(pszSrvGroupsName), "%sSrvGroups", m_szModuleName); + modules[0] = m_szModuleName; + modules[1] = pszP2PName; + modules[2] = pszGroupsName; + modules[3] = pszSrvGroupsName; + CallService("DBEditorpp/RegisterModule",(WPARAM)modules,(LPARAM)4); + + HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit); + HookProtoEvent(ME_USERINFO_INITIALISE, &CIcqProto::OnUserInfoInit); + HookProtoEvent(ME_IDLE_CHANGED, &CIcqProto::OnIdleChanged); + + InitAvatars(); + + // Init extra optional modules + InitPopUps(); + InitXStatusItems(FALSE); + + if (hExtraXStatus == NULL) + { + if (HookProtoEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CIcqProto::CListMW_ExtraIconsRebuild)) + { // note if the Hook was successful (e.g. clist_nicer creates them too late) + HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CIcqProto::CListMW_ExtraIconsApply); + bXStatusExtraIconsReady = 1; + } + } + else + { + HANDLE hContact = FindFirstContact(); + while (hContact != NULL) + { + DWORD bXStatus = getContactXStatus(hContact); + if (bXStatus > 0) + setContactExtraIcon(hContact, bXStatus); + + hContact = FindNextContact(hContact); + } + } + + return 0; +} + +int CIcqProto::OnPreShutdown(WPARAM wParam,LPARAM lParam) +{ + // signal info update thread to stop + icq_InfoUpdateCleanup(); + + // Make sure all connections are closed + CloseContactDirectConns(NULL); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AddToList - adds a contact to the contact list + +HANDLE CIcqProto::AddToList( int flags, PROTOSEARCHRESULT* psr ) +{ + if (psr) + { + if (psr->cbSize == sizeof(ICQSEARCHRESULT)) + { + ICQSEARCHRESULT *isr = (ICQSEARCHRESULT*)psr; + if (isr->uin) + return AddToListByUIN(isr->uin, flags); + else + { // aim contact + char szUid[MAX_PATH]; + + if (isr->hdr.flags & PSR_UNICODE) + unicode_to_ansi_static((WCHAR*)isr->hdr.id, szUid, MAX_PATH); + else + null_strcpy(szUid, (char*)isr->hdr.id, MAX_PATH); + + if (szUid[0] == 0) return 0; + return AddToListByUID(szUid, flags); + } + } + else + { + char szUid[MAX_PATH]; + + if (psr->flags & PSR_UNICODE) + unicode_to_ansi_static((WCHAR*)psr->id, szUid, MAX_PATH); + else + null_strcpy(szUid, (char*)psr->id, MAX_PATH); + + if (szUid[0] == 0) return 0; + if (IsStringUIN(szUid)) + return AddToListByUIN(atoi(szUid), flags); + else + return AddToListByUID(szUid, flags); + } + } + + return 0; // Failure +} + +HANDLE __cdecl CIcqProto::AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ) +{ + DWORD uin = 0; + uid_str uid = {0}; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0)) == -1) + return 0; + + dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob + 1); + dbei.pBlob[dbei.cbBlob] = '\0'; + + if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei)) + return 0; // failed to get event + + if (strcmpnull(dbei.szModule, m_szModuleName)) + return 0; // this event is not ours + + switch(dbei.eventType) { + case EVENTTYPE_CONTACTS: + { + char *pbOffset = (char*)dbei.pBlob; + char *pbEnd = pbOffset + dbei.cbBlob; + for (int i = 0; i <= iContact; i++) { + pbOffset += strlennull(pbOffset) + 1; // Nick + if (pbOffset >= pbEnd) break; + if (i == iContact) + { // we found the contact, get uid + if (IsStringUIN((char*)pbOffset)) + uin = atoi((char*)pbOffset); + else + { + uin = 0; + strcpy(uid, (char*)pbOffset); + } + } + pbOffset += strlennull(pbOffset) + 1; // Uin + if (pbOffset >= pbEnd) break; + } + } + break; + + case EVENTTYPE_AUTHREQUEST: + case EVENTTYPE_ADDED: + if ( getContactUid( DbGetAuthEventContact(&dbei), &uin, &uid)) + return 0; + + default: + return 0; + } + + if (uin != 0) + return AddToListByUIN(uin, flags); // Success + + // add aim contact + if (strlennull(uid)) + return AddToListByUID(uid, flags); // Success + + return NULL; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AuthAllow - processes the successful authorization + +int CIcqProto::Authorize( HANDLE hDbEvent ) +{ + if (icqOnline() && hDbEvent) + { + HANDLE hContact = HContactFromAuthEvent( hDbEvent ); + if (hContact == INVALID_HANDLE_VALUE) + return 1; + + DWORD uin; + uid_str uid; + if (getContactUid(hContact, &uin, &uid)) + return 1; + + icq_sendAuthResponseServ(uin, uid, 1, _T("")); + + deleteSetting(hContact, "Grant"); + + return 0; // Success + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AuthDeny - handles the unsuccessful authorization + +int CIcqProto::AuthDeny( HANDLE hDbEvent, const TCHAR* szReason ) +{ + if (icqOnline() && hDbEvent) + { + HANDLE hContact = HContactFromAuthEvent(hDbEvent); + if (hContact == INVALID_HANDLE_VALUE) + return 1; + + DWORD uin; + uid_str uid; + if (getContactUid(hContact, &uin, &uid)) + return 1; + + icq_sendAuthResponseServ(uin, uid, 0, szReason); + + if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + + return 0; // Success + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int __cdecl CIcqProto::AuthRecv( HANDLE hContact, PROTORECVEVENT* pre ) +{ + setContactHidden( hContact, 0 ); + ICQAddRecvEvent( NULL, EVENTTYPE_AUTHREQUEST, pre, pre->lParam, (PBYTE)pre->szMessage, 0 ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int __cdecl CIcqProto::AuthRequest( HANDLE hContact, const TCHAR* szMessage ) +{ + if ( !icqOnline()) + return 1; + + if (hContact) + { + DWORD dwUin; + uid_str szUid; + if (getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (dwUin) + { + char *utf = tchar_to_utf8(szMessage); + icq_sendAuthReqServ(dwUin, szUid, utf); + SAFE_FREE(&utf); + return 0; // Success + } + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// ChangeInfo + +HANDLE __cdecl CIcqProto::ChangeInfo( int iInfoType, void* pInfoData ) +{ + return NULL; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileAllow - starts a file transfer + +HANDLE __cdecl CIcqProto::FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ) +{ + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 0; // Invalid contact + + if (icqOnline() && hContact && szPath && hTransfer) + { // approve old fashioned file transfer + basic_filetransfer *ft = (basic_filetransfer *)hTransfer; + + if (!IsValidFileTransfer(ft)) + return 0; // Invalid transfer + + if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) + { + filetransfer *ft = (filetransfer *)hTransfer; + ft->szSavePath = tchar_to_utf8(szPath); + + { + icq_lock l(expectedFileRecvMutex); + expectedFileRecvs.insert(ft); + } + + // Was request received thru DC and have we a open DC, send through that + if (ft->bDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + icq_sendFileAcceptDirect(hContact, ft); + else + icq_sendFileAcceptServ(dwUin, ft, 0); + + return hTransfer; // Success + } + else if (ft->ft_magic == FT_MAGIC_OSCAR) + { // approve oscar file transfer + return oftFileAllow(hContact, hTransfer, szPath); + } + } + + return 0; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileCancel - cancels a file transfer + +int __cdecl CIcqProto::FileCancel( HANDLE hContact, HANDLE hTransfer ) +{ + DWORD dwUin; + uid_str szUid; + if ( getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (hContact && hTransfer) + { + basic_filetransfer *ft = (basic_filetransfer *)hTransfer; + + if (!IsValidFileTransfer(ft)) + return 1; // Invalid transfer + + if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) + { // cancel old fashioned file transfer + filetransfer * ft = (filetransfer*)hTransfer; + icq_CancelFileTransfer(hContact, ft); + return 0; // Success + } + else if (ft->ft_magic == FT_MAGIC_OSCAR) + { // cancel oscar file transfer + return oftFileCancel(hContact, hTransfer); + } + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileDeny - denies a file transfer + +int __cdecl CIcqProto::FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ) +{ + int nReturnValue = 1; + DWORD dwUin; + uid_str szUid; + basic_filetransfer *ft = (basic_filetransfer*)hTransfer; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (icqOnline() && hTransfer && hContact) + { + if (!IsValidFileTransfer(hTransfer)) + return 1; // Invalid transfer + + if (dwUin && ft->ft_magic == FT_MAGIC_ICQ) + { // deny old fashioned file transfer + filetransfer *ft = (filetransfer*)hTransfer; + char *szReasonUtf = tchar_to_utf8(szReason); + // Was request received thru DC and have we a open DC, send through that + if (ft->bDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + icq_sendFileDenyDirect(hContact, ft, szReasonUtf); + else + icq_sendFileDenyServ(dwUin, ft, szReasonUtf, 0); + SAFE_FREE(&szReasonUtf); + + nReturnValue = 0; // Success + } + else if (ft->ft_magic == FT_MAGIC_OSCAR) + { // deny oscar file transfer + return oftFileDeny(hContact, hTransfer, szReason); + } + } + // Release possible orphan structure + SafeReleaseFileTransfer((void**)&ft); + + return nReturnValue; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileResume - processes file renaming etc + +int __cdecl CIcqProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) +{ + if (icqOnline() && hTransfer) + { + basic_filetransfer *ft = (basic_filetransfer *)hTransfer; + + if (!IsValidFileTransfer(ft)) + return 1; // Invalid transfer + + if (ft->ft_magic == FT_MAGIC_ICQ) + { + char *szFileNameUtf = tchar_to_utf8(*szFilename); + icq_sendFileResume((filetransfer *)hTransfer, *action, szFileNameUtf); + SAFE_FREE(&szFileNameUtf); + } + else if (ft->ft_magic == FT_MAGIC_OSCAR) + { + oftFileResume((oscar_filetransfer *)hTransfer, *action, *szFilename); + } + else + return 1; // Failure + + return 0; // Success + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +DWORD_PTR __cdecl CIcqProto::GetCaps( int type, HANDLE hContact ) +{ + DWORD_PTR nReturn = 0; + + switch ( type ) { + + case PFLAGNUM_1: + nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | + PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_EXTSEARCH | + PF1_EXTSEARCHUI | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | + PF1_ADDED | PF1_CONTACT; + if (!m_bAimEnabled) + nReturn |= PF1_NUMERICUSERID; + if (m_bSsiEnabled && getSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER)) + nReturn |= PF1_SERVERCLIST; + break; + + case PFLAGNUM_2: + nReturn = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_INVISIBLE; + if (m_bAimEnabled) + nReturn |= PF2_ONTHEPHONE; + break; + + case PFLAGNUM_3: + nReturn = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_INVISIBLE; + break; + + case PFLAGNUM_4: + nReturn = PF4_SUPPORTIDLE | PF4_IMSENDUTF | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC; + if (m_bAvatarsEnabled) + nReturn |= PF4_AVATARS; +#ifdef DBG_CAPMTN + nReturn |= PF4_SUPPORTTYPING; +#endif + break; + + case PFLAGNUM_5: + nReturn = PF2_FREECHAT; + if (m_bAimEnabled) + nReturn |= PF2_ONTHEPHONE; + break; + + case PFLAG_UNIQUEIDTEXT: + nReturn = (DWORD_PTR)Translate("User ID"); + break; + + case PFLAG_UNIQUEIDSETTING: + nReturn = (DWORD_PTR)UNIQUEIDSETTING; + break; + + case PFLAG_MAXCONTACTSPERPACKET: + if ( hContact ) + { // determine per contact + BYTE bClientId = getSettingByte(hContact, "ClientID", CLID_GENERIC); + + if (bClientId == CLID_MIRANDA) + { + if (CheckContactCapabilities(hContact, CAPF_CONTACTS) && getContactStatus(hContact) != ID_STATUS_OFFLINE) + nReturn = 0x100; // limited only by packet size + else + nReturn = MAX_CONTACTSSEND; + } + else if (bClientId == CLID_ICQ6) + { + if (CheckContactCapabilities(hContact, CAPF_CONTACTS)) + nReturn = 1; // crapy ICQ6 cannot handle multiple contacts in the transfer + else + nReturn = 0; // this version does not support contacts transfer at all + } + else + nReturn = MAX_CONTACTSSEND; + } + else // return generic limit + nReturn = MAX_CONTACTSSEND; + break; + + case PFLAG_MAXLENOFMESSAGE: + nReturn = MAX_MESSAGESNACSIZE-102; + } + + return nReturn; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetIcon - loads an icon for the contact list + +HICON __cdecl CIcqProto::GetIcon( int iconIndex ) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)m_hIconProtocol->Handle(); + + bool big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = m_hIconProtocol->GetIcon(big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + hIcon = CopyIcon(hIcon); + m_hIconProtocol->ReleaseIcon(big); + return hIcon; + + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int __cdecl CIcqProto::GetInfo(HANDLE hContact, int infoType) +{ + if (icqOnline()) + { + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + DWORD dwCookie; + if (dwUin) + dwCookie = icq_sendGetInfoServ(hContact, dwUin, (infoType & SGIF_ONOPEN) != 0); + else // TODO: this needs something better + dwCookie = icq_sendGetAimProfileServ(hContact, szUid); + + return (dwCookie) ? 0 : 1; + } + + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by UID + +void CIcqProto::CheekySearchThread( void* ) +{ + char szUin[UINMAXLEN]; + ICQSEARCHRESULT isr = {0}; + isr.hdr.cbSize = sizeof(isr); + + if (cheekySearchUin) + { + _itoa(cheekySearchUin, szUin, 10); + isr.hdr.id = (FNAMECHAR*)szUin; + } + else + { + isr.hdr.id = (FNAMECHAR*)cheekySearchUid; + } + isr.uin = cheekySearchUin; + + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)cheekySearchId, (LPARAM)&isr); + BroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)cheekySearchId, 0); + cheekySearchId = -1; +} + + +HANDLE __cdecl CIcqProto::SearchBasic( const PROTOCHAR *pszSearch ) +{ + if (strlennull(pszSearch) == 0) + return 0; + + char pszUIN[255]; + int nHandle = 0; + int i, j; + + if (!m_bAimEnabled) + { + for (i=j=0; (i=0x30) && (pszSearch[i]<=0x39)) + { + pszUIN[j] = pszSearch[i]; + j++; + } + } + } + else + { + for (i=j=0; (i= 0x80) continue; + pszUIN[j] = pszSearch[i]; + j++; + } + } + } + pszUIN[j] = 0; + + if (strlennull(pszUIN)) + { + DWORD dwUin; + if (IsStringUIN(pszUIN)) + dwUin = atoi(pszUIN); + else + dwUin = 0; + + // Cheeky instant UIN search + if (!dwUin || GetKeyState(VK_CONTROL)&0x8000) + { + cheekySearchId = GenerateCookie(0); + cheekySearchUin = dwUin; + cheekySearchUid = null_strdup(pszUIN); + ForkThread(&CIcqProto::CheekySearchThread, 0); // The caller needs to get this return value before the results + nHandle = cheekySearchId; + } + else if (icqOnline()) + { + nHandle = SearchByUin(dwUin); + } + + // Success + return (HANDLE)nHandle; + } + + // Failure + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE __cdecl CIcqProto::SearchByEmail( const PROTOCHAR *email ) +{ + if (email && icqOnline() && strlennull(email) > 0) + { + DWORD dwSearchId, dwSecId; + char *szEmail = tchar_to_ansi(email); + + // Success + dwSearchId = SearchByMail(szEmail); + if (m_bAimEnabled) + dwSecId = icq_searchAimByEmail(szEmail, dwSearchId); + else + dwSecId = 0; + + SAFE_FREE(&szEmail); + + if (dwSearchId) + return ( HANDLE )dwSearchId; + else + return ( HANDLE )dwSecId; + } + + return 0; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SearchByName - searches the contact by its first or last name, or by a nickname + +HANDLE __cdecl CIcqProto::SearchByName(const PROTOCHAR *nick, const PROTOCHAR *firstName, const PROTOCHAR *lastName) +{ + if (icqOnline()) + { + if (nick || firstName || lastName) + { + char *nickUtf = tchar_to_utf8(nick); + char *firstNameUtf = tchar_to_utf8(firstName); + char *lastNameUtf = tchar_to_utf8(lastName); + + // Success + HANDLE dwCookie = (HANDLE)SearchByNames(nickUtf, firstNameUtf, lastNameUtf, 0); + + SAFE_FREE(&nickUtf); + SAFE_FREE(&firstNameUtf); + SAFE_FREE(&lastNameUtf); + + return dwCookie; + } + } + + return 0; // Failure +} + + +HWND __cdecl CIcqProto::CreateExtendedSearchUI( HWND parent ) +{ + if (parent && hInst) + return CreateDialog(hInst, MAKEINTRESOURCE(IDD_ICQADVANCEDSEARCH), parent, AdvancedSearchDlgProc); + + return NULL; // Failure +} + +HWND __cdecl CIcqProto::SearchAdvanced( HWND hwndDlg ) +{ + if (icqOnline() && IsWindow(hwndDlg)) + { + int nDataLen; + BYTE* bySearchData; + + if (bySearchData = createAdvancedSearchStructure(hwndDlg, &nDataLen)) + { + int result = icq_sendAdvancedSearchServ(bySearchData, nDataLen); + SAFE_FREE((void**)&bySearchData); + return ( HWND )result; // Success + } + } + + return NULL; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int __cdecl CIcqProto::RecvContacts( HANDLE hContact, PROTORECVEVENT* pre ) +{ + ICQSEARCHRESULT **isrList = (ICQSEARCHRESULT**)pre->szMessage; + int i; + DWORD cbBlob = 0; + DWORD flags = 0; + + if (pre->flags & PREF_UTF || pre->flags & PREF_UNICODE) + flags |= DBEF_UTF; + + for (i = 0; i < pre->lParam; i++) + { + if (pre->flags & PREF_UNICODE) + cbBlob += get_utf8_size((WCHAR*)isrList[i]->hdr.nick) + 2; + else + cbBlob += strlennull((char*)isrList[i]->hdr.nick) + 2; // both trailing zeros + if (isrList[i]->uin) + cbBlob += getUINLen(isrList[i]->uin); + else if (pre->flags & PREF_UNICODE) + cbBlob += strlennull((WCHAR*)isrList[i]->hdr.id); + else + cbBlob += strlennull((char*)isrList[i]->hdr.id); + } + PBYTE pBlob = (PBYTE)_alloca(cbBlob), pCurBlob; + for (i = 0, pCurBlob = pBlob; i < pre->lParam; i++) + { + if (pre->flags & PREF_UNICODE) + make_utf8_string_static((WCHAR*)isrList[i]->hdr.nick, (char*)pCurBlob, cbBlob - (pCurBlob - pBlob)); + else + strcpy((char*)pCurBlob, (char*)isrList[i]->hdr.nick); + pCurBlob += strlennull((char*)pCurBlob) + 1; + if (isrList[i]->uin) + { + char szUin[UINMAXLEN]; + _itoa(isrList[i]->uin, szUin, 10); + strcpy((char*)pCurBlob, szUin); + } + else + { // aim contact + if (pre->flags & PREF_UNICODE) + unicode_to_ansi_static((WCHAR*)isrList[i]->hdr.id, (char*)pCurBlob, cbBlob - (pCurBlob - pBlob)); + else + strcpy((char*)pCurBlob, (char*)isrList[i]->hdr.id); + } + pCurBlob += strlennull((char*)pCurBlob) + 1; + } + + ICQAddRecvEvent(hContact, EVENTTYPE_CONTACTS, pre, cbBlob, pBlob, flags); + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvFile + +int __cdecl CIcqProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) +{ + return Proto_RecvFile(hContact, evt); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +int __cdecl CIcqProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* pre ) +{ + DWORD cbBlob; + DWORD flags = 0; + + cbBlob = strlennull(pre->szMessage) + 1; + // process utf-8 encoded messages + if ((pre->flags & PREF_UTF) && !IsUSASCII(pre->szMessage, strlennull(pre->szMessage))) + flags |= DBEF_UTF; + // process unicode ucs-2 messages + if ((pre->flags & PREF_UNICODE) && !IsUnicodeAscii((WCHAR*)(pre->szMessage+cbBlob), strlennull((WCHAR*)(pre->szMessage+cbBlob)))) + cbBlob *= (sizeof(WCHAR)+1); + + ICQAddRecvEvent(hContact, EVENTTYPE_MESSAGE, pre, cbBlob, (PBYTE)pre->szMessage, flags); + + // stop contact from typing - some clients do not sent stop notify + if (CheckContactCapabilities(hContact, CAPF_TYPING)) + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, PROTOTYPE_CONTACTTYPING_OFF); + + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvUrl + +int __cdecl CIcqProto::RecvUrl( HANDLE hContact, PROTORECVEVENT* ) +{ + return 1; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int __cdecl CIcqProto::SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ) +{ + if (hContact && hContactsList) + { + int i; + DWORD dwUin; + uid_str szUid; + WORD wRecipientStatus; + DWORD dwCookie; + + if (getContactUid(hContact, &dwUin, &szUid)) + { // Invalid contact + return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The receiver has an invalid user ID."); + } + + wRecipientStatus = getContactStatus(hContact); + + // Failures + if (!icqOnline()) + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "You cannot send messages when you are offline."); + } + else if (!hContactsList || (nContacts < 1) || (nContacts > MAX_CONTACTSSEND)) + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #1)"); + } + // OK + else + { + if (CheckContactCapabilities(hContact, CAPF_CONTACTS) && wRecipientStatus != ID_STATUS_OFFLINE) + { // Use the new format if possible + int nDataLen, nNamesLen; + struct icq_contactsend_s* contacts = NULL; + + // Format the data part and the names part + // This is kinda messy, but there is no simple way to do it. First + // we need to calculate the length of the packet. + contacts = (struct icq_contactsend_s*)_alloca(sizeof(struct icq_contactsend_s)*nContacts); + ZeroMemory(contacts, sizeof(struct icq_contactsend_s)*nContacts); + { + nDataLen = 0; nNamesLen = 0; + for (i = 0; i < nContacts; i++) + { + uid_str szContactUid; + + if (!IsICQContact(hContactsList[i])) + break; // Abort if a non icq contact is found + if (getContactUid(hContactsList[i], &contacts[i].uin, &szContactUid)) + break; // Abort if invalid contact + contacts[i].uid = contacts[i].uin?NULL:null_strdup(szContactUid); + contacts[i].szNick = NickFromHandleUtf(hContactsList[i]); + nDataLen += getUIDLen(contacts[i].uin, contacts[i].uid) + 4; + nNamesLen += strlennull(contacts[i].szNick) + 8; + } + + if (i == nContacts) + { + icq_packet mData, mNames; + +#ifdef _DEBUG + NetLog_Server("Sending contacts to %s.", strUID(dwUin, szUid)); +#endif + // Do not calculate the exact size of the data packet - only the maximal size (easier) + // Sumarize size of group information + // - we do not utilize the full power of the protocol and send all contacts with group "General" + // just like ICQ6 does + nDataLen += 9; + nNamesLen += 9; + + // Create data structures + mData.wPlace = 0; + mData.pData = (LPBYTE)SAFE_MALLOC(nDataLen); + mData.wLen = nDataLen; + mNames.wPlace = 0; + mNames.pData = (LPBYTE)SAFE_MALLOC(nNamesLen); + + // pack Group Name + packWord(&mData, 7); + packBuffer(&mData, (LPBYTE)"General", 7); + packWord(&mNames, 7); + packBuffer(&mNames, (LPBYTE)"General", 7); + + // all contacts in one group + packWord(&mData, (WORD)nContacts); + packWord(&mNames, (WORD)nContacts); + for (i = 0; i < nContacts; i++) + { + uid_str szContactUid; + WORD wLen; + + if (contacts[i].uin) + strUID(contacts[i].uin, szContactUid); + else + strcpy(szContactUid, contacts[i].uid); + + // prepare UID + wLen = strlennull(szContactUid); + packWord(&mData, wLen); + packBuffer(&mData, (LPBYTE)szContactUid, wLen); + + // prepare Nick + wLen = strlennull(contacts[i].szNick); + packWord(&mNames, (WORD)(wLen + 4)); + packTLV(&mNames, 0x01, wLen, (LPBYTE)contacts[i].szNick); + } + + // Cleanup temporary list + for(i = 0; i < nContacts; i++) + { + SAFE_FREE(&contacts[i].szNick); + SAFE_FREE(&contacts[i].uid); + } + + // Rate check + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) + { // rate is too high, the message will not go thru... + SAFE_FREE((void**)&mData.pData); + SAFE_FREE((void**)&mNames.pData); + + return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The message could not be delivered. You are sending too fast. Wait a while and try again."); + } + + // Set up the ack type + cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_CONTACTS, hContact, dwUin, FALSE); + + // AIM clients do not send acknowledgement + if (!dwUin && pCookieData->nAckType == ACKTYPE_CLIENT) + pCookieData->nAckType = ACKTYPE_SERVER; + // Send the message + dwCookie = icq_SendChannel2Contacts(dwUin, szUid, hContact, (char*)mData.pData, mData.wPlace, (char*)mNames.pData, mNames.wPlace, pCookieData); + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_CONTACTS, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + // Release our buffers + SAFE_FREE((void**)&mData.pData); + SAFE_FREE((void**)&mNames.pData); + } + else + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #2)"); + } + + for(i = 0; i < nContacts; i++) + { + SAFE_FREE(&contacts[i].szNick); + SAFE_FREE(&contacts[i].uid); + } + } + } + else if (dwUin) + { // old format is only understood by ICQ clients + int nBodyLength; + char szContactUin[UINMAXLEN]; + char szCount[17]; + struct icq_contactsend_s* contacts = NULL; + uid_str szContactUid; + + + // Format the body + // This is kinda messy, but there is no simple way to do it. First + // we need to calculate the length of the packet. + contacts = (struct icq_contactsend_s*)_alloca(sizeof(struct icq_contactsend_s)*nContacts); + ZeroMemory(contacts, sizeof(struct icq_contactsend_s)*nContacts); + { + nBodyLength = 0; + for (i = 0; i < nContacts; i++) + { + if (!IsICQContact(hContactsList[i])) + break; // Abort if a non icq contact is found + if (getContactUid(hContactsList[i], &contacts[i].uin, &szContactUid)) + break; // Abort if invalid contact + contacts[i].uid = contacts[i].uin?NULL:null_strdup(szContactUid); + contacts[i].szNick = NickFromHandle(hContactsList[i]); + // Compute this contact's length + nBodyLength += getUIDLen(contacts[i].uin, contacts[i].uid) + 1; + nBodyLength += strlennull(contacts[i].szNick) + 1; + } + + if (i == nContacts) + { + char* pBody; + char* pBuffer; + +#ifdef _DEBUG + NetLog_Server("Sending contacts to %d.", dwUin); +#endif + // Compute count record's length + _itoa(nContacts, szCount, 10); + nBodyLength += strlennull(szCount) + 1; + + // Finally we need to copy the contact data into the packet body + pBuffer = pBody = (char *)SAFE_MALLOC(nBodyLength); + null_strcpy(pBuffer, szCount, nBodyLength - 1); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + for (i = 0; i < nContacts; i++) + { + if (contacts[i].uin) + { + _itoa(contacts[i].uin, szContactUin, 10); + strcpy(pBuffer, szContactUin); + } + else + strcpy(pBuffer, contacts[i].uid); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + strcpy(pBuffer, contacts[i].szNick); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + } + + for (i = 0; i < nContacts; i++) + { // release memory + SAFE_FREE(&contacts[i].szNick); + SAFE_FREE(&contacts[i].uid); + } + + // Set up the ack type + cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_CONTACTS, hContact, dwUin, TRUE); + + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { + int iRes = icq_SendDirectMessage(hContact, pBody, nBodyLength, 1, pCookieData, NULL); + + if (iRes) + { + SAFE_FREE((void**)&pBody); + + return iRes; // we succeded, return + } + } + + // Rate check + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) + { // rate is too high, the message will not go thru... + SAFE_FREE((void**)&pCookieData); + SAFE_FREE((void**)&pBody); + + return ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The message could not be delivered. You are sending too fast. Wait a while and try again."); + } + // Select channel and send +/* + if (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || wRecipientStatus == ID_STATUS_OFFLINE) + { + dwCookie = icq_SendChannel4Message(dwUin, hContact, MTYPE_CONTACTS, (WORD)nBodyLength, pBody, pCookieData); + } + else +*/ + { + WORD wPriority; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + dwCookie = icq_SendChannel2Message(dwUin, hContact, pBody, nBodyLength, wPriority, pCookieData, NULL); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_CONTACTS, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + SAFE_FREE((void**)&pBody); + } + else + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "Bad data (internal error #2)"); + } + } + } + else + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_CONTACTS, "The reciever does not support receiving of contacts."); + } + } + return dwCookie; + } + + // Exit with Failure + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE __cdecl CIcqProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) +{ + if ( !icqOnline()) + return 0; + + if (hContact && szDescription && ppszFiles) + { + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 0; // Invalid contact + + if (getContactStatus(hContact) != ID_STATUS_OFFLINE) + { + if (CheckContactCapabilities(hContact, CAPF_OSCAR_FILE)) + return oftInitTransfer(hContact, dwUin, szUid, (LPCTSTR*)ppszFiles, szDescription); + + if (dwUin) + { + WORD wClientVersion = getSettingWord(hContact, "Version", 7); + + if (wClientVersion < 7) + NetLog_Server("IcqSendFile() can't send to version %u", wClientVersion); + else + { + int i; + filetransfer* ft; + struct _stat statbuf; + + // Initialize filetransfer struct + ft = CreateFileTransfer(hContact, dwUin, (wClientVersion == 7) ? 7: 8); + + for (ft->dwFileCount = 0; ppszFiles[ft->dwFileCount]; ft->dwFileCount++); + ft->pszFiles = (char **)SAFE_MALLOC(sizeof(char *) * ft->dwFileCount); + ft->dwTotalSize = 0; + for (i = 0; i < (int)ft->dwFileCount; i++) + { + ft->pszFiles[i] = (ppszFiles[i]) ? tchar_to_utf8(ppszFiles[i]) : NULL; + + if (_tstat(ppszFiles[i], &statbuf)) + NetLog_Server("IcqSendFile() was passed invalid filename(s)"); + else + ft->dwTotalSize += statbuf.st_size; + } + ft->szDescription = tchar_to_utf8(szDescription); + ft->dwTransferSpeed = 100; + ft->sending = 1; + ft->fileId = -1; + ft->iCurrentFile = 0; + ft->dwCookie = AllocateCookie(CKT_FILE, 0, hContact, ft); + ft->hConnection = NULL; + + // Send file transfer request + { + char szFiles[64], tmp[64]; + char *pszFiles; + + + NetLog_Server("Init file send"); + + if (ft->dwFileCount == 1) + { + pszFiles = strchr(ft->pszFiles[0], '\\'); + if (pszFiles) + pszFiles++; + else + pszFiles = ft->pszFiles[0]; + } + else + { + null_snprintf(szFiles, SIZEOF(szFiles), ICQTranslateUtfStatic("%d Files", tmp, SIZEOF(tmp)), ft->dwFileCount); + pszFiles = szFiles; + } + + // Send packet + { + if (ft->nVersion == 7) + { + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { + int iRes = icq_sendFileSendDirectv7(ft, pszFiles); + if (iRes) return ft; // Success + } + NetLog_Server("Sending v%u file transfer request through server", 7); + icq_sendFileSendServv7(ft, pszFiles); + } + else + { + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { + int iRes = icq_sendFileSendDirectv8(ft, pszFiles); + if (iRes) return ft; // Success + } + NetLog_Server("Sending v%u file transfer request through server", 8); + icq_sendFileSendServv8(ft, pszFiles, ACKTYPE_NONE); + } + } + } + + return ft; // Success + } + } + } + } + + return 0; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SendMessage - sends a message + +int __cdecl CIcqProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) +{ + if (hContact && pszSrc) + { + DWORD dwCookie; + char* puszText = NULL; + int bNeedFreeU = 0; + cookie_message_data *pCookieData = NULL; + + // Invalid contact + DWORD dwUin; + uid_str szUID; + if (getContactUid(hContact, &dwUin, &szUID)) + return ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The receiver has an invalid user ID."); + + if (flags & PREF_UNICODE) + { + puszText = make_utf8_string((WCHAR*)(pszSrc + strlennull(pszSrc) + 1)); // get the UTF-16 part + bNeedFreeU = 1; + } + else if (flags & PREF_UTF) + puszText = (char*)pszSrc; + else + { + puszText = (char*)ansi_to_utf8(pszSrc); + bNeedFreeU = 1; + } + + WORD wRecipientStatus = getContactStatus(hContact); + + BOOL plain_ascii = IsUSASCII(puszText, strlennull(puszText)); + + BOOL oldAnsi = plain_ascii || !m_bUtfEnabled || + (!(flags & (PREF_UTF | PREF_UNICODE)) && m_bUtfEnabled == 1) || + !CheckContactCapabilities(hContact, CAPF_UTF) || + !getSettingByte(hContact, "UnicodeSend", 1); + + if (m_bTempVisListEnabled && m_iStatus == ID_STATUS_INVISIBLE) + makeContactTemporaryVisible(hContact); // make us temporarily visible to contact + + // Failure scenarios + if (!icqOnline()) + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "You cannot send messages when you are offline."); + } + else if ((wRecipientStatus == ID_STATUS_OFFLINE) && (strlennull(puszText) > 4096)) + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "Messages to offline contacts must be shorter than 4096 characters."); + } + // Looks OK + else + { +#ifdef _DEBUG + NetLog_Server("Send %smessage - Message cap is %u", puszText ? "unicode " : "", CheckContactCapabilities(hContact, CAPF_SRV_RELAY)); + NetLog_Server("Send %smessage - Contact status is %u", puszText ? "unicode " : "", wRecipientStatus); +#endif + if (dwUin && m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { // send thru direct + char *dc_msg = puszText; + char *dc_cap = plain_ascii ? NULL : CAP_UTF8MSGS; + char *szUserAnsi = NULL; + + if (!plain_ascii && oldAnsi) + { + szUserAnsi = ConvertMsgToUserSpecificAnsi(hContact, puszText); + if (szUserAnsi) + { + dc_msg = szUserAnsi; + dc_cap = NULL; + } + } + + // Set up the ack type + pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, TRUE); + pCookieData->nAckType = ACKTYPE_CLIENT; + dwCookie = icq_SendDirectMessage(hContact, dc_msg, strlennull(dc_msg), 1, pCookieData, dc_cap); + + SAFE_FREE(&szUserAnsi); + if (dwCookie) + { // free the buffers if alloced + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; // we succeded, return + } + // on failure, fallback to send thru server + } + + if (!dwUin || !CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || + wRecipientStatus == ID_STATUS_OFFLINE || wRecipientStatus == ID_STATUS_INVISIBLE || + getSettingByte(hContact, "OnlyServerAcks", getSettingByte(NULL, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS)) || + !getSettingByte(hContact, "SlowSend", getSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND))) + { + /// TODO: add support for RTL & user customizable font + { + char *mng = MangleXml(puszText, strlennull(puszText)); + int len = strlennull(mng); + mng = (char*)SAFE_REALLOC(mng, len + 28); + memmove(mng + 12, mng, len + 1); + memcpy(mng, "", 12); + strcat(mng, ""); + if (bNeedFreeU) SAFE_FREE(&puszText); + puszText = mng; + bNeedFreeU = 1; + } + + WCHAR *pwszText = plain_ascii ? NULL : make_unicode_string(puszText); + if ((plain_ascii ? strlennull(puszText) : strlennull(pwszText) * sizeof(WCHAR)) > MAX_MESSAGESNACSIZE) + { // max length check // TLV(2) is currently limited to 0xA00 bytes in online mode + // only limit to not get disconnected, all other will be handled by error 0x0A + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered, it is too long."); + + // free the buffers if alloced + SAFE_FREE((void**)&pwszText); + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; + } + // Rate check + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) + { // rate is too high, the message will not go thru... + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered. You are sending too fast. Wait a while and try again."); + + // free the buffers if alloced + SAFE_FREE((void**)&pwszText); + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; + } + + pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, FALSE); + + if (plain_ascii) + dwCookie = icq_SendChannel1Message(dwUin, szUID, hContact, puszText, pCookieData); + else + dwCookie = icq_SendChannel1MessageW(dwUin, szUID, hContact, pwszText, pCookieData); + // free the unicode message + SAFE_FREE((void**)&pwszText); + } + else + { + WORD wPriority; + + char *srv_msg = puszText; + char *srv_cap = plain_ascii ? NULL : CAP_UTF8MSGS; + char *szUserAnsi = NULL; + + if (!plain_ascii && oldAnsi) + { + szUserAnsi = ConvertMsgToUserSpecificAnsi(hContact, puszText); + if (szUserAnsi) + { + srv_msg = szUserAnsi; + srv_cap = NULL; + } + } + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + if (strlennull(srv_msg) + (!oldAnsi ? 144 : 102) > MAX_MESSAGESNACSIZE) + { // max length check + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered, it is too long."); + + SAFE_FREE(&szUserAnsi); + // free the buffers if alloced + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; + } + // Rate check + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) + { // rate is too high, the message will not go thru... + dwCookie = ReportGenericSendError(hContact, ACKTYPE_MESSAGE, "The message could not be delivered. You are sending too fast. Wait a while and try again."); + + SAFE_FREE(&szUserAnsi); + // free the buffers if alloced + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; + } + + pCookieData = CreateMessageCookieData(MTYPE_PLAIN, hContact, dwUin, TRUE); + dwCookie = icq_SendChannel2Message(dwUin, hContact, srv_msg, strlennull(srv_msg), wPriority, pCookieData, srv_cap); + SAFE_FREE(&szUserAnsi); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData && pCookieData->nAckType == ACKTYPE_NONE) + { + SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_MESSAGE, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + } + // free the buffers if alloced + if (bNeedFreeU) SAFE_FREE(&puszText); + + return dwCookie; // Success + } + + return 0; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int __cdecl CIcqProto::SendUrl( HANDLE hContact, int flags, const char* url ) +{ + if (hContact && url) + { + DWORD dwCookie; + WORD wRecipientStatus; + DWORD dwUin; + + if (getContactUid(hContact, &dwUin, NULL)) + { // Invalid contact + return ReportGenericSendError(hContact, ACKTYPE_URL, "The receiver has an invalid user ID."); + } + + wRecipientStatus = getContactStatus(hContact); + + // Failure + if (!icqOnline()) + { + dwCookie = ReportGenericSendError(hContact, ACKTYPE_URL, "You cannot send messages when you are offline."); + } + // Looks OK + else + { + char* szDesc; + char* szBody; + int nBodyLen; + int nDescLen; + int nUrlLen; + + + // Set up the ack type + cookie_message_data *pCookieData = CreateMessageCookieData(MTYPE_URL, hContact, dwUin, TRUE); + + // Format the body + nUrlLen = strlennull(url); + szDesc = (char *)url + nUrlLen + 1; + nDescLen = strlennull(szDesc); + nBodyLen = nUrlLen + nDescLen + 2; + szBody = (char *)_alloca(nBodyLen); + strcpy(szBody, szDesc); + szBody[nDescLen] = (char)0xFE; // Separator + strcpy(szBody + nDescLen + 1, url); + + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { + int iRes = icq_SendDirectMessage(hContact, szBody, nBodyLen, 1, pCookieData, NULL); + if (iRes) return iRes; // we succeded, return + } + + // Rate check + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_LIMIT)) + { // rate is too high, the message will not go thru... + SAFE_FREE((void**)&pCookieData); + + return ReportGenericSendError(hContact, ACKTYPE_URL, "The message could not be delivered. You are sending too fast. Wait a while and try again."); + } + // Select channel and send +/* + if (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY) || + wRecipientStatus == ID_STATUS_OFFLINE) + { + dwCookie = icq_SendChannel4Message(dwUin, hContact, MTYPE_URL, + (WORD)nBodyLen, szBody, pCookieData); + } + else +*/ + { + WORD wPriority; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + dwCookie = icq_SendChannel2Message(dwUin, hContact, szBody, nBodyLen, wPriority, pCookieData, NULL); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + SendProtoAck(hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_URL, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + } + + return dwCookie; // Success + } + + return 0; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetApparentMode - sets the visibility status + +int __cdecl CIcqProto::SetApparentMode( HANDLE hContact, int mode ) +{ + DWORD uin; + uid_str uid; + + if (getContactUid(hContact, &uin, &uid)) + return 1; // Invalid contact + + if (hContact) + { + // Only 3 modes are supported + if (mode == 0 || mode == ID_STATUS_ONLINE || mode == ID_STATUS_OFFLINE) + { + int oldMode = getSettingWord(hContact, "ApparentMode", 0); + + // Don't send redundant updates + if (mode != oldMode) + { + setSettingWord(hContact, "ApparentMode", (WORD)mode); + + // Not being online is only an error when in SS mode. This is not handled + // yet so we just ignore this for now. + if (icqOnline()) + { + if (oldMode != 0) + { // Remove from old list + if (oldMode == ID_STATUS_OFFLINE && getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) + { // Need to remove Ignore item as well + icq_removeServerPrivacyItem(hContact, uin, uid, getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0), SSI_ITEM_IGNORE); + + setSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0); + } + icq_sendChangeVisInvis(hContact, uin, uid, oldMode==ID_STATUS_OFFLINE, 0); + } + if (mode != 0) + { // Add to new list + if (mode==ID_STATUS_OFFLINE && getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) + return 0; // Success: offline by ignore item + + icq_sendChangeVisInvis(hContact, uin, uid, mode==ID_STATUS_OFFLINE, 1); + } + } + + return 0; // Success + } + } + } + + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PrepareStatusNote - returns correct status note for given status + +char* CIcqProto::PrepareStatusNote(int nStatus) +{ + char *szStatusNote = NULL; + BYTE bXStatus = getContactXStatus(NULL); + + // use custom status message as status note + if (bXStatus) + szStatusNote = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); + + if (!szStatusNote || !szStatusNote[0]) + { // get standard status message (no custom status defined) + icq_lock l(m_modeMsgsMutex); + + char **pszStatusNote = MirandaStatusToAwayMsg(nStatus); + if (pszStatusNote) + szStatusNote = null_strdup(*pszStatusNote); + } + + if (!szStatusNote) + // nothing available set empty status note + szStatusNote = null_strdup(""); + + return szStatusNote; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetStatus - sets the protocol status + +int __cdecl CIcqProto::SetStatus(int iNewStatus) +{ + int nNewStatus = MirandaStatusToSupported(iNewStatus); + + // check if netlib handles are ready + if (!m_hServerNetlibUser) + return 0; + + if (m_bTempVisListEnabled && icqOnline()) // remove temporary visible users + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_REMOVETEMPVISIBLE, BUL_TEMPVISIBLE); + + if (nNewStatus == m_iStatus) + return 0; + + // clear custom status on status change + if (getSettingByte(NULL, "XStatusReset", DEFAULT_XSTATUS_RESET)) + setXStatusEx(0, 0); + + // New status is OFFLINE + if (nNewStatus == ID_STATUS_OFFLINE) + { // for quick logoff + if (icqOnline()) + { // set offline status note (otherwise the old will remain) + char *szOfflineNote = PrepareStatusNote(nNewStatus); + + // Create unnamed event to wait until the status note change process is completed + m_hNotifyNameInfoEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + int bNoteChanged = SetStatusNote(szOfflineNote, 0, FALSE); + + SAFE_FREE(&szOfflineNote); + + // Note was changed, wait until the process is over + if (bNoteChanged) + ICQWaitForSingleObject(m_hNotifyNameInfoEvent, 4000, TRUE); + + // Release the event + CloseHandle(m_hNotifyNameInfoEvent); + m_hNotifyNameInfoEvent = NULL; + } + + m_iDesiredStatus = nNewStatus; + + if (hServerConn) + { // Connected, Send disconnect packet + icq_sendCloseConnection(); + + icq_serverDisconnect(FALSE); + + SetCurrentStatus(ID_STATUS_OFFLINE); + + NetLog_Server("Logged off."); + } + } + else + { + switch (m_iStatus) { + + // We are offline and need to connect + case ID_STATUS_OFFLINE: + { + // Update user connection settings + UpdateGlobalSettings(); + + // Read UIN from database + m_dwLocalUIN = getContactUin(NULL); + if (m_dwLocalUIN == 0) + { + SetCurrentStatus(ID_STATUS_OFFLINE); + BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID); + icq_LogMessage(LOG_FATAL, LPGEN("You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again.")); + return 0; + } + + // Set status to 'Connecting' + m_iDesiredStatus = nNewStatus; + SetCurrentStatus(ID_STATUS_CONNECTING); + + // Read password from database + char *pszPwd = GetUserPassword(FALSE); + + if (pszPwd) + icq_login(pszPwd); + else + RequestPassword(); + + break; + } + + // We are connecting... We only need to change the going online status + case ID_STATUS_CONNECTING: + m_iDesiredStatus = nNewStatus; + break; + + // We are already connected so we should just change status + default: + SetCurrentStatus(nNewStatus); + + char *szStatusNote = PrepareStatusNote(nNewStatus); + + //! This is a bit tricky, we do trigger status note change thread and then + // change the status note right away (this spares one packet) - so SetStatusNote() + // will only change User Details Directory + SetStatusNote(szStatusNote, 6000, FALSE); + + if (m_iStatus == ID_STATUS_INVISIBLE) + { + if (m_bSsiEnabled) + updateServVisibilityCode(3); + icq_setstatus(MirandaStatusToIcq(m_iStatus), szStatusNote); + } + else + { + icq_setstatus(MirandaStatusToIcq(m_iStatus), szStatusNote); + if (m_bSsiEnabled) + updateServVisibilityCode(4); + } + SAFE_FREE(&szStatusNote); + + if (m_bAimEnabled) + { + icq_lock l(m_modeMsgsMutex); + + char ** pszStatusNote = MirandaStatusToAwayMsg(m_iStatus); + + if (pszStatusNote) + icq_sendSetAimAwayMsgServ(*pszStatusNote); + else // clear the away message + icq_sendSetAimAwayMsgServ(NULL); + } + } + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetAwayMsgThread - return a contact's status message + +struct status_message_thread_data +{ + HANDLE hContact; + char *szMessage; + HANDLE hProcess; +}; + +void __cdecl CIcqProto::GetAwayMsgThread( void *pStatusData ) +{ + status_message_thread_data *pThreadData = (status_message_thread_data*)pStatusData; + if (pThreadData) { + // wait a little + Sleep(100); + + setStatusMsgVar(pThreadData->hContact, pThreadData->szMessage, false); + + TCHAR *tszMsg = mir_utf8decodeT(pThreadData->szMessage); + BroadcastAck(pThreadData->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, pThreadData->hProcess, (LPARAM)tszMsg); + mir_free(tszMsg); + + SAFE_FREE(&pThreadData->szMessage); + SAFE_FREE((void**)&pThreadData); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_GetAwayMsg - returns a contact's away message + +HANDLE __cdecl CIcqProto::GetAwayMsg( HANDLE hContact ) +{ + DWORD dwUin; + uid_str szUID; + + if (getContactUid(hContact, &dwUin, &szUID)) + return 0; // Invalid contact + + if (!dwUin || !CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) + { // No individual status messages, check if the contact has Status Note, if yes give it + char *szStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, NULL); + + if (strlennull(szStatusNote) > 0) + { // Give Status Note + status_message_thread_data *pThreadData = (status_message_thread_data*)SAFE_MALLOC(sizeof(status_message_thread_data)); + + pThreadData->hContact = hContact; + pThreadData->szMessage = szStatusNote; + pThreadData->hProcess = (HANDLE)GenerateCookie(0); + ForkThread(&CIcqProto::GetAwayMsgThread, pThreadData); + + return pThreadData->hProcess; + } + SAFE_FREE(&szStatusNote); + } + + if (!icqOnline()) + return 0; + + WORD wStatus = getContactStatus(hContact); + + if (dwUin) + { + int wMessageType = 0; + + switch(wStatus) + { + case ID_STATUS_ONLINE: + if (CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) + wMessageType = MTYPE_AUTOONLINE; + break; + + case ID_STATUS_AWAY: + wMessageType = MTYPE_AUTOAWAY; + break; + + case ID_STATUS_NA: + wMessageType = MTYPE_AUTONA; + break; + + case ID_STATUS_OCCUPIED: + wMessageType = MTYPE_AUTOBUSY; + break; + + case ID_STATUS_DND: + wMessageType = MTYPE_AUTODND; + break; + + case ID_STATUS_FREECHAT: + wMessageType = MTYPE_AUTOFFC; + break; + + default: + break; + } + + if (wMessageType) + { + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + { + int iRes = icq_sendGetAwayMsgDirect(hContact, wMessageType); + if (iRes) return (HANDLE)iRes; // we succeded, return + } + if (CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) + return (HANDLE)icq_sendGetAwayMsgServExt(hContact, dwUin, szUID, wMessageType, + (WORD)(getSettingWord(hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success + else + return (HANDLE)icq_sendGetAwayMsgServ(hContact, dwUin, wMessageType, + (WORD)(getSettingWord(hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success + } + } + else + { // AIM contact + if (wStatus == ID_STATUS_AWAY) + return (HANDLE)icq_sendGetAimAwayMsgServ(hContact, szUID, MTYPE_AUTOAWAY); + } + + return 0; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG - processes received status mode message + +int __cdecl CIcqProto::RecvAwayMsg( HANDLE hContact, int statusMode, PROTORECVEVENT* evt ) +{ + if (evt->flags & PREF_UTF) { + setStatusMsgVar(hContact, evt->szMessage, false); + + TCHAR* pszMsg = mir_utf8decodeT(evt->szMessage); + BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)pszMsg); + mir_free(pszMsg); + } + else { + setStatusMsgVar(hContact, evt->szMessage, true); + BroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)evt->lParam, (LPARAM)(TCHAR*)_A2T(evt->szMessage)); + } + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AWAYMSG - send status mode message (individual mode) + +int __cdecl CIcqProto::SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ) +{ + return 1; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetAwayMsg - sets the away status message + +int __cdecl CIcqProto::SetAwayMsg(int status, const TCHAR* msg) +{ + icq_lock l(m_modeMsgsMutex); + + char **ppszMsg = MirandaStatusToAwayMsg(MirandaStatusToSupported(status)); + if (!ppszMsg) + return 1; // Failure + + // Prepare UTF-8 status message + char *szNewUtf = tchar_to_utf8(msg); + + if (strcmpnull(szNewUtf, *ppszMsg)) + { + // Free old message + SAFE_FREE(ppszMsg); + + // Set new message + *ppszMsg = szNewUtf; + szNewUtf = NULL; + + if ((m_iStatus == status) && icqOnline()) + { // update current status note + char *szNote = *ppszMsg ? *ppszMsg : ""; + + BYTE bXStatus = getContactXStatus(NULL); + if (!bXStatus) + SetStatusNote(szNote, 1000, FALSE); + + if (m_bAimEnabled) + icq_sendSetAimAwayMsgServ(*ppszMsg); + } + } + SAFE_FREE(&szNewUtf); + + return 0; // Success +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// GetMyAwayMsg - obtain the current away message + +INT_PTR CIcqProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam) +{ + icq_lock l(m_modeMsgsMutex); + + char **ppszMsg = MirandaStatusToAwayMsg(wParam ? wParam : m_iStatus); + + if (!ppszMsg || !*ppszMsg) + return 0; + + int nMsgLen = strlennull(*ppszMsg) + 1; + + if (lParam & SGMA_UNICODE) + { + WCHAR *szMsg = (WCHAR*)_alloca(nMsgLen * sizeof(WCHAR)); + + make_unicode_string_static(*ppszMsg, szMsg, nMsgLen); + return (INT_PTR)mir_wstrdup(szMsg); + } + else + { // convert to ansi + char *szMsg = (char*)_alloca(nMsgLen); + + if (utf8_decode_static(*ppszMsg, szMsg, nMsgLen)) + return (INT_PTR)mir_strdup(szMsg); + } + + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// PS_UserIsTyping - sends a UTN notification + +int __cdecl CIcqProto::UserIsTyping( HANDLE hContact, int type ) +{ + if (hContact && icqOnline()) + { + if (CheckContactCapabilities(hContact, CAPF_TYPING)) + { + switch (type) { + case PROTOTYPE_SELFTYPING_ON: + sendTypingNotification(hContact, MTN_BEGUN); + return 0; + + case PROTOTYPE_SELFTYPING_OFF: + sendTypingNotification(hContact, MTN_FINISHED); + return 0; + } + } + } + + return 1; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// OnEvent - maintain protocol events + +int __cdecl CIcqProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) +{ + switch( eventType ) { + case EV_PROTO_ONLOAD: + return OnModulesLoaded(0, 0); + + case EV_PROTO_ONEXIT: + return OnPreShutdown(0, 0); + + case EV_PROTO_ONOPTIONS: + return OnOptionsInit(wParam, lParam); + + case EV_PROTO_ONERASE: + { + char szDbSetting[MAX_PATH]; + + null_snprintf(szDbSetting, sizeof(szDbSetting), "%sP2P", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); + null_snprintf(szDbSetting, sizeof(szDbSetting), "%sSrvGroups", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); + null_snprintf(szDbSetting, sizeof(szDbSetting), "%sGroups", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbSetting); + break; + } + + case EV_PROTO_ONCONTACTDELETED: + return ServListDbContactDeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return ServListDbSettingChanged(wParam, lParam); + } + return 1; +} diff --git a/protocols/IcqOscarJ/src/icq_proto.h b/protocols/IcqOscarJ/src/icq_proto.h new file mode 100644 index 0000000000..aa903689ad --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_proto.h @@ -0,0 +1,984 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, George Hazan +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Protocol Interface declarations +// +// ----------------------------------------------------------------------------- +#ifndef _ICQ_PROTO_H_ +#define _ICQ_PROTO_H_ + +#include "m_system_cpp.h" +#include "m_protoint.h" + +#define LISTSIZE 100 + +#define XSTATUS_COUNT 86 + +struct CIcqProto; +typedef void ( __cdecl CIcqProto::*IcqThreadFunc )( void* ); +typedef int ( __cdecl CIcqProto::*IcqEventFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIcqProto::*IcqServiceFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIcqProto::*IcqServiceFuncParam )( WPARAM, LPARAM, LPARAM ); + +// for InfoUpdate +struct userinfo +{ + DWORD dwUin; + HANDLE hContact; + time_t queued; +}; + +struct CIcqProto : public PROTO_INTERFACE, public MZeroedObject +{ + CIcqProto( const char*, const TCHAR* ); + ~CIcqProto(); + + //==================================================================================== + // PROTO_INTERFACE + //==================================================================================== + + virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); + virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); + + virtual int __cdecl Authorize( HANDLE hContact ); + virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); + virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); + + virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); + + virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); + virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); + virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); + virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); + + virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); + virtual HICON __cdecl GetIcon( int iconIndex ); + virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); + + virtual HANDLE __cdecl SearchBasic( const PROTOCHAR *id ); + virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR *email ); + virtual HANDLE __cdecl SearchByName(const PROTOCHAR *nick, const PROTOCHAR *firstName, const PROTOCHAR *lastName); + virtual HWND __cdecl SearchAdvanced( HWND owner ); + virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); + + virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); + virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); + + virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); + virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); + virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); + virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); + + virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); + virtual int __cdecl SetStatus( int iNewStatus ); + + virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); + virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); + virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); + virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); + + virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); + + virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); + + //====| Services |==================================================================== + INT_PTR __cdecl AddServerContact(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetInfoSetting(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl ChangeInfoEx(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetAvatarCaps(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetAvatarInfo(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetMyAvatar(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetMyAwayMsg(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetXStatus(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetXStatusEx(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetXStatusIcon(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GrantAuthorization(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl menuXStatus(WPARAM wParam,LPARAM lParam,LPARAM fParam); + INT_PTR __cdecl OpenWebProfile(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl RequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl RequestAuthorization(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl RequestXStatusDetails(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl RevokeAuthorization(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SendSms(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SendYouWereAdded(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SetMyAvatar(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SetNickName(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SetPassword(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SetXStatus(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl SetXStatusEx(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl ShowXStatusDetails(WPARAM wParam, LPARAM lParam); + + INT_PTR __cdecl OnCreateAccMgrUI(WPARAM, LPARAM); + + //====| Events |====================================================================== + void __cdecl OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + int __cdecl OnIdleChanged( WPARAM, LPARAM ); + int __cdecl OnModernOptInit( WPARAM, LPARAM ); + int __cdecl OnModulesLoaded( WPARAM, LPARAM ); + int __cdecl OnOptionsInit( WPARAM, LPARAM ); + int __cdecl OnPreShutdown( WPARAM, LPARAM ); + int __cdecl OnPreBuildContactMenu( WPARAM, LPARAM ); + int __cdecl OnMsgUserTyping( WPARAM, LPARAM ); + int __cdecl OnProcessSrmmIconClick( WPARAM, LPARAM ); + int __cdecl OnProcessSrmmEvent( WPARAM, LPARAM ); + int __cdecl OnReloadIcons( WPARAM, LPARAM ); + void __cdecl OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + void __cdecl OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + int __cdecl OnUserInfoInit( WPARAM, LPARAM ); + + int __cdecl CListMW_ExtraIconsRebuild( WPARAM, LPARAM ); + int __cdecl CListMW_ExtraIconsApply( WPARAM, LPARAM ); + int __cdecl OnPreBuildStatusMenu( WPARAM, LPARAM ); + + //====| Data |======================================================================== + IcqIconHandle m_hIconProtocol; + HANDLE m_hServerNetlibUser, m_hDirectNetlibUser; + HANDLE hxstatuschanged, hxstatusiconchanged; + + BYTE m_bGatewayMode; + BYTE m_bSecureLogin; + BYTE m_bSecureConnection; + BYTE m_bAimEnabled; + BYTE m_bUtfEnabled; + WORD m_wAnsiCodepage; + BYTE m_bDCMsgEnabled; + BYTE m_bTempVisListEnabled; + BYTE m_bSsiEnabled; + BYTE m_bSsiSimpleGroups; + BYTE m_bAvatarsEnabled; + BYTE m_bXStatusEnabled; + BYTE m_bMoodsEnabled; + + icq_critical_section *localSeqMutex; + icq_critical_section *connectionHandleMutex; + + int m_bIdleAllow; + DWORD m_dwLocalUIN; + BYTE m_bConnectionLost; + + char m_szPassword[PASSWORDMAXLEN]; + BYTE m_bRememberPwd; + + int cheekySearchId; + DWORD cheekySearchUin; + char* cheekySearchUid; + + /******************************************************************* + * Function declarations + *******************************************************************/ + + //----| capabilities.cpp |------------------------------------------------------------ + // Deletes all oscar capabilities for a given contact. + void ClearAllContactCapabilities(HANDLE hContact); + + // Deletes one or many oscar capabilities for a given contact. + void ClearContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); + + // Sets one or many oscar capabilities for a given contact. + void SetContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); + + // Returns true if the given contact supports the requested capabilites. + BOOL CheckContactCapabilities(HANDLE hContact, DWORD fdwCapabilities); + + // Scans a binary buffer for oscar capabilities and adds them to the contact. + void AddCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength); + + // Scans a binary buffer for oscar capabilities and sets them to the contact. + void SetCapabilitiesFromBuffer(HANDLE hContact, BYTE *pBuffer, int nLength, BOOL bReset); + + //----| chan_01login.cpp |------------------------------------------------------------ + void handleLoginChannel(BYTE *buf, WORD datalen, serverthread_info *info); + + //----| chan_02data.cpp |------------------------------------------------------------- + void handleDataChannel(BYTE *buf, WORD wLen, serverthread_info *info); + + void LogFamilyError(WORD wFamily, WORD wError); + + //----| chan_03error.cpp |------------------------------------------------------------ + void handleErrorChannel(unsigned char *buf, WORD datalen); + + //----| chan_04close.cpp |------------------------------------------------------------ + void handleCloseChannel(BYTE *buf, WORD datalen, serverthread_info *info); + void handleLoginReply(BYTE *buf, WORD datalen, serverthread_info *info); + void handleMigration(serverthread_info *info); + void handleSignonError(WORD wError); + + int connectNewServer(serverthread_info *info); + + //----| chan_05ping.cpp |------------------------------------------------------------- + void handlePingChannel(BYTE *buf, WORD wLen); + + void __cdecl KeepAliveThread(void *arg); + + void StartKeepAlive(serverthread_info *info); + void StopKeepAlive(serverthread_info *info); + + //----| cookies.cpp |----------------------------------------------------------------- + icq_critical_section *cookieMutex; // we want this in avatar thread, used as queue lock + LIST cookies; + WORD wCookieSeq; + + DWORD AllocateCookie(BYTE bType, WORD wIdent, HANDLE hContact, void *pvExtra); + void FreeCookie(DWORD dwCookie); + void FreeCookieByData(BYTE bType, void *pvExtra); + void ReleaseCookie(DWORD dwCookie); + DWORD GenerateCookie(WORD wIdent); + + int GetCookieType(DWORD dwCookie); + + int FindCookie(DWORD wCookie, HANDLE *phContact, void **ppvExtra); + int FindCookieByData(void *pvExtra, DWORD *pdwCookie, HANDLE *phContact); + int FindCookieByType(BYTE bType, DWORD *pdwCookie, HANDLE *phContact, void **ppvExtra); + int FindMessageCookie(DWORD dwMsgID1, DWORD dwMsgID2, DWORD *pdwCookie, HANDLE *phContact, cookie_message_data **ppvExtra); + + void InitMessageCookie(cookie_message_data *pCookie); + cookie_message_data* CreateMessageCookie(WORD bMsgType, BYTE bAckType); + cookie_message_data* CreateMessageCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin, int bUseSrvRelay); + + void RemoveExpiredCookies(void); + + //----| directpackets.cpp |----------------------------------------------------------- + void icq_sendDirectMsgAck(directconnect* dc, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, char* szCap); + DWORD icq_sendGetAwayMsgDirect(HANDLE hContact, int type); + void icq_sendAwayMsgReplyDirect(directconnect *dc, WORD wCookie, BYTE msgType, const char** szMsg); + void icq_sendFileAcceptDirect(HANDLE hContact, filetransfer *ft); + void icq_sendFileDenyDirect(HANDLE hContact, filetransfer *ft, const char *szReason); + int icq_sendFileSendDirectv7(filetransfer *ft, const char *pszFiles); + int icq_sendFileSendDirectv8(filetransfer *ft, const char *pszFiles); + DWORD icq_SendDirectMessage(HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap); + void icq_sendXtrazRequestDirect(HANDLE hContact, DWORD dwCookie, char* szBody, int nBodyLen, WORD wType); + void icq_sendXtrazResponseDirect(HANDLE hContact, WORD wCookie, char* szBody, int nBodyLen, WORD wType); + + //----| fam_01service.cpp |----------------------------------------------------------- + HANDLE m_hNotifyNameInfoEvent; + + void handleServiceFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); + char* buildUinList(int subtype, WORD wMaxLen, HANDLE *hContactResume); + void sendEntireListServ(WORD wFamily, WORD wSubtype, int listType); + void setUserInfo(void); + void handleServUINSettings(int nPort, serverthread_info *info); + + //----| fam_02location.cpp |---------------------------------------------------------- + void handleLocationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); + void handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie); + + //----| fam_03buddy.cpp |------------------------------------------------------------- + void handleBuddyFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); + void handleReplyBuddy(BYTE *buf, WORD wPackLen); + void handleUserOffline(BYTE *buf, WORD wPackLen); + void handleUserOnline(BYTE *buf, WORD wPackLen, serverthread_info *info); + void parseStatusNote(DWORD dwUin, char *szUid, HANDLE hContact, oscar_tlv_chain *pChain); + void handleNotifyRejected(BYTE *buf, WORD wPackLen); + + //----| fam_04message.cpp |----------------------------------------------------------- + icq_mode_messages m_modeMsgs; + icq_critical_section *m_modeMsgsMutex; + HANDLE m_modeMsgsEvent; + + void handleMsgFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader); + + void handleReplyICBM(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleRecvServMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleRecvServMsgType1(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); + void handleRecvServMsgType2(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); + void handleRecvServMsgType4(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef); + void handleRecvServMsgError(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleRecvMsgResponse(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleServerAck(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleStatusMsgReply(const char *szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char *szMsg, int nMsgFlags); + void handleTypingNotification(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleMissedMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleOffineMessagesReply(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef); + void handleRecvServMsgContacts(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand); + void handleRuntimeError(WORD wError); + + void parseServRelayData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType); + void parseServRelayPluginData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wVersion); + + HANDLE handleMessageAck(DWORD dwUin, char *szUID, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags, int nMsgFlags); + void handleMessageTypes(DWORD dwUin, char *szUID, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, int nMsgFlags, message_ack_params *pAckParams); + void sendMessageTypesAck(HANDLE hContact, int bUnicode, message_ack_params *pArgs); + void sendTypingNotification(HANDLE hContact, WORD wMTNCode); + + int unpackPluginTypeId(BYTE **pBuffer, WORD *pwLen, int *pTypeId, WORD *pFunctionId, BOOL bThruDC); + + char* convertMsgToUserSpecificUtf(HANDLE hContact, const char *szMsg); + + //----| fam_09bos.cpp |--------------------------------------------------------------- + void handleBosFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); + void handlePrivacyRightsReply(unsigned char *pBuffer, WORD wBufferLength); + void makeContactTemporaryVisible(HANDLE hContact); + + //----| fam_0alookup.cpp |------------------------------------------------------------ + void handleLookupFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); + + void handleLookupEmailReply(BYTE* buf, WORD wLen, DWORD dwCookie); + void ReleaseLookupCookie(DWORD dwCookie, cookie_search *pCookie); + + //----| fam_0bstatus.cpp |------------------------------------------------------------ + void handleStatusFam(unsigned char *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); + + //----| fam_13servclist.cpp |--------------------------------------------------------- + BOOL bIsSyncingCL; + + WORD m_wServerListLimits[0x20]; + WORD m_wServerListGroupMaxContacts; + WORD m_wServerListRecordNameMaxLength; + + void handleServCListFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info); + void handleServerCListRightsReply(BYTE *buf, WORD wLen); + void handleServerCListAck(cookie_servlist_action* sc, WORD wError); + void handleServerCListReply(BYTE *buf, WORD wLen, WORD wFlags, serverthread_info *info); + void handleServerCListItemAdd(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); + void handleServerCListItemUpdate(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); + void handleServerCListItemDelete(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); + void handleRecvAuthRequest(BYTE *buf, WORD wLen); + void handleRecvAuthResponse(BYTE *buf, WORD wLen); + void handleRecvAdded(BYTE *buf, WORD wLen); + + HANDLE HContactFromRecordName(const char *szRecordName, int *bAdded); + + void processCListReply(const char *szRecordName, WORD wGroupId, WORD wItemId, WORD wItemType, oscar_tlv_chain *pItemData); + + void icq_sendServerBeginOperation(int bImport); + void icq_sendServerEndOperation(); + void sendRosterAck(void); + + int getServerDataFromItemTLV(oscar_tlv_chain* pChain, unsigned char *buf); + DWORD updateServerGroupData(WORD wGroupId, void *groupData, int groupSize, DWORD dwOperationFlags); + void updateServAvatarHash(BYTE *pHash, int size); + void updateServVisibilityCode(BYTE bCode); + + //----| fam_15icqserver.cpp |--------------------------------------------------------- + void handleIcqExtensionsFam(BYTE *pBuffer, WORD wBufferLength, snac_header* pSnacHeader); + + void handleExtensionError(BYTE *buf, WORD wPackLen); + void handleExtensionServerInfo(BYTE *buf, WORD wPackLen, WORD wFlags); + void handleExtensionMetaResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags); + + int parseUserInfoRecord(HANDLE hContact, oscar_tlv *pData, UserInfoRecordItem pRecordDef[], int nRecordDef, int nMaxRecords); + + void handleDirectoryQueryResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, WORD wFlags); + void handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype); + + void parseDirectoryUserDetailsData(HANDLE hContact, oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType); + void parseDirectorySearchData(oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType); + + void parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode); + void parseUserInfoUpdateAck(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode); + + void ReleaseSearchCookie(DWORD dwCookie, cookie_search *pCookie); + + //----| fam_17signon.cpp |------------------------------------------------------------ + void handleAuthorizationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader, serverthread_info *info); + void handleAuthKeyResponse(BYTE *buf, WORD wPacketLen, serverthread_info *info); + + void sendClientAuth(const char *szKey, WORD wKeyLen, BOOL bSecure); + + //----| icq_avatars.cpp |------------------------------------------------------------- + icq_critical_section *m_avatarsMutex; + avatars_request *m_avatarsQueue; + + BOOL m_avatarsConnectionPending; + avatars_server_connection *m_avatarsConnection; + + int bAvatarsFolderInited; + HANDLE hAvatarsFolder; + + void requestAvatarConnection(); + void __cdecl AvatarThread(avatars_server_connection *pInfo); + + void handleAvatarOwnerHash(WORD wItemID, BYTE bFlags, BYTE *pData, BYTE nDataLen); + void handleAvatarContactHash(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *pHash, int nHashLen, WORD wOldStatus); + + void InitAvatars(); + avatars_request *ReleaseAvatarRequestInQueue(avatars_request *request); + + TCHAR* GetOwnAvatarFileName(); + void GetFullAvatarFileName(int dwUin, const char *szUid, int dwFormat, TCHAR *pszDest, int cbLen); + void GetAvatarFileName(int dwUin, const char *szUid, TCHAR *pszDest, int cbLen); + int IsAvatarChanged(HANDLE hContact, const BYTE *pHash, int nHashLen); + + int GetAvatarData(HANDLE hContact, DWORD dwUin, const char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file); + int SetAvatarData(HANDLE hContact, WORD wRef, const BYTE *data, unsigned int datalen); + + void StartAvatarThread(HANDLE hConn, char* cookie, WORD cookieLen); + void StopAvatarThread(); + + //----| icq_clients.cpp |------------------------------------------------------------- + const char* detectUserClient(HANDLE hContact, int nIsICQ, WORD wUserClass, DWORD dwOnlineSince, const char *szCurrentClient, WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, BYTE bDirectFlag, DWORD dwDirectCookie, DWORD dwWebPort, BYTE *caps, WORD wLen, BYTE *bClientId, char *szClientBuf); + + //----| icq_db.cpp |------------------------------------------------------------------ + HANDLE AddEvent(HANDLE hContact, WORD wType, DWORD dwTime, DWORD flags, DWORD cbBlob, PBYTE pBlob); + void CreateResidentSetting(const char* szSetting); + HANDLE FindFirstContact(); + HANDLE FindNextContact(HANDLE hContact); + int IsICQContact(HANDLE hContact); + + int getSetting(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); + BYTE getSettingByte(HANDLE hContact, const char *szSetting, BYTE byDef); + WORD getSettingWord(HANDLE hContact, const char *szSetting, WORD wDef); + DWORD getSettingDword(HANDLE hContact, const char *szSetting, DWORD dwDef); + double getSettingDouble(HANDLE hContact, const char *szSetting, double dDef); + int getSettingString(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); + int getSettingStringW(HANDLE hContact, const char *szSetting, DBVARIANT *dbv); + int getSettingStringStatic(HANDLE hContact, const char *szSetting, char *dest, int dest_len); + char* getSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, char *szDef); + char* getSettingStringUtf(HANDLE hContact, const char *szSetting, char *szDef); + int getContactUid(HANDLE hContact, DWORD *pdwUin, uid_str *ppszUid); + DWORD getContactUin(HANDLE hContact); + WORD getContactStatus(HANDLE hContact); + char* getContactCListGroup(HANDLE hContact); + + int deleteSetting(HANDLE hContact, const char *szSetting); + + int setSettingByte(HANDLE hContact, const char *szSetting, BYTE byValue); + int setSettingWord(HANDLE hContact, const char *szSetting, WORD wValue); + int setSettingDword(HANDLE hContact, const char *szSetting, DWORD dwValue); + int setSettingDouble(HANDLE hContact, const char *szSetting, double dValue); + int setSettingString(HANDLE hContact, const char *szSetting, const char *szValue); + int setSettingStringW(HANDLE hContact, const char *szSetting, const WCHAR *wszValue); + int setSettingStringUtf(HANDLE hContact, const char *szModule, const char *szSetting, const char *szValue); + int setSettingStringUtf(HANDLE hContact, const char *szSetting, const char *szValue); + int setSettingBlob(HANDLE hContact, const char *szSetting, const BYTE *pValue, const int cbValue); + int setContactHidden(HANDLE hContact, BYTE bHidden); + void setStatusMsgVar(HANDLE hContact, char* szStatusMsg, bool isAnsi); + + //----| icq_direct.cpp |-------------------------------------------------------------- + icq_critical_section *directConnListMutex; + LIST directConns; + + icq_critical_section *expectedFileRecvMutex; + LIST expectedFileRecvs; + + void __cdecl icq_directThread(struct directthreadstartinfo* dtsi); + + void handleDirectPacket(directconnect* dc, PBYTE buf, WORD wLen); + void sendPeerInit_v78(directconnect* dc); + void sendPeerInitAck(directconnect* dc); + void sendPeerMsgInit(directconnect* dc, DWORD dwSeq); + void sendPeerFileInit(directconnect* dc); + int sendDirectPacket(directconnect* dc, icq_packet* pkt); + + void CloseContactDirectConns(HANDLE hContact); + directconnect* FindFileTransferDC(filetransfer* ft); + filetransfer* FindExpectedFileRecv(DWORD dwUin, DWORD dwTotalSize); + BOOL IsDirectConnectionOpen(HANDLE hContact, int type, int bPassive); + void OpenDirectConnection(HANDLE hContact, int type, void* pvExtra); + void CloseDirectConnection(directconnect *dc); + int SendDirectMessage(HANDLE hContact, icq_packet *pkt); + + //----| icq_directmsg.cpp |----------------------------------------------------------- + void handleDirectMessage(directconnect* dc, PBYTE buf, WORD wLen); + void handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText); + + //----| icq_filerequests.cpp |-------------------------------------------------------- + filetransfer* CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion); + + void handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText); + void handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC); + void handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText); + + void icq_CancelFileTransfer(HANDLE hContact, filetransfer* ft); + + //----| icq_filetransfer.cpp |-------------------------------------------------------- + void icq_AcceptFileTransfer(HANDLE hContact, filetransfer *ft); + void icq_sendFileResume(filetransfer *ft, int action, const char *szFilename); + void icq_InitFileSend(filetransfer *ft); + + void handleFileTransferPacket(directconnect *dc, PBYTE buf, WORD wLen); + void handleFileTransferIdle(directconnect *dc); + + //----| icq_infoupdate.cpp |---------------------------------------------------------- + icq_critical_section *infoUpdateMutex; + HANDLE hInfoQueueEvent; + int nInfoUserCount; + int bInfoPendingUsers; + BOOL bInfoUpdateEnabled; + BOOL bInfoUpdateRunning; + HANDLE hInfoThread; + DWORD dwInfoActiveRequest; + userinfo m_infoUpdateList[LISTSIZE]; + + void __cdecl InfoUpdateThread(void*); + + void icq_InitInfoUpdate(void); // Queues all outdated users + BOOL icq_QueueUser(HANDLE hContact); // Queue one UIN to the list for updating + void icq_DequeueUser(DWORD dwUin); // Remove one UIN from the list + void icq_RescanInfoUpdate(); // Add all outdated contacts to the list + void icq_InfoUpdateCleanup(void); // Clean up on exit + void icq_EnableUserLookup(BOOL bEnable); // Enable/disable user info lookups + + //----| log.cpp |----------------------------------------------------------------- + BOOL bErrorBoxVisible; + + void __cdecl icq_LogMessageThread(void* arg); + + void icq_LogMessage(int level, const char *szMsg); + void icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg); //szMsg is optional + void icq_LogFatalParam(const char *szMsg, WORD wError); + + //----| icq_packet.cpp |-------------------------------------------------------------- + void ppackLETLVLNTSfromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); + void ppackLETLVWordLNTSfromDB(PBYTE *buf, int *buflen, WORD w, const char *szSetting, WORD wType); + void ppackLETLVLNTSBytefromDB(PBYTE *buf, int *buflen, const char *szSetting, BYTE b, WORD wType); + + void ppackTLVStringFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); + void ppackTLVStringUtfFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wType); + void ppackTLVDateFromDB(PBYTE *buf, int *buflen, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, WORD wType); + + int ppackTLVWordStringItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID); + int ppackTLVWordStringUtfItemFromDB(PBYTE *buf, int *buflen, const char *szSetting, WORD wTypeID, WORD wTypeData, WORD wID); + + BOOL unpackUID(BYTE **ppBuf, WORD *pwLen, DWORD *pdwUIN, uid_str *ppszUID); + + //----| icq_popups.cpp |-------------------------------------------------------------- + int ShowPopUpMsg(HANDLE hContact, const char *szTitle, const char *szMsg, BYTE bType); + + //----| icq_proto.cpp |-------------------------------------------------------------- + void __cdecl CheekySearchThread( void* ); + + void __cdecl GetAwayMsgThread( void *pStatusData ); + + char* PrepareStatusNote(int nStatus); + + //----| icq_rates.cpp |--------------------------------------------------------------- + icq_critical_section *m_ratesMutex; + rates *m_rates; + + rates_queue *m_ratesQueue_Request; // rate queue for xtraz requests + rates_queue *m_ratesQueue_Response; // rate queue for msg responses + + int handleRateItem(rates_queue_item *item, int nQueueType = RQT_DEFAULT, int nMinDelay = 0, BOOL bAllowDelay = TRUE); + + void __cdecl rateDelayThread(struct rate_delay_args *pArgs); + + //----| icq_server.cpp |-------------------------------------------------------------- + HANDLE hServerConn; + WORD wListenPort; + WORD wLocalSequence; + UINT serverThreadId; + HANDLE serverThreadHandle; + + __inline bool icqOnline() const + { return (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING); + } + + void __cdecl SendPacketAsyncThread(icq_packet* pArgs); + void __cdecl ServerThread(serverthread_start_info *infoParam); + + void icq_serverDisconnect(BOOL bBlock); + void icq_login(const char* szPassword); + + int handleServerPackets(BYTE *buf, int len, serverthread_info *info); + void sendServPacket(icq_packet *pPacket); + void sendServPacketAsync(icq_packet *pPacket); + + int IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel); + + //----| icq_servlist.cpp |------------------------------------------------------------ + HANDLE hHookSettingChanged; + HANDLE hHookContactDeleted; + HANDLE hHookCListGroupChange; + icq_critical_section *servlistMutex; + + DWORD* pdwServerIDList; + int nServerIDListCount; + int nServerIDListSize; + + // server-list update board + icq_critical_section *servlistQueueMutex; + int servlistQueueCount; + int servlistQueueSize; + ssiqueueditems **servlistQueueList; + int servlistQueueState; + HANDLE servlistQueueThreadHandle; + int servlistEditCount; + + void servlistBeginOperation(int operationCount, int bImport); + void servlistEndOperation(int operationCount); + + void __cdecl servlistQueueThread(void* queueState); + + void servlistQueueAddGroupItem(servlistgroupitem* pGroupItem, int dwTimeout); + int servlistHandlePrimitives(DWORD dwOperation); + void servlistProcessLogin(); + + void servlistPostPacket(icq_packet* packet, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout); + void servlistPostPacketDouble(icq_packet* packet1, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout, icq_packet* packet2, WORD wAction2); + + // server-list pending queue + int servlistPendingCount; + int servlistPendingSize; + servlistpendingitem** servlistPendingList; + + int servlistPendingFindItem(int nType, HANDLE hContact, const char *pszGroup); + void servlistPendingAddItem(servlistpendingitem* pItem); + servlistpendingitem* servlistPendingRemoveItem(int nType, HANDLE hContact, const char *pszGroup); + + void servlistPendingAddContactOperation(HANDLE hContact, LPARAM param, PENDING_CONTACT_CALLBACK callback, DWORD flags); + void servlistPendingAddGroupOperation(const char *pszGroup, LPARAM param, PENDING_GROUP_CALLBACK callback, DWORD flags); + int servlistPendingAddContact(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM param, PENDING_CONTACT_CALLBACK callback, int bDoInline, LPARAM operationParam = 0, PENDING_CONTACT_CALLBACK operationCallback = NULL); + int servlistPendingAddGroup(const char *pszGroup, WORD wGroupID, LPARAM param, PENDING_GROUP_CALLBACK callback, int bDoInline, LPARAM operationParam = 0, PENDING_GROUP_CALLBACK operationCallback = NULL); + void servlistPendingRemoveContact(HANDLE hContact, WORD wContactID, WORD wGroupID, int nResult); + void servlistPendingRemoveGroup(const char *pszGroup, WORD wGroupID, int nResult); + void servlistPendingFlushOperations(); + + // server-list support functions + int nJustAddedCount; + int nJustAddedSize; + HANDLE* pdwJustAddedList; + + void AddJustAddedContact(HANDLE hContact); + BOOL IsContactJustAdded(HANDLE hContact); + void FlushJustAddedContacts(); + + WORD GenerateServerID(int bGroupType, int bFlags, int wCount = 0); + void ReserveServerID(WORD wID, int bGroupType, int bFlags); + void FreeServerID(WORD wID, int bGroupType); + BOOL CheckServerID(WORD wID, unsigned int wCount); + void FlushServerIDs(); + void LoadServerIDs(); + void StoreServerIDs(); + + void* collectGroups(int *count); + void* collectBuddyGroup(WORD wGroupID, int *count); + char* getServListGroupName(WORD wGroupID); + void setServListGroupName(WORD wGroupID, const char *szGroupName); + WORD getServListGroupLinkID(const char *szPath); + void setServListGroupLinkID(const char *szPath, WORD wGroupID); + int IsServerGroupsDefined(); + char* getServListGroupCListPath(WORD wGroupId); + char* getServListUniqueGroupName(const char *szGroupName, int bAlloced); + + int __cdecl servlistCreateGroup_gotParentGroup(const char *szGroup, WORD wGroupID, LPARAM param, int nResult); + int __cdecl servlistCreateGroup_Ready(const char *szGroup, WORD groupID, LPARAM param, int nResult); + void servlistCreateGroup(const char *szGroupPath, LPARAM param, PENDING_GROUP_CALLBACK callback); + + int __cdecl servlistAddContact_gotGroup(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult); + int __cdecl servlistAddContact_Ready(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM lParam, int nResult); + void servlistAddContact(HANDLE hContact, const char *pszGroup); + + int __cdecl servlistRemoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); + void servlistRemoveContact(HANDLE hContact); + + int __cdecl servlistMoveContact_gotTargetGroup(const char *szGroup, WORD wNewGroupID, LPARAM lParam, int nResult); + int __cdecl servlistMoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); + void servlistMoveContact(HANDLE hContact, const char *pszNewGroup); + + int __cdecl servlistUpdateContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult); + void servlistUpdateContact(HANDLE hContact); + + int __cdecl servlistRenameGroup_Ready(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult); + void servlistRenameGroup(char *szGroup, WORD wGroupId, char *szNewGroup); + + int __cdecl servlistRemoveGroup_Ready(const char *szGroup, WORD groupID, LPARAM lParam, int nResult); + void servlistRemoveGroup(const char *szGroup, WORD wGroupId); + + void removeGroupPathLinks(WORD wGroupID); + int getServListGroupLevel(WORD wGroupId); + + void resetServContactAuthState(HANDLE hContact, DWORD dwUin); + + void FlushSrvGroupsCache(); + int getCListGroupHandle(const char *szGroup); + int getCListGroupExists(const char *szGroup); + int moveContactToCListGroup(HANDLE hContact, const char *szGroup); /// TODO: this should be DB function + + DWORD icq_sendServerItem(DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wItemId, const char *szName, BYTE *pTLVs, int nTlvLength, WORD wItemType, DWORD dwOperation, DWORD dwTimeout, void **doubleObject); + DWORD icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId, DWORD dwOperation, DWORD dwTimeout, void **doubleObject); + DWORD icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType, DWORD dwOperation, DWORD dwTimeout); + DWORD icq_sendServerGroup(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent, DWORD dwOperationFlags); + + DWORD icq_modifyServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wAction, DWORD dwOperation, WORD wItemId, WORD wType); + DWORD icq_removeServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType); + DWORD icq_addServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType); + + int __cdecl ServListDbSettingChanged(WPARAM wParam, LPARAM lParam); + int __cdecl ServListDbContactDeleted(WPARAM wParam, LPARAM lParam); + int __cdecl ServListCListGroupChange(WPARAM wParam, LPARAM lParam); + + //----| stdpackets.cpp |---------------------------------------------------------- + void icq_sendCloseConnection(); + + void icq_requestnewfamily(WORD wFamily, void (CIcqProto::*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen)); + + void icq_setidle(int bAllow); + void icq_setstatus(WORD wStatus, const char *szStatusNote = NULL); + DWORD icq_sendGetInfoServ(HANDLE, DWORD, int); + DWORD icq_sendGetAimProfileServ(HANDLE hContact, char *szUid); + DWORD icq_sendGetAwayMsgServ(HANDLE, DWORD, int, WORD); + DWORD icq_sendGetAwayMsgServExt(HANDLE hContact, DWORD dwUin, char *szUID, int type, WORD wVersion); + DWORD icq_sendGetAimAwayMsgServ(HANDLE hContact, char *szUID, int type); + void icq_sendSetAimAwayMsgServ(const char *szMsg); + + void icq_sendFileSendServv7(filetransfer* ft, const char *szFiles); + void icq_sendFileSendServv8(filetransfer* ft, const char *szFiles, int nAckType); + + void icq_sendFileAcceptServ(DWORD dwUin, filetransfer *ft, int nAckType); + void icq_sendFileAcceptServv7(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType); + void icq_sendFileAcceptServv8(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType); + + void icq_sendFileDenyServ(DWORD dwUin, filetransfer *ft, const char *szReason, int nAckType); + + DWORD icq_sendAdvancedSearchServ(BYTE *fieldsBuffer,int bufferLen); + DWORD icq_changeUserPasswordServ(const char *szPassword); + DWORD icq_changeUserDirectoryInfoServ(const BYTE *pData, WORD wDataLen, BYTE bRequestType); + void icq_sendGenericContact(DWORD dwUin, const char *szUid, WORD wFamily, WORD wSubType); + void icq_sendNewContact(DWORD dwUin, const char *szUid); + void icq_sendRemoveContact(DWORD dwUin, const char *szUid); + void icq_sendChangeVisInvis(HANDLE hContact, DWORD dwUin, char* szUID, int list, int add); + void icq_sendEntireVisInvisList(int); + void icq_sendAwayMsgReplyServ(DWORD, DWORD, DWORD, WORD, WORD, BYTE, char **); + void icq_sendAwayMsgReplyServExt(DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char **szMsg); + + DWORD icq_sendSMSServ(const char *szPhoneNumber, const char *szMsg); + void icq_sendMessageCapsServ(DWORD dwUin); + void icq_sendRevokeAuthServ(DWORD dwUin, char *szUid); + void icq_sendGrantAuthServ(DWORD dwUin, const char *szUid, const char *szMsg); + void icq_sendAuthReqServ(DWORD dwUin, char* szUid, const char *szMsg); + void icq_sendAuthResponseServ(DWORD dwUin, char* szUid,int auth,const TCHAR *szReason); + void icq_sendYouWereAddedServ(DWORD,DWORD); + + DWORD sendDirectorySearchPacket(const BYTE *pSearchData, WORD wDataLen, WORD wPage, BOOL bOnlineUsersOnly); + DWORD sendTLVSearchPacket(BYTE bType, char* pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly); + void sendOwnerInfoRequest(void); + DWORD sendUserInfoMultiRequest(BYTE *pRequestData, WORD wDataLen, int nItems); + + DWORD icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, cookie_message_data *pCookieData); + DWORD icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, WCHAR *pszText, cookie_message_data *pCookieData); // UTF-16 + DWORD icq_SendChannel2Message(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLength, WORD wPriority, cookie_message_data *pCookieData, char *szCap); + DWORD icq_SendChannel2Contacts(DWORD dwUin, char *szUid, HANDLE hContact, const char *pData, WORD wDataLen, const char *pNames, WORD wNamesLen, cookie_message_data *pCookieData); + DWORD icq_SendChannel4Message(DWORD dwUin, HANDLE hContact, BYTE bMsgType, WORD wMsgLen, const char *szMsg, cookie_message_data *pCookieData); + + void icq_sendAdvancedMsgAck(DWORD, DWORD, DWORD, WORD, BYTE, BYTE); + void icq_sendContactsAck(DWORD dwUin, char *szUid, DWORD dwMsgID1, DWORD dwMsgID2); + + void icq_sendReverseReq(directconnect *dc, DWORD dwCookie, cookie_message_data *pCookie); + void icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie); + + void icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, cookie_message_data *pCookieData); + void icq_sendXtrazResponseServ(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szBody, int nBodyLen, int nType); + + DWORD SearchByUin(DWORD dwUin); + DWORD SearchByNames(const char *pszNick, const char *pszFirstName, const char *pszLastName, WORD wPage); + DWORD SearchByMail(const char *pszEmail); + + DWORD icq_searchAimByEmail(const char* pszEmail, DWORD dwSearchId); + + void oft_sendFileRequest(DWORD dwUin, char *szUid, oscar_filetransfer *ft, const char *pszFiles, DWORD dwLocalInternalIP); + void oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer *ft); + void oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer *ft); + void oft_sendFileCancel(DWORD dwUin, char *szUid, oscar_filetransfer *ft); + void oft_sendFileResponse(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResponse); + void oft_sendFileRedirect(DWORD dwUin, char *szUid, oscar_filetransfer *ft, DWORD dwIP, WORD wPort, int bProxy); + + //---- | icq_svcs.cpp |---------------------------------------------------------------- + HANDLE AddToListByUIN(DWORD dwUin, DWORD dwFlags); + HANDLE AddToListByUID(const char *szUID, DWORD dwFlags); + + void ICQAddRecvEvent(HANDLE hContact, WORD wType, PROTORECVEVENT* pre, DWORD cbBlob, PBYTE pBlob, DWORD flags); + INT_PTR __cdecl IcqAddCapability(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl IcqCheckCapability(WPARAM wParam, LPARAM lParam); + + std::list CustomCapList; + + //----| icq_uploadui.cpp |------------------------------------------------------------ + void ShowUploadContactsDialog(void); + + //----| icq_xstatus.cpp |------------------------------------------------------------- + int m_bHideXStatusUI; + int m_bHideXStatusMenu; + int bXStatusExtraIconsReady; + HANDLE hHookExtraIconsRebuild; + HANDLE hHookStatusBuild; + HANDLE hHookExtraIconsApply; + HANDLE hXStatusExtraIcons[XSTATUS_COUNT]; + IcqIconHandle hXStatusIcons[XSTATUS_COUNT]; + HANDLE hXStatusItems[XSTATUS_COUNT + 1]; + + int hXStatusCListIcons[XSTATUS_COUNT]; + BOOL bXStatusCListIconsValid[XSTATUS_COUNT]; + + void InitXStatusItems(BOOL bAllowStatus); + BYTE getContactXStatus(HANDLE hContact); + DWORD sendXStatusDetailsRequest(HANDLE hContact, int bForced); + DWORD requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay); + HICON getXStatusIcon(int bStatus, UINT flags); + void releaseXStatusIcon(int bStatus, UINT flags); + void setXStatusEx(BYTE bXStatus, BYTE bQuiet); + void setContactExtraIcon(HANDLE hContact, int xstatus); + void handleXStatusCaps(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *caps, int capsize, char *moods, int moodsize); + void updateServerCustomStatus(int fullUpdate); + + void InitXStatusIcons(); + void UninitXStatusIcons(); + + //----| icq_xtraz.cpp |--------------------------------------------------------------- + void handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); + void handleXtrazNotifyResponse(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szMsg, int nMsgLen); + + void handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); + void handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC); + + DWORD SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced); + void SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC); + + //----| init.cpp |-------------------------------------------------------------------- + void UpdateGlobalSettings(); + + //----| loginpassword.cpp |----------------------------------------------------------- + void RequestPassword(); + + //----| oscar_filetransfer.cpp |------------------------------------------------------ + icq_critical_section *oftMutex; + int fileTransferCount; + basic_filetransfer** fileTransferList; + + oscar_filetransfer* CreateOscarTransfer(); + filetransfer *CreateIcqFileTransfer(); + void ReleaseFileTransfer(void *ft); + void SafeReleaseFileTransfer(void **ft); + oscar_filetransfer* FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2); + + oscar_listener* CreateOscarListener(oscar_filetransfer *ft, NETLIBNEWCONNECTIONPROC_V2 handler); + void ReleaseOscarListener(oscar_listener **pListener); + + void OpenOscarConnection(HANDLE hContact, oscar_filetransfer *ft, int type); + void CloseOscarConnection(oscar_connection *oc); + int CreateOscarProxyConnection(oscar_connection *oc); + + int getFileTransferIndex(void *ft); + int IsValidFileTransfer(void *ft); + int IsValidOscarTransfer(void *ft); + + void handleRecvServMsgOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand); + void handleRecvServResponseOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, void* ft); + + HANDLE oftInitTransfer(HANDLE hContact, DWORD dwUin, char *szUid, const TCHAR **pszFiles, const TCHAR *szDescription); + HANDLE oftFileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR *szPath); + DWORD oftFileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR *szReason); + DWORD oftFileCancel(HANDLE hContact, HANDLE hTransfer); + void oftFileResume(oscar_filetransfer *ft, int action, const TCHAR *szFilename); + + void sendOscarPacket(oscar_connection *oc, icq_packet *packet); + void handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen); + void sendOFT2FramePacket(oscar_connection *oc, WORD datatype); + + void proxy_sendInitTunnel(oscar_connection *oc); + void proxy_sendJoinTunnel(oscar_connection *oc, WORD wPort); + + //----| stdpackets.cpp |-------------------------------------------------------------- + void __cdecl oft_connectionThread(struct oscarthreadstartinfo *otsi); + + int oft_handlePackets(oscar_connection *oc, BYTE *buf, int len); + int oft_handleFileData(oscar_connection *oc, BYTE *buf, int len); + int oft_handleProxyData(oscar_connection *oc, BYTE *buf, int len); + void oft_sendFileData(oscar_connection *oc); + void oft_sendPeerInit(oscar_connection *oc); + void oft_sendFileReply(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResult); + + //----| upload.cpp |------------------------------------------------------------------ + int StringToListItemId(const char *szSetting,int def); + + //----| utilities.cpp |--------------------------------------------------------------- + int BroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam); + char* ConvertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg); + + char* GetUserStoredPassword(char *szBuffer, int cbSize); + char* GetUserPassword(BOOL bAlways); + WORD GetMyStatusFlags(); + + DWORD ReportGenericSendError(HANDLE hContact, int nType, const char* szErrorMsg); + void SetCurrentStatus(int nStatus); + + void ForkThread( IcqThreadFunc pFunc, void* arg ); + HANDLE ForkThreadEx( IcqThreadFunc pFunc, void* arg, UINT* threadID = NULL ); + + void __cdecl ProtocolAckThread(icq_ack_args* pArguments); + void SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage); + + HANDLE CreateProtoEvent(const char* szEvent); + void CreateProtoService(const char* szService, IcqServiceFunc serviceProc); + void CreateProtoServiceParam(const char* szService, IcqServiceFuncParam serviceProc, LPARAM lParam); + HANDLE HookProtoEvent(const char* szEvent, IcqEventFunc pFunc); + + int NetLog_Server(const char *fmt,...); + int NetLog_Direct(const char *fmt,...); + int NetLog_Uni(BOOL bDC, const char *fmt,...); + + icq_critical_section *contactsCacheMutex; + LIST contactsCache; + + void AddToContactsCache(HANDLE hContact, DWORD dwUin, const char *szUid); + void DeleteFromContactsCache(HANDLE hContact); + void InitContactsCache(); + void UninitContactsCache(); + + void AddToSpammerList(DWORD dwUIN); + BOOL IsOnSpammerList(DWORD dwUIN); + + HANDLE NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP); + + HANDLE HandleFromCacheByUid(DWORD dwUin, const char *szUid); + HANDLE HContactFromUIN(DWORD dwUin, int *Added); + HANDLE HContactFromUID(DWORD dwUin, const char *szUid, int *Added); + HANDLE HContactFromAuthEvent(HANDLE hEvent); + + void ResetSettingsOnListReload(); + void ResetSettingsOnConnect(); + void ResetSettingsOnLoad(); + + int IsMetaInfoChanged(HANDLE hContact); + + char *setStatusNoteText, *setStatusMoodData; + void __cdecl SetStatusNoteThread(void *pArguments); + int SetStatusNote(const char *szStatusNote, DWORD dwDelay, int bForced); + int SetStatusMood(const char *szMoodData, DWORD dwDelay); + + BOOL writeDbInfoSettingString(HANDLE hContact, const char* szSetting, char** buf, WORD* pwLength); + BOOL writeDbInfoSettingWord(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength); + BOOL writeDbInfoSettingWordWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength); + BOOL writeDbInfoSettingByte(HANDLE hContact, const char *pszSetting, char **buf, WORD* pwLength); + BOOL writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength); + + void writeDbInfoSettingTLVStringUtf(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVString(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVWord(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVByte(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVDouble(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVDate(HANDLE hContact, const char *szSettingYear, const char *szSettingMonth, const char *szSettingDay, oscar_tlv_chain *chain, WORD wTlv); + void writeDbInfoSettingTLVBlob(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv); + + char** MirandaStatusToAwayMsg(int nStatus); + + BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType); +}; + +#endif diff --git a/protocols/IcqOscarJ/src/icq_rates.cpp b/protocols/IcqOscarJ/src/icq_rates.cpp new file mode 100644 index 0000000000..e7513ec148 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_rates.cpp @@ -0,0 +1,529 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Rate Management stuff +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +// +// Rate Level 1 Management +///////////////////////////// + +rates::rates(CIcqProto *ppro, BYTE *pBuffer, WORD wLen) +{ + nGroups = 0; + memset(&groups, 0, MAX_RATES_GROUP_COUNT * sizeof(rates_group)); + this->ppro = ppro; + + // Parse Rate Data Block + WORD wCount; + unpackWord(&pBuffer, &wCount); + wLen -= 2; + + if (wCount > MAX_RATES_GROUP_COUNT) + { // just sanity check + ppro->NetLog_Server("Rates: Error: Data packet contains too many rate groups!"); + wCount = MAX_RATES_GROUP_COUNT; + } + + nGroups = wCount; + // Parse Group details + int i; + for (i=0; i= 35) + { + pBuffer += 2; // Group ID + unpackDWord(&pBuffer, &pGroup->dwWindowSize); + unpackDWord(&pBuffer, &pGroup->dwClearLevel); + unpackDWord(&pBuffer, &pGroup->dwAlertLevel); + unpackDWord(&pBuffer, &pGroup->dwLimitLevel); + pBuffer += 8; + unpackDWord(&pBuffer, &pGroup->dwMaxLevel); + pBuffer += 5; + wLen -= 35; + } + else + { // packet broken, put some basic defaults + pGroup->dwWindowSize = 10; + pGroup->dwMaxLevel = 5000; + } + pGroup->rCurrentLevel = pGroup->dwMaxLevel; + } + // Parse Group associated pairs + for (i=0; inPairs = wNum; + pGroup->pPairs = (WORD*)SAFE_MALLOC(wNum*4); + for (int n=0; npPairs[n] = wItem; + } +#ifdef _DEBUG + ppro->NetLog_Server("Rates: %d# %d pairs.", i+1, wNum); +#endif + wLen -= wNum*4; + } +} + + +rates::~rates() +{ + for (int i = 0; i < nGroups; i++) + SAFE_FREE((void**)&groups[i].pPairs); + + nGroups = 0; +} + + +WORD rates::getGroupFromSNAC(WORD wFamily, WORD wCommand) +{ + if (this) + { + for (int i = 0; i < nGroups; i++) + { + rates_group* pGroup = &groups[i]; + + for (int j = 0; j < 2 * pGroup->nPairs; j += 2) + { + if (pGroup->pPairs[j] == wFamily && pGroup->pPairs[j + 1] == wCommand) + { // we found the group + return (WORD)(i + 1); + } + } + } + _ASSERTE(0); + } + + return 0; // Failure +} + + +WORD rates::getGroupFromPacket(icq_packet *pPacket) +{ + if (this) + { + if (pPacket->nChannel == ICQ_DATA_CHAN && pPacket->wLen >= 0x10) + { + WORD wFamily, wCommand; + BYTE *pBuf = pPacket->pData + 6; + + unpackWord(&pBuf, &wFamily); + unpackWord(&pBuf, &wCommand); + + return getGroupFromSNAC(wFamily, wCommand); + } + } + return 0; +} + + +rates_group* rates::getGroup(WORD wGroup) +{ + if (this && wGroup && wGroup <= nGroups) + return &groups[wGroup - 1]; + + return NULL; +} + + +int rates::getNextRateLevel(WORD wGroup) +{ + rates_group *pGroup = getGroup(wGroup); + + if (pGroup) + { + int nLevel = pGroup->rCurrentLevel*(pGroup->dwWindowSize-1)/pGroup->dwWindowSize + (GetTickCount() - pGroup->tCurrentLevel)/pGroup->dwWindowSize; + + return nLevel < (int)pGroup->dwMaxLevel ? nLevel : pGroup->dwMaxLevel; + } + return -1; // Failure +} + + +int rates::getDelayToLimitLevel(WORD wGroup, int nLevel) +{ + rates_group *pGroup = getGroup(wGroup); + + if (pGroup) + return (getLimitLevel(wGroup, nLevel) - pGroup->rCurrentLevel)*pGroup->dwWindowSize + pGroup->rCurrentLevel; + + return 0; // Failure +} + + +void rates::packetSent(icq_packet *pPacket) +{ + if (this) + { + WORD wGroup = getGroupFromPacket(pPacket); + + if (wGroup) + updateLevel(wGroup, getNextRateLevel(wGroup)); + } +} + + +void rates::updateLevel(WORD wGroup, int nLevel) +{ + rates_group *pGroup = getGroup(wGroup); + + if (pGroup) + { + pGroup->rCurrentLevel = nLevel; + pGroup->tCurrentLevel = GetTickCount(); +#ifdef _DEBUG + ppro->NetLog_Server("Rates: New level %d for #%d", nLevel, wGroup); +#endif + } +} + + +int rates::getLimitLevel(WORD wGroup, int nLevel) +{ + rates_group *pGroup = getGroup(wGroup); + + if (pGroup) + { + switch(nLevel) + { + case RML_CLEAR: + return pGroup->dwClearLevel; + + case RML_ALERT: + return pGroup->dwAlertLevel; + + case RML_LIMIT: + return pGroup->dwLimitLevel; + + case RML_IDLE_10: + return pGroup->dwClearLevel + ((pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); + + case RML_IDLE_30: + return pGroup->dwClearLevel + (3*(pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); + + case RML_IDLE_50: + return pGroup->dwClearLevel + ((pGroup->dwMaxLevel - pGroup->dwClearLevel)/2); + + case RML_IDLE_70: + return pGroup->dwClearLevel + (7*(pGroup->dwMaxLevel - pGroup->dwClearLevel)/10); + } + } + return 9999; // some high number - without rates we allow anything +} + + +void rates::initAckPacket(icq_packet *pPacket) +{ + serverPacketInit(pPacket, 10 + nGroups * (int)sizeof(WORD)); + packFNACHeader(pPacket, ICQ_SERVICE_FAMILY, ICQ_CLIENT_RATE_ACK); + for (WORD wGroup = 1; wGroup <= nGroups; wGroup++) + packWord(pPacket, wGroup); +} + + + +// +// Rate Level 2 Management +///////////////////////////// + + +rates_queue_item::rates_queue_item(CIcqProto *ppro, WORD wGroup) : bCreated(FALSE), dwUin(0), szUid(NULL) +{ + this->ppro = ppro; + this->wGroup = wGroup; +} + +rates_queue_item::~rates_queue_item() +{ + if (bCreated) + { + SAFE_FREE(&szUid); + bCreated = FALSE; + } +} + + +BOOL rates_queue_item::isEqual(rates_queue_item *pItem) +{ // the same event (equal address of _vftable) for the same contact + return (pItem->hContact == this->hContact) && (*(void**)pItem == *(void**)this); +} + + +rates_queue_item* rates_queue_item::copyItem(rates_queue_item *pDest) +{ + if (!pDest) + pDest = new rates_queue_item(ppro, wGroup); + + pDest->hContact = hContact; + pDest->dwUin = dwUin; + pDest->szUid = dwUin ? null_strdup(szUid) : NULL; + pDest->bCreated = TRUE; + + return pDest; +} + + +void rates_queue_item::execute() +{ +#ifdef _DEBUG + ppro->NetLog_Server("Rates: Error executing abstract event."); +#endif +} + + +BOOL rates_queue_item::isOverRate(int nLevel) +{ + icq_lock l(ppro->m_ratesMutex); + + if (ppro->m_rates) + return ppro->m_rates->getNextRateLevel(wGroup) < ppro->m_rates->getLimitLevel(wGroup, nLevel); + + return FALSE; +} + + +rates_queue::rates_queue(CIcqProto *ppro, const char *szDescr, int nLimitLevel, int nWaitLevel, int nDuplicates) +{ + this->listsMutex = new icq_critical_section(); + this->ppro = ppro; + this->szDescr = szDescr; + limitLevel = nLimitLevel; + waitLevel = nWaitLevel; + duplicates = nDuplicates; +} + + +rates_queue::~rates_queue() +{ + cleanup(); + delete listsMutex; +} + + +// links to functions that are under Rate Control +struct rate_delay_args +{ + int nDelay; + rates_queue *queue; + IcqRateFunc delaycode; +}; + +void __cdecl CIcqProto::rateDelayThread(rate_delay_args *pArgs) +{ + SleepEx(pArgs->nDelay, TRUE); + (pArgs->queue->*pArgs->delaycode)(); + SAFE_FREE((void**)&pArgs); +} + + +void rates_queue::initDelay(int nDelay, IcqRateFunc delaycode) +{ +#ifdef _DEBUG + ppro->NetLog_Server("Rates: Delay %dms", nDelay); +#endif + + rate_delay_args *pArgs = (rate_delay_args*)SAFE_MALLOC(sizeof(rate_delay_args)); // This will be freed in the new thread + pArgs->queue = this; + pArgs->nDelay = nDelay; + pArgs->delaycode = delaycode; + + ppro->ForkThread((IcqThreadFunc)&CIcqProto::rateDelayThread, pArgs); +} + + +void rates_queue::cleanup() +{ + icq_lock l(listsMutex); + + if (pendingListSize) + ppro->NetLog_Server("Rates: Purging %d %s(s).", pendingListSize, szDescr); + + for (int i=0; i < pendingListSize; i++) + delete pendingList[i]; + SAFE_FREE((void**)&pendingList); + pendingListSize = 0; +} + + +void rates_queue::processQueue() +{ + if (!pendingList) + return; + + if (!ppro->icqOnline()) + { + cleanup(); + return; + } + // take from queue, execute + rates_queue_item *item = pendingList[0]; + + ppro->m_ratesMutex->Enter(); + listsMutex->Enter(); + if (item->isOverRate(limitLevel)) + { // the rate is higher, keep sleeping + int nDelay = ppro->m_rates->getDelayToLimitLevel(item->wGroup, ppro->m_rates->getLimitLevel(item->wGroup, waitLevel)); + + listsMutex->Leave(); + ppro->m_ratesMutex->Leave(); + if (nDelay < 10) nDelay = 10; + initDelay(nDelay, &rates_queue::processQueue); + return; + } + ppro->m_ratesMutex->Leave(); + + if (pendingListSize > 1) + { // we need to keep order + memmove(&pendingList[0], &pendingList[1], (pendingListSize - 1) * sizeof(rates_queue_item*)); + } + else + SAFE_FREE((void**)&pendingList); + + int bSetupTimer = --pendingListSize != 0; + + listsMutex->Leave(); + + if (ppro->icqOnline()) + { + ppro->NetLog_Server("Rates: Resuming %s.", szDescr); + item->execute(); + } + else + ppro->NetLog_Server("Rates: Discarding %s.", szDescr); + + if (bSetupTimer) + { + // in queue remained some items, setup timer + ppro->m_ratesMutex->Enter(); + int nDelay = ppro->m_rates->getDelayToLimitLevel(item->wGroup, waitLevel); + ppro->m_ratesMutex->Leave(); + + if (nDelay < 10) nDelay = 10; + initDelay(nDelay, &rates_queue::processQueue); + } + delete item; +} + + +void rates_queue::putItem(rates_queue_item *pItem, int nMinDelay) +{ + int bFound = FALSE; + + if (!ppro->icqOnline()) + return; + + ppro->NetLog_Server("Rates: Delaying %s.", szDescr); + + listsMutex->Enter(); + if (pendingListSize) + { + for (int i = 0; i < pendingListSize; i++) + { + if (pendingList[i]->isEqual(pItem)) + { + if (duplicates == -1) + { // discard existing, append new item + delete pendingList[i]; + memcpy(&pendingList[i], &pendingList[i + 1], (pendingListSize - i - 1) * sizeof(rates_queue_item*)); + bFound = TRUE; + } + else if (duplicates == 1) + { // keep existing, ignore new + listsMutex->Leave(); + return; + } + // otherwise keep existing and append new + } + } + } + if (!bFound) + { // not found, enlarge the queue + pendingListSize++; + pendingList = (rates_queue_item**)SAFE_REALLOC(pendingList, pendingListSize * sizeof(rates_queue_item*)); + } + pendingList[pendingListSize - 1] = pItem->copyItem(); + + if (pendingListSize == 1) + { // queue was empty setup timer + listsMutex->Leave(); + ppro->m_ratesMutex->Enter(); + int nDelay = ppro->m_rates->getDelayToLimitLevel(pItem->wGroup, waitLevel); + ppro->m_ratesMutex->Leave(); + + if (nDelay < 10) nDelay = 10; + if (nDelay < nMinDelay) nDelay = nMinDelay; + initDelay(nDelay, &rates_queue::processQueue); + } + else + listsMutex->Leave(); +} + + +int CIcqProto::handleRateItem(rates_queue_item *item, int nQueueType, int nMinDelay, BOOL bAllowDelay) +{ + rates_queue *pQueue = NULL; + + m_ratesMutex->Enter(); + switch (nQueueType) + { + case RQT_REQUEST: + pQueue = m_ratesQueue_Request; + break; + case RQT_RESPONSE: + pQueue = m_ratesQueue_Response; + break; + } + + if (pQueue) + { + if (bAllowDelay && (item->isOverRate(pQueue->waitLevel) || nMinDelay)) + { // limit reached or min delay configured, add to queue + pQueue->putItem(item, nMinDelay); + + m_ratesMutex->Leave(); + return 1; + } + } + m_ratesMutex->Leave(); + + item->execute(); + return 0; +} diff --git a/protocols/IcqOscarJ/src/icq_rates.h b/protocols/IcqOscarJ/src/icq_rates.h new file mode 100644 index 0000000000..ab16e74007 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_rates.h @@ -0,0 +1,146 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Rate management +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_RATES_H +#define __ICQ_RATES_H + +#define MAX_RATES_GROUP_COUNT 5 + +struct rates_group +{ + DWORD dwWindowSize; + DWORD dwClearLevel; + DWORD dwAlertLevel; + DWORD dwLimitLevel; + DWORD dwMaxLevel; + // current level + int rCurrentLevel; + int tCurrentLevel; + // links + WORD *pPairs; + int nPairs; +}; + +struct rates : public MZeroedObject +{ +private: + CIcqProto *ppro; + int nGroups; + rates_group groups[MAX_RATES_GROUP_COUNT]; + + rates_group *getGroup(WORD wGroup); +public: + rates(CIcqProto *ppro, BYTE *pBuffer, WORD wLen); + ~rates(); + + WORD getGroupFromSNAC(WORD wFamily, WORD wCommand); + WORD getGroupFromPacket(icq_packet *pPacket); + + int getLimitLevel(WORD wGroup, int nLevel); + int getDelayToLimitLevel(WORD wGroup, int nLevel); + int getNextRateLevel(WORD wGroup); + + void packetSent(icq_packet *pPacket); + void updateLevel(WORD wGroup, int nLevel); + + void initAckPacket(icq_packet *pPacket); +}; + +#define RML_CLEAR 0x01 +#define RML_ALERT 0x02 +#define RML_LIMIT 0x03 +#define RML_IDLE_10 0x10 +#define RML_IDLE_30 0x11 +#define RML_IDLE_50 0x12 +#define RML_IDLE_70 0x13 + +// Rates - Level 2 + +// queue types +#define RQT_DEFAULT 0 // standard - pushes all items without much delay +#define RQT_REQUEST 1 // request - pushes only first item on duplicity +#define RQT_RESPONSE 2 // response - pushes only last item on duplicity + +// +// generic queue item +// +struct rates_queue_item : public MZeroedObject +{ + friend struct rates_queue; +protected: + CIcqProto *ppro; + BOOL bCreated; + WORD wGroup; + + virtual BOOL isEqual(rates_queue_item *pItem); + virtual rates_queue_item* copyItem(rates_queue_item *pDest = NULL); +public: + rates_queue_item(CIcqProto *ppro, WORD wGroup); + virtual ~rates_queue_item(); + + BOOL isOverRate(int nLevel); + + virtual void execute(); + + HANDLE hContact; + DWORD dwUin; + char *szUid; +}; + +struct rates_queue; +typedef void (rates_queue::*IcqRateFunc)(void); + +// +// generic item queue (FIFO) +// +struct rates_queue : public MZeroedObject +{ +private: + CIcqProto *ppro; + const char *szDescr; + icq_critical_section *listsMutex; // we need to be thread safe + int pendingListSize; + rates_queue_item **pendingList; + int duplicates; +protected: + void cleanup(); + void processQueue(); + void initDelay(int nDelay, IcqRateFunc delaycode); +public: + rates_queue(CIcqProto *ppro, const char *szDescr, int nLimitLevel, int nWaitLevel, int nDuplicates = 0); + ~rates_queue(); + + void putItem(rates_queue_item *pItem, int nMinDelay); + + int limitLevel; // RML_* + int waitLevel; +}; + + +#endif /* __ICQ_RATES_H */ diff --git a/protocols/IcqOscarJ/src/icq_server.cpp b/protocols/IcqOscarJ/src/icq_server.cpp new file mode 100644 index 0000000000..63a5d63d84 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_server.cpp @@ -0,0 +1,444 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Manages main server connection, low-level communication +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void icq_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra); + +///////////////////////////////////////////////////////////////////////////////////////// +// ICQ Server thread + +void __cdecl CIcqProto::ServerThread(serverthread_start_info *infoParam) +{ + serverthread_info info = {0}; + + info.isLoginServer = 1; + info.wAuthKeyLen = infoParam->wPassLen; + null_strcpy((char*)info.szAuthKey, infoParam->szPass, info.wAuthKeyLen); + // store server port + info.wServerPort = infoParam->nloc.wPort; + + srand(time(NULL)); + + ResetSettingsOnConnect(); + + // Connect to the login server + NetLog_Server("Authenticating to server"); + { + NETLIBOPENCONNECTION nloc = infoParam->nloc; + nloc.timeout = 6; + if (m_bGatewayMode) + nloc.flags |= NLOCF_HTTPGATEWAY; + + hServerConn = NetLib_OpenConnection(m_hServerNetlibUser, NULL, &nloc); + + SAFE_FREE((void**)&nloc.szHost); + SAFE_FREE((void**)&infoParam); + + if (hServerConn && m_bSecureConnection) + { + if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hServerConn, 0)) + { + icq_LogMessage(LOG_ERROR, LPGEN("Unable to connect to ICQ login server, SSL could not be negotiated")); + SetCurrentStatus(ID_STATUS_OFFLINE); + NetLib_CloseConnection(&hServerConn, TRUE); + return; + } + } + } + + // Login error + if (hServerConn == NULL) + { + DWORD dwError = GetLastError(); + + SetCurrentStatus(ID_STATUS_OFFLINE); + + icq_LogUsingErrorCode(LOG_ERROR, dwError, LPGEN("Unable to connect to ICQ login server")); + return; + } + + // Initialize direct connection ports + { + DWORD dwInternalIP; + BYTE bConstInternalIP = getSettingByte(NULL, "ConstRealIP", 0); + + info.hDirectBoundPort = NetLib_BindPort(icq_newConnectionReceived, this, &wListenPort, &dwInternalIP); + if (!info.hDirectBoundPort) + { + icq_LogUsingErrorCode(LOG_WARNING, GetLastError(), LPGEN("Miranda was unable to allocate a port to listen for direct peer-to-peer connections between clients. You will be able to use most of the ICQ network without problems but you may be unable to send or receive files.\n\nIf you have a firewall this may be blocking Miranda, in which case you should configure your firewall to leave some ports open and tell Miranda which ports to use in M->Options->ICQ->Network.")); + wListenPort = 0; + if (!bConstInternalIP) deleteSetting(NULL, "RealIP"); + } + else if (!bConstInternalIP) + setSettingDword(NULL, "RealIP", dwInternalIP); + } + + // Initialize rate limiting queues + { + icq_lock l(m_ratesMutex); + + m_ratesQueue_Request = new rates_queue(this, "request", RML_IDLE_30, RML_IDLE_50, 1); + m_ratesQueue_Response = new rates_queue(this, "response", RML_IDLE_10, RML_IDLE_30, -1); + } + + // This is the "infinite" loop that receives the packets from the ICQ server + { + int recvResult; + NETLIBPACKETRECVER packetRecv = {0}; + + info.hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 0x2400); + packetRecv.cbSize = sizeof(packetRecv); + packetRecv.dwTimeout = INFINITE; + while (serverThreadHandle) + { + if (info.bReinitRecver) + { // we reconnected, reinit struct + info.bReinitRecver = 0; + ZeroMemory(&packetRecv, sizeof(packetRecv)); + packetRecv.cbSize = sizeof(packetRecv); + packetRecv.dwTimeout = INFINITE; + } + + recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)info.hPacketRecver, (LPARAM)&packetRecv); + + if (recvResult == 0) + { + NetLog_Server("Clean closure of server socket"); + break; + } + + if (recvResult == SOCKET_ERROR) + { + NetLog_Server("Abortive closure of server socket, error: %d", GetLastError()); + break; + } + + if (m_iDesiredStatus == ID_STATUS_OFFLINE) + { // Disconnect requested, send disconnect packet + icq_sendCloseConnection(); + + // disconnected upon request + m_bConnectionLost = FALSE; + SetCurrentStatus(ID_STATUS_OFFLINE); + + NetLog_Server("Logged off."); + break; + } + + // Deal with the packet + packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable, &info); + } + serverThreadHandle = NULL; + + // Time to shutdown + NetLib_CloseConnection(&hServerConn, TRUE); + + // Close the packet receiver (connection may still be open) + NetLib_SafeCloseHandle(&info.hPacketRecver); + + // Close DC port + NetLib_SafeCloseHandle(&info.hDirectBoundPort); + } + + // disable auto info-update thread + icq_EnableUserLookup(FALSE); + + if (m_iStatus != ID_STATUS_OFFLINE && m_iDesiredStatus != ID_STATUS_OFFLINE) + { + if (!info.bLoggedIn) + icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nLogin sequence failed for unknown reason.\nTry again later.")); + + // set flag indicating we were kicked out + m_bConnectionLost = TRUE; + + SetCurrentStatus(ID_STATUS_OFFLINE); + } + + // signal keep-alive thread to stop + StopKeepAlive(&info); + + // Close all open DC connections + CloseContactDirectConns(NULL); + + // Close avatar connection if any + StopAvatarThread(); + + // Offline all contacts + HANDLE hContact = FindFirstContact(); + while (hContact) + { + DWORD dwUIN; + uid_str szUID; + + if (!getContactUid(hContact, &dwUIN, &szUID)) + { + if (getContactStatus(hContact) != ID_STATUS_OFFLINE) + { + char tmp = 0; + + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + + handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0); + } + } + + hContact = FindNextContact(hContact); + } + + setSettingDword(NULL, "LogonTS", 0); // clear logon time + + servlistPendingFlushOperations(); // clear pending operations list + + // release rates queues + { + icq_lock l(m_ratesMutex); + + SAFE_DELETE((MZeroedObject**)&m_ratesQueue_Request); + SAFE_DELETE((MZeroedObject**)&m_ratesQueue_Response); + SAFE_DELETE((MZeroedObject**)&m_rates); + } + + FlushServerIDs(); // clear server IDs list + + NetLog_Server("%s thread ended.", "Server"); +} + + +void CIcqProto::icq_serverDisconnect(BOOL bBlock) +{ + if ( !hServerConn) + return; + + NetLog_Server("Server shutdown requested"); + Netlib_Shutdown(hServerConn); + + if (serverThreadHandle) { + // Not called from network thread? + if (bBlock && GetCurrentThreadId() != serverThreadId) + while (ICQWaitForSingleObject(serverThreadHandle, INFINITE) != WAIT_OBJECT_0); + + CloseHandle(serverThreadHandle); + serverThreadHandle = NULL; + } +} + + +int CIcqProto::handleServerPackets(BYTE *buf, int len, serverthread_info *info) +{ + BYTE channel; + WORD sequence; + WORD datalen; + int bytesUsed = 0; + + while (len > 0) + { + if (info->bReinitRecver) + break; + + // All FLAPS begin with 0x2a + if (*buf++ != FLAP_MARKER) + break; + + if (len < 6) + break; + + unpackByte(&buf, &channel); + unpackWord(&buf, &sequence); + unpackWord(&buf, &datalen); + + if (len < 6 + datalen) + break; + + +#ifdef _DEBUG + NetLog_Server("Server FLAP: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); +#endif + + switch (channel) { + case ICQ_LOGIN_CHAN: + handleLoginChannel(buf, datalen, info); + break; + + case ICQ_DATA_CHAN: + handleDataChannel(buf, datalen, info); + break; + + case ICQ_ERROR_CHAN: + handleErrorChannel(buf, datalen); + break; + + case ICQ_CLOSE_CHAN: + handleCloseChannel(buf, datalen, info); + break; // we need this for walking thru proxy + + case ICQ_PING_CHAN: + handlePingChannel(buf, datalen); + break; + + default: + NetLog_Server("Warning: Unhandled Server FLAP Channel: Channel %u, Seq %u, Length %u bytes", channel, sequence, datalen); + break; + } + + /* Increase pointers so we can check for more FLAPs */ + buf += datalen; + len -= (datalen + 6); + bytesUsed += (datalen + 6); + } + + return bytesUsed; +} + + +void CIcqProto::sendServPacket(icq_packet *pPacket) +{ + // make sure to have the connection handle + connectionHandleMutex->Enter(); + + if (hServerConn) + { + int nSendResult; + + // This critsec makes sure that the sequence order doesn't get screwed up + localSeqMutex->Enter(); + + // :IMPORTANT: + // The FLAP sequence must be a WORD. When it reaches 0xFFFF it should wrap to + // 0x0000, otherwise we'll get kicked by server. + wLocalSequence++; + + // Pack sequence number + pPacket->pData[2] = ((wLocalSequence & 0xff00) >> 8); + pPacket->pData[3] = (wLocalSequence & 0x00ff); + + nSendResult = Netlib_Send(hServerConn, (const char *)pPacket->pData, pPacket->wLen, 0); + + localSeqMutex->Leave(); + connectionHandleMutex->Leave(); + + // Send error + if (nSendResult == SOCKET_ERROR) + { + icq_LogUsingErrorCode(LOG_ERROR, GetLastError(), LPGEN("Your connection with the ICQ server was abortively closed")); + icq_serverDisconnect(FALSE); + + if (m_iStatus != ID_STATUS_OFFLINE) + { + SetCurrentStatus(ID_STATUS_OFFLINE); + } + } + else + { // Rates management + icq_lock l(m_ratesMutex); + m_rates->packetSent(pPacket); + } + + } + else + { + connectionHandleMutex->Leave(); + NetLog_Server("Error: Failed to send packet (no connection)"); + } + + SAFE_FREE((void**)&pPacket->pData); +} + + +void __cdecl CIcqProto::SendPacketAsyncThread(icq_packet* pkt) +{ + sendServPacket( pkt ); + SAFE_FREE((void**)&pkt); +} + + +void CIcqProto::sendServPacketAsync(icq_packet *packet) +{ + icq_packet *pPacket; + + pPacket = (icq_packet*)SAFE_MALLOC(sizeof(icq_packet)); // This will be freed in the new thread + memcpy(pPacket, packet, sizeof(icq_packet)); + + ForkThread(( IcqThreadFunc )&CIcqProto::SendPacketAsyncThread, pPacket); +} + + +int CIcqProto::IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel) +{ + icq_lock l(m_ratesMutex); + + if (m_rates) + { + WORD wGroup = m_rates->getGroupFromSNAC(wFamily, wCommand); + + // check if the rate is not over specified level + if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, nLevel)) + return TRUE; + } + + return FALSE; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// ICQ Server thread + +void CIcqProto::icq_login(const char* szPassword) +{ + DWORD dwUin = getContactUin(NULL); + serverthread_start_info* stsi = (serverthread_start_info*)SAFE_MALLOC(sizeof(serverthread_start_info)); + + // Server host name + char szServer[MAX_PATH]; + if (getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH)) + stsi->nloc.szHost = null_strdup(m_bSecureConnection ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); + else + stsi->nloc.szHost = null_strdup(szServer); + + // Server port + stsi->nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); + if (stsi->nloc.wPort == 0) + stsi->nloc.wPort = RandRange(1024, 65535); + + // User password + stsi->wPassLen = strlennull(szPassword); + if (stsi->wPassLen > 8) stsi->wPassLen = 8; + null_strcpy(stsi->szPass, szPassword, stsi->wPassLen); + + // Randomize sequence + wLocalSequence = generate_flap_sequence(); + + m_dwLocalUIN = dwUin; + + // Initialize members + m_avatarsConnectionPending = TRUE; + + serverThreadHandle = ForkThreadEx(( IcqThreadFunc )&CIcqProto::ServerThread, stsi, &serverThreadId); +} diff --git a/protocols/IcqOscarJ/src/icq_server.h b/protocols/IcqOscarJ/src/icq_server.h new file mode 100644 index 0000000000..eba3ecfa42 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_server.h @@ -0,0 +1,71 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Declarations for server thread +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_SERVER_H +#define __ICQ_SERVER_H + +struct serverthread_start_info +{ + NETLIBOPENCONNECTION nloc; + WORD wPassLen; + char szPass[128]; +}; + +struct serverthread_info +{ + struct CIcqProto *ppro; + int bLoggedIn; + int isLoginServer; + BYTE szAuthKey[20]; + WORD wAuthKeyLen; + WORD wServerPort; + char *newServer; + BYTE *cookieData; + int cookieDataLen; + int newServerSSL; + int newServerReady; + int isMigrating; + HANDLE hPacketRecver; + int bReinitRecver; + int bMyAvatarInited; +// + HANDLE hDirectBoundPort; +// + HANDLE hKeepAliveEvent; +}; + +/*---------* Functions *---------------*/ + +void icq_serverDisconnect(BOOL bBlock); +void icq_login(const char *szPassword); + +int IsServerOverRate(WORD wFamily, WORD wCommand, int nLevel); + + +#endif /* __ICQ_SERVER_H */ diff --git a/protocols/IcqOscarJ/src/icq_servlist.cpp b/protocols/IcqOscarJ/src/icq_servlist.cpp new file mode 100644 index 0000000000..b2adc4831c --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_servlist.cpp @@ -0,0 +1,2829 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Functions that handles list of used server IDs, sends low-level packets for SSI information +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +// SERVER-LIST UPDATE BOARD +// + +void CIcqProto::servlistBeginOperation(int operationCount, int bImport) +{ + if (operationCount) + { // check if we should send operation begin packet + if (!servlistEditCount) + icq_sendServerBeginOperation(bImport); + // update count of active operations + servlistEditCount += operationCount; +#ifdef _DEBUG + NetLog_Server("Server-List: Begin operation processed (%d operations active)", servlistEditCount); +#endif + } +} + +void CIcqProto::servlistEndOperation(int operationCount) +{ + if (operationCount) + { + if (operationCount > servlistEditCount) + { // sanity check + NetLog_Server("Error: Server-List End operation is not paired!"); + operationCount = servlistEditCount; + } + // update count of active operations + servlistEditCount -= operationCount; + // check if we should send operation end packet + if (!servlistEditCount) + icq_sendServerEndOperation(); +#ifdef _DEBUG + NetLog_Server("Server-List: End operation processed (%d operations active)", servlistEditCount); +#endif + } +} + +void __cdecl CIcqProto::servlistQueueThread(void *param) +{ + int* queueState = ( int* )param; + +#ifdef _DEBUG + NetLog_Server("Server-List: Starting Update board."); +#endif + + SleepEx(50, FALSE); + // handle server-list requests queue + servlistQueueMutex->Enter(); + while (servlistQueueCount) + { + ssiqueueditems* pItem = NULL; + int bItemDouble; + WORD wItemAction; + icq_packet groupPacket = {0}; + icq_packet groupPacket2 = {0}; + cookie_servlist_action* pGroupCookie = NULL; + int nEndOperations; + + // first check if the state is calm + while (*queueState) + { + int i; + time_t tNow = time(NULL); + int bFound = FALSE; + + for (i = 0; i < servlistQueueCount; i++) + { // check if we do not have some expired items to handle, otherwise keep sleeping + if ((servlistQueueList[i]->tAdded + servlistQueueList[i]->dwTimeout) < tNow) + { // got expired item, stop sleep even when changes goes on + bFound = TRUE; + break; + } + } + if (bFound) break; + // reset queue state, keep sleeping + *queueState = FALSE; + servlistQueueMutex->Leave(); + SleepEx(100, TRUE); + servlistQueueMutex->Enter(); + } + if (!icqOnline()) + { // do not try to send packets if offline + servlistQueueMutex->Leave(); + SleepEx(100, TRUE); + servlistQueueMutex->Enter(); + continue; + } +#ifdef _DEBUG + NetLog_Server("Server-List: %d items in queue.", servlistQueueCount); +#endif + // take the oldest item (keep the board FIFO) + pItem = servlistQueueList[0]; // take first (queue contains at least one item here) + wItemAction = (WORD)(pItem->pItems[0]->dwOperation & SSOF_ACTIONMASK); + bItemDouble = pItem->pItems[0]->dwOperation & SSOG_DOUBLE; + // check item rate - too high -> sleep + m_ratesMutex->Enter(); + { + WORD wRateGroup = m_rates->getGroupFromSNAC(ICQ_LISTS_FAMILY, wItemAction); + int nRateLevel = bItemDouble ? RML_IDLE_30 : RML_IDLE_10; + + while (m_rates->getNextRateLevel(wRateGroup) < m_rates->getLimitLevel(wRateGroup, nRateLevel)) + { // the rate is higher, keep sleeping + int nDelay = m_rates->getDelayToLimitLevel(wRateGroup, nRateLevel); + + m_ratesMutex->Leave(); + // do not keep the queue frozen + servlistQueueMutex->Leave(); + if (nDelay < 10) nDelay = 10; +#ifdef _DEBUG + NetLog_Server("Server-List: Delaying %dms [Rates]", nDelay); +#endif + SleepEx(nDelay, FALSE); + // check if the rate is now ok + servlistQueueMutex->Enter(); + m_ratesMutex->Enter(); + } + } + m_ratesMutex->Leave(); + { // setup group packet(s) & cookie + int totalSize = 0; + int i; + cookie_servlist_action *pGroupCookie; + DWORD dwGroupCookie; + // determine the total size of the packet + for(i = 0; i < pItem->nItems; i++) + totalSize += pItem->pItems[i]->packet.wLen - 0x10; + + // process begin & end operation flags + { + int bImportOperation = FALSE; + int nBeginOperations = 0; + + nEndOperations = 0; + for(i = 0; i < pItem->nItems; i++) + { // collect begin & end operation flags + if (pItem->pItems[i]->dwOperation & SSOF_BEGIN_OPERATION) + nBeginOperations++; + if (pItem->pItems[i]->dwOperation & SSOF_END_OPERATION) + nEndOperations++; + // check if the operation is import + if (pItem->pItems[i]->dwOperation & SSOF_IMPORT_OPERATION) + bImportOperation = TRUE; + } + // really begin operation if requested + if (nBeginOperations) + servlistBeginOperation(nBeginOperations, bImportOperation); + } + + if (pItem->nItems > 1) + { // pack all packet's data, create group cookie + pGroupCookie = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + pGroupCookie->dwAction = SSA_ACTION_GROUP; + pGroupCookie->dwGroupCount = pItem->nItems; + pGroupCookie->pGroupItems = (cookie_servlist_action**)SAFE_MALLOC(pItem->nItems * sizeof(cookie_servlist_action*)); + for (i = 0; i < pItem->nItems; i++) + { // build group cookie data - assign cookies datas + pGroupCookie->pGroupItems[i] = pItem->pItems[i]->cookie; + // release the separate cookie id + FreeCookieByData(CKT_SERVERLIST, pItem->pItems[i]->cookie); + } + // allocate cookie id + dwGroupCookie = AllocateCookie(CKT_SERVERLIST, wItemAction, 0, pGroupCookie); + // prepare packet data + serverPacketInit(&groupPacket, (WORD)(totalSize + 0x0A)); // FLAP size added inside + packFNACHeader(&groupPacket, ICQ_LISTS_FAMILY, wItemAction, 0, dwGroupCookie); + for (i = 0; i < pItem->nItems; i++) + packBuffer(&groupPacket, pItem->pItems[i]->packet.pData + 0x10, (WORD)(pItem->pItems[i]->packet.wLen - 0x10)); + + if (bItemDouble) + { // prepare second packet + wItemAction = ((servlistgroupitemdouble*)(pItem->pItems[0]))->wAction2; + totalSize = 0; + // determine the total size of the packet + for(i = 0; i < pItem->nItems; i++) + totalSize += ((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.wLen - 0x10; + + pGroupCookie = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + pGroupCookie->dwAction = SSA_ACTION_GROUP; + pGroupCookie->dwGroupCount = pItem->nItems; + pGroupCookie->pGroupItems = (cookie_servlist_action**)SAFE_MALLOC(pItem->nItems * sizeof(cookie_servlist_action*)); + for (i = 0; i < pItem->nItems; i++) + pGroupCookie->pGroupItems[i] = pItem->pItems[i]->cookie; + // allocate cookie id + dwGroupCookie = AllocateCookie(CKT_SERVERLIST, wItemAction, 0, pGroupCookie); + // prepare packet data + serverPacketInit(&groupPacket2, (WORD)(totalSize + 0x0A)); // FLAP size added inside + packFNACHeader(&groupPacket2, ICQ_LISTS_FAMILY, wItemAction, 0, dwGroupCookie); + for (i = 0; i < pItem->nItems; i++) + packBuffer(&groupPacket2, ((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.pData + 0x10, (WORD)(((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.wLen - 0x10)); + } + } + else + { // just send the one packet, do not create action group + pGroupCookie = pItem->pItems[0]->cookie; + memcpy(&groupPacket, &pItem->pItems[0]->packet, sizeof(icq_packet)); + if (bItemDouble) + memcpy(&groupPacket2, &((servlistgroupitemdouble*)(pItem->pItems[0]))->packet2, sizeof(icq_packet)); + } + + { // remove grouped item from queue & release grouped item + servlistQueueCount--; + servlistQueueList[0] = servlistQueueList[servlistQueueCount]; + + for (i = 0; i < pItem->nItems; i++) + { // release memory + if (pItem->nItems > 1) + { // free the packet only if we created the group packet + SAFE_FREE((void**)&pItem->pItems[i]->packet.pData); + if (pItem->pItems[i]->dwOperation & SSOG_DOUBLE) + SAFE_FREE((void**)&((servlistgroupitemdouble*)(pItem->pItems[i]))->packet2.pData); + } + SAFE_FREE((void**)&pItem->pItems[i]); + break; + } + SAFE_FREE((void**)&pItem); + // resize the queue + if (servlistQueueSize > servlistQueueCount + 6) + { + servlistQueueSize -= 4; + servlistQueueList = (ssiqueueditems**)SAFE_REALLOC(servlistQueueList, servlistQueueSize * sizeof(ssiqueueditems*)); + } + } + } + servlistQueueMutex->Leave(); + // send group packet + sendServPacket(&groupPacket); + // send second group packet (if present) + if (bItemDouble) + sendServPacket(&groupPacket2); + // process end operation marks + if (nEndOperations) + servlistEndOperation(nEndOperations); + // loose the loop a bit + SleepEx(100, TRUE); + servlistQueueMutex->Enter(); + } + // clean-up thread + CloseHandle(servlistQueueThreadHandle); + servlistQueueThreadHandle = NULL; + servlistQueueMutex->Leave(); +#ifdef _DEBUG + NetLog_Server("Server-List: Update Board ending."); +#endif +} + +void CIcqProto::servlistQueueAddGroupItem(servlistgroupitem* pGroupItem, int dwTimeout) +{ + icq_lock l(servlistQueueMutex); + + { // add the packet to queue + DWORD dwMark = pGroupItem->dwOperation & SSOF_GROUPINGMASK; + ssiqueueditems* pItem = NULL; + + // try to find compatible item + for (int i = 0; i < servlistQueueCount; i++) + { + if ((servlistQueueList[i]->pItems[0]->dwOperation & SSOF_GROUPINGMASK) == dwMark && servlistQueueList[i]->nItems < MAX_SERVLIST_PACKET_ITEMS) + { // found compatible item, check if it does not contain operation for the same server-list item + pItem = servlistQueueList[i]; + + for (int j = 0; j < pItem->nItems; j++) + if (pItem->pItems[j]->cookie->wContactId == pGroupItem->cookie->wContactId && + pItem->pItems[j]->cookie->wGroupId == pGroupItem->cookie->wGroupId) + { + pItem = NULL; + break; + } + // cannot send two operations for the same server-list record in one packet, look for another + if (!pItem) continue; + +#ifdef _DEBUG + NetLog_Server("Server-List: Adding packet to item #%d with operation %x.", i, servlistQueueList[i]->pItems[0]->dwOperation); +#endif + break; + } + } + if (!pItem) + { // compatible item was not found, create new one, add to queue + pItem = (ssiqueueditems*)SAFE_MALLOC(sizeof(ssiqueueditems)); + pItem->tAdded = time(NULL); + pItem->dwTimeout = dwTimeout; + + if (servlistQueueCount == servlistQueueSize) + { // resize the queue - it is too small + servlistQueueSize += 4; + servlistQueueList = (ssiqueueditems**)SAFE_REALLOC(servlistQueueList, servlistQueueSize * sizeof(ssiqueueditems*)); + } + // really add to queue + servlistQueueList[servlistQueueCount++] = pItem; +#ifdef _DEBUG + NetLog_Server("Server-List: Adding new item to queue."); +#endif + } + else if (pItem->dwTimeout > dwTimeout) + { // if the timeout of currently added packet is shorter, update the previous one + pItem->dwTimeout = dwTimeout; + } + // add GroupItem to queueditems (pItem) + pItem->pItems[pItem->nItems++] = pGroupItem; + } + // wake up board thread (keep sleeping or start new one) + if (!servlistQueueThreadHandle) + { + // create new board thread + servlistQueueThreadHandle = ForkThreadEx( &CIcqProto::servlistQueueThread, &servlistQueueState ); + } + else // signal thread, that queue was changed during sleep + servlistQueueState = TRUE; +} + +int CIcqProto::servlistHandlePrimitives(DWORD dwOperation) +{ + if (dwOperation & SSO_BEGIN_OPERATION) + { // operation starting, no action ready yet + servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); + return TRUE; + } + else if (dwOperation & SSO_END_OPERATION) + { // operation ending without action + servlistEndOperation(1); + return TRUE; + } + + return FALSE; +} + +void CIcqProto::servlistPostPacket(icq_packet* packet, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout) +{ + cookie_servlist_action* pCookie; + + if (servlistHandlePrimitives(dwOperation)) + return; + + if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) + return; // invalid cookie + + if (dwOperation & SSOF_SEND_DIRECTLY) + { // send directly - this is for some special cases + // begin operation if requested + if (dwOperation & SSOF_BEGIN_OPERATION) + servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); + + // send the packet + sendServPacket(packet); + + // end operation if requested + if (dwOperation & SSOF_END_OPERATION) + servlistEndOperation(1); + } + else + { // add to server-list update board + servlistgroupitem* pGroupItem; + + // prepare group item + pGroupItem = (servlistgroupitem*)SAFE_MALLOC(sizeof(servlistgroupitem)); + pGroupItem->dwOperation = dwOperation; + pGroupItem->cookie = pCookie; + // packet data are alloced, keep them until they are sent + memcpy(&pGroupItem->packet, packet, sizeof(icq_packet)); + + servlistQueueAddGroupItem(pGroupItem, dwTimeout); + } +} + +void CIcqProto::servlistPostPacketDouble(icq_packet* packet1, DWORD dwCookie, DWORD dwOperation, DWORD dwTimeout, icq_packet* packet2, WORD wAction2) +{ + cookie_servlist_action* pCookie; + + if (servlistHandlePrimitives(dwOperation)) + return; + + if (!FindCookie(dwCookie, NULL, (void**)&pCookie)) + return; // invalid cookie + + if (dwOperation & SSOF_SEND_DIRECTLY) + { // send directly - this is for some special cases + // begin operation if requested + if (dwOperation & SSOF_BEGIN_OPERATION) + servlistBeginOperation(1, dwOperation & SSOF_IMPORT_OPERATION); + + // send the packets + sendServPacket(packet1); + sendServPacket(packet2); + + // end operation if requested + if (dwOperation & SSOF_END_OPERATION) + servlistEndOperation(1); + } + else + { // add to server-list update board + servlistgroupitemdouble* pGroupItem; + + // prepare group item + pGroupItem = (servlistgroupitemdouble*)SAFE_MALLOC(sizeof(servlistgroupitemdouble)); + pGroupItem->dwOperation = dwOperation; + pGroupItem->cookie = pCookie; + pGroupItem->wAction2 = wAction2; + // packets data are alloced, keep them until they are sent + memcpy(&pGroupItem->packet, packet1, sizeof(icq_packet)); + memcpy(&pGroupItem->packet2, packet2, sizeof(icq_packet)); + + servlistQueueAddGroupItem((servlistgroupitem*)pGroupItem, dwTimeout); + } +} + +void CIcqProto::servlistProcessLogin() +{ + // reset edit state counter + servlistEditCount = 0; + + /// TODO: preserve queue state in DB! restore here! + + // if the server-list queue contains items and thread is not running, start it + if (servlistQueueCount && !servlistQueueThreadHandle) + servlistQueueThreadHandle = ForkThreadEx( &CIcqProto::servlistQueueThread, &servlistQueueState ); +} + +// HERE ENDS SERVER-LIST UPDATE BOARD IMPLEMENTATION // +/////////////////////////////////////////////////////// +//===================================================// + +// PENDING SERVER-LIST OPERATIONS +// +#define ITEM_PENDING_CONTACT 0x01 +#define ITEM_PENDING_GROUP 0x02 + +#define CALLBACK_RESULT_CONTINUE 0x00 +#define CALLBACK_RESULT_POSTPONE 0x0D +#define CALLBACK_RESULT_PURGE 0x10 + + +#define SPOF_AUTO_CREATE_ITEM 0x01 + +int CIcqProto::servlistPendingFindItem(int nType, HANDLE hContact, const char *pszGroup) +{ + if (servlistPendingList) + for (int i = 0; i < servlistPendingCount; i++) + if (servlistPendingList[i]->nType == nType) + { + if (((nType == ITEM_PENDING_CONTACT) && (servlistPendingList[i]->hContact == hContact)) || + ((nType == ITEM_PENDING_GROUP) && (!strcmpnull(servlistPendingList[i]->szGroup, pszGroup)))) + return i; + } + return -1; +} + + +void CIcqProto::servlistPendingAddItem(servlistpendingitem *pItem) +{ + if (servlistPendingCount >= servlistPendingSize) // add new + { + servlistPendingSize += 10; + servlistPendingList = (servlistpendingitem**)SAFE_REALLOC(servlistPendingList, servlistPendingSize * sizeof(servlistpendingitem*)); + } + + servlistPendingList[servlistPendingCount++] = pItem; +} + + +servlistpendingitem* CIcqProto::servlistPendingRemoveItem(int nType, HANDLE hContact, const char *pszGroup) +{ // unregister pending item, trigger pending operations + int iItem; + servlistpendingitem *pItem = NULL; + + icq_lock l(servlistMutex); + + if ((iItem = servlistPendingFindItem(nType, hContact, pszGroup)) != -1) + { // found, remove from the pending list + pItem = servlistPendingList[iItem]; + + servlistPendingList[iItem] = servlistPendingList[--servlistPendingCount]; + + if (servlistPendingCount + 10 < servlistPendingSize) + { + servlistPendingSize -= 5; + servlistPendingList = (servlistpendingitem**)SAFE_REALLOC(servlistPendingList, servlistPendingSize * sizeof(servlistpendingitem*)); + } + // was the first operation was created automatically to postpone ItemAdd? + if (pItem->operations && pItem->operations[0].flags & SPOF_AUTO_CREATE_ITEM) + { // yes, add new item + servlistpendingitem *pNewItem = (servlistpendingitem*)SAFE_MALLOC(sizeof(servlistpendingitem)); + + if (pNewItem) + { // move the remaining operations +#ifdef _DEBUG + if (pItem->nType == ITEM_PENDING_CONTACT) + NetLog_Server("Server-List: Resuming contact %x operation.", pItem->hContact); + else + NetLog_Server("Server-List: Resuming group \"%s\" operation.", pItem->szGroup); +#endif + + pNewItem->nType = pItem->nType; + pNewItem->hContact = pItem->hContact; + pNewItem->szGroup = null_strdup(pItem->szGroup); + pNewItem->wContactID = pItem->wContactID; + pNewItem->wGroupID = pItem->wGroupID; + pNewItem->operationsCount = pItem->operationsCount - 1; + pNewItem->operations = (servlistpendingoperation*)SAFE_MALLOC(pNewItem->operationsCount * sizeof(servlistpendingoperation)); + memcpy(pNewItem->operations, pItem->operations + 1, pNewItem->operationsCount * sizeof(servlistpendingoperation)); + pItem->operationsCount = 1; + + servlistPendingAddItem(pNewItem); + // clear the flag + pItem->operations[0].flags &= ~SPOF_AUTO_CREATE_ITEM; + } + } + } +#ifdef _DEBUG + else + NetLog_Server("Server-List Error: Trying to remove non-existing pending %s.", nType == ITEM_PENDING_CONTACT ? "contact" : "group"); +#endif + + return pItem; +} + + +void CIcqProto::servlistPendingAddContactOperation(HANDLE hContact, LPARAM param, PENDING_CONTACT_CALLBACK callback, DWORD flags) +{ // add postponed operation (add contact, update contact, regroup resume, etc.) + // - after contact is added + int iItem; + servlistpendingitem *pItem = NULL; + + icq_lock l(servlistMutex); + + if ((iItem = servlistPendingFindItem(ITEM_PENDING_CONTACT, hContact, NULL)) != -1) + pItem = servlistPendingList[iItem]; + + if (pItem) + { + int iOperation = pItem->operationsCount++; + + pItem->operations = (servlistpendingoperation*)SAFE_REALLOC(pItem->operations, pItem->operationsCount * sizeof(servlistpendingoperation)); + pItem->operations[iOperation].param = param; + pItem->operations[iOperation].callback = (PENDING_GROUP_CALLBACK)callback; + pItem->operations[iOperation].flags = flags; + } + else + { + NetLog_Server("Server-List Error: Trying to add pending operation to a non existing contact."); + } +} + + +void CIcqProto::servlistPendingAddGroupOperation(const char *pszGroup, LPARAM param, PENDING_GROUP_CALLBACK callback, DWORD flags) +{ // add postponed operation - after group is added + int iItem; + servlistpendingitem *pItem = NULL; + + icq_lock l(servlistMutex); + + if ((iItem = servlistPendingFindItem(ITEM_PENDING_GROUP, NULL, pszGroup)) != -1) + pItem = servlistPendingList[iItem]; + + if (pItem) + { + int iOperation = pItem->operationsCount++; + + pItem->operations = (servlistpendingoperation*)SAFE_REALLOC(pItem->operations, pItem->operationsCount * sizeof(servlistpendingoperation)); + pItem->operations[iOperation].param = param; + pItem->operations[iOperation].callback = callback; + pItem->operations[iOperation].flags = flags; + } + else + { + NetLog_Server("Server-List Error: Trying to add pending operation to a non existing group."); + } +} + + +int CIcqProto::servlistPendingAddContact(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM param, PENDING_CONTACT_CALLBACK callback, int bDoInline, LPARAM operationParam, PENDING_CONTACT_CALLBACK operationCallback) +{ + int iItem; + servlistpendingitem *pItem = NULL; + + servlistMutex->Enter(); + + if ((iItem = servlistPendingFindItem(ITEM_PENDING_CONTACT, hContact, NULL)) != -1) + pItem = servlistPendingList[iItem]; + + if (pItem) + { +#ifdef _DEBUG + NetLog_Server("Server-List: Pending contact %x already in list; adding as operation.", hContact); +#endif + servlistPendingAddContactOperation(hContact, param, callback, SPOF_AUTO_CREATE_ITEM); + + if (operationCallback) + servlistPendingAddContactOperation(hContact, operationParam, operationCallback, 0); + + servlistMutex->Leave(); + + return 0; // Pending + } + +#ifdef _DEBUG + NetLog_Server("Server-List: Starting contact %x operation.", hContact); +#endif + + pItem = (servlistpendingitem *)SAFE_MALLOC(sizeof(servlistpendingitem)); + pItem->nType = ITEM_PENDING_CONTACT; + pItem->hContact = hContact; + pItem->wContactID = wContactID; + pItem->wGroupID = wGroupID; + + servlistPendingAddItem(pItem); + + if (operationCallback) + servlistPendingAddContactOperation(hContact, operationParam, operationCallback, 0); + + servlistMutex->Leave(); + + if (bDoInline) + { // not postponed, called directly if requested + (this->*callback)(hContact, wContactID, wGroupID, param, PENDING_RESULT_INLINE); + } + + return 1; // Ready +} + + +int CIcqProto::servlistPendingAddGroup(const char *pszGroup, WORD wGroupID, LPARAM param, PENDING_GROUP_CALLBACK callback, int bDoInline, LPARAM operationParam, PENDING_GROUP_CALLBACK operationCallback) +{ + int iItem; + servlistpendingitem *pItem = NULL; + + servlistMutex->Enter(); + + if ((iItem = servlistPendingFindItem(ITEM_PENDING_GROUP, NULL, pszGroup)) != -1) + pItem = servlistPendingList[iItem]; + + if (pItem) + { +#ifdef _DEBUG + NetLog_Server("Server-List: Pending group \"%s\" already in list; adding as operation.", pszGroup); +#endif + servlistPendingAddGroupOperation(pszGroup, param, callback, SPOF_AUTO_CREATE_ITEM); + + if (operationCallback) + servlistPendingAddGroupOperation(pszGroup, operationParam, operationCallback, 0); + + servlistMutex->Leave(); + + return 0; // Pending + } + +#ifdef _DEBUG + NetLog_Server("Server-List: Starting group \"%s\" operation.", pszGroup); +#endif + + pItem = (servlistpendingitem *)SAFE_MALLOC(sizeof(servlistpendingitem)); + pItem->nType = ITEM_PENDING_GROUP; + pItem->szGroup = null_strdup(pszGroup); + pItem->wGroupID = wGroupID; + + servlistPendingAddItem(pItem); + + if (operationCallback) + servlistPendingAddGroupOperation(pszGroup, operationParam, operationCallback, 0); + + servlistMutex->Leave(); + + if (bDoInline) + { // not postponed, called directly if requested + (this->*callback)(pszGroup, wGroupID, param, PENDING_RESULT_INLINE); + } + + return 1; // Ready +} + + +void CIcqProto::servlistPendingRemoveContact(HANDLE hContact, WORD wContactID, WORD wGroupID, int nResult) +{ +#ifdef _DEBUG + NetLog_Server("Server-List: %s contact %x operation.", (nResult != PENDING_RESULT_PURGE) ? "Ending" : "Purging", hContact); +#endif + + servlistpendingitem *pItem = servlistPendingRemoveItem(ITEM_PENDING_CONTACT, hContact, NULL); + + if (pItem) + { // process pending operations + if (pItem->operations) + { + for (int i = 0; i < pItem->operationsCount; i++) + { + int nCallbackState = (this->*(PENDING_CONTACT_CALLBACK)(pItem->operations[i].callback))(hContact, wContactID, wGroupID, pItem->operations[i].param, nResult); + + if (nResult != PENDING_RESULT_PURGE && nCallbackState == CALLBACK_RESULT_POSTPONE) + { // any following pending operations cannot be processed now, move them to the new pending contact + for (int j = i + 1; j < pItem->operationsCount; j++) + servlistPendingAddContactOperation(hContact, pItem->operations[j].param, (PENDING_CONTACT_CALLBACK)(pItem->operations[j].callback), pItem->operations[j].flags); + break; + } + else if (nCallbackState == CALLBACK_RESULT_PURGE) + { // purge all following operations - fatal failure occured + nResult = PENDING_RESULT_PURGE; + } + } + SAFE_FREE((void**)&pItem->operations); + } + // release item's memory + SAFE_FREE((void**)&pItem); + } + else + NetLog_Server("Server-List Error: Trying to remove a non existing pending contact."); +} + + +void CIcqProto::servlistPendingRemoveGroup(const char *pszGroup, WORD wGroupID, int nResult) +{ +#ifdef _DEBUG + NetLog_Server("Server-List: %s group \"%s\" operation.", (nResult != PENDING_RESULT_PURGE) ? "Ending" : "Purging", pszGroup); +#endif + + servlistpendingitem *pItem = servlistPendingRemoveItem(ITEM_PENDING_GROUP, NULL, pszGroup); + + if (pItem) + { // process pending operations + if (pItem->operations) + { + for (int i = 0; i < pItem->operationsCount; i++) + { + int nCallbackState = (this->*pItem->operations[i].callback)(pItem->szGroup, wGroupID, pItem->operations[i].param, nResult); + + if (nResult != PENDING_RESULT_PURGE && nCallbackState == CALLBACK_RESULT_POSTPONE) + { // any following pending operations cannot be processed now, move them to the new pending group + for (int j = i + 1; j < pItem->operationsCount; j++) + servlistPendingAddGroupOperation(pItem->szGroup, pItem->operations[j].param, pItem->operations[j].callback, pItem->operations[j].flags); + break; + } + else if (nCallbackState == CALLBACK_RESULT_PURGE) + { // purge all following operations - fatal failure occured + nResult = PENDING_RESULT_PURGE; + } + } + SAFE_FREE((void**)&pItem->operations); + } + // release item's memory + SAFE_FREE((void**)&pItem->szGroup); + SAFE_FREE((void**)&pItem); + } + else + NetLog_Server("Server-List Error: Trying to remove a non existing pending group."); +} + + +// Remove All pending operations +void CIcqProto::servlistPendingFlushOperations() +{ + icq_lock l(servlistMutex); + + for (int i = servlistPendingCount; i; i--) + { // purge all items + servlistpendingitem *pItem = servlistPendingList[i - 1]; + + if (pItem->nType == ITEM_PENDING_CONTACT) + servlistPendingRemoveContact(pItem->hContact, 0, 0, PENDING_RESULT_PURGE); + else if (pItem->nType == ITEM_PENDING_GROUP) + servlistPendingRemoveGroup(pItem->szGroup, 0, PENDING_RESULT_PURGE); + } + // release the list completely + SAFE_FREE((void**)&servlistPendingList); + servlistPendingCount = 0; + servlistPendingSize = 0; +} + +// END OF SERVER-LIST PENDING OPERATIONS +//// + + +// used for adding new contacts to list - sync with visible items +void CIcqProto::AddJustAddedContact(HANDLE hContact) +{ + icq_lock l(servlistMutex); + + if (nJustAddedCount >= nJustAddedSize) + { + nJustAddedSize += 10; + pdwJustAddedList = (HANDLE*)SAFE_REALLOC(pdwJustAddedList, nJustAddedSize * sizeof(HANDLE)); + } + + pdwJustAddedList[nJustAddedCount] = hContact; + nJustAddedCount++; +} + + +// was the contact added during this serv-list load +BOOL CIcqProto::IsContactJustAdded(HANDLE hContact) +{ + icq_lock l(servlistMutex); + + if (pdwJustAddedList) + { + for (int i = 0; iEnter(); + if (nServerIDListCount >= nServerIDListSize) + { + nServerIDListSize += 100; + pdwServerIDList = (DWORD*)SAFE_REALLOC(pdwServerIDList, nServerIDListSize * sizeof(DWORD)); + } + + pdwServerIDList[nServerIDListCount] = wID | (bGroupType & 0x00FF0000) | (bFlags & 0xFF000000); + nServerIDListCount++; + servlistMutex->Leave(); + + if (!bIsSyncingCL) + StoreServerIDs(); +} + + +// Remove a server ID from the list of reserved IDs. +// Used for deleting contacts and other modifications. +void CIcqProto::FreeServerID(WORD wID, int bGroupType) +{ + DWORD dwId = wID | (bGroupType & 0x00FF0000); + + icq_lock l(servlistMutex); + + if (pdwServerIDList) + { + for (int i = 0; i= wID) && ((pdwServerIDList[i] & 0xFFFF) <= wID + wCount)) + return TRUE; + } + } + + return FALSE; +} + +void CIcqProto::FlushServerIDs() +{ + icq_lock l(servlistMutex); + + SAFE_FREE((void**)&pdwServerIDList); + nServerIDListCount = 0; + nServerIDListSize = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct GroupReserveIdsEnumParam +{ + CIcqProto *ppro; + char *szModule; +}; + +static int GroupReserveIdsEnumProc(const char *szSetting,LPARAM lParam) +{ + if (szSetting && strlennull(szSetting)<5) + { + // it is probably server group + GroupReserveIdsEnumParam *param = (GroupReserveIdsEnumParam*)lParam; + char val[MAX_PATH+2]; // dummy + + DBVARIANT dbv = {DBVT_DELETED}; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = val; + dbv.cchVal = MAX_PATH; + + DBCONTACTGETSETTING cgs; + cgs.szModule = param->szModule; + cgs.szSetting = szSetting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) + { // we failed to read setting, try also utf8 - DB bug + dbv.type = DBVT_UTF8; + dbv.pszVal = val; + dbv.cchVal = MAX_PATH; + if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) + return 0; // we failed also, invalid setting + } + if (dbv.type != DBVT_ASCIIZ) + { // it is not a cached server-group name + return 0; + } + param->ppro->ReserveServerID((WORD)strtoul(szSetting, NULL, 0x10), SSIT_GROUP, 0); +#ifdef _DEBUG + param->ppro->NetLog_Server("Loaded group %u:'%s'", strtoul(szSetting, NULL, 0x10), val); +#endif + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Load all known server IDs from DB to list +void CIcqProto::LoadServerIDs() +{ + WORD wSrvID; + int nGroups = 0, nContacts = 0, nPermits = 0, nDenys = 0, nIgnores = 0, nUnhandled = 0; + + servlistMutex->Enter(); + if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0)) + ReserveServerID(wSrvID, SSIT_ITEM, 0); + if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, 0)) + ReserveServerID(wSrvID, SSIT_ITEM, 0); + if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0)) + ReserveServerID(wSrvID, SSIT_ITEM, 0); + if (wSrvID = getSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, 0)) + ReserveServerID(wSrvID, SSIT_ITEM, 0); + if (wSrvID = getSettingWord(NULL, "SrvImportID", 0)) + ReserveServerID(wSrvID, SSIT_ITEM, 0); + + DBCONTACTENUMSETTINGS dbces; + int nStart = nServerIDListCount; + + char szModule[MAX_PATH]; + null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); + + GroupReserveIdsEnumParam param = { this, szModule }; + dbces.pfnEnumProc = &GroupReserveIdsEnumProc; + dbces.szModule = szModule; + dbces.lParam = (LPARAM)¶m; + CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); + + nGroups = nServerIDListCount - nStart; + + HANDLE hContact = FindFirstContact(); + + while (hContact) + { // search all our contacts, reserve their server IDs + if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) + { + ReserveServerID(wSrvID, SSIT_ITEM, 0); + nContacts++; + } + if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0)) + { + ReserveServerID(wSrvID, SSIT_ITEM, 0); + nDenys++; + } + if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0)) + { + ReserveServerID(wSrvID, SSIT_ITEM, 0); + nPermits++; + } + if (wSrvID = getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0)) + { + ReserveServerID(wSrvID, SSIT_ITEM, 0); + nIgnores++; + } + + hContact = FindNextContact(hContact); + } + servlistMutex->Leave(); + + DBVARIANT dbv = {0}; + if (!getSetting(NULL, DBSETTING_SERVLIST_UNHANDLED, &dbv)) + { + int dataLen = dbv.cpbVal; + BYTE *pData = dbv.pbVal; + + while (dataLen >= 4) + { + BYTE bGroupType; + BYTE bFlags; + + unpackLEWord(&pData, &wSrvID); + unpackByte(&pData, &bGroupType); + unpackByte(&pData, &bFlags); + + ReserveServerID(wSrvID, bGroupType, bFlags); + dataLen -= 4; + nUnhandled++; + } + + ICQFreeVariant(&dbv); + } + + NetLog_Server("Loaded SSI: %d contacts, %d groups, %d permit, %d deny, %d ignore, %d unknown items.", nContacts, nGroups, nPermits, nDenys, nIgnores, nUnhandled); +} + + +void CIcqProto::StoreServerIDs() /// TODO: allow delayed +{ + BYTE *pUnhandled = NULL; + int cbUnhandled = 0; + + servlistMutex->Enter(); + if (pdwServerIDList) + for (int i = 0; i> 0x10); + ppackByte(&pUnhandled, &cbUnhandled, (pdwServerIDList[i] & 0xFF000000) >> 0x18); + } + servlistMutex->Leave(); + + if (pUnhandled) + setSettingBlob(NULL, DBSETTING_SERVLIST_UNHANDLED, pUnhandled, cbUnhandled); + else + deleteSetting(NULL, DBSETTING_SERVLIST_UNHANDLED); + + SAFE_FREE((void**)&pUnhandled); +} + + +// Generate server ID with wCount IDs free after it, for sub-groups. +WORD CIcqProto::GenerateServerID(int bGroupType, int bFlags, int wCount) +{ + WORD wId; + + while (TRUE) + { + // Randomize a new ID + // Max value is probably 0x7FFF, lowest value is probably 0x0001 (generated by Icq2Go) + // We use range 0x1000-0x7FFF. + wId = (WORD)RandRange(0x1000, 0x7FFF); + + if (!CheckServerID(wId, wCount)) + break; + } + + ReserveServerID(wId, bGroupType, bFlags); + + return wId; +} + + +/*********************************************** +* +* --- Low-level packet sending functions --- +* +*/ + +struct doubleServerItemObject +{ + WORD wAction; + icq_packet packet; +}; + +DWORD CIcqProto::icq_sendServerItem(DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wItemId, const char *szName, BYTE *pTLVs, int nTlvLength, WORD wItemType, DWORD dwOperation, DWORD dwTimeout, void **doubleObject) +{ // generic packet + icq_packet packet; + int nNameLen; + WORD wTLVlen = (WORD)nTlvLength; + + // Prepare item name length + nNameLen = strlennull(szName); + + // Build the packet + serverPacketInit(&packet, (WORD)(nNameLen + 20 + wTLVlen)); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, wAction, 0, dwCookie); + packWord(&packet, (WORD)nNameLen); + if (nNameLen) + packBuffer(&packet, (LPBYTE)szName, (WORD)nNameLen); + packWord(&packet, wGroupId); + packWord(&packet, wItemId); + packWord(&packet, wItemType); + packWord(&packet, wTLVlen); + if (wTLVlen) + packBuffer(&packet, pTLVs, wTLVlen); + + if (!doubleObject) + { // Send the packet and return the cookie + servlistPostPacket(&packet, dwCookie, dwOperation | wAction, dwTimeout); + } + else + { + if (*doubleObject) + { // Send both packets and return the cookie + doubleServerItemObject* helper = (doubleServerItemObject*)*doubleObject; + + servlistPostPacketDouble(&helper->packet, dwCookie, dwOperation | helper->wAction, dwTimeout, &packet, wAction); + SAFE_FREE(doubleObject); + } + else + { // Create helper object, return the cookie + doubleServerItemObject* helper = (doubleServerItemObject*)SAFE_MALLOC(sizeof(doubleServerItemObject)); + + if (helper) + { + helper->wAction = wAction; + memcpy(&helper->packet, &packet, sizeof(icq_packet)); + *doubleObject = helper; + } + else // memory alloc failed + return 0; + } + } + + // Force reload of server-list after change + setSettingWord(NULL, "SrvRecordCount", 0); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendServerContact(HANDLE hContact, DWORD dwCookie, WORD wAction, WORD wGroupId, WORD wContactId, DWORD dwOperation, DWORD dwTimeout, void **doubleObject) +{ + DWORD dwUin; + uid_str szUid; + icq_packet pBuffer; + char *szNick = NULL, *szNote = NULL; + BYTE *pData = NULL, *pMetaToken = NULL, *pMetaTime = NULL; + int nNickLen, nNoteLen, nDataLen = 0, nMetaTokenLen = 0, nMetaTimeLen = 0; + WORD wTLVlen; + BYTE bAuth; + int bDataTooLong = FALSE; + + // Prepare UID + if (getContactUid(hContact, &dwUin, &szUid)) + { + NetLog_Server("Buddy upload failed (UID missing)."); + return 0; + } + + bAuth = getSettingByte(hContact, "Auth", 0); + szNick = getSettingStringUtf(hContact, "CList", "MyHandle", NULL); + szNote = getSettingStringUtf(hContact, "UserInfo", "MyNotes", NULL); + + DBVARIANT dbv; + + if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &dbv)) + { + nMetaTokenLen = dbv.cpbVal; + pMetaToken = (BYTE*)_alloca(dbv.cpbVal); + memcpy(pMetaToken, dbv.pbVal, dbv.cpbVal); + + ICQFreeVariant(&dbv); + } + if (!getSetting(hContact, DBSETTING_METAINFO_TIME, &dbv)) + { + nMetaTimeLen = dbv.cpbVal; + pMetaTime = (BYTE*)_alloca(dbv.cpbVal); + for (int i = 0; i < dbv.cpbVal; i++) + pMetaTime[i] = dbv.pbVal[dbv.cpbVal - i - 1]; + + ICQFreeVariant(&dbv); + } + + if (!getSetting(hContact, DBSETTING_SERVLIST_DATA, &dbv)) + { // read additional server item data + nDataLen = dbv.cpbVal; + pData = (BYTE*)_alloca(nDataLen); + memcpy(pData, dbv.pbVal, nDataLen); + + ICQFreeVariant(&dbv); + } + + nNickLen = strlennull(szNick); + nNoteLen = strlennull(szNote); + + // Limit the strings + if (nNickLen > MAX_SSI_TLV_NAME_SIZE) + { + bDataTooLong = TRUE; + nNickLen = null_strcut(szNick, MAX_SSI_TLV_NAME_SIZE); + } + if (nNoteLen > MAX_SSI_TLV_COMMENT_SIZE) + { + bDataTooLong = TRUE; + nNoteLen = null_strcut(szNote, MAX_SSI_TLV_COMMENT_SIZE); + } + if (bDataTooLong) + { // Inform the user + /// TODO: do something with this for Manage Server-List dialog. + if (wAction != ICQ_LISTS_REMOVEFROMLIST) // do not report this when removing from list + icq_LogMessage(LOG_WARNING, LPGEN("The contact's information was too big and was truncated.")); + } + + // Build the packet + wTLVlen = (nNickLen?4+nNickLen:0) + (nNoteLen?4+nNoteLen:0) + (bAuth?4:0) + nDataLen + (nMetaTokenLen?4+nMetaTokenLen:0) + (nMetaTimeLen?4+nMetaTimeLen:0); + + // Initialize our handy data buffer + pBuffer.wPlace = 0; + pBuffer.pData = (BYTE *)_alloca(wTLVlen); + pBuffer.wLen = wTLVlen; + + if (nNickLen) + packTLV(&pBuffer, SSI_TLV_NAME, (WORD)nNickLen, (LPBYTE)szNick); // Nickname TLV + + if (nNoteLen) + packTLV(&pBuffer, SSI_TLV_COMMENT, (WORD)nNoteLen, (LPBYTE)szNote); // Comment TLV + + if (nMetaTokenLen) + packTLV(&pBuffer, SSI_TLV_METAINFO_TOKEN, (WORD)nMetaTokenLen, pMetaToken); + + if (nMetaTimeLen) + packTLV(&pBuffer, SSI_TLV_METAINFO_TIME, (WORD)nMetaTimeLen, pMetaTime); + + if (pData) + packBuffer(&pBuffer, pData, (WORD)nDataLen); + + if (bAuth) // icq5 gives this as last TLV + packDWord(&pBuffer, 0x00660000); // "Still waiting for auth" TLV + + SAFE_FREE((void**)&szNick); + SAFE_FREE((void**)&szNote); + + return icq_sendServerItem(dwCookie, wAction, wGroupId, wContactId, strUID(dwUin, szUid), pBuffer.pData, wTLVlen, SSI_ITEM_BUDDY, dwOperation, dwTimeout, doubleObject); +} + + +DWORD CIcqProto::icq_sendSimpleItem(DWORD dwCookie, WORD wAction, DWORD dwUin, char* szUID, WORD wGroupId, WORD wItemId, WORD wItemType, DWORD dwOperation, DWORD dwTimeout) +{ // for privacy items + return icq_sendServerItem(dwCookie, wAction, wGroupId, wItemId, strUID(dwUin, szUID), NULL, 0, wItemType, dwOperation, dwTimeout, NULL); +} + + +DWORD CIcqProto::icq_sendServerGroup(DWORD dwCookie, WORD wAction, WORD wGroupId, const char *szName, void *pContent, int cbContent, DWORD dwOperationFlags) +{ + WORD wTLVlen; + icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer + // I should be ashamed! ;) + + if (strlennull(szName) == 0 && wGroupId != 0) + { + NetLog_Server("Group upload failed (GroupName missing)."); + return 0; // without name we could not change the group + } + + // Calculate buffer size + wTLVlen = (cbContent?4+cbContent:0); + + // Initialize our handy data buffer + pBuffer.wPlace = 0; + pBuffer.pData = (BYTE *)_alloca(wTLVlen); + pBuffer.wLen = wTLVlen; + + if (wTLVlen) + packTLV(&pBuffer, SSI_TLV_SUBITEMS, (WORD)cbContent, (LPBYTE)pContent); // Groups TLV + + return icq_sendServerItem(dwCookie, wAction, wGroupId, 0, szName, pBuffer.pData, wTLVlen, SSI_ITEM_GROUP, SSOP_GROUP_ACTION | dwOperationFlags, 400, NULL); +} + + +DWORD CIcqProto::icq_modifyServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wAction, DWORD dwOperation, WORD wItemId, WORD wType) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + DWORD dwCookie; + + if (ack) + { + ack->dwAction = dwOperation; // remove privacy item + ack->hContact = hContact; + ack->wContactId = wItemId; + + dwCookie = AllocateCookie(CKT_SERVERLIST, wAction, hContact, ack); + } + else // cookie failed + return 0; + + return icq_sendSimpleItem(dwCookie, wAction, dwUin, szUid, 0, wItemId, wType, SSOP_ITEM_ACTION, 400); +} + + +DWORD CIcqProto::icq_removeServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType) +{ + return icq_modifyServerPrivacyItem(hContact, dwUin, szUid, ICQ_LISTS_REMOVEFROMLIST, SSA_PRIVACY_REMOVE, wItemId, wType); +} + + +DWORD CIcqProto::icq_addServerPrivacyItem(HANDLE hContact, DWORD dwUin, char *szUid, WORD wItemId, WORD wType) +{ + return icq_modifyServerPrivacyItem(hContact, dwUin, szUid, ICQ_LISTS_ADDTOLIST, SSA_PRIVACY_ADD, wItemId, wType); +} + +/***************************************** +* +* --- Contact DB Utilities --- +* +*/ + + +/// TODO: do not check by plugin version, check by ServListStructures version! +int CIcqProto::IsServerGroupsDefined() +{ + int iRes = 1; + + if (getSettingDword(NULL, "Version", 0) < 0x00030608) + { // group cache & linking data too old, flush, reload from server + char szModule[MAX_PATH]; + + // flush obsolete linking data + null_snprintf(szModule, SIZEOF(szModule), "%sGroups", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szModule); + + iRes = 0; // no groups defined, or older version + } + // store our current version + setSettingDword(NULL, "Version", ICQ_PLUG_VERSION & 0x00FFFFFF); + + return iRes; +} + + +void CIcqProto::FlushSrvGroupsCache() +{ + char szModule[MAX_PATH]; + + null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); + CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szModule); +} + + +// Look thru DB and collect all ContactIDs from a group +void* CIcqProto::collectBuddyGroup(WORD wGroupID, int *count) +{ + WORD* buf = NULL; + int cnt = 0; + HANDLE hContact; + WORD wItemID; + + hContact = FindFirstContact(); + + while (hContact) + { // search all contacts + if (wGroupID == getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0)) + { // add only buddys from specified group + wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); + + if (wItemID) + { // valid ID, add + cnt++; + buf = (WORD*)SAFE_REALLOC(buf, cnt*sizeof(WORD)); + buf[cnt-1] = wItemID; + if (!count) break; + } + } + + hContact = FindNextContact(hContact); + } + + if (count) + *count = cnt<<1; // we return size in bytes + return buf; +} + + +// Look thru DB and collect all GroupIDs +void* CIcqProto::collectGroups(int *count) +{ + WORD* buf = NULL; + int cnt = 0; + int i; + HANDLE hContact; + WORD wGroupID; + + hContact = FindFirstContact(); + + while (hContact) + { // search all contacts + if (wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0)) + { // add only valid IDs + for (i = 0; ipfnGetGroupName() +int CIcqProto::getCListGroupExists(const char *szGroup) +{ + int hGroup = 0; + CLIST_INTERFACE *clint = NULL; + + if (!szGroup) return 0; + + if (ServiceExists(MS_CLIST_RETRIEVE_INTERFACE)) + clint = (CLIST_INTERFACE*)CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, 0); + + if (clint && clint->version >= 1) + { // we've got clist interface, use it + int size = strlennull(szGroup) + 2; + TCHAR *tszGroup = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(szGroup, tszGroup, size)) + for (int i = 1; TRUE; i++) + { + TCHAR *tszGroupName = (TCHAR*)clint->pfnGetGroupName(i, NULL); + + if (!tszGroupName) break; + + if (!_tcscmp(tszGroup, tszGroupName)) + { // we have found the group + hGroup = i; + break; + } + } + } + else + { // old ansi version - no other way + int size = strlennull(szGroup) + 2; + char *aszGroup = (char*)_alloca(size); + + utf8_decode_static(szGroup, aszGroup, size); + + for (int i = 1; TRUE; i++) + { + char *paszGroup = (char*)CallService(MS_CLIST_GROUPGETNAME, i, 0); + + if (!paszGroup) break; + + if (!strcmpnull(aszGroup, paszGroup)) + { // we found the group + hGroup = i; + break; + } + } + } + + return hGroup; +} + + +int CIcqProto::moveContactToCListGroup(HANDLE hContact, const char *szGroup) +{ + int hGroup = getCListGroupHandle(szGroup); + + if (ServiceExists(MS_CLIST_CONTACTCHANGEGROUP)) + return CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, hGroup); + else /// TODO: is this neccessary ? + return setSettingStringUtf(hContact, "CList", "Group", szGroup); +} + + +// utility function which counts > on start of a server group name +static int countGroupNameLevel(const char *szGroupName) +{ + int nNameLen = strlennull(szGroupName); + int i = 0; + + while (i 0) + { // it is probably a sub-group locate parent group + WORD wParentGroupId = wGroupId; + int nParentGroupLevel; + + do + { // we look for parent group at the correct level + wParentGroupId--; + nParentGroupLevel = getServListGroupLevel(wParentGroupId); + } while ((nParentGroupLevel >= nGroupLevel) && (nParentGroupLevel != -1)); + + if (nParentGroupLevel == -1) + { // that was not a sub-group, it was just a group starting with > + setServListGroupLinkID(szGroup, wGroupId); + return szGroup; + } + + { // recursively determine parent group clist path + char *szParentGroup = getServListGroupCListPath(wParentGroupId); + + /// FIXME: properly handle ~N suffixes + szParentGroup = (char*)SAFE_REALLOC(szParentGroup, strlennull(szGroup) + strlennull(szParentGroup) + 2); + strcat(szParentGroup, "\\"); + strcat(szParentGroup, (char*)szGroup + nGroupLevel); + /* if (strstrnull(szGroup, "~")) + { // check if the ~ was not added to obtain unique servlist item name + char *szUniqueMark = strrchr(szParentGroup, '~'); + + *szUniqueMark = '\0'; + // not the same group without ~, return it + if (getServListGroupLinkID(szParentGroup) != wGroupId) + *szUniqueMark = '~'; + } */ /// FIXME: this is necessary, but needs group loading changes + SAFE_FREE((void**)&szGroup); + szGroup = szParentGroup; + + + if (getServListGroupLinkID(szGroup) == wGroupId) + { // known path, give + return szGroup; + } + else + { // unknown path, setup a link + setServListGroupLinkID(szGroup, wGroupId); + return szGroup; + } + } + } + else + { // normal group, setup a link + setServListGroupLinkID(szGroup, wGroupId); + return szGroup; + } + } + } + return NULL; +} + + +static int SrvGroupNamesEnumProc(const char *szSetting, LPARAM lParam) +{ // check server-group cache item + const char **params = (const char**)lParam; + CIcqProto *ppro = (CIcqProto*)params[0]; + char *szGroupName = ppro->getSettingStringUtf(NULL, params[3], szSetting, NULL); + + if (!strcmpnull(szGroupName, params[2])) + params[1] = szSetting; // do not need the real value, just arbitrary non-NULL + + SAFE_FREE(&szGroupName); + return 0; +} + +char* CIcqProto::getServListUniqueGroupName(const char *szGroupName, int bAlloced) +{ // enum ICQSrvGroups and create unique name if neccessary + DBCONTACTENUMSETTINGS dbces; + char szModule[MAX_PATH]; + char *pars[4]; + int uniqueID = 1; + char *szGroupNameBase = (char*)szGroupName; + char *szNewGroupName = NULL; + + if (!bAlloced) + szGroupNameBase = null_strdup(szGroupName); + null_strcut(szGroupNameBase, m_wServerListRecordNameMaxLength); + + null_snprintf(szModule, SIZEOF(szModule), "%sSrvGroups", m_szModuleName); + + do { + pars[0] = (char*)this; + pars[1] = NULL; + pars[2] = szNewGroupName ? szNewGroupName : szGroupNameBase; + pars[3] = szModule; + + dbces.pfnEnumProc = &SrvGroupNamesEnumProc; + dbces.szModule = szModule; + dbces.lParam = (LPARAM)pars; + + CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); + + if (pars[1]) + { // the groupname already exists, create another + SAFE_FREE((void**)&szNewGroupName); + + char szUnique[10]; + _itoa(uniqueID++, szUnique, 10); + null_strcut(szGroupNameBase, m_wServerListRecordNameMaxLength - strlennull(szUnique) - 1); + szNewGroupName = (char*)SAFE_MALLOC(strlennull(szUnique) + strlennull(szGroupNameBase) + 2); + if (szNewGroupName) + { + strcpy(szNewGroupName, szGroupNameBase); + strcat(szNewGroupName, "~"); + strcat(szNewGroupName, szUnique); + } + } + } while (pars[1] && szNewGroupName); + + if (szNewGroupName) + { + SAFE_FREE(&szGroupNameBase); + return szNewGroupName; + } + if (szGroupName != szGroupNameBase) + { + SAFE_FREE(&szGroupNameBase); + return (char*)szGroupName; + } + else + return szGroupNameBase; +} + + +// this is the second part of recursive event-driven procedure +int CIcqProto::servlistCreateGroup_gotParentGroup(const char *szGroup, WORD wGroupID, LPARAM param, int nResult) +{ + cookie_servlist_action* clue = (cookie_servlist_action*)param; + char *szSubGroupName = clue->szGroupName; + char *szSubGroup; + int wSubGroupLevel = -1; + WORD wSubGroupID; + + SAFE_FREE((void**)&clue); + + if (nResult == PENDING_RESULT_PURGE) + { // only cleanup + return CALLBACK_RESULT_CONTINUE; + } + + szSubGroup = (char*)SAFE_MALLOC(strlennull(szGroup) + strlennull(szSubGroupName) + 2); + if (szSubGroup) + { + strcpy(szSubGroup, szGroup); + strcat(szSubGroup, "\\"); + strcat(szSubGroup, szSubGroupName); + } + + if (nResult == PENDING_RESULT_SUCCESS) // if we got an id count level + wSubGroupLevel = getServListGroupLevel(wGroupID); + + if (wSubGroupLevel == -1) + { // something went wrong, give the id and go away + servlistPendingRemoveGroup(szSubGroup, wGroupID, PENDING_RESULT_FAILED); + + SAFE_FREE((void**)&szSubGroupName); + SAFE_FREE((void**)&szSubGroup); + return CALLBACK_RESULT_CONTINUE; + } + wSubGroupLevel++; // we are a sub-group + wSubGroupID = wGroupID + 1; + + // check if on that id is not group of the same or greater level, if yes, try next + while (CheckServerID(wSubGroupID, 0) && (getServListGroupLevel(wSubGroupID) >= wSubGroupLevel)) + { + wSubGroupID++; + } + + if (!CheckServerID(wSubGroupID, 0)) + { // the next id is free, so create our group with that id + cookie_servlist_action *ack; + DWORD dwCookie; + char *szSubGroupItem = (char*)SAFE_MALLOC(strlennull(szSubGroupName) + wSubGroupLevel + 1); + + if (szSubGroupItem) + { + int i; + + for (i=0; i < wSubGroupLevel; i++) + szSubGroupItem[i] = '>'; + + strcpy(szSubGroupItem + wSubGroupLevel, szSubGroupName); + szSubGroupItem[strlennull(szSubGroupName) + wSubGroupLevel] = '\0'; + SAFE_FREE((void**)&szSubGroupName); + // check and create unique group name (Miranda does allow more subgroups with the same name!) + szSubGroupItem = getServListUniqueGroupName(szSubGroupItem, TRUE); + + if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) + { // we have cookie good, go on +#ifdef _DEBUG + NetLog_Server("Server-List: Creating sub-group \"%s\", parent group \"%s\".", szSubGroupItem, szGroup); +#endif + ReserveServerID(wSubGroupID, SSIT_GROUP, 0); + + ack->wGroupId = wSubGroupID; + ack->szGroupName = szSubGroupItem; // we need that name + ack->szGroup = szSubGroup; + ack->dwAction = SSA_GROUP_ADD; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, szSubGroupItem, NULL, 0, SSOF_BEGIN_OPERATION); + return CALLBACK_RESULT_CONTINUE; + } + SAFE_FREE((void**)&szSubGroupItem); + } + } + // we failed to create sub-group give parent groupid + icq_LogMessage(LOG_ERROR, LPGEN("Failed to create the correct sub-group, the using closest parent group.")); + + servlistPendingRemoveGroup(szSubGroup, wGroupID, PENDING_RESULT_FAILED); + + SAFE_FREE((void**)&szSubGroupName); + SAFE_FREE((void**)&szSubGroup); + return CALLBACK_RESULT_CONTINUE; +} + + +int CIcqProto::servlistCreateGroup_Ready(const char *szGroup, WORD groupID, LPARAM param, int nResult) +{ + WORD wGroupID = 0; + + if (nResult == PENDING_RESULT_PURGE) + return CALLBACK_RESULT_CONTINUE; + + if (wGroupID = getServListGroupLinkID(szGroup)) + { // the path is known, continue the process + servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_SUCCESS); + return CALLBACK_RESULT_CONTINUE; + } + + if (!strstrnull(szGroup, "\\") || m_bSsiSimpleGroups) + { // a root group can be simply created without problems; simple groups are mapped directly + cookie_servlist_action* ack; + DWORD dwCookie; + + if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) + { // we have cookie good, go on +#ifdef _DEBUG + NetLog_Server("Server-List: Creating root group \"%s\".", szGroup); +#endif + ack->wGroupId = GenerateServerID(SSIT_GROUP, 0); + ack->szGroup = null_strdup(szGroup); // we need that name + // check if the groupname is unique - just to be sure, Miranda should handle that! + ack->szGroupName = getServListUniqueGroupName(ack->szGroup, FALSE); + ack->dwAction = SSA_GROUP_ADD; + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, 0, ack); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_ADDTOLIST, ack->wGroupId, ack->szGroup, NULL, 0, SSOF_BEGIN_OPERATION); + + return CALLBACK_RESULT_POSTPONE; + } + } + else + { // this is a sub-group + char* szSub = null_strdup(szGroup); // create subgroup, recursive, event-driven, possibly relocate + cookie_servlist_action* ack; + char *szLast; + + if (strstrnull(szSub, "\\")) + { // determine parent group + szLast = strrchr(szSub, '\\') + 1; + + szLast[-1] = '\0'; + } + // make parent group id + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { + ack->szGroupName = null_strdup(szLast); // groupname + servlistCreateGroup(szSub, (LPARAM)ack, &CIcqProto::servlistCreateGroup_gotParentGroup); + SAFE_FREE((void**)&szSub); + + return CALLBACK_RESULT_POSTPONE; + } + + SAFE_FREE((void**)&szSub); + } + servlistPendingRemoveGroup(szGroup, groupID, PENDING_RESULT_FAILED); + + return CALLBACK_RESULT_CONTINUE; +} + + +// create group with this path, a bit complex task +// this supposes that all server groups are known +void CIcqProto::servlistCreateGroup(const char *szGroupPath, LPARAM param, PENDING_GROUP_CALLBACK callback) +{ + char *szGroup = (char*)szGroupPath; + + if (!strlennull(szGroup)) szGroup = DEFAULT_SS_GROUP; + + servlistPendingAddGroup(szGroup, 0, 0, &CIcqProto::servlistCreateGroup_Ready, TRUE, param, callback); +} + + +/***************************************** +* +* --- Server-List Operations --- +* +*/ + +int CIcqProto::servlistAddContact_gotGroup(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action* ack = (cookie_servlist_action*)lParam; + + if (ack) SAFE_FREE(&ack->szGroup); + + if (nResult == PENDING_RESULT_PURGE) + { // only cleanup + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + if (!ack || !wGroupID) // something went wrong + { + if (ack) servlistPendingRemoveContact(ack->hContact, 0, wGroupID, PENDING_RESULT_FAILED); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); + + if (wItemID) /// TODO: redundant ??? + { // Only add the contact if it doesnt already have an ID + servlistPendingRemoveContact(ack->hContact, wItemID, wGroupID, PENDING_RESULT_SUCCESS); + NetLog_Server("Failed to add contact to server side list (%s)", "already there"); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + wItemID = GenerateServerID(SSIT_ITEM, 0); + + ack->dwAction = SSA_CONTACT_ADD; + ack->wGroupId = wGroupID; + ack->wContactId = wItemID; + + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, ack->hContact, ack); + + icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_ADDTOLIST, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT | SSOF_BEGIN_OPERATION, 400, NULL); + + return CALLBACK_RESULT_CONTINUE; +} + + +// Need to be called when Pending Contact is active +int CIcqProto::servlistAddContact_Ready(HANDLE hContact, WORD wContactID, WORD wGroupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action* ack = (cookie_servlist_action*)lParam; + + if (nResult == PENDING_RESULT_PURGE) + { // removing obsolete items, just free the memory + SAFE_FREE((void**)&ack->szGroup); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); + + if (wItemID) + { // Only add the contact if it doesn't already have an ID + servlistPendingRemoveContact(ack->hContact, wItemID, getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0), PENDING_RESULT_SUCCESS); + NetLog_Server("Failed to add contact to server side list (%s)", "already there"); + SAFE_FREE((void**)&ack->szGroup); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + // obtain a correct groupid first + servlistCreateGroup(ack->szGroup, lParam, &CIcqProto::servlistAddContact_gotGroup); + + return CALLBACK_RESULT_POSTPONE; +} + + +// Called when contact should be added to server list, if group does not exist, create one +void CIcqProto::servlistAddContact(HANDLE hContact, const char *pszGroup) +{ + DWORD dwUin; + uid_str szUid; + cookie_servlist_action* ack; + + // Get UID + if (getContactUid(hContact, &dwUin, &szUid)) + { // Could not do anything without uid + NetLog_Server("Failed to add contact to server side list (%s)", "no UID"); + return; + } + + if (!(ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)))) + { // Could not do anything without cookie + NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed"); + return; + } + else + { + ack->hContact = hContact; + ack->szGroup = null_strdup(pszGroup); + // call thru pending operations - makes sure the contact is ready to be added + servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistAddContact_Ready, TRUE); + return; + } +} + + +int CIcqProto::servlistRemoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) +{ + WORD wGroupID; + WORD wItemID; + cookie_servlist_action* ack = (cookie_servlist_action*)lParam; + DWORD dwCookie; + + if (nResult == PENDING_RESULT_PURGE) + { + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + // Get the contact's group ID + if (!(wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0))) + { // Could not find a usable group ID + servlistPendingRemoveContact(hContact, contactID, groupID, PENDING_RESULT_FAILED); + + NetLog_Server("Failed to remove contact from server side list (%s)", "no group ID"); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + // Get the contact's item ID + if (!(wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0))) + { // Could not find usable item ID + servlistPendingRemoveContact(hContact, contactID, wGroupID, PENDING_RESULT_FAILED); + + NetLog_Server("Failed to remove contact from server side list (%s)", "no item ID"); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + ack->dwAction = SSA_CONTACT_REMOVE; + ack->hContact = hContact; + ack->wGroupId = wGroupID; + ack->wContactId = wItemID; + + dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, hContact, ack); + + icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT | SSOF_BEGIN_OPERATION, 400, NULL); + + return CALLBACK_RESULT_POSTPONE; +} + + +// Called when contact should be removed from server list, remove group if it remain empty +void CIcqProto::servlistRemoveContact(HANDLE hContact) +{ + DWORD dwUin; + uid_str szUid; + cookie_servlist_action* ack; + + // Get UID + if (getContactUid(hContact, &dwUin, &szUid)) + { + // Could not do anything without uid + NetLog_Server("Failed to remove contact from server side list (%s)", "no UID"); + return; + } + + if (!(ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)))) + { // Could not do anything without cookie + NetLog_Server("Failed to remove contact from server side list (%s)", "malloc failed"); + return; + } + else + { + ack->hContact = hContact; + // call thru pending operations - makes sure the contact is ready to be removed + servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistRemoveContact_Ready, TRUE); + return; + } +} + + +int CIcqProto::servlistMoveContact_gotTargetGroup(const char *szGroup, WORD wNewGroupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)lParam; + + if (ack) SAFE_FREE(&ack->szGroup); + + if (nResult == PENDING_RESULT_PURGE) + { // removing obsolete items, just free the memory + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + if (!ack || !wNewGroupID || !ack->hContact) // something went wrong + { + if (ack) servlistPendingRemoveContact(ack->hContact, 0, 0, PENDING_RESULT_FAILED); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); + WORD wGroupID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_GROUP, 0); + + if (!wItemID) + { // We have no ID, so try to simply add the contact to serv-list + NetLog_Server("Unable to move contact (no ItemID) -> trying to add"); + // we know the GroupID, so directly call add + return servlistAddContact_gotGroup(szGroup, wNewGroupID, lParam, nResult); + } + + if (wGroupID == wNewGroupID) + { // Only move the contact if it had different GroupID + servlistPendingRemoveContact(ack->hContact, wItemID, wNewGroupID, PENDING_RESULT_SUCCESS); + NetLog_Server("Contact not moved to group on server side list (same Group)"); + return CALLBACK_RESULT_CONTINUE; + } + + ack->szGroupName = NULL; + ack->dwAction = SSA_CONTACT_SET_GROUP; + ack->wGroupId = wGroupID; + ack->wContactId = wItemID; + ack->wNewContactId = GenerateServerID(SSIT_ITEM, 0); // icq5 recreates also this, imitate + ack->wNewGroupId = wNewGroupID; + ack->lParam = 0; // we use this as a sign + + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, ack->hContact, ack); + DWORD dwCookie2 = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_ADDTOLIST, ack->hContact, ack); + + { // imitate icq5, previously here was different order, but AOL changed and it ceased to work + void *doubleObject = NULL; + + icq_sendServerContact(ack->hContact, dwCookie2, ICQ_LISTS_ADDTOLIST, wNewGroupID, ack->wNewContactId, SSO_CONTACT_SETGROUP | SSOF_BEGIN_OPERATION, 500, &doubleObject); + icq_sendServerContact(ack->hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupID, wItemID, SSO_CONTACT_SETGROUP | SSOF_BEGIN_OPERATION, 500, &doubleObject); + } + return CALLBACK_RESULT_CONTINUE; +} + + +int CIcqProto::servlistMoveContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)lParam; + + if (nResult == PENDING_RESULT_PURGE) + { // removing obsolete items, just free the memory + SAFE_FREE(&ack->szGroup); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + WORD wItemID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_ID, 0); + WORD wGroupID = getSettingWord(ack->hContact, DBSETTING_SERVLIST_GROUP, 0); + + if (!wGroupID && wItemID) + { // Only move the contact if it had an GroupID + servlistPendingRemoveContact(ack->hContact, contactID, groupID, PENDING_RESULT_FAILED); + + NetLog_Server("Failed to move contact to group on server side list (%s)", "no Group"); + SAFE_FREE(&ack->szGroup); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + // obtain a correct target groupid first + servlistCreateGroup(ack->szGroup, lParam, &CIcqProto::servlistMoveContact_gotTargetGroup); + + return CALLBACK_RESULT_POSTPONE; +} + + +// Called when contact should be moved from one group to another, create new, remove empty +void CIcqProto::servlistMoveContact(HANDLE hContact, const char *pszNewGroup) +{ + DWORD dwUin; + uid_str szUid; + + if (!hContact) return; // we do not move us, caused our uin was wrongly added to list + + // Get UID + if (getContactUid(hContact, &dwUin, &szUid)) + { // Could not do anything without uin + NetLog_Server("Failed to move contact to group on server side list (%s)", "no UID"); + return; + } + + if ((pszNewGroup != NULL) && (pszNewGroup[0]!='\0') && !getCListGroupExists(pszNewGroup)) + { // the contact moved to non existing group, do not do anything: MetaContact hack + NetLog_Server("Contact not moved - probably hiding by MetaContacts."); + return; + } + + if (!getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) /// FIXME:::: this should be in _ready + { // the contact is not stored on the server, check if we should try to add + if (!getSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER) || + DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) + return; + } + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + if (!ack) + { // Could not do anything without cookie + NetLog_Server("Failed to add contact to server side list (%s)", "malloc failed"); + return; + } + else + { + ack->hContact = hContact; + ack->szGroup = null_strdup(pszNewGroup); + // call thru pending operations - makes sure the contact is ready to be moved + servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistMoveContact_Ready, TRUE); + return; + } +} + + +int CIcqProto::servlistUpdateContact_Ready(HANDLE hContact, WORD contactID, WORD groupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)lParam; + + if (nResult == PENDING_RESULT_PURGE) + { // removing obsolete items, just free the memory + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + WORD wItemID; + WORD wGroupID; + + // Get the contact's group ID + if (!(wGroupID = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0))) + { + servlistPendingRemoveContact(hContact, contactID, groupID, PENDING_RESULT_FAILED); + // Could not find a usable group ID + NetLog_Server("Failed to update contact's details on server side list (%s)", "no group ID"); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + // Get the contact's item ID + if (!(wItemID = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0))) + { + servlistPendingRemoveContact(hContact, contactID, wGroupID, PENDING_RESULT_FAILED); + // Could not find usable item ID + NetLog_Server("Failed to update contact's details on server side list (%s)", "no item ID"); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + ack->dwAction = SSA_CONTACT_UPDATE; + ack->wContactId = wItemID; + ack->wGroupId = wGroupID; + ack->hContact = hContact; + + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, hContact, ack); + + // There is no need to send ICQ_LISTS_CLI_MODIFYSTART or + // ICQ_LISTS_CLI_MODIFYEND when just changing nick name + icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_UPDATEGROUP, wGroupID, wItemID, SSOP_ITEM_ACTION | SSOF_CONTACT, 400, NULL); + + return CALLBACK_RESULT_POSTPONE; +} + + +// Is called when a contact' details has been changed locally to update +// the server side details. +void CIcqProto::servlistUpdateContact(HANDLE hContact) +{ + DWORD dwUin; + uid_str szUid; + + // Get UID + if (getContactUid(hContact, &dwUin, &szUid)) + { + // Could not set nickname on server without uid + NetLog_Server("Failed to update contact's details on server side list (%s)", "no UID"); + return; + } + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + if (!ack) + { + // Could not allocate cookie - use old fake + NetLog_Server("Failed to update contact's details on server side list (%s)", "malloc failed"); + return; + } + else + { + ack->hContact = hContact; + // call thru pending operations - makes sure the contact is ready to be updated + servlistPendingAddContact(hContact, 0, 0, (LPARAM)ack, &CIcqProto::servlistUpdateContact_Ready, TRUE); + return; + } +} + + +int CIcqProto::servlistRenameGroup_Ready(const char *szGroup, WORD wGroupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)lParam; + + if (nResult == PENDING_RESULT_PURGE) + { // only cleanup + if (ack) SAFE_FREE(&ack->szGroupName); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + if (!ack || !wGroupID) // something went wrong + { + servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_FAILED); + + if (ack) SAFE_FREE(&ack->szGroupName); + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + void *groupData; + int groupSize; + + if (groupData = collectBuddyGroup(wGroupID, &groupSize)) + { + ack->dwAction = SSA_GROUP_RENAME; + ack->wGroupId = wGroupID; + ack->szGroup = null_strdup(szGroup); // we need this name + // check if the new name is unique, create unique groupname if necessary + ack->szGroupName = getServListUniqueGroupName(ack->szGroupName, TRUE); + + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, wGroupID, ack->szGroupName, groupData, groupSize, 0); + SAFE_FREE(&groupData); + } + return CALLBACK_RESULT_POSTPONE; +} + + +void CIcqProto::servlistRenameGroup(char *szGroup, WORD wGroupId, char *szNewGroup) +{ + char *szNewGroupName; + int nGroupLevel = getServListGroupLevel(wGroupId); + + if (nGroupLevel == -1) return; // we failed to prepare group + + if (!m_bSsiSimpleGroups) + { + char *szGroupName = szGroup; + int i = nGroupLevel; + while (i) + { // find correct part of grouppath + szGroupName = strstrnull(szGroupName, "\\"); + if (!szGroupName) return; // failed to get correct part of the grouppath + szGroupName++; + i--; + } + szNewGroupName = szNewGroup; + i = nGroupLevel; + while (i) + { // find correct part of new grouppath + szNewGroupName = strstrnull(szNewGroupName, "\\"); + if (!szNewGroupName) return; // failed to get correct part of the new grouppath + szNewGroupName++; + i--; + } + // truncate possible sub-groups + char *szLast = strstrnull(szGroupName, "\\"); + if (szLast) + szLast[0] = '\0'; + szLast = strstrnull(szNewGroupName, "\\"); + if (szLast) + szLast[0] = '\0'; + + // this group was not changed, nothing to rename + if (!strcmpnull(szGroupName, szNewGroupName)) return; + + szGroupName = szNewGroupName; + szNewGroupName = (char*)SAFE_MALLOC(strlennull(szGroupName) + 1 + nGroupLevel); + if (!szNewGroupName) return; // Failure + + for (i = 0; i < nGroupLevel; i++) + { // create level prefix + szNewGroupName[i] = '>'; + } + strcat(szNewGroupName, szGroupName); + } + else // simple groups do not require any conversion + szNewGroupName = null_strdup(szNewGroup); + + cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (!ack) + { // cookie failed + NetLog_Server("Error: Failed to allocate cookie"); + + SAFE_FREE(&szNewGroupName); + return; + } + // store new group name for future use + ack->szGroupName = szNewGroupName; + // call thru pending operations - makes sure the group is ready for rename + servlistPendingAddGroup(szGroup, wGroupId, (LPARAM)ack, &CIcqProto::servlistRenameGroup_Ready, TRUE); +} + + +int CIcqProto::servlistRemoveGroup_Ready(const char *szGroup, WORD groupID, LPARAM lParam, int nResult) +{ + cookie_servlist_action *ack = (cookie_servlist_action*)lParam; + + if (nResult == PENDING_RESULT_PURGE) + { // only cleanup + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + WORD wGroupID = getServListGroupLinkID(szGroup); + char *szGroupName; + + if (wGroupID && (szGroupName = getServListGroupName(wGroupID))) + { // the group is valid, check if it is empty + void *groupData = collectBuddyGroup(wGroupID, NULL); + + if (groupData) + { // the group is not empty, cannot delete + SAFE_FREE(&groupData); + SAFE_FREE(&szGroupName); + // end operation + servlistPendingRemoveGroup(szGroup, wGroupID, PENDING_RESULT_SUCCESS); + // cleanup + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; + } + + if (!CheckServerID((WORD)(wGroupID+1), 0) || getServListGroupLevel((WORD)(wGroupID+1)) == 0) + { // is next id an sub-group, if yes, we cannot delete this group + ack->dwAction = SSA_GROUP_REMOVE; + ack->wContactId = 0; + ack->wGroupId = wGroupID; + ack->hContact = NULL; + ack->szGroup = null_strdup(szGroup); // we need that name + ack->szGroupName = szGroupName; + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_REMOVEFROMLIST, 0, ack); + + icq_sendServerGroup(dwCookie, ICQ_LISTS_REMOVEFROMLIST, ack->wGroupId, ack->szGroupName, NULL, 0, 0); + } + return CALLBACK_RESULT_POSTPONE; + } + // end operation + servlistPendingRemoveGroup(szGroup, groupID, PENDING_RESULT_SUCCESS); + // cleanup + SAFE_FREE((void**)&ack); + return CALLBACK_RESULT_CONTINUE; +} + + +void CIcqProto::servlistRemoveGroup(const char *szGroup, WORD wGroupId) +{ + if (!szGroup) return; + + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + if (!ack) + { // cookie failed + NetLog_Server("Error: Failed to allocate cookie"); + return; + } + + // call thru pending operations - makes sure the group is ready for removal + servlistPendingAddGroup(szGroup, wGroupId, (LPARAM)ack, &CIcqProto::servlistRemoveGroup_Ready, TRUE); +} + + +/*void CIcqProto::servlistMoveGroup(const char *szGroup, WORD wNewGroupId) +{ +// relocate the group +}*/ + + +void CIcqProto::resetServContactAuthState(HANDLE hContact, DWORD dwUin) +{ + WORD wContactId = getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); + WORD wGroupId = getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); + + if (wContactId && wGroupId) + { + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + if (ack) + { // we have cookie good, go on + ack->hContact = hContact; + ack->wContactId = wContactId; + ack->wGroupId = wGroupId; + ack->dwAction = SSA_CONTACT_FIX_AUTH; + + DWORD dwCookie = AllocateCookie(CKT_SERVERLIST, 0, hContact, ack); + + { + void *doubleObject = NULL; + + icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_REMOVEFROMLIST, wGroupId, wContactId, SSO_CONTACT_FIXAUTH | SSOF_BEGIN_OPERATION | SSOF_END_OPERATION, 200, &doubleObject); + deleteSetting(hContact, DBSETTING_METAINFO_TOKEN); + deleteSetting(hContact, DBSETTING_METAINFO_TIME); + deleteSetting(hContact, DBSETTING_SERVLIST_DATA); + icq_sendServerContact(hContact, dwCookie, ICQ_LISTS_ADDTOLIST, wGroupId, wContactId, SSO_CONTACT_FIXAUTH | SSOF_BEGIN_OPERATION | SSOF_END_OPERATION, 200, &doubleObject); + } + } + else + NetLog_Server("Error: Failed to allocate cookie"); + } +} + +/***************************************** +* +* --- Miranda Contactlist Hooks --- +* +*/ + +int CIcqProto::ServListDbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; + + // TODO: Queue changes that occur while offline + if (!icqOnline() || !m_bSsiEnabled || bIsSyncingCL) + return 0; + +#ifdef _DEBUG + if (cws->value.type == DBVT_DELETED) + NetLog_Server("DB-Events: Module \"%s\", setting \"%s\" deleted.", cws->szModule, cws->szSetting); + else + NetLog_Server("DB-Events: Module \"%s\", setting \"%s\" changed, data type %x.", cws->szModule, cws->szSetting, cws->value.type); +#endif + + if (!strcmpnull(cws->szModule, "CList")) + { + // Has contact been renamed? + if (!strcmpnull(cws->szSetting, "MyHandle") && + getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) + { // Update contact's details in server-list + servlistUpdateContact((HANDLE)wParam); + } + + // Has contact been moved to another group? + if (!strcmpnull(cws->szSetting, "Group") && + getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) + { // Read group from DB + char* szNewGroup = getContactCListGroup((HANDLE)wParam); + + SAFE_FREE(&szNewGroup); + } + } + else if (!strcmpnull(cws->szModule, "UserInfo")) + { + if (!strcmpnull(cws->szSetting, "MyNotes") && + getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) + { // Update contact's details in server-list + servlistUpdateContact((HANDLE)wParam); + } + } + + return 0; +} + + +int CIcqProto::ServListDbContactDeleted(WPARAM wParam, LPARAM lParam) +{ +#ifdef _DEBUG + NetLog_Server("DB-Events: Contact %x deleted.", wParam); +#endif + + DeleteFromContactsCache((HANDLE)wParam); + + if ( !icqOnline() && m_bSsiEnabled) + { // contact was deleted only locally - retrieve full list on next connect + setSettingWord((HANDLE)wParam, "SrvRecordCount", 0); + } + + if ( !icqOnline() || !m_bSsiEnabled) + return 0; + + { // we need all server contacts on local buddy list + DWORD dwUIN; + uid_str szUID; + + if (getContactUid((HANDLE)wParam, &dwUIN, &szUID)) + return 0; + + WORD wContactID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0); + WORD wGroupID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_GROUP, 0); + WORD wVisibleID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_PERMIT, 0); + WORD wInvisibleID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_DENY, 0); + WORD wIgnoreID = getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0); + + // Remove from queue for user details request + icq_DequeueUser(dwUIN); + + // Close all opened peer connections + CloseContactDirectConns((HANDLE)wParam); + + if ((wGroupID && wContactID) || wVisibleID || wInvisibleID || wIgnoreID) + { + if (wContactID) + { // delete contact from server + servlistRemoveContact((HANDLE)wParam); + } + + if (wVisibleID) + { // detete permit record + icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wVisibleID, SSI_ITEM_PERMIT); + } + + if (wInvisibleID) + { // delete deny record + icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wInvisibleID, SSI_ITEM_DENY); + } + + if (wIgnoreID) + { // delete ignore record + icq_removeServerPrivacyItem((HANDLE)wParam, dwUIN, szUID, wIgnoreID, SSI_ITEM_IGNORE); + } + } + } + + return 0; +} + + +int CIcqProto::ServListCListGroupChange(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + CLISTGROUPCHANGE *grpchg = (CLISTGROUPCHANGE*)lParam; + + if (!icqOnline() || !m_bSsiEnabled || bIsSyncingCL) + return 0; + + // only change server-list if it is allowed + if (!getSettingByte(NULL, "StoreServerDetails", DEFAULT_SS_STORE)) + return 0; + + + if (hContact == NULL) + { // change made to group + if (grpchg->pszNewName == NULL && grpchg->pszOldName != NULL) + { // group removed + char *szOldName = tchar_to_utf8(grpchg->pszOldName); + WORD wGroupId = getServListGroupLinkID(szOldName); + +#ifdef _DEBUG + NetLog_Server("CList-Events: Group %x:\"%s\" deleted.", wGroupId, szOldName); +#endif + if (wGroupId) + { // the group is known, remove from server + servlistPostPacket(NULL, 0, SSO_BEGIN_OPERATION, 100); // start server modifications here + servlistRemoveGroup(szOldName, wGroupId); + } + SAFE_FREE(&szOldName); + } + else if (grpchg->pszNewName != NULL && grpchg->pszOldName != NULL) + { // group renamed + char *szNewName = tchar_to_utf8(grpchg->pszNewName); + char *szOldName = tchar_to_utf8(grpchg->pszOldName); + WORD wGroupId = getServListGroupLinkID(szOldName); + +#ifdef _DEBUG + NetLog_Server("CList-Events: Group %x:\"%s\" changed to \"%s\".", wGroupId, szOldName, szNewName); +#endif + if (wGroupId) + { // group is known, rename on server + servlistRenameGroup(szOldName, wGroupId, szNewName); + } + SAFE_FREE(&szOldName); + SAFE_FREE(&szNewName); + } + } + else + { // change to contact + if (IsICQContact(hContact)) + { // our contact, fine move on the server as well + char *szNewName = grpchg->pszNewName ? tchar_to_utf8(grpchg->pszNewName) : NULL; + +#ifdef _DEBUG + NetLog_Server("CList-Events: Contact %x moved to group \"%s\".", hContact, szNewName); +#endif + servlistMoveContact(hContact, szNewName); + SAFE_FREE(&szNewName); + } + } + return 0; +} diff --git a/protocols/IcqOscarJ/src/icq_servlist.h b/protocols/IcqOscarJ/src/icq_servlist.h new file mode 100644 index 0000000000..76118ce3c0 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_servlist.h @@ -0,0 +1,172 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQ_SERVLIST_H +#define __ICQ_SERVLIST_H + +// actions: +#define SSA_CHECK_ROSTER 0 // request serv-list +#define SSA_VISIBILITY 1 // update visibility +#define SSA_CONTACT_UPDATE 2 // update contact's details +#define SSA_GROUP_RENAME 5 // rename group +#define SSA_PRIVACY_ADD 0xA // add privacy item +#define SSA_PRIVACY_REMOVE 0xB // remove privacy item +#define SSA_CONTACT_ADD 0x10 // add contact w/o auth +#define SSA_CONTACT_SET_GROUP 0x12 // move to group +#define SSA_CONTACT_REMOVE 0x13 // delete contact +#define SSA_CONTACT_FIX_AUTH 0x40 // reuploading contact for auth re-request +#define SSA_GROUP_ADD 0x15 // create group +#define SSA_GROUP_REMOVE 0x16 // delete group +#define SSA_GROUP_UPDATE 0x17 // update group +#define SSA_SERVLIST_ACK 0x20 // send proto ack only (UploadUI) +#define SSA_SETAVATAR 0x30 +#define SSA_REMOVEAVATAR 0x31 +#define SSA_IMPORT 7 +#define SSA_ACTION_GROUP 0x80 // grouped action + +struct CIcqProto; +// callback prototypes for pending operation mechanism: +typedef int (__cdecl CIcqProto::*PENDING_GROUP_CALLBACK)(const char* pszGroup, WORD wGroupId, LPARAM lParam, int nResult); +typedef int (__cdecl CIcqProto::*PENDING_CONTACT_CALLBACK)(HANDLE hContact, WORD wContactId, WORD wGroupId, LPARAM lParam, int nResult); + +// cookie struct for SSI actions +struct cookie_servlist_action +{ + HANDLE hContact; + char *szGroup; + WORD wContactId; + WORD wGroupId; + char *szGroupName; + WORD wNewContactId; + WORD wNewGroupId; + int dwAction; + LPARAM lParam; + int dwGroupCount; + cookie_servlist_action **pGroupItems; +}; + +// server id type groups +#define SSIT_ITEM 0x00000000 +#define SSIT_GROUP 0x00010000 + +// server id flags +#define SSIF_UNHANDLED 0x01000000 + + +// pending operations +#define PENDING_RESULT_SUCCESS 0x00 +#define PENDING_RESULT_INLINE 0x01 +#define PENDING_RESULT_FAILED 0x0F +#define PENDING_RESULT_PURGE 0x10 + +// serv-list update board +#define SSOG_SINGLE 0x00010000 +#define SSOG_DOUBLE 0x00020000 + +#define SSOF_CONTACT 0x00800000 +#define SSOF_BEGIN_OPERATION 0x00100000 +#define SSOF_END_OPERATION 0x00200000 +#define SSOF_IMPORT_OPERATION 0x00400000 + +#define SSOP_ITEM_ACTION 0x01000000 | SSOG_SINGLE +// SSA_PRIVACY_ADD +// SSA_CONTACT_ADD +// SSA_CONTACT_UPDATE +// SSA_VISIBILITY +// SSA_PRIVACY_REMOVE +// SSA_CONTACT_REMOVE +// SSA_SETAVATAR +// SSA_REMOVEAVATAR +#define SSOP_GROUP_ACTION 0x02000000 | SSOG_SINGLE +// SSA_GROUP_ADD +// SSA_GROUP_RENAME +// SSA_GROUP_UPDATE +// SSA_GROUP_REMOVE +#define SSO_CONTACT_SETGROUP 0x04000000 | SSOG_DOUBLE +// SSA_CONTACT_SET_GROUP +#define SSO_CONTACT_FIXAUTH 0x06000000 | SSOG_DOUBLE +// SSA_CONTACT_FIX_AUTH + +#define SSO_BEGIN_OPERATION 0x80000000 +#define SSO_END_OPERATION 0x40000000 + +#define SSOF_SEND_DIRECTLY 0x10000000 + +#define SSOF_ACTIONMASK 0x0000FFFF +#define SSOF_GROUPINGMASK 0x0F0FFFFF + + +#define MAX_SERVLIST_PACKET_ITEMS 200 + +// server-list request handler item +struct servlistgroupitem +{ // generic parent + DWORD dwOperation; + cookie_servlist_action* cookie; + icq_packet packet; + // perhaps add some dummy bytes +}; + +struct servlistgroupitemdouble: public servlistgroupitem +{ + icq_packet packet2; + WORD wAction2; +}; + +struct ssiqueueditems +{ + time_t tAdded; + int dwTimeout; + int nItems; + servlistgroupitem* pItems[MAX_SERVLIST_PACKET_ITEMS]; +}; + + +// cookie structs for pending records +struct servlistpendingoperation +{ + DWORD flags; + PENDING_GROUP_CALLBACK callback; + LPARAM param; +}; + +struct servlistpendingitem +{ + int nType; + HANDLE hContact; + char* szGroup; + WORD wContactID; + WORD wGroupID; + + servlistpendingoperation* operations; + int operationsCount; +}; + + +#endif /* __ICQ_SERVLIST_H */ diff --git a/protocols/IcqOscarJ/src/icq_uploadui.cpp b/protocols/IcqOscarJ/src/icq_uploadui.cpp new file mode 100644 index 0000000000..f5e5c937b3 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_uploadui.cpp @@ -0,0 +1,1019 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Implements Manage Server List dialog +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +static int bListInit = 0; +static HANDLE hItemAll; +static int dwUploadDelay = 1000; // initial setting, it is too low for icq server but good for short updates + +static HWND hwndUploadContacts=NULL; +static const UINT settingsControls[]={IDOK}; + +static WORD* pwGroupIds = NULL; +static int cbGroupIds = 0; + +// Init default clist options +static void ResetCListOptions(HWND hwndList) +{ + int i; + + SendMessage(hwndList, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP)NULL); + SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(hwndList, CLM_SETLEFTMARGIN, 2, 0); + SendMessage(hwndList, CLM_SETINDENT, 10, 0); + for(i=0; i<=FONTID_MAX; i++) + SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); + SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList, GWL_STYLE)|CLS_SHOWHIDDEN); + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS) // hide empty groups + SendMessage(hwndList, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0); +} + +// Selects the "All contacts" checkbox if all other list entries +// are selected, deselects it if not. +static void UpdateAllContactsCheckmark(HWND hwndList, CIcqProto* ppro, HANDLE phItemAll) +{ + int check = 1; + + HANDLE hContact = ppro->FindFirstContact(); + while (hContact) + { + HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + if (!SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) + { // if any of our contacts is unchecked, uncheck all contacts as well + check = 0; + break; + } + } + hContact = ppro->FindNextContact(hContact); + } + + SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)phItemAll, check); +} + +// Loop over all contacts and update the checkmark +// that indicates wether or not they are already uploaded +static int UpdateCheckmarks(HWND hwndList, CIcqProto* ppro, HANDLE phItemAll) +{ + int bAll = 1; + bListInit = 1; // lock CLC events + + HANDLE hContact = ppro->FindFirstContact(); + while (hContact) + { + HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + if (ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0)) + SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)hItem, 1); + else + bAll = 0; + } + hContact = ppro->FindNextContact(hContact); + } + + // Update the "All contacts" checkmark + if (phItemAll) + SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)phItemAll, bAll); + + bListInit = 0; + + return bAll; +} + +static void DeleteOtherContactsFromControl(HWND hCtrl, CIcqProto* ppro) +{ + HANDLE hContact; + HANDLE hItem; + + hContact = db_find_first(); + while (hContact) + { + hItem = (HANDLE)SendMessage(hCtrl, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + if (!ppro->IsICQContact(hContact)) + SendMessage(hCtrl, CLM_DELETEITEM, (WPARAM)hItem, 0); + } + hContact = db_find_next(hContact); + } +} + +static void AppendToUploadLog(HWND hwndDlg, const char *fmt, ...) +{ + va_list va; + char szText[1024]; + int iItem; + + va_start(va, fmt); + mir_vsnprintf(szText, sizeof(szText), fmt, va); + va_end(va); + + iItem = ListBoxAddStringUtf(GetDlgItem(hwndDlg, IDC_LOG), szText); + SendDlgItemMessage(hwndDlg, IDC_LOG, LB_SETTOPINDEX, iItem, 0); +} + +static void DeleteLastUploadLogLine(HWND hwndDlg) +{ + SendDlgItemMessage(hwndDlg, IDC_LOG, LB_DELETESTRING, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, 0); +} + +static void GetLastUploadLogLine(HWND hwndDlg, char *szBuf, size_t cbBuf) +{ + WCHAR str[MAX_PATH]; + SendDlgItemMessageW(hwndDlg, IDC_LOG, LB_GETTEXT, SendDlgItemMessage(hwndDlg, IDC_LOG, LB_GETCOUNT, 0, 0)-1, (LPARAM)str); + make_utf8_string_static(str, szBuf, cbBuf); +} + +static int GroupEnumIdsEnumProc(const char *szSetting,LPARAM lParam) +{ + if (szSetting && strlennull(szSetting)<5) + { // it is probably server group + char val[MAX_PATH+2]; // dummy + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = val; + dbv.cchVal = MAX_PATH; + + cgs.szModule=(char*)lParam; + cgs.szSetting=szSetting; + cgs.pValue=&dbv; + if(CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)NULL,(LPARAM)&cgs)) + return 0; // this converts all string types to DBVT_ASCIIZ + if(dbv.type!=DBVT_ASCIIZ) + { // it is not a cached server-group name + return 0; + } + pwGroupIds = (WORD*)SAFE_REALLOC(pwGroupIds, (cbGroupIds+1)*sizeof(WORD)); + pwGroupIds[cbGroupIds] = (WORD)strtoul(szSetting, NULL, 0x10); + cbGroupIds++; + } + return 0; +} + +static void enumServerGroups(CIcqProto* ppro) +{ + DBCONTACTENUMSETTINGS dbces; + + char szModule[MAX_PATH+9]; + + strcpy(szModule, ppro->m_szModuleName); + strcat(szModule, "SrvGroups"); + + dbces.pfnEnumProc = &GroupEnumIdsEnumProc; + dbces.szModule = szModule; + dbces.lParam = (LPARAM)szModule; + + CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&dbces); +} + +static DWORD sendUploadGroup(CIcqProto* ppro, WORD wAction, WORD wGroupId, char* szItemName) +{ + DWORD dwCookie; + cookie_servlist_action* ack; + + if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) + { // we have cookie good, go on + ack->wGroupId = wGroupId; + ack->dwAction = SSA_SERVLIST_ACK; + dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, wAction, 0, ack); + ack->lParam = dwCookie; + + ppro->icq_sendServerGroup(dwCookie, wAction, ack->wGroupId, szItemName, NULL, 0, 0); + return dwCookie; + } + return 0; +} + +static DWORD sendUploadBuddy(CIcqProto* ppro, HANDLE hContact, WORD wAction, DWORD dwUin, char *szUID, WORD wContactId, WORD wGroupId, WORD wItemType) +{ + DWORD dwCookie; + cookie_servlist_action* ack; + + if (ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action))) + { // we have cookie good, go on + ack->hContact = hContact; + ack->wContactId = wContactId; + ack->wGroupId = wGroupId; + ack->dwAction = SSA_SERVLIST_ACK; + dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, wAction, hContact, ack); + ack->lParam = dwCookie; + + if (wItemType == SSI_ITEM_BUDDY) + ppro->icq_sendServerContact(hContact, dwCookie, wAction, ack->wGroupId, ack->wContactId, SSOP_ITEM_ACTION | SSOF_CONTACT, 500, NULL); + else + ppro->icq_sendSimpleItem(dwCookie, wAction, dwUin, szUID, ack->wGroupId, ack->wContactId, wItemType, SSOP_ITEM_ACTION, 500); + + return dwCookie; + } + return 0; +} + +static char* getServerResultDesc(int wCode) +{ + switch (wCode) + { + case 0: return LPGEN("OK"); + case 2: return LPGEN("NOT FOUND"); + case 3: return LPGEN("ALREADY EXISTS"); + case 0xA: return LPGEN("INVALID DATA"); + case 0xC: return LPGEN("LIST FULL"); + default: return LPGEN("FAILED"); + } +} + +#define ACTION_NONE 0 +#define ACTION_ADDBUDDY 1 +#define ACTION_ADDBUDDYAUTH 2 +#define ACTION_REMOVEBUDDY 3 +#define ACTION_ADDGROUP 4 +#define ACTION_REMOVEGROUP 5 +#define ACTION_UPDATESTATE 6 +#define ACTION_MOVECONTACT 7 +#define ACTION_ADDVISIBLE 8 +#define ACTION_REMOVEVISIBLE 9 +#define ACTION_ADDINVISIBLE 10 +#define ACTION_REMOVEINVISIBLE 11 + +#define STATE_READY 1 +#define STATE_REGROUP 2 +#define STATE_ITEMS 3 +#define STATE_VISIBILITY 5 +#define STATE_CONSOLIDATE 4 + +#define M_PROTOACK (WM_USER+100) +#define M_UPLOADMORE (WM_USER+101) +#define M_INITCLIST (WM_USER+102) + +static INT_PTR CALLBACK DlgProcUploadList(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam) +{ + CIcqProto* ppro = (CIcqProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + static int working; + static HANDLE hProtoAckHook; + static int currentSequence; + static int currentAction; + static int currentState; + static HANDLE hCurrentContact; + static int lastAckResult = 0; + static WORD wNewContactId; + static WORD wNewGroupId; + static char *szNewGroupName; + static WORD wNewVisibilityId; + + switch(message) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + { + char str[MAX_PATH]; + + working = 0; + hProtoAckHook = NULL; + currentState = STATE_READY; + + ResetCListOptions(GetDlgItem(hwndDlg, IDC_CLIST)); + + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Select contacts you want to store on server."), str, MAX_PATH)); + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Ready..."), str, MAX_PATH)); + } + return TRUE; + + // The M_PROTOACK message is received when the + // server has responded to our last update packet + case M_PROTOACK: + { + int bMulti = 0; + ACKDATA *ack = (ACKDATA*)lParam; + char szLastLogLine[MAX_PATH]; + char str[MAX_PATH]; + + // Is this an ack we are waiting for? + if (strcmpnull(ack->szModule, ppro->m_szModuleName)) + break; + + if (ack->type == ICQACKTYPE_RATEWARNING) + { // we are sending tooo fast, slow down the process + if (ack->hProcess != (HANDLE)1) break; // check class + if (ack->lParam == 2 || ack->lParam == 3) // check status + { + GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); + DeleteLastUploadLogLine(hwndDlg); + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Server rate warning -> slowing down the process."), str, MAX_PATH)); + AppendToUploadLog(hwndDlg, szLastLogLine); + + dwUploadDelay *= 2; + + break; + } + if (ack->lParam == 4) dwUploadDelay /= 2; // the rate is ok, turn up + } + + if (ack->type != ICQACKTYPE_SERVERCLIST) + break; + + if ((int)ack->hProcess != currentSequence) + break; + + lastAckResult = ack->result == ACKRESULT_SUCCESS ? 0 : 1; + + switch (currentAction) { + case ACTION_ADDBUDDY: + if (ack->result == ACKRESULT_SUCCESS) + { + ppro->setSettingByte(hCurrentContact, "Auth", 0); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); + break; + } + else + { // If the server refused to add the contact without authorization, + // we try again _with_ authorization TLV + DWORD dwUIN; + uid_str szUID; + + ppro->setSettingByte(hCurrentContact, "Auth", 1); + + if (!ppro->getContactUid(hCurrentContact, &dwUIN, &szUID)) + { + currentAction = ACTION_ADDBUDDYAUTH; + currentSequence = sendUploadBuddy(ppro, hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUIN, szUID, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); + } + + return FALSE; + } + + case ACTION_ADDBUDDYAUTH: + if (ack->result == ACKRESULT_SUCCESS) + { + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); + } + else + { + ppro->deleteSetting(hCurrentContact, "Auth"); + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + } + + break; + + case ACTION_REMOVEBUDDY: + if (ack->result == ACKRESULT_SUCCESS) + { // clear obsolete settings + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + ppro->deleteSetting(hCurrentContact, DBSETTING_SERVLIST_ID); + ppro->deleteSetting(hCurrentContact, DBSETTING_SERVLIST_GROUP); + ppro->deleteSetting(hCurrentContact, "Auth"); + } + break; + + case ACTION_ADDGROUP: + if (ack->result == ACKRESULT_SUCCESS) + { + void* groupData; + int groupSize; + cookie_servlist_action* ack; + + ppro->setServListGroupName(wNewGroupId, szNewGroupName); // add group to list + ppro->setServListGroupLinkID(szNewGroupName, wNewGroupId); // grouppath is known + + groupData = ppro->collectGroups(&groupSize); + groupData = SAFE_REALLOC(groupData, groupSize+2); + *(((WORD*)groupData)+(groupSize>>1)) = wNewGroupId; // add this new group id + groupSize += 2; + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { + DWORD dwCookie; // we do not use this + + ack->dwAction = SSA_SERVLIST_ACK; + dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + + ppro->icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, 0); + } + SAFE_FREE((void**)&groupData); + } + else + ppro->FreeServerID(wNewGroupId, SSIT_GROUP); + + SAFE_FREE((void**)&szNewGroupName); + break; + + case ACTION_REMOVEGROUP: + if (ack->result == ACKRESULT_SUCCESS) + { + void* groupData; + int groupSize; + cookie_servlist_action* ack; + + ppro->FreeServerID(wNewGroupId, SSIT_GROUP); + ppro->setServListGroupName(wNewGroupId, NULL); // remove group from list + ppro->removeGroupPathLinks(wNewGroupId); // grouppath is known + + groupData = ppro->collectGroups(&groupSize); + + ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + if (ack) + { + DWORD dwCookie; // we do not use this + + ack->dwAction = SSA_SERVLIST_ACK; + dwCookie = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + + ppro->icq_sendServerGroup(dwCookie, ICQ_LISTS_UPDATEGROUP, 0, ack->szGroupName, groupData, groupSize, 0); + } + SAFE_FREE((void**)&groupData); + } + break; + + case ACTION_UPDATESTATE: + // do nothing + break; + + case ACTION_MOVECONTACT: + if (ack->result == ACKRESULT_SUCCESS) + { + ppro->FreeServerID(ppro->getSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, 0), SSIT_ITEM); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_ID, wNewContactId); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_GROUP, wNewGroupId); + dwUploadDelay *= 2; // we double the delay here (2 packets) + } + break; + + case ACTION_ADDVISIBLE: + if (ack->result == ACKRESULT_SUCCESS) + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_PERMIT, wNewContactId); + else + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + break; + + case ACTION_ADDINVISIBLE: + if (ack->result == ACKRESULT_SUCCESS) + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_DENY, wNewContactId); + else + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + break; + + case ACTION_REMOVEVISIBLE: + if (ack->result == ACKRESULT_SUCCESS) + { + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_PERMIT, 0); + } + break; + + case ACTION_REMOVEINVISIBLE: + if (ack->result == ACKRESULT_SUCCESS) + { + ppro->FreeServerID(wNewContactId, SSIT_ITEM); + ppro->setSettingWord(hCurrentContact, DBSETTING_SERVLIST_DENY, 0); + } + break; + } + + // Update the log window + GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); + DeleteLastUploadLogLine(hwndDlg); + AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine, + ICQTranslateUtfStatic(getServerResultDesc(ack->lParam), str, MAX_PATH)); + + if (!bMulti) + { + SetTimer(hwndDlg, M_UPLOADMORE, dwUploadDelay, 0); // delay + } + } + break; + + case WM_TIMER: + { + switch (wParam) + { + case M_UPLOADMORE: + KillTimer(hwndDlg, M_UPLOADMORE); + if (currentAction == ACTION_MOVECONTACT) + dwUploadDelay /= 2; // turn it back + + PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); + + return 0; + } + } + + // The M_UPLOADMORE window message is received when the user presses 'Update' + // and every time an ack from the server has been taken care of. + case M_UPLOADMORE: + { + HANDLE hContact; + HANDLE hItem; + DWORD dwUin; + uid_str szUid; + char *pszNick; + char *pszGroup; + int isChecked; + int isOnServer; + BOOL bUidOk; + char str[MAX_PATH]; + HWND hwndList = GetDlgItem(hwndDlg, IDC_CLIST); + + switch (currentState) + { + case STATE_REGROUP: + + // TODO: iterate over all checked groups and create if needed + // if creation requires reallocation of groups do it here + + currentState = STATE_ITEMS; + hCurrentContact = NULL; + PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); + break; + + case STATE_ITEMS: + // Iterate over all contacts until one is found that + // needs to be updated on the server + if (hCurrentContact == NULL) + hContact = ppro->FindFirstContact(); + else // we do not want to go thru all contacts over and over again + { + hContact = hCurrentContact; + if (lastAckResult) // if the last operation on this contact fail, do not do it again, go to next + hContact = ppro->FindNextContact(hContact); + } + + while (hContact) + { + hCurrentContact = hContact; + + hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + isChecked = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0) != 0; + isOnServer = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) != 0; + + bUidOk = !ppro->getContactUid(hContact, &dwUin, &szUid); + + // Is this one out of sync? + if (bUidOk && (isChecked != isOnServer)) + { + // Only upload custom nicks + pszNick = ppro->getSettingStringUtf(hContact, "CList", "MyHandle", NULL); + + if (isChecked) + { // Queue for uploading + pszGroup = ppro->getContactCListGroup(hContact); + if (!strlennull(pszGroup)) + pszGroup = null_strdup(DEFAULT_SS_GROUP); + + // Get group ID from cache, if not ready use parent group, if still not ready create one + wNewGroupId = ppro->getServListGroupLinkID(pszGroup); + if (!wNewGroupId && strstrnull(pszGroup, "\\") != NULL) + { // if it is sub-group, take master parent + strstrnull(pszGroup, "\\")[0] = '\0'; + wNewGroupId = ppro->getServListGroupLinkID(pszGroup); + } + if (!wNewGroupId && currentAction != ACTION_ADDGROUP) + { // if the group still does not exist and there was no try before, try to add group + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding group \"%s\"..."), str, MAX_PATH), pszGroup); + + wNewGroupId = ppro->GenerateServerID(SSIT_GROUP, 0); // ??? + szNewGroupName = pszGroup; + currentAction = ACTION_ADDGROUP; + currentSequence = sendUploadGroup(ppro, ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup); + SAFE_FREE(&pszNick); + + return FALSE; + } + + SAFE_FREE(&pszGroup); + + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Uploading %s..."), str, MAX_PATH), pszNick ? pszNick : strUID(dwUin, szUid)); + + currentAction = ACTION_ADDBUDDY; + + if (wNewGroupId) + { + wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); + + currentSequence = sendUploadBuddy(ppro, hCurrentContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, + wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); + SAFE_FREE(&pszNick); + + return FALSE; + } + else + { + char szLastLogLine[MAX_PATH]; + // Update the log window with the failure and continue with next contact + GetLastUploadLogLine(hwndDlg, szLastLogLine, MAX_PATH); + DeleteLastUploadLogLine(hwndDlg); + AppendToUploadLog(hwndDlg, "%s%s", szLastLogLine, ICQTranslateUtfStatic(LPGEN("FAILED"), str, MAX_PATH)); + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("No upload group available"), str, MAX_PATH)); + ppro->NetLog_Server("Upload failed, no group"); + currentState = STATE_READY; + } + } + else + { // Queue for deletion + if (pszNick) + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s..."), str, MAX_PATH), pszNick); + else + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s..."), str, MAX_PATH), strUID(dwUin, szUid)); + + wNewGroupId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); + wNewContactId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); + currentAction = ACTION_REMOVEBUDDY; + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, + wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); + } + SAFE_FREE((void**)&pszNick); + + break; + } + else if (bUidOk && isChecked) + { // the contact is and should be on server, check if it is in correct group, move otherwise + WORD wCurrentGroupId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); + + pszGroup = ppro->getContactCListGroup(hContact); + if (!strlennull(pszGroup)) + pszGroup = null_strdup(DEFAULT_SS_GROUP); + wNewGroupId = ppro->getServListGroupLinkID(pszGroup); + if (!wNewGroupId && strstrnull(pszGroup, "\\") != NULL) + { // if it is sub-group, take master parent + strstrnull(pszGroup, "\\")[0] = '\0'; + wNewGroupId = ppro->getServListGroupLinkID(pszGroup); + } + if (!wNewGroupId && currentAction != ACTION_ADDGROUP) + { // if the group still does not exist and there was no try before, try to add group + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding group \"%s\"..."), str, MAX_PATH), pszGroup); + + wNewGroupId = ppro->GenerateServerID(SSIT_GROUP, 0); + szNewGroupName = pszGroup; + currentAction = ACTION_ADDGROUP; + currentSequence = sendUploadGroup(ppro, ICQ_LISTS_ADDTOLIST, wNewGroupId, pszGroup); + + return FALSE; + } + if (wNewGroupId && (wNewGroupId != wCurrentGroupId)) + { // we have a group the contact should be in, move it + WORD wCurrentContactId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); + BYTE bAuth = ppro->getSettingByte(hContact, "Auth", 0); + + pszNick = ppro->getSettingStringUtf(hContact, "CList", "MyHandle", NULL); + + if (pszNick) + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Moving %s to group \"%s\"..."), str, MAX_PATH), pszNick, pszGroup); + else + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Moving %s to group \"%s\"..."), str, MAX_PATH), strUID(dwUin, szUid), pszGroup); + + currentAction = ACTION_MOVECONTACT; + wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); + sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wCurrentContactId, wCurrentGroupId, SSI_ITEM_BUDDY); + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, wNewGroupId, SSI_ITEM_BUDDY); + SAFE_FREE((void**)&pszNick); + SAFE_FREE((void**)&pszGroup); + + break; + } + SAFE_FREE((void**)&pszGroup); + } + } + hContact = db_find_next(hContact); + } + if (!hContact) + { + currentState = STATE_VISIBILITY; + hCurrentContact = NULL; + PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); + } + break; + + case STATE_VISIBILITY: + // Iterate over all contacts until one is found that + // needs to be updated on the server + if (hCurrentContact == NULL) + hContact = ppro->FindFirstContact(); + else // we do not want to go thru all contacts over and over again + { + hContact = hCurrentContact; + if (lastAckResult) // if the last operation on this contact fail, do not do it again, go to next + hContact = ppro->FindNextContact(hContact); + } + + while (hContact) + { + WORD wApparentMode = ppro->getSettingWord(hContact, "ApparentMode", 0); + WORD wDenyId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0); + WORD wPermitId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0); + WORD wIgnoreId = ppro->getSettingWord(hContact, DBSETTING_SERVLIST_IGNORE, 0); + + hCurrentContact = hContact; + ppro->getContactUid(hContact, &dwUin, &szUid); + + if (wApparentMode == ID_STATUS_ONLINE) + { // contact is on the visible list + if (wPermitId == 0) + { + currentAction = ACTION_ADDVISIBLE; + wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding %s to visible list..."), str, MAX_PATH), strUID(dwUin, szUid)); + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_PERMIT); + break; + } + } + if (wApparentMode == ID_STATUS_OFFLINE) + { // contact is on the invisible list + if (wDenyId == 0 && wIgnoreId == 0) + { + currentAction = ACTION_ADDINVISIBLE; + wNewContactId = ppro->GenerateServerID(SSIT_ITEM, 0); + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Adding %s to invisible list..."), str, MAX_PATH), strUID(dwUin, szUid)); + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_ADDTOLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_DENY); + break; + } + } + if (wApparentMode != ID_STATUS_ONLINE) + { // contact is not on visible list + if (wPermitId != 0) + { + currentAction = ACTION_REMOVEVISIBLE; + wNewContactId = wPermitId; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s from visible list..."), str, MAX_PATH), strUID(dwUin, szUid)); + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_PERMIT); + break; + } + } + if (wApparentMode != ID_STATUS_OFFLINE) + { // contact is not on invisible list + if (wDenyId != 0) + { + currentAction = ACTION_REMOVEINVISIBLE; + wNewContactId = wDenyId; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting %s from invisible list..."), str, MAX_PATH), strUID(dwUin, szUid)); + currentSequence = sendUploadBuddy(ppro, hContact, ICQ_LISTS_REMOVEFROMLIST, dwUin, szUid, wNewContactId, 0, SSI_ITEM_DENY); + break; + } + } + hContact = db_find_next(hContact); + } + if (!hContact) + { + currentState = STATE_CONSOLIDATE; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Cleaning groups"), str, MAX_PATH)); + EnableDlgItem(hwndDlg, IDCANCEL, FALSE); + enumServerGroups(ppro); + PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); + } + break; + + case STATE_CONSOLIDATE: // updage group data, remove redundant groups + if (currentAction == ACTION_UPDATESTATE) + DeleteLastUploadLogLine(hwndDlg); + + if (cbGroupIds) // some groups in the list + { + void* groupData; + int groupSize; + + cbGroupIds--; + wNewGroupId = pwGroupIds[cbGroupIds]; + + if (groupData = ppro->collectBuddyGroup(wNewGroupId, &groupSize)) + { // the group is still not empty, just update it + char* pszGroup = ppro->getServListGroupName(wNewGroupId); + cookie_servlist_action* ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + ack->dwAction = SSA_SERVLIST_ACK; + ack->wGroupId = wNewGroupId; + currentSequence = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + ack->lParam = currentSequence; + currentAction = ACTION_UPDATESTATE; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Updating group \"%s\"..."), str, MAX_PATH), pszGroup); + + ppro->icq_sendServerGroup(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, groupData, groupSize, 0); + + SAFE_FREE((void**)&pszGroup); + } + else // the group is empty, delete it if it does not have sub-groups + { + if (!ppro->CheckServerID((WORD)(wNewGroupId+1), 0) || ppro->getServListGroupLevel((WORD)(wNewGroupId+1)) == 0) + { // is next id an sub-group, if yes, we cannot delete this group + char *pszGroup = ppro->getServListGroupName(wNewGroupId); + currentAction = ACTION_REMOVEGROUP; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Deleting group \"%s\"..."), str, MAX_PATH), pszGroup); + currentSequence = sendUploadGroup(ppro, ICQ_LISTS_REMOVEFROMLIST, wNewGroupId, pszGroup); + SAFE_FREE((void**)&pszGroup); + } + else // update empty group + { + char *pszGroup = ppro->getServListGroupName(wNewGroupId); + cookie_servlist_action *ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action)); + + ack->dwAction = SSA_SERVLIST_ACK; + ack->wGroupId = wNewGroupId; + currentSequence = ppro->AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_UPDATEGROUP, 0, ack); + ack->lParam = currentSequence; + currentAction = ACTION_UPDATESTATE; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("Updating group \"%s\"..."), str, MAX_PATH), pszGroup); + + ppro->icq_sendServerGroup(currentSequence, ICQ_LISTS_UPDATEGROUP, wNewGroupId, pszGroup, 0, 0, 0); + + SAFE_FREE((void**)&pszGroup); + } + } + SAFE_FREE((void**)&groupData); // free the memory + } + else + { // all groups processed + SAFE_FREE((void**)&pwGroupIds); + currentState = STATE_READY; + } + break; + } + + if (currentState == STATE_READY) + { + // All contacts are in sync + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("All operations complete"), str, MAX_PATH)); + EnableDlgItem(hwndDlg, IDCANCEL, TRUE); + SetDlgItemTextUtf(hwndDlg, IDCANCEL, ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); + // end server modifications here + ppro->servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); + working = 0; + // SendMessage(hwndList, CLM_SETGREYOUTFLAGS,0,0); + UpdateCheckmarks(hwndList, ppro, hItemAll); + // EnableWindow(hwndList, FALSE); + if (hProtoAckHook) + UnhookEvent(hProtoAckHook); + } + break; + } + + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + SendDlgItemMessage(hwndDlg, IDC_LOG, LB_RESETCONTENT, 0, 0); + if (!ppro->icqOnline()) + { + char str[MAX_PATH]; + AppendToUploadLog(hwndDlg, ICQTranslateUtfStatic(LPGEN("You have to be online to sychronize the server-list !"), str, MAX_PATH)); + break; + } + working = 1; + hCurrentContact = NULL; + currentState = STATE_REGROUP; + currentAction = ACTION_NONE; + icq_ShowMultipleControls(hwndDlg, settingsControls, SIZEOF(settingsControls), SW_HIDE); + // SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0xFFFFFFFF, 0); + // InvalidateRect(GetDlgItem(hwndDlg, IDC_CLIST), NULL, FALSE); + EnableDlgItem(hwndDlg, IDC_CLIST, FALSE); + hProtoAckHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, M_PROTOACK); + // start server modifications here + ppro->servlistPostPacket(NULL, 0, SSO_BEGIN_OPERATION | SSOF_IMPORT_OPERATION, 100); + PostMessage(hwndDlg, M_UPLOADMORE, 0, 0); + break; + + case IDCANCEL: // TODO: this must be clean + DestroyWindow(hwndDlg); + break; + } + break; + + case WM_NOTIFY: + switch(((NMHDR*)lParam)->idFrom) { + case IDC_CLIST: + { + HWND hClist = GetDlgItem(hwndDlg, IDC_CLIST); + + switch(((NMHDR*)lParam)->code) { + case CLN_OPTIONSCHANGED: + ResetCListOptions(hClist); + break; + + case CLN_NEWCONTACT: + case CLN_CONTACTMOVED: + // Delete non-icq contacts + DeleteOtherContactsFromControl(hClist, ppro); + if (hItemAll) + UpdateAllContactsCheckmark(hClist, ppro, hItemAll); + break; + + case CLN_LISTREBUILT: + { + int bCheck = false; + + // Delete non-icq contacts + if ( ppro ) { + DeleteOtherContactsFromControl(hClist, ppro); + if (!bListInit) // do not enter twice + bCheck = UpdateCheckmarks(hClist, ppro, NULL); + } + + if (!hItemAll) // Add the "All contacts" item + { + CLCINFOITEM cii = {0}; + + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX; + cii.pszText = TranslateT(LPGEN("** All contacts **")); + hItemAll = (HANDLE)SendMessage(hClist, CLM_ADDINFOITEM, 0, (LPARAM)&cii); + } + + SendMessage(hClist, CLM_SETCHECKMARK, (WPARAM)hItemAll, bCheck); + } + break; + + case CLN_CHECKCHANGED: + { + NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam; + HANDLE hContact; + HANDLE hItem; + + if (bListInit) break; + + if (nm->flags&CLNF_ISINFO) + { + int check; + + check = SendMessage(hClist, CLM_GETCHECKMARK, (WPARAM)hItemAll, 0); + + hContact = ppro->FindFirstContact(); + while (hContact) + { + hItem = (HANDLE)SendMessage(hClist, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + SendMessage(hClist, CLM_SETCHECKMARK, (WPARAM)hItem, check); + hContact = ppro->FindNextContact(hContact); + } + } + else + UpdateAllContactsCheckmark(hClist, ppro, hItemAll); + } + break; + } + } + break; + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + if (hProtoAckHook) + UnhookEvent(hProtoAckHook); + if (working) + { // end server modifications here + ppro->servlistPostPacket(NULL, 0, SSO_END_OPERATION, 100); + } + hwndUploadContacts = NULL; + working = 0; + break; + } + + return FALSE; +} + +void CIcqProto::ShowUploadContactsDialog(void) +{ + if (hwndUploadContacts == NULL) + { + hItemAll = NULL; + hwndUploadContacts = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ICQUPLOADLIST), NULL, DlgProcUploadList, LPARAM(this)); + } + + SetForegroundWindow(hwndUploadContacts); +} diff --git a/protocols/IcqOscarJ/src/icq_xstatus.cpp b/protocols/IcqOscarJ/src/icq_xstatus.cpp new file mode 100644 index 0000000000..b567105dbe --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_xstatus.cpp @@ -0,0 +1,1381 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Angeli-Ka, Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Support for Custom Statuses +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" +#include "m_extraicons.h" +#include "..\icons_pack\src\resource.h" + + +extern HANDLE hExtraXStatus; + +void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow); + +BYTE CIcqProto::getContactXStatus(HANDLE hContact) +{ + if (!m_bXStatusEnabled && !m_bMoodsEnabled) + return 0; + + BYTE bXStatus = getSettingByte(hContact, DBSETTING_XSTATUS_ID, 0); + + if (bXStatus < 1 || bXStatus > XSTATUS_COUNT) return 0; + + return bXStatus; +} + + +DWORD CIcqProto::sendXStatusDetailsRequest(HANDLE hContact, int bForced) +{ + DWORD dwCookie = 0; + + if (m_bXStatusEnabled && getContactXStatus(hContact) != 0) + { // only request custom status detail when the contact has one + int nNotifyLen = 94 + UINMAXLEN; + char *szNotify = (char*)_alloca(nNotifyLen); + + null_snprintf(szNotify, nNotifyLen, "cAwaySrvAwayStat1%d", m_dwLocalUIN); + + dwCookie = SendXtrazNotifyRequest(hContact, "srvMng", szNotify, bForced); + } + return dwCookie; +} + + +DWORD CIcqProto::requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay) +{ + if (!validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY)) + return 0; // apply privacy rules + + if (!CheckContactCapabilities(hContact, CAPF_XSTATUS)) + return 0; // contact does not have xstatus + + // delay is disabled only if fired from dialog + if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && bAllowDelay) + return 0; // Contact does not support xtraz, do not request details + + struct rates_xstatus_request: public rates_queue_item { + protected: + virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) { + rates_xstatus_request *pDest = (rates_xstatus_request*)aDest; + if (!pDest) + pDest = new rates_xstatus_request(ppro, wGroup); + + pDest->bForced = bForced; + return rates_queue_item::copyItem(pDest); + }; + public: + rates_xstatus_request(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { }; + virtual ~rates_xstatus_request() { }; + + virtual void execute() { + dwCookie = ppro->sendXStatusDetailsRequest(hContact, bForced); + }; + + BOOL bForced; + DWORD dwCookie; + }; + + m_ratesMutex->Enter(); + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND); + m_ratesMutex->Leave(); + + rates_xstatus_request rr(this, wGroup); + rr.bForced = !bAllowDelay; + rr.hContact = hContact; + + // delay at least one sec if allowed + if (!handleRateItem(&rr, RQT_REQUEST, 1000, bAllowDelay)) + return rr.dwCookie; + + return -1; // delayed +} + + +static HANDLE LoadXStatusIconLibrary(TCHAR *path, const TCHAR *sub) +{ + TCHAR* p = _tcsrchr(path, '\\'); + HANDLE hLib; + + _tcscpy(p, sub); + _tcscat(p, _T("\\xstatus_ICQ.dll")); + if (hLib = LoadLibrary(path)) return hLib; + _tcscpy(p, sub); + _tcscat(p, _T("\\xstatus_icons.dll")); + if (hLib = LoadLibrary(path)) return hLib; + _tcscpy(p, _T("\\")); + return hLib; +} + +static TCHAR *InitXStatusIconLibrary(TCHAR *buf, size_t buf_size) +{ + TCHAR path[2*MAX_PATH]; + HMODULE hXStatusIconsDLL; + + // get miranda's exe path + GetModuleFileName(NULL, path, MAX_PATH); + + hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Icons")); + if (!hXStatusIconsDLL) // TODO: add "Custom Folders" support + hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Plugins")); + + if (hXStatusIconsDLL) + { + null_strcpy(buf, path, buf_size - 1); + + char ident[MAX_PATH]; + if (LoadStringA(hXStatusIconsDLL, IDS_IDENTIFY, ident, sizeof(ident)) == 0 || strcmpnull(ident, "# Custom Status Icons #")) + { // library is invalid + *buf = 0; + } + FreeLibrary(hXStatusIconsDLL); + } + else + *buf = 0; + + return buf; +} + + +HICON CIcqProto::getXStatusIcon(int bStatus, UINT flags) +{ + HICON icon = NULL; + + if (bStatus > 0 && bStatus <= XSTATUS_COUNT) + icon = hXStatusIcons[bStatus - 1]->GetIcon((flags & LR_BIGICON) != 0); + + if (flags & LR_SHARED || !icon) + return icon; + else + return CopyIcon(icon); +} + + +void CIcqProto::releaseXStatusIcon(int bStatus, UINT flags) +{ + if (bStatus > 0 && bStatus <= XSTATUS_COUNT) { + IcqIconHandle p = hXStatusIcons[bStatus - 1]; + if (p) + p->ReleaseIcon((flags & LR_BIGICON) != 0); + } +} + + +void CIcqProto::setContactExtraIcon(HANDLE hContact, int xstatus) +{ + HANDLE hIcon; + + if (hExtraXStatus == NULL) + { + if (xstatus > 0 && bXStatusExtraIconsReady < 2) + CListMW_ExtraIconsRebuild(0, 0); + + hIcon = (xstatus <= 0 ? (HANDLE)-1 : hXStatusExtraIcons[xstatus-1]); + + IconExtraColumn iec; + + iec.cbSize = sizeof(iec); + iec.hImage = hIcon; + iec.ColumnType = EXTRA_ICON_ADV1; + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); + } + else + { + hIcon = (HANDLE) -1; + + if (xstatus <= 0) + { + ExtraIcon_SetIcon(hExtraXStatus, hContact, (char *) NULL); + } + else + { + char szTemp[MAX_PATH]; + null_snprintf(szTemp, sizeof(szTemp), "%s_xstatus%d", m_szModuleName, xstatus-1); + ExtraIcon_SetIcon(hExtraXStatus, hContact, szTemp); + } + } + + NotifyEventHooks(hxstatusiconchanged, (WPARAM)hContact, (LPARAM)hIcon); +} + + +int CIcqProto::CListMW_ExtraIconsRebuild(WPARAM wParam, LPARAM lParam) +{ + if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { + for (int i = 0; i < XSTATUS_COUNT; i++) + { + hXStatusExtraIcons[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)getXStatusIcon(i + 1, LR_SHARED), 0); + releaseXStatusIcon(i + 1, 0); + } + + if (!bXStatusExtraIconsReady) + { // try to hook the events again if they did not existed during init + HookProtoEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CIcqProto::CListMW_ExtraIconsRebuild); + HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CIcqProto::CListMW_ExtraIconsApply); + } + + bXStatusExtraIconsReady = 2; + } + return 0; +} + + +int CIcqProto::CListMW_ExtraIconsApply(WPARAM wParam, LPARAM lParam) +{ + if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_SET_ICON)) + { + if (IsICQContact((HANDLE)wParam)) + { + // only apply icons to our contacts, do not mess others + DWORD bXStatus = getContactXStatus((HANDLE)wParam); + + if ((m_bXStatusEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_XSTATUS)) || + (m_bMoodsEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_STATUS_MOOD))) + setContactExtraIcon((HANDLE)wParam, bXStatus); + } + } + return 0; +} + +#define NULLCAP {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + +capstr capXStatus[XSTATUS_COUNT] = { + {0x01, 0xD8, 0xD7, 0xEE, 0xAC, 0x3B, 0x49, 0x2A, 0xA5, 0x8D, 0xD3, 0xD8, 0x77, 0xE6, 0x6B, 0x92}, + {0x5A, 0x58, 0x1E, 0xA1, 0xE5, 0x80, 0x43, 0x0C, 0xA0, 0x6F, 0x61, 0x22, 0x98, 0xB7, 0xE4, 0xC7}, + {0x83, 0xC9, 0xB7, 0x8E, 0x77, 0xE7, 0x43, 0x78, 0xB2, 0xC5, 0xFB, 0x6C, 0xFC, 0xC3, 0x5B, 0xEC}, + {0xE6, 0x01, 0xE4, 0x1C, 0x33, 0x73, 0x4B, 0xD1, 0xBC, 0x06, 0x81, 0x1D, 0x6C, 0x32, 0x3D, 0x81}, + {0x8C, 0x50, 0xDB, 0xAE, 0x81, 0xED, 0x47, 0x86, 0xAC, 0xCA, 0x16, 0xCC, 0x32, 0x13, 0xC7, 0xB7}, + {0x3F, 0xB0, 0xBD, 0x36, 0xAF, 0x3B, 0x4A, 0x60, 0x9E, 0xEF, 0xCF, 0x19, 0x0F, 0x6A, 0x5A, 0x7F}, + {0xF8, 0xE8, 0xD7, 0xB2, 0x82, 0xC4, 0x41, 0x42, 0x90, 0xF8, 0x10, 0xC6, 0xCE, 0x0A, 0x89, 0xA6}, + {0x80, 0x53, 0x7D, 0xE2, 0xA4, 0x67, 0x4A, 0x76, 0xB3, 0x54, 0x6D, 0xFD, 0x07, 0x5F, 0x5E, 0xC6}, + {0xF1, 0x8A, 0xB5, 0x2E, 0xDC, 0x57, 0x49, 0x1D, 0x99, 0xDC, 0x64, 0x44, 0x50, 0x24, 0x57, 0xAF}, + {0x1B, 0x78, 0xAE, 0x31, 0xFA, 0x0B, 0x4D, 0x38, 0x93, 0xD1, 0x99, 0x7E, 0xEE, 0xAF, 0xB2, 0x18}, + {0x61, 0xBE, 0xE0, 0xDD, 0x8B, 0xDD, 0x47, 0x5D, 0x8D, 0xEE, 0x5F, 0x4B, 0xAA, 0xCF, 0x19, 0xA7}, + {0x48, 0x8E, 0x14, 0x89, 0x8A, 0xCA, 0x4A, 0x08, 0x82, 0xAA, 0x77, 0xCE, 0x7A, 0x16, 0x52, 0x08}, + {0x10, 0x7A, 0x9A, 0x18, 0x12, 0x32, 0x4D, 0xA4, 0xB6, 0xCD, 0x08, 0x79, 0xDB, 0x78, 0x0F, 0x09}, + {0x6F, 0x49, 0x30, 0x98, 0x4F, 0x7C, 0x4A, 0xFF, 0xA2, 0x76, 0x34, 0xA0, 0x3B, 0xCE, 0xAE, 0xA7}, + {0x12, 0x92, 0xE5, 0x50, 0x1B, 0x64, 0x4F, 0x66, 0xB2, 0x06, 0xB2, 0x9A, 0xF3, 0x78, 0xE4, 0x8D}, + {0xD4, 0xA6, 0x11, 0xD0, 0x8F, 0x01, 0x4E, 0xC0, 0x92, 0x23, 0xC5, 0xB6, 0xBE, 0xC6, 0xCC, 0xF0}, + {0x60, 0x9D, 0x52, 0xF8, 0xA2, 0x9A, 0x49, 0xA6, 0xB2, 0xA0, 0x25, 0x24, 0xC5, 0xE9, 0xD2, 0x60}, + {0x63, 0x62, 0x73, 0x37, 0xA0, 0x3F, 0x49, 0xFF, 0x80, 0xE5, 0xF7, 0x09, 0xCD, 0xE0, 0xA4, 0xEE}, + {0x1F, 0x7A, 0x40, 0x71, 0xBF, 0x3B, 0x4E, 0x60, 0xBC, 0x32, 0x4C, 0x57, 0x87, 0xB0, 0x4C, 0xF1}, + {0x78, 0x5E, 0x8C, 0x48, 0x40, 0xD3, 0x4C, 0x65, 0x88, 0x6F, 0x04, 0xCF, 0x3F, 0x3F, 0x43, 0xDF}, + {0xA6, 0xED, 0x55, 0x7E, 0x6B, 0xF7, 0x44, 0xD4, 0xA5, 0xD4, 0xD2, 0xE7, 0xD9, 0x5C, 0xE8, 0x1F}, + {0x12, 0xD0, 0x7E, 0x3E, 0xF8, 0x85, 0x48, 0x9E, 0x8E, 0x97, 0xA7, 0x2A, 0x65, 0x51, 0xE5, 0x8D}, + {0xBA, 0x74, 0xDB, 0x3E, 0x9E, 0x24, 0x43, 0x4B, 0x87, 0xB6, 0x2F, 0x6B, 0x8D, 0xFE, 0xE5, 0x0F}, + {0x63, 0x4F, 0x6B, 0xD8, 0xAD, 0xD2, 0x4A, 0xA1, 0xAA, 0xB9, 0x11, 0x5B, 0xC2, 0x6D, 0x05, 0xA1}, + {0x2C, 0xE0, 0xE4, 0xE5, 0x7C, 0x64, 0x43, 0x70, 0x9C, 0x3A, 0x7A, 0x1C, 0xE8, 0x78, 0xA7, 0xDC}, + {0x10, 0x11, 0x17, 0xC9, 0xA3, 0xB0, 0x40, 0xF9, 0x81, 0xAC, 0x49, 0xE1, 0x59, 0xFB, 0xD5, 0xD4}, + {0x16, 0x0C, 0x60, 0xBB, 0xDD, 0x44, 0x43, 0xF3, 0x91, 0x40, 0x05, 0x0F, 0x00, 0xE6, 0xC0, 0x09}, + {0x64, 0x43, 0xC6, 0xAF, 0x22, 0x60, 0x45, 0x17, 0xB5, 0x8C, 0xD7, 0xDF, 0x8E, 0x29, 0x03, 0x52}, + {0x16, 0xF5, 0xB7, 0x6F, 0xA9, 0xD2, 0x40, 0x35, 0x8C, 0xC5, 0xC0, 0x84, 0x70, 0x3C, 0x98, 0xFA}, + {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0, 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}, + {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27, 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}, + {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48, 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}, + NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, + NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, + NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, + NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, + NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, + NULLCAP, NULLCAP, NULLCAP, NULLCAP}; + +const char *nameXStatus[XSTATUS_COUNT] = { + LPGEN("Angry"), // 23 + LPGEN("Taking a bath"), // 1 + LPGEN("Tired"), // 2 + LPGEN("Birthday"), // 3 + LPGEN("Drinking beer"), // 4 + LPGEN("Thinking"), // 5 + LPGEN("Eating"), // 80 + LPGEN("Watching TV"), // 7 + LPGEN("Meeting"), // 8 + LPGEN("Coffee"), // 9 + LPGEN("Listening to music"),// 10 + LPGEN("Business"), // 11 + LPGEN("Shooting"), // 12 + LPGEN("Having fun"), // 13 + LPGEN("On the phone"), // 14 + LPGEN("Gaming"), // 15 + LPGEN("Studying"), // 16 + LPGEN("Shopping"), // 0 + LPGEN("Feeling sick"), // 17 + LPGEN("Sleeping"), // 18 + LPGEN("Surfing"), // 19 + LPGEN("Internet"), // 20 + LPGEN("Working"), // 21 + LPGEN("Typing"), // 22 + LPGEN("Picnic"), // 66 + LPGEN("Cooking"), + LPGEN("Smoking"), + LPGEN("I'm high"), + LPGEN("On WC"), // 68 + LPGEN("To be or not to be"),// 77 + LPGEN("Watching pro7 on TV"), + LPGEN("Love"), // 61 + LPGEN("Hot Dog"), //6 + LPGEN("Rough"), //24 + LPGEN("Rock On"), //25 + LPGEN("Baby"), //26 + LPGEN("Soccer"), //27 + LPGEN("Pirate"), //28 + LPGEN("Cyclop"), //29 + LPGEN("Monkey"), //30 + LPGEN("Birdie"), //31 + LPGEN("Cool"), //32 + LPGEN("Evil"), //33 + LPGEN("Alien"), //34 + LPGEN("Scooter"), //35 + LPGEN("Mask"), //36 + LPGEN("Money"), //37 + LPGEN("Pilot"), //38 + LPGEN("Afro"), //39 + LPGEN("St. Patrick"), //40 + LPGEN("Headmaster"), //41 + LPGEN("Lips"), //42 + LPGEN("Ice-Cream"), //43 + LPGEN("Pink Lady"), //44 + LPGEN("Up yours"), //45 + LPGEN("Laughing"), //46 + LPGEN("Dog"), //47 + LPGEN("Candy"), //48 + LPGEN("Crazy Professor"),//50 + LPGEN("Ninja"), //51 + LPGEN("Cocktail"), //52 + LPGEN("Punch"), //53 + LPGEN("Donut"), //54 + LPGEN("Feeling Good"), //55 + LPGEN("Lollypop"), //56 + LPGEN("Oink Oink"), //57 + LPGEN("Kitty"), //58 + LPGEN("Sumo"), //59 + LPGEN("Broken hearted"),//60 + LPGEN("Free for Chat"), //62 + LPGEN("@home"), //63 + LPGEN("@work"), //64 + LPGEN("Strawberry"), //65 + LPGEN("Angel"), //67 + LPGEN("Pizza"), //69 + LPGEN("Snoring"), //70 + LPGEN("On my mobile"), //71 + LPGEN("Depressed"), //72 + LPGEN("Beetle"), //73 + LPGEN("Double Rainbow"),//74 + LPGEN("Basketball"), //75 + LPGEN("Cupid shot me"), //76 + LPGEN("Celebrating"), //78 + LPGEN("Sushi"), //79 + LPGEN("Playing"), //81 + LPGEN("Writing") //84 + }; + +const int moodXStatus[XSTATUS_COUNT] = { + 23, + 1, + 2, + 3, + 4, + 5, + 80, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 0, + 17, + 18, + 19, + 20, + 21, + 22, + 66, + -1, + -1, + -1, + 68, + 77, + -1, + 61, + 6, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 62, + 63, + 64, + 65, + 67, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 78, + 79, + 81, + 84}; + +void CIcqProto::handleXStatusCaps(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *caps, int capsize, char *moods, int moodsize) +{ + int bChanged = FALSE; + int nCustomStatusID = 0, nMoodID = 0; + + if (!m_bXStatusEnabled && !m_bMoodsEnabled) + { + ClearContactCapabilities(hContact, CAPF_STATUS_MOOD | CAPF_XSTATUS); + return; + } + int nOldXStatusID = getContactXStatus(hContact); + + if (m_bXStatusEnabled) + { + if (caps) + { // detect custom status capabilities + if (capsize > 0) + for (int i = 0; i < XSTATUS_COUNT; i++) + { + if (MatchCapability(caps, capsize, (const capstr*)capXStatus[i], BINARY_CAP_SIZE)) + { + BYTE bXStatusId = (BYTE)(i+1); + char str[MAX_PATH]; + + SetContactCapabilities(hContact, CAPF_XSTATUS); + + if (nOldXStatusID != bXStatusId) + { // only write default name when it is really needed, i.e. on Custom Status change + setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId); + setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); + deleteSetting(hContact, DBSETTING_XSTATUS_MSG); + + NetLog_Server("%s changed custom status to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); + bChanged = TRUE; + } +#ifdef _DEBUG + else + NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); +#endif + + if (getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO)) + requestXStatusDetails(hContact, TRUE); + + nCustomStatusID = bXStatusId; + + break; + } + } + + if (nCustomStatusID == 0) + { +#ifdef _DEBUG + if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_XSTATUS)) + NetLog_Server("%s has removed custom status.", strUID(dwUIN, szUID)); +#endif + ClearContactCapabilities(hContact, CAPF_XSTATUS); + } + } +#ifdef _DEBUG + else if (CheckContactCapabilities(hContact, CAPF_XSTATUS)) + { + char str[MAX_PATH]; + NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH)); + } +#endif + } + if (m_bMoodsEnabled) + { + if (moods && moodsize < 32) + { // process custom statuses (moods) from ICQ6 + if (moodsize > 0) + for (int i = 0; i < XSTATUS_COUNT; i++) + { + char szMoodId[32], szMoodData[32]; + + null_strcpy(szMoodData, moods, moodsize); + + if (moodXStatus[i] == -1) continue; + null_snprintf(szMoodId, SIZEOF(szMoodId), "0icqmood%d", moodXStatus[i]); + if (!strcmpnull(szMoodId, szMoodData)) + { + BYTE bXStatusId = (BYTE)(i+1); + char str[MAX_PATH]; + + SetContactCapabilities(hContact, CAPF_STATUS_MOOD); + + if (nCustomStatusID == 0 && nOldXStatusID != bXStatusId) + { // only write default name when it is really needed, i.e. on Custom Status change + setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId); + setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); + deleteSetting(hContact, DBSETTING_XSTATUS_MSG); + + NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); + bChanged = TRUE; + } +#ifdef _DEBUG + else if (nOldXStatusID != bXStatusId) + NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); + else + NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH)); +#endif + // cannot retrieve mood details here - need to be processed with new user details + nMoodID = bXStatusId; + + break; + } + } + + if (nMoodID == 0 && moods) + { +#ifdef _DEBUG + if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_STATUS_MOOD)) + NetLog_Server("%s has removed mood.", strUID(dwUIN, szUID)); +#endif + ClearContactCapabilities(hContact, CAPF_STATUS_MOOD); + } + } +#ifdef _DEBUG + else if (CheckContactCapabilities(hContact, CAPF_STATUS_MOOD)) + { // Mood was not changed, but contact has one, add a small log notice + char str[MAX_PATH]; + NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH)); + } +#endif + } + + if (nCustomStatusID != 0 && nMoodID != 0 && nCustomStatusID != nMoodID) + NetLog_Server("Warning: Diverse custom statuses detected, using custom status."); + + if ((nCustomStatusID == 0 && (caps || !m_bXStatusEnabled)) && (nMoodID == 0 && (moods || !m_bMoodsEnabled))) + { + if (getSettingByte(hContact, DBSETTING_XSTATUS_ID, -1) != -1) + bChanged = TRUE; + deleteSetting(hContact, DBSETTING_XSTATUS_ID); + deleteSetting(hContact, DBSETTING_XSTATUS_NAME); + deleteSetting(hContact, DBSETTING_XSTATUS_MSG); + } + + if (m_bXStatusEnabled != 10 && m_bMoodsEnabled != 10) + { + setContactExtraIcon(hContact, nCustomStatusID ? nCustomStatusID : (nMoodID ? nMoodID : (moods ? 0 : nOldXStatusID))); + + if (bChanged) + NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0); + } +} + + +void CIcqProto::updateServerCustomStatus(int fullUpdate) +{ + BYTE bXStatus = getContactXStatus(NULL); + + if (fullUpdate) + { // update client capabilities + if (m_bXStatusEnabled) + setUserInfo(); + + char szMoodData[32]; + + // prepare mood id + if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus-1] != -1) + null_snprintf(szMoodData, SIZEOF(szMoodData), "0icqmood%d", moodXStatus[bXStatus-1]); + else + szMoodData[0] = '\0'; + + SetStatusMood(szMoodData, 1500); + } + + char *szStatusNote = NULL; + + if (bXStatus && (m_bXStatusEnabled || m_bMoodsEnabled)) + { // use custom status message as status note + szStatusNote = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); + } + else + { // retrieve standard status message (e.g. custom status set to none) + char **pszMsg = MirandaStatusToAwayMsg(m_iStatus); + + m_modeMsgsMutex->Enter(); + if (pszMsg) + szStatusNote = null_strdup(*pszMsg); + m_modeMsgsMutex->Leave(); + // no default status message, set empty + if (!szStatusNote) + szStatusNote = null_strdup(""); + } + + if (szStatusNote) + SetStatusNote(szStatusNote, 1500, FALSE); + + SAFE_FREE(&szStatusNote); +} + + +static WNDPROC OldMessageEditProc; + +static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) { + case WM_CHAR: + if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) + { + PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0); + return 0; + } + if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) + { // ctrl-a + SendMessage(hwnd, EM_SETSEL, 0, -1); + return 0; + } + if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) + { // ctrl-w + SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0); + return 0; + } + if (wParam == 127 && GetKeyState(VK_CONTROL) & 0x8000) + { // ctrl-backspace + DWORD start, end; + WCHAR *text; + + SendMessage(hwnd, EM_GETSEL, (WPARAM) & end, (LPARAM) (PDWORD) NULL); + SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0); + SendMessage(hwnd, EM_GETSEL, (WPARAM) & start, (LPARAM) (PDWORD) NULL); + text = GetWindowTextUcs(hwnd); + MoveMemory(text + start, text + end, sizeof(WCHAR) * (strlennull(text) + 1 - end)); + SetWindowTextUcs(hwnd, text); + SAFE_FREE(&text); + SendMessage(hwnd, EM_SETSEL, start, start); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd); + return 0; + } + break; + } + return CallWindowProc(OldMessageEditProc,hwnd,msg,wParam,lParam); +} + +struct SetXStatusData +{ + CIcqProto* ppro; + BYTE bAction; + BYTE bXStatus; + HANDLE hContact; + HANDLE hEvent; + DWORD iEvent; + int countdown; + char* okButtonFormat; +}; + +struct InitXStatusData +{ + CIcqProto* ppro; + BYTE bAction; + BYTE bXStatus; + char* szXStatusName; + char* szXStatusMsg; + HANDLE hContact; +}; + +#define HM_PROTOACK (WM_USER+10) +static INT_PTR CALLBACK SetXStatusDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam) +{ + SetXStatusData *dat = (SetXStatusData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + char str[MAX_PATH]; + + switch(message) { + case HM_PROTOACK: + { + ACKDATA *ack = (ACKDATA*)lParam; + if (ack->type != ICQACKTYPE_XSTATUS_RESPONSE) break; + if (ack->hContact != dat->hContact) break; + if ((DWORD)ack->hProcess != dat->iEvent) break; + + ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_HIDE); + ShowDlgItem(hwndDlg, IDC_XMSG, SW_SHOW); + ShowDlgItem(hwndDlg, IDC_XTITLE, SW_SHOW); + SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); + UnhookEvent(dat->hEvent); dat->hEvent = NULL; + char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, ""); + SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText); + SAFE_FREE(&szText); + szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, ""); + SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText); + SAFE_FREE(&szText); + } + break; + + case WM_INITDIALOG: + { + InitXStatusData *init = (InitXStatusData*)lParam; + + TranslateDialogDefault(hwndDlg); + dat = (SetXStatusData*)SAFE_MALLOC(sizeof(SetXStatusData)); + dat->ppro = init->ppro; + SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat); + dat->bAction = init->bAction; + + if (!init->bAction) + { // set our xStatus + dat->bXStatus = init->bXStatus; + SendDlgItemMessage(hwndDlg, IDC_XMSG, EM_LIMITTEXT, 1024, 0); + OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc); + SetDlgItemTextUtf(hwndDlg, IDC_XMSG, init->szXStatusMsg); + + if (dat->ppro->m_bXStatusEnabled) + { // custom status enabled, prepare title edit + SendDlgItemMessage(hwndDlg, IDC_XTITLE, EM_LIMITTEXT, 256, 0); + OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc); + SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, init->szXStatusName); + } + else + { // only moods enabled, hide title, resize message edit control + ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE); + ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); + MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8); + MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65); + } + + dat->okButtonFormat = GetDlgItemTextUtf(hwndDlg,IDOK); + dat->countdown = 5; + SendMessage(hwndDlg, WM_TIMER, 0, 0); + SetTimer(hwndDlg,1,1000,0); + } + else + { // retrieve contact's xStatus + dat->hContact = init->hContact; + dat->bXStatus = dat->ppro->getContactXStatus(dat->hContact); + dat->okButtonFormat = NULL; + SendMessage(GetDlgItem(hwndDlg, IDC_XTITLE), EM_SETREADONLY, 1, 0); + SendMessage(GetDlgItem(hwndDlg, IDC_XMSG), EM_SETREADONLY, 1, 0); + + if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS) && !dat->ppro->getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO)) + { + SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Cancel"), str, MAX_PATH)); + dat->hEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_PROTOACK); + ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_SHOW); + ShowDlgItem(hwndDlg, IDC_XMSG, SW_HIDE); + ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); + dat->iEvent = dat->ppro->requestXStatusDetails(dat->hContact, FALSE); + } + else + { + SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH)); + dat->hEvent = NULL; + char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, ""); + SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText); + SAFE_FREE(&szText); + + if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_STATUS_MOOD) && !dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS)) + { // only for clients supporting just moods and not custom status + szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_STATUS_NOTE, ""); + // hide title, resize message edit control + ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE); + ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE); + MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8); + MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65); + } + else + szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, ""); + + SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText); + SAFE_FREE(&szText); + } + } + + if (dat->bXStatus) + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED | LR_BIGICON)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED)); + } + + char buf[MAX_PATH]; + char *format = GetWindowTextUtf(hwndDlg); + + null_snprintf(str, sizeof(str), format, dat->bXStatus?ICQTranslateUtfStatic(nameXStatus[dat->bXStatus-1], buf, MAX_PATH):""); + SetWindowTextUtf(hwndDlg, str); + SAFE_FREE(&format); + return TRUE; + } + case WM_TIMER: + if(dat->countdown==-1) + { + DestroyWindow(hwndDlg); + break; + } + { + null_snprintf(str,sizeof(str),dat->okButtonFormat,dat->countdown); + SetDlgItemTextUtf(hwndDlg,IDOK,str); + } + dat->countdown--; + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + DestroyWindow(hwndDlg); + break; + case IDC_XTITLE: + case IDC_XMSG: + if (!dat->bAction) + { // set our xStatus + KillTimer(hwndDlg,1); + SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("OK"), str, MAX_PATH)); + } + break; + } + break; + + case WM_DESTROY: + if (!dat->bAction) + { // set our xStatus + char szSetting[64]; + char *szValue; + + dat->ppro->setSettingByte(NULL, DBSETTING_XSTATUS_ID, dat->bXStatus); + szValue = GetDlgItemTextUtf(hwndDlg,IDC_XMSG); + null_snprintf(szSetting, 64, "XStatus%dMsg", dat->bXStatus); + dat->ppro->setSettingStringUtf(NULL, szSetting, szValue); + dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szValue); + SAFE_FREE(&szValue); + + if (dat->ppro->m_bXStatusEnabled) + { + szValue = GetDlgItemTextUtf(hwndDlg,IDC_XTITLE); + null_snprintf(szSetting, 64, "XStatus%dName", dat->bXStatus); + dat->ppro->setSettingStringUtf(NULL, szSetting, szValue); + dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szValue); + SAFE_FREE(&szValue); + + if (dat->bXStatus) + { + dat->ppro->releaseXStatusIcon(dat->bXStatus, LR_BIGICON); + dat->ppro->releaseXStatusIcon(dat->bXStatus, 0); + } + } + dat->ppro->updateServerCustomStatus(TRUE); + + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc); + if (dat->ppro->m_bXStatusEnabled) + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc); + } + if (dat->hEvent) UnhookEvent(dat->hEvent); + SAFE_FREE(&dat->okButtonFormat); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, NULL); + SAFE_FREE((void**)&dat); + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + } + return FALSE; +} + + +void CIcqProto::setXStatusEx(BYTE bXStatus, BYTE bQuiet) +{ + CLISTMENUITEM mi = {0}; + BYTE bOldXStatus = getSettingByte(NULL, DBSETTING_XSTATUS_ID, 0); + + mi.cbSize = sizeof(mi); + + if (!m_bHideXStatusUI) + { + if (bOldXStatus <= XSTATUS_COUNT) + { + mi.flags = CMIM_FLAGS; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bOldXStatus], (LPARAM)&mi); + } + + mi.flags = CMIM_FLAGS | CMIF_CHECKED; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bXStatus], (LPARAM)&mi); + } + + if (bXStatus) + { + char szSetting[64]; + char str[MAX_PATH]; + char *szName = NULL, *szMsg = NULL; + + if (m_bXStatusEnabled) + { + null_snprintf(szSetting, 64, "XStatus%dName", bXStatus); + szName = getSettingStringUtf(NULL, szSetting, ICQTranslateUtfStatic(nameXStatus[bXStatus-1], str, MAX_PATH)); + } + null_snprintf(szSetting, 64, "XStatus%dMsg", bXStatus); + szMsg = getSettingStringUtf(NULL, szSetting, ""); + + null_snprintf(szSetting, 64, "XStatus%dStat", bXStatus); + if (!bQuiet && !getSettingByte(NULL, szSetting, 0)) + { + InitXStatusData init; + init.ppro = this; + init.bAction = 0; // set + init.bXStatus = bXStatus; + init.szXStatusName = szName; + init.szXStatusMsg = szMsg; + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init); + } + else + { + setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus); + if (m_bXStatusEnabled) + setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szName); + setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szMsg); + + updateServerCustomStatus(TRUE); + } + SAFE_FREE(&szName); + SAFE_FREE(&szMsg); + } + else + { + setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus); + deleteSetting(NULL, DBSETTING_XSTATUS_NAME); + deleteSetting(NULL, DBSETTING_XSTATUS_MSG); + + updateServerCustomStatus(TRUE); + } +} + + +INT_PTR CIcqProto::menuXStatus(WPARAM wParam,LPARAM lParam,LPARAM fParam) +{ + setXStatusEx((BYTE)fParam, 0); + return 0; +} + + +void CIcqProto::InitXStatusItems(BOOL bAllowStatus) +{ + CLISTMENUITEM mi; + int i = 0, len = strlennull(m_szModuleName); + char srvFce[MAX_PATH + 64]; + char szItem[MAX_PATH + 64]; + int bXStatusMenuBuilt = 0; + + BYTE bXStatus = getContactXStatus(NULL); + + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return; + + if (!bAllowStatus) return; + + // Custom Status UI is disabled, no need to continue items' init + if (m_bHideXStatusUI || m_bHideXStatusMenu) return; + + null_snprintf(szItem, sizeof(szItem), Translate("%s Custom Status"), m_szModuleName); + mi.cbSize = sizeof(mi); + mi.pszPopupName = szItem; + mi.popupPosition = 500084000; + mi.position = 2000040000; + + for (i = 0; i <= XSTATUS_COUNT; i++) + { + null_snprintf(srvFce, sizeof(srvFce), "%s/menuXStatus%d", m_szModuleName, i); + + mi.position++; + + if (!i) + bXStatusMenuBuilt = ServiceExists(srvFce); + + if (!bXStatusMenuBuilt) + CreateProtoServiceParam(srvFce+len, &CIcqProto::menuXStatus, i); + + mi.flags = (i ? CMIF_ICONFROMICOLIB : 0) | (bXStatus == i?CMIF_CHECKED:0); + mi.icolibItem = i ? hXStatusIcons[i-1]->Handle() : NULL; + mi.pszName = i ? (char*)nameXStatus[i-1] : (char *)LPGEN("None"); + mi.pszService = srvFce; + mi.pszContactOwner = m_szModuleName; + + hXStatusItems[i] = Menu_AddStatusMenuItem(&mi); + + // CMIF_HIDDEN does not work for adding services + CListShowMenuItem(hXStatusItems[i], !(m_bHideXStatusUI || m_bHideXStatusMenu)); + } +} + + +void CIcqProto::InitXStatusIcons() +{ + if (!m_bXStatusEnabled && !m_bMoodsEnabled) + return; + + TCHAR lib[2*MAX_PATH] = {0}; + TCHAR *icon_lib = InitXStatusIconLibrary(lib, SIZEOF(lib)); + + char szSection[MAX_PATH + 64], *szAccountName = tchar_to_utf8(m_tszUserName); + null_snprintf(szSection, sizeof(szSection), "Status Icons/%s/Custom Status", szAccountName); + SAFE_FREE(&szAccountName); + + for (int i = 0; i < XSTATUS_COUNT; i++) + { + char szTemp[64]; + + null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i); + hXStatusIcons[i] = IconLibDefine(nameXStatus[i], szSection, m_szModuleName, szTemp, icon_lib, -(IDI_XSTATUS1+i)); + } + + // initialize arrays for CList custom status icons + memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); + memset(hXStatusCListIcons, -1, sizeof(hXStatusCListIcons)); +} + + +void CIcqProto::UninitXStatusIcons() +{ + for (int i = 0; i < XSTATUS_COUNT; i++) + IconLibRemove(&hXStatusIcons[i]); + + // clear clist icon state indicators + memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); +} + + +INT_PTR CIcqProto::ShowXStatusDetails(WPARAM wParam, LPARAM lParam) +{ + InitXStatusData init; + init.ppro = this; + init.bAction = 1; // retrieve + init.hContact = (HANDLE)wParam; + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init); + + return 0; +} + +INT_PTR CIcqProto::SetXStatus(WPARAM wParam, LPARAM lParam) +{ // obsolete (TODO: remove in next version) + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; + + if (wParam >= 0 && wParam <= XSTATUS_COUNT) + { + setXStatusEx((BYTE)wParam, 1); + return wParam; + } + return 0; +} + + +INT_PTR CIcqProto::GetXStatus(WPARAM wParam, LPARAM lParam) +{ // obsolete (TODO: remove in next version) + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; + + if (!icqOnline()) return 0; + + BYTE status = getContactXStatus(NULL); + + if (wParam) *((char**)wParam) = m_bXStatusEnabled ? DBSETTING_XSTATUS_NAME : NULL; + if (lParam) *((char**)lParam) = DBSETTING_XSTATUS_MSG; + + return status; +} + + +INT_PTR CIcqProto::SetXStatusEx(WPARAM wParam, LPARAM lParam) +{ + ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; + + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1; + + if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure + + if (pData->flags & CSSF_MASK_STATUS) + { // set custom status + int status = *pData->status; + + if (status >= 0 && status <= XSTATUS_COUNT) + setXStatusEx((BYTE)status, 1); + else + return 1; // Failure + } + + if (pData->flags & (CSSF_MASK_NAME | CSSF_MASK_MESSAGE)) + { + BYTE status = getContactXStatus(NULL); + + if (!status) return 1; // Failure + + if (m_bXStatusEnabled && (pData->flags & CSSF_MASK_NAME)) + { // set custom status name + if (pData->flags & CSSF_UNICODE) + setSettingStringW(NULL, DBSETTING_XSTATUS_NAME, pData->pwszName); + else + setSettingString(NULL, DBSETTING_XSTATUS_NAME, pData->pszName); + } + if (pData->flags & CSSF_MASK_MESSAGE) + { // set custom status message + if (pData->flags & CSSF_UNICODE) + setSettingStringW(NULL, DBSETTING_XSTATUS_MSG, pData->pwszMessage); + else + setSettingString(NULL, DBSETTING_XSTATUS_MSG, pData->pszMessage); + + // update status note if used for custom status message + updateServerCustomStatus(FALSE); + } + } + + if (pData->flags & CSSF_DISABLE_UI) + { // hide menu items + contact menu item + m_bHideXStatusUI = (*pData->wParam) ? 0 : 1; + } + + if (pData->flags & CSSF_DISABLE_MENU) + { // hide menu items only + m_bHideXStatusMenu = (*pData->wParam) ? 0 : 1; + } + + return 0; // Success +} + + +INT_PTR CIcqProto::GetXStatusEx(WPARAM wParam, LPARAM lParam) +{ + ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam; + HANDLE hContact = (HANDLE)wParam; + + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1; + + if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure + + if (pData->flags & CSSF_MASK_STATUS) + { // fill status member + *pData->status = getContactXStatus(hContact); + } + + if (pData->flags & CSSF_MASK_NAME) + { // fill status name member + if (pData->flags & CSSF_DEFAULT_NAME) + { + int status = *pData->wParam; + + if (status < 1 || status > XSTATUS_COUNT) return 1; // Failure + + if (pData->flags & CSSF_UNICODE) + { + char *text = (char*)nameXStatus[status -1]; + + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pData->pwszName, MAX_PATH); + } + else + strcpy(pData->pszName, (char*)nameXStatus[status - 1]); + } + else + { // moods does not support status title + if (!m_bXStatusEnabled) return 1; + + if (pData->flags & CSSF_UNICODE) + { + char *str = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ""); + WCHAR *wstr = make_unicode_string(str); + + wcscpy(pData->pwszName, wstr); + SAFE_FREE(&str); + SAFE_FREE(&wstr); + } + else + { + DBVARIANT dbv = {0}; + + if (!getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv) && dbv.pszVal) + strcpy(pData->pszName, dbv.pszVal); + else + strcpy(pData->pszName, ""); + + ICQFreeVariant(&dbv); + } + } + } + + if (pData->flags & CSSF_MASK_MESSAGE) + { // fill status message member + if (pData->flags & CSSF_UNICODE) + { + char *str = getSettingStringUtf(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, ""); + WCHAR *wstr = make_unicode_string(str); + + wcscpy(pData->pwszMessage, wstr); + SAFE_FREE(&str); + SAFE_FREE(&wstr); + } + else + { + DBVARIANT dbv = {0}; + + if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv) && dbv.pszVal) + strcpy(pData->pszMessage, dbv.pszVal); + else + strcpy(pData->pszMessage, ""); + + ICQFreeVariant(&dbv); + } + } + + if (pData->flags & CSSF_DISABLE_UI) + { + if (pData->wParam) *pData->wParam = !m_bHideXStatusUI; + } + + if (pData->flags & CSSF_DISABLE_MENU) + { + if (pData->wParam) *pData->wParam = !m_bHideXStatusMenu; + } + + if (pData->flags & CSSF_STATUSES_COUNT) + { + if (pData->wParam) *pData->wParam = XSTATUS_COUNT; + } + + if (pData->flags & CSSF_STR_SIZES) + { + DBVARIANT dbv = {DBVT_DELETED}; + + if (pData->wParam) + { + if (m_bXStatusEnabled && !getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv)) + *pData->wParam = strlennull(dbv.pszVal); + else + *pData->wParam = 0; + ICQFreeVariant(&dbv); + } + if (pData->lParam) + { + if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv)) + *pData->lParam = strlennull(dbv.pszVal); + else + *pData->lParam = 0; + ICQFreeVariant(&dbv); + } + } + + return 0; // Success +} + + +INT_PTR CIcqProto::GetXStatusIcon(WPARAM wParam, LPARAM lParam) +{ + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0; + + if (!wParam) + wParam = getContactXStatus(NULL); + + if (wParam >= 1 && wParam <= XSTATUS_COUNT) + { + return (INT_PTR)getXStatusIcon((BYTE)wParam, lParam); + } + return 0; +} + + +INT_PTR CIcqProto::RequestXStatusDetails(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + + if (!m_bXStatusEnabled) return 0; + + if (hContact && !getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO) && + getContactXStatus(hContact) && CheckContactCapabilities(hContact, CAPF_XSTATUS)) + { // user has xstatus, no auto-retrieve details, valid contact, request details + return requestXStatusDetails(hContact, TRUE); + } + return 0; +} + + +INT_PTR CIcqProto::RequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam) +{ + if (!m_bXStatusEnabled && !m_bMoodsEnabled) return -1; + + BYTE bXStatus = getContactXStatus((HANDLE)wParam); + + if (bXStatus) + { + int idx=-1; + + if (!bXStatusCListIconsValid[bXStatus-1]) + { // adding icon + int idx = hXStatusCListIcons[bXStatus-1]; + HIMAGELIST hCListImageList = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0); + + if (hCListImageList) + { + HICON hXStatusIcon = getXStatusIcon(bXStatus, LR_SHARED); + + if (idx > 0) + ImageList_ReplaceIcon(hCListImageList, idx, hXStatusIcon); + else + hXStatusCListIcons[bXStatus-1] = ImageList_AddIcon(hCListImageList, hXStatusIcon); + // mark icon index in the array as valid + bXStatusCListIconsValid[bXStatus-1] = TRUE; + + releaseXStatusIcon(bXStatus, 0); + } + } + idx = bXStatusCListIconsValid[bXStatus-1] ? hXStatusCListIcons[bXStatus-1] : -1; + + if (idx > 0) + return (idx & 0xFFFF) << 16; + } + return -1; +} diff --git a/protocols/IcqOscarJ/src/icq_xtraz.cpp b/protocols/IcqOscarJ/src/icq_xtraz.cpp new file mode 100644 index 0000000000..2b73274365 --- /dev/null +++ b/protocols/IcqOscarJ/src/icq_xtraz.cpp @@ -0,0 +1,466 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Internal Xtraz API +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +void CIcqProto::handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) +{ + char *szNotify = strstrnull(szMsg, ""); + char *szQuery = strstrnull(szMsg, ""); + + HANDLE hContact = HContactFromUIN(dwUin, NULL); + if (hContact) // user sent us xtraz, he supports it + SetContactCapabilities(hContact, CAPF_XTRAZ); + + if (szNotify && szQuery) + { // valid request + char *szWork, *szEnd; + int nNotifyLen, nQueryLen; + + szNotify += 8; + szQuery += 7; + szEnd = strstrnull(szMsg, ""); + if (!szEnd) szEnd = szMsg + nMsgLen; + nNotifyLen = (szEnd - szNotify); + szEnd = strstrnull(szMsg, ""); + if (!szEnd) szEnd = szNotify; + szNotify = DemangleXml(szNotify, nNotifyLen); + nQueryLen = (szEnd - szQuery); + szQuery = DemangleXml(szQuery, nQueryLen); + szWork = strstrnull(szQuery, ""); + szEnd = strstrnull(szQuery, ""); +#ifdef _DEBUG + NetLog_Server("Query: %s", szQuery); + NetLog_Server("Notify: %s", szNotify); +#endif + if (szWork && szEnd) + { // this is our plugin + szWork += 10; + *szEnd = '\0'; + + if (!stricmpnull(szWork, "srvMng") && strstrnull(szNotify, "AwayStat")) + { + char *szSender = strstrnull(szNotify, ""); + char *szEndSend = strstrnull(szNotify, ""); + + if (szSender && szEndSend) + { + szSender += 10; + *szEndSend = '\0'; + + if ((DWORD)atoi(szSender) == dwUin) + { + BYTE dwXId = m_bXStatusEnabled ? getContactXStatus(NULL) : 0; + + if (dwXId && validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY)) + { // apply privacy rules + NotifyEventHooks(m_modeMsgsEvent, (WPARAM)MTYPE_SCRIPT_NOTIFY, (LPARAM)dwUin); + + char *tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, ""); + char *szXName = MangleXml(tmp, strlennull(tmp)); + SAFE_FREE(&tmp); + + tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); + char *szXMsg = MangleXml(tmp, strlennull(tmp)); + SAFE_FREE(&tmp); + + int nResponseLen = 212 + strlennull(szXName) + strlennull(szXMsg) + UINMAXLEN + 2; + char *szResponse = (char*)_alloca(nResponseLen + 1); + // send response + null_snprintf(szResponse, nResponseLen, + "" + "cAwaySrv" + "" + "" + "%d" + "%d" + "%s" + "%s", + m_dwLocalUIN, dwXId, szXName, szXMsg); + + SAFE_FREE(&szXName); + SAFE_FREE(&szXMsg); + + struct rates_xstatus_response: public rates_queue_item { + protected: + virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) { + rates_xstatus_response *pDest = (rates_xstatus_response*)aDest; + if (!pDest) + pDest = new rates_xstatus_response(ppro, wGroup); + + pDest->bThruDC = bThruDC; + pDest->dwMsgID1 = dwMsgID1; + pDest->dwMsgID2 = dwMsgID2; + pDest->wCookie = wCookie; + pDest->szResponse = null_strdup(szResponse); + + return rates_queue_item::copyItem(pDest); + }; + public: + rates_xstatus_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup), szResponse(NULL) { }; + virtual ~rates_xstatus_response() { if (bCreated) SAFE_FREE(&szResponse); }; + + virtual void execute() { + ppro->SendXtrazNotifyResponse(dwUin, dwMsgID1, dwMsgID2, wCookie, szResponse, strlennull(szResponse), bThruDC); + }; + + BOOL bThruDC; + DWORD dwMsgID1; + DWORD dwMsgID2; + WORD wCookie; + char *szResponse; + }; + + m_ratesMutex->Enter(); + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); + m_ratesMutex->Leave(); + + rates_xstatus_response rr(this, wGroup); + rr.hContact = hContact; + rr.dwUin = dwUin; + rr.bThruDC = bThruDC; + rr.dwMsgID1 = dwMID; + rr.dwMsgID2 = dwMID2; + rr.wCookie = wCookie; + rr.szResponse = szResponse; + + handleRateItem(&rr, RQT_RESPONSE, 0, !bThruDC); + } + else if (dwXId) + NetLog_Server("Privacy: Ignoring XStatus request"); + else + NetLog_Server("Error: We are not in XStatus, skipping"); + } + else + NetLog_Server("Error: Invalid sender information"); + } + else + NetLog_Server("Error: Missing sender information"); + } + else + NetLog_Server("Error: Unknown plugin \"%s\" in Xtraz message", szWork); + } + else + NetLog_Server("Error: Missing PluginID in Xtraz message"); + + SAFE_FREE(&szNotify); + SAFE_FREE(&szQuery); + } + else + NetLog_Server("Error: Invalid Xtraz Notify message"); +} + + +void CIcqProto::handleXtrazNotifyResponse(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szMsg, int nMsgLen) +{ + char *szMem, *szRes, *szEnd; + int nResLen; + +#ifdef _DEBUG + NetLog_Server("Received Xtraz Notify Response"); +#endif + + szRes = strstrnull(szMsg, ""); + szEnd = strstrnull(szMsg, ""); + + if (szRes && szEnd) + { // valid response + char *szNode, *szWork; + + szRes += 5; + nResLen = szEnd - szRes; + + szMem = szRes = DemangleXml(szRes, nResLen); + +#ifdef _DEBUG + NetLog_Server("Response: %s", szRes); +#endif + + BroadcastAck(hContact, ICQACKTYPE_XTRAZNOTIFY_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, (LPARAM)szRes); + +NextVal: + szNode = strstrnull(szRes, ""); else szEnd = NULL; + + if (szNode && szEnd) + { + *(szEnd-1) = '\0'; + szNode += 13; //one more than the length of the string to skip ' or " too + szWork = szEnd + 1; + + if (!stricmpnull(szNode, "cAwaySrv")) + { + int bChanged = FALSE; + + *szEnd = ' '; + szNode = strstrnull(szWork, ""); + szEnd = strstrnull(szWork, ""); + if (szNode && szEnd) + { + szNode += 7; + *szEnd = '\0'; + if (atoi(szNode) != getContactXStatus(hContact)) + { // this is strange - but go on + NetLog_Server("Warning: XStatusIds do not match!"); + } + *szEnd = ' '; + } + szNode = strstrnull(szWork, ""); + szEnd = strstrnull(szWork, ""); + if (szNode && szEnd) + { // we got XStatus title, save it + char *szXName, *szOldXName; + szNode += 7; + *szEnd = '\0'; + szXName = DemangleXml(szNode, strlennull(szNode)); + // check if the name changed + szOldXName = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); + if (strcmpnull(szOldXName, szXName)) + bChanged = TRUE; + SAFE_FREE(&szOldXName); + setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, szXName); + SAFE_FREE(&szXName); + *szEnd = ' '; + } + szNode = strstrnull(szWork, ""); + szEnd = strstrnull(szWork, ""); + if (szNode && szEnd) + { // we got XStatus mode msg, save it + char *szXMsg, *szOldXMsg; + szNode += 6; + *szEnd = '\0'; + szXMsg = DemangleXml(szNode, strlennull(szNode)); + // check if the decription changed + szOldXMsg = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); + if (strcmpnull(szOldXMsg, szXMsg)) + bChanged = TRUE; + SAFE_FREE(&szOldXMsg); + setSettingStringUtf(hContact, DBSETTING_XSTATUS_MSG, szXMsg); + SAFE_FREE(&szXMsg); + } + BroadcastAck(hContact, ICQACKTYPE_XSTATUS_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); + if (bChanged) + NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0); + } + else + { + char *szSrvEnd = strstrnull(szEnd, ""); + + if (szSrvEnd && strstrnull(szSrvEnd, ""); + szEnd = strstrnull(szData, ""); + + if (szPid && szEnd) + { + szPid += 5; + + return DemangleXml(szPid, szEnd - szPid); + } + return NULL; +} + + +void CIcqProto::handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) +{ + HANDLE hContact; + char* szPluginID; + + hContact = HContactFromUIN(dwUin, NULL); + if (hContact) // user sent us xtraz, he supports it + SetContactCapabilities(hContact, CAPF_XTRAZ); + + szPluginID = getXmlPidItem(szMsg, nMsgLen); + if (!strcmpnull(szPluginID, "ICQChatRecv")) + { // it is a invitation to multi-user chat + } + else + { + NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); + } + SAFE_FREE(&szPluginID); +} + + +void CIcqProto::handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) +{ + HANDLE hContact; + char* szPluginID; + + hContact = HContactFromUIN(dwUin, NULL); + if (hContact) // user sent us xtraz, he supports it + SetContactCapabilities(hContact, CAPF_XTRAZ); + + szPluginID = getXmlPidItem(szMsg, nMsgLen); + if (!strcmpnull(szPluginID, "viewCard")) + { // it is a greeting card + char *szWork, *szEnd, *szUrl, *szNum; + + szWork = strstrnull(szMsg, ""); + szEnd = strstrnull(szMsg, ""); + if (szWork && szEnd) + { + int nDataLen = szEnd - szWork; + + szUrl = (char*)_alloca(nDataLen); + memcpy(szUrl, szWork+5, nDataLen); + szUrl[nDataLen - 5] = '\0'; + + if (!_strnicmp(szUrl, "view_", 5)) + { + szNum = szUrl + 5; + szWork = strstrnull(szUrl, ".html"); + if (szWork) + { + strcpy(szWork, ".php"); + strcat(szWork, szWork+5); + } + while (szWork = strstrnull(szUrl, "&")) + { // unescape & code + strcpy(szWork+1, szWork+5); + } + szWork = (char*)SAFE_MALLOC(nDataLen + MAX_PATH); + ICQTranslateUtfStatic(LPGEN("Greeting card:"), szWork, MAX_PATH); + strcat(szWork, "\r\nhttp://www.icq.com/friendship/pages/view_page_"); + strcat(szWork, szNum); + + // Create message to notify user + { + CCSDATA ccs; + PROTORECVEVENT pre = {0}; + int bAdded; + + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = HContactFromUIN(dwUin, &bAdded); + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.timestamp = time(NULL); + pre.szMessage = szWork; + pre.flags = PREF_UTF; + + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } + SAFE_FREE(&szWork); + } + else + NetLog_Uni(bThruDC, "Error: Non-standard greeting card message"); + } + else + NetLog_Uni(bThruDC, "Error: Malformed greeting card message"); + } + else + { + NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); + } + SAFE_FREE(&szPluginID); +} + + +// Functions really sending Xtraz stuff +DWORD CIcqProto::SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced) +{ + char *szQueryBody; + char *szNotifyBody; + DWORD dwUin; + int nBodyLen; + char *szBody; + DWORD dwCookie; + + if (getContactUid(hContact, &dwUin, NULL)) + return 0; // Invalid contact + + if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && !bForced) + return 0; // Contact does not support xtraz, do not send anything + + szQueryBody = MangleXml(szQuery, strlennull(szQuery)); + szNotifyBody = MangleXml(szNotify, strlennull(szNotify)); + nBodyLen = strlennull(szQueryBody) + strlennull(szNotifyBody) + 41; + szBody = (char*)_alloca(nBodyLen); + nBodyLen = null_snprintf(szBody, nBodyLen, "%s%s", szQueryBody, szNotifyBody); + SAFE_FREE((void**)&szQueryBody); + SAFE_FREE((void**)&szNotifyBody); + + // Set up the ack type + cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_SCRIPT_NOTIFY, ACKTYPE_CLIENT); + dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + // have we a open DC, send through that + if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + icq_sendXtrazRequestDirect(hContact, dwCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); + else + icq_sendXtrazRequestServ(dwUin, dwCookie, szBody, nBodyLen, pCookieData); + + return dwCookie; +} + + +void CIcqProto::SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC) +{ + char *szResBody = MangleXml(szResponse, nResponseLen); + int nBodyLen = strlennull(szResBody) + 21; + char *szBody = (char*)_alloca(nBodyLen); + HANDLE hContact = HContactFromUIN(dwUin, NULL); + + if (hContact != INVALID_HANDLE_VALUE && !CheckContactCapabilities(hContact, CAPF_XTRAZ)) + { + SAFE_FREE(&szResBody); + return; // Contact does not support xtraz, do not send anything + } + + nBodyLen = null_snprintf(szBody, nBodyLen, "%s", szResBody); + SAFE_FREE(&szResBody); + + // Was request received thru DC and have we a open DC, send through that + if (bThruDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) + icq_sendXtrazResponseDirect(hContact, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); + else + icq_sendXtrazResponseServ(dwUin, dwMID, dwMID2, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); +} diff --git a/protocols/IcqOscarJ/src/icqosc_svcs.cpp b/protocols/IcqOscarJ/src/icqosc_svcs.cpp new file mode 100644 index 0000000000..ee6dd1731c --- /dev/null +++ b/protocols/IcqOscarJ/src/icqosc_svcs.cpp @@ -0,0 +1,816 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// High-level code for exported API services +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +INT_PTR CIcqProto::AddServerContact(WPARAM wParam, LPARAM lParam) +{ + DWORD dwUin; + uid_str szUid; + + if (!m_bSsiEnabled) return 0; + + // Does this contact have a UID? + if (!getContactUid((HANDLE)wParam, &dwUin, &szUid) && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_ID, 0) && !getSettingWord((HANDLE)wParam, DBSETTING_SERVLIST_IGNORE, 0)) + { /// TODO: remove possible 0x6A TLV in contact server-list data!!! + // Read group from DB + char *pszGroup = getContactCListGroup((HANDLE)wParam); + + servlistAddContact((HANDLE)wParam, pszGroup); + SAFE_FREE((void**)&pszGroup); + } + return 0; +} + + +static int LookupDatabaseSetting(const FieldNamesItem* table, int code, DBVARIANT *dbv, BYTE type) +{ + char *text = LookupFieldName(table, code); + + if (!text) + { + dbv->type = DBVT_DELETED; + return 1; + } + + if (type == DBVT_ASCIIZ) + { + dbv->pszVal = mir_strdup(Translate(text)); + dbv->type = DBVT_ASCIIZ; + } + else if (type == DBVT_UTF8 || !type) + { + char tmp[MAX_PATH]; + + dbv->pszVal = mir_strdup(ICQTranslateUtfStatic(text, tmp, MAX_PATH)); + dbv->type = DBVT_UTF8; + } + else if (type == DBVT_WCHAR) + { + WCHAR* wtext = make_unicode_string(text); + + dbv->pwszVal = mir_wstrdup(TranslateW(wtext)); + dbv->type = DBVT_WCHAR; + + SAFE_FREE((void**)&wtext); + } + return 0; // Success +} + +INT_PTR CIcqProto::GetInfoSetting(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTGETSETTING *cgs = (DBCONTACTGETSETTING*)lParam; + BYTE type = cgs->pValue->type; + + cgs->pValue->type = 0; // original type without conversion + INT_PTR rc = CallService(MS_DB_CONTACT_GETSETTING_STR, wParam, lParam); + + if (!rc) + { // Success + DBVARIANT dbv; + + memcpy(&dbv, cgs->pValue, sizeof(DBVARIANT)); + + if (dbv.type == DBVT_BLOB) + { + cgs->pValue->pbVal = (BYTE*)mir_alloc(dbv.cpbVal); + + memcpy(cgs->pValue->pbVal, dbv.pbVal, dbv.cpbVal); + } + else if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_UTF8) + { // convert to the desired type + if (!type) + type = dbv.type; + + if (dbv.type == type) + { // type is correct, only move it to miranda's heap + cgs->pValue->pszVal = mir_strdup(dbv.pszVal); + } + else if (type == DBVT_WCHAR) + { + if (dbv.type != DBVT_UTF8) + { + int len = MultiByteToWideChar(CP_ACP, 0, dbv.pszVal, -1, NULL, 0); + cgs->pValue->pwszVal = (WCHAR*)mir_alloc((len + 1)*sizeof(WCHAR)); + if (cgs->pValue->pwszVal == NULL) + rc = 1; + else + { + MultiByteToWideChar(CP_ACP, 0, dbv.pszVal, -1, cgs->pValue->pwszVal, len); + cgs->pValue->pwszVal[len] = '\0'; + } + } + else + { + char *savePtr = dbv.pszVal ? strcpy((char*)_alloca(strlennull(dbv.pszVal) + 1), dbv.pszVal) : NULL; + if (!mir_utf8decode(savePtr, &cgs->pValue->pwszVal)) + rc = 1; + } + } + else if (type == DBVT_UTF8) + { + cgs->pValue->pszVal = mir_utf8encode(dbv.pszVal); + if (cgs->pValue->pszVal == NULL) + rc = 1; + } + else if (type == DBVT_ASCIIZ) + { + cgs->pValue->pszVal = mir_strdup(dbv.pszVal); + mir_utf8decode(cgs->pValue->pszVal, NULL); + } + + cgs->pValue->type = type; + } + else if (!strcmpnull(cgs->szModule, m_szModuleName) && (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD)) + { + int code = (dbv.type == DBVT_BYTE) ? dbv.bVal : ((dbv.type == DBVT_WORD) ? dbv.wVal : dbv.dVal); + + if (!strcmpnull(cgs->szSetting, "Language1") || !strcmpnull(cgs->szSetting, "Language2") || !strcmpnull(cgs->szSetting, "Language3")) + rc = LookupDatabaseSetting(languageField, code, cgs->pValue, type); + else if (!strcmpnull(cgs->szSetting, "Country") || !strcmpnull(cgs->szSetting, "OriginCountry") || !strcmpnull(cgs->szSetting, "CompanyCountry")) + { + if (code == 420) code = 42; // conversion of obsolete codes (OMG!) + else if (code == 421) code = 4201; + else if (code == 102) code = 1201; + rc = LookupDatabaseSetting(countryField, code, cgs->pValue, type); + } + else if (!strcmpnull(cgs->szSetting, "Gender")) + rc = LookupDatabaseSetting(genderField, code, cgs->pValue, type); + else if (!strcmpnull(cgs->szSetting, "MaritalStatus")) + rc = LookupDatabaseSetting(maritalField, code, cgs->pValue, type); + else if (!strcmpnull(cgs->szSetting, "StudyLevel")) + rc = LookupDatabaseSetting(studyLevelField, code, cgs->pValue, type); + else if (!strcmpnull(cgs->szSetting, "CompanyIndustry")) + rc = LookupDatabaseSetting(industryField, code, cgs->pValue, type); + else if (!strcmpnull(cgs->szSetting, "Interest0Cat") || !strcmpnull(cgs->szSetting, "Interest1Cat") || !strcmpnull(cgs->szSetting, "Interest2Cat") || !strcmpnull(cgs->szSetting, "Interest3Cat")) + rc = LookupDatabaseSetting(interestsField, code, cgs->pValue, type); + } + // Release database memory + ICQFreeVariant(&dbv); + } + + return rc; +} + + +INT_PTR CIcqProto::ChangeInfoEx(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline() && wParam) + { + PBYTE buf = NULL; + int buflen = 0; + BYTE b; + + // userinfo + ppackTLVWord(&buf, &buflen, 0x1C2, (WORD)GetACP()); + + if (wParam & CIXT_CONTACT) + { // contact information + BYTE *pBlock = NULL; + int cbBlock = 0; + int nItems = 0; + + // Emails + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail0", 0x78, 0x64, 0x00); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail1", 0x78, 0x64, 0x00); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "e-mail2", 0x78, 0x64, 0x00); + ppackTLVBlockItems(&buf, &buflen, 0x8C, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); + + // Phones + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Phone", 0x6E, 0x64, 0x01); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "CompanyPhone", 0x6E, 0x64, 0x02); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Cellular", 0x6E, 0x64, 0x03); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "Fax", 0x6E, 0x64, 0x04); + nItems += ppackTLVWordStringItemFromDB(&pBlock, &cbBlock, "CompanyFax", 0x6E, 0x64, 0x05); + ppackTLVBlockItems(&buf, &buflen, 0xC8, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); + + ppackTLVByte(&buf, &buflen, 0x1EA, getSettingByte(NULL, "AllowSpam", 0)); + } + + if (wParam & CIXT_BASIC) + { // upload basic user info + ppackTLVStringUtfFromDB(&buf, &buflen, "Nick", 0x78); + ppackTLVStringUtfFromDB(&buf, &buflen, "FirstName", 0x64); + ppackTLVStringUtfFromDB(&buf, &buflen, "LastName", 0x6E); + ppackTLVStringUtfFromDB(&buf, &buflen, "About", 0x186); + } + + if (wParam & CIXT_MORE) + { + b = getSettingByte(NULL, "Gender", 0); + ppackTLVByte(&buf, &buflen, 0x82, (BYTE)(b ? (b == 'M' ? 2 : 1) : 0)); + + ppackTLVDateFromDB(&buf, &buflen, "BirthYear", "BirthMonth", "BirthDay", 0x1A4); + + ppackTLVWord(&buf, &buflen, 0xAA, getSettingByte(NULL, "Language1", 0)); + ppackTLVWord(&buf, &buflen, 0xB4, getSettingByte(NULL, "Language2", 0)); + ppackTLVWord(&buf, &buflen, 0xBE, getSettingByte(NULL, "Language3", 0)); + + ppackTLVWord(&buf, &buflen, 0x12C, getSettingByte(NULL, "MaritalStatus", 0)); + } + + if (wParam & CIXT_WORK) + { + BYTE *pBlock = NULL; + int cbBlock = 0; + int nItems = 1; + + // Jobs + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyPosition", 0x64); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "Company", 0x6E); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyDepartment", 0x7D); + ppackTLVStringFromDB(&pBlock, &cbBlock, "CompanyHomepage", 0x78); + ppackTLVWord(&pBlock, &cbBlock, 0x82, getSettingWord(NULL, "CompanyIndustry", 0)); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyStreet", 0xAA); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyCity", 0xB4); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyState", 0xBE); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "CompanyZIP", 0xC8); + ppackTLVDWord(&pBlock, &cbBlock, 0xD2, getSettingWord(NULL, "CompanyCountry", 0)); + /// TODO: pack unknown data (need to preserve them in Block Items) + ppackTLVBlockItems(&buf, &buflen, 0x118, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); + + // ppackTLVWord(&buf, &buflen, getSettingWord(NULL, "CompanyOccupation", 0), TLV_OCUPATION, 1); // Lost In Conversion + } + + if (wParam & CIXT_EDUCATION) + { + BYTE *pBlock = NULL; + int cbBlock = 0; + int nItems = 1; + + // Studies + ppackTLVWord(&pBlock, &cbBlock, 0x64, getSettingWord(NULL, "StudyLevel", 0)); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "StudyInstitute", 0x6E); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "StudyDegree", 0x78); + ppackTLVWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "StudyYear", 0)); + ppackTLVBlockItems(&buf, &buflen, 0x10E, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); + } + + if (wParam & CIXT_LOCATION) + { + BYTE *pBlock = NULL; + int cbBlock = 0; + int nItems = 1; + + // Home Address + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "Street", 0x64); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "City", 0x6E); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "State", 0x78); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "ZIP", 0x82); + ppackTLVDWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "Country", 0)); + ppackTLVBlockItems(&buf, &buflen, 0x96, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); + + nItems = 1; + // Origin Address + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginStreet", 0x64); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginCity", 0x6E); + ppackTLVStringUtfFromDB(&pBlock, &cbBlock, "OriginState", 0x78); + ppackTLVDWord(&pBlock, &cbBlock, 0x8C, getSettingWord(NULL, "OriginCountry", 0)); + ppackTLVBlockItems(&buf, &buflen, 0xA0, &nItems, &pBlock, (WORD*)&cbBlock, TRUE); + + ppackTLVStringFromDB(&buf, &buflen, "Homepage", 0xFA); + + // Timezone + WORD wTimezone = getSettingByte(NULL, "Timezone", 0); + if ((wTimezone & 0x0080) == 0x80) wTimezone |= 0xFF00; // extend signed number + ppackTLVWord(&buf, &buflen, 0x17C, wTimezone); + } + + if (wParam & CIXT_BACKGROUND) + { + BYTE *pBlock = NULL; + int cbBlock = 0; + int nItems = 0; + + // Interests + nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest0Text", 0x6E, 0x64, getSettingWord(NULL, "Interest0Cat", 0)); + nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest1Text", 0x6E, 0x64, getSettingWord(NULL, "Interest1Cat", 0)); + nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest2Text", 0x6E, 0x64, getSettingWord(NULL, "Interest2Cat", 0)); + nItems += ppackTLVWordStringUtfItemFromDB(&pBlock, &cbBlock, "Interest3Text", 0x6E, 0x64, getSettingWord(NULL, "Interest3Cat", 0)); + ppackTLVBlockItems(&buf, &buflen, 0x122, &nItems, &pBlock, (WORD*)&cbBlock, FALSE); + + + /* WORD w; /// not supported anymore + + w = StringToListItemId("Past0", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past0Text", TLV_PASTINFO); + w = StringToListItemId("Past1", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past1Text", TLV_PASTINFO); + w = StringToListItemId("Past2", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past2Text", TLV_PASTINFO); + + w = StringToListItemId("Affiliation0", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation0Text", TLV_AFFILATIONS); + w = StringToListItemId("Affiliation1", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation1Text", TLV_AFFILATIONS); + w = StringToListItemId("Affiliation2", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation2Text", TLV_AFFILATIONS);*/ + } + + DWORD dwCookie = icq_changeUserDirectoryInfoServ(buf, (WORD)buflen, DIRECTORYREQUEST_UPDATEOWNER); + + SAFE_FREE((void**)&buf); + + return dwCookie; + } + + return 0; // Failure +} + + +INT_PTR CIcqProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam) +{ + if (wParam == AF_MAXSIZE) + { + POINT *size = (POINT*)lParam; + + if (size) + { + size->x = 64; + size->y = 64; + + return 0; + } + } + else if (wParam == AF_PROPORTION) + { + return PIP_NONE; + } + else if (wParam == AF_FORMATSUPPORTED) + { + if (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_XML || lParam == PA_FORMAT_BMP) + return 1; + else + return 0; + } + else if (wParam == AF_ENABLED) + { + if (m_bSsiEnabled && m_bAvatarsEnabled) + return 1; + else + return 0; + } + else if (wParam == AF_DONTNEEDDELAYS) + { + return 0; + } + else if (wParam == AF_MAXFILESIZE) + { // server accepts images of 7168 bytees, not bigger + return 7168; + } + else if (wParam == AF_DELAYAFTERFAIL) + { // do not request avatar again if server gave an error + return 1 * 60 * 60 * 1000; // one hour + } + else if (wParam == AF_FETCHALWAYS) + { // avatars can be fetched all the time (server only operation) + return 1; + } + return 0; +} + + +INT_PTR CIcqProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) +{ + PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)lParam; + DWORD dwUIN; + uid_str szUID; + DBVARIANT dbv = {DBVT_DELETED}; + + if (!m_bAvatarsEnabled) return GAIR_NOAVATAR; + + if (getSetting(pai->hContact, "AvatarHash", &dbv) || dbv.type != DBVT_BLOB || (dbv.cpbVal != 0x14 && dbv.cpbVal != 0x09)) + { + ICQFreeVariant(&dbv); + return GAIR_NOAVATAR; // we did not found avatar hash or hash invalid - no avatar available + } + + if (getContactUid(pai->hContact, &dwUIN, &szUID)) + { + ICQFreeVariant(&dbv); + return GAIR_NOAVATAR; // we do not support avatars for invalid contacts + } + + int dwPaFormat = getSettingByte(pai->hContact, "AvatarType", PA_FORMAT_UNKNOWN); + + if (dwPaFormat != PA_FORMAT_UNKNOWN) + { // we know the format, test file + TCHAR tszFile[MAX_PATH * 2 + 4]; + + GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszFile, MAX_PATH * 2); + + lstrcpyn(pai->filename, tszFile, SIZEOF(pai->filename)); // Avatar API does not support unicode :-( + pai->format = dwPaFormat; + + if (!IsAvatarChanged(pai->hContact, dbv.pbVal, dbv.cpbVal)) + { // hashes are the same + if (_taccess(tszFile, 0) == 0) + { + ICQFreeVariant(&dbv); + + return GAIR_SUCCESS; // we have found the avatar file, whoala + } + } + } + + if (IsAvatarChanged(pai->hContact, dbv.pbVal, dbv.cpbVal)) + { // we didn't received the avatar before - this ensures we will not request avatar again and again + if ((wParam & GAIF_FORCE) != 0 && pai->hContact != 0) + { // request avatar data + TCHAR tszFile[MAX_PATH * 2 + 4]; + + GetAvatarFileName(dwUIN, szUID, tszFile, MAX_PATH * 2); + GetAvatarData(pai->hContact, dwUIN, szUID, dbv.pbVal, dbv.cpbVal, tszFile); + lstrcpyn(pai->filename, tszFile, SIZEOF(pai->filename)); // Avatar API does not support unicode :-( + + ICQFreeVariant(&dbv); + + return GAIR_WAITFOR; + } + } + ICQFreeVariant(&dbv); + + return GAIR_NOAVATAR; +} + + +INT_PTR CIcqProto::GetMyAvatar(WPARAM wParam, LPARAM lParam) +{ + if (!m_bAvatarsEnabled) return -2; + + if (!wParam) return -3; + + TCHAR *tszFile = GetOwnAvatarFileName(); + if (tszFile && !_taccess(tszFile, 0)) + { + _tcsncpy((TCHAR*)wParam, tszFile, (int)lParam); + SAFE_FREE(&tszFile); + return 0; + } + + SAFE_FREE(&tszFile); + return -1; +} + + +INT_PTR CIcqProto::GrantAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline() && wParam != 0) + { + DWORD dwUin; + uid_str szUid; + + if (getContactUid((HANDLE)wParam, &dwUin, &szUid)) + return 0; // Invalid contact + + // send without reason, do we need any ? + icq_sendGrantAuthServ(dwUin, szUid, NULL); + // auth granted, remove contact menu item + deleteSetting((HANDLE)wParam, "Grant"); + } + + return 0; +} + +int CIcqProto::OnIdleChanged(WPARAM wParam, LPARAM lParam) +{ + int bIdle = (lParam&IDF_ISIDLE); + int bPrivacy = (lParam&IDF_PRIVACY); + + if (bPrivacy) return 0; + + setSettingDword(NULL, "IdleTS", bIdle ? time(0) : 0); + + if (m_bTempVisListEnabled) // remove temporary visible users + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_REMOVETEMPVISIBLE, BUL_TEMPVISIBLE); + + icq_setidle(bIdle ? 1 : 0); + + return 0; +} + +INT_PTR CIcqProto::RevokeAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline() && wParam != 0) + { + DWORD dwUin; + uid_str szUid; + + if (getContactUid((HANDLE)wParam, &dwUin, &szUid)) + return 0; // Invalid contact + + if (MessageBoxUtf(NULL, LPGEN("Are you sure you want to revoke user's authorization (this will remove you from his/her list on some clients) ?"), LPGEN("Confirmation"), MB_ICONQUESTION | MB_YESNO) != IDYES) + return 0; + + icq_sendRevokeAuthServ(dwUin, szUid); + } + + return 0; +} + + +INT_PTR CIcqProto::SendSms(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline() && wParam && lParam) + return icq_sendSMSServ((const char *)wParam, (const char *)lParam); + + return 0; // Failure +} + +INT_PTR CIcqProto::SendYouWereAdded(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline()) + { + CCSDATA* ccs = (CCSDATA*)lParam; + if (ccs->hContact) + { + DWORD dwUin, dwMyUin; + + if (getContactUid(ccs->hContact, &dwUin, NULL)) + return 1; // Invalid contact + + dwMyUin = getContactUin(NULL); + + if (dwUin) + { + icq_sendYouWereAddedServ(dwUin, dwMyUin); + return 0; // Success + } + } + } + + return 1; // Failure +} + +INT_PTR CIcqProto::SetMyAvatar(WPARAM wParam, LPARAM lParam) +{ + TCHAR* tszFile = (TCHAR*)lParam; + int iRet = -1; + + if (!m_bAvatarsEnabled || !m_bSsiEnabled) return -2; + + if (tszFile) + { // set file for avatar + int dwPaFormat = DetectAvatarFormat(tszFile); + if (dwPaFormat != PA_FORMAT_XML) + { + // if it should be image, check if it is valid + HBITMAP avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (WPARAM)tszFile); + if (!avt) return iRet; + DeleteObject(avt); + } + + TCHAR tszMyFile[MAX_PATH+1]; + GetFullAvatarFileName(0, NULL, dwPaFormat, tszMyFile, MAX_PATH); + // if not in our storage, copy + if (lstrcmp(tszFile, tszMyFile) && !CopyFile(tszFile, tszMyFile, FALSE)) + { + NetLog_Server("Failed to copy our avatar to local storage."); + return iRet; + } + + BYTE *hash = calcMD5HashOfFile(tszMyFile); + if (hash) + { + BYTE* ihash = (BYTE*)_alloca(0x14); + // upload hash to server + ihash[0] = 0; //unknown + ihash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC; //hash type + ihash[2] = 1; //hash status + ihash[3] = 0x10; //hash len + memcpy(ihash+4, hash, 0x10); + updateServAvatarHash(ihash, 0x14); + + if (setSettingBlob(NULL, "AvatarHash", ihash, 0x14)) + { + NetLog_Server("Failed to save avatar hash."); + } + + TCHAR tmp[MAX_PATH]; + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)tszMyFile, (LPARAM)tmp); + setSettingStringT(NULL, "AvatarFile", tmp); + + iRet = 0; + + SAFE_FREE((void**)&hash); + } + } + else + { // delete user avatar + deleteSetting(NULL, "AvatarFile"); + setSettingBlob(NULL, "AvatarHash", hashEmptyAvatar, 9); + updateServAvatarHash(hashEmptyAvatar, 9); // set blank avatar + iRet = 0; + } + + return iRet; +} + +INT_PTR CIcqProto::SetNickName(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline()) + { + setSettingString(NULL, "Nick", (char*)lParam); + + return ChangeInfoEx(CIXT_BASIC, 0); + } + + return 0; // Failure +} + +INT_PTR CIcqProto::SetPassword(WPARAM wParam, LPARAM lParam) +{ + char *pwd = (char*)lParam; + int len = strlennull(pwd); + + if (len && len < PASSWORDMAXLEN) + { + strcpy(m_szPassword, pwd); + m_bRememberPwd = TRUE; + } + return 0; +} + + +// TODO: Adding needs some more work in general + +HANDLE CIcqProto::AddToListByUIN(DWORD dwUin, DWORD dwFlags) +{ + int bAdded; + HANDLE hContact = HContactFromUIN(dwUin, &bAdded); + if (hContact) + { + if (!(dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + { + setContactHidden(hContact, 0); + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + } + + return hContact; // Success + } + + return NULL; // Failure +} + + +HANDLE CIcqProto::AddToListByUID(const char *szUID, DWORD dwFlags) +{ + int bAdded; + HANDLE hContact = HContactFromUID(0, szUID, &bAdded); + if (hContact) + { + if (!(dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + { + setContactHidden(hContact, 0); + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + } + + return hContact; // Success + } + + return NULL; // Failure +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::ICQAddRecvEvent(HANDLE hContact, WORD wType, PROTORECVEVENT* pre, DWORD cbBlob, PBYTE pBlob, DWORD flags) +{ + if (pre->flags & PREF_CREATEREAD) + flags |= DBEF_READ; + + if (pre->flags & PREF_UTF) + flags |= DBEF_UTF; + + if (hContact && DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) + { + DWORD dwUin; + uid_str szUid; + + //setContactHidden(hContact, 0); + + // if the contact was hidden, add to client-list if not in server-list authed + if (!getSettingWord(hContact, DBSETTING_SERVLIST_ID, 0) || getSettingByte(hContact, "Auth", 0)) + { + getContactUid(hContact, &dwUin, &szUid); + icq_sendNewContact(dwUin, szUid); /// FIXME + } + } + + AddEvent(hContact, wType, pre->timestamp, flags, cbBlob, pBlob); +} + +INT_PTR __cdecl CIcqProto::IcqAddCapability(WPARAM wParam, LPARAM lParam) +{ + ICQ_CUSTOMCAP *icqCustomCapIn = (ICQ_CUSTOMCAP *)lParam; + ICQ_CUSTOMCAP *icqCustomCap = (ICQ_CUSTOMCAP *)malloc(sizeof(ICQ_CUSTOMCAP)); + memcpy(icqCustomCap, icqCustomCapIn, sizeof(ICQ_CUSTOMCAP)); + CustomCapList.push_back(icqCustomCap); +// MessageBoxA(NULL, ((ICQ_CUSTOMCAP *)(lstCustomCaps->items[lstCustomCaps->realCount-1]))->name, "custom cap", MB_OK); + return 0; +} + + +INT_PTR __cdecl CIcqProto::IcqCheckCapability(WPARAM wParam, LPARAM lParam) +{ + int res = 0; + DBCONTACTGETSETTING dbcgs; + DBVARIANT dbvariant; + HANDLE hContact = (HANDLE)wParam; + ICQ_CUSTOMCAP *icqCustomCap = (ICQ_CUSTOMCAP *)lParam; + dbcgs.pValue = &dbvariant; + dbcgs.szModule = m_szModuleName; + dbcgs.szSetting = "CapBuf"; + + CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); + + if (dbvariant.type == DBVT_BLOB) + { + res = MatchCapability(dbvariant.pbVal, dbvariant.cpbVal, (const capstr*)&icqCustomCap->caps, 0x10)?1:0; // FIXME: Why icqCustomCap->caps is not capstr? + } + + CallService(MS_DB_CONTACT_FREEVARIANT,0,(LPARAM)(DBVARIANT*)&dbvariant); + + return res; +} + + + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR icq_getEventTextMissedMessage(WPARAM wParam, LPARAM lParam) +{ + DBEVENTGETTEXT *pEvent = (DBEVENTGETTEXT *)lParam; + + INT_PTR nRetVal = 0; + char *pszText = NULL; + + if (pEvent->dbei->cbBlob > 1) + { + switch (((WORD*)pEvent->dbei->pBlob)[0]) + { + case 0: + pszText = LPGEN("** This message was blocked by the ICQ server ** The message was invalid."); + break; + + case 1: + pszText = LPGEN("** This message was blocked by the ICQ server ** The message was too long."); + break; + + case 2: + pszText = LPGEN("** This message was blocked by the ICQ server ** The sender has flooded the server."); + break; + + case 4: + pszText = LPGEN("** This message was blocked by the ICQ server ** You are too evil."); + break; + + default: + pszText = LPGEN("** Unknown missed message event."); + break; + } + if (pEvent->datatype == DBVT_WCHAR) + { + WCHAR *pwszText; + int wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszText, strlennull(pszText), NULL, 0); + + pwszText = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); + pwszText[wchars] = 0; + + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszText, strlennull(pszText), pwszText, wchars); + + nRetVal = (INT_PTR)mir_wstrdup(TranslateW(pwszText)); + } + else if (pEvent->datatype == DBVT_ASCIIZ) + nRetVal = (INT_PTR)mir_strdup(Translate(pszText)); + } + + return nRetVal; +} diff --git a/protocols/IcqOscarJ/src/icqosc_svcs.h b/protocols/IcqOscarJ/src/icqosc_svcs.h new file mode 100644 index 0000000000..844eecee51 --- /dev/null +++ b/protocols/IcqOscarJ/src/icqosc_svcs.h @@ -0,0 +1,39 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __ICQOSC_SVCS_H +#define __ICQOSC_SVCS_H + + +#define ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE "ICQ/GetEventTextMissedMessage" + +INT_PTR icq_getEventTextMissedMessage(WPARAM wParam, LPARAM lParam); + + +#endif /* __ICQOSC_SVCS_H */ diff --git a/protocols/IcqOscarJ/src/icqoscar.cpp b/protocols/IcqOscarJ/src/icqoscar.cpp new file mode 100644 index 0000000000..5ce67145cd --- /dev/null +++ b/protocols/IcqOscarJ/src/icqoscar.cpp @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001,2002 Jon Keating, Richard Hughes +// Copyright © 2002,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// The only purpose of this file is to make sure that the precompiled headers +// are included and compiled. The Visual Studio settings for this file must be +// 'Create precompiled header file' and all the other .c files must be set to +// 'User precompiled header file'. Remember to check this when adding new +// files to the project... +// +// ----------------------------------------------------------------------------- + + +#include "icqoscar.h" diff --git a/protocols/IcqOscarJ/src/icqoscar.h b/protocols/IcqOscarJ/src/icqoscar.h new file mode 100644 index 0000000000..ef0e32a6fd --- /dev/null +++ b/protocols/IcqOscarJ/src/icqoscar.h @@ -0,0 +1,134 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Includes all header files that should be precompiled to speed up compilation. +// +// ----------------------------------------------------------------------------- +#define MIRANDA_VER 0x0A00 + +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#include + +// Windows includes +#include +#include +#include + +// Standard includes +#include +#include +#include +#include +#include +#include +#include +#include + +//C++ +#include + +#ifndef _DEBUG +#ifdef _MSC_VER + #include +#endif +#endif + +#ifndef AW_VER_POSITIVE +#define AW_VER_POSITIVE 0x00000004 +#endif + +#ifndef _ASSERTE +#define _ASSERTE(x) +#endif + +// Miranda IM SDK includes +#include // This must be included first +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Project resources +#include "resource.h" + +// ICQ plugin includes +#include "version.h" +#include "iconlib.h" +#include "globals.h" +#include "i18n.h" +#include "icq_db.h" +#include "cookies.h" +#include "icq_packet.h" +#include "utilities.h" +#include "oscar_filetransfer.h" +#include "icq_direct.h" +#include "icq_server.h" +#include "icqosc_svcs.h" +#include "icq_servlist.h" +#include "icq_http.h" +#include "icq_fieldnames.h" +#include "icq_constants.h" +#include "capabilities.h" +#include "guids.h" +#include "init.h" +#include "stdpackets.h" +#include "tlv.h" +#include "channels.h" +#include "families.h" +#include "m_icq.h" +#include "m_icqplus.h" +#include "icq_advsearch.h" +#include "log.h" + +#include "icq_rates.h" + +#include "icq_avatar.h" + +#include "changeinfo/changeinfo.h" +#include "icq_popups.h" +#include "icq_proto.h" + +extern LIST g_Instances; diff --git a/protocols/IcqOscarJ/src/init.cpp b/protocols/IcqOscarJ/src/init.cpp new file mode 100644 index 0000000000..450ea73b16 --- /dev/null +++ b/protocols/IcqOscarJ/src/init.cpp @@ -0,0 +1,245 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" +#include "m_extraicons.h" + +HINSTANCE hInst; +int hLangpack; + +HANDLE hStaticServices[1]; +IcqIconHandle hStaticIcons[4]; +HANDLE hStaticHooks[1];; +HANDLE hExtraXStatus = NULL; + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + "IcqOscarJ Protocol", + __VERSION_DWORD, + "Support for ICQ network, enhanced.", + "Joe Kucera, Bio, Martin Öberg, Richard Hughes, Jon Keating, etc", + "jokusoftware@miranda-im.org", + "(C) 2000-2010 M.Öberg, R.Hughes, J.Keating, Bio, Angeli-Ka, G.Hazan, J.Kucera", + "http://miranda-ng.org/", + UNICODE_AWARE, //doesn't replace anything built-in + {0x73a9615c, 0x7d4e, 0x4555, {0xba, 0xdb, 0xee, 0x5, 0xdc, 0x92, 0x8e, 0xff}} // {73A9615C-7D4E-4555-BADB-EE05DC928EFF} +}; + +extern "C" PLUGININFOEX __declspec(dllexport) *MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static PROTO_INTERFACE* icqProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) +{ + CIcqProto *ppro = new CIcqProto(pszProtoName, tszUserName); + g_Instances.insert(ppro); + return ppro; +} + + +static int icqProtoUninit( PROTO_INTERFACE* ppro ) +{ + g_Instances.remove(( CIcqProto* )ppro); + delete ( CIcqProto* )ppro; + return 0; +} + + +static int OnModulesLoaded( WPARAM, LPARAM ) +{ + hExtraXStatus = ExtraIcon_Register("xstatus", "ICQ XStatus"); + return 0; +} + + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP( &pluginInfo ); + + srand(time(NULL)); + _tzset(); + + // Register the module + PROTOCOLDESCRIPTOR pd = {0}; + pd.cbSize = sizeof(pd); + pd.szName = ICQ_PROTOCOL_NAME; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = icqProtoInit; + pd.fnUninit = icqProtoUninit; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + // Initialize charset conversion routines + InitI18N(); + + // Register static services + hStaticServices[0] = CreateServiceFunction(ICQ_DB_GETEVENTTEXT_MISSEDMESSAGE, icq_getEventTextMissedMessage); + + { + // Define global icons + char szSectionName[MAX_PATH]; + null_snprintf(szSectionName, sizeof(szSectionName), "Protocols/%s", ICQ_PROTOCOL_NAME); + + TCHAR lib[MAX_PATH]; + GetModuleFileName(hInst, lib, MAX_PATH); + hStaticIcons[ISI_AUTH_REQUEST] = IconLibDefine(LPGEN("Request authorization"), szSectionName, NULL, "req_auth", lib, -IDI_AUTH_ASK); + hStaticIcons[ISI_AUTH_GRANT] = IconLibDefine(LPGEN("Grant authorization"), szSectionName, NULL, "grant_auth", lib, -IDI_AUTH_GRANT); + hStaticIcons[ISI_AUTH_REVOKE] = IconLibDefine(LPGEN("Revoke authorization"), szSectionName, NULL, "revoke_auth", lib, -IDI_AUTH_REVOKE); + hStaticIcons[ISI_ADD_TO_SERVLIST] = IconLibDefine(LPGEN("Add to server list"), szSectionName, NULL, "add_to_server", lib, -IDI_SERVLIST_ADD); + } + + hStaticHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + + g_MenuInit(); + return 0; +} + + +extern "C" int __declspec(dllexport) Unload(void) +{ + int i; + + // Release static icon handles + for (i = 0; i < SIZEOF(hStaticIcons); i++) + IconLibRemove(&hStaticIcons[i]); + + // Release static event hooks + for (i = 0; i < SIZEOF(hStaticHooks); i++) + if (hStaticHooks[i]) + UnhookEvent(hStaticHooks[i]); + + // destroying contact menu + g_MenuUninit(); + + // Destroy static service functions + for (i = 0; i < SIZEOF(hStaticServices); i++) + if (hStaticServices[i]) + DestroyServiceFunction(hStaticServices[i]); + + g_Instances.destroy(); + + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// OnPrebuildContactMenu event + +void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow) +{ + CLISTMENUITEM mi = {0}; + + mi.cbSize = sizeof(mi); + if (bShow) + mi.flags = CMIM_FLAGS; + else + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItem, (LPARAM)&mi); +} + +static void CListSetMenuItemIcon(HANDLE hMenuItem, HICON hIcon) +{ + CLISTMENUITEM mi = {0}; + + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS | CMIM_ICON; + + mi.hIcon = hIcon; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItem, (LPARAM)&mi); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnReloadIcons event + +int CIcqProto::OnReloadIcons(WPARAM wParam, LPARAM lParam) +{ + memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid)); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// UpdateGlobalSettings event + +void CIcqProto::UpdateGlobalSettings() +{ + char szServer[MAX_PATH] = ""; + getSettingStringStatic(NULL, "OscarServer", szServer, MAX_PATH); + + m_bSecureConnection = getSettingByte(NULL, "SecureConnection", DEFAULT_SECURE_CONNECTION); + if (szServer[0]) + { + if (strstr(szServer, "aol.com")) + setSettingString(NULL, "OscarServer", m_bSecureConnection ? DEFAULT_SERVER_HOST_SSL : DEFAULT_SERVER_HOST); + + if (m_bSecureConnection && !_strnicmp(szServer, "login.", 6)) + { + setSettingString(NULL, "OscarServer", DEFAULT_SERVER_HOST_SSL); + setSettingWord(NULL, "OscarPort", DEFAULT_SERVER_PORT_SSL); + } + } + + if (m_hServerNetlibUser) + { + NETLIBUSERSETTINGS nlus = {0}; + + nlus.cbSize = sizeof(NETLIBUSERSETTINGS); + if (!m_bSecureConnection && CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)m_hServerNetlibUser, (LPARAM)&nlus)) + { + if (nlus.useProxy && nlus.proxyType == PROXYTYPE_HTTP) + m_bGatewayMode = 1; + else + m_bGatewayMode = 0; + } + else + m_bGatewayMode = 0; + } + + m_bSecureLogin = getSettingByte(NULL, "SecureLogin", DEFAULT_SECURE_LOGIN); + m_bAimEnabled = getSettingByte(NULL, "AimEnabled", DEFAULT_AIM_ENABLED); + m_bUtfEnabled = getSettingByte(NULL, "UtfEnabled", DEFAULT_UTF_ENABLED); + m_wAnsiCodepage = getSettingWord(NULL, "AnsiCodePage", DEFAULT_ANSI_CODEPAGE); + m_bDCMsgEnabled = getSettingByte(NULL, "DirectMessaging", DEFAULT_DCMSG_ENABLED); + m_bTempVisListEnabled = getSettingByte(NULL, "TempVisListEnabled", DEFAULT_TEMPVIS_ENABLED); + m_bSsiEnabled = getSettingByte(NULL, "UseServerCList", DEFAULT_SS_ENABLED); + m_bSsiSimpleGroups = FALSE; /// TODO: enable, after server-list revolution is over + m_bAvatarsEnabled = getSettingByte(NULL, "AvatarsEnabled", DEFAULT_AVATARS_ENABLED); + m_bXStatusEnabled = getSettingByte(NULL, "XStatusEnabled", DEFAULT_XSTATUS_ENABLED); + m_bMoodsEnabled = getSettingByte(NULL, "MoodsEnabled", DEFAULT_MOODS_ENABLED); +} diff --git a/protocols/IcqOscarJ/src/init.h b/protocols/IcqOscarJ/src/init.h new file mode 100644 index 0000000000..0e93a8a89f --- /dev/null +++ b/protocols/IcqOscarJ/src/init.h @@ -0,0 +1,40 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +// Debug defines +#define DBG_CAPHTML +#define DBG_CAPMTN +#define DBG_CAPXTRAZ +#undef DBG_CAPXTRAZ_MUC +#define DBG_NEWCAPS +#define DBG_OSCARFT +#define DBG_AIMCONTACTSEND + +void g_MenuInit(); +void g_MenuUninit(); diff --git a/protocols/IcqOscarJ/src/log.cpp b/protocols/IcqOscarJ/src/log.cpp new file mode 100644 index 0000000000..402863a456 --- /dev/null +++ b/protocols/IcqOscarJ/src/log.cpp @@ -0,0 +1,161 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +extern BOOL bPopUpService; + +static const char *szLevelDescr[] = {LPGEN("ICQ Note"), LPGEN("ICQ Warning"), LPGEN("ICQ Error"), LPGEN("ICQ Fatal")}; + +struct LogMessageInfo { + const char *szMsg; + const char *szTitle; + BYTE bLevel; +}; + + +void __cdecl CIcqProto::icq_LogMessageThread(void* arg) +{ + LogMessageInfo *err = (LogMessageInfo*)arg; + if (!err) + return; + + if (bPopUpService && getSettingByte(NULL, "PopupsLogEnabled", DEFAULT_LOG_POPUPS_ENABLED)) + { + ShowPopUpMsg(NULL, err->szTitle, err->szMsg, err->bLevel); + + SAFE_FREE((void**)&err->szMsg); + SAFE_FREE((void**)&err); + + return; + } + + bErrorBoxVisible = TRUE; + if (err->szMsg && err->szTitle) + MessageBoxUtf(NULL, err->szMsg, err->szTitle, MB_OK); + SAFE_FREE((void**)&err->szMsg); + SAFE_FREE((void**)&err); + bErrorBoxVisible = FALSE; +} + + +void CIcqProto::icq_LogMessage(int level, const char *szMsg) +{ + NetLog_Server("%s", szMsg); + + int displayLevel = getSettingByte(NULL, "ShowLogLevel", LOG_WARNING); + if (level >= displayLevel) + { + if (!bErrorBoxVisible || !getSettingByte(NULL, "IgnoreMultiErrorBox", 0)) + { + // error not shown or allowed multi - show messagebox + LogMessageInfo *lmi = (LogMessageInfo*)SAFE_MALLOC(sizeof(LogMessageInfo)); + lmi->bLevel = (BYTE)level; + lmi->szMsg = null_strdup(szMsg); + lmi->szTitle = szLevelDescr[level]; + ForkThread( &CIcqProto::icq_LogMessageThread, lmi); + } + } +} + +void CIcqProto::icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg) +{ + char szBuf[1024]; + char str[1024]; + char str2[64]; + char szErrorMsg[512]; + char *pszErrorMsg = NULL; + int bNeedFree = FALSE; + + switch(dwError) { + case ERROR_TIMEOUT: + case WSAETIMEDOUT: + pszErrorMsg = LPGEN("The server did not respond to the connection attempt within a reasonable time, it may be temporarily down. Try again later."); + break; + + case ERROR_GEN_FAILURE: + pszErrorMsg = LPGEN("The connection with the server was abortively closed during the connection attempt. You may have lost your local network connection."); + break; + + case WSAEHOSTUNREACH: + case WSAENETUNREACH: + pszErrorMsg = LPGEN("Miranda was unable to resolve the name of a server to its numeric address. This is most likely caused by a catastrophic loss of your network connection (for example, your modem has disconnected), but if you are behind a proxy, you may need to use the 'Resolve hostnames through proxy' option in M->Options->Network."); + break; + + case WSAEHOSTDOWN: + case WSAENETDOWN: + case WSAECONNREFUSED: + pszErrorMsg = LPGEN("Miranda was unable to make a connection with a server. It is likely that the server is down, in which case you should wait for a while and try again later."); + break; + + case ERROR_ACCESS_DENIED: + pszErrorMsg = LPGEN("Your proxy rejected the user name and password that you provided. Please check them in M->Options->Network."); + break; + + case WSAHOST_NOT_FOUND: + case WSANO_DATA: + pszErrorMsg = LPGEN("The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ."); + break; + + default: + { + TCHAR err[512]; + + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, err, SIZEOF(err), NULL)) + { + + pszErrorMsg = make_utf8_string(err); + + bNeedFree = TRUE; + } + break; + } + } + + null_snprintf(szBuf, sizeof(szBuf), "%s%s%s (%s %d)", + szMsg ? ICQTranslateUtfStatic(szMsg, str, 1024) : "", + szMsg ? "\r\n\r\n" : "", + ICQTranslateUtfStatic(pszErrorMsg, szErrorMsg, 512), + ICQTranslateUtfStatic(LPGEN("error"), str2, 64), + dwError); + + if (bNeedFree) + SAFE_FREE(&pszErrorMsg); + + icq_LogMessage(level, szBuf); +} + +void CIcqProto::icq_LogFatalParam(const char *szMsg, WORD wError) +{ + char str[MAX_PATH]; + char buf[MAX_PATH]; + + null_snprintf(buf, MAX_PATH, ICQTranslateUtfStatic(szMsg, str, MAX_PATH), wError); + icq_LogMessage(LOG_FATAL, buf); +} diff --git a/protocols/IcqOscarJ/src/log.h b/protocols/IcqOscarJ/src/log.h new file mode 100644 index 0000000000..6da25df0d7 --- /dev/null +++ b/protocols/IcqOscarJ/src/log.h @@ -0,0 +1,38 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __LOG_H +#define __LOG_H + +#define LOG_NOTE 0 //trivial problems or problems that will already have been reported elsewhere +#define LOG_WARNING 1 //problems that may have caused data loss +#define LOG_ERROR 2 //problems that cause a disconnection from the network +#define LOG_FATAL 3 //problems requiring user intervention: password wrong, rate exceeded, etc. + +#endif /* __LOG_H */ diff --git a/protocols/IcqOscarJ/src/oscar_filetransfer.cpp b/protocols/IcqOscarJ/src/oscar_filetransfer.cpp new file mode 100644 index 0000000000..9630abc070 --- /dev/null +++ b/protocols/IcqOscarJ/src/oscar_filetransfer.cpp @@ -0,0 +1,2447 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// OSCAR File-Transfers implementation +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +struct oscarthreadstartinfo +{ + int type; + int incoming; + HANDLE hContact; + HANDLE hConnection; + DWORD dwRemoteIP; + oscar_filetransfer *ft; + oscar_listener *listener; +}; + + +// small utility function +extern void NormalizeBackslash(char* path); + +// +// Common functions +///////////////////////////// + +char *FindFilePathContainer(const char **files, int iFile, char *szContainer) +{ + const char *szThisFile = files[iFile]; + char *szFileName = (char*)ExtractFileName(szThisFile); + + szContainer[0] = '\0'; + + if (szThisFile != szFileName) + { // find an earlier subdirectory to be used as a container + for (int i = iFile - 1; i >= 0; i--) + { + int len = strlennull(files[i]); + + if (!_strnicmp(files[i], szThisFile, len) && (szThisFile[len] == '\\' || szThisFile[len] == '/')) + { + const char *pszLastBackslash; + + if (((pszLastBackslash = strrchr(files[i], '\\')) == NULL) && + ((pszLastBackslash = strrchr(files[i], '/')) == NULL)) + { + strcpy(szContainer, files[i]); + } + else + { + len = pszLastBackslash - files[i] + 1; + null_strcpy(szContainer, szThisFile + len, szFileName - szThisFile - len); + } + } + } + } + return szFileName; +} + + +// +// Utility functions +///////////////////////////// + +oscar_filetransfer* CIcqProto::CreateOscarTransfer() +{ + oscar_filetransfer* ft = (oscar_filetransfer*)SAFE_MALLOC(sizeof(oscar_filetransfer)); + + ft->ft_magic = FT_MAGIC_OSCAR; // Setup signature + // Init members + ft->fileId = -1; + + icq_lock l(oftMutex); + + fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*(fileTransferCount + 1)); + fileTransferList[fileTransferCount++] = ft; + +#ifdef _DEBUG + NetLog_Direct("OFT: FT struct 0x%x created", ft); +#endif + + return ft; +} + + +filetransfer *CIcqProto::CreateIcqFileTransfer() +{ + filetransfer *ft = (filetransfer*)SAFE_MALLOC(sizeof(filetransfer)); + + ft->ft_magic = FT_MAGIC_ICQ; + + icq_lock l(oftMutex); + + fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*(fileTransferCount + 1)); + fileTransferList[fileTransferCount++] = (basic_filetransfer*)ft; + +#ifdef _DEBUG + NetLog_Direct("FT struct 0x%x created", ft); +#endif + + return ft; +} + + +int CIcqProto::getFileTransferIndex(void *ft) +{ + for (int i = 0; i < fileTransferCount; i++) + { + if (fileTransferList[i] == ft) + return i; + } + return -1; +} + + +void CIcqProto::ReleaseFileTransfer(void *ft) +{ + int i = getFileTransferIndex(ft); + + if (i != -1) + { + fileTransferCount--; + fileTransferList[i] = fileTransferList[fileTransferCount]; + fileTransferList = (basic_filetransfer**)SAFE_REALLOC(fileTransferList, sizeof(basic_filetransfer*)*fileTransferCount); + } +} + + +int CIcqProto::IsValidFileTransfer(void *ft) +{ + icq_lock l(oftMutex); + + if (getFileTransferIndex(ft) != -1) return 1; + + return 0; +} + + +int CIcqProto::IsValidOscarTransfer(void *ft) +{ + icq_lock l(oftMutex); + + if (getFileTransferIndex(ft) != -1 && ((basic_filetransfer*)ft)->ft_magic == FT_MAGIC_OSCAR) + return 1; + + return 0; +} + + +oscar_filetransfer* CIcqProto::FindOscarTransfer(HANDLE hContact, DWORD dwID1, DWORD dwID2) +{ + icq_lock l(oftMutex); + + for (int i = 0; i < fileTransferCount; i++) + { + if (fileTransferList[i]->ft_magic == FT_MAGIC_OSCAR) + { + oscar_filetransfer *oft = (oscar_filetransfer*)fileTransferList[i]; + + if (oft->hContact == hContact && oft->pMessage.dwMsgID1 == dwID1 && oft->pMessage.dwMsgID2 == dwID2) + return oft; + } + } + + return NULL; +} + + +// Release file transfer structure +void CIcqProto::SafeReleaseFileTransfer(void **ft) +{ + basic_filetransfer **bft = (basic_filetransfer**)ft; + + icq_lock l(oftMutex); + + // Check for filetransfer validity + if (getFileTransferIndex(*ft) == -1) + return; + + if (*bft) + { + if ((*bft)->ft_magic == FT_MAGIC_ICQ) + { // release ICQ filetransfer structure and its contents + filetransfer *ift = (filetransfer*)(*bft); + + SAFE_FREE(&ift->szFilename); + SAFE_FREE(&ift->szDescription); + SAFE_FREE(&ift->szSavePath); + SAFE_FREE(&ift->szThisFile); + SAFE_FREE(&ift->szThisSubdir); + if (ift->pszFiles) + { + for (int i = 0; i < (int)ift->dwFileCount; i++) + SAFE_FREE(&ift->pszFiles[i]); + SAFE_FREE((void**)&ift->pszFiles); + } + // Invalidate transfer + ReleaseFileTransfer(ift); +#ifdef _DEBUG + NetLog_Direct("FT struct 0x%x released", ft); +#endif + // Release memory + SAFE_FREE((void**)ft); + } + else if ((*bft)->ft_magic == FT_MAGIC_OSCAR) + { // release oscar filetransfer structure and its contents + oscar_filetransfer *oft = (oscar_filetransfer*)(*bft); + // If connected, close connection + if (oft->connection) + CloseOscarConnection(oft->connection); + // Release oscar listener + if (oft->listener) + ReleaseOscarListener((oscar_listener**)&oft->listener); + // Release cookie + if (oft->dwCookie) + FreeCookie(oft->dwCookie); + // Release all dynamic members + SAFE_FREE(&oft->rawFileName); + SAFE_FREE(&oft->szSavePath); + SAFE_FREE(&oft->szThisFile); + SAFE_FREE(&oft->szThisPath); + SAFE_FREE(&oft->szDescription); + if (oft->files) + { + for (int i = 0; i < oft->wFilesCount; i++) + SAFE_FREE(&oft->files[i].szFile); + SAFE_FREE((void**)&oft->files); + } + if (oft->files_list) + { +/* for (int i = 0; i < oft->wFilesCount; i++) + SAFE_FREE(&oft->files_list[i]);*/ + SAFE_FREE((void**)&oft->files_list); + } + if (oft->file_containers) + { + for (int i = 0; i < oft->containerCount; i++) + SAFE_FREE(&oft->file_containers[i]); + SAFE_FREE((void**)&oft->file_containers); + } + if (oft->fileId != -1) + { +#ifdef _DEBUG + NetLog_Direct("OFT: _close(%u)", oft->fileId); +#endif + _close(oft->fileId); + } + // Invalidate transfer + ReleaseFileTransfer(oft); +#ifdef _DEBUG + NetLog_Direct("OFT: FT struct 0x%x released", ft); +#endif + // Release memory + SAFE_FREE((void**)ft); + } + } +} + + +// Calculate oft checksum of buffer +// -------------------------------- +// Information was gathered from Gaim's sources, thanks +// +DWORD oft_calc_checksum(int offset, const BYTE *buffer, int len, DWORD dwChecksum) +{ + DWORD checksum = (dwChecksum >> 16) & 0xffff; + + for (int i = 0; i < len; i++) + { + WORD val = buffer[i]; + DWORD oldchecksum = checksum; + + if (((i + offset) & 1) == 0) + val = val << 8; + + if (checksum < val) + checksum -= val + 1; + else // simulate carry + checksum -= val; + } + checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); + checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); + return checksum << 16; +} + + +DWORD oft_calc_file_checksum(int hFile, __int64 maxSize) +{ + BYTE buf[OFT_BUFFER_SIZE]; + int bytesRead; + __int64 offset = 0; + DWORD dwCheck = 0xFFFF0000; + + _lseek(hFile, 0, SEEK_SET); + bytesRead = _read(hFile, buf, (maxSize < sizeof(buf)) ? maxSize : (unsigned)sizeof(buf)); + if (bytesRead == -1) + return dwCheck; + + while(bytesRead) + { + dwCheck = oft_calc_checksum((int)offset, buf, bytesRead, dwCheck); + offset += bytesRead; + bytesRead = _read(hFile, buf, sizeof(buf)); + if (bytesRead + offset > maxSize) bytesRead = (int)(maxSize - offset); + } + _lseek(hFile, 0, SEEK_SET); // back to beginning + + return dwCheck; +} + + +oscar_listener* CIcqProto::CreateOscarListener(oscar_filetransfer *ft, NETLIBNEWCONNECTIONPROC_V2 handler) +{ + oscar_listener *listener = (oscar_listener*)SAFE_MALLOC(sizeof(oscar_listener)); + + if (listener) + { + listener->ppro = this; + listener->ft = ft; + if (listener->hBoundPort = NetLib_BindPort(handler, listener, &listener->wPort, NULL)) + return listener; // Success + + SAFE_FREE((void**)&listener); + } + + return NULL; // Failure +} + + +void CIcqProto::ReleaseOscarListener(oscar_listener **pListener) +{ + oscar_listener *listener = *pListener; + + if (listener) + { // Close listening port + if (listener->hBoundPort) + NetLib_SafeCloseHandle(&listener->hBoundPort); + + NetLog_Direct("Oscar listener on port %d released.", listener->wPort); + } + SAFE_FREE((void**)pListener); +} + + +// +// Miranda FT interface handlers & services +///////////////////////////// + +void CIcqProto::handleRecvServMsgOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand) +{ + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (wCommand == 0) + { // this is OFT request + oscar_tlv_chain* chain = readIntoTLVChain(&buf, wLen, 0); + + if (chain) + { + WORD wAckType = chain->getWord(0x0A, 1); + + if (wAckType == 1) + { // This is first request in this OFT + oscar_filetransfer *ft = CreateOscarTransfer(); + char *pszFileName = NULL; + char *pszDescription = NULL; + WORD wFilenameLength; + + NetLog_Server("This is a file request"); + + // This TLV chain may contain the following TLVs: + // TLV(A): Acktype 0x0001 - file request / abort request + // 0x0002 - file ack + // TLV(F): Unknown + // TLV(E): Language ? + // TLV(2): Proxy IP + // TLV(16): Proxy IP Check + // TLV(3): External IP + // TLV(4): Internal IP + // TLV(5): Port + // TLV(17): Port Check + // TLV(10): Proxy Flag + // TLV(D): Charset of User Message + // TLV(C): User Message (ICQ_COOL_FT) + // TLV(2711): FT info + // TLV(2712): Charset of file name + + // init filetransfer structure + ft->pMessage.dwMsgID1 = dwID1; + ft->pMessage.dwMsgID2 = dwID2; + ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; + ft->dwProxyIP = chain->getDWord(0x02, 1); + ft->dwRemoteInternalIP = chain->getDWord(0x03, 1); + ft->dwRemoteExternalIP = chain->getDWord(0x04, 1); + ft->wRemotePort = chain->getWord(0x05, 1); + ft->wReqNum = wAckType; + + { // User Message + oscar_tlv* tlv = chain->getTLV(0x0C, 1); + + if (tlv) + { // parse User Message + BYTE* tBuf = tlv->pData; + + pszDescription = (char*)_alloca(tlv->wLen + 2); + unpackString(&tBuf, (char*)pszDescription, tlv->wLen); + pszDescription[tlv->wLen] = '\0'; + pszDescription[tlv->wLen+1] = '\0'; + { // apply User Message encoding + oscar_tlv *charset = chain->getTLV(0x0D, 1); + char *str = pszDescription; + char *bTag,*eTag; + + if (charset) + { // decode charset + char *szEnc = (char*)_alloca(charset->wLen + 1); + + null_strcpy(szEnc, (char*)charset->pData, charset->wLen); + str = ApplyEncoding((char*)pszDescription, szEnc); + } + else + str = null_strdup(str); + // eliminate HTML tags + pszDescription = EliminateHtml(str, strlennull(str)); + + bTag = strstrnull(pszDescription, ""); + if (bTag) + { // take special Description - ICQJ's extension + eTag = strstrnull(bTag, ""); + if (eTag) + { + *eTag = '\0'; + str = null_strdup(bTag + 6); + SAFE_FREE(&pszDescription); + pszDescription = str; + } + } + else + { + bTag = strstrnull(pszDescription, ""); + if (bTag) + { // take only - Description tag if present + eTag = strstrnull(bTag, ""); + if (eTag) + { + *eTag = '\0'; + str = null_strdup(bTag + 4); + SAFE_FREE(&pszDescription); + pszDescription = str; + } + } + } + } + } + if (!strlennull(pszDescription)) + { + SAFE_FREE(&pszDescription); + pszDescription = ICQTranslateUtf(LPGEN("No description given")); + } + } + { // parse File Transfer Info block + oscar_tlv* tlv = chain->getTLV(0x2711, 1); + + // sanity check + if (!tlv || tlv->wLen < 8) + { + NetLog_Server("Error: Malformed file request"); + // release structures + SafeReleaseFileTransfer((void**)&ft); + SAFE_FREE(&pszDescription); + return; + } + + BYTE* tBuf = tlv->pData; + WORD tLen = tlv->wLen; + WORD wFlag; + + unpackWord(&tBuf, &wFlag); // FT flag + unpackWord(&tBuf, &ft->wFilesCount); + unpackDWord(&tBuf, (DWORD*)&ft->qwTotalSize); + tLen -= 8; + // Filename / Directory Name + if (tLen) + { // some filename specified, unpack + wFilenameLength = tLen - 1; + pszFileName = (char*)_alloca(tLen); + unpackString(&tBuf, (char*)pszFileName, wFilenameLength); + pszFileName[wFilenameLength] = '\0'; + } + else if (ft->wFilesCount == 1) // give some generic file name + pszFileName = "unnamed_file"; + else // or empty directory name + pszFileName = ""; + + // apply Filename / Directory Name encoding + oscar_tlv* charset = chain->getTLV(0x2712, 1); + if (charset) { + char* szEnc = (char*)_alloca(charset->wLen + 1); + null_strcpy(szEnc, (char*)charset->pData, charset->wLen); + pszFileName = ApplyEncoding(pszFileName, szEnc); + } + else pszFileName = ansi_to_utf8(pszFileName); + + if (ft->wFilesCount == 1) + { // Filename - use for DB event + char *szFileName = (char*)_alloca(strlennull(pszFileName) + 1); + + strcpy(szFileName, pszFileName); + SAFE_FREE(&pszFileName); + pszFileName = szFileName; + } + else + { // Save Directory name for future use + ft->szThisPath = pszFileName; + // for multi-file transfer we do not display "folder" name, but create only a simple notice + pszFileName = (char*)_alloca(64); + + char tmp[64]; + null_snprintf(pszFileName, 64, ICQTranslateUtfStatic(LPGEN("%d Files"), tmp, SIZEOF(tmp)), ft->wFilesCount); + } + } + // Total Size TLV (ICQ 6 and AIM 6) + { + oscar_tlv *tlv = chain->getTLV(0x2713, 1); + + if (tlv && tlv->wLen >= 8) + { + BYTE *tBuf = tlv->pData; + + unpackQWord(&tBuf, &ft->qwTotalSize); + } + } + int bAdded; + HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded); + + ft->hContact = hContact; + ft->fileId = -1; + + // Send chain event + char *szBlob = (char*)_alloca(sizeof(DWORD) + strlennull(pszFileName) + strlennull(pszDescription) + 2); + *(PDWORD)szBlob = 0; + strcpy(szBlob + sizeof(DWORD), pszFileName); + strcpy(szBlob + sizeof(DWORD) + strlennull(pszFileName) + 1, pszDescription); + + TCHAR* ptszFileName = mir_utf8decodeT(pszFileName); + + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time(NULL); + pre.tszDescription = mir_utf8decodeT(pszDescription); + pre.ptszFiles = &ptszFileName; + pre.lParam = (LPARAM)ft; + + CCSDATA ccs; + ccs.szProtoService = PSR_FILE; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + mir_free(pre.tszDescription); + mir_free(ptszFileName); + } + else if (wAckType == 2) + { // First attempt failed, reverse requested + oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); + + if (ft) + { + NetLog_Direct("OFT: Redirect received (%d)", wAckType); + + ft->wReqNum = wAckType; + + if (ft->flags & OFTF_SENDING) + { + ReleaseOscarListener((oscar_listener**)&ft->listener); + + ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; + ft->dwProxyIP = chain->getDWord(0x02, 1); + ft->dwRemoteInternalIP = chain->getDWord(0x03, 1); + ft->dwRemoteExternalIP = chain->getDWord(0x04, 1); + ft->wRemotePort = chain->getWord(0x05, 1); + + OpenOscarConnection(hContact, ft, ft->bUseProxy ? OCT_PROXY_RECV: OCT_REVERSE); + } + else + { // Just sanity + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&ft); + } + } + else + NetLog_Server("Error: Invalid request, no such transfer"); + } + else if (wAckType == 3) + { // Transfering thru proxy, join tunnel + oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); + + if (ft) + { // release possible previous listener + NetLog_Direct("OFT: Redirect received (%d)", wAckType); + + ft->wReqNum = wAckType; + + ReleaseOscarListener((oscar_listener**)&ft->listener); + + ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; + ft->dwProxyIP = chain->getDWord(0x02, 1); + ft->wRemotePort = chain->getWord(0x05, 1); + + if (ft->bUseProxy && ft->dwProxyIP) + { // Init proxy connection + OpenOscarConnection(hContact, ft, OCT_PROXY_RECV); + } + else + { // try Stage 4 + OpenOscarConnection(hContact, ft, OCT_PROXY); + } + } + else + NetLog_Server("Error: Invalid request, no such transfer"); + } + else if (wAckType == 4) + { + oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); + + if (ft) + { + NetLog_Direct("OFT: Redirect received (%d)", wAckType); + + ft->wReqNum = wAckType; + ft->bUseProxy = chain->getTLV(0x10, 1) ? 1 : 0; + ft->dwProxyIP = chain->getDWord(0x02, 1); + ft->wRemotePort = chain->getWord(0x05, 1); + + if (ft->bUseProxy && ft->dwProxyIP) + { // Init proxy connection + OpenOscarConnection(hContact, ft, OCT_PROXY_RECV); + } + else + NetLog_Server("Error: Invalid request, IP missing."); + } + else + NetLog_Server("Error: Invalid request, no such transfer"); + } + else + NetLog_Server("Error: Uknown Stage %d request", wAckType); + + disposeChain(&chain); + } + else + NetLog_Server("Error: Missing TLV chain in OFT request"); + } + else if (wCommand == 1) + { // transfer cancelled/aborted + oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); + + if (ft) + { + NetLog_Server("OFT: File transfer cancelled by %s", strUID(dwUin, szUID)); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); + // Notify user, that the FT was cancelled // TODO: new ACKRESULT_? + icq_LogMessage(LOG_ERROR, LPGEN("The file transfer was aborted by the other user.")); + // Release transfer + SafeReleaseFileTransfer((void**)&ft); + } + else + NetLog_Server("Error: Invalid request, no such transfer"); + } + else if (wCommand == 2) + { // transfer accepted - connection established + oscar_filetransfer *ft = FindOscarTransfer(hContact, dwID1, dwID2); + + if (ft) + { + NetLog_Direct("OFT: Session established."); + // Init connection + if (ft->flags & OFTF_SENDING) + { + if (ft->connection && ft->connection->status == OCS_CONNECTED) + { + if (!(ft->flags & OFTF_FILE_REQUEST_SENT)) + { + ft->flags |= OFTF_FILE_REQUEST_SENT; + // proceed with first file + oft_sendPeerInit(ft->connection); + } + } + ft->flags |= OFTF_INITIALIZED; // accept was received + } + else + NetLog_Server("Warning: Received invalid rendezvous accept"); + } + else + NetLog_Server("Error: Invalid request, no such transfer"); + } + else + { + NetLog_Server("Error: Unknown wCommand=0x%x in OFT request", wCommand); + } +} + + +void CIcqProto::handleRecvServResponseOFT(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, void* ft) +{ + WORD wDataLen; + + if (wLen < 2) return; + + unpackWord(&buf, &wDataLen); + + if (wDataLen == 2) + { + oscar_filetransfer *oft = (oscar_filetransfer*)ft; + WORD wStatus; + + unpackWord(&buf, &wStatus); + + switch (wStatus) + { + case 1: + { // FT denied (icq5) + NetLog_Server("OFT: File transfer denied by %s", strUID(dwUin, szUID)); + + BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)oft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oft); + } + break; + + case 4: // Proxy error + { + icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Proxy error")); + + BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oft); + } + break; + + case 5: // Invalid request + { + icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Invalid request")); + + BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oft); + } + break; + + case 6: // Proxy Failed (IP = 0) + { + icq_LogMessage(LOG_ERROR, LPGEN("The file transfer failed: Proxy unavailable")); + + BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oft); + } + break; + + default: + { + NetLog_Server("OFT: Uknown request response code 0x%x", wStatus); + + BroadcastAck(oft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)oft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oft); + } + } + } +} + + +// This function is called from the Netlib when someone is connecting to our oscar_listener +static void oft_newConnectionReceived(HANDLE hNewConnection, DWORD dwRemoteIP, void *pExtra) +{ + oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo)); + oscar_listener *listener = (oscar_listener*)pExtra; + + otsi->type = listener->ft->flags & OFTF_SENDING ? OCT_NORMAL : OCT_REVERSE; + otsi->incoming = 1; + otsi->hConnection = hNewConnection; + otsi->dwRemoteIP = dwRemoteIP; + otsi->listener = listener; + + // Start a new thread for the incomming connection + listener->ppro->ForkThread(( IcqThreadFunc )&CIcqProto::oft_connectionThread, otsi ); +} + + +static char *oftGetFileContainer(oscar_filetransfer* oft, const char** files, int iFile) +{ + char szPath[MAX_PATH]; + char* szFileName = FindFilePathContainer(files, iFile, szPath); + char *szPathUtf = ansi_to_utf8(szPath); + int i; + + // try to find existing container + for (i = 0; i < oft->containerCount; i++) + if (!strcmpnull(szPathUtf, oft->file_containers[i])) + { + SAFE_FREE((void**)&szPathUtf); + + return oft->file_containers[i]; + } + + // create new container + i = oft->containerCount++; + oft->file_containers = (char**)SAFE_REALLOC(oft->file_containers, (sizeof(char*) * oft->containerCount)); + oft->file_containers[i] = szPathUtf; + + return oft->file_containers[i]; +} + + +HANDLE CIcqProto::oftInitTransfer(HANDLE hContact, DWORD dwUin, char* szUid, const TCHAR** files, const TCHAR* pszDesc) +{ + oscar_filetransfer *ft; + int i, filesCount; + struct _stati64 statbuf; + char ** filesUtf; + + // Initialize filetransfer struct + NetLog_Server("Init file send"); + + ft = CreateOscarTransfer(); + ft->hContact = hContact; + ft->pMessage.bMessageType = MTYPE_FILEREQ; + InitMessageCookie(&ft->pMessage); + + for (filesCount = 0; files[filesCount]; filesCount++); + ft->files = (oft_file_record *)SAFE_MALLOC(sizeof(oft_file_record) * filesCount); + ft->files_list = (char**)SAFE_MALLOC(sizeof(TCHAR *) * filesCount); + ft->qwTotalSize = 0; + + filesUtf = (char**)SAFE_MALLOC(sizeof(char *) * filesCount); + for(i = 0; i < filesCount; i++) filesUtf[i] = FileNameToUtf(files[i]); + + // Prepare files arrays + for (i = 0; i < filesCount; i++) + { + if (_tstati64(files[i], &statbuf)) + NetLog_Server("IcqSendFile() was passed invalid filename \"%s\"", files[i]); + else + { + if (!(statbuf.st_mode&_S_IFDIR)) + { // take only files + ft->files[ft->wFilesCount].szFile = ft->files_list[ft->wFilesCount] = null_strdup(filesUtf[i]); + ft->files[ft->wFilesCount].szContainer = oftGetFileContainer(ft, (LPCSTR*) filesUtf, i); + + ft->wFilesCount++; + ft->qwTotalSize += statbuf.st_size; + } + } + } + + for (i = 0; i < filesCount; i++) + SAFE_FREE(&filesUtf[i]); + SAFE_FREE((void**)&filesUtf); + + if (!ft->wFilesCount) + { // found no valid files to send + icq_LogMessage(LOG_ERROR, LPGEN("Failed to Initialize File Transfer. No valid files were specified.")); + // Notify UI + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&ft); + + return 0; // Failure + } +#ifdef __GNUC__ +#define OSCAR_MAX_SIZE 0x100000000ULL +#else +#define OSCAR_MAX_SIZE 0x100000000 +#endif + if (ft->qwTotalSize >= OSCAR_MAX_SIZE && ft->wFilesCount > 1) + { // file larger than 4GB can be send only as single + icq_LogMessage(LOG_ERROR, LPGEN("The files are too big to be sent at once. Files bigger than 4GB can be sent only separately.")); + // Notify UI + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&ft); + + return 0; // Failure + } + + NetLog_Server("OFT: Found %d files.", ft->wFilesCount); + + ft->szDescription = tchar_to_utf8(pszDesc); + ft->flags = OFTF_SENDING; + ft->fileId = -1; + ft->iCurrentFile = 0; + ft->dwCookie = AllocateCookie(CKT_FILE, ICQ_MSG_SRV_SEND, hContact, ft); + + // Init oscar fields + { + ft->wEncrypt = 0; + ft->wCompress = 0; + ft->wPartsCount = 1; + ft->wPartsLeft = 1; + strcpy(ft->rawIDString, "Cool FileXfer"); + ft->bHeaderFlags = 0x20; + ft->bNameOff = 0x1C; + ft->bSizeOff = 0x11; + ft->dwRecvForkCheck = 0xFFFF0000; + ft->dwThisForkCheck = 0xFFFF0000; + ft->dwRecvFileCheck = 0xFFFF0000; + } + + // Send file transfer request + { + char *pszFiles; + + if (ft->wFilesCount == 1) + { // transfering single file, give filename + pszFiles = (char*)ExtractFileName(ft->files[0].szFile); + } + else + { // check if transfering one directory + char *szFirstDiv, *szFirstDir = ft->file_containers[0]; + int nFirstDirLen; + + // default is no root dir + pszFiles = ""; + + if ((szFirstDiv = strstrnull(szFirstDir, "\\")) || (szFirstDiv = strstrnull(szFirstDir, "/"))) + nFirstDirLen = szFirstDiv - szFirstDir; + else + nFirstDirLen = strlennull(szFirstDir); + + if (nFirstDirLen) + { // got root dir from first container, check if others are only sub-dirs + for (i = 0; i < ft->containerCount; i++) + { + if (_strnicmp((char*)ft->file_containers[i], (char*)szFirstDir, nFirstDirLen)) + { + szFirstDir = NULL; + break; + } + } + if (szFirstDir) + { // fine, we are sending only one directory + pszFiles = szFirstDir; + if (szFirstDiv) szFirstDiv[0] = '\0'; + nFirstDirLen++; // include backslash + // cut all files container by root dir - it is transferred as root separately + for (i = 0; i < ft->wFilesCount; i++) + ft->files[i].szContainer += nFirstDirLen; + } + } + } + + // Create listener + ft->listener = CreateOscarListener(ft, oft_newConnectionReceived); + + // Send packet + if (ft->listener) + { + oft_sendFileRequest(dwUin, szUid, ft, pszFiles, getSettingDword(NULL, "RealIP", 0)); + } + else + { // try stage 1 proxy + ft->szThisFile = null_strdup(pszFiles); + OpenOscarConnection(hContact, ft, OCT_PROXY_INIT); + } + } + + return ft; // Success +} + + +HANDLE CIcqProto::oftFileAllow(HANDLE hContact, HANDLE hTransfer, const TCHAR *szPath) +{ + oscar_filetransfer *ft = (oscar_filetransfer*)hTransfer; + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 0; // Invalid contact + + if (!IsValidOscarTransfer(ft)) + return 0; // Invalid transfer + + ft->szSavePath = tchar_to_utf8(szPath); + + if (ft->szThisPath) + { // Append Directory name to the save path, when transfering a directory + ft->szSavePath = (char*)SAFE_REALLOC(ft->szSavePath, strlennull(ft->szSavePath) + strlennull(ft->szThisPath) + 4); + NormalizeBackslash(ft->szSavePath); + strcat(ft->szSavePath, ft->szThisPath); + NormalizeBackslash(ft->szSavePath); + } +#ifdef _DEBUG + NetLog_Direct("OFT: Request accepted, saving to '%s'.", ft->szSavePath); +#endif + + // Create cookie + ft->dwCookie = AllocateCookie(CKT_FILE, ICQ_MSG_SRV_SEND, hContact, ft); + + OpenOscarConnection(hContact, ft, ft->bUseProxy ? OCT_PROXY_RECV: OCT_NORMAL); + return hTransfer; // Success +} + + +DWORD CIcqProto::oftFileDeny(HANDLE hContact, HANDLE hTransfer, const TCHAR *szReason) +{ + oscar_filetransfer *ft = (oscar_filetransfer*)hTransfer; + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (IsValidOscarTransfer(ft)) + { + if (ft->hContact != hContact) + return 1; // Bad contact or hTransfer + +#ifdef _DEBUG + NetLog_Direct("OFT: Request denied."); +#endif + + oft_sendFileDeny(dwUin, szUid, ft); + + // Release structure + SafeReleaseFileTransfer((void**)&ft); + + return 0; // Success + } + return 1; // Invalid transfer +} + + +DWORD CIcqProto::oftFileCancel(HANDLE hContact, HANDLE hTransfer) +{ + oscar_filetransfer* ft = (oscar_filetransfer*)hTransfer; + DWORD dwUin; + uid_str szUid; + + if (getContactUid(hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (IsValidOscarTransfer(ft)) + { + if (ft->hContact != hContact) + return 1; // Bad contact or hTransfer + +#ifdef _DEBUG + NetLog_Direct("OFT: Transfer cancelled."); +#endif + + oft_sendFileCancel(dwUin, szUid, ft); + + BroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + + // Release structure + SafeReleaseFileTransfer((void**)&ft); + + return 0; // Success + } + return 1; // Invalid transfer +} + + +void CIcqProto::oftFileResume(oscar_filetransfer *ft, int action, const TCHAR *szFilename) +{ + int openFlags; + + if (ft->connection == NULL) + return; + + oscar_connection *oc = ft->connection; + +#ifdef _DEBUG + NetLog_Direct("OFT: Resume Transfer, Action: %d, FileName: '%s'", action, szFilename); +#endif + + switch (action) + { + case FILERESUME_RESUME: + openFlags = _O_BINARY | _O_RDWR; + break; + + case FILERESUME_OVERWRITE: + openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; + ft->qwFileBytesDone = 0; + break; + + case FILERESUME_SKIP: + openFlags = _O_BINARY | _O_WRONLY; + ft->qwFileBytesDone = ft->qwThisFileSize; + break; + + case FILERESUME_RENAME: + openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; + SAFE_FREE(&ft->szThisFile); + ft->szThisFile = tchar_to_utf8(szFilename); + ft->qwFileBytesDone = 0; + break; + + default: // workaround for bug in Miranda Core + if (ft->resumeAction == FILERESUME_RESUME) + openFlags = _O_BINARY | _O_RDWR; + else + { // default to overwrite + openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY; + ft->qwFileBytesDone = 0; + } + } + ft->resumeAction = action; + + ft->fileId = OpenFileUtf(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE); +#ifdef _DEBUG + NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, openFlags, ft->fileId); +#endif + if (ft->fileId == -1) + { +#ifdef _DEBUG + NetLog_Direct("OFT: errno=%d", errno); +#endif + icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oc->ft); + return; + } + + if (action == FILERESUME_RESUME) + ft->qwFileBytesDone = _lseeki64(ft->fileId, 0, SEEK_END); + else + _lseeki64(ft->fileId, ft->qwFileBytesDone, SEEK_SET); + + ft->qwBytesDone += ft->qwFileBytesDone; + + if (action == FILERESUME_RESUME) + { // use smart-resume + oc->status = OCS_RESUME; + ft->dwRecvFileCheck = oft_calc_file_checksum(ft->fileId, ft->qwFileBytesDone); + _lseek(ft->fileId, 0, SEEK_END); + +#ifdef _DEBUG + NetLog_Direct("OFT: Starting Smart-Resume"); +#endif + + sendOFT2FramePacket(oc, OFT_TYPE_RESUMEREQUEST); + + return; + } + else if (action == FILERESUME_SKIP) + { // we are skipping the file, send "we are done" + oc->status = OCS_NEGOTIATION; + } + else + { // Send "we are ready" + oc->status = OCS_DATA; + ft->flags |= OFTF_FILE_RECEIVING; + + sendOFT2FramePacket(oc, OFT_TYPE_READY); + } + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + + if (!ft->qwThisFileSize || action == FILERESUME_SKIP) + { // if the file is empty we will not receive any data + BYTE buf; + oft_handleFileData(oc, &buf, 0); + } +} + + +static void oft_buildProtoFileTransferStatus(oscar_filetransfer* ft, PROTOFILETRANSFERSTATUS* pfts) +{ + ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS)); + pfts->cbSize = sizeof(PROTOFILETRANSFERSTATUS); + pfts->hContact = ft->hContact; + pfts->flags = PFTS_UTF + ((ft->flags & OFTF_SENDING) ? PFTS_SENDING : PFTS_RECEIVING); + if (ft->flags & OFTF_SENDING) + pfts->pszFiles = ft->files_list; + else + pfts->pszFiles = NULL; /* FIXME */ + pfts->totalFiles = ft->wFilesCount; + pfts->currentFileNumber = ft->iCurrentFile; + pfts->totalBytes = ft->qwTotalSize; + pfts->totalProgress = ft->qwBytesDone; + pfts->szWorkingDir = ft->szThisPath; + pfts->szCurrentFile = ft->szThisFile; + pfts->currentFileSize = ft->qwThisFileSize; + pfts->currentFileTime = ft->dwThisFileDate; + pfts->currentFileProgress = ft->qwFileBytesDone; +} + + +void CIcqProto::CloseOscarConnection(oscar_connection *oc) +{ + icq_lock l(oftMutex); + + if (oc) + { + oc->type = OCT_CLOSING; + + if (oc->hConnection) + { // we need this for Netlib handle consistency + NetLib_CloseConnection(&oc->hConnection, FALSE); + } + } +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::OpenOscarConnection(HANDLE hContact, oscar_filetransfer *ft, int type) +{ + oscarthreadstartinfo *otsi = (oscarthreadstartinfo*)SAFE_MALLOC(sizeof(oscarthreadstartinfo)); + + otsi->hContact = hContact; + otsi->type = type; + otsi->ft = ft; + + ForkThread(( IcqThreadFunc )&CIcqProto::oft_connectionThread, otsi ); +} + + +int CIcqProto::CreateOscarProxyConnection(oscar_connection *oc) +{ + NETLIBOPENCONNECTION nloc = {0}; + + // inform UI + BroadcastAck(oc->ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTPROXY, oc->ft, 0); + + nloc.szHost = OSCAR_PROXY_HOST; + nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); + if (nloc.wPort == 0) + nloc.wPort = RandRange(1024, 65535); + if (m_bGatewayMode) + nloc.flags |= NLOCF_HTTPGATEWAY; + + oc->hConnection = NetLib_OpenConnection(m_hServerNetlibUser, "Proxy ", &nloc); + if (!oc->hConnection) + { // proxy connection failed + return 0; + } + oc->type = OCT_PROXY; + oc->status = OCS_PROXY; + oc->ft->connection = oc; + // init proxy + proxy_sendInitTunnel(oc); + + return 1; // Success +} + + +void __cdecl CIcqProto::oft_connectionThread( oscarthreadstartinfo *otsi ) +{ + oscar_connection oc = {0}; + oscar_listener *source; + NETLIBPACKETRECVER packetRecv={0}; + HANDLE hPacketRecver; + + oc.hContact = otsi->hContact; + oc.hConnection = otsi->hConnection; + oc.type = otsi->type; + oc.incoming = otsi->incoming; + oc.ft = otsi->ft; + source = otsi->listener; + if (oc.incoming) + { + if (IsValidOscarTransfer(source->ft)) + { + oc.ft = source->ft; + oc.ft->dwRemoteExternalIP = otsi->dwRemoteIP; + oc.hContact = oc.ft->hContact; + oc.ft->connection = &oc; + oc.status = OCS_CONNECTED; + } + else + { // FT is already over, kill listener + NetLog_Direct("Received unexpected connection, closing."); + + CloseOscarConnection(&oc); + ReleaseOscarListener(&source); + + SAFE_FREE((void**)&otsi); + return; + } + } + SAFE_FREE((void**)&otsi); + + if (oc.hContact) + { // Load contact information + getContactUid(oc.hContact, &oc.dwUin, &oc.szUid); + } + + // Load local IP information + oc.dwLocalExternalIP = getSettingDword(NULL, "IP", 0); + oc.dwLocalInternalIP = getSettingDword(NULL, "RealIP", 0); + + if (!oc.incoming) + { // create outgoing connection + if (oc.type == OCT_NORMAL || oc.type == OCT_REVERSE) + { // create outgoing connection to peer + NETLIBOPENCONNECTION nloc = {0}; + IN_ADDR addr = {0}, addr2 = {0}; + + if (oc.ft->dwRemoteExternalIP == oc.dwLocalExternalIP && oc.ft->dwRemoteInternalIP) + addr.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); + else if (oc.ft->dwRemoteExternalIP) + { + addr.S_un.S_addr = htonl(oc.ft->dwRemoteExternalIP); + // for different internal, try it also (for LANs with multiple external IP, VPNs, etc.) + if (oc.ft->dwRemoteInternalIP != oc.ft->dwRemoteExternalIP) + addr2.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); + } + else // try LAN + addr.S_un.S_addr = htonl(oc.ft->dwRemoteInternalIP); + + // Inform UI that we will attempt to connect + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, oc.ft, 0); + + if (!addr.S_un.S_addr && oc.type == OCT_NORMAL) + { // IP to connect to is empty, request reverse + oscar_listener* listener = CreateOscarListener(oc.ft, oft_newConnectionReceived); + + if (listener) + { // we got listening port, fine send request + oc.ft->listener = listener; + // notify UI + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0); + + oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE); + return; + } + if (!CreateOscarProxyConnection(&oc)) + { // normal connection failed, notify peer, wait for error or stage 3 proxy + oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); + // stage 3 can follow + return; + } + } + else if (addr.S_un.S_addr && oc.ft->wRemotePort) + { + nloc.szHost = inet_ntoa(addr); + nloc.wPort = oc.ft->wRemotePort; + nloc.timeout = 8; // 8 secs to connect + oc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, oc.type==OCT_REVERSE?"Reverse ":NULL, &nloc); + if (!oc.hConnection && addr2.S_un.S_addr) + { // first address failed, try second one if available + nloc.szHost = inet_ntoa(addr2); + oc.hConnection = NetLib_OpenConnection(m_hDirectNetlibUser, oc.type==OCT_REVERSE?"Reverse ":NULL, &nloc); + } + if (!oc.hConnection) + { + if (oc.type == OCT_NORMAL) + { // connection failed, try reverse + oscar_listener* listener = CreateOscarListener(oc.ft, oft_newConnectionReceived); + + if (listener) + { // we got listening port, fine send request + oc.ft->listener = listener; + // notify UI that we await connection + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_LISTENING, oc.ft, 0); + + oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, oc.dwLocalInternalIP, listener->wPort, FALSE); + return; + } + } + if (!CreateOscarProxyConnection(&oc)) + { // proxy connection failed, notify peer, wait for error or stage 4 proxy + oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); + // stage 3 or stage 4 can follow + return; + } + } + else + { + oc.status = OCS_CONNECTED; + // ack normal connection + oc.ft->connection = &oc; + // acknowledge OFT - connection is ready + oft_sendFileAccept(oc.dwUin, oc.szUid, oc.ft); + // signal UI + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, oc.ft, 0); + } + } + else + { // try proxy, stage 3 (sending) + if (!CreateOscarProxyConnection(&oc)) + { // proxy connection failed, notify peer, wait for error or stage 4 proxy + oft_sendFileRedirect(oc.dwUin, oc.szUid, oc.ft, 0, 0, FALSE); + // stage 4 can follow + return; + } + } + } + else if (oc.type == OCT_PROXY_RECV) + { // stage 2 & stage 4 + if (oc.ft->dwProxyIP && oc.ft->wRemotePort) + { // create proxy connection, join tunnel + NETLIBOPENCONNECTION nloc = {0}; + IN_ADDR addr = {0}; + + // inform UI that we will connect to file proxy + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTPROXY, oc.ft, 0); + + addr.S_un.S_addr = htonl(oc.ft->dwProxyIP); + nloc.szHost = inet_ntoa(addr); + nloc.wPort = getSettingWord(NULL, "OscarPort", m_bSecureConnection ? DEFAULT_SERVER_PORT_SSL : DEFAULT_SERVER_PORT); + if (nloc.wPort == 0) + nloc.wPort = RandRange(1024, 65535); + if (m_bGatewayMode) + nloc.flags |= NLOCF_HTTPGATEWAY; + oc.hConnection = NetLib_OpenConnection(m_hServerNetlibUser, "Proxy ", &nloc); + if (!oc.hConnection) + { // proxy connection failed, we are out of possibilities + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); + // notify the other side, that we failed + oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x04); + // Release structure + SafeReleaseFileTransfer((void**)&oc.ft); + return; + } + oc.status = OCS_PROXY; + oc.ft->connection = &oc; + // Join proxy tunnel + proxy_sendJoinTunnel(&oc, oc.ft->wRemotePort); + } + else // stage 2 failed (empty IP) + { // try stage 3, or send response error 0x06 + if (!CreateOscarProxyConnection(&oc)) + { + oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x06); + // notify UI + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); + // Release structure + SafeReleaseFileTransfer((void**)&oc.ft); + return; + } + } + } + else if (oc.type == OCT_PROXY) + { // stage 4 + if (!CreateOscarProxyConnection(&oc)) + { // proxy connection failed, we are out of possibilities + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); + // notify the other side, that we failed + oft_sendFileResponse(oc.dwUin, oc.szUid, oc.ft, 0x06); + // Release structure + SafeReleaseFileTransfer((void**)&oc.ft); + return; + } + } + else if (oc.type == OCT_PROXY_INIT) + { // stage 1 + if (!CreateOscarProxyConnection(&oc)) + { // We failed to init transfer, notify UI + icq_LogMessage(LOG_ERROR, LPGEN("Failed to Initialize File Transfer. Unable to bind local port and File proxy unavailable.")); + // Release transfer + SafeReleaseFileTransfer((void**)&oc.ft); + return; + } + else + oc.type = OCT_PROXY_INIT; + } + } + if (!oc.hConnection) + { // one more sanity check + NetLog_Direct("Error: No OFT connection."); + return; + } + if (oc.status != OCS_PROXY) + { // Connected, notify FT UI + BroadcastAck(oc.ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, oc.ft, 0); + + // send init OFT frame - just for different order of packets (just like Trillian) + if (oc.status == OCS_CONNECTED && (oc.ft->flags & OFTF_SENDING) && ((oc.ft->flags & OFTF_INITIALIZED) || oc.type == OCT_REVERSE) && !(oc.ft->flags & OFTF_FILE_REQUEST_SENT)) + { + oc.ft->flags |= OFTF_FILE_REQUEST_SENT; + // proceed with first file + oft_sendPeerInit(&oc); + } + } + hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)oc.hConnection, 8192); + packetRecv.cbSize = sizeof(packetRecv); + + // Packet receiving loop + + while (oc.hConnection) + { + int recvResult; + + packetRecv.dwTimeout = oc.wantIdleTime ? 0 : 120000; + + recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hPacketRecver, (LPARAM)&packetRecv); + if (!recvResult) + { + NetLog_Direct("Clean closure of oscar socket (%p)", oc.hConnection); + break; + } + + if (recvResult == SOCKET_ERROR) + { + if (GetLastError() == ERROR_TIMEOUT) + { // TODO: this will not work on some systems + if (oc.wantIdleTime) + { // here we want to send file data packets + oft_sendFileData(&oc); + } + else if (oc.status != OCS_WAITING) + { + NetLog_Direct("Connection timeouted, closing."); + break; + } + } + else if (oc.type != OCT_CLOSING || GetLastError() != 87) + { // log only significant errors, not "connection killed by us" + NetLog_Direct("Abortive closure of oscar socket (%p) (%d)", oc.hConnection, GetLastError()); + break; + } + } + + if (oc.type == OCT_CLOSING) + packetRecv.bytesUsed = packetRecv.bytesAvailable; + else + packetRecv.bytesUsed = oft_handlePackets(&oc, packetRecv.buffer, packetRecv.bytesAvailable); + } + + // End of packet receiving loop + + NetLib_SafeCloseHandle(&hPacketRecver); + + CloseOscarConnection(&oc); + + { // Clean up + icq_lock l(oftMutex); + + if (getFileTransferIndex(oc.ft) != -1) + oc.ft->connection = NULL; // release link + } + // Give server some time for abort/cancel to arrive + SleepEx(1000, TRUE); + // Error handling + if (IsValidOscarTransfer(oc.ft)) + { + if (oc.status == OCS_DATA) + { + BroadcastAck(oc.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); + + icq_LogMessage(LOG_ERROR, LPGEN("Connection lost during file transfer.")); + // Release structure + SafeReleaseFileTransfer((void**)&oc.ft); + } + else if (oc.status == OCS_NEGOTIATION) + { + BroadcastAck(oc.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc.ft, 0); + + icq_LogMessage(LOG_ERROR, LPGEN("File transfer negotiation failed for unknown reason.")); + // Release structure + SafeReleaseFileTransfer((void**)&oc.ft); + } + } +} + + +void CIcqProto::sendOscarPacket(oscar_connection *oc, icq_packet *packet) +{ + if (oc->hConnection) + { + int nResult; + + nResult = Netlib_Send(oc->hConnection, (const char*)packet->pData, packet->wLen, 0); + + if (nResult == SOCKET_ERROR) + { + NetLog_Direct("Oscar %p socket error: %d, closing", oc->hConnection, GetLastError()); + CloseOscarConnection(oc); + } + } + + SAFE_FREE((void**)&packet->pData); +} + + +int CIcqProto::oft_handlePackets(oscar_connection *oc, BYTE *buf, int len) +{ + int bytesUsed = 0; + + while (len > 0) + { + if (oc->status == OCS_DATA && (oc->ft->flags & OFTF_FILE_RECEIVING)) + { + return oft_handleFileData(oc, buf, len); + } + else if (oc->status == OCS_PROXY) + { + return oft_handleProxyData(oc, buf, len); + } + if (len < 6) + break; + + BYTE *pBuf = buf; + DWORD dwHead; + unpackDWord(&pBuf, &dwHead); + if (dwHead != 0x4F465432) + { // bad packet + NetLog_Direct("OFT: Received invalid packet (dwHead = 0x%x).", dwHead); + + CloseOscarConnection(oc); + break; + } + + WORD datalen; + unpackWord(&pBuf, &datalen); + + if (len < datalen) // wait for whole packet + break; + + WORD datatype; + unpackWord(&pBuf, &datatype); +#ifdef _DEBUG + NetLog_Direct("OFT2: Type %u, Length %u bytes", datatype, datalen); +#endif + handleOFT2FramePacket(oc, datatype, pBuf, (WORD)(datalen - 8)); + + /* Increase pointers so we can check for more data */ + buf += datalen; + len -= datalen; + bytesUsed += datalen; + } + + return bytesUsed; +} + + +int CIcqProto::oft_handleProxyData(oscar_connection *oc, BYTE *buf, int len) +{ + oscar_filetransfer *ft = oc->ft; + BYTE *pBuf; + WORD datalen; + WORD wCommand; + int bytesUsed = 0; + + + while (len > 2) + { + pBuf = buf; + + unpackWord(&pBuf, &datalen); + datalen += 2; + + if (len < datalen) + break; // packet is not complete + + if (datalen < 12) + { // malformed packet + CloseOscarConnection(oc); + break; + } + pBuf += 2; // packet version + unpackWord(&pBuf, &wCommand); + pBuf += 6; + // handle packet + switch (wCommand) + { + case 0x01: // Error + { + WORD wError; + char* szError; + + unpackWord(&pBuf, &wError); + switch(wError) + { + case 0x0D: + szError = "Bad request"; + break; + case 0x0E: + szError = "Malformed packet"; + break; + case 0x10: + szError = "Initial request timeout"; + break; + case 0x1A: + szError = "Accept period timeout"; + break; + case 0x1C: + szError = "Invalid data"; + break; + + default: + szError = "Unknown"; + } + // Notify peer + oft_sendFileResponse(oc->dwUin, oc->szUid, oc->ft, 0x06); + + NetLog_Server("Proxy Error: %s (0x%x)", szError, wError); + // Notify UI + BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, oc->ft, 0); + // Release structure + SafeReleaseFileTransfer((void**)&oc->ft); + } + break; + + case 0x03: // Tunnel created + { + WORD wCode; + DWORD dwIP; + + unpackWord(&pBuf, &wCode); + unpackDWord(&pBuf, &dwIP); + + if (oc->type == OCT_PROXY_INIT) + { // Proxy ready, send Stage 1 Request + ft->bUseProxy = 1; + ft->wRemotePort = wCode; + ft->dwProxyIP = dwIP; + oft_sendFileRequest(oc->dwUin, oc->szUid, ft, ft->szThisFile, 0); + SAFE_FREE(&ft->szThisFile); + // Notify UI + BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, oc->ft, 0); + } + else + { + NetLog_Server("Proxy Tunnel ready, notify peer."); + oft_sendFileRedirect(oc->dwUin, oc->szUid, ft, dwIP, wCode, TRUE); + } + } + break; + + case 0x05: // Connection ready + oc->status = OCS_CONNECTED; // connection ready to send packets + // Notify UI + BroadcastAck(oc->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, oc->ft, 0); + // signal we are ready + if (oc->type == OCT_PROXY_RECV) + { + oft_sendFileAccept(oc->dwUin, oc->szUid, ft); + if (ft->flags & OFTF_SENDING) // connection is ready for transfer (sending only) + ft->flags |= OFTF_INITIALIZED; + } + + NetLog_Server("Proxy Tunnel established"); + + if ((ft->flags & OFTF_INITIALIZED) && (ft->flags & OFTF_SENDING) && !(ft->flags & OFTF_FILE_REQUEST_SENT)) + { + ft->flags |= OFTF_FILE_REQUEST_SENT; + // proceed with first file + oft_sendPeerInit(ft->connection); + } + break; + + default: + NetLog_Server("Unknown proxy command 0x%x", wCommand); + } + + buf += datalen; + len -= datalen; + bytesUsed += datalen; + } + + return bytesUsed; +} + + +int CIcqProto::oft_handleFileData(oscar_connection *oc, BYTE *buf, int len) +{ + oscar_filetransfer *ft = oc->ft; + DWORD dwLen = len; + int bytesUsed = 0; + + // do not accept more data than expected + if (ft->qwThisFileSize - ft->qwFileBytesDone < dwLen) + dwLen = (int)(ft->qwThisFileSize - ft->qwFileBytesDone); + + if (ft->fileId == -1) + { // something went terribly bad +#ifdef _DEBUG + NetLog_Direct("Error: handleFileData(%u bytes) without fileId!", len); +#endif + CloseOscarConnection(oc); + return 0; + } + _write(ft->fileId, buf, dwLen); + // update checksum + ft->dwRecvFileCheck = oft_calc_checksum((int)ft->qwFileBytesDone, buf, dwLen, ft->dwRecvFileCheck); + bytesUsed += dwLen; + ft->qwBytesDone += dwLen; + ft->qwFileBytesDone += dwLen; + + if (GetTickCount() > ft->dwLastNotify + 700 || ft->qwFileBytesDone == ft->qwThisFileSize) + { // notify FT UI of our progress, at most every 700ms - do not be faster than Miranda + PROTOFILETRANSFERSTATUS pfts; + + oft_buildProtoFileTransferStatus(ft, &pfts); + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&pfts); + ft->dwLastNotify = GetTickCount(); + } + if (ft->qwFileBytesDone == ft->qwThisFileSize) + { + /* EOF */ + ft->flags &= ~OFTF_FILE_RECEIVING; + +#ifdef _DEBUG + NetLog_Direct("OFT: _close(%u)", ft->fileId); +#endif + _close(ft->fileId); + ft->fileId = -1; + + if (ft->resumeAction != FILERESUME_SKIP && ft->dwRecvFileCheck != ft->dwThisFileCheck) + { + NetLog_Direct("Error: File checksums does not match!"); + { // Notify UI + char *pszMsg = ICQTranslateUtf(LPGEN("The checksum of file \"%s\" does not match, the file is probably damaged.")); + char szBuf[MAX_PATH]; + + null_snprintf(szBuf, MAX_PATH, pszMsg, ExtractFileName(ft->szThisFile)); + icq_LogMessage(LOG_ERROR, szBuf); + + SAFE_FREE(&pszMsg); + } + } // keep transfer going (icq6 ignores checksums completely) + else if (ft->resumeAction == FILERESUME_SKIP) + NetLog_Direct("OFT: File receive skipped."); + else + NetLog_Direct("OFT: File received successfully."); + + if ((DWORD)(ft->iCurrentFile + 1) == ft->wFilesCount) + { + ft->bHeaderFlags = 0x01; // the whole process is over + // ack received file + sendOFT2FramePacket(oc, OFT_TYPE_DONE); + oc->type = OCT_CLOSING; + NetLog_Direct("File Transfer completed successfully."); + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&ft); + } + else + { // ack received file + sendOFT2FramePacket(oc, OFT_TYPE_DONE); + oc->status = OCS_NEGOTIATION; + } + + } + return bytesUsed; +} + + +void CIcqProto::handleOFT2FramePacket(oscar_connection *oc, WORD datatype, BYTE *pBuffer, WORD wLen) +{ + oscar_filetransfer *ft = oc->ft; + DWORD dwID1; + DWORD dwID2; + + if (wLen < 232) + { // allow shorter packets, but at least with filename + NetLog_Direct("Error: Malformed OFT2 Frame, ignoring."); + return; + } + + unpackLEDWord(&pBuffer, &dwID1); + wLen -= 4; + unpackLEDWord(&pBuffer, &dwID2); + wLen -= 4; + + if (datatype == OFT_TYPE_REQUEST && !(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + { // first request does not contain MsgIDs we need to send them in ready packet + dwID1 = ft->pMessage.dwMsgID1; + dwID2 = ft->pMessage.dwMsgID2; + } + + if (ft->pMessage.dwMsgID1 != dwID1 || ft->pMessage.dwMsgID2 != dwID2) + { // this is not the right packet - bad Message IDs + NetLog_Direct("Error: Invalid Packet Cookie, closing."); + CloseOscarConnection(oc); + + return; + } + + switch (datatype) { + + case OFT_TYPE_REQUEST: + { // Sender ready + if (ft->flags & OFTF_SENDING) + { // just sanity check - this is only for receiving client + NetLog_Direct("Error: Invalid Packet, closing."); + CloseOscarConnection(oc); + return; + } + + // Read Frame data + if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + { + unpackWord(&pBuffer, &ft->wEncrypt); + unpackWord(&pBuffer, &ft->wCompress); + unpackWord(&pBuffer, &ft->wFilesCount); + } + else + pBuffer += 6; + unpackWord(&pBuffer, &ft->wFilesLeft); + ft->iCurrentFile = ft->wFilesCount - ft->wFilesLeft; + if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + unpackWord(&pBuffer, &ft->wPartsCount); + else + pBuffer += 2; + unpackWord(&pBuffer, &ft->wPartsLeft); + if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + { // just check it + DWORD dwSize; + + unpackDWord(&pBuffer, &dwSize); + if (dwSize != (DWORD)ft->qwTotalSize) + { // the 32bits does not match, use them as full size + ft->qwTotalSize = dwSize; + + NetLog_Server("Warning: Invalid total size."); + } + } + else + pBuffer += 4; + { // this allows us to receive single >4GB file correctly + DWORD dwSize; + + unpackDWord(&pBuffer, &dwSize); + if (dwSize == (DWORD)ft->qwTotalSize && ft->wFilesCount == 1) + ft->qwThisFileSize = ft->qwTotalSize; + else + ft->qwThisFileSize = dwSize; + } + unpackDWord(&pBuffer, &ft->dwThisFileDate); + unpackDWord(&pBuffer, &ft->dwThisFileCheck); + unpackDWord(&pBuffer, &ft->dwRecvForkCheck); + unpackDWord(&pBuffer, &ft->dwThisForkSize); + unpackDWord(&pBuffer, &ft->dwThisFileCreation); + unpackDWord(&pBuffer, &ft->dwThisForkCheck); + pBuffer += 4; // File Bytes Done + unpackDWord(&pBuffer, &ft->dwRecvFileCheck); + if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + unpackString(&pBuffer, ft->rawIDString, 32); + else + pBuffer += 32; + unpackByte(&pBuffer, &ft->bHeaderFlags); + unpackByte(&pBuffer, &ft->bNameOff); + unpackByte(&pBuffer, &ft->bSizeOff); + if (!(ft->flags & OFTF_FILE_REQUEST_RECEIVED)) + { + unpackString(&pBuffer, (char*)ft->rawDummy, 69); + unpackString(&pBuffer, (char*)ft->rawMacInfo, 16); + } + else + pBuffer += 85; + unpackWord(&pBuffer, &ft->wEncoding); + unpackWord(&pBuffer, &ft->wSubEncoding); + ft->cbRawFileName = wLen - 176; + SAFE_FREE((void**)&ft->rawFileName); // release previous buffers + SAFE_FREE(&ft->szThisFile); + ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName + 2); + unpackString(&pBuffer, ft->rawFileName, ft->cbRawFileName); + // Prepare file + if (ft->wEncoding == 2) + { // UCS-2 encoding + ft->szThisFile = ApplyEncoding(ft->rawFileName, "unicode-2-0"); + } + else + { + ft->szThisFile = ansi_to_utf8(ft->rawFileName); + } + + { // convert dir markings to normal backslashes + int i; + + for (i = 0; i < strlennull(ft->szThisFile); i++) + { + if (ft->szThisFile[i] == 0x01) ft->szThisFile[i] = '\\'; + } + } + + ft->flags |= OFTF_FILE_REQUEST_RECEIVED; // First Frame Processed + + NetLog_Direct("File '%s', %I64u Bytes", ft->szThisFile, ft->qwThisFileSize); + + { // Prepare Path Information + char *szFile = strrchr(ft->szThisFile, '\\'); + + SAFE_FREE(&ft->szThisPath); // release previous path + if (szFile) + { + ft->szThisPath = ft->szThisFile; + szFile[0] = '\0'; // split that strings + ft->szThisFile = null_strdup(szFile + 1); + // no cheating with paths + if (!IsValidRelativePath(ft->szThisPath)) + { + NetLog_Direct("Invalid path information"); + break; + } + } + else + ft->szThisPath = null_strdup(""); + } + + /* no cheating with paths */ + if (!IsValidRelativePath(ft->szThisFile)) + { + NetLog_Direct("Invalid path information"); + break; + } + char *szFullPath = (char*)SAFE_MALLOC(strlennull(ft->szSavePath)+strlennull(ft->szThisPath)+strlennull(ft->szThisFile)+3); + strcpy(szFullPath, ft->szSavePath); + NormalizeBackslash(szFullPath); + strcat(szFullPath, ft->szThisPath); + NormalizeBackslash(szFullPath); + // make sure the dest dir exists + if (MakeDirUtf(szFullPath)) + NetLog_Direct("Failed to create destination directory!"); + + strcat(szFullPath, ft->szThisFile); + // we joined the full path to dest file + SAFE_FREE(&ft->szThisFile); + ft->szThisFile = szFullPath; + + ft->qwFileBytesDone = 0; + + { + /* file resume */ + PROTOFILETRANSFERSTATUS pfts; + + oft_buildProtoFileTransferStatus(ft, &pfts); + if (BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&pfts)) + { + oc->status = OCS_WAITING; + break; /* UI supports resume: it will call PS_FILERESUME */ + } + + ft->fileId = OpenFileUtf(ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); +#ifdef _DEBUG + NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, ft->fileId); +#endif + if (ft->fileId == -1) + { +#ifdef _DEBUG + NetLog_Direct("OFT: errno=%d", errno); +#endif + icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oc->ft); + return; + } + } + // Send "we are ready" + oc->status = OCS_DATA; + ft->flags |= OFTF_FILE_RECEIVING; + + sendOFT2FramePacket(oc, OFT_TYPE_READY); + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + if (!ft->qwThisFileSize) + { // if the file is empty we will not receive any data + BYTE buf; + + oft_handleFileData(oc, &buf, 0); + } + return; + } + + case OFT_TYPE_READY: + case OFT_TYPE_RESUMEACK: + { // Receiver is ready + oc->status = OCS_DATA; + oc->wantIdleTime = 1; + ft->flags |= OFTF_FILE_SENDING; + + NetLog_Direct("OFT: Receiver ready."); + } + break; + + case OFT_TYPE_RESUMEREQUEST: + { // Receiver wants to resume file transfer from point + DWORD dwResumeCheck, dwResumeOffset, dwFileCheck; + + if (!(ft->flags & OFTF_SENDING)) + { // just sanity check - this is only for sending client + NetLog_Direct("Error: Invalid Packet, closing."); + CloseOscarConnection(oc); + + return; + } + // Read Resume Frame data + pBuffer += 44; + unpackDWord(&pBuffer, &dwResumeOffset); + unpackDWord(&pBuffer, &dwResumeCheck); + + dwFileCheck = oft_calc_file_checksum(ft->fileId, dwResumeOffset); + if (dwFileCheck == dwResumeCheck && dwResumeOffset <= ft->qwThisFileSize) + { // resume seems ok + ft->qwFileBytesDone = dwResumeOffset; + ft->qwBytesDone += dwResumeOffset; + _lseek(ft->fileId, dwResumeOffset, SEEK_SET); + + NetLog_Direct("OFT: Resume request, ready."); + } + else + NetLog_Direct("OFT: Resume request, restarting."); + + // Ready for resume + sendOFT2FramePacket(oc, OFT_TYPE_RESUMEREADY); + } + break; + + case OFT_TYPE_RESUMEREADY: + { // Process Smart-resume reply + DWORD dwResumeOffset, dwResumeCheck; + + if (ft->flags & OFTF_SENDING) + { // just sanity check - this is only for receiving client + NetLog_Direct("Error: Invalid Packet, closing."); + CloseOscarConnection(oc); + + return; + } + // Read Resume Reply data + pBuffer += 44; + unpackDWord(&pBuffer, &dwResumeOffset); + unpackDWord(&pBuffer, &dwResumeCheck); + + if (ft->qwFileBytesDone != dwResumeOffset) + { + ft->qwBytesDone -= (ft->qwFileBytesDone - dwResumeOffset); + ft->qwFileBytesDone = dwResumeOffset; + if (dwResumeOffset) + ft->dwRecvFileCheck = dwResumeCheck; + else // Restarted resume (data mismatch) + ft->dwRecvFileCheck = 0xFFFF0000; + } + _lseek(ft->fileId, dwResumeOffset, SEEK_SET); + + if (ft->qwThisFileSize != ft->qwFileBytesDone) + NetLog_Direct("OFT: Resuming from offset %u.", dwResumeOffset); + + // Prepare to receive data + oc->status = OCS_DATA; + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + + // Ready for receive + sendOFT2FramePacket(oc, OFT_TYPE_RESUMEACK); + + if (ft->qwThisFileSize == ft->qwFileBytesDone) + { // all data already processed + BYTE buf; + + oft_handleFileData(oc, &buf, 0); + } + } + break; + + case OFT_TYPE_DONE: + { // File done + oc->status = OCS_NEGOTIATION; + oc->wantIdleTime = 0; + + ft->flags &= ~OFTF_FILE_SENDING; + + NetLog_Direct("OFT: File sent successfully."); + +#ifdef _DEBUG + NetLog_Direct("OFT: _close(%u)", ft->fileId); +#endif + _close(ft->fileId); // FIXME: this needs fix for "skip file" feature + ft->fileId = -1; + ft->iCurrentFile++; + // continue with next file + oft_sendPeerInit(oc); + } + break; + + default: + NetLog_Direct("Error: Uknown OFT frame type 0x%x", datatype); + } +} + + +// +// Proxy packets +///////////////////////////// + +void CIcqProto::proxy_sendInitTunnel(oscar_connection *oc) +{ + icq_packet packet; + WORD wLen = 39 + getUINLen(m_dwLocalUIN); + + packet.wLen = wLen; + init_generic_packet(&packet, 2); + + packWord(&packet, wLen); + packWord(&packet, OSCAR_PROXY_VERSION); + packWord(&packet, 0x02); // wCommand + packDWord(&packet, 0); // Unknown + packWord(&packet, 0); // Flags? + packUIN(&packet, m_dwLocalUIN); + packLEDWord(&packet, oc->ft->pMessage.dwMsgID1); + packLEDWord(&packet, oc->ft->pMessage.dwMsgID2); + packDWord(&packet, 0x00010010); // TLV(1) + packGUID(&packet, MCAP_FILE_TRANSFER); + + sendOscarPacket(oc, &packet); +} + +void CIcqProto::proxy_sendJoinTunnel(oscar_connection *oc, WORD wPort) +{ + icq_packet packet; + WORD wLen = 41 + getUINLen(m_dwLocalUIN); + + packet.wLen = wLen; + init_generic_packet(&packet, 2); + + packWord(&packet, wLen); + packWord(&packet, OSCAR_PROXY_VERSION); + packWord(&packet, 0x04); // wCommand + packDWord(&packet, 0); // Unknown + packWord(&packet, 0); // Flags? + packUIN(&packet, m_dwLocalUIN); + packWord(&packet, wPort); + packLEDWord(&packet, oc->ft->pMessage.dwMsgID1); + packLEDWord(&packet, oc->ft->pMessage.dwMsgID2); + packDWord(&packet, 0x00010010); // TLV(1) + packGUID(&packet, MCAP_FILE_TRANSFER); + + sendOscarPacket(oc, &packet); +} + +// +// Direct packets +///////////////////////////// + +void CIcqProto::oft_sendFileData(oscar_connection *oc) +{ + oscar_filetransfer *ft = oc->ft; + BYTE buf[OFT_BUFFER_SIZE]; + + if (ft->fileId == -1) + return; + + int bytesRead = _read(ft->fileId, buf, sizeof(buf)); + if (bytesRead == -1) + return; + + if (!bytesRead) + { // + oc->wantIdleTime = 0; + return; + } + + if ((DWORD)bytesRead > (ft->qwThisFileSize - ft->qwFileBytesDone)) + { // do not send more than expected, limit to known size + bytesRead = (DWORD)(ft->qwThisFileSize - ft->qwFileBytesDone); + oc->wantIdleTime = 0; + } + + if (bytesRead) + { + icq_packet packet; + + packet.wLen = bytesRead; + init_generic_packet(&packet, 0); + packBuffer(&packet, buf, (WORD)bytesRead); // we are sending raw data + sendOscarPacket(oc, &packet); + + ft->qwBytesDone += bytesRead; + ft->qwFileBytesDone += bytesRead; + } + + if (GetTickCount() > ft->dwLastNotify + 700 || oc->wantIdleTime == 0 || ft->qwFileBytesDone == ft->qwThisFileSize) + { // notify only once a while or after last data packet sent + PROTOFILETRANSFERSTATUS pfts; + + oft_buildProtoFileTransferStatus(ft, &pfts); + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&pfts); + ft->dwLastNotify = GetTickCount(); + } +} + +void CIcqProto::oft_sendPeerInit(oscar_connection *oc) +{ + icq_lock l(oftMutex); + + oscar_filetransfer *ft = oc->ft; + struct _stati64 statbuf; + char *pszThisFileName; + + // prepare init frame + if (ft->iCurrentFile >= (int)ft->wFilesCount) + { // All files done, great! + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oc->ft); + return; + } + + SAFE_FREE(&ft->szThisFile); + ft->szThisFile = null_strdup(ft->files[ft->iCurrentFile].szFile); + if (FileStatUtf(ft->szThisFile, &statbuf)) + { + icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oc->ft); + return; + } + + { // create full relative filename + char* szThisContainer = ft->files[ft->iCurrentFile].szContainer; + + pszThisFileName = (char*)SAFE_MALLOC(strlennull(ft->szThisFile) + strlennull(szThisContainer) + 4); + strcpy(pszThisFileName, szThisContainer); + NormalizeBackslash(pszThisFileName); + strcat(pszThisFileName, ExtractFileName(ft->szThisFile)); + } + { // convert backslashes to dir markings + int i; + for (i = 0; i < strlennull(pszThisFileName); i++) + if (pszThisFileName[i] == '\\' || pszThisFileName[i] == '/') + pszThisFileName[i] = 0x01; + } + + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + + ft->fileId = OpenFileUtf(ft->szThisFile, _O_BINARY | _O_RDONLY, 0); +#ifdef _DEBUG + NetLog_Direct("OFT: OpenFileUtf(%s, %u) returned %u", ft->szThisFile, _O_BINARY | _O_RDONLY, ft->fileId); +#endif + if (ft->fileId == -1) + { +#ifdef _DEBUG + NetLog_Direct("OFT: errno=%d", errno); +#endif + SAFE_FREE((void**)&pszThisFileName); + icq_LogMessage(LOG_ERROR, LPGEN("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.")); + // + BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + // Release transfer + SafeReleaseFileTransfer((void**)&oc->ft); + return; + } + + ft->qwThisFileSize = statbuf.st_size; + ft->dwThisFileDate = statbuf.st_mtime; + ft->dwThisFileCreation = statbuf.st_ctime; + ft->dwThisFileCheck = oft_calc_file_checksum(ft->fileId, ft->qwThisFileSize); + ft->qwFileBytesDone = 0; + ft->dwRecvFileCheck = 0xFFFF0000; + SAFE_FREE((void**)&ft->rawFileName); + + if (IsUSASCII(pszThisFileName, strlennull(pszThisFileName))) + { + ft->wEncoding = 0; // ascii + ft->cbRawFileName = strlennull(pszThisFileName) + 1; + if (ft->cbRawFileName < 64) ft->cbRawFileName = 64; + ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName); + strcpy(ft->rawFileName, (char*)pszThisFileName); + SAFE_FREE((void**)&pszThisFileName); + } + else + { + ft->wEncoding = 2; // ucs-2 + WCHAR *pwsThisFile = make_unicode_string(pszThisFileName); + SAFE_FREE((void**)&pszThisFileName); + ft->cbRawFileName = strlennull(pwsThisFile) * (int)sizeof(WCHAR) + 2; + if (ft->cbRawFileName < 64) ft->cbRawFileName = 64; + ft->rawFileName = (char*)SAFE_MALLOC(ft->cbRawFileName); + // convert to LE ordered string + BYTE *pwsThisFileBuf = (BYTE*)pwsThisFile; // need this - unpackWideString moves the address! + unpackWideString(&pwsThisFileBuf, (WCHAR*)ft->rawFileName, (WORD)(strlennull(pwsThisFile) * sizeof(WCHAR))); + SAFE_FREE((void**)&pwsThisFile); + } + ft->wFilesLeft = (WORD)(ft->wFilesCount - ft->iCurrentFile); + + sendOFT2FramePacket(oc, OFT_TYPE_REQUEST); +} + +void CIcqProto::sendOFT2FramePacket(oscar_connection *oc, WORD datatype) +{ + oscar_filetransfer *ft = oc->ft; + icq_packet packet; + + packet.wLen = 192 + ft->cbRawFileName; + init_generic_packet(&packet, 0); + // Basic Oscar Frame + packDWord(&packet, 0x4F465432); // Magic + packWord(&packet, packet.wLen); + packWord(&packet, datatype); + // Cookie + packLEDWord(&packet, ft->pMessage.dwMsgID1); + packLEDWord(&packet, ft->pMessage.dwMsgID2); + packWord(&packet, ft->wEncrypt); + packWord(&packet, ft->wCompress); + packWord(&packet, ft->wFilesCount); + packWord(&packet, ft->wFilesLeft); + packWord(&packet, ft->wPartsCount); + packWord(&packet, ft->wPartsLeft); + packDWord(&packet, (DWORD)ft->qwTotalSize); + packDWord(&packet, (DWORD)ft->qwThisFileSize); + packDWord(&packet, ft->dwThisFileDate); + packDWord(&packet, ft->dwThisFileCheck); + packDWord(&packet, ft->dwRecvForkCheck); + packDWord(&packet, ft->dwThisForkSize); + packDWord(&packet, ft->dwThisFileCreation); + packDWord(&packet, ft->dwThisForkCheck); + packDWord(&packet, (DWORD)ft->qwFileBytesDone); + packDWord(&packet, ft->dwRecvFileCheck); + packBuffer(&packet, (LPBYTE)ft->rawIDString, 32); + packByte(&packet, ft->bHeaderFlags); + packByte(&packet, ft->bNameOff); + packByte(&packet, ft->bSizeOff); + packBuffer(&packet, ft->rawDummy, 69); + packBuffer(&packet, ft->rawMacInfo, 16); + packWord(&packet, ft->wEncoding); + packWord(&packet, ft->wSubEncoding); + packBuffer(&packet, (LPBYTE)ft->rawFileName, ft->cbRawFileName); + + sendOscarPacket(oc, &packet); +} diff --git a/protocols/IcqOscarJ/src/oscar_filetransfer.h b/protocols/IcqOscarJ/src/oscar_filetransfer.h new file mode 100644 index 0000000000..fa6ec9169e --- /dev/null +++ b/protocols/IcqOscarJ/src/oscar_filetransfer.h @@ -0,0 +1,164 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// OSCAR File-Transfers headers +// +// ----------------------------------------------------------------------------- +#ifndef __OSCAR_FILETRANSFER_H +#define __OSCAR_FILETRANSFER_H + + +#define FT_MAGIC_ICQ 0x00 +#define FT_MAGIC_OSCAR 0x4F + +struct basic_filetransfer +{ + cookie_message_data pMessage; + BYTE ft_magic; +}; + +#define OFT_BUFFER_SIZE 8192 + +struct oft_file_record +{ + char *szContainer; + char *szFile; +}; + +char *FindFilePathContainer(const char **files, int iFile, char *szContainer); + + +// file-transfer status flags +#define OFTF_INITIALIZED 0x0001 // connection established (ack received) +#define OFTF_SENDING 0x0002 // sending files (receiving otherwise) +#define OFTF_FILE_REQUEST_SENT 0x0004 // request sent (sending only) +#define OFTF_FILE_REQUEST_RECEIVED 0x0008 // first request processed (receiving only) +#define OFTF_FILE_SENDING 0x0010 // sending file contents +#define OFTF_FILE_RECEIVING 0x0020 // receiving file contents +#define OFTF_FILE_DONE 0x0040 // file finished + +struct oscar_filetransfer: public basic_filetransfer +{ + HANDLE hContact; + int flags; // combination of OFTF_* + int containerCount; + char **file_containers; + oft_file_record *files; + char **files_list; // sending only + int iCurrentFile; + int currentIsDir; + int bUseProxy; + DWORD dwProxyIP; + DWORD dwRemoteInternalIP; + DWORD dwRemoteExternalIP; + WORD wRemotePort; + char *szSavePath; + char *szDescription; + char *szThisFile; + char *szThisPath; + // Request sequence + DWORD dwCookie; + WORD wReqNum; + // OFT2 header data + WORD wEncrypt, wCompress; + WORD wFilesCount,wFilesLeft; + WORD wPartsCount, wPartsLeft; + DWORD64 qwTotalSize; + DWORD64 qwThisFileSize; + DWORD dwThisFileDate; // modification date + DWORD dwThisFileCheck; + DWORD dwRecvForkCheck, dwThisForkSize; + DWORD dwThisFileCreation; // creation date (not used) + DWORD dwThisForkCheck; + DWORD64 qwBytesDone; + DWORD dwRecvFileCheck; + char rawIDString[32]; + BYTE bHeaderFlags; + BYTE bNameOff, bSizeOff; + BYTE rawDummy[69]; + BYTE rawMacInfo[16]; + WORD wEncoding, wSubEncoding; + WORD cbRawFileName; + char *rawFileName; + // helper data + DWORD64 qwFileBytesDone; + int fileId; + struct oscar_connection *connection; + struct oscar_listener *listener; + DWORD dwLastNotify; + int resumeAction; +}; + +#define OFT_TYPE_REQUEST 0x0101 // I am going to send you this file, is that ok? +#define OFT_TYPE_READY 0x0202 // Yes, it is ok for you to send me that file +#define OFT_TYPE_DONE 0x0204 // I received that file with no problems +#define OFT_TYPE_RESUMEREQUEST 0x0205 // Resume transferring from position +#define OFT_TYPE_RESUMEREADY 0x0106 // Ok, I am ready to send it +#define OFT_TYPE_RESUMEACK 0x0207 // Fine, ready to receive + +void SafeReleaseFileTransfer(void **ft); + +struct oscar_connection +{ + HANDLE hContact; + HANDLE hConnection; + int status; + DWORD dwUin; + uid_str szUid; + DWORD dwLocalInternalIP; + DWORD dwLocalExternalIP; + int type; + int incoming; + oscar_filetransfer *ft; + int wantIdleTime; +}; + +#define OCT_NORMAL 0 +#define OCT_REVERSE 1 +#define OCT_PROXY 2 +#define OCT_PROXY_INIT 3 +#define OCT_PROXY_RECV 4 +#define OCT_CLOSING 10 + +#define OCS_READY 0 +#define OCS_CONNECTED 1 +#define OCS_NEGOTIATION 2 +#define OCS_RESUME 3 +#define OCS_DATA 4 +#define OCS_PROXY 8 +#define OCS_WAITING 10 + +struct oscar_listener +{ + CIcqProto *ppro; + WORD wPort; + HANDLE hBoundPort; + oscar_filetransfer *ft; +}; + + +#endif /* __OSCAR_FILETRANSFER_H */ + diff --git a/protocols/IcqOscarJ/src/resource.h b/protocols/IcqOscarJ/src/resource.h new file mode 100644 index 0000000000..1dbd905dde --- /dev/null +++ b/protocols/IcqOscarJ/src/resource.h @@ -0,0 +1,176 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resources.rc +// +#define IDI_ICQ 101 +#define IDS_IDENTIFY 102 +#define IDD_ICQACCOUNT 103 +#define IDD_ASKAUTH 104 +#define IDD_LOGINPW 105 +#define IDD_OPT_ICQ 108 +#define IDD_OPT_ICQCONTACTS 109 +#define IDD_OPT_ICQFEATURES 110 +#define IDD_OPT_ICQPRIVACY 111 +#define IDI_AUTH_ASK 150 +#define IDI_AUTH_GRANT 151 +#define IDI_AUTH_REVOKE 152 +#define IDI_SERVLIST_ADD 160 +#define IDD_INFO_ICQ 240 +#define IDD_ICQADVANCEDSEARCH 242 +#define IDD_ICQUPLOADLIST 253 +#define IDD_SETXSTATUS 256 +#define IDD_PWCONFIRM 300 +#define IDD_INFO_CHANGEINFO 301 +#define IDD_OPT_POPUPS 400 +#define IDC_POPUPS_ENABLED 410 +#define IDC_POPUPS_LOG_ENABLED 411 +#define IDC_POPUPS_SPAM_ENABLED 412 +#define IDC_POPUP_LOG0_TEXTCOLOR 420 +#define IDC_POPUP_LOG1_TEXTCOLOR 421 +#define IDC_POPUP_LOG2_TEXTCOLOR 422 +#define IDC_POPUP_LOG3_TEXTCOLOR 423 +#define IDC_POPUP_SPAM_TEXTCOLOR 425 +#define IDC_POPUP_LOG0_BACKCOLOR 430 +#define IDC_POPUP_LOG1_BACKCOLOR 431 +#define IDC_POPUP_LOG2_BACKCOLOR 432 +#define IDC_POPUP_LOG3_BACKCOLOR 433 +#define IDC_POPUP_SPAM_BACKCOLOR 435 +#define IDC_POPUP_LOG0_TIMEOUT 440 +#define IDC_POPUP_LOG1_TIMEOUT 441 +#define IDC_POPUP_LOG2_TIMEOUT 442 +#define IDC_POPUP_LOG3_TIMEOUT 443 +#define IDC_POPUP_SPAM_TIMEOUT 444 +#define IDC_USEWINCOLORS 450 +#define IDC_USESYSICONS 451 +#define IDC_PREVIEW 455 +#define IDC_LOG 1001 +#define IDI_EXPANDSTRINGEDIT 1001 +#define IDC_SAVEPASS 1004 +#define IDC_RETRXSTATUS 1005 +#define IDC_XTITLE_STATIC 1006 +#define IDC_XMSG_STATIC 1007 +#define IDC_SSL 1008 +#define IDC_MD5LOGIN 1009 +#define IDC_UTFENABLE 1010 +#define IDC_XTITLE 1010 +#define IDC_KEEPALIVE 1011 +#define IDC_XMSG 1011 +#define IDC_UTFALL 1012 +#define IDC_UTFSTATIC 1013 +#define IDC_UTFCODEPAGE 1014 +#define IDC_PW 1015 +#define IDC_TEMPVISIBLE 1015 +#define IDC_REGISTER 1016 +#define IDC_EDITAUTH 1017 +#define IDC_LOGINPW 1018 +#define IDC_INSTRUCTION 1019 +#define IDC_PASSWORD 1020 +#define IDC_SUPTIME 1020 +#define IDC_DCENABLE 1020 +#define IDC_DCPASSIVE 1021 +#define IDC_OLDPASS 1021 +#define IDC_ICQNUM 1022 +#define IDC_USEPOPUPCOLORS 1023 +#define IDC_USEDEFCOLORS 1024 +#define IDC_AIMENABLE 1030 +#define IDC_CLIST 1035 +#define IDC_XSTATUSENABLE 1040 +#define IDC_XSTATUSAUTO 1041 +#define IDC_XSTATUSRESET 1042 +#define IDC_MOODSENABLE 1043 +#define IDC_KILLSPAMBOTS 1045 +#define IDC_EMAIL 1048 +#define IDC_NICK 1053 +#define IDC_GENDER 1060 +#define IDC_CITY 1061 +#define IDC_STATE 1062 +#define IDC_COUNTRY 1063 +#define IDC_COMPANY 1066 +#define IDC_DEPARTMENT 1067 +#define IDC_POSITION 1069 +#define IDC_IP 1094 +#define IDC_UINSTATIC 1122 +#define IDC_UIN 1123 +#define IDC_STATIC11 1154 +#define IDC_STATIC12 1155 +#define IDC_ICQSERVER 1171 +#define IDC_ICQPORT 1172 +#define IDC_VERSION 1179 +#define IDC_FIRSTNAME 1224 +#define IDC_LASTNAME 1225 +#define IDC_REALIP 1230 +#define IDC_RECONNECTREQD 1239 +#define IDC_OFFLINETOENABLE 1240 +#define IDC_PORT 1249 +#define IDC_MIRVER 1251 +#define IDC_ONLINESINCE 1252 +#define IDC_SYSTEMUPTIME 1253 +#define IDC_IDLETIME 1254 +#define IDC_STATUS 1255 +#define IDC_SLOWSEND 1301 +#define IDC_ONLYSERVERACKS 1302 +#define IDC_LOGLEVEL 1331 +#define IDC_LEVELDESCR 1332 +#define IDC_NOERRMULTI 1333 +#define IDC_STICQGROUP 1374 +#define IDC_AGERANGE 1410 +#define IDC_MARITALSTATUS 1411 +#define IDC_KEYWORDS 1412 +#define IDC_LANGUAGE 1414 +#define IDC_WORKFIELD 1421 +#define IDC_PASTCAT 1422 +#define IDC_PASTKEY 1423 +#define IDC_INTERESTSCAT 1424 +#define IDC_INTERESTSKEY 1425 +#define IDC_ORGANISATION 1426 +#define IDC_ORGKEYWORDS 1427 +#define IDC_OTHERGROUP 1429 +#define IDC_ONLINEONLY 1430 +#define IDC_HOMEPAGECAT 1431 +#define IDC_HOMEPAGEKEY 1432 +#define IDC_SUMMARYGROUP 1434 +#define IDC_WORKGROUP 1435 +#define IDC_LOCATIONGROUP 1436 +#define IDC_BACKGROUNDGROUP 1437 +#define IDC_NEWUINLINK 1438 +#define IDC_LOOKUPLINK 1439 +#define IDC_RESETSERVER 1472 +#define IDC_UPLOADNOW 1521 +#define IDC_GROUPS 1522 +#define IDC_ALLGROUPS 1526 +#define IDC_VISIBILITY 1527 +#define IDC_IGNORE 1528 +#define IDC_ENABLE 1529 +#define IDC_LOADFROMSERVER 1530 +#define IDC_ADDSERVER 1532 +#define IDC_SAVETOSERVER 1533 +#define IDC_ENABLEAVATARS 1536 +#define IDC_AUTOLOADAVATARS 1537 +#define IDC_STRICTAVATARCHECK 1539 +#define IDC_WEBAWARE 1546 +#define IDC_DCALLOW_ANY 1547 +#define IDC_DCALLOW_CLIST 1548 +#define IDC_DCALLOW_AUTH 1549 +#define IDC_PUBLISHPRIMARY 1550 +#define IDC_ADD_ANY 1551 +#define IDC_ADD_AUTH 1552 +#define IDC_STATUSMSG_CLIST 1553 +#define IDC_STATUSMSG_VISIBLE 1554 +#define IDC_STATIC_NOTONLINE 1555 +#define IDC_STATIC_DC2 1556 +#define IDC_STATIC_DC1 1557 +#define IDC_STATIC_CLIST 1558 +#define IDC_SAVE 1600 +#define IDC_LIST 1601 +#define IDC_UPLOADING 1602 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1026 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/IcqOscarJ/src/stdpackets.cpp b/protocols/IcqOscarJ/src/stdpackets.cpp new file mode 100644 index 0000000000..3bc9502560 --- /dev/null +++ b/protocols/IcqOscarJ/src/stdpackets.cpp @@ -0,0 +1,1895 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + +extern const int moodXStatus[]; + +/***************************************************************************** +* +* Some handy extra pack functions for basic message type headers +* +*/ + +// This is the part of the message header that is common for all message channels +static void packServMsgSendHeader(icq_packet *p, DWORD dwSequence, DWORD dwID1, DWORD dwID2, DWORD dwUin, const char *szUID, WORD wFmt, WORD wLen) +{ + serverPacketInit(p, (WORD)(21 + getUIDLen(dwUin, szUID) + wLen)); + packFNACHeader(p, ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, 0, dwSequence | ICQ_MSG_SRV_SEND<<0x10); + packLEDWord(p, dwID1); // Msg ID part 1 + packLEDWord(p, dwID2); // Msg ID part 2 + packWord(p, wFmt); // Message channel + packUID(p, dwUin, szUID); // User ID +} + + +static void packServIcqExtensionHeader(icq_packet *p, CIcqProto *ppro, WORD wLen, WORD wType, WORD wSeq, WORD wCmd = ICQ_META_CLI_REQUEST) +{ + serverPacketInit(p, (WORD)(24 + wLen)); + packFNACHeader(p, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST, 0, wSeq | (wCmd<<0x10)); + packWord(p, 0x01); // TLV type 1 + packWord(p, (WORD)(10 + wLen)); // TLV len + packLEWord(p, (WORD)(8 + wLen)); // Data chunk size (TLV.Length-2) + packLEDWord(p, ppro->m_dwLocalUIN); // My UIN + packLEWord(p, wType); // Request type + packWord(p, wSeq); +} + + +static void packServIcqDirectoryHeader(icq_packet *p, CIcqProto *ppro, WORD wLen, WORD wType, WORD wCommand, WORD wSeq, WORD wSubCommand = ICQ_META_CLI_REQUEST) +{ + packServIcqExtensionHeader(p, ppro, wLen + 0x1E, CLI_META_INFO_REQ, wSeq, wSubCommand); + packLEWord(p, wType); + packLEWord(p, wLen + 0x1A); + packFNACHeader(p, 0x5b9, wCommand, 0, 0, 2); + packWord(p, 0); + packWord(p, (WORD)GetACP()); + packDWord(p, 2); +} + + +static void packServTLV5HeaderBasic(icq_packet *p, WORD wLen, DWORD ID1, DWORD ID2, WORD wCommand, const plugin_guid pGuid) +{ + // TLV(5) header + packWord(p, 0x05); // Type + packWord(p, (WORD)(26 + wLen)); // Len + // TLV(5) data + packWord(p, wCommand); // Command + packLEDWord(p, ID1); // msgid1 + packLEDWord(p, ID2); // msgid2 + packGUID(p, pGuid); // capabilities (4 dwords) +} + + +static void packServTLV5HeaderMsg(icq_packet *p, WORD wLen, DWORD ID1, DWORD ID2, WORD wAckType) +{ + packServTLV5HeaderBasic(p, (WORD)(wLen + 10), ID1, ID2, 0, MCAP_SRV_RELAY_FMT); + + packTLVWord(p, 0x0A, wAckType); // TLV: 0x0A Acktype: 1 for normal, 2 for ack + packDWord(p, 0x000F0000); // TLV: 0x0F empty +} + + +static void packServTLV2711Header(icq_packet *packet, WORD wCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD X1, WORD X2, int nLen) +{ + packWord(packet, 0x2711); // Type + packWord(packet, (WORD)(51 + nLen)); // Len + // TLV(0x2711) data + packLEWord(packet, 0x1B); // Unknown + packByte(packet, (BYTE)wVersion); // Client (message) version + packGUID(packet, PSIG_MESSAGE); + packDWord(packet, CLIENTFEATURES); + packDWord(packet, DC_TYPE); + packLEWord(packet, wCookie); // Reference cookie + packLEWord(packet, 0x0E); // Unknown + packLEWord(packet, wCookie); // Reference cookie again + packDWord(packet, 0); // Unknown (12 bytes) + packDWord(packet, 0); // - + packDWord(packet, 0); // - + packByte(packet, bMsgType); // Message type + packByte(packet, bMsgFlags); // Flags + packLEWord(packet, X1); // Accepted + packWord(packet, X2); // Unknown, priority? +} + + +static void packServDCInfo(icq_packet *p, CIcqProto* ppro, BOOL bEmpty) +{ + packTLVDWord(p, 0x03, bEmpty ? 0 : ppro->getSettingDword(NULL, "RealIP", 0)); // TLV: 0x03 DWORD IP + packTLVWord(p, 0x05, (WORD)(bEmpty ? 0 : ppro->wListenPort)); // TLV: 0x05 Listen port +} + + +static void packServChannel2Header(icq_packet *p, CIcqProto* ppro, DWORD dwUin, WORD wLen, DWORD dwID1, DWORD dwID2, DWORD dwCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD wPriority, int isAck, int includeDcInfo, BYTE bRequestServerAck) +{ + packServMsgSendHeader(p, dwCookie, dwID1, dwID2, dwUin, NULL, 0x0002, (WORD)(wLen + 95 + (bRequestServerAck?4:0) + (includeDcInfo?14:0))); + + packWord(p, 0x05); // TLV type + packWord(p, (WORD)(wLen + 91 + (includeDcInfo?14:0))); /* TLV len */ + packWord(p, (WORD)(isAck ? 2: 0)); /* not aborting anything */ + packLEDWord(p, dwID1); // Msg ID part 1 + packLEDWord(p, dwID2); // Msg ID part 2 + packGUID(p, MCAP_SRV_RELAY_FMT); /* capability (4 dwords) */ + packDWord(p, 0x000A0002); // TLV: 0x0A WORD: 1 for normal, 2 for ack + packWord(p, (WORD)(isAck ? 2 : 1)); + + if (includeDcInfo) + packServDCInfo(p, ppro, FALSE); + + packDWord(p, 0x000F0000); // TLV: 0x0F empty + + packServTLV2711Header(p, (WORD)dwCookie, wVersion, bMsgType, bMsgFlags, (WORD)MirandaStatusToIcq(ppro->m_iStatus), wPriority, wLen); +} + + +static void packServAdvancedReply(icq_packet *p, DWORD dwUin, const char *szUid, DWORD dwID1, DWORD dwID2, WORD wCookie, WORD wLen) +{ + serverPacketInit(p, (WORD)(getUIDLen(dwUin, szUid) + 23 + wLen)); + packFNACHeader(p, ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE, 0, ICQ_MSG_RESPONSE<<0x10 | (wCookie & 0x7FFF)); + packLEDWord(p, dwID1); // Msg ID part 1 + packLEDWord(p, dwID2); // Msg ID part 2 + packWord(p, 0x02); // Channel + packUID(p, dwUin, szUid); // Contact UID + packWord(p, 0x03); // Msg specific formating +} + + +static void packServAdvancedMsgReply(icq_packet *p, DWORD dwUin, const char *szUid, DWORD dwID1, DWORD dwID2, WORD wCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD wLen) +{ + packServAdvancedReply(p, dwUin, szUid, dwID1, dwID2, wCookie, (WORD)(wLen + 51)); + + packLEWord(p, 0x1B); // Unknown + packByte(p, (BYTE)wVersion); // Protocol version + packGUID(p, PSIG_MESSAGE); + packDWord(p, CLIENTFEATURES); + packDWord(p, DC_TYPE); + packLEWord(p, wCookie); // Reference + packLEWord(p, 0x0E); // Unknown + packLEWord(p, wCookie); // Reference + packDWord(p, 0); // Unknown + packDWord(p, 0); // Unknown + packDWord(p, 0); // Unknown + packByte(p, bMsgType); // Message type + packByte(p, bMsgFlags); // Message flags + packLEWord(p, 0); // Ack status code ( 0 = accepted, this is hardcoded because + // it is only used this way yet) + packLEWord(p, 0); // Unused priority field +} + + +void packMsgColorInfo(icq_packet *packet) +{ // TODO: make configurable + packLEDWord(packet, 0x00000000); // Foreground colour + packLEDWord(packet, 0x00FFFFFF); // Background colour +} + + +void packEmptyMsg(icq_packet *packet) +{ + packLEWord(packet, 1); + packByte(packet, 0); +} + +/***************************************************************************** +* +* Functions to actually send the stuff +* +*/ + +void CIcqProto::icq_sendCloseConnection() +{ + icq_packet packet; + + packet.wLen = 0; + write_flap(&packet, ICQ_CLOSE_CHAN); + sendServPacket(&packet); +} + + +void CIcqProto::icq_requestnewfamily(WORD wFamily, void (CIcqProto::*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen)) +{ + icq_packet packet; + cookie_family_request *request; + int bRequestSSL = m_bSecureConnection && (wFamily != ICQ_AVATAR_FAMILY); // Avatar servers does not support SSL + + request = (cookie_family_request*)SAFE_MALLOC(sizeof(cookie_family_request)); + request->wFamily = wFamily; + request->familyHandler = familyhandler; + + DWORD dwCookie = AllocateCookie(CKT_SERVICEREQUEST, ICQ_CLIENT_NEW_SERVICE, 0, request); // generate and alloc cookie + + serverPacketInit(&packet, 12 + (bRequestSSL ? 4 : 0)); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_NEW_SERVICE, 0, dwCookie); + packWord(&packet, wFamily); + if (bRequestSSL) + packDWord(&packet, 0x008C0000); // use SSL + + sendServPacket(&packet); +} + + +void CIcqProto::icq_setidle(int bAllow) +{ + icq_packet packet; + + if (bAllow != m_bIdleAllow) + { + /* SNAC 1,11 */ + serverPacketInit(&packet, 14); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE); + if (bAllow==1) + packDWord(&packet, 0x0000003C); + else + packDWord(&packet, 0x00000000); + + m_bIdleAllow = bAllow; + sendServPacket(&packet); + } +} + + +void CIcqProto::icq_setstatus(WORD wStatus, const char *szStatusNote) +{ + icq_packet packet; + char *szCurrentStatusNote = szStatusNote ? getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL) : NULL; + WORD wStatusMoodLen = 0, wStatusNoteLen = 0, wSessionDataLen = 0; + char *szMoodData = NULL; + + if (szStatusNote && strcmpnull(szCurrentStatusNote, szStatusNote)) + { // status note was changed, update now + DBVARIANT dbv = {DBVT_DELETED}; + + if (m_bMoodsEnabled && !getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) + szMoodData = null_strdup(dbv.pszVal); + + ICQFreeVariant(&dbv); + + wStatusNoteLen = strlennull(szStatusNote); + wStatusMoodLen = strlennull(szMoodData); + + wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; + } + SAFE_FREE(&szCurrentStatusNote); + + // Pack data in packet + serverPacketInit(&packet, (WORD)(18 + (wSessionDataLen ? wSessionDataLen + 4 : 0))); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); + packWord(&packet, 0x06); // TLV 6 + packWord(&packet, 0x04); // TLV length + packWord(&packet, GetMyStatusFlags()); // Status flags + packWord(&packet, wStatus); // Status + if (wSessionDataLen) + { // Pack session data + packWord(&packet, 0x1D); // TLV 1D + packWord(&packet, wSessionDataLen); // TLV length + packWord(&packet, 0x02); // Item Type + if (wStatusNoteLen) + { + packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length + packWord(&packet, wStatusNoteLen); // Text Length + packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen); + packWord(&packet, 0); // Encoding not specified (utf-8 is default) + } + else + packWord(&packet, 0); // Flags + Item Length + packWord(&packet, 0x0E); // Item Type + packWord(&packet, wStatusMoodLen); // Flags + Item Length + if (wStatusMoodLen) + packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood + + // Save current status note + setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, szStatusNote); + } + // Release memory + SAFE_FREE(&szMoodData); + + // Send packet + sendServPacket(&packet); +} + + +DWORD CIcqProto::icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, cookie_message_data *pCookieData) +{ + icq_packet packet; + WORD wPacketLength; + + WORD wMessageLen = strlennull(pszText); + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + if (pCookieData->nAckType == ACKTYPE_SERVER) + wPacketLength = 25; + else + wPacketLength = 21; + + // Pack the standard header + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 1, (WORD)(wPacketLength + wMessageLen)); + + // Pack first TLV + packWord(&packet, 0x0002); // TLV(2) + packWord(&packet, (WORD)(wMessageLen + 13)); // TLV len + + // Pack client features + packWord(&packet, 0x0501); // TLV(501) + packWord(&packet, 0x0001); // TLV len + packByte(&packet, 0x1); // Features, meaning unknown, duplicated from ICQ Lite + + // Pack text TLV + packWord(&packet, 0x0101); // TLV(2) + packWord(&packet, (WORD)(wMessageLen + 4)); // TLV len + packWord(&packet, 0x0003); // Message charset number, again copied from ICQ Lite + packWord(&packet, 0x0000); // Message charset subset + packBuffer(&packet, (LPBYTE)pszText, (WORD)(wMessageLen)); // Message text + + // Pack request server ack TLV + if (pCookieData->nAckType == ACKTYPE_SERVER) + packDWord(&packet, 0x00030000); // TLV(3) + + // Pack store on server TLV + packDWord(&packet, 0x00060000); // TLV(6) + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, WCHAR *pszText, cookie_message_data *pCookieData) +{ + icq_packet packet; + WORD wMessageLen; + DWORD dwCookie; + WORD wPacketLength; + WCHAR *ppText; + int i; + + wMessageLen = strlennull(pszText) * (int)sizeof(WCHAR); + dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + if (pCookieData->nAckType == ACKTYPE_SERVER) + wPacketLength = 26; + else + wPacketLength = 22; + + // Pack the standard header + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 1, (WORD)(wPacketLength + wMessageLen)); + + // Pack first TLV + packWord(&packet, 0x0002); // TLV(2) + packWord(&packet, (WORD)(wMessageLen + 14)); // TLV len + + // Pack client features + packWord(&packet, 0x0501); // TLV(501) + packWord(&packet, 0x0002); // TLV len + packWord(&packet, 0x0106); // Features, meaning unknown, duplicated from ICQ 2003b + + // Pack text TLV + packWord(&packet, 0x0101); // TLV(2) + packWord(&packet, (WORD)(wMessageLen + 4)); // TLV len + packWord(&packet, 0x0002); // Message charset number, again copied from ICQ 2003b + packWord(&packet, 0x0000); // Message charset subset + ppText = pszText; // we must convert the widestring + for (i = 0; inAckType == ACKTYPE_SERVER) + packDWord(&packet, 0x00030000); // TLV(3) + + // Pack store on server TLV + packDWord(&packet, 0x00060000); // TLV(6) + + sendServPacket(&packet); + return dwCookie; +} + + +DWORD CIcqProto::icq_SendChannel2Message(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLen, WORD wPriority, cookie_message_data *pCookieData, char *szCap) +{ + icq_packet packet; + + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + // Pack the standard header + packServChannel2Header(&packet, this, dwUin, (WORD)(nBodyLen + (szCap ? 53:11)), pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwCookie, ICQ_VERSION, (BYTE)pCookieData->bMessageType, 0, + wPriority, 0, 0, (BYTE)((pCookieData->nAckType == ACKTYPE_SERVER)?1:0)); + + packLEWord(&packet, (WORD)(nBodyLen+1)); // Length of message + packBuffer(&packet, (LPBYTE)szMessage, (WORD)(nBodyLen+1)); // Message + packMsgColorInfo(&packet); + + if (szCap) + { + packLEDWord(&packet, 0x00000026); // length of GUID + packBuffer(&packet, (LPBYTE)szCap, 0x26); // UTF-8 GUID + } + + // Pack request server ack TLV + if (pCookieData->nAckType == ACKTYPE_SERVER) + packDWord(&packet, 0x00030000); // TLV(3) + + sendServPacket(&packet); + return dwCookie; +} + + +DWORD CIcqProto::icq_SendChannel2Contacts(DWORD dwUin, char *szUid, HANDLE hContact, const char *pData, WORD wDataLen, const char *pNames, WORD wNamesLen, cookie_message_data *pCookieData) +{ + icq_packet packet; + + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, pCookieData); + + WORD wPacketLength = wDataLen + wNamesLen + 0x12; + + // Pack the standard header + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUid, 2, (WORD)(wPacketLength + ((pCookieData->nAckType == ACKTYPE_SERVER)?0x22:0x1E))); + + packServTLV5HeaderBasic(&packet, wPacketLength, pCookieData->dwMsgID1, pCookieData->dwMsgID2, 0, MCAP_CONTACTS); + + packTLVWord(&packet, 0x0A, 1); // TLV: 0x0A Acktype: 1 for normal, 2 for ack + packDWord(&packet, 0x000F0000); // TLV: 0x0F empty + packTLV(&packet, 0x2711, wDataLen, (LPBYTE)pData); // TLV: 0x2711 Content (Contact UIDs) + packTLV(&packet, 0x2712, wNamesLen, (LPBYTE)pNames);// TLV: 0x2712 Extended Content (Contact NickNames) + + // Pack request ack TLV + if (pCookieData->nAckType == ACKTYPE_SERVER) + { + packDWord(&packet, 0x00030000); // TLV(3) + } + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_SendChannel4Message(DWORD dwUin, HANDLE hContact, BYTE bMsgType, WORD wMsgLen, const char *szMsg, cookie_message_data *pCookieData) +{ + icq_packet packet; + WORD wPacketLength; + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + if (pCookieData->nAckType == ACKTYPE_SERVER) + wPacketLength = 28; + else + wPacketLength = 24; + + // Pack the standard header + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, NULL, 4, (WORD)(wPacketLength + wMsgLen)); + + // Pack first TLV + packWord(&packet, 0x05); // TLV(5) + packWord(&packet, (WORD)(wMsgLen + 16)); // TLV len + packLEDWord(&packet, m_dwLocalUIN); // My UIN + packByte(&packet, bMsgType); // Message type + packByte(&packet, 0); // Message flags + packLEWord(&packet, wMsgLen); // Message length + packBuffer(&packet, (LPBYTE)szMsg, wMsgLen); // Message text + packMsgColorInfo(&packet); + + // Pack request ack TLV + if (pCookieData->nAckType == ACKTYPE_SERVER) + { + packDWord(&packet, 0x00030000); // TLV(3) + } + + // Pack store on server TLV + packDWord(&packet, 0x00060000); // TLV(6) + + sendServPacket(&packet); + + return dwCookie; +} + + +void CIcqProto::sendOwnerInfoRequest(void) +{ + icq_packet packet; + + cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); + pCookieData->bRequestType = DIRECTORYREQUEST_INFOOWNER; + + DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); + WORD wDataLen = getUINLen(m_dwLocalUIN) + 4; + + packServIcqDirectoryHeader(&packet, this, wDataLen + 8, META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); + packWord(&packet, 0x03); // with interests (ICQ6 uses 2 at login) + packDWord(&packet, 0x01); + packWord(&packet, wDataLen); + + packTLVUID(&packet, 0x32, m_dwLocalUIN, NULL); + + sendServPacket(&packet); +} + + +DWORD CIcqProto::sendUserInfoMultiRequest(BYTE *pRequestData, WORD wDataLen, int nItems) +{ + icq_packet packet; + + cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); + if (!pCookieData) return 0; // Failure + pCookieData->bRequestType = DIRECTORYREQUEST_INFOMULTI; + + DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); + + packServIcqDirectoryHeader(&packet, this, wDataLen + 2, META_DIRECTORY_QUERY, DIRECTORY_QUERY_MULTI_INFO, (WORD)dwCookie); + packWord(&packet, nItems); + packBuffer(&packet, pRequestData, wDataLen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendGetInfoServ(HANDLE hContact, DWORD dwUin, int bManual) +{ + icq_packet packet; + DWORD dwCookie = 0; + + if (IsServerOverRate(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST, bManual ? RML_IDLE_10 : RML_IDLE_50)) + return dwCookie; + + DBVARIANT infoToken = {DBVT_DELETED}; + BYTE *pToken = NULL; + WORD cbToken = 0; + + if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &infoToken)) + { // retrieve user details using privacy token + cbToken = infoToken.cpbVal; + pToken = (BYTE*)_alloca(cbToken); + memcpy(pToken, infoToken.pbVal, cbToken); + + ICQFreeVariant(&infoToken); + } + + cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); + pCookieData->bRequestType = DIRECTORYREQUEST_INFOUSER; + + dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, hContact, (void*)pCookieData); + WORD wDataLen = cbToken + getUINLen(dwUin) + (cbToken ? 8 : 4); + + packServIcqDirectoryHeader(&packet, this, wDataLen + 8, META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); + packWord(&packet, 0x03); + packDWord(&packet, 1); + packWord(&packet, wDataLen); + if (pToken) + packTLV(&packet, 0x3C, cbToken, pToken); + packTLVUID(&packet, 0x32, dwUin, NULL); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendGetAimProfileServ(HANDLE hContact, char* szUid) +{ + icq_packet packet; + BYTE bUIDlen = strlennull(szUid); + + if (IsServerOverRate(ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, RML_IDLE_10)) + return 0; + + cookie_fam15_data *pCookieData = (cookie_fam15_data*)SAFE_MALLOC(sizeof(cookie_fam15_data)); + pCookieData->bRequestType = REQUESTTYPE_PROFILE; + + DWORD dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, ICQ_LOCATION_REQ_USER_INFO, hContact, (void*)pCookieData); + + serverPacketInit(&packet, (WORD)(13 + bUIDlen)); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie); + packWord(&packet, 0x01); // request profile info + packByte(&packet, bUIDlen); + packBuffer(&packet, (LPBYTE)szUid, bUIDlen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendGetAwayMsgServ(HANDLE hContact, DWORD dwUin, int type, WORD wVersion) +{ + icq_packet packet; + + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_IDLE_30)) + return 0; + + cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + packServChannel2Header(&packet, this, dwUin, 3, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwCookie, wVersion, (BYTE)type, 3, 1, 0, 0, 0); + packEmptyMsg(&packet); // Message + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendGetAwayMsgServExt(HANDLE hContact, DWORD dwUin, char *szUID, int type, WORD wVersion) +{ + icq_packet packet; + + if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_IDLE_30)) + return 0; + + cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 2, 122 + getPluginTypeIdLen(type)); + + // TLV(5) header + packServTLV5HeaderMsg(&packet, 82 + getPluginTypeIdLen(type), pCookieData->dwMsgID1, pCookieData->dwMsgID2, 1); + + // TLV(0x2711) header + packServTLV2711Header(&packet, (WORD)dwCookie, wVersion, MTYPE_PLUGIN, 0, 0, 0x100, 27 + getPluginTypeIdLen(type)); + // + packLEWord(&packet, 0); // Empty msg + + packPluginTypeId(&packet, type); + + packLEDWord(&packet, 0x15); + packLEDWord(&packet, 0); + packLEDWord(&packet, 0x0D); + packBuffer(&packet, (LPBYTE)"text/x-aolrtf", 0x0D); + + // Send the monster + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendGetAimAwayMsgServ(HANDLE hContact, char *szUID, int type) +{ + icq_packet packet; + BYTE bUIDlen = strlennull(szUID); + + cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (byte)type); + DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); + + serverPacketInit(&packet, (WORD)(13 + bUIDlen)); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie); + packWord(&packet, 0x03); + packUID(&packet, 0, szUID); + + sendServPacket(&packet); + + return dwCookie; +} + + +void CIcqProto::icq_sendSetAimAwayMsgServ(const char *szMsg) +{ + icq_packet packet; + WORD wMsgLen = strlennull(szMsg); + + DWORD dwCookie = GenerateCookie(ICQ_LOCATION_SET_USER_INFO); + + if (wMsgLen) + { + if (wMsgLen > 0x1000) wMsgLen = 0x1000; // limit length + + if (IsUSASCII(szMsg, wMsgLen)) + { + const char* fmt = "text/x-aolrtf; charset=\"us-ascii\""; + const WORD fmtlen = (WORD)strlen(fmt); + + serverPacketInit(&packet, 23 + wMsgLen + fmtlen); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); + packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); + packTLV(&packet, 0x03, fmtlen, (LPBYTE)fmt); + packTLV(&packet, 0x04, wMsgLen, (LPBYTE)szMsg); + } + else + { + const char* fmt = "text/x-aolrtf; charset=\"unicode-2-0\""; + const WORD fmtlen = (WORD)strlen(fmt); + + WCHAR *szMsgW = make_unicode_string(szMsg); + wMsgLen = (WORD)strlennull(szMsgW) * sizeof(WCHAR); + + WCHAR *szMsgW2 = (WCHAR*)alloca(wMsgLen), *szMsgW3 = szMsgW; + unpackWideString((BYTE**)&szMsgW3, szMsgW2, wMsgLen); + SAFE_FREE(&szMsgW); + + serverPacketInit(&packet, 23 + wMsgLen + fmtlen); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); + packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); + packTLV(&packet, 0x03, fmtlen, (LPBYTE)fmt); + packTLV(&packet, 0x04, wMsgLen, (LPBYTE)szMsgW2); + } + } + else + { + serverPacketInit(&packet, 19); + packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); + packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); + packTLV(&packet, 0x04, 0, NULL); + } + + sendServPacket(&packet); +} + + +void CIcqProto::icq_sendFileSendServv7(filetransfer* ft, const char *szFiles) +{ + icq_packet packet; + WORD wDescrLen = 0, wFilesLen = 0; + char *szFilesAnsi = NULL, *szDescrAnsi = NULL; + + if (!utf8_decode(szFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + else + wFilesLen = strlennull(szFilesAnsi); + + if (!utf8_decode(ft->szDescription, &szDescrAnsi)) + szDescrAnsi = NULL; + else + wDescrLen = strlennull(szDescrAnsi); + + packServChannel2Header(&packet, this, ft->dwUin, (WORD)(18 + wDescrLen + wFilesLen), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ICQ_VERSION, MTYPE_FILEREQ, 0, 1, 0, 1, 1); + + packLEWord(&packet, (WORD)(wDescrLen + 1)); + packBuffer(&packet, (LPBYTE)szDescrAnsi, (WORD)(wDescrLen + 1)); + packLEDWord(&packet, 0); // unknown + packLEWord(&packet, (WORD)(wFilesLen + 1)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packLEDWord(&packet, ft->dwTotalSize); + packLEDWord(&packet, 0); // unknown + + SAFE_FREE(&szFilesAnsi); + SAFE_FREE(&szDescrAnsi); + + sendServPacket(&packet); +} + + +void CIcqProto::icq_sendFileSendServv8(filetransfer* ft, const char *szFiles, int nAckType) +{ + icq_packet packet; + WORD wDescrLen = 0, wFilesLen = 0; + char *szFilesAnsi = NULL, *szDescrAnsi = NULL; + + if (!utf8_decode(szFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + else + wFilesLen = strlennull(szFilesAnsi); + + if (!utf8_decode(ft->szDescription, &szDescrAnsi)) + szDescrAnsi = NULL; + else + wDescrLen = strlennull(szDescrAnsi); + + // 202 + UIN len + file description (no null) + file name (null included) + // Packet size = Flap length + 4 + WORD wFlapLen = 178 + wDescrLen + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); + packServMsgSendHeader(&packet, ft->dwCookie, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwUin, NULL, 2, wFlapLen); + + // TLV(5) header + packServTLV5HeaderMsg(&packet, (WORD)(138 + wDescrLen + wFilesLen), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 1); + + // Port & IP information + packServDCInfo(&packet, this, FALSE); + + // TLV(0x2711) header + packServTLV2711Header(&packet, (WORD)ft->dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)MirandaStatusToIcq(m_iStatus), 0x100, 69 + wDescrLen + wFilesLen); + + packEmptyMsg(&packet); // Message (unused) + + packPluginTypeId(&packet, MTYPE_FILEREQ); + + packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length + packLEDWord(&packet, wDescrLen); // Description + packBuffer(&packet, (LPBYTE)szDescrAnsi, wDescrLen); + packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6 + packWord(&packet, 0x0222); // Unknown, seen 0x2e01 + packLEWord(&packet, (WORD)(wFilesLen + 1)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packLEDWord(&packet, ft->dwTotalSize); + packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000) + + SAFE_FREE(&szFilesAnsi); + SAFE_FREE(&szDescrAnsi); + + // Pack request server ack TLV + if (nAckType == ACKTYPE_SERVER) + packDWord(&packet, 0x00030000); // TLV(3) + + // Send the monster + sendServPacket(&packet); +} + + +/* also sends rejections */ +void CIcqProto::icq_sendFileAcceptServv8(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType) +{ + icq_packet packet; + WORD wDescrLen, wFilesLen; + char *szFilesAnsi = NULL, *szDescrAnsi = NULL; + + /* if !accepted, szDescr == szReason, szFiles = "" */ + + if (!accepted) szFiles = ""; + + if (!utf8_decode(szFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + + if (!utf8_decode(szDescr, &szDescrAnsi)) + szDescrAnsi = NULL; + + wDescrLen = strlennull(szDescrAnsi); + wFilesLen = strlennull(szFilesAnsi); + + // 202 + UIN len + file description (no null) + file name (null included) + // Packet size = Flap length + 4 + WORD wFlapLen = 178 + wDescrLen + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); + packServMsgSendHeader(&packet, dwCookie, TS1, TS2, dwUin, NULL, 2, wFlapLen); + + // TLV(5) header + packServTLV5HeaderMsg(&packet, (WORD)(138 + wDescrLen + wFilesLen), TS1, TS2, 2); + + // Port & IP information + packServDCInfo(&packet, this, !accepted); + + // TLV(0x2711) header + packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)(accepted ? 0:1), 0, 69 + wDescrLen + wFilesLen); + // + packEmptyMsg(&packet); // Message (unused) + + packPluginTypeId(&packet, MTYPE_FILEREQ); + + packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length + packLEDWord(&packet, wDescrLen); // Description + packBuffer(&packet, (LPBYTE)szDescrAnsi, wDescrLen); + packWord(&packet, wPort); // Port + packWord(&packet, 0x00); // Unknown + packLEWord(&packet, (WORD)(wFilesLen + 1)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packLEDWord(&packet, dwTotalSize); + packLEDWord(&packet, (DWORD)wPort); // Unknown + + SAFE_FREE(&szFilesAnsi); + SAFE_FREE(&szDescrAnsi); + + // Pack request server ack TLV + if (nAckType == ACKTYPE_SERVER) + { + packDWord(&packet, 0x00030000); // TLV(3) + } + + // Send the monster + sendServPacket(&packet); +} + + +void CIcqProto::icq_sendFileAcceptServv7(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char* szFiles, const char* szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType) +{ + icq_packet packet; + WORD wDescrLen, wFilesLen; + char *szFilesAnsi = NULL, *szDescrAnsi = NULL; + + /* if !accepted, szDescr == szReason, szFiles = "" */ + + if (!accepted) szFiles = ""; + + if (!utf8_decode(szFiles, &szFilesAnsi)) + szFilesAnsi = NULL; + + if (!utf8_decode(szDescr, &szDescrAnsi)) + szDescrAnsi = NULL; + + wDescrLen = strlennull(szDescrAnsi); + wFilesLen = strlennull(szFilesAnsi); + + // 150 + UIN len + file description (with null) + file name (2 nulls) + // Packet size = Flap length + 4 + WORD wFlapLen = 127 + wDescrLen + 1 + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); + packServMsgSendHeader(&packet, dwCookie, TS1, TS2, dwUin, NULL, 2, wFlapLen); + + // TLV(5) header + packServTLV5HeaderMsg(&packet, (WORD)(88 + wDescrLen + wFilesLen), TS1, TS2, 2); + + // Port & IP information + packServDCInfo(&packet, this, !accepted); + + // TLV(0x2711) header + packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_FILEREQ, 0, (WORD)(accepted ? 0:1), 0, 19 + wDescrLen + wFilesLen); + // + packLEWord(&packet, (WORD)(wDescrLen + 1)); // Description + packBuffer(&packet, (LPBYTE)szDescrAnsi, (WORD)(wDescrLen + 1)); + packWord(&packet, wPort); // Port + packWord(&packet, 0x00); // Unknown + packLEWord(&packet, (WORD)(wFilesLen + 2)); + packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); + packByte(&packet, 0); + packLEDWord(&packet, dwTotalSize); + packLEDWord(&packet, (DWORD)wPort); // Unknown + + SAFE_FREE(&szFilesAnsi); + SAFE_FREE(&szDescrAnsi); + + // Pack request server ack TLV + if (nAckType == ACKTYPE_SERVER) + { + packDWord(&packet, 0x00030000); // TLV(3) + } + + // Send the monster + sendServPacket(&packet); +} + + +void CIcqProto::icq_sendFileAcceptServ(DWORD dwUin, filetransfer *ft, int nAckType) +{ + char *szDesc = ft->szDescription; + + if (ft->bEmptyDesc) szDesc = ""; // keep empty if it originally was (Trillian workaround) + + if (ft->nVersion >= 8) + { + icq_sendFileAcceptServv8(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szDesc, ft->dwTotalSize, wListenPort, TRUE, nAckType); + NetLog_Server("Sent file accept v%u through server, port %u", 8, wListenPort); + } + else + { + icq_sendFileAcceptServv7(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szDesc, ft->dwTotalSize, wListenPort, TRUE, nAckType); + NetLog_Server("Sent file accept v%u through server, port %u", 7, wListenPort); + } +} + + +void CIcqProto::icq_sendFileDenyServ(DWORD dwUin, filetransfer *ft, const char *szReason, int nAckType) +{ + if (ft->nVersion >= 8) + { + icq_sendFileAcceptServv8(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szReason, ft->dwTotalSize, wListenPort, FALSE, nAckType); + NetLog_Server("Sent file deny v%u through server", 8); + } + else + { + icq_sendFileAcceptServv7(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szReason, ft->dwTotalSize, wListenPort, FALSE, nAckType); + NetLog_Server("Sent file deny v%u through server", 7); + } +} + + +void CIcqProto::icq_sendAwayMsgReplyServ(DWORD dwUin, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char** szMsg) +{ + HANDLE hContact = HContactFromUIN(dwUin, NULL); + + if (validateStatusMessageRequest(hContact, msgType)) + { + NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dwUin); + + icq_lock l(m_modeMsgsMutex); + + if (szMsg && *szMsg) + { + char *pszMsg = NULL; + WORD wReplyVersion = ICQ_VERSION; + + if (wVersion == 9) + { + pszMsg = *szMsg; + wReplyVersion = 9; + } + else + { // only v9 protocol supports UTF-8 mode messagees + WORD wMsgLen = strlennull(*szMsg) + 1; + char *szAnsiMsg = (char*)_alloca(wMsgLen); + + utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); + pszMsg = szAnsiMsg; + } + + WORD wMsgLen = strlennull(pszMsg); + + // limit msg len to max snac size - we get disconnected if exceeded + if (wMsgLen > MAX_MESSAGESNACSIZE) + wMsgLen = MAX_MESSAGESNACSIZE; + + icq_packet packet; + + packServAdvancedMsgReply(&packet, dwUin, NULL, dwMsgID1, dwMsgID2, wCookie, wReplyVersion, msgType, 3, (WORD)(wMsgLen + 3)); + packLEWord(&packet, (WORD)(wMsgLen + 1)); + packBuffer(&packet, (LPBYTE)pszMsg, wMsgLen); + packByte(&packet, 0); + + sendServPacket(&packet); + } + } +} + + +void CIcqProto::icq_sendAwayMsgReplyServExt(DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char **szMsg) +{ + HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); + + if (validateStatusMessageRequest(hContact, msgType)) + { + NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dwUin); + + icq_lock l(m_modeMsgsMutex); + + if (szMsg && *szMsg) + { + char *pszMsg = NULL; + WORD wReplyVersion = ICQ_VERSION; + + if (wVersion == 9) + { + pszMsg = *szMsg; + wReplyVersion = 9; + } + else + { // only v9 protocol supports UTF-8 mode messagees + WORD wMsgLen = strlennull(*szMsg) + 1; + char *szAnsiMsg = (char*)_alloca(wMsgLen); + + utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); + pszMsg = szAnsiMsg; + } + // convert to HTML + char *mng = MangleXml(pszMsg, strlennull(pszMsg)); + pszMsg = (char*)SAFE_MALLOC(strlennull(mng) + 28); + strcpy(pszMsg, ""); /// TODO: add support for RTL & user customizable font + strcat(pszMsg, mng); + SAFE_FREE(&mng); + strcat(pszMsg, ""); + + WORD wMsgLen = strlennull(pszMsg); + + // limit msg len to max snac size - we get disconnected if exceeded /// FIXME: correct HTML cutting + if (wMsgLen > MAX_MESSAGESNACSIZE) + wMsgLen = MAX_MESSAGESNACSIZE; + + icq_packet packet; + + packServAdvancedMsgReply(&packet, dwUin, szUID, dwMsgID1, dwMsgID2, wCookie, wReplyVersion, MTYPE_PLUGIN, 0, wMsgLen + 27 + getPluginTypeIdLen(msgType)); + packLEWord(&packet, 0); // Message size + packPluginTypeId(&packet, msgType); + + packLEDWord(&packet, wMsgLen + 21); + packLEDWord(&packet, wMsgLen); + packBuffer(&packet, (LPBYTE)pszMsg, wMsgLen); + + packLEDWord(&packet, 0x0D); + packBuffer(&packet, (LPBYTE)"text/x-aolrtf", 0x0D); + + sendServPacket(&packet); + SAFE_FREE(&pszMsg); + } + } +} + + +void CIcqProto::icq_sendAdvancedMsgAck(DWORD dwUin, DWORD dwTimestamp, DWORD dwTimestamp2, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags) +{ + icq_packet packet; + + packServAdvancedMsgReply(&packet, dwUin, NULL, dwTimestamp, dwTimestamp2, wCookie, ICQ_VERSION, bMsgType, bMsgFlags, 11); + packEmptyMsg(&packet); // Status message + packMsgColorInfo(&packet); + + sendServPacket(&packet); +} + + +void CIcqProto::icq_sendContactsAck(DWORD dwUin, char *szUid, DWORD dwMsgID1, DWORD dwMsgID2) +{ + icq_packet packet; + + packServMsgSendHeader(&packet, 0, dwMsgID1, dwMsgID2, dwUin, szUid, 2, 0x1E); + packServTLV5HeaderBasic(&packet, 0, dwMsgID1, dwMsgID2, 2, MCAP_CONTACTS); + + sendServPacket(&packet); +} + + +// Searches + +DWORD CIcqProto::SearchByUin(DWORD dwUin) +{ + WORD wInfoLen; + icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer + // I should be ashamed! ;) + + // Calculate data size + wInfoLen = 4 + getUINLen(dwUin); + + // Initialize our handy data buffer + pBuffer.wPlace = 0; + pBuffer.pData = (BYTE *)_alloca(wInfoLen); + pBuffer.wLen = wInfoLen; + + // Initialize our handy data buffer + packTLVUID(&pBuffer, 0x32, dwUin, NULL); + + // Send it off for further packing + return sendDirectorySearchPacket(pBuffer.pData, wInfoLen, 0, FALSE); +} + + +DWORD CIcqProto::SearchByNames(const char *pszNick, const char *pszFirstName, const char *pszLastName, WORD wPage) +{ // use directory search like ICQ6 does + WORD wInfoLen = 0; + WORD wNickLen,wFirstLen,wLastLen; + icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer + // I should be ashamed! ;) + + wNickLen = strlennull(pszNick); + wFirstLen = strlennull(pszFirstName); + wLastLen = strlennull(pszLastName); + + _ASSERTE(wFirstLen || wLastLen || wNickLen); + + + // Calculate data size + if (wFirstLen) + wInfoLen = wFirstLen + 4; + if (wLastLen) + wInfoLen += wLastLen + 4; + if (wNickLen) + wInfoLen += wNickLen + 4; + + // Initialize our handy data buffer + pBuffer.wPlace = 0; + pBuffer.pData = (BYTE *)_alloca(wInfoLen); + pBuffer.wLen = wInfoLen; + + // Pack the search details + if (wNickLen) + packTLV(&pBuffer, 0x78, wNickLen, (PBYTE)pszNick); + + if (wLastLen) + packTLV(&pBuffer, 0x6E, wLastLen, (PBYTE)pszLastName); + + if (wFirstLen) + packTLV(&pBuffer, 0x64, wFirstLen, (PBYTE)pszFirstName); + + // Send it off for further packing + if (wInfoLen) + return sendDirectorySearchPacket(pBuffer.pData, wInfoLen, wPage, FALSE); + else + return 0; // Failure +} + + +DWORD CIcqProto::SearchByMail(const char* pszEmail) +{ + DWORD dwCookie = 0; + WORD wInfoLen = 0; + WORD wEmailLen; + BYTE *pBuffer; + int pBufferPos; + + wEmailLen = strlennull(pszEmail); + + _ASSERTE(wEmailLen); + + if (wEmailLen > 0) + { + // Calculate data size + wInfoLen = wEmailLen + 7; + + // Initialize our handy data buffer + pBuffer = (BYTE *)_alloca(wInfoLen); + pBufferPos = 0; + + // Pack the search details + packLETLVLNTS(&pBuffer, &pBufferPos, pszEmail, TLV_EMAIL); + + // Send it off for further packing + dwCookie = sendTLVSearchPacket(SEARCHTYPE_EMAIL, (char*)pBuffer, META_SEARCH_EMAIL, wInfoLen, FALSE); + } + + return dwCookie; +} + + +DWORD CIcqProto::sendDirectorySearchPacket(const BYTE *pSearchData, WORD wDataLen, WORD wPage, BOOL bOnlineUsersOnly) +{ + icq_packet packet; + DWORD dwCookie; + + _ASSERTE(pSearchData); + _ASSERTE(wDataLen >= 4); + + cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); + if (pCookieData) + { + pCookieData->bRequestType = DIRECTORYREQUEST_SEARCH; + dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); + } + else + return 0; + + // Pack headers + packServIcqDirectoryHeader(&packet, this, wDataLen + (bOnlineUsersOnly ? 14 : 8), META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); + packWord(&packet, 0x02); + + // Pack requested page number + packWord(&packet, wPage); + + // Pack search data + packWord(&packet, 0x0001); + packWord(&packet, wDataLen + (bOnlineUsersOnly ? 6 : 0)); + packBuffer(&packet, pSearchData, wDataLen); + + if (bOnlineUsersOnly) + { // Pack "Online users only" flag + packTLVWord(&packet, 0x136, 1); + } + + // Go! + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::sendTLVSearchPacket(BYTE bType, char* pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly) +{ + icq_packet packet; + cookie_search* pCookie; + + _ASSERTE(pSearchDataBuf); + _ASSERTE(wInfoLen >= 4); + + pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); + if (!pCookie) + return 0; + + pCookie->bSearchType = bType; + DWORD dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie); + + // Pack headers + packServIcqExtensionHeader(&packet, this, (WORD)(wInfoLen + (wSearchType==META_SEARCH_GENERIC?7:2)), CLI_META_INFO_REQ, (WORD)dwCookie); + + // Pack search type + packLEWord(&packet, wSearchType); + + // Pack search data + packBuffer(&packet, (LPBYTE)pSearchDataBuf, wInfoLen); + + if (wSearchType == META_SEARCH_GENERIC && bOnlineUsersOnly) + { // Pack "Online users only" flag - only for generic search + BYTE bData = 1; + packTLV(&packet, TLV_ONLINEONLY, 1, &bData); + } + + // Go! + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendAdvancedSearchServ(BYTE* fieldsBuffer,int bufferLen) +{ + icq_packet packet; + DWORD dwCookie; + + cookie_search *pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); + if (pCookie) + { + pCookie->bSearchType = SEARCHTYPE_DETAILS; + dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie); + } + else + return 0; + + packServIcqExtensionHeader(&packet, this, (WORD)bufferLen, CLI_META_INFO_REQ, (WORD)dwCookie); + packBuffer(&packet, (LPBYTE)fieldsBuffer, (WORD)bufferLen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_searchAimByEmail(const char* pszEmail, DWORD dwSearchId) +{ + icq_packet packet; + DWORD dwCookie; + cookie_search* pCookie; + WORD wEmailLen; + + if (!FindCookie(dwSearchId, NULL, (void**)&pCookie)) + { + dwSearchId = 0; + pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); + pCookie->bSearchType = SEARCHTYPE_EMAIL; + } + + if (pCookie) + { + pCookie->dwMainId = dwSearchId; + pCookie->szObject = null_strdup(pszEmail); + dwCookie = AllocateCookie(CKT_SEARCH, ICQ_LOOKUP_REQUEST, 0, pCookie); + } + else + return 0; + + wEmailLen = strlennull(pszEmail); + serverPacketInit(&packet, (WORD)(10 + wEmailLen)); + packFNACHeader(&packet, ICQ_LOOKUP_FAMILY, ICQ_LOOKUP_REQUEST, 0, dwCookie); + packBuffer(&packet, (LPBYTE)pszEmail, wEmailLen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_changeUserPasswordServ(const char *szPassword) +{ + icq_packet packet; + WORD wPasswordLen = strlennull(szPassword); + DWORD dwCookie = GenerateCookie(0); + + packServIcqExtensionHeader(&packet, this, (WORD)(wPasswordLen + 4), CLI_META_INFO_REQ, (WORD)dwCookie, ICQ_META_SRV_UPDATE); + packLEWord(&packet, META_SET_PASSWORD_REQ); + packLEWord(&packet, wPasswordLen); + packBuffer(&packet, (BYTE*)szPassword, wPasswordLen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_changeUserDirectoryInfoServ(const BYTE *pData, WORD wDataLen, BYTE bRequestType) +{ + icq_packet packet; + cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); + pCookieData->bRequestType = bRequestType; + DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_UPDATE, 0, NULL, pCookieData); + + packServIcqDirectoryHeader(&packet, this, wDataLen + 4, META_DIRECTORY_UPDATE, DIRECTORY_SET_INFO, (WORD)dwCookie, ICQ_META_SRV_UPDATE); + packWord(&packet, 0x0003); + packWord(&packet, wDataLen); + packBuffer(&packet, pData, wDataLen); + + sendServPacket(&packet); + + return dwCookie; +} + + +DWORD CIcqProto::icq_sendSMSServ(const char *szPhoneNumber, const char *szMsg) +{ + icq_packet packet; + DWORD dwCookie; + WORD wBufferLen; + char* szBuffer = NULL; + char* szMyNick = NULL; + char szTime[30]; + time_t now; + int nBufferSize; + + now = time(NULL); + strftime(szTime, sizeof(szTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); + /* Sun, 00 Jan 0000 00:00:00 GMT */ + + szMyNick = null_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)(HANDLE)NULL, 0)); + nBufferSize = 1 + strlennull(szMyNick) + strlennull(szPhoneNumber) + strlennull(szMsg) + sizeof("1252utf80000000000Yes"); + + if (szBuffer = (char *)_alloca(nBufferSize)) + { + + wBufferLen = null_snprintf(szBuffer, nBufferSize, + "" + "" + "%s" /* phone number */ + "" + "" + "%s" /* body */ + "" + "" + "1252" + "" + "" + "utf8" + "" + "" + "%u" /* my UIN */ + "" + "" + "%s" /* my nick */ + "" + "" + "Yes" + "" + "" + "", + szPhoneNumber, szMsg, m_dwLocalUIN, szMyNick, szTime); + + dwCookie = GenerateCookie(0); + + packServIcqExtensionHeader(&packet, this, (WORD)(wBufferLen + 27), CLI_META_INFO_REQ, (WORD)dwCookie); + packWord(&packet, 0x8214); /* send sms */ + packWord(&packet, 1); + packWord(&packet, 0x16); + packDWord(&packet, 0); + packDWord(&packet, 0); + packDWord(&packet, 0); + packDWord(&packet, 0); + packWord(&packet, 0); + packWord(&packet, (WORD)(wBufferLen + 1)); + packBuffer(&packet, (LPBYTE)szBuffer, (WORD)(1 + wBufferLen)); + + sendServPacket(&packet); + } + else + { + dwCookie = 0; + } + + SAFE_FREE((void**)&szMyNick); + return dwCookie; +} + +void CIcqProto::icq_sendGenericContact(DWORD dwUin, const char *szUid, WORD wFamily, WORD wSubType) +{ + icq_packet packet; + int nUinLen; + + nUinLen = getUIDLen(dwUin, szUid); + + serverPacketInit(&packet, (WORD)(nUinLen + 11)); + packFNACHeader(&packet, wFamily, wSubType); + packUID(&packet, dwUin, szUid); + + sendServPacket(&packet); +} + +void CIcqProto::icq_sendNewContact(DWORD dwUin, const char *szUid) +{ + /* Try to add to temporary buddy list */ + icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST); +} + + +void CIcqProto::icq_sendRemoveContact(DWORD dwUin, const char *szUid) +{ + /* Remove from temporary buddy list */ + icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_REMOVEFROMTEMPLIST); +} + + +// list==0: visible list +// list==1: invisible list +void CIcqProto::icq_sendChangeVisInvis(HANDLE hContact, DWORD dwUin, char* szUID, int list, int add) +{ // TODO: This needs grouping & rate management + // Tell server to change our server-side contact visbility list + if (m_bSsiEnabled) + { + WORD wContactId; + char* szSetting; + WORD wType; + + if (list == 0) + { + wType = SSI_ITEM_PERMIT; + szSetting = DBSETTING_SERVLIST_PERMIT; + } + else + { + wType = SSI_ITEM_DENY; + szSetting = DBSETTING_SERVLIST_DENY; + } + + if (add) + { + // check if we should make the changes, this is 2nd level check + if (getSettingWord(hContact, szSetting, 0) != 0) + return; + + // Add + wContactId = GenerateServerID(SSIT_ITEM, 0); + + icq_addServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType); + + setSettingWord(hContact, szSetting, wContactId); + } + else + { + // Remove + wContactId = getSettingWord(hContact, szSetting, 0); + + if (wContactId) + { + icq_removeServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType); + + deleteSetting(hContact, szSetting); + } + } + } + + // Notify server that we have changed + // our client side visibility list + { + int nUinLen; + icq_packet packet; + WORD wSnac = 0; + + if (list && m_iStatus == ID_STATUS_INVISIBLE) + return; + + if (!list && m_iStatus != ID_STATUS_INVISIBLE) + return; + + + if (list && add) + wSnac = ICQ_CLI_ADDINVISIBLE; + else if (list && !add) + wSnac = ICQ_CLI_REMOVEINVISIBLE; + else if (!list && add) + wSnac = ICQ_CLI_ADDVISIBLE; + else if (!list && !add) + wSnac = ICQ_CLI_REMOVEVISIBLE; + + nUinLen = getUIDLen(dwUin, szUID); + + serverPacketInit(&packet, (WORD)(nUinLen + 11)); + packFNACHeader(&packet, ICQ_BOS_FAMILY, wSnac); + packUID(&packet, dwUin, szUID); + + sendServPacket(&packet); + } +} + +void CIcqProto::icq_sendEntireVisInvisList(int list) +{ + if (list) + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE); + else + sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE); +} + +void CIcqProto::icq_sendRevokeAuthServ(DWORD dwUin, char *szUid) +{ + icq_sendGenericContact(dwUin, szUid, ICQ_LISTS_FAMILY, ICQ_LISTS_REVOKEAUTH); +} + +void CIcqProto::icq_sendGrantAuthServ(DWORD dwUin, const char *szUid, const char *szMsg) +{ + icq_packet packet; + BYTE nUinlen; + char *szUtfMsg = NULL; + WORD nMsglen; + + nUinlen = getUIDLen(dwUin, szUid); + + // Prepare custom utf-8 message + szUtfMsg = ansi_to_utf8(szMsg); + nMsglen = strlennull(szUtfMsg); + + serverPacketInit(&packet, (WORD)(15 + nUinlen + nMsglen)); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_GRANTAUTH); + packUID(&packet, dwUin, szUid); + packWord(&packet, nMsglen); + packBuffer(&packet, (LPBYTE)szUtfMsg, nMsglen); + packWord(&packet, 0); + + SAFE_FREE((void**)&szUtfMsg); + + sendServPacket(&packet); +} + +void CIcqProto::icq_sendAuthReqServ(DWORD dwUin, char *szUid, const char *szMsg) +{ + icq_packet packet; + BYTE nUinlen; + WORD nMsglen; + + nUinlen = getUIDLen(dwUin, szUid); + nMsglen = strlennull(szMsg); + + serverPacketInit(&packet, (WORD)(15 + nUinlen + nMsglen)); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_REQUESTAUTH); + packUID(&packet, dwUin, szUid); + packWord(&packet, nMsglen); + packBuffer(&packet, (LPBYTE)szMsg, nMsglen); + packWord(&packet, 0); + + sendServPacket(&packet); +} + +void CIcqProto::icq_sendAuthResponseServ(DWORD dwUin, char* szUid, int auth, const TCHAR *szReason) +{ + icq_packet packet; + BYTE nUinLen = getUIDLen(dwUin, szUid); + + // Prepare custom utf-8 reason + char *szUtfReason = tchar_to_utf8(szReason); + WORD nReasonLen = strlennull(szUtfReason); + + serverPacketInit(&packet, (WORD)(16 + nUinLen + nReasonLen)); + packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_AUTHRESPONSE); + packUID(&packet, dwUin, szUid); + packByte(&packet, (BYTE)auth); + packWord(&packet, nReasonLen); + packBuffer(&packet, (LPBYTE)szUtfReason, nReasonLen); + packWord(&packet, 0); + + SAFE_FREE(&szUtfReason); + + sendServPacket(&packet); +} + +void CIcqProto::icq_sendYouWereAddedServ(DWORD dwUin, DWORD dwMyUin) +{ + icq_packet packet; + DWORD dwID1; + DWORD dwID2; + + dwID1 = time(NULL); + dwID2 = RandRange(0, 0x00FF); + + packServMsgSendHeader(&packet, 0, dwID1, dwID2, dwUin, NULL, 0x0004, 17); + packWord(&packet, 0x0005); // TLV(5) + packWord(&packet, 0x0009); + packLEDWord(&packet, dwMyUin); + packByte(&packet, MTYPE_ADDED); + packByte(&packet, 0); // msg-flags + packEmptyMsg(&packet); // NTS + packDWord(&packet, 0x00060000); // TLV(6) + + sendServPacket(&packet); +} + +void CIcqProto::icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, cookie_message_data *pCookieData) +{ + icq_packet packet; + WORD wCoreLen; + + wCoreLen = 11 + getPluginTypeIdLen(pCookieData->bMessageType) + nBodyLen; + packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, NULL, 2, (WORD)(99 + wCoreLen)); + + // TLV(5) header + packServTLV5HeaderMsg(&packet, (WORD)(55 + wCoreLen), pCookieData->dwMsgID1, pCookieData->dwMsgID2, 1); + + // TLV(0x2711) header + packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, 0, 0x100, wCoreLen); + // + packEmptyMsg(&packet); + + packPluginTypeId(&packet, pCookieData->bMessageType); + + packLEDWord(&packet, nBodyLen + 4); + packLEDWord(&packet, nBodyLen); + packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); + + // Pack request server ack TLV + packDWord(&packet, 0x00030000); // TLV(3) + + // Send the monster + sendServPacket(&packet); +} + +void CIcqProto::icq_sendXtrazResponseServ(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szBody, int nBodyLen, int nType) +{ + icq_packet packet; + + packServAdvancedMsgReply(&packet, dwUin, NULL, dwMID, dwMID2, wCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)(getPluginTypeIdLen(nType) + 11 + nBodyLen)); + // + packEmptyMsg(&packet); + + packPluginTypeId(&packet, nType); + + packLEDWord(&packet, nBodyLen + 4); + packLEDWord(&packet, nBodyLen); + packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); + + // Send the monster + sendServPacket(&packet); +} + +void CIcqProto::icq_sendReverseReq(directconnect *dc, DWORD dwCookie, cookie_message_data *pCookie) +{ + icq_packet packet; + + packServMsgSendHeader(&packet, dwCookie, pCookie->dwMsgID1, pCookie->dwMsgID2, dc->dwRemoteUin, NULL, 2, 0x47); + + packServTLV5HeaderBasic(&packet, 0x29, pCookie->dwMsgID1, pCookie->dwMsgID2, 0, MCAP_REVERSE_DC_REQ); + + packTLVWord(&packet, 0x0A, 1); // TLV: 0x0A Acktype: 1 for normal, 2 for ack + packDWord(&packet, 0x000F0000); // TLV: 0x0F empty + packDWord(&packet, 0x2711001B); // TLV: 0x2711 Content + // TLV(0x2711) data + packLEDWord(&packet, m_dwLocalUIN); // Our UIN + packDWord(&packet, dc->dwLocalExternalIP);// IP to connect to + packLEDWord(&packet, wListenPort); // Port to connect to + packByte(&packet, DC_NORMAL); // generic DC type + packDWord(&packet, dc->dwRemotePort); // unknown + packDWord(&packet, wListenPort); // port again ? + packLEWord(&packet, ICQ_VERSION); // DC Version + packLEDWord(&packet, dwCookie); // Req Cookie + + // Send the monster + sendServPacket(&packet); +} + +void CIcqProto::icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie) +{ + icq_packet packet; + int nUinLen = getUINLen(dc->dwRemoteUin); + + serverPacketInit(&packet, (WORD)(nUinLen + 74)); + packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE, 0, ICQ_MSG_RESPONSE<<0x10 | (dwCookie & 0x7FFF)); + packLEDWord(&packet, dwMsgID1); // Msg ID part 1 + packLEDWord(&packet, dwMsgID2); // Msg ID part 2 + packWord(&packet, 0x02); + packUIN(&packet, dc->dwRemoteUin); + packWord(&packet, 0x03); + packLEDWord(&packet, dc->dwRemoteUin); + packLEDWord(&packet, dc->dwRemotePort); + packLEDWord(&packet, wListenPort); + packLEWord(&packet, ICQ_VERSION); + packLEDWord(&packet, dwCookie); + + sendServPacket(&packet); +} + + +// OSCAR file-transfer packets starts here +// +void CIcqProto::oft_sendFileRequest(DWORD dwUin, char *szUid, oscar_filetransfer *ft, const char *pszFiles, DWORD dwLocalInternalIP) +{ + icq_packet packet; + + char *szCoolStr = (char*)_alloca(strlennull(ft->szDescription)+strlennull(pszFiles) + 160); + sprintf(szCoolStr, "%s%I64u1%s", pszFiles, ft->qwTotalSize, ft->szDescription); + szCoolStr = MangleXml(szCoolStr, strlennull(szCoolStr)); + + WORD wDataLen = 93 + strlennull(szCoolStr) + strlennull(pszFiles); + if (ft->bUseProxy) wDataLen += 4; + + packServMsgSendHeader(&packet, ft->dwCookie, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, (WORD)(wDataLen + 0x1E)); + packServTLV5HeaderBasic(&packet, wDataLen, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, MCAP_FILE_TRANSFER); + + packTLVWord(&packet, 0x0A, ++ft->wReqNum); // Request sequence + packDWord(&packet, 0x000F0000); // Unknown + packTLV(&packet, 0x0D, 5, (LPBYTE)"utf-8"); // Charset + packTLV(&packet, 0x0C, (WORD)strlennull(szCoolStr), (LPBYTE)szCoolStr); // User message (CoolData XML) + SAFE_FREE(&szCoolStr); + if (ft->bUseProxy) + { + packTLVDWord(&packet, 0x02, ft->dwProxyIP); // Proxy IP + packTLVDWord(&packet, 0x16, ft->dwProxyIP ^ 0x0FFFFFFFF); // Proxy IP check + } + else + { + packTLVDWord(&packet, 0x02, dwLocalInternalIP); + packTLVDWord(&packet, 0x16, dwLocalInternalIP ^ 0x0FFFFFFFF); + } + packTLVDWord(&packet, 0x03, dwLocalInternalIP); // Client IP + if (ft->bUseProxy) + { + packTLVWord(&packet, 0x05, ft->wRemotePort); + packTLVWord(&packet, 0x17, (WORD)(ft->wRemotePort ^ 0x0FFFF)); + packDWord(&packet, 0x00100000); // Proxy flag + } + else + { + oscar_listener *pListener = (oscar_listener*)ft->listener; + + packTLVWord(&packet, 0x05, pListener->wPort); + packTLVWord(&packet, 0x15, (WORD)((pListener->wPort) ^ 0x0FFFF)); + } + { // TLV(0x2711) + packWord(&packet, 0x2711); + packWord(&packet, (WORD)(9 + strlennull(pszFiles))); + packWord(&packet, (WORD)(ft->wFilesCount == 1 ? 1 : 2)); + packWord(&packet, ft->wFilesCount); + packDWord(&packet, (DWORD)ft->qwTotalSize); + packBuffer(&packet, (LPBYTE)pszFiles, (WORD)(strlennull(pszFiles) + 1)); + } + packTLV(&packet, 0x2712, 5, (LPBYTE)"utf-8"); + { // TLV(0x2713) + packWord(&packet, 0x2713); + packWord(&packet, 8); + packQWord(&packet, ft->qwTotalSize); + } + + sendServPacket(&packet); // Send the monster +} + + +void CIcqProto::oft_sendFileReply(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResult) +{ + icq_packet packet; + + packServMsgSendHeader(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, 0x1E); + packServTLV5HeaderBasic(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, wResult, MCAP_FILE_TRANSFER); + + sendServPacket(&packet); +} + + +void CIcqProto::oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer *ft) +{ + oft_sendFileReply(dwUin, szUid, ft, 0x02); +} + + +void CIcqProto::oft_sendFileResponse(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResponse) +{ + icq_packet packet; + + packServAdvancedReply(&packet, dwUin, szUid, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, 4); + packWord(&packet, 0x02); // Length of following data + packWord(&packet, wResponse); // Response code + + sendServPacket(&packet); +} + + +void CIcqProto::oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer *ft) +{ + if (dwUin) + { // ICQ clients uses special deny file transfer + oft_sendFileResponse(dwUin, szUid, ft, 0x01); + } + else + oft_sendFileReply(dwUin, szUid, ft, 0x01); +} + + +void CIcqProto::oft_sendFileCancel(DWORD dwUin, char *szUid, oscar_filetransfer *ft) +{ + oft_sendFileReply(dwUin, szUid, ft, 0x01); +} + + +void CIcqProto::oft_sendFileRedirect(DWORD dwUin, char *szUid, oscar_filetransfer *ft, DWORD dwIP, WORD wPort, int bProxy) +{ + icq_packet packet; + + packServMsgSendHeader(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, (WORD)(bProxy ? 0x4a : 0x4e)); + packServTLV5HeaderBasic(&packet, (WORD)(bProxy ? 0x2C : 0x30), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, MCAP_FILE_TRANSFER); + // Connection point data + packTLVWord(&packet, 0x0A, ++ft->wReqNum); // Ack Type + packTLVWord(&packet, 0x14, 0x0A); // Unknown ? + packTLVDWord(&packet, 0x02, dwIP); // Internal IP / Proxy IP + packTLVDWord(&packet, 0x16, dwIP ^ 0x0FFFFFFFF); // IP Check ? + if (!bProxy) + packTLVDWord(&packet, 0x03, dwIP); + packTLVWord(&packet, 0x05, wPort); // Listening Port + packTLVWord(&packet, 0x17, (WORD)(wPort ^ 0x0FFFF)); // Port Check ? + if (bProxy) + packDWord(&packet, 0x00100000); // Proxy Flag + + sendServPacket(&packet); +} diff --git a/protocols/IcqOscarJ/src/stdpackets.h b/protocols/IcqOscarJ/src/stdpackets.h new file mode 100644 index 0000000000..b656d713c6 --- /dev/null +++ b/protocols/IcqOscarJ/src/stdpackets.h @@ -0,0 +1,43 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Low-level functions that really sends data to server +// +// ----------------------------------------------------------------------------- +#ifndef __STDPACKETS_H +#define __STDPACKETS_H + +struct icq_contactsend_s +{ + DWORD uin; + char *uid; + char *szNick; +}; + + +void packMsgColorInfo(icq_packet *packet); + +#endif /* __STDPACKETS_H */ diff --git a/protocols/IcqOscarJ/src/tlv.cpp b/protocols/IcqOscarJ/src/tlv.cpp new file mode 100644 index 0000000000..7c4eafca3a --- /dev/null +++ b/protocols/IcqOscarJ/src/tlv.cpp @@ -0,0 +1,391 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2009 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Helper functions for Oscar TLV chains +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + + +/* set maxTlvs<=0 to get all TLVs in length, or a positive integer to get at most the first n */ +oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs) +{ + oscar_tlv_chain *now, *last, *chain = NULL; + WORD now_tlv_len; + int len = wLen; + + if (!buf || !wLen) return NULL; + + while (len > 0) /* don't use unsigned variable for this check */ + { + now = (oscar_tlv_chain *)SAFE_MALLOC(sizeof(oscar_tlv_chain)); + + if (!now) + { + disposeChain(&chain); + return NULL; + } + + unpackWord(buf, &(now->tlv.wType)); + unpackWord(buf, &now_tlv_len); + now->tlv.wLen = now_tlv_len; + len -= 4; + + if (now_tlv_len < 1) + { + now->tlv.pData = NULL; + } + else if (now_tlv_len <= len) + { + now->tlv.pData = (BYTE *)SAFE_MALLOC(now_tlv_len); + if (now->tlv.pData) + memcpy(now->tlv.pData, *buf, now_tlv_len); + } + else + { // the packet is shorter than it should be + SAFE_FREE((void**)&now); + return chain; // give at least the rest of chain + } + + if (chain) // keep the original order + last->next = now; + else + chain = now; + + last = now; + + len -= now_tlv_len; + *buf += now_tlv_len; + + if (--maxTlvs == 0) + break; + } + + return chain; +} + +// Returns a pointer to the TLV with type wType and number wIndex in the chain +// If wIndex = 1, the first matching TLV will be returned, if wIndex = 2, +// the second matching one will be returned. +// wIndex must be > 0 +oscar_tlv* oscar_tlv_chain::getTLV(WORD wType, WORD wIndex) +{ + int i = 0; + oscar_tlv_chain *list = this; + + while (list) + { + if (list->tlv.wType == wType) + i++; + if (i >= wIndex) + return &list->tlv; + list = list->next; + } + + return NULL; +} + + +WORD oscar_tlv_chain::getChainLength() +{ + int len = 0; + oscar_tlv_chain *list = this; + + while (list) + { + len += list->tlv.wLen + 4; + list = list->next; + } + return len; +} + + +oscar_tlv* oscar_tlv_chain::putTLV(WORD wType, WORD wLen, BYTE *pData, BOOL bReplace) +{ + oscar_tlv *tlv = getTLV(wType, 1); + + if (tlv && bReplace) + { + SAFE_FREE((void**)&tlv->pData); + } + else + { + oscar_tlv_chain *last = this; + + while (last && last->next) + last = last->next; + + if (last) + { + last->next = (oscar_tlv_chain*)SAFE_MALLOC(sizeof(oscar_tlv_chain)); + tlv = &last->next->tlv; + tlv->wType = wType; + } + } + if (tlv) + { + tlv->wLen = wLen; + tlv->pData = (PBYTE)SAFE_MALLOC(wLen); + memcpy(tlv->pData, pData, wLen); + } + return tlv; +} + + +oscar_tlv_chain* oscar_tlv_chain::removeTLV(oscar_tlv *tlv) +{ + oscar_tlv_chain *list = this, *prev = NULL, *chain = this; + + while (list) + { + if (&list->tlv == tlv) + { + if (prev) // relink + prev->next = list->next; + else if (list->next) + { // move second item's tlv to the first item + list->tlv = list->next->tlv; + list = list->next; + } + else // result is an empty chain (NULL) + chain = NULL; + // release chain item memory + SAFE_FREE((void**)&list->tlv.pData); + SAFE_FREE((void**)&list); + } + prev = list; + list = list->next; + } + + return chain; +} + + +WORD oscar_tlv_chain::getLength(WORD wType, WORD wIndex) +{ + oscar_tlv *tlv = getTLV(wType, wIndex); + if (tlv) + return tlv->wLen; + + return 0; +} + + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* Values are returned in MSB format */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +DWORD oscar_tlv_chain::getDWord(WORD wType, WORD wIndex) +{ + DWORD dw = 0; + + oscar_tlv *tlv = getTLV(wType, wIndex); + if (tlv && tlv->wLen >= 4) + { + dw |= (*((tlv->pData)+0) << 24); + dw |= (*((tlv->pData)+1) << 16); + dw |= (*((tlv->pData)+2) << 8); + dw |= (*((tlv->pData)+3)); + } + + return dw; +} + + +WORD oscar_tlv_chain::getWord(WORD wType, WORD wIndex) +{ + WORD w = 0; + + oscar_tlv *tlv = getTLV(wType, wIndex); + if (tlv && tlv->wLen >= 2) + { + w |= (*((tlv->pData)+0) << 8); + w |= (*((tlv->pData)+1)); + } + + return w; +} + + +BYTE oscar_tlv_chain::getByte(WORD wType, WORD wIndex) +{ + BYTE b = 0; + + oscar_tlv *tlv = getTLV(wType, wIndex); + if (tlv && tlv->wLen) + { + b = *(tlv->pData); + } + + return b; +} + + +int oscar_tlv_chain::getNumber(WORD wType, WORD wIndex) +{ + oscar_tlv *tlv = getTLV(wType, wIndex); + + if (tlv) + { + if (tlv->wLen == 1) + return getByte(wType, wIndex); + else if (tlv->wLen == 2) + return getWord(wType, wIndex); + else if (tlv->wLen == 4) + return getDWord(wType, wIndex); + } + return 0; +} + + +double oscar_tlv_chain::getDouble(WORD wType, WORD wIndex) +{ + oscar_tlv *tlv = getTLV(wType, wIndex); + + if (tlv && tlv->wLen == 8) + { + BYTE *buf = tlv->pData; + double d = 0; + + unpackQWord(&buf, (DWORD64*)&d); + + return d; + } + return 0; +} + + +char* oscar_tlv_chain::getString(WORD wType, WORD wIndex) +{ + char *str = NULL; + + oscar_tlv *tlv = getTLV(wType, wIndex); + if (tlv) + { + str = (char*)SAFE_MALLOC(tlv->wLen + 1); /* For \0 */ + + if (!str) return NULL; + + memcpy(str, tlv->pData, tlv->wLen); + str[tlv->wLen] = '\0'; + } + + return str; +} + + +void disposeChain(oscar_tlv_chain **chain) +{ + if (!chain || !*chain) + return; + + oscar_tlv_chain *now = *chain; + + while (now) + { + oscar_tlv_chain *next = now->next; + + SAFE_FREE((void**)&now->tlv.pData); + SAFE_FREE((void**)&now); + now = next; + } + + *chain = NULL; +} + + +oscar_tlv_record_list* readIntoTLVRecordList(BYTE **buf, WORD wLen, int nCount) +{ + oscar_tlv_record_list *list = NULL, *last; + + while (wLen >= 2) + { + WORD wRecordSize; + + unpackWord(buf, &wRecordSize); + wLen -= 2; + if (wRecordSize && wRecordSize <= wLen) + { + oscar_tlv_record_list *pRecord = (oscar_tlv_record_list*)SAFE_MALLOC(sizeof(oscar_tlv_record_list)); + BYTE *pData = *buf; + + *buf += wRecordSize; + wLen -= wRecordSize; + + pRecord->item = readIntoTLVChain(&pData, wRecordSize, 0); + if (pRecord->item) + { // keep the order + if (list) + last->next = pRecord; + else + list = pRecord; + + last = pRecord; + } + else + SAFE_FREE((void**)&pRecord); + } + + if (--nCount == 0) break; + } + return list; +} + + +void disposeRecordList(oscar_tlv_record_list** list) +{ + if (!list || !*list) + return; + + oscar_tlv_record_list *now = *list; + + while (now) + { + oscar_tlv_record_list *next = now->next; + + disposeChain(&now->item); + SAFE_FREE((void**)&now); + now = next; + } + + *list = NULL; +} + + +oscar_tlv_chain* oscar_tlv_record_list::getRecordByTLV(WORD wType, int nValue) +{ + oscar_tlv_record_list *list = this; + + while (list) + { + if (list->item && list->item->getTLV(wType, 1) && list->item->getNumber(wType, 1) == nValue) + return list->item; + list = list->next; + } + + return NULL; +} diff --git a/protocols/IcqOscarJ/src/tlv.h b/protocols/IcqOscarJ/src/tlv.h new file mode 100644 index 0000000000..5cee00c7c4 --- /dev/null +++ b/protocols/IcqOscarJ/src/tlv.h @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __TLV_H +#define __TLV_H + +/*---------* Structures *--------------*/ + +struct oscar_tlv +{ + WORD wType; + WORD wLen; + BYTE *pData; +}; + + +struct oscar_tlv_chain +{ + oscar_tlv tlv; + oscar_tlv_chain *next; + + WORD getChainLength(); + + oscar_tlv* getTLV(WORD wType, WORD wIndex); + oscar_tlv* putTLV(WORD wType, WORD wLen, BYTE *pData, BOOL bReplace); + oscar_tlv_chain* removeTLV(oscar_tlv *tlv); + WORD getLength(WORD wType, WORD wIndex); + + DWORD getDWord(WORD wType, WORD wIndex); + WORD getWord(WORD wType, WORD wIndex); + BYTE getByte(WORD wType, WORD wIndex); + int getNumber(WORD wType, WORD wIndex); + double getDouble(WORD wType, WORD wIndex); + char* getString(WORD wType, WORD wIndex); +}; + + +struct oscar_tlv_record_list +{ + oscar_tlv_chain *item; + oscar_tlv_record_list *next; + + oscar_tlv_chain* getRecordByTLV(WORD wType, int nValue); +}; + +/*---------* Functions *---------------*/ + +oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs); +void disposeChain(oscar_tlv_chain** chain); + +oscar_tlv_record_list* readIntoTLVRecordList(BYTE **buf, WORD wLen, int nCount); +void disposeRecordList(oscar_tlv_record_list** list); + + +#endif /* __TLV_H */ diff --git a/protocols/IcqOscarJ/src/utilities.cpp b/protocols/IcqOscarJ/src/utilities.cpp new file mode 100644 index 0000000000..70f7547108 --- /dev/null +++ b/protocols/IcqOscarJ/src/utilities.cpp @@ -0,0 +1,2183 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#include "icqoscar.h" + + +struct gateway_index +{ + HANDLE hConn; + DWORD dwIndex; +}; + +static icq_critical_section *gatewayMutex = NULL; + +static gateway_index *gateways = NULL; +static int gatewayCount = 0; + +static DWORD *spammerList = NULL; +static int spammerListCount = 0; + + +void MoveDlgItem(HWND hwndDlg, int iItem, int left, int top, int width, int height) +{ + RECT rc; + + rc.left = left; + rc.top = top; + rc.right = left + width; + rc.bottom = top + height; + MapDialogRect(hwndDlg, &rc); + MoveWindow(GetDlgItem(hwndDlg, iItem), rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); +} + + +void EnableDlgItem(HWND hwndDlg, UINT control, int state) +{ + EnableWindow(GetDlgItem(hwndDlg, control), state); +} + + +void ShowDlgItem(HWND hwndDlg, UINT control, int state) +{ + ShowWindow(GetDlgItem(hwndDlg, control), state); +} + + +void icq_EnableMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state) +{ + for (int i = 0; i < cControls; i++) + EnableDlgItem(hwndDlg, controls[i], state); +} + + +void icq_ShowMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state) +{ + for (int i = 0; i < cControls; i++) + ShowDlgItem(hwndDlg, controls[i], state); +} + + +// Maps the ICQ status flag (as seen in the status change SNACS) and returns +// a Miranda style status. +int IcqStatusToMiranda(WORD nIcqStatus) +{ + int nMirandaStatus; + + // :NOTE: The order in which the flags are compared are important! + // I dont like this method but it works. + + if (nIcqStatus & ICQ_STATUSF_INVISIBLE) + nMirandaStatus = ID_STATUS_INVISIBLE; + else + if (nIcqStatus & ICQ_STATUSF_DND) + nMirandaStatus = ID_STATUS_DND; + else + if (nIcqStatus & ICQ_STATUSF_OCCUPIED) + nMirandaStatus = ID_STATUS_OCCUPIED; + else + if (nIcqStatus & ICQ_STATUSF_NA) + nMirandaStatus = ID_STATUS_NA; + else + if (nIcqStatus & ICQ_STATUSF_AWAY) + nMirandaStatus = ID_STATUS_AWAY; + else + if (nIcqStatus & ICQ_STATUSF_FFC) + nMirandaStatus = ID_STATUS_FREECHAT; + else + // Can be discussed, but I think 'online' is the most generic ICQ status + nMirandaStatus = ID_STATUS_ONLINE; + + return nMirandaStatus; +} + +WORD MirandaStatusToIcq(int nMirandaStatus) +{ + WORD nIcqStatus; + + switch (nMirandaStatus) { +case ID_STATUS_ONLINE: + nIcqStatus = ICQ_STATUS_ONLINE; + break; + +case ID_STATUS_AWAY: + nIcqStatus = ICQ_STATUS_AWAY; + break; + +case ID_STATUS_OUTTOLUNCH: +case ID_STATUS_NA: + nIcqStatus = ICQ_STATUS_NA; + break; + +case ID_STATUS_ONTHEPHONE: +case ID_STATUS_OCCUPIED: + nIcqStatus = ICQ_STATUS_OCCUPIED; + break; + +case ID_STATUS_DND: + nIcqStatus = ICQ_STATUS_DND; + break; + +case ID_STATUS_INVISIBLE: + nIcqStatus = ICQ_STATUS_INVISIBLE; + break; + +case ID_STATUS_FREECHAT: + nIcqStatus = ICQ_STATUS_FFC; + break; + +case ID_STATUS_OFFLINE: + // Oscar doesnt have anything that maps to this status. This should never happen. + _ASSERTE(nMirandaStatus != ID_STATUS_OFFLINE); + nIcqStatus = 0; + break; + +default: + // Online seems to be a good default. + // Since it cant be offline, it must be a new type of online status. + nIcqStatus = ICQ_STATUS_ONLINE; + break; + } + + return nIcqStatus; +} + +int MirandaStatusToSupported(int nMirandaStatus) +{ + int nSupportedStatus; + + switch (nMirandaStatus) { + + // These status mode does not need any mapping +case ID_STATUS_ONLINE: +case ID_STATUS_AWAY: +case ID_STATUS_NA: +case ID_STATUS_OCCUPIED: +case ID_STATUS_DND: +case ID_STATUS_INVISIBLE: +case ID_STATUS_OFFLINE: + nSupportedStatus = nMirandaStatus; + break; + +case ID_STATUS_FREECHAT: + nSupportedStatus = ID_STATUS_ONLINE; + break; + + // This mode is not support and must be mapped to something else +case ID_STATUS_OUTTOLUNCH: + nSupportedStatus = ID_STATUS_NA; + break; + + // This mode is not support and must be mapped to something else +case ID_STATUS_ONTHEPHONE: + nSupportedStatus = ID_STATUS_OCCUPIED; + break; + + // This is not supposed to happen. +default: + _ASSERTE(0); + // Online seems to be a good default. + nSupportedStatus = ID_STATUS_ONLINE; + break; + } + + return nSupportedStatus; +} + +char *MirandaStatusToString(int mirandaStatus) +{ + return (char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, mirandaStatus, 0); +} + +char *MirandaStatusToStringUtf(int mirandaStatus) +{ // return miranda status description in utf-8, use unicode service is possible + return tchar_to_utf8((TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, mirandaStatus, GSMDF_TCHAR)); +} + +char** CIcqProto::MirandaStatusToAwayMsg(int nStatus) +{ + switch (nStatus) { + +case ID_STATUS_ONLINE: + return &m_modeMsgs.szOnline; + +case ID_STATUS_AWAY: + return &m_modeMsgs.szAway; + +case ID_STATUS_NA: + return &m_modeMsgs.szNa; + +case ID_STATUS_OCCUPIED: + return &m_modeMsgs.szOccupied; + +case ID_STATUS_DND: + return &m_modeMsgs.szDnd; + +case ID_STATUS_FREECHAT: + return &m_modeMsgs.szFfc; + +default: + return NULL; + } +} + +int AwayMsgTypeToStatus(int nMsgType) +{ + switch (nMsgType) { +case MTYPE_AUTOONLINE: + return ID_STATUS_ONLINE; + +case MTYPE_AUTOAWAY: + return ID_STATUS_AWAY; + +case MTYPE_AUTOBUSY: + return ID_STATUS_OCCUPIED; + +case MTYPE_AUTONA: + return ID_STATUS_NA; + +case MTYPE_AUTODND: + return ID_STATUS_DND; + +case MTYPE_AUTOFFC: + return ID_STATUS_FREECHAT; + +default: + return ID_STATUS_OFFLINE; + } +} + + +void SetGatewayIndex(HANDLE hConn, DWORD dwIndex) +{ + icq_lock l(gatewayMutex); + + for (int i = 0; i < gatewayCount; i++) + { + if (hConn == gateways[i].hConn) + { + gateways[i].dwIndex = dwIndex; + return; + } + } + + gateways = (gateway_index *)SAFE_REALLOC(gateways, sizeof(gateway_index) * (gatewayCount + 1)); + gateways[gatewayCount].hConn = hConn; + gateways[gatewayCount].dwIndex = dwIndex; + gatewayCount++; +} + + +DWORD GetGatewayIndex(HANDLE hConn) +{ + icq_lock l(gatewayMutex); + + for (int i = 0; i < gatewayCount; i++) + { + if (hConn == gateways[i].hConn) + return gateways[i].dwIndex; + } + + return 1; // this is default +} + + +void FreeGatewayIndex(HANDLE hConn) +{ + icq_lock l(gatewayMutex); + + for (int i = 0; i < gatewayCount; i++) + { + if (hConn == gateways[i].hConn) + { + gatewayCount--; + memmove(&gateways[i], &gateways[i+1], sizeof(gateway_index) * (gatewayCount - i)); + gateways = (gateway_index*)SAFE_REALLOC(gateways, sizeof(gateway_index) * gatewayCount); + + // Gateway found, exit loop + break; + } + } +} + + +void CIcqProto::AddToSpammerList(DWORD dwUIN) +{ + icq_lock l(gatewayMutex); + + spammerList = (DWORD *)SAFE_REALLOC(spammerList, sizeof(DWORD) * (spammerListCount + 1)); + spammerList[spammerListCount] = dwUIN; + spammerListCount++; +} + + +BOOL CIcqProto::IsOnSpammerList(DWORD dwUIN) +{ + icq_lock l(gatewayMutex); + + for (int i = 0; i < spammerListCount; i++) + { + if (dwUIN == spammerList[i]) + return TRUE; + } + + return FALSE; +} + + +// ICQ contacts cache + +void CIcqProto::AddToContactsCache(HANDLE hContact, DWORD dwUin, const char *szUid) +{ + if (!hContact || (!dwUin && !szUid)) + return; + +#ifdef _DEBUG + NetLog_Server("Adding contact to cache: %u%s%s", dwUin, dwUin ? "" : " - ", dwUin ? "" : szUid); +#endif + + icq_contacts_cache *cache_item = (icq_contacts_cache*)SAFE_MALLOC(sizeof(icq_contacts_cache)); + cache_item->hContact = hContact; + cache_item->dwUin = dwUin; + if (!dwUin) + cache_item->szUid = null_strdup(szUid); + + icq_lock l(contactsCacheMutex); + contactsCache.insert(cache_item); +} + + +void CIcqProto::InitContactsCache() +{ + if (!gatewayMutex) + gatewayMutex = new icq_critical_section(); + else + gatewayMutex->_Lock(); + + contactsCacheMutex = new icq_critical_section(); + + // build cache + icq_lock l(contactsCacheMutex); + + HANDLE hContact = FindFirstContact(); + + while (hContact) + { + DWORD dwUin; + uid_str szUid; + + if (!getContactUid(hContact, &dwUin, &szUid)) + AddToContactsCache(hContact, dwUin, szUid); + + hContact = FindNextContact(hContact); + } +} + + +void CIcqProto::UninitContactsCache(void) +{ + contactsCacheMutex->Enter(); + + // cleanup the cache + for (int i = 0; i < contactsCache.getCount(); i++) + { + icq_contacts_cache *cache_item = contactsCache[i]; + + SAFE_FREE((void**)&cache_item->szUid); + SAFE_FREE((void**)&cache_item); + } + + contactsCache.destroy(); + + contactsCacheMutex->Leave(); + + SAFE_DELETE(&contactsCacheMutex); + + if (gatewayMutex && gatewayMutex->getLockCount() > 1) + gatewayMutex->_Release(); + else + SAFE_DELETE(&gatewayMutex); +} + + +void CIcqProto::DeleteFromContactsCache(HANDLE hContact) +{ + icq_lock l(contactsCacheMutex); + + for (int i = 0; i < contactsCache.getCount(); i++) + { + icq_contacts_cache *cache_item = contactsCache[i]; + + if (cache_item->hContact == hContact) + { +#ifdef _DEBUG + NetLog_Server("Removing contact from cache: %u%s%s, position: %u", cache_item->dwUin, cache_item->dwUin ? "" : " - ", cache_item->dwUin ? "" : cache_item->szUid, i); +#endif + contactsCache.remove(i); + // Release memory + SAFE_FREE((void**)&cache_item->szUid); + SAFE_FREE((void**)&cache_item); + break; + } + } +} + + +HANDLE CIcqProto::HandleFromCacheByUid(DWORD dwUin, const char *szUid) +{ + icq_contacts_cache cache_item = {NULL, dwUin, szUid}; + + icq_lock l(contactsCacheMutex); + // find in list + int i = contactsCache.getIndex(&cache_item); + if (i != -1) + return contactsCache[i]->hContact; + + return NULL; +} + + +HANDLE CIcqProto::HContactFromUIN(DWORD dwUin, int *Added) +{ + if (Added) *Added = 0; + + HANDLE hContact = HandleFromCacheByUid(dwUin, NULL); + if (hContact) return hContact; + + hContact = FindFirstContact(); + while (hContact) + { + DWORD dwContactUin; + + dwContactUin = getContactUin(hContact); + if (dwContactUin == dwUin) + { + AddToContactsCache(hContact, dwUin, NULL); + return hContact; + } + + hContact = FindNextContact(hContact); + } + + //not present: add + if (Added) + { + hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); + if (!hContact) + { + NetLog_Server("Failed to create ICQ contact %u", dwUin); + return INVALID_HANDLE_VALUE; + } + + if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName) != 0) + { + // For some reason we failed to register the protocol to this contact + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + NetLog_Server("Failed to register ICQ contact %u", dwUin); + return INVALID_HANDLE_VALUE; + } + + setSettingDword(hContact, UNIQUEIDSETTING, dwUin); + + if (!bIsSyncingCL) + { + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + setContactHidden(hContact, 1); + + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + + icq_QueueUser(hContact); + + if (icqOnline()) + icq_sendNewContact(dwUin, NULL); + } + AddToContactsCache(hContact, dwUin, NULL); + *Added = 1; + + return hContact; + } + + // not in list, check that uin do not belong to us + if (getContactUin(NULL) == dwUin) + return NULL; + + return INVALID_HANDLE_VALUE; +} + + +HANDLE CIcqProto::HContactFromUID(DWORD dwUin, const char *szUid, int *Added) +{ + if (dwUin) + return HContactFromUIN(dwUin, Added); + + if (Added) *Added = 0; + + if (!m_bAimEnabled) return INVALID_HANDLE_VALUE; + + HANDLE hContact = HandleFromCacheByUid(dwUin, szUid); + if (hContact) return hContact; + + hContact = FindFirstContact(); + while (hContact) + { + DWORD dwContactUin; + uid_str szContactUid; + + if (!getContactUid(hContact, &dwContactUin, &szContactUid)) + { + if (!dwContactUin && !stricmpnull(szContactUid, szUid)) + { + if (strcmpnull(szContactUid, szUid)) + { // fix case in SN + setSettingString(hContact, UNIQUEIDSETTING, szUid); + } + return hContact; + } + } + hContact = FindNextContact(hContact); + } + + //not present: add + if (Added) + { + hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName); + + setSettingString(hContact, UNIQUEIDSETTING, szUid); + + if (!bIsSyncingCL) + { + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + setContactHidden(hContact, 1); + + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + + if (icqOnline()) + icq_sendNewContact(0, szUid); + } + AddToContactsCache(hContact, 0, szUid); + *Added = 1; + + return hContact; + } + + return INVALID_HANDLE_VALUE; +} + + +HANDLE CIcqProto::HContactFromAuthEvent(HANDLE hEvent) +{ + DBEVENTINFO dbei = { sizeof(dbei) }; + DWORD body[3]; + + dbei.cbBlob = sizeof(DWORD)*2; + dbei.pBlob = (PBYTE)&body; + + if (CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei)) + return INVALID_HANDLE_VALUE; + + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) + return INVALID_HANDLE_VALUE; + + if (strcmpnull(dbei.szModule, m_szModuleName)) + return INVALID_HANDLE_VALUE; + + return DbGetAuthEventContact(&dbei); +} + +char *NickFromHandle(HANDLE hContact) +{ + if (hContact == INVALID_HANDLE_VALUE) + return null_strdup(Translate("")); + + return null_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0)); +} + +char *NickFromHandleUtf(HANDLE hContact) +{ + if (hContact == INVALID_HANDLE_VALUE) + return ICQTranslateUtf(LPGEN("")); + + return tchar_to_utf8((TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); +} + +char *strUID(DWORD dwUIN, char *pszUID) +{ + if (dwUIN && pszUID) + _ltoa(dwUIN, pszUID, 10); + + return pszUID; +} + + +/* a strlen() that likes NULL */ +int __fastcall strlennull(const char *string) +{ + if (string) + return (int)strlen(string); + + return 0; +} + + +/* a wcslen() that likes NULL */ +int __fastcall strlennull(const WCHAR *string) +{ + if (string) + return (int)wcslen(string); + + return 0; +} + + +/* a strcmp() that likes NULL */ +int __fastcall strcmpnull(const char *str1, const char *str2) +{ + if (str1 && str2) + return strcmp(str1, str2); + + if (!str1 && !str2) + return 0; + + return 1; +} + +/* a stricmp() that likes NULL */ +int __fastcall stricmpnull(const char *str1, const char *str2) +{ + if (str1 && str2) + return _stricmp(str1, str2); + + if (!str1 && !str2) + return 0; + + return 1; +} + +char* __fastcall strstrnull(const char *str, const char *substr) +{ + if (str) + return (char*)strstr(str, substr); + + return NULL; +} + +int null_snprintf(char *buffer, size_t count, const char *fmt, ...) +{ + va_list va; + int len; + + ZeroMemory(buffer, count); + va_start(va, fmt); + len = _vsnprintf(buffer, count-1, fmt, va); + va_end(va); + return len; +} + +int null_snprintf(WCHAR *buffer, size_t count, const WCHAR *fmt, ...) +{ + va_list va; + int len; + + ZeroMemory(buffer, count * sizeof(WCHAR)); + va_start(va, fmt); + len = _vsnwprintf(buffer, count, fmt, va); + va_end(va); + return len; +} + + +char* __fastcall null_strdup(const char *string) +{ + if (string) + return _strdup(string); + + return NULL; +} + + +WCHAR* __fastcall null_strdup(const WCHAR *string) +{ + if (string) + return wcsdup(string); + + return NULL; +} + + +char* __fastcall null_strcpy(char *dest, const char *src, size_t maxlen) +{ + if (!dest) + return NULL; + + if (src && src[0]) + { + strncpy(dest, src, maxlen); + dest[maxlen] = '\0'; + } + else + dest[0] = '\0'; + + return dest; +} + + +WCHAR* __fastcall null_strcpy(WCHAR *dest, const WCHAR *src, size_t maxlen) +{ + if (!dest) + return NULL; + + if (src && src[0]) + { + wcsncpy(dest, src, maxlen); + dest[maxlen] = '\0'; + } + else + dest[0] = '\0'; + + return dest; +} + + +int __fastcall null_strcut(char *string, int maxlen) +{ // limit the string to max length (null & utf-8 strings ready) + int len = (int)strlennull(string); + + if (len < maxlen) + return len; + + len = maxlen; + + if (UTF8_IsValid(string)) // handle utf-8 string + { // find the first byte of possible multi-byte character + while ((string[len] & 0xc0) == 0x80) len--; + } + // simply cut the string + string[len] = '\0'; + + return len; +} + + +void parseServerAddress(char* szServer, WORD* wPort) +{ + int i = 0; + + while (szServer[i] && szServer[i] != ':') i++; + if (szServer[i] == ':') + { // port included + *wPort = atoi(&szServer[i + 1]); + } // otherwise do not change port + + szServer[i] = '\0'; +} + +char *DemangleXml(const char *string, int len) +{ + char *szWork = (char*)SAFE_MALLOC(len+1), *szChar = szWork; + int i; + + for (i=0; i') l += 4; else if (string[i]=='&') l += 5; else if (string[i]=='"') l += 6; else l++; + } + szChar = szWork = (char*)SAFE_MALLOC(l + 1); + for (i = 0; i') + { + *(DWORD*)szChar = ';tg&'; + szChar += 4; + } + else if (string[i]=='&') + { + *(DWORD*)szChar = 'pma&'; + szChar += 4; + *szChar = ';'; + szChar++; + } + else if (string[i]=='"') + { + *(DWORD*)szChar = 'ouq&'; + szChar += 4; + *(WORD*)szChar = ';t'; + szChar += 2; + } + else + { + *szChar = string[i]; + szChar++; + } + } + *szChar = '\0'; + + return szWork; +} + +char *EliminateHtml(const char *string, int len) +{ + char *tmp = (char*)SAFE_MALLOC(len + 1); + int i,j; + BOOL tag = FALSE; + char *res; + + for (i=0,j=0;i", 4) || !_strnicmp(string + i, "
", 5))) + { // insert newline + tmp[j] = '\r'; + j++; + tmp[j] = '\n'; + j++; + } + tag = TRUE; + } + else if (tag && string[i] == '>') + { + tag = FALSE; + } + else if (!tag) + { + tmp[j] = string[i]; + j++; + } + tmp[j] = '\0'; + } + SAFE_FREE((void**)&string); + res = DemangleXml(tmp, strlennull(tmp)); + SAFE_FREE((void**)&tmp); + + return res; +} + +char *ApplyEncoding(const char *string, const char *pszEncoding) +{ // decode encoding to Utf-8 + if (string && pszEncoding) + { // we do only encodings known to icq5.1 // TODO: check if this is enough + if (!_strnicmp(pszEncoding, "utf-8", 5)) + { // it is utf-8 encoded + return null_strdup(string); + } + if (!_strnicmp(pszEncoding, "unicode-2-0", 11)) + { // it is UCS-2 encoded + int wLen = strlennull((WCHAR*)string) + 1; + WCHAR *szStr = (WCHAR*)_alloca(wLen*2); + BYTE *tmp = (BYTE*)string; + + unpackWideString(&tmp, szStr, (WORD)(wLen*2)); + + return make_utf8_string(szStr); + } + if (!_strnicmp(pszEncoding, "iso-8859-1", 10)) + { // we use "Latin I" instead - it does the job + return ansi_to_utf8_codepage(string, 1252); + } + } + if (string) + { // consider it CP_ACP + return ansi_to_utf8(string); + } + + return NULL; +} + +void CIcqProto::ResetSettingsOnListReload() +{ + // Reset a bunch of session specific settings + setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0); + setSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, 0); + setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0); + setSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, 0); + setSettingWord(NULL, "SrvRecordCount", 0); + deleteSetting(NULL, DBSETTING_SERVLIST_UNHANDLED); + + HANDLE hContact = FindFirstContact(); + + while (hContact) + { + // All these values will be restored during the serv-list receive + setSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); + setSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); + setSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0); + setSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0); + deleteSetting(hContact, DBSETTING_SERVLIST_IGNORE); + setSettingByte(hContact, "Auth", 0); + deleteSetting(hContact, DBSETTING_SERVLIST_DATA); + + hContact = FindNextContact(hContact); + } + + FlushSrvGroupsCache(); +} + +void CIcqProto::ResetSettingsOnConnect() +{ + // Reset a bunch of session specific settings + setSettingByte(NULL, "SrvVisibility", 0); + setSettingDword(NULL, "IdleTS", 0); + + HANDLE hContact = FindFirstContact(); + + while (hContact) + { + setSettingDword(hContact, "LogonTS", 0); + setSettingDword(hContact, "IdleTS", 0); + setSettingDword(hContact, "TickTS", 0); + setSettingByte(hContact, "TemporaryVisible", 0); + + // All these values will be restored during the login + if (getContactStatus(hContact) != ID_STATUS_OFFLINE) + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + + hContact = FindNextContact(hContact); + } +} + +void CIcqProto::ResetSettingsOnLoad() +{ + setSettingDword(NULL, "IdleTS", 0); + setSettingDword(NULL, "LogonTS", 0); + + HANDLE hContact = FindFirstContact(); + + while (hContact) + { + setSettingDword(hContact, "LogonTS", 0); + setSettingDword(hContact, "IdleTS", 0); + setSettingDword(hContact, "TickTS", 0); + if (getContactStatus(hContact) != ID_STATUS_OFFLINE) + { + setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); + + deleteSetting(hContact, DBSETTING_XSTATUS_ID); + deleteSetting(hContact, DBSETTING_XSTATUS_NAME); + deleteSetting(hContact, DBSETTING_XSTATUS_MSG); + } + setSettingByte(hContact, "DCStatus", 0); + + hContact = FindNextContact(hContact); + } +} + +int RandRange(int nLow, int nHigh) +{ + return nLow + (int)((nHigh-nLow+1)*rand()/(RAND_MAX+1.0)); +} + + +BOOL IsStringUIN(const char *pszString) +{ + int i; + int nLen = strlennull(pszString); + + if (nLen > 0 && pszString[0] != '0') + { + for (i=0; i '9')) + return FALSE; + + return TRUE; + } + + return FALSE; +} + + +void __cdecl CIcqProto::ProtocolAckThread(icq_ack_args* pArguments) +{ + Sleep(150); + + if (pArguments->nAckResult == ACKRESULT_SUCCESS) + NetLog_Server("Sent fake message ack"); + else if (pArguments->nAckResult == ACKRESULT_FAILED) + NetLog_Server("Message delivery failed"); + + BroadcastAck(pArguments->hContact, pArguments->nAckType, pArguments->nAckResult, pArguments->hSequence, pArguments->pszMessage); + + SAFE_FREE((void**)(char **)&pArguments->pszMessage); + SAFE_FREE((void**)&pArguments); +} + +void CIcqProto::SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage) +{ + icq_ack_args* pArgs = (icq_ack_args*)SAFE_MALLOC(sizeof(icq_ack_args)); // This will be freed in the new thread + pArgs->hContact = hContact; + pArgs->hSequence = (HANDLE)dwCookie; + pArgs->nAckResult = nAckResult; + pArgs->nAckType = nAckType; + pArgs->pszMessage = (LPARAM)null_strdup(pszMessage); + + ForkThread(( IcqThreadFunc )&CIcqProto::ProtocolAckThread, pArgs ); +} + +void CIcqProto::SetCurrentStatus(int nStatus) +{ + int nOldStatus = m_iStatus; + + m_iStatus = nStatus; + BroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, nStatus); +} + + +int CIcqProto::IsMetaInfoChanged(HANDLE hContact) +{ + DBVARIANT infoToken = {DBVT_DELETED}; + int res = 0; + + if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &infoToken)) + { // contact does have info from directory, check if it is not outdated + double dInfoTime = 0; + double dInfoSaved = 0; + + if ((dInfoTime = getSettingDouble(hContact, DBSETTING_METAINFO_TIME, 0)) > 0) + { + if ((dInfoSaved = getSettingDouble(hContact, DBSETTING_METAINFO_SAVED, 0)) > 0) + { + if (dInfoSaved < dInfoTime) + res = 2; // directory info outdated + } + else + res = 1; // directory info not saved at all + } + + ICQFreeVariant(&infoToken); + } + else + { // it cannot be detected if user info was not changed, so use a generic threshold + DBVARIANT infoSaved = {DBVT_DELETED}; + DWORD dwInfoTime = 0; + + if (!getSetting(hContact, DBSETTING_METAINFO_SAVED, &infoSaved)) + { + if (infoSaved.type == DBVT_BLOB && infoSaved.cpbVal == 8) + { + double dwTime = *(double*)infoSaved.pbVal; + + dwInfoTime = (dwTime - 25567) * 86400; + } + else if (infoSaved.type == DBVT_DWORD) + dwInfoTime = infoSaved.dVal; + + ICQFreeVariant(&infoSaved); + + if ((time(NULL) - dwInfoTime) > 14*3600*24) + { + res = 3; // threshold exceeded + } + } + else + res = 4; // no timestamp found + } + + return res; +} + + +void __cdecl CIcqProto::SetStatusNoteThread(void *pDelay) +{ + if (pDelay) + SleepEx((DWORD)pDelay, TRUE); + + cookieMutex->Enter(); + + if (icqOnline() && (setStatusNoteText || setStatusMoodData)) + { // send status note change packets, write status note to database + if (setStatusNoteText) + { // change status note in directory + m_ratesMutex->Enter(); + if (m_rates) + { // rate management + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); + + while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_LIMIT)) + { // we are over rate, need to wait before sending + int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_10); + + m_ratesMutex->Leave(); + cookieMutex->Leave(); +#ifdef _DEBUG + NetLog_Server("Rates: SetStatusNote delayed %dms", nDelay); +#endif + SleepEx(nDelay, TRUE); // do not keep things locked during sleep + cookieMutex->Enter(); + m_ratesMutex->Enter(); + if (!m_rates) // we lost connection when we slept, go away + break; + } + } + m_ratesMutex->Leave(); + + BYTE *pBuffer = NULL; + int cbBuffer = 0; + + ppackTLV(&pBuffer, &cbBuffer, 0x226, strlennull(setStatusNoteText), (BYTE*)setStatusNoteText); + icq_changeUserDirectoryInfoServ(pBuffer, cbBuffer, DIRECTORYREQUEST_UPDATENOTE); + + SAFE_FREE((void**)&pBuffer); + } + + if (setStatusNoteText || setStatusMoodData) + { // change status note and mood in session data + m_ratesMutex->Enter(); + if (m_rates) + { // rate management + WORD wGroup = m_rates->getGroupFromSNAC(ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); + + while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_LIMIT)) + { // we are over rate, need to wait before sending + int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_10); + + m_ratesMutex->Leave(); + cookieMutex->Leave(); +#ifdef _DEBUG + NetLog_Server("Rates: SetStatusNote delayed %dms", nDelay); +#endif + SleepEx(nDelay, TRUE); // do not keep things locked during sleep + cookieMutex->Enter(); + m_ratesMutex->Enter(); + if (!m_rates) // we lost connection when we slept, go away + break; + } + } + m_ratesMutex->Leave(); + + // check if the session data were not updated already + char *szCurrentStatusNote = getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL); + char *szCurrentStatusMood = NULL; + DBVARIANT dbv = {DBVT_DELETED}; + + if (m_bMoodsEnabled && !getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) + szCurrentStatusMood = dbv.pszVal; + + if (!setStatusNoteText && szCurrentStatusNote) + setStatusNoteText = null_strdup(szCurrentStatusNote); + if (m_bMoodsEnabled && !setStatusMoodData && szCurrentStatusMood) + setStatusMoodData = null_strdup(szCurrentStatusMood); + + if (strcmpnull(szCurrentStatusNote, setStatusNoteText) || (m_bMoodsEnabled && strcmpnull(szCurrentStatusMood, setStatusMoodData))) + { + setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, setStatusNoteText); + if (m_bMoodsEnabled) + setSettingString(NULL, DBSETTING_STATUS_MOOD, setStatusMoodData); + + WORD wStatusNoteLen = strlennull(setStatusNoteText); + WORD wStatusMoodLen = m_bMoodsEnabled ? strlennull(setStatusMoodData) : 0; + icq_packet packet; + WORD wDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; + + serverPacketInit(&packet, wDataLen + 14); + packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); + // Change only session data + packWord(&packet, 0x1D); // TLV 1D + packWord(&packet, wDataLen); // TLV length + packWord(&packet, 0x02); // Item Type + if (wStatusNoteLen) + { + packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length + packWord(&packet, wStatusNoteLen); // Text Length + packBuffer(&packet, (LPBYTE)setStatusNoteText, wStatusNoteLen); + packWord(&packet, 0); // Encoding not specified (utf-8 is default) + } + else + packWord(&packet, 0); // Flags + Item Length + packWord(&packet, 0x0E); // Item Type + packWord(&packet, wStatusMoodLen); // Flags + Item Length + if (wStatusMoodLen) + packBuffer(&packet, (LPBYTE)setStatusMoodData, wStatusMoodLen); // Mood + + sendServPacket(&packet); + } + SAFE_FREE(&szCurrentStatusNote); + ICQFreeVariant(&dbv); + } + } + SAFE_FREE(&setStatusNoteText); + SAFE_FREE(&setStatusMoodData); + + cookieMutex->Leave(); +} + + +int CIcqProto::SetStatusNote(const char *szStatusNote, DWORD dwDelay, int bForce) +{ + int bChanged = FALSE; + + // bForce is intended for login sequence - need to call this earlier than icqOnline() + // the process is delayed and icqOnline() is ready when needed inside SetStatusNoteThread() + if (!bForce && !icqOnline()) return bChanged; + + // reuse generic critical section (used for cookies list and object variables locks) + icq_lock l(cookieMutex); + + if (!setStatusNoteText && (!m_bMoodsEnabled || !setStatusMoodData)) + { // check if the status note was changed and if yes, create thread to change it + char *szCurrentStatusNote = getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL); + + if (strcmpnull(szCurrentStatusNote, szStatusNote)) + { // status note was changed + // create thread to change status note on existing server connection + setStatusNoteText = null_strdup(szStatusNote); + + if (dwDelay) + ForkThread(&CIcqProto::SetStatusNoteThread, (void*)dwDelay); + else // we cannot afford any delay, so do not run in separate thread + SetStatusNoteThread(NULL); + + bChanged = TRUE; + } + SAFE_FREE(&szCurrentStatusNote); + } + else + { // only alter status note object with new status note, keep the thread waiting for execution + SAFE_FREE(&setStatusNoteText); + setStatusNoteText = null_strdup(szStatusNote); + + bChanged = TRUE; + } + + return bChanged; +} + + +int CIcqProto::SetStatusMood(const char *szMoodData, DWORD dwDelay) +{ + int bChanged = FALSE; + + if (!icqOnline()) return bChanged; + + // reuse generic critical section (used for cookies list and object variables locks) + icq_lock l(cookieMutex); + + if (!setStatusNoteText && !setStatusMoodData) + { // check if the status mood was changed and if yes, create thread to change it + char *szCurrentStatusMood = NULL; + DBVARIANT dbv = {DBVT_DELETED}; + + if (!getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) + szCurrentStatusMood = dbv.pszVal; + + if (strcmpnull(szCurrentStatusMood, szMoodData)) + { // status mood was changed + // create thread to change status mood on existing server connection + setStatusMoodData = null_strdup(szMoodData); + if (dwDelay) + ForkThread(&CIcqProto::SetStatusNoteThread, (void*)dwDelay); + else // we cannot afford any delay, so do not run in separate thread + SetStatusNoteThread(NULL); + + bChanged = TRUE; + } + ICQFreeVariant(&dbv); + } + else + { // only alter status mood object with new status mood, keep the thread waiting for execution + SAFE_FREE(&setStatusMoodData); + setStatusMoodData = null_strdup(szMoodData); + + bChanged = TRUE; + } + + return bChanged; +} + + +void CIcqProto::writeDbInfoSettingTLVStringUtf(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + oscar_tlv *pTLV = chain->getTLV(wTlv, 1); + + if (pTLV && pTLV->wLen > 0) + { + char *str = (char*)_alloca(pTLV->wLen + 1); + + memcpy(str, pTLV->pData, pTLV->wLen); + str[pTLV->wLen] = '\0'; + setSettingStringUtf(hContact, szSetting, str); + } + else + deleteSetting(hContact, szSetting); +} + + +void CIcqProto::writeDbInfoSettingTLVString(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + oscar_tlv *pTLV = chain->getTLV(wTlv, 1); + + if (pTLV && pTLV->wLen > 0) + { + char *str = (char*)_alloca(pTLV->wLen + 1); + + memcpy(str, pTLV->pData, pTLV->wLen); + str[pTLV->wLen] = '\0'; + setSettingString(hContact, szSetting, str); + } + else + deleteSetting(hContact, szSetting); +} + + +void CIcqProto::writeDbInfoSettingTLVWord(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + int num = chain->getNumber(wTlv, 1); + + if (num > 0) + setSettingWord(hContact, szSetting, num); + else + deleteSetting(hContact, szSetting); +} + + +void CIcqProto::writeDbInfoSettingTLVByte(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + int num = chain->getNumber(wTlv, 1); + + if (num > 0) + setSettingByte(hContact, szSetting, num); + else + deleteSetting(hContact, szSetting); +} + + +void CIcqProto::writeDbInfoSettingTLVDouble(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + double num = chain->getDouble(wTlv, 1); + + if (num > 0) + setSettingDouble(hContact, szSetting, num); + else + deleteSetting(hContact, szSetting); +} + +void CIcqProto::writeDbInfoSettingTLVDate(HANDLE hContact, const char* szSettingYear, const char* szSettingMonth, const char* szSettingDay, oscar_tlv_chain* chain, WORD wTlv) +{ + double time = chain->getDouble(wTlv, 1); + + if (time > 0) + { // date is stored as double with unit equal to a day, incrementing since 1/1/1900 0:00 GMT + SYSTEMTIME sTime = {0}; + if (VariantTimeToSystemTime(time + 2, &sTime)) + { + setSettingWord(hContact, szSettingYear, sTime.wYear); + setSettingByte(hContact, szSettingMonth, (BYTE)sTime.wMonth); + setSettingByte(hContact, szSettingDay, (BYTE)sTime.wDay); + } + else + { + deleteSetting(hContact, szSettingYear); + deleteSetting(hContact, szSettingMonth); + deleteSetting(hContact, szSettingDay); + } + } + else + { + deleteSetting(hContact, szSettingYear); + deleteSetting(hContact, szSettingMonth); + deleteSetting(hContact, szSettingDay); + } +} + + +void CIcqProto::writeDbInfoSettingTLVBlob(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) +{ + oscar_tlv *pTLV = chain->getTLV(wTlv, 1); + + if (pTLV && pTLV->wLen > 0) + setSettingBlob(hContact, szSetting, pTLV->pData, pTLV->wLen); + else + deleteSetting(hContact, szSetting); +} + + +BOOL CIcqProto::writeDbInfoSettingString(HANDLE hContact, const char* szSetting, char** buf, WORD* pwLength) +{ + WORD wLen; + + if (*pwLength < 2) + return FALSE; + + unpackLEWord((LPBYTE*)buf, &wLen); + *pwLength -= 2; + + if (*pwLength < wLen) + return FALSE; + + if ((wLen > 0) && (**buf) && ((*buf)[wLen-1]==0)) // Make sure we have a proper string + { + WORD wCp = getSettingWord(hContact, "InfoCodePage", getSettingWord(hContact, "InfoCP", CP_ACP)); + + if (wCp != CP_ACP) + { + char *szUtf = ansi_to_utf8_codepage(*buf, wCp); + + if (szUtf) + { + setSettingStringUtf(hContact, szSetting, szUtf); + SAFE_FREE((void**)&szUtf); + } + else + setSettingString(hContact, szSetting, *buf); + } + else + setSettingString(hContact, szSetting, *buf); + } + else + deleteSetting(hContact, szSetting); + + *buf += wLen; + *pwLength -= wLen; + + return TRUE; +} + +BOOL CIcqProto::writeDbInfoSettingWord(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength) +{ + WORD wVal; + + + if (*pwLength < 2) + return FALSE; + + unpackLEWord((LPBYTE*)buf, &wVal); + *pwLength -= 2; + + if (wVal != 0) + setSettingWord(hContact, szSetting, wVal); + else + deleteSetting(hContact, szSetting); + + return TRUE; +} + +BOOL CIcqProto::writeDbInfoSettingWordWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength) +{ + WORD wVal; + char sbuf[MAX_PATH]; + char *text; + + if (*pwLength < 2) + return FALSE; + + unpackLEWord((LPBYTE*)buf, &wVal); + *pwLength -= 2; + + text = LookupFieldNameUtf(table, wVal, sbuf, MAX_PATH); + if (text) + setSettingStringUtf(hContact, szSetting, text); + else + deleteSetting(hContact, szSetting); + + return TRUE; +} + +BOOL CIcqProto::writeDbInfoSettingByte(HANDLE hContact, const char *pszSetting, char **buf, WORD* pwLength) +{ + BYTE byVal; + + if (*pwLength < 1) + return FALSE; + + unpackByte((LPBYTE*)buf, &byVal); + *pwLength -= 1; + + if (byVal != 0) + setSettingByte(hContact, pszSetting, byVal); + else + deleteSetting(hContact, pszSetting); + + return TRUE; +} + +BOOL CIcqProto::writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength) +{ + BYTE byVal; + char sbuf[MAX_PATH]; + char *text; + + if (*pwLength < 1) + return FALSE; + + unpackByte((LPBYTE*)buf, &byVal); + *pwLength -= 1; + + text = LookupFieldNameUtf(table, byVal, sbuf, MAX_PATH); + if (text) + setSettingStringUtf(hContact, szSetting, text); + else + deleteSetting(hContact, szSetting); + + return TRUE; +} + +char* time2text(time_t time) +{ + tm *local = localtime(&time); + + if (local) + { + char *str = asctime(local); + str[24] = '\0'; // remove new line + return str; + } + else + return ""; +} + + +BOOL CIcqProto::validateStatusMessageRequest(HANDLE hContact, WORD byMessageType) +{ + // Privacy control + if (getSettingByte(NULL, "StatusMsgReplyCList", 0)) + { + // Don't send statusmessage to unknown contacts + if (hContact == INVALID_HANDLE_VALUE) + return FALSE; + + // Don't send statusmessage to temporary contacts or hidden contacts + if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) || + DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) + return FALSE; + + // Don't send statusmessage to invisible contacts + if (getSettingByte(NULL, "StatusMsgReplyVisible", 0)) + { + WORD wStatus = getContactStatus(hContact); + if (wStatus == ID_STATUS_OFFLINE) + return FALSE; + } + } + + // Dont send messages to people you are hiding from + if (hContact != INVALID_HANDLE_VALUE && + getSettingWord(hContact, "ApparentMode", 0) == ID_STATUS_OFFLINE) + { + return FALSE; + } + + // Dont respond to request for other statuses than your current one + if ((byMessageType == MTYPE_AUTOONLINE && m_iStatus != ID_STATUS_ONLINE) || + (byMessageType == MTYPE_AUTOAWAY && m_iStatus != ID_STATUS_AWAY) || + (byMessageType == MTYPE_AUTOBUSY && m_iStatus != ID_STATUS_OCCUPIED) || + (byMessageType == MTYPE_AUTONA && m_iStatus != ID_STATUS_NA) || + (byMessageType == MTYPE_AUTODND && m_iStatus != ID_STATUS_DND) || + (byMessageType == MTYPE_AUTOFFC && m_iStatus != ID_STATUS_FREECHAT)) + { + return FALSE; + } + + if (hContact != INVALID_HANDLE_VALUE && m_iStatus==ID_STATUS_INVISIBLE && + getSettingWord(hContact, "ApparentMode", 0) != ID_STATUS_ONLINE) + { + if (!getSettingByte(hContact, "TemporaryVisible", 0)) + { // Allow request to temporary visible contacts + return FALSE; + } + } + + // All OK! + return TRUE; +} + + +void __fastcall SAFE_DELETE(MZeroedObject **p) +{ + if (*p) + { + delete *p; + *p = NULL; + } +} + + +void __fastcall SAFE_DELETE(lockable_struct **p) +{ + if (*p) + { + (*p)->_Release(); + *p = NULL; + } +} + + +void __fastcall SAFE_FREE(void** p) +{ + if (*p) + { + free(*p); + *p = NULL; + } +} + + +void* __fastcall SAFE_MALLOC(size_t size) +{ + void* p = NULL; + + if (size) + { + p = malloc(size); + + if (p) + ZeroMemory(p, size); + } + return p; +} + + +void* __fastcall SAFE_REALLOC(void* p, size_t size) +{ + if (p) + { + return realloc(p, size); + } + else + return SAFE_MALLOC(size); +} + + +DWORD ICQWaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds, int bWaitAlways) +{ + DWORD dwResult; + + do { // will get WAIT_IO_COMPLETION for QueueUserAPC(), ignore it unless terminating + dwResult = WaitForSingleObjectEx(hObject, dwMilliseconds, TRUE); + } while (dwResult == WAIT_IO_COMPLETION && (bWaitAlways || !Miranda_Terminated())); + + return dwResult; +} + + +HANDLE NetLib_OpenConnection(HANDLE hUser, const char* szIdent, NETLIBOPENCONNECTION* nloc) +{ + Netlib_Logf(hUser, "%sConnecting to %s:%u", szIdent?szIdent:"", nloc->szHost, nloc->wPort); + + nloc->cbSize = sizeof(NETLIBOPENCONNECTION); + nloc->flags |= NLOCF_V2; + + return (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hUser, (LPARAM)nloc); +} + + +HANDLE CIcqProto::NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP) +{ + NETLIBBIND nlb = {0}; + + nlb.cbSize = sizeof(NETLIBBIND); + nlb.pfnNewConnectionV2 = pFunc; + nlb.pExtra = lParam; + SetLastError(ERROR_INVALID_PARAMETER); // this must be here - NetLib does not set any error :(( + + HANDLE hBoundPort = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hDirectNetlibUser, (LPARAM)&nlb); + + if (pwPort) *pwPort = nlb.wPort; + if (pdwIntIP) *pdwIntIP = nlb.dwInternalIP; + + return hBoundPort; +} + + +void NetLib_CloseConnection(HANDLE *hConnection, int bServerConn) +{ + if (*hConnection) + { + NetLib_SafeCloseHandle(hConnection); + + if (bServerConn) + FreeGatewayIndex(*hConnection); + } +} + + +void NetLib_SafeCloseHandle(HANDLE *hConnection) +{ + if (*hConnection) + { + Netlib_CloseHandle(*hConnection); + *hConnection = NULL; + } +} + + +int CIcqProto::NetLog_Server(const char *fmt,...) +{ + va_list va; + char szText[1024]; + + va_start(va,fmt); + mir_vsnprintf(szText,sizeof(szText),fmt,va); + va_end(va); + return CallService(MS_NETLIB_LOG,(WPARAM)m_hServerNetlibUser,(LPARAM)szText); +} + +int CIcqProto::NetLog_Direct(const char *fmt,...) +{ + va_list va; + char szText[1024]; + + va_start(va,fmt); + mir_vsnprintf(szText,sizeof(szText),fmt,va); + va_end(va); + return CallService(MS_NETLIB_LOG,(WPARAM)m_hDirectNetlibUser,(LPARAM)szText); +} + +int CIcqProto::NetLog_Uni(BOOL bDC, const char *fmt,...) +{ + va_list va; + char szText[1024]; + HANDLE hNetlib; + + va_start(va,fmt); + mir_vsnprintf(szText,sizeof(szText),fmt,va); + va_end(va); + + if (bDC) + hNetlib = m_hDirectNetlibUser; + else + hNetlib = m_hServerNetlibUser; + + return CallService(MS_NETLIB_LOG,(WPARAM)hNetlib,(LPARAM)szText); +} + +int CIcqProto::BroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam) +{ + ACKDATA ack={0}; + + ack.cbSize = sizeof(ACKDATA); + ack.szModule = m_szModuleName; + ack.hContact = hContact; + ack.type = type; + ack.result = result; + ack.hProcess = hProcess; + ack.lParam = lParam; + return CallService(MS_PROTO_BROADCASTACK,0,(LPARAM)&ack); +} + +char* __fastcall ICQTranslateUtf(const char *src) +{ // this takes UTF-8 strings only!!! + char *szRes = NULL; + + if (!strlennull(src)) + { // for the case of empty strings + return null_strdup(src); + } + + { // we can use unicode translate (0.5+) + WCHAR* usrc = make_unicode_string(src); + + szRes = make_utf8_string(TranslateW(usrc)); + + SAFE_FREE((void**)&usrc); + } + return szRes; +} + +char* __fastcall ICQTranslateUtfStatic(const char *src, char *buf, size_t bufsize) +{ // this takes UTF-8 strings only!!! + if (strlennull(src)) + { // we can use unicode translate (0.5+) + WCHAR *usrc = make_unicode_string(src); + + make_utf8_string_static(TranslateW(usrc), buf, bufsize); + + SAFE_FREE((void**)&usrc); + } + else + buf[0] = '\0'; + + return buf; +} + +void CIcqProto::ForkThread( IcqThreadFunc pFunc, void* arg ) +{ + CloseHandle(( HANDLE )mir_forkthreadowner(( pThreadFuncOwner )*( void** )&pFunc, this, arg, NULL )); +} + +HANDLE CIcqProto::ForkThreadEx( IcqThreadFunc pFunc, void* arg, UINT* threadID ) +{ + return ( HANDLE )mir_forkthreadowner(( pThreadFuncOwner )*( void** )&pFunc, this, arg, threadID ); +} + + +char* CIcqProto::GetUserStoredPassword(char *szBuffer, int cbSize) +{ + if (!getSettingStringStatic(NULL, "Password", szBuffer, cbSize)) + { + CallService(MS_DB_CRYPT_DECODESTRING, strlennull(szBuffer) + 1, (LPARAM)szBuffer); + + if (strlennull(szBuffer)) + return szBuffer; + } + return NULL; +} + + +char* CIcqProto::GetUserPassword(BOOL bAlways) +{ + if (m_szPassword[0] != '\0' && (m_bRememberPwd || bAlways)) + return m_szPassword; + + if (GetUserStoredPassword(m_szPassword, sizeof(m_szPassword))) + { + m_bRememberPwd = TRUE; + + return m_szPassword; + } + + return NULL; +} + + +WORD CIcqProto::GetMyStatusFlags() +{ + WORD wFlags = 0; + + // Webaware setting bit flag + if (getSettingByte(NULL, "WebAware", 0)) + wFlags |= STATUS_WEBAWARE; + + // DC setting bit flag + switch (getSettingByte(NULL, "DCType", 0)) + { + case 0: + break; + + case 1: + wFlags |= STATUS_DCCONT; + break; + + case 2: + wFlags |= STATUS_DCAUTH; + break; + + default: + wFlags |= STATUS_DCDISABLED; + break; + } + return wFlags; +} + + +int IsValidRelativePath(const char *filename) +{ + if (strstrnull(filename, "..\\") || strstrnull(filename, "../") || + strstrnull(filename, ":\\") || strstrnull(filename, ":/") || + filename[0] == '\\' || filename[0] == '/') + return 0; // Contains malicious chars, Failure + + return 1; // Success +} + + +const char* ExtractFileName(const char *fullname) +{ + const char *szFileName; + + // already is only filename + if (((szFileName = strrchr(fullname, '\\')) == NULL) && ((szFileName = strrchr(fullname, '/')) == NULL)) + return fullname; + + return szFileName + 1; // skip backslash +} + + +char* FileNameToUtf(const TCHAR *filename) +{ + // reasonable only on NT systems + HINSTANCE hKernel = GetModuleHandle(_T("KERNEL32")); + DWORD (CALLBACK *RealGetLongPathName)(LPCWSTR, LPWSTR, DWORD); + + *(FARPROC *)&RealGetLongPathName = GetProcAddress(hKernel, "GetLongPathNameW"); + + if (RealGetLongPathName) + { // the function is available (it is not on old NT systems) + WCHAR *usFileName = NULL; + int wchars = RealGetLongPathName(filename, usFileName, 0); + usFileName = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); + RealGetLongPathName(filename, usFileName, wchars); + + return make_utf8_string(usFileName); + } + return make_utf8_string(filename); +} + + +int FileAccessUtf(const char *path, int mode) +{ + int size = strlennull(path) + 2; + TCHAR *szPath = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(path, szPath, size)) + return _taccess(szPath, mode); + + return -1; +} + + +int FileStatUtf(const char *path, struct _stati64 *buffer) +{ + int size = strlennull(path) + 2; + TCHAR *szPath = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(path, szPath, size)) + return _tstati64(szPath, buffer); + + return -1; +} + + +int MakeDirUtf(const char *dir) +{ + int wRes = -1; + int size = strlennull(dir) + 2; + TCHAR *szDir = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(dir, szDir, size)) + { // _tmkdir can created only one dir at once + wRes = _tmkdir(szDir); + // check if dir not already existed - return success if yes + if (wRes == -1 && errno == 17 /* EEXIST */) + wRes = 0; + else if (wRes && errno == 2 /* ENOENT */) + { // failed, try one directory less first + char *szLast = (char*)strrchr(dir, '\\'); + if (!szLast) szLast = (char*)strrchr(dir, '/'); + if (szLast) + { + char cOld = *szLast; + + *szLast = '\0'; + if (!MakeDirUtf(dir)) + wRes = _tmkdir(szDir); + + *szLast = cOld; + } + } + } + + return wRes; +} + + +int OpenFileUtf(const char *filename, int oflag, int pmode) +{ + int size = strlennull(filename) + 2; + TCHAR *szFile = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(filename, szFile, size)) + return _topen(szFile, oflag, pmode); + + return -1; +} + + +WCHAR *GetWindowTextUcs(HWND hWnd) +{ + WCHAR *utext; + int nLen = GetWindowTextLengthW(hWnd); + utext = (WCHAR*)SAFE_MALLOC((nLen+2)*sizeof(WCHAR)); + GetWindowTextW(hWnd, utext, nLen + 1); + return utext; +} + + +void SetWindowTextUcs(HWND hWnd, WCHAR *text) +{ + SetWindowTextW(hWnd, text); +} + + +char* GetWindowTextUtf(HWND hWnd) +{ + int nLen = GetWindowTextLength(hWnd); + TCHAR *szText = (TCHAR*)_alloca((nLen + 2) * sizeof(TCHAR)); + + GetWindowText(hWnd, szText, nLen + 1); + + return tchar_to_utf8(szText); +} + + +char* GetDlgItemTextUtf(HWND hwndDlg, int iItem) +{ + return GetWindowTextUtf(GetDlgItem(hwndDlg, iItem)); +} + + +void SetWindowTextUtf(HWND hWnd, const char *szText) +{ + int size = strlennull(szText) + 2; + TCHAR *tszText = (TCHAR*)_alloca(size * sizeof(TCHAR)); + + if (utf8_to_tchar_static(szText, tszText, size)) + SetWindowText(hWnd, tszText); +} + + +void SetDlgItemTextUtf(HWND hwndDlg, int iItem, const char *szText) +{ + SetWindowTextUtf(GetDlgItem(hwndDlg, iItem), szText); +} + + +static int ControlAddStringUtf(HWND ctrl, DWORD msg, const char *szString) +{ + char str[MAX_PATH]; + char *szItem = ICQTranslateUtfStatic(szString, str, MAX_PATH); + int item = -1; + WCHAR *wItem = make_unicode_string(szItem); + item = SendMessage(ctrl, msg, 0, (LPARAM)wItem); + SAFE_FREE((void**)&wItem); + return item; +} + +int ComboBoxAddStringUtf(HWND hCombo, const char *szString, DWORD data) +{ + int item = ControlAddStringUtf(hCombo, CB_ADDSTRING, szString); + SendMessage(hCombo, CB_SETITEMDATA, item, data); + + return item; +} + +int ListBoxAddStringUtf(HWND hList, const char *szString) +{ + return ControlAddStringUtf(hList, LB_ADDSTRING, szString); +} + +int MessageBoxUtf(HWND hWnd, const char *szText, const char *szCaption, UINT uType) +{ + int res; + char str[1024]; + char cap[MAX_PATH]; + WCHAR *text = make_unicode_string(ICQTranslateUtfStatic(szText, str, 1024)); + WCHAR *caption = make_unicode_string(ICQTranslateUtfStatic(szCaption, cap, MAX_PATH)); + res = MessageBoxW(hWnd, text, caption, uType); + SAFE_FREE((void**)&caption); + SAFE_FREE((void**)&text); + return res; +} + +char* CIcqProto::ConvertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg) +{ // this takes utf-8 encoded message + WORD wCP = getSettingWord(hContact, "CodePage", m_wAnsiCodepage); + char* szAnsi = NULL; + + if (wCP != CP_ACP) // convert to proper codepage + if (!utf8_decode_codepage(szMsg, &szAnsi, wCP)) + return NULL; + + return szAnsi; +} + +// just broadcast generic send error with dummy cookie and return that cookie +DWORD CIcqProto::ReportGenericSendError(HANDLE hContact, int nType, const char* szErrorMsg) +{ + DWORD dwCookie = GenerateCookie(0); + SendProtoAck(hContact, dwCookie, ACKRESULT_FAILED, nType, Translate(szErrorMsg)); + return dwCookie; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::CreateProtoService(const char* szService, IcqServiceFunc serviceProc) +{ + char temp[MAX_PATH*2]; + + null_snprintf(temp, sizeof(temp), "%s%s", m_szModuleName, szService); + CreateServiceFunctionObj( temp, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this ); +} + +void CIcqProto::CreateProtoServiceParam(const char* szService, IcqServiceFuncParam serviceProc, LPARAM lParam) +{ + char temp[MAX_PATH*2]; + + null_snprintf(temp, sizeof(temp), "%s%s", m_szModuleName, szService); + CreateServiceFunctionObjParam( temp, ( MIRANDASERVICEOBJPARAM )*( void** )&serviceProc, this, lParam ); +} + + +HANDLE CIcqProto::HookProtoEvent(const char* szEvent, IcqEventFunc pFunc) +{ + return ::HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&pFunc, this); +} + + +HANDLE CIcqProto::CreateProtoEvent(const char* szEvent) +{ + char str[MAX_PATH + 32]; + strcpy(str, m_szModuleName); + strcat(str, szEvent); + return CreateHookableEvent(str); +} diff --git a/protocols/IcqOscarJ/src/utilities.h b/protocols/IcqOscarJ/src/utilities.h new file mode 100644 index 0000000000..962ecce15f --- /dev/null +++ b/protocols/IcqOscarJ/src/utilities.h @@ -0,0 +1,188 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Describe me here please... +// +// ----------------------------------------------------------------------------- +#ifndef __UTILITIES_H +#define __UTILITIES_H + + +struct icq_ack_args +{ + HANDLE hContact; + int nAckType; + int nAckResult; + HANDLE hSequence; + LPARAM pszMessage; +}; + +struct icq_contacts_cache +{ + HANDLE hContact; + DWORD dwUin; + const char *szUid; +}; + + +/*---------* Functions *---------------*/ + +void MoveDlgItem(HWND hwndDlg, int iItem, int left, int top, int width, int height); +void EnableDlgItem(HWND hwndDlg, UINT control, int state); +void ShowDlgItem(HWND hwndDlg, UINT control, int state); +void icq_EnableMultipleControls(HWND hwndDlg, const UINT* controls, int cControls, int state); +void icq_ShowMultipleControls(HWND hwndDlg, const UINT* controls, int cControls, int state); +int IcqStatusToMiranda(WORD wStatus); +WORD MirandaStatusToIcq(int nStatus); +int MirandaStatusToSupported(int nMirandaStatus); +char *MirandaStatusToString(int); +char *MirandaStatusToStringUtf(int); + +int AwayMsgTypeToStatus(int nMsgType); + +void SetGatewayIndex(HANDLE hConn, DWORD dwIndex); +DWORD GetGatewayIndex(HANDLE hConn); +void FreeGatewayIndex(HANDLE hConn); + +char *NickFromHandle(HANDLE hContact); +char *NickFromHandleUtf(HANDLE hContact); +char *strUID(DWORD dwUIN, char *pszUID); + +int __fastcall strlennull(const char *string); +int __fastcall strcmpnull(const char *str1, const char *str2); +int __fastcall stricmpnull(const char *str1, const char *str2); +char* __fastcall strstrnull(const char *str, const char *substr); +int null_snprintf(char *buffer, size_t count, const char *fmt, ...); +char* __fastcall null_strdup(const char *string); +char* __fastcall null_strcpy(char *dest, const char *src, size_t maxlen); +int __fastcall null_strcut(char *string, int maxlen); + +int __fastcall strlennull(const WCHAR *string); +int null_snprintf(WCHAR *buffer, size_t count, const WCHAR *fmt, ...); +WCHAR* __fastcall null_strdup(const WCHAR *string); +WCHAR* __fastcall null_strcpy(WCHAR *dest, const WCHAR *src, size_t maxlen); + +void parseServerAddress(char *szServer, WORD* wPort); + +char *DemangleXml(const char *string, int len); +char *MangleXml(const char *string, int len); +char *EliminateHtml(const char *string, int len); +char *ApplyEncoding(const char *string, const char *pszEncoding); + +int RandRange(int nLow, int nHigh); + +BOOL IsStringUIN(const char *pszString); + +char* time2text(time_t time); + +BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType); + +void __fastcall SAFE_FREE(void** p); +void* __fastcall SAFE_MALLOC(size_t size); +void* __fastcall SAFE_REALLOC(void* p, size_t size); + +__inline static void SAFE_FREE(char** str) { SAFE_FREE((void**)str); } +__inline static void SAFE_FREE(WCHAR** str) { SAFE_FREE((void**)str); } + +struct lockable_struct: public MZeroedObject +{ +private: + int nLockCount; +public: + lockable_struct() { _Lock(); }; + virtual ~lockable_struct() {}; + + void _Lock() { nLockCount++; }; + void _Release() { nLockCount--; if (!nLockCount) delete this; }; + + int getLockCount() { return nLockCount; }; +}; + +void __fastcall SAFE_DELETE(MZeroedObject **p); +void __fastcall SAFE_DELETE(lockable_struct **p); + +DWORD ICQWaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds, int bWaitAlways = FALSE); + + +struct icq_critical_section: public lockable_struct +{ +private: + HANDLE hMutex; + +public: + icq_critical_section() { hMutex = CreateMutex(NULL, FALSE, NULL); } + ~icq_critical_section() { CloseHandle(hMutex); } + + void Enter(void) { ICQWaitForSingleObject(hMutex, INFINITE, TRUE); } + void Leave(void) { ReleaseMutex(hMutex); } +}; + +__inline static void SAFE_DELETE(icq_critical_section **p) { SAFE_DELETE((lockable_struct**)p); } + +struct icq_lock +{ +private: + icq_critical_section *pMutex; +public: + icq_lock(icq_critical_section *mutex) { pMutex = mutex; pMutex->Enter(); }; + ~icq_lock() { pMutex->Leave(); pMutex = NULL; }; +}; + + +HANDLE NetLib_OpenConnection(HANDLE hUser, const char* szIdent, NETLIBOPENCONNECTION* nloc); +void NetLib_CloseConnection(HANDLE *hConnection, int bServerConn); +void NetLib_SafeCloseHandle(HANDLE *hConnection); + +char* __fastcall ICQTranslateUtf(const char *src); +char* __fastcall ICQTranslateUtfStatic(const char *src, char *buf, size_t bufsize); + +WORD GetMyStatusFlags(); + +/* Unicode FS utility functions */ + +int IsValidRelativePath(const char *filename); +const char* ExtractFileName(const char *fullname); +char* FileNameToUtf(const TCHAR *filename); + +int FileAccessUtf(const char *path, int mode); +int FileStatUtf(const char *path, struct _stati64 *buffer); +int MakeDirUtf(const char *dir); +int OpenFileUtf(const char *filename, int oflag, int pmode); + +/* Unicode UI utility functions */ +WCHAR* GetWindowTextUcs(HWND hWnd); +void SetWindowTextUcs(HWND hWnd, WCHAR *text); +char *GetWindowTextUtf(HWND hWnd); +char *GetDlgItemTextUtf(HWND hwndDlg, int iItem); +void SetWindowTextUtf(HWND hWnd, const char *szText); +void SetDlgItemTextUtf(HWND hwndDlg, int iItem, const char *szText); + +int ComboBoxAddStringUtf(HWND hCombo, const char *szString, DWORD data); +int ListBoxAddStringUtf(HWND hList, const char *szString); + +int MessageBoxUtf(HWND hWnd, const char *szText, const char *szCaption, UINT uType); + +#endif /* __UTILITIES_H */ diff --git a/protocols/IcqOscarJ/src/version.h b/protocols/IcqOscarJ/src/version.h new file mode 100644 index 0000000000..0231d7a7ea --- /dev/null +++ b/protocols/IcqOscarJ/src/version.h @@ -0,0 +1,3 @@ +#define __FILEVERSION_STRING 0,11,0,1 +#define __VERSION_STRING "0.11.0.1" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 11, 0, 1) diff --git a/protocols/IcqOscarJ/stdpackets.cpp b/protocols/IcqOscarJ/stdpackets.cpp deleted file mode 100644 index 3bc9502560..0000000000 --- a/protocols/IcqOscarJ/stdpackets.cpp +++ /dev/null @@ -1,1895 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - -extern const int moodXStatus[]; - -/***************************************************************************** -* -* Some handy extra pack functions for basic message type headers -* -*/ - -// This is the part of the message header that is common for all message channels -static void packServMsgSendHeader(icq_packet *p, DWORD dwSequence, DWORD dwID1, DWORD dwID2, DWORD dwUin, const char *szUID, WORD wFmt, WORD wLen) -{ - serverPacketInit(p, (WORD)(21 + getUIDLen(dwUin, szUID) + wLen)); - packFNACHeader(p, ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, 0, dwSequence | ICQ_MSG_SRV_SEND<<0x10); - packLEDWord(p, dwID1); // Msg ID part 1 - packLEDWord(p, dwID2); // Msg ID part 2 - packWord(p, wFmt); // Message channel - packUID(p, dwUin, szUID); // User ID -} - - -static void packServIcqExtensionHeader(icq_packet *p, CIcqProto *ppro, WORD wLen, WORD wType, WORD wSeq, WORD wCmd = ICQ_META_CLI_REQUEST) -{ - serverPacketInit(p, (WORD)(24 + wLen)); - packFNACHeader(p, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST, 0, wSeq | (wCmd<<0x10)); - packWord(p, 0x01); // TLV type 1 - packWord(p, (WORD)(10 + wLen)); // TLV len - packLEWord(p, (WORD)(8 + wLen)); // Data chunk size (TLV.Length-2) - packLEDWord(p, ppro->m_dwLocalUIN); // My UIN - packLEWord(p, wType); // Request type - packWord(p, wSeq); -} - - -static void packServIcqDirectoryHeader(icq_packet *p, CIcqProto *ppro, WORD wLen, WORD wType, WORD wCommand, WORD wSeq, WORD wSubCommand = ICQ_META_CLI_REQUEST) -{ - packServIcqExtensionHeader(p, ppro, wLen + 0x1E, CLI_META_INFO_REQ, wSeq, wSubCommand); - packLEWord(p, wType); - packLEWord(p, wLen + 0x1A); - packFNACHeader(p, 0x5b9, wCommand, 0, 0, 2); - packWord(p, 0); - packWord(p, (WORD)GetACP()); - packDWord(p, 2); -} - - -static void packServTLV5HeaderBasic(icq_packet *p, WORD wLen, DWORD ID1, DWORD ID2, WORD wCommand, const plugin_guid pGuid) -{ - // TLV(5) header - packWord(p, 0x05); // Type - packWord(p, (WORD)(26 + wLen)); // Len - // TLV(5) data - packWord(p, wCommand); // Command - packLEDWord(p, ID1); // msgid1 - packLEDWord(p, ID2); // msgid2 - packGUID(p, pGuid); // capabilities (4 dwords) -} - - -static void packServTLV5HeaderMsg(icq_packet *p, WORD wLen, DWORD ID1, DWORD ID2, WORD wAckType) -{ - packServTLV5HeaderBasic(p, (WORD)(wLen + 10), ID1, ID2, 0, MCAP_SRV_RELAY_FMT); - - packTLVWord(p, 0x0A, wAckType); // TLV: 0x0A Acktype: 1 for normal, 2 for ack - packDWord(p, 0x000F0000); // TLV: 0x0F empty -} - - -static void packServTLV2711Header(icq_packet *packet, WORD wCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD X1, WORD X2, int nLen) -{ - packWord(packet, 0x2711); // Type - packWord(packet, (WORD)(51 + nLen)); // Len - // TLV(0x2711) data - packLEWord(packet, 0x1B); // Unknown - packByte(packet, (BYTE)wVersion); // Client (message) version - packGUID(packet, PSIG_MESSAGE); - packDWord(packet, CLIENTFEATURES); - packDWord(packet, DC_TYPE); - packLEWord(packet, wCookie); // Reference cookie - packLEWord(packet, 0x0E); // Unknown - packLEWord(packet, wCookie); // Reference cookie again - packDWord(packet, 0); // Unknown (12 bytes) - packDWord(packet, 0); // - - packDWord(packet, 0); // - - packByte(packet, bMsgType); // Message type - packByte(packet, bMsgFlags); // Flags - packLEWord(packet, X1); // Accepted - packWord(packet, X2); // Unknown, priority? -} - - -static void packServDCInfo(icq_packet *p, CIcqProto* ppro, BOOL bEmpty) -{ - packTLVDWord(p, 0x03, bEmpty ? 0 : ppro->getSettingDword(NULL, "RealIP", 0)); // TLV: 0x03 DWORD IP - packTLVWord(p, 0x05, (WORD)(bEmpty ? 0 : ppro->wListenPort)); // TLV: 0x05 Listen port -} - - -static void packServChannel2Header(icq_packet *p, CIcqProto* ppro, DWORD dwUin, WORD wLen, DWORD dwID1, DWORD dwID2, DWORD dwCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD wPriority, int isAck, int includeDcInfo, BYTE bRequestServerAck) -{ - packServMsgSendHeader(p, dwCookie, dwID1, dwID2, dwUin, NULL, 0x0002, (WORD)(wLen + 95 + (bRequestServerAck?4:0) + (includeDcInfo?14:0))); - - packWord(p, 0x05); // TLV type - packWord(p, (WORD)(wLen + 91 + (includeDcInfo?14:0))); /* TLV len */ - packWord(p, (WORD)(isAck ? 2: 0)); /* not aborting anything */ - packLEDWord(p, dwID1); // Msg ID part 1 - packLEDWord(p, dwID2); // Msg ID part 2 - packGUID(p, MCAP_SRV_RELAY_FMT); /* capability (4 dwords) */ - packDWord(p, 0x000A0002); // TLV: 0x0A WORD: 1 for normal, 2 for ack - packWord(p, (WORD)(isAck ? 2 : 1)); - - if (includeDcInfo) - packServDCInfo(p, ppro, FALSE); - - packDWord(p, 0x000F0000); // TLV: 0x0F empty - - packServTLV2711Header(p, (WORD)dwCookie, wVersion, bMsgType, bMsgFlags, (WORD)MirandaStatusToIcq(ppro->m_iStatus), wPriority, wLen); -} - - -static void packServAdvancedReply(icq_packet *p, DWORD dwUin, const char *szUid, DWORD dwID1, DWORD dwID2, WORD wCookie, WORD wLen) -{ - serverPacketInit(p, (WORD)(getUIDLen(dwUin, szUid) + 23 + wLen)); - packFNACHeader(p, ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE, 0, ICQ_MSG_RESPONSE<<0x10 | (wCookie & 0x7FFF)); - packLEDWord(p, dwID1); // Msg ID part 1 - packLEDWord(p, dwID2); // Msg ID part 2 - packWord(p, 0x02); // Channel - packUID(p, dwUin, szUid); // Contact UID - packWord(p, 0x03); // Msg specific formating -} - - -static void packServAdvancedMsgReply(icq_packet *p, DWORD dwUin, const char *szUid, DWORD dwID1, DWORD dwID2, WORD wCookie, WORD wVersion, BYTE bMsgType, BYTE bMsgFlags, WORD wLen) -{ - packServAdvancedReply(p, dwUin, szUid, dwID1, dwID2, wCookie, (WORD)(wLen + 51)); - - packLEWord(p, 0x1B); // Unknown - packByte(p, (BYTE)wVersion); // Protocol version - packGUID(p, PSIG_MESSAGE); - packDWord(p, CLIENTFEATURES); - packDWord(p, DC_TYPE); - packLEWord(p, wCookie); // Reference - packLEWord(p, 0x0E); // Unknown - packLEWord(p, wCookie); // Reference - packDWord(p, 0); // Unknown - packDWord(p, 0); // Unknown - packDWord(p, 0); // Unknown - packByte(p, bMsgType); // Message type - packByte(p, bMsgFlags); // Message flags - packLEWord(p, 0); // Ack status code ( 0 = accepted, this is hardcoded because - // it is only used this way yet) - packLEWord(p, 0); // Unused priority field -} - - -void packMsgColorInfo(icq_packet *packet) -{ // TODO: make configurable - packLEDWord(packet, 0x00000000); // Foreground colour - packLEDWord(packet, 0x00FFFFFF); // Background colour -} - - -void packEmptyMsg(icq_packet *packet) -{ - packLEWord(packet, 1); - packByte(packet, 0); -} - -/***************************************************************************** -* -* Functions to actually send the stuff -* -*/ - -void CIcqProto::icq_sendCloseConnection() -{ - icq_packet packet; - - packet.wLen = 0; - write_flap(&packet, ICQ_CLOSE_CHAN); - sendServPacket(&packet); -} - - -void CIcqProto::icq_requestnewfamily(WORD wFamily, void (CIcqProto::*familyhandler)(HANDLE hConn, char* cookie, WORD cookieLen)) -{ - icq_packet packet; - cookie_family_request *request; - int bRequestSSL = m_bSecureConnection && (wFamily != ICQ_AVATAR_FAMILY); // Avatar servers does not support SSL - - request = (cookie_family_request*)SAFE_MALLOC(sizeof(cookie_family_request)); - request->wFamily = wFamily; - request->familyHandler = familyhandler; - - DWORD dwCookie = AllocateCookie(CKT_SERVICEREQUEST, ICQ_CLIENT_NEW_SERVICE, 0, request); // generate and alloc cookie - - serverPacketInit(&packet, 12 + (bRequestSSL ? 4 : 0)); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_NEW_SERVICE, 0, dwCookie); - packWord(&packet, wFamily); - if (bRequestSSL) - packDWord(&packet, 0x008C0000); // use SSL - - sendServPacket(&packet); -} - - -void CIcqProto::icq_setidle(int bAllow) -{ - icq_packet packet; - - if (bAllow != m_bIdleAllow) - { - /* SNAC 1,11 */ - serverPacketInit(&packet, 14); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE); - if (bAllow==1) - packDWord(&packet, 0x0000003C); - else - packDWord(&packet, 0x00000000); - - m_bIdleAllow = bAllow; - sendServPacket(&packet); - } -} - - -void CIcqProto::icq_setstatus(WORD wStatus, const char *szStatusNote) -{ - icq_packet packet; - char *szCurrentStatusNote = szStatusNote ? getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL) : NULL; - WORD wStatusMoodLen = 0, wStatusNoteLen = 0, wSessionDataLen = 0; - char *szMoodData = NULL; - - if (szStatusNote && strcmpnull(szCurrentStatusNote, szStatusNote)) - { // status note was changed, update now - DBVARIANT dbv = {DBVT_DELETED}; - - if (m_bMoodsEnabled && !getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) - szMoodData = null_strdup(dbv.pszVal); - - ICQFreeVariant(&dbv); - - wStatusNoteLen = strlennull(szStatusNote); - wStatusMoodLen = strlennull(szMoodData); - - wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; - } - SAFE_FREE(&szCurrentStatusNote); - - // Pack data in packet - serverPacketInit(&packet, (WORD)(18 + (wSessionDataLen ? wSessionDataLen + 4 : 0))); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); - packWord(&packet, 0x06); // TLV 6 - packWord(&packet, 0x04); // TLV length - packWord(&packet, GetMyStatusFlags()); // Status flags - packWord(&packet, wStatus); // Status - if (wSessionDataLen) - { // Pack session data - packWord(&packet, 0x1D); // TLV 1D - packWord(&packet, wSessionDataLen); // TLV length - packWord(&packet, 0x02); // Item Type - if (wStatusNoteLen) - { - packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length - packWord(&packet, wStatusNoteLen); // Text Length - packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen); - packWord(&packet, 0); // Encoding not specified (utf-8 is default) - } - else - packWord(&packet, 0); // Flags + Item Length - packWord(&packet, 0x0E); // Item Type - packWord(&packet, wStatusMoodLen); // Flags + Item Length - if (wStatusMoodLen) - packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood - - // Save current status note - setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, szStatusNote); - } - // Release memory - SAFE_FREE(&szMoodData); - - // Send packet - sendServPacket(&packet); -} - - -DWORD CIcqProto::icq_SendChannel1Message(DWORD dwUin, char *szUID, HANDLE hContact, char *pszText, cookie_message_data *pCookieData) -{ - icq_packet packet; - WORD wPacketLength; - - WORD wMessageLen = strlennull(pszText); - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - if (pCookieData->nAckType == ACKTYPE_SERVER) - wPacketLength = 25; - else - wPacketLength = 21; - - // Pack the standard header - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 1, (WORD)(wPacketLength + wMessageLen)); - - // Pack first TLV - packWord(&packet, 0x0002); // TLV(2) - packWord(&packet, (WORD)(wMessageLen + 13)); // TLV len - - // Pack client features - packWord(&packet, 0x0501); // TLV(501) - packWord(&packet, 0x0001); // TLV len - packByte(&packet, 0x1); // Features, meaning unknown, duplicated from ICQ Lite - - // Pack text TLV - packWord(&packet, 0x0101); // TLV(2) - packWord(&packet, (WORD)(wMessageLen + 4)); // TLV len - packWord(&packet, 0x0003); // Message charset number, again copied from ICQ Lite - packWord(&packet, 0x0000); // Message charset subset - packBuffer(&packet, (LPBYTE)pszText, (WORD)(wMessageLen)); // Message text - - // Pack request server ack TLV - if (pCookieData->nAckType == ACKTYPE_SERVER) - packDWord(&packet, 0x00030000); // TLV(3) - - // Pack store on server TLV - packDWord(&packet, 0x00060000); // TLV(6) - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_SendChannel1MessageW(DWORD dwUin, char *szUID, HANDLE hContact, WCHAR *pszText, cookie_message_data *pCookieData) -{ - icq_packet packet; - WORD wMessageLen; - DWORD dwCookie; - WORD wPacketLength; - WCHAR *ppText; - int i; - - wMessageLen = strlennull(pszText) * (int)sizeof(WCHAR); - dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - if (pCookieData->nAckType == ACKTYPE_SERVER) - wPacketLength = 26; - else - wPacketLength = 22; - - // Pack the standard header - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 1, (WORD)(wPacketLength + wMessageLen)); - - // Pack first TLV - packWord(&packet, 0x0002); // TLV(2) - packWord(&packet, (WORD)(wMessageLen + 14)); // TLV len - - // Pack client features - packWord(&packet, 0x0501); // TLV(501) - packWord(&packet, 0x0002); // TLV len - packWord(&packet, 0x0106); // Features, meaning unknown, duplicated from ICQ 2003b - - // Pack text TLV - packWord(&packet, 0x0101); // TLV(2) - packWord(&packet, (WORD)(wMessageLen + 4)); // TLV len - packWord(&packet, 0x0002); // Message charset number, again copied from ICQ 2003b - packWord(&packet, 0x0000); // Message charset subset - ppText = pszText; // we must convert the widestring - for (i = 0; inAckType == ACKTYPE_SERVER) - packDWord(&packet, 0x00030000); // TLV(3) - - // Pack store on server TLV - packDWord(&packet, 0x00060000); // TLV(6) - - sendServPacket(&packet); - return dwCookie; -} - - -DWORD CIcqProto::icq_SendChannel2Message(DWORD dwUin, HANDLE hContact, const char *szMessage, int nBodyLen, WORD wPriority, cookie_message_data *pCookieData, char *szCap) -{ - icq_packet packet; - - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - // Pack the standard header - packServChannel2Header(&packet, this, dwUin, (WORD)(nBodyLen + (szCap ? 53:11)), pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwCookie, ICQ_VERSION, (BYTE)pCookieData->bMessageType, 0, - wPriority, 0, 0, (BYTE)((pCookieData->nAckType == ACKTYPE_SERVER)?1:0)); - - packLEWord(&packet, (WORD)(nBodyLen+1)); // Length of message - packBuffer(&packet, (LPBYTE)szMessage, (WORD)(nBodyLen+1)); // Message - packMsgColorInfo(&packet); - - if (szCap) - { - packLEDWord(&packet, 0x00000026); // length of GUID - packBuffer(&packet, (LPBYTE)szCap, 0x26); // UTF-8 GUID - } - - // Pack request server ack TLV - if (pCookieData->nAckType == ACKTYPE_SERVER) - packDWord(&packet, 0x00030000); // TLV(3) - - sendServPacket(&packet); - return dwCookie; -} - - -DWORD CIcqProto::icq_SendChannel2Contacts(DWORD dwUin, char *szUid, HANDLE hContact, const char *pData, WORD wDataLen, const char *pNames, WORD wNamesLen, cookie_message_data *pCookieData) -{ - icq_packet packet; - - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, pCookieData); - - WORD wPacketLength = wDataLen + wNamesLen + 0x12; - - // Pack the standard header - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUid, 2, (WORD)(wPacketLength + ((pCookieData->nAckType == ACKTYPE_SERVER)?0x22:0x1E))); - - packServTLV5HeaderBasic(&packet, wPacketLength, pCookieData->dwMsgID1, pCookieData->dwMsgID2, 0, MCAP_CONTACTS); - - packTLVWord(&packet, 0x0A, 1); // TLV: 0x0A Acktype: 1 for normal, 2 for ack - packDWord(&packet, 0x000F0000); // TLV: 0x0F empty - packTLV(&packet, 0x2711, wDataLen, (LPBYTE)pData); // TLV: 0x2711 Content (Contact UIDs) - packTLV(&packet, 0x2712, wNamesLen, (LPBYTE)pNames);// TLV: 0x2712 Extended Content (Contact NickNames) - - // Pack request ack TLV - if (pCookieData->nAckType == ACKTYPE_SERVER) - { - packDWord(&packet, 0x00030000); // TLV(3) - } - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_SendChannel4Message(DWORD dwUin, HANDLE hContact, BYTE bMsgType, WORD wMsgLen, const char *szMsg, cookie_message_data *pCookieData) -{ - icq_packet packet; - WORD wPacketLength; - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - if (pCookieData->nAckType == ACKTYPE_SERVER) - wPacketLength = 28; - else - wPacketLength = 24; - - // Pack the standard header - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, NULL, 4, (WORD)(wPacketLength + wMsgLen)); - - // Pack first TLV - packWord(&packet, 0x05); // TLV(5) - packWord(&packet, (WORD)(wMsgLen + 16)); // TLV len - packLEDWord(&packet, m_dwLocalUIN); // My UIN - packByte(&packet, bMsgType); // Message type - packByte(&packet, 0); // Message flags - packLEWord(&packet, wMsgLen); // Message length - packBuffer(&packet, (LPBYTE)szMsg, wMsgLen); // Message text - packMsgColorInfo(&packet); - - // Pack request ack TLV - if (pCookieData->nAckType == ACKTYPE_SERVER) - { - packDWord(&packet, 0x00030000); // TLV(3) - } - - // Pack store on server TLV - packDWord(&packet, 0x00060000); // TLV(6) - - sendServPacket(&packet); - - return dwCookie; -} - - -void CIcqProto::sendOwnerInfoRequest(void) -{ - icq_packet packet; - - cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); - pCookieData->bRequestType = DIRECTORYREQUEST_INFOOWNER; - - DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); - WORD wDataLen = getUINLen(m_dwLocalUIN) + 4; - - packServIcqDirectoryHeader(&packet, this, wDataLen + 8, META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); - packWord(&packet, 0x03); // with interests (ICQ6 uses 2 at login) - packDWord(&packet, 0x01); - packWord(&packet, wDataLen); - - packTLVUID(&packet, 0x32, m_dwLocalUIN, NULL); - - sendServPacket(&packet); -} - - -DWORD CIcqProto::sendUserInfoMultiRequest(BYTE *pRequestData, WORD wDataLen, int nItems) -{ - icq_packet packet; - - cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); - if (!pCookieData) return 0; // Failure - pCookieData->bRequestType = DIRECTORYREQUEST_INFOMULTI; - - DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); - - packServIcqDirectoryHeader(&packet, this, wDataLen + 2, META_DIRECTORY_QUERY, DIRECTORY_QUERY_MULTI_INFO, (WORD)dwCookie); - packWord(&packet, nItems); - packBuffer(&packet, pRequestData, wDataLen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendGetInfoServ(HANDLE hContact, DWORD dwUin, int bManual) -{ - icq_packet packet; - DWORD dwCookie = 0; - - if (IsServerOverRate(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST, bManual ? RML_IDLE_10 : RML_IDLE_50)) - return dwCookie; - - DBVARIANT infoToken = {DBVT_DELETED}; - BYTE *pToken = NULL; - WORD cbToken = 0; - - if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &infoToken)) - { // retrieve user details using privacy token - cbToken = infoToken.cpbVal; - pToken = (BYTE*)_alloca(cbToken); - memcpy(pToken, infoToken.pbVal, cbToken); - - ICQFreeVariant(&infoToken); - } - - cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); - pCookieData->bRequestType = DIRECTORYREQUEST_INFOUSER; - - dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, hContact, (void*)pCookieData); - WORD wDataLen = cbToken + getUINLen(dwUin) + (cbToken ? 8 : 4); - - packServIcqDirectoryHeader(&packet, this, wDataLen + 8, META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); - packWord(&packet, 0x03); - packDWord(&packet, 1); - packWord(&packet, wDataLen); - if (pToken) - packTLV(&packet, 0x3C, cbToken, pToken); - packTLVUID(&packet, 0x32, dwUin, NULL); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendGetAimProfileServ(HANDLE hContact, char* szUid) -{ - icq_packet packet; - BYTE bUIDlen = strlennull(szUid); - - if (IsServerOverRate(ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, RML_IDLE_10)) - return 0; - - cookie_fam15_data *pCookieData = (cookie_fam15_data*)SAFE_MALLOC(sizeof(cookie_fam15_data)); - pCookieData->bRequestType = REQUESTTYPE_PROFILE; - - DWORD dwCookie = AllocateCookie(CKT_FAMILYSPECIAL, ICQ_LOCATION_REQ_USER_INFO, hContact, (void*)pCookieData); - - serverPacketInit(&packet, (WORD)(13 + bUIDlen)); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie); - packWord(&packet, 0x01); // request profile info - packByte(&packet, bUIDlen); - packBuffer(&packet, (LPBYTE)szUid, bUIDlen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendGetAwayMsgServ(HANDLE hContact, DWORD dwUin, int type, WORD wVersion) -{ - icq_packet packet; - - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_IDLE_30)) - return 0; - - cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - packServChannel2Header(&packet, this, dwUin, 3, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwCookie, wVersion, (BYTE)type, 3, 1, 0, 0, 0); - packEmptyMsg(&packet); // Message - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendGetAwayMsgServExt(HANDLE hContact, DWORD dwUin, char *szUID, int type, WORD wVersion) -{ - icq_packet packet; - - if (IsServerOverRate(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND, RML_IDLE_30)) - return 0; - - cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (BYTE)type); - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, szUID, 2, 122 + getPluginTypeIdLen(type)); - - // TLV(5) header - packServTLV5HeaderMsg(&packet, 82 + getPluginTypeIdLen(type), pCookieData->dwMsgID1, pCookieData->dwMsgID2, 1); - - // TLV(0x2711) header - packServTLV2711Header(&packet, (WORD)dwCookie, wVersion, MTYPE_PLUGIN, 0, 0, 0x100, 27 + getPluginTypeIdLen(type)); - // - packLEWord(&packet, 0); // Empty msg - - packPluginTypeId(&packet, type); - - packLEDWord(&packet, 0x15); - packLEDWord(&packet, 0); - packLEDWord(&packet, 0x0D); - packBuffer(&packet, (LPBYTE)"text/x-aolrtf", 0x0D); - - // Send the monster - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendGetAimAwayMsgServ(HANDLE hContact, char *szUID, int type) -{ - icq_packet packet; - BYTE bUIDlen = strlennull(szUID); - - cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_AUTOAWAY, (byte)type); - DWORD dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData); - - serverPacketInit(&packet, (WORD)(13 + bUIDlen)); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, dwCookie); - packWord(&packet, 0x03); - packUID(&packet, 0, szUID); - - sendServPacket(&packet); - - return dwCookie; -} - - -void CIcqProto::icq_sendSetAimAwayMsgServ(const char *szMsg) -{ - icq_packet packet; - WORD wMsgLen = strlennull(szMsg); - - DWORD dwCookie = GenerateCookie(ICQ_LOCATION_SET_USER_INFO); - - if (wMsgLen) - { - if (wMsgLen > 0x1000) wMsgLen = 0x1000; // limit length - - if (IsUSASCII(szMsg, wMsgLen)) - { - const char* fmt = "text/x-aolrtf; charset=\"us-ascii\""; - const WORD fmtlen = (WORD)strlen(fmt); - - serverPacketInit(&packet, 23 + wMsgLen + fmtlen); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); - packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); - packTLV(&packet, 0x03, fmtlen, (LPBYTE)fmt); - packTLV(&packet, 0x04, wMsgLen, (LPBYTE)szMsg); - } - else - { - const char* fmt = "text/x-aolrtf; charset=\"unicode-2-0\""; - const WORD fmtlen = (WORD)strlen(fmt); - - WCHAR *szMsgW = make_unicode_string(szMsg); - wMsgLen = (WORD)strlennull(szMsgW) * sizeof(WCHAR); - - WCHAR *szMsgW2 = (WCHAR*)alloca(wMsgLen), *szMsgW3 = szMsgW; - unpackWideString((BYTE**)&szMsgW3, szMsgW2, wMsgLen); - SAFE_FREE(&szMsgW); - - serverPacketInit(&packet, 23 + wMsgLen + fmtlen); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); - packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); - packTLV(&packet, 0x03, fmtlen, (LPBYTE)fmt); - packTLV(&packet, 0x04, wMsgLen, (LPBYTE)szMsgW2); - } - } - else - { - serverPacketInit(&packet, 19); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO, 0, dwCookie); - packTLV(&packet, 0x0f, 1, (LPBYTE)"\x02"); - packTLV(&packet, 0x04, 0, NULL); - } - - sendServPacket(&packet); -} - - -void CIcqProto::icq_sendFileSendServv7(filetransfer* ft, const char *szFiles) -{ - icq_packet packet; - WORD wDescrLen = 0, wFilesLen = 0; - char *szFilesAnsi = NULL, *szDescrAnsi = NULL; - - if (!utf8_decode(szFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - else - wFilesLen = strlennull(szFilesAnsi); - - if (!utf8_decode(ft->szDescription, &szDescrAnsi)) - szDescrAnsi = NULL; - else - wDescrLen = strlennull(szDescrAnsi); - - packServChannel2Header(&packet, this, ft->dwUin, (WORD)(18 + wDescrLen + wFilesLen), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ICQ_VERSION, MTYPE_FILEREQ, 0, 1, 0, 1, 1); - - packLEWord(&packet, (WORD)(wDescrLen + 1)); - packBuffer(&packet, (LPBYTE)szDescrAnsi, (WORD)(wDescrLen + 1)); - packLEDWord(&packet, 0); // unknown - packLEWord(&packet, (WORD)(wFilesLen + 1)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packLEDWord(&packet, ft->dwTotalSize); - packLEDWord(&packet, 0); // unknown - - SAFE_FREE(&szFilesAnsi); - SAFE_FREE(&szDescrAnsi); - - sendServPacket(&packet); -} - - -void CIcqProto::icq_sendFileSendServv8(filetransfer* ft, const char *szFiles, int nAckType) -{ - icq_packet packet; - WORD wDescrLen = 0, wFilesLen = 0; - char *szFilesAnsi = NULL, *szDescrAnsi = NULL; - - if (!utf8_decode(szFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - else - wFilesLen = strlennull(szFilesAnsi); - - if (!utf8_decode(ft->szDescription, &szDescrAnsi)) - szDescrAnsi = NULL; - else - wDescrLen = strlennull(szDescrAnsi); - - // 202 + UIN len + file description (no null) + file name (null included) - // Packet size = Flap length + 4 - WORD wFlapLen = 178 + wDescrLen + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); - packServMsgSendHeader(&packet, ft->dwCookie, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwUin, NULL, 2, wFlapLen); - - // TLV(5) header - packServTLV5HeaderMsg(&packet, (WORD)(138 + wDescrLen + wFilesLen), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 1); - - // Port & IP information - packServDCInfo(&packet, this, FALSE); - - // TLV(0x2711) header - packServTLV2711Header(&packet, (WORD)ft->dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)MirandaStatusToIcq(m_iStatus), 0x100, 69 + wDescrLen + wFilesLen); - - packEmptyMsg(&packet); // Message (unused) - - packPluginTypeId(&packet, MTYPE_FILEREQ); - - packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length - packLEDWord(&packet, wDescrLen); // Description - packBuffer(&packet, (LPBYTE)szDescrAnsi, wDescrLen); - packWord(&packet, 0x8c82); // Unknown (port?), seen 0x80F6 - packWord(&packet, 0x0222); // Unknown, seen 0x2e01 - packLEWord(&packet, (WORD)(wFilesLen + 1)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packLEDWord(&packet, ft->dwTotalSize); - packLEDWord(&packet, 0x0008c82); // Unknown, (seen 0xf680 ~33000) - - SAFE_FREE(&szFilesAnsi); - SAFE_FREE(&szDescrAnsi); - - // Pack request server ack TLV - if (nAckType == ACKTYPE_SERVER) - packDWord(&packet, 0x00030000); // TLV(3) - - // Send the monster - sendServPacket(&packet); -} - - -/* also sends rejections */ -void CIcqProto::icq_sendFileAcceptServv8(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char *szFiles, const char *szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType) -{ - icq_packet packet; - WORD wDescrLen, wFilesLen; - char *szFilesAnsi = NULL, *szDescrAnsi = NULL; - - /* if !accepted, szDescr == szReason, szFiles = "" */ - - if (!accepted) szFiles = ""; - - if (!utf8_decode(szFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - - if (!utf8_decode(szDescr, &szDescrAnsi)) - szDescrAnsi = NULL; - - wDescrLen = strlennull(szDescrAnsi); - wFilesLen = strlennull(szFilesAnsi); - - // 202 + UIN len + file description (no null) + file name (null included) - // Packet size = Flap length + 4 - WORD wFlapLen = 178 + wDescrLen + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); - packServMsgSendHeader(&packet, dwCookie, TS1, TS2, dwUin, NULL, 2, wFlapLen); - - // TLV(5) header - packServTLV5HeaderMsg(&packet, (WORD)(138 + wDescrLen + wFilesLen), TS1, TS2, 2); - - // Port & IP information - packServDCInfo(&packet, this, !accepted); - - // TLV(0x2711) header - packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)(accepted ? 0:1), 0, 69 + wDescrLen + wFilesLen); - // - packEmptyMsg(&packet); // Message (unused) - - packPluginTypeId(&packet, MTYPE_FILEREQ); - - packLEDWord(&packet, (WORD)(18 + wDescrLen + wFilesLen + 1)); // Remaining length - packLEDWord(&packet, wDescrLen); // Description - packBuffer(&packet, (LPBYTE)szDescrAnsi, wDescrLen); - packWord(&packet, wPort); // Port - packWord(&packet, 0x00); // Unknown - packLEWord(&packet, (WORD)(wFilesLen + 1)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packLEDWord(&packet, dwTotalSize); - packLEDWord(&packet, (DWORD)wPort); // Unknown - - SAFE_FREE(&szFilesAnsi); - SAFE_FREE(&szDescrAnsi); - - // Pack request server ack TLV - if (nAckType == ACKTYPE_SERVER) - { - packDWord(&packet, 0x00030000); // TLV(3) - } - - // Send the monster - sendServPacket(&packet); -} - - -void CIcqProto::icq_sendFileAcceptServv7(DWORD dwUin, DWORD TS1, DWORD TS2, DWORD dwCookie, const char* szFiles, const char* szDescr, DWORD dwTotalSize, WORD wPort, BOOL accepted, int nAckType) -{ - icq_packet packet; - WORD wDescrLen, wFilesLen; - char *szFilesAnsi = NULL, *szDescrAnsi = NULL; - - /* if !accepted, szDescr == szReason, szFiles = "" */ - - if (!accepted) szFiles = ""; - - if (!utf8_decode(szFiles, &szFilesAnsi)) - szFilesAnsi = NULL; - - if (!utf8_decode(szDescr, &szDescrAnsi)) - szDescrAnsi = NULL; - - wDescrLen = strlennull(szDescrAnsi); - wFilesLen = strlennull(szFilesAnsi); - - // 150 + UIN len + file description (with null) + file name (2 nulls) - // Packet size = Flap length + 4 - WORD wFlapLen = 127 + wDescrLen + 1 + wFilesLen + (nAckType == ACKTYPE_SERVER?4:0); - packServMsgSendHeader(&packet, dwCookie, TS1, TS2, dwUin, NULL, 2, wFlapLen); - - // TLV(5) header - packServTLV5HeaderMsg(&packet, (WORD)(88 + wDescrLen + wFilesLen), TS1, TS2, 2); - - // Port & IP information - packServDCInfo(&packet, this, !accepted); - - // TLV(0x2711) header - packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_FILEREQ, 0, (WORD)(accepted ? 0:1), 0, 19 + wDescrLen + wFilesLen); - // - packLEWord(&packet, (WORD)(wDescrLen + 1)); // Description - packBuffer(&packet, (LPBYTE)szDescrAnsi, (WORD)(wDescrLen + 1)); - packWord(&packet, wPort); // Port - packWord(&packet, 0x00); // Unknown - packLEWord(&packet, (WORD)(wFilesLen + 2)); - packBuffer(&packet, (LPBYTE)szFilesAnsi, (WORD)(wFilesLen + 1)); - packByte(&packet, 0); - packLEDWord(&packet, dwTotalSize); - packLEDWord(&packet, (DWORD)wPort); // Unknown - - SAFE_FREE(&szFilesAnsi); - SAFE_FREE(&szDescrAnsi); - - // Pack request server ack TLV - if (nAckType == ACKTYPE_SERVER) - { - packDWord(&packet, 0x00030000); // TLV(3) - } - - // Send the monster - sendServPacket(&packet); -} - - -void CIcqProto::icq_sendFileAcceptServ(DWORD dwUin, filetransfer *ft, int nAckType) -{ - char *szDesc = ft->szDescription; - - if (ft->bEmptyDesc) szDesc = ""; // keep empty if it originally was (Trillian workaround) - - if (ft->nVersion >= 8) - { - icq_sendFileAcceptServv8(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szDesc, ft->dwTotalSize, wListenPort, TRUE, nAckType); - NetLog_Server("Sent file accept v%u through server, port %u", 8, wListenPort); - } - else - { - icq_sendFileAcceptServv7(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szDesc, ft->dwTotalSize, wListenPort, TRUE, nAckType); - NetLog_Server("Sent file accept v%u through server, port %u", 7, wListenPort); - } -} - - -void CIcqProto::icq_sendFileDenyServ(DWORD dwUin, filetransfer *ft, const char *szReason, int nAckType) -{ - if (ft->nVersion >= 8) - { - icq_sendFileAcceptServv8(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szReason, ft->dwTotalSize, wListenPort, FALSE, nAckType); - NetLog_Server("Sent file deny v%u through server", 8); - } - else - { - icq_sendFileAcceptServv7(dwUin, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, ft->dwCookie, ft->szFilename, szReason, ft->dwTotalSize, wListenPort, FALSE, nAckType); - NetLog_Server("Sent file deny v%u through server", 7); - } -} - - -void CIcqProto::icq_sendAwayMsgReplyServ(DWORD dwUin, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char** szMsg) -{ - HANDLE hContact = HContactFromUIN(dwUin, NULL); - - if (validateStatusMessageRequest(hContact, msgType)) - { - NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dwUin); - - icq_lock l(m_modeMsgsMutex); - - if (szMsg && *szMsg) - { - char *pszMsg = NULL; - WORD wReplyVersion = ICQ_VERSION; - - if (wVersion == 9) - { - pszMsg = *szMsg; - wReplyVersion = 9; - } - else - { // only v9 protocol supports UTF-8 mode messagees - WORD wMsgLen = strlennull(*szMsg) + 1; - char *szAnsiMsg = (char*)_alloca(wMsgLen); - - utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); - pszMsg = szAnsiMsg; - } - - WORD wMsgLen = strlennull(pszMsg); - - // limit msg len to max snac size - we get disconnected if exceeded - if (wMsgLen > MAX_MESSAGESNACSIZE) - wMsgLen = MAX_MESSAGESNACSIZE; - - icq_packet packet; - - packServAdvancedMsgReply(&packet, dwUin, NULL, dwMsgID1, dwMsgID2, wCookie, wReplyVersion, msgType, 3, (WORD)(wMsgLen + 3)); - packLEWord(&packet, (WORD)(wMsgLen + 1)); - packBuffer(&packet, (LPBYTE)pszMsg, wMsgLen); - packByte(&packet, 0); - - sendServPacket(&packet); - } - } -} - - -void CIcqProto::icq_sendAwayMsgReplyServExt(DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wCookie, WORD wVersion, BYTE msgType, char **szMsg) -{ - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (validateStatusMessageRequest(hContact, msgType)) - { - NotifyEventHooks(m_modeMsgsEvent, (WPARAM)msgType, (LPARAM)dwUin); - - icq_lock l(m_modeMsgsMutex); - - if (szMsg && *szMsg) - { - char *pszMsg = NULL; - WORD wReplyVersion = ICQ_VERSION; - - if (wVersion == 9) - { - pszMsg = *szMsg; - wReplyVersion = 9; - } - else - { // only v9 protocol supports UTF-8 mode messagees - WORD wMsgLen = strlennull(*szMsg) + 1; - char *szAnsiMsg = (char*)_alloca(wMsgLen); - - utf8_decode_static(*szMsg, szAnsiMsg, wMsgLen); - pszMsg = szAnsiMsg; - } - // convert to HTML - char *mng = MangleXml(pszMsg, strlennull(pszMsg)); - pszMsg = (char*)SAFE_MALLOC(strlennull(mng) + 28); - strcpy(pszMsg, ""); /// TODO: add support for RTL & user customizable font - strcat(pszMsg, mng); - SAFE_FREE(&mng); - strcat(pszMsg, ""); - - WORD wMsgLen = strlennull(pszMsg); - - // limit msg len to max snac size - we get disconnected if exceeded /// FIXME: correct HTML cutting - if (wMsgLen > MAX_MESSAGESNACSIZE) - wMsgLen = MAX_MESSAGESNACSIZE; - - icq_packet packet; - - packServAdvancedMsgReply(&packet, dwUin, szUID, dwMsgID1, dwMsgID2, wCookie, wReplyVersion, MTYPE_PLUGIN, 0, wMsgLen + 27 + getPluginTypeIdLen(msgType)); - packLEWord(&packet, 0); // Message size - packPluginTypeId(&packet, msgType); - - packLEDWord(&packet, wMsgLen + 21); - packLEDWord(&packet, wMsgLen); - packBuffer(&packet, (LPBYTE)pszMsg, wMsgLen); - - packLEDWord(&packet, 0x0D); - packBuffer(&packet, (LPBYTE)"text/x-aolrtf", 0x0D); - - sendServPacket(&packet); - SAFE_FREE(&pszMsg); - } - } -} - - -void CIcqProto::icq_sendAdvancedMsgAck(DWORD dwUin, DWORD dwTimestamp, DWORD dwTimestamp2, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags) -{ - icq_packet packet; - - packServAdvancedMsgReply(&packet, dwUin, NULL, dwTimestamp, dwTimestamp2, wCookie, ICQ_VERSION, bMsgType, bMsgFlags, 11); - packEmptyMsg(&packet); // Status message - packMsgColorInfo(&packet); - - sendServPacket(&packet); -} - - -void CIcqProto::icq_sendContactsAck(DWORD dwUin, char *szUid, DWORD dwMsgID1, DWORD dwMsgID2) -{ - icq_packet packet; - - packServMsgSendHeader(&packet, 0, dwMsgID1, dwMsgID2, dwUin, szUid, 2, 0x1E); - packServTLV5HeaderBasic(&packet, 0, dwMsgID1, dwMsgID2, 2, MCAP_CONTACTS); - - sendServPacket(&packet); -} - - -// Searches - -DWORD CIcqProto::SearchByUin(DWORD dwUin) -{ - WORD wInfoLen; - icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer - // I should be ashamed! ;) - - // Calculate data size - wInfoLen = 4 + getUINLen(dwUin); - - // Initialize our handy data buffer - pBuffer.wPlace = 0; - pBuffer.pData = (BYTE *)_alloca(wInfoLen); - pBuffer.wLen = wInfoLen; - - // Initialize our handy data buffer - packTLVUID(&pBuffer, 0x32, dwUin, NULL); - - // Send it off for further packing - return sendDirectorySearchPacket(pBuffer.pData, wInfoLen, 0, FALSE); -} - - -DWORD CIcqProto::SearchByNames(const char *pszNick, const char *pszFirstName, const char *pszLastName, WORD wPage) -{ // use directory search like ICQ6 does - WORD wInfoLen = 0; - WORD wNickLen,wFirstLen,wLastLen; - icq_packet pBuffer; // I reuse the ICQ packet type as a generic buffer - // I should be ashamed! ;) - - wNickLen = strlennull(pszNick); - wFirstLen = strlennull(pszFirstName); - wLastLen = strlennull(pszLastName); - - _ASSERTE(wFirstLen || wLastLen || wNickLen); - - - // Calculate data size - if (wFirstLen) - wInfoLen = wFirstLen + 4; - if (wLastLen) - wInfoLen += wLastLen + 4; - if (wNickLen) - wInfoLen += wNickLen + 4; - - // Initialize our handy data buffer - pBuffer.wPlace = 0; - pBuffer.pData = (BYTE *)_alloca(wInfoLen); - pBuffer.wLen = wInfoLen; - - // Pack the search details - if (wNickLen) - packTLV(&pBuffer, 0x78, wNickLen, (PBYTE)pszNick); - - if (wLastLen) - packTLV(&pBuffer, 0x6E, wLastLen, (PBYTE)pszLastName); - - if (wFirstLen) - packTLV(&pBuffer, 0x64, wFirstLen, (PBYTE)pszFirstName); - - // Send it off for further packing - if (wInfoLen) - return sendDirectorySearchPacket(pBuffer.pData, wInfoLen, wPage, FALSE); - else - return 0; // Failure -} - - -DWORD CIcqProto::SearchByMail(const char* pszEmail) -{ - DWORD dwCookie = 0; - WORD wInfoLen = 0; - WORD wEmailLen; - BYTE *pBuffer; - int pBufferPos; - - wEmailLen = strlennull(pszEmail); - - _ASSERTE(wEmailLen); - - if (wEmailLen > 0) - { - // Calculate data size - wInfoLen = wEmailLen + 7; - - // Initialize our handy data buffer - pBuffer = (BYTE *)_alloca(wInfoLen); - pBufferPos = 0; - - // Pack the search details - packLETLVLNTS(&pBuffer, &pBufferPos, pszEmail, TLV_EMAIL); - - // Send it off for further packing - dwCookie = sendTLVSearchPacket(SEARCHTYPE_EMAIL, (char*)pBuffer, META_SEARCH_EMAIL, wInfoLen, FALSE); - } - - return dwCookie; -} - - -DWORD CIcqProto::sendDirectorySearchPacket(const BYTE *pSearchData, WORD wDataLen, WORD wPage, BOOL bOnlineUsersOnly) -{ - icq_packet packet; - DWORD dwCookie; - - _ASSERTE(pSearchData); - _ASSERTE(wDataLen >= 4); - - cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); - if (pCookieData) - { - pCookieData->bRequestType = DIRECTORYREQUEST_SEARCH; - dwCookie = AllocateCookie(CKT_DIRECTORY_QUERY, 0, NULL, (void*)pCookieData); - } - else - return 0; - - // Pack headers - packServIcqDirectoryHeader(&packet, this, wDataLen + (bOnlineUsersOnly ? 14 : 8), META_DIRECTORY_QUERY, DIRECTORY_QUERY_INFO, (WORD)dwCookie); - packWord(&packet, 0x02); - - // Pack requested page number - packWord(&packet, wPage); - - // Pack search data - packWord(&packet, 0x0001); - packWord(&packet, wDataLen + (bOnlineUsersOnly ? 6 : 0)); - packBuffer(&packet, pSearchData, wDataLen); - - if (bOnlineUsersOnly) - { // Pack "Online users only" flag - packTLVWord(&packet, 0x136, 1); - } - - // Go! - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::sendTLVSearchPacket(BYTE bType, char* pSearchDataBuf, WORD wSearchType, WORD wInfoLen, BOOL bOnlineUsersOnly) -{ - icq_packet packet; - cookie_search* pCookie; - - _ASSERTE(pSearchDataBuf); - _ASSERTE(wInfoLen >= 4); - - pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); - if (!pCookie) - return 0; - - pCookie->bSearchType = bType; - DWORD dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie); - - // Pack headers - packServIcqExtensionHeader(&packet, this, (WORD)(wInfoLen + (wSearchType==META_SEARCH_GENERIC?7:2)), CLI_META_INFO_REQ, (WORD)dwCookie); - - // Pack search type - packLEWord(&packet, wSearchType); - - // Pack search data - packBuffer(&packet, (LPBYTE)pSearchDataBuf, wInfoLen); - - if (wSearchType == META_SEARCH_GENERIC && bOnlineUsersOnly) - { // Pack "Online users only" flag - only for generic search - BYTE bData = 1; - packTLV(&packet, TLV_ONLINEONLY, 1, &bData); - } - - // Go! - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendAdvancedSearchServ(BYTE* fieldsBuffer,int bufferLen) -{ - icq_packet packet; - DWORD dwCookie; - - cookie_search *pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); - if (pCookie) - { - pCookie->bSearchType = SEARCHTYPE_DETAILS; - dwCookie = AllocateCookie(CKT_SEARCH, 0, 0, pCookie); - } - else - return 0; - - packServIcqExtensionHeader(&packet, this, (WORD)bufferLen, CLI_META_INFO_REQ, (WORD)dwCookie); - packBuffer(&packet, (LPBYTE)fieldsBuffer, (WORD)bufferLen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_searchAimByEmail(const char* pszEmail, DWORD dwSearchId) -{ - icq_packet packet; - DWORD dwCookie; - cookie_search* pCookie; - WORD wEmailLen; - - if (!FindCookie(dwSearchId, NULL, (void**)&pCookie)) - { - dwSearchId = 0; - pCookie = (cookie_search*)SAFE_MALLOC(sizeof(cookie_search)); - pCookie->bSearchType = SEARCHTYPE_EMAIL; - } - - if (pCookie) - { - pCookie->dwMainId = dwSearchId; - pCookie->szObject = null_strdup(pszEmail); - dwCookie = AllocateCookie(CKT_SEARCH, ICQ_LOOKUP_REQUEST, 0, pCookie); - } - else - return 0; - - wEmailLen = strlennull(pszEmail); - serverPacketInit(&packet, (WORD)(10 + wEmailLen)); - packFNACHeader(&packet, ICQ_LOOKUP_FAMILY, ICQ_LOOKUP_REQUEST, 0, dwCookie); - packBuffer(&packet, (LPBYTE)pszEmail, wEmailLen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_changeUserPasswordServ(const char *szPassword) -{ - icq_packet packet; - WORD wPasswordLen = strlennull(szPassword); - DWORD dwCookie = GenerateCookie(0); - - packServIcqExtensionHeader(&packet, this, (WORD)(wPasswordLen + 4), CLI_META_INFO_REQ, (WORD)dwCookie, ICQ_META_SRV_UPDATE); - packLEWord(&packet, META_SET_PASSWORD_REQ); - packLEWord(&packet, wPasswordLen); - packBuffer(&packet, (BYTE*)szPassword, wPasswordLen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_changeUserDirectoryInfoServ(const BYTE *pData, WORD wDataLen, BYTE bRequestType) -{ - icq_packet packet; - cookie_directory_data *pCookieData = (cookie_directory_data*)SAFE_MALLOC(sizeof(cookie_directory_data)); - pCookieData->bRequestType = bRequestType; - DWORD dwCookie = AllocateCookie(CKT_DIRECTORY_UPDATE, 0, NULL, pCookieData); - - packServIcqDirectoryHeader(&packet, this, wDataLen + 4, META_DIRECTORY_UPDATE, DIRECTORY_SET_INFO, (WORD)dwCookie, ICQ_META_SRV_UPDATE); - packWord(&packet, 0x0003); - packWord(&packet, wDataLen); - packBuffer(&packet, pData, wDataLen); - - sendServPacket(&packet); - - return dwCookie; -} - - -DWORD CIcqProto::icq_sendSMSServ(const char *szPhoneNumber, const char *szMsg) -{ - icq_packet packet; - DWORD dwCookie; - WORD wBufferLen; - char* szBuffer = NULL; - char* szMyNick = NULL; - char szTime[30]; - time_t now; - int nBufferSize; - - now = time(NULL); - strftime(szTime, sizeof(szTime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); - /* Sun, 00 Jan 0000 00:00:00 GMT */ - - szMyNick = null_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)(HANDLE)NULL, 0)); - nBufferSize = 1 + strlennull(szMyNick) + strlennull(szPhoneNumber) + strlennull(szMsg) + sizeof("1252utf80000000000Yes"); - - if (szBuffer = (char *)_alloca(nBufferSize)) - { - - wBufferLen = null_snprintf(szBuffer, nBufferSize, - "" - "" - "%s" /* phone number */ - "" - "" - "%s" /* body */ - "" - "" - "1252" - "" - "" - "utf8" - "" - "" - "%u" /* my UIN */ - "" - "" - "%s" /* my nick */ - "" - "" - "Yes" - "" - "" - "", - szPhoneNumber, szMsg, m_dwLocalUIN, szMyNick, szTime); - - dwCookie = GenerateCookie(0); - - packServIcqExtensionHeader(&packet, this, (WORD)(wBufferLen + 27), CLI_META_INFO_REQ, (WORD)dwCookie); - packWord(&packet, 0x8214); /* send sms */ - packWord(&packet, 1); - packWord(&packet, 0x16); - packDWord(&packet, 0); - packDWord(&packet, 0); - packDWord(&packet, 0); - packDWord(&packet, 0); - packWord(&packet, 0); - packWord(&packet, (WORD)(wBufferLen + 1)); - packBuffer(&packet, (LPBYTE)szBuffer, (WORD)(1 + wBufferLen)); - - sendServPacket(&packet); - } - else - { - dwCookie = 0; - } - - SAFE_FREE((void**)&szMyNick); - return dwCookie; -} - -void CIcqProto::icq_sendGenericContact(DWORD dwUin, const char *szUid, WORD wFamily, WORD wSubType) -{ - icq_packet packet; - int nUinLen; - - nUinLen = getUIDLen(dwUin, szUid); - - serverPacketInit(&packet, (WORD)(nUinLen + 11)); - packFNACHeader(&packet, wFamily, wSubType); - packUID(&packet, dwUin, szUid); - - sendServPacket(&packet); -} - -void CIcqProto::icq_sendNewContact(DWORD dwUin, const char *szUid) -{ - /* Try to add to temporary buddy list */ - icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST); -} - - -void CIcqProto::icq_sendRemoveContact(DWORD dwUin, const char *szUid) -{ - /* Remove from temporary buddy list */ - icq_sendGenericContact(dwUin, szUid, ICQ_BUDDY_FAMILY, ICQ_USER_REMOVEFROMTEMPLIST); -} - - -// list==0: visible list -// list==1: invisible list -void CIcqProto::icq_sendChangeVisInvis(HANDLE hContact, DWORD dwUin, char* szUID, int list, int add) -{ // TODO: This needs grouping & rate management - // Tell server to change our server-side contact visbility list - if (m_bSsiEnabled) - { - WORD wContactId; - char* szSetting; - WORD wType; - - if (list == 0) - { - wType = SSI_ITEM_PERMIT; - szSetting = DBSETTING_SERVLIST_PERMIT; - } - else - { - wType = SSI_ITEM_DENY; - szSetting = DBSETTING_SERVLIST_DENY; - } - - if (add) - { - // check if we should make the changes, this is 2nd level check - if (getSettingWord(hContact, szSetting, 0) != 0) - return; - - // Add - wContactId = GenerateServerID(SSIT_ITEM, 0); - - icq_addServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType); - - setSettingWord(hContact, szSetting, wContactId); - } - else - { - // Remove - wContactId = getSettingWord(hContact, szSetting, 0); - - if (wContactId) - { - icq_removeServerPrivacyItem(hContact, dwUin, szUID, wContactId, wType); - - deleteSetting(hContact, szSetting); - } - } - } - - // Notify server that we have changed - // our client side visibility list - { - int nUinLen; - icq_packet packet; - WORD wSnac = 0; - - if (list && m_iStatus == ID_STATUS_INVISIBLE) - return; - - if (!list && m_iStatus != ID_STATUS_INVISIBLE) - return; - - - if (list && add) - wSnac = ICQ_CLI_ADDINVISIBLE; - else if (list && !add) - wSnac = ICQ_CLI_REMOVEINVISIBLE; - else if (!list && add) - wSnac = ICQ_CLI_ADDVISIBLE; - else if (!list && !add) - wSnac = ICQ_CLI_REMOVEVISIBLE; - - nUinLen = getUIDLen(dwUin, szUID); - - serverPacketInit(&packet, (WORD)(nUinLen + 11)); - packFNACHeader(&packet, ICQ_BOS_FAMILY, wSnac); - packUID(&packet, dwUin, szUID); - - sendServPacket(&packet); - } -} - -void CIcqProto::icq_sendEntireVisInvisList(int list) -{ - if (list) - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE); - else - sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE); -} - -void CIcqProto::icq_sendRevokeAuthServ(DWORD dwUin, char *szUid) -{ - icq_sendGenericContact(dwUin, szUid, ICQ_LISTS_FAMILY, ICQ_LISTS_REVOKEAUTH); -} - -void CIcqProto::icq_sendGrantAuthServ(DWORD dwUin, const char *szUid, const char *szMsg) -{ - icq_packet packet; - BYTE nUinlen; - char *szUtfMsg = NULL; - WORD nMsglen; - - nUinlen = getUIDLen(dwUin, szUid); - - // Prepare custom utf-8 message - szUtfMsg = ansi_to_utf8(szMsg); - nMsglen = strlennull(szUtfMsg); - - serverPacketInit(&packet, (WORD)(15 + nUinlen + nMsglen)); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_GRANTAUTH); - packUID(&packet, dwUin, szUid); - packWord(&packet, nMsglen); - packBuffer(&packet, (LPBYTE)szUtfMsg, nMsglen); - packWord(&packet, 0); - - SAFE_FREE((void**)&szUtfMsg); - - sendServPacket(&packet); -} - -void CIcqProto::icq_sendAuthReqServ(DWORD dwUin, char *szUid, const char *szMsg) -{ - icq_packet packet; - BYTE nUinlen; - WORD nMsglen; - - nUinlen = getUIDLen(dwUin, szUid); - nMsglen = strlennull(szMsg); - - serverPacketInit(&packet, (WORD)(15 + nUinlen + nMsglen)); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_REQUESTAUTH); - packUID(&packet, dwUin, szUid); - packWord(&packet, nMsglen); - packBuffer(&packet, (LPBYTE)szMsg, nMsglen); - packWord(&packet, 0); - - sendServPacket(&packet); -} - -void CIcqProto::icq_sendAuthResponseServ(DWORD dwUin, char* szUid, int auth, const TCHAR *szReason) -{ - icq_packet packet; - BYTE nUinLen = getUIDLen(dwUin, szUid); - - // Prepare custom utf-8 reason - char *szUtfReason = tchar_to_utf8(szReason); - WORD nReasonLen = strlennull(szUtfReason); - - serverPacketInit(&packet, (WORD)(16 + nUinLen + nReasonLen)); - packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_AUTHRESPONSE); - packUID(&packet, dwUin, szUid); - packByte(&packet, (BYTE)auth); - packWord(&packet, nReasonLen); - packBuffer(&packet, (LPBYTE)szUtfReason, nReasonLen); - packWord(&packet, 0); - - SAFE_FREE(&szUtfReason); - - sendServPacket(&packet); -} - -void CIcqProto::icq_sendYouWereAddedServ(DWORD dwUin, DWORD dwMyUin) -{ - icq_packet packet; - DWORD dwID1; - DWORD dwID2; - - dwID1 = time(NULL); - dwID2 = RandRange(0, 0x00FF); - - packServMsgSendHeader(&packet, 0, dwID1, dwID2, dwUin, NULL, 0x0004, 17); - packWord(&packet, 0x0005); // TLV(5) - packWord(&packet, 0x0009); - packLEDWord(&packet, dwMyUin); - packByte(&packet, MTYPE_ADDED); - packByte(&packet, 0); // msg-flags - packEmptyMsg(&packet); // NTS - packDWord(&packet, 0x00060000); // TLV(6) - - sendServPacket(&packet); -} - -void CIcqProto::icq_sendXtrazRequestServ(DWORD dwUin, DWORD dwCookie, char* szBody, int nBodyLen, cookie_message_data *pCookieData) -{ - icq_packet packet; - WORD wCoreLen; - - wCoreLen = 11 + getPluginTypeIdLen(pCookieData->bMessageType) + nBodyLen; - packServMsgSendHeader(&packet, dwCookie, pCookieData->dwMsgID1, pCookieData->dwMsgID2, dwUin, NULL, 2, (WORD)(99 + wCoreLen)); - - // TLV(5) header - packServTLV5HeaderMsg(&packet, (WORD)(55 + wCoreLen), pCookieData->dwMsgID1, pCookieData->dwMsgID2, 1); - - // TLV(0x2711) header - packServTLV2711Header(&packet, (WORD)dwCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, 0, 0x100, wCoreLen); - // - packEmptyMsg(&packet); - - packPluginTypeId(&packet, pCookieData->bMessageType); - - packLEDWord(&packet, nBodyLen + 4); - packLEDWord(&packet, nBodyLen); - packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); - - // Pack request server ack TLV - packDWord(&packet, 0x00030000); // TLV(3) - - // Send the monster - sendServPacket(&packet); -} - -void CIcqProto::icq_sendXtrazResponseServ(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szBody, int nBodyLen, int nType) -{ - icq_packet packet; - - packServAdvancedMsgReply(&packet, dwUin, NULL, dwMID, dwMID2, wCookie, ICQ_VERSION, MTYPE_PLUGIN, 0, (WORD)(getPluginTypeIdLen(nType) + 11 + nBodyLen)); - // - packEmptyMsg(&packet); - - packPluginTypeId(&packet, nType); - - packLEDWord(&packet, nBodyLen + 4); - packLEDWord(&packet, nBodyLen); - packBuffer(&packet, (LPBYTE)szBody, (WORD)nBodyLen); - - // Send the monster - sendServPacket(&packet); -} - -void CIcqProto::icq_sendReverseReq(directconnect *dc, DWORD dwCookie, cookie_message_data *pCookie) -{ - icq_packet packet; - - packServMsgSendHeader(&packet, dwCookie, pCookie->dwMsgID1, pCookie->dwMsgID2, dc->dwRemoteUin, NULL, 2, 0x47); - - packServTLV5HeaderBasic(&packet, 0x29, pCookie->dwMsgID1, pCookie->dwMsgID2, 0, MCAP_REVERSE_DC_REQ); - - packTLVWord(&packet, 0x0A, 1); // TLV: 0x0A Acktype: 1 for normal, 2 for ack - packDWord(&packet, 0x000F0000); // TLV: 0x0F empty - packDWord(&packet, 0x2711001B); // TLV: 0x2711 Content - // TLV(0x2711) data - packLEDWord(&packet, m_dwLocalUIN); // Our UIN - packDWord(&packet, dc->dwLocalExternalIP);// IP to connect to - packLEDWord(&packet, wListenPort); // Port to connect to - packByte(&packet, DC_NORMAL); // generic DC type - packDWord(&packet, dc->dwRemotePort); // unknown - packDWord(&packet, wListenPort); // port again ? - packLEWord(&packet, ICQ_VERSION); // DC Version - packLEDWord(&packet, dwCookie); // Req Cookie - - // Send the monster - sendServPacket(&packet); -} - -void CIcqProto::icq_sendReverseFailed(directconnect* dc, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwCookie) -{ - icq_packet packet; - int nUinLen = getUINLen(dc->dwRemoteUin); - - serverPacketInit(&packet, (WORD)(nUinLen + 74)); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE, 0, ICQ_MSG_RESPONSE<<0x10 | (dwCookie & 0x7FFF)); - packLEDWord(&packet, dwMsgID1); // Msg ID part 1 - packLEDWord(&packet, dwMsgID2); // Msg ID part 2 - packWord(&packet, 0x02); - packUIN(&packet, dc->dwRemoteUin); - packWord(&packet, 0x03); - packLEDWord(&packet, dc->dwRemoteUin); - packLEDWord(&packet, dc->dwRemotePort); - packLEDWord(&packet, wListenPort); - packLEWord(&packet, ICQ_VERSION); - packLEDWord(&packet, dwCookie); - - sendServPacket(&packet); -} - - -// OSCAR file-transfer packets starts here -// -void CIcqProto::oft_sendFileRequest(DWORD dwUin, char *szUid, oscar_filetransfer *ft, const char *pszFiles, DWORD dwLocalInternalIP) -{ - icq_packet packet; - - char *szCoolStr = (char*)_alloca(strlennull(ft->szDescription)+strlennull(pszFiles) + 160); - sprintf(szCoolStr, "%s%I64u1%s", pszFiles, ft->qwTotalSize, ft->szDescription); - szCoolStr = MangleXml(szCoolStr, strlennull(szCoolStr)); - - WORD wDataLen = 93 + strlennull(szCoolStr) + strlennull(pszFiles); - if (ft->bUseProxy) wDataLen += 4; - - packServMsgSendHeader(&packet, ft->dwCookie, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, (WORD)(wDataLen + 0x1E)); - packServTLV5HeaderBasic(&packet, wDataLen, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, MCAP_FILE_TRANSFER); - - packTLVWord(&packet, 0x0A, ++ft->wReqNum); // Request sequence - packDWord(&packet, 0x000F0000); // Unknown - packTLV(&packet, 0x0D, 5, (LPBYTE)"utf-8"); // Charset - packTLV(&packet, 0x0C, (WORD)strlennull(szCoolStr), (LPBYTE)szCoolStr); // User message (CoolData XML) - SAFE_FREE(&szCoolStr); - if (ft->bUseProxy) - { - packTLVDWord(&packet, 0x02, ft->dwProxyIP); // Proxy IP - packTLVDWord(&packet, 0x16, ft->dwProxyIP ^ 0x0FFFFFFFF); // Proxy IP check - } - else - { - packTLVDWord(&packet, 0x02, dwLocalInternalIP); - packTLVDWord(&packet, 0x16, dwLocalInternalIP ^ 0x0FFFFFFFF); - } - packTLVDWord(&packet, 0x03, dwLocalInternalIP); // Client IP - if (ft->bUseProxy) - { - packTLVWord(&packet, 0x05, ft->wRemotePort); - packTLVWord(&packet, 0x17, (WORD)(ft->wRemotePort ^ 0x0FFFF)); - packDWord(&packet, 0x00100000); // Proxy flag - } - else - { - oscar_listener *pListener = (oscar_listener*)ft->listener; - - packTLVWord(&packet, 0x05, pListener->wPort); - packTLVWord(&packet, 0x15, (WORD)((pListener->wPort) ^ 0x0FFFF)); - } - { // TLV(0x2711) - packWord(&packet, 0x2711); - packWord(&packet, (WORD)(9 + strlennull(pszFiles))); - packWord(&packet, (WORD)(ft->wFilesCount == 1 ? 1 : 2)); - packWord(&packet, ft->wFilesCount); - packDWord(&packet, (DWORD)ft->qwTotalSize); - packBuffer(&packet, (LPBYTE)pszFiles, (WORD)(strlennull(pszFiles) + 1)); - } - packTLV(&packet, 0x2712, 5, (LPBYTE)"utf-8"); - { // TLV(0x2713) - packWord(&packet, 0x2713); - packWord(&packet, 8); - packQWord(&packet, ft->qwTotalSize); - } - - sendServPacket(&packet); // Send the monster -} - - -void CIcqProto::oft_sendFileReply(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResult) -{ - icq_packet packet; - - packServMsgSendHeader(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, 0x1E); - packServTLV5HeaderBasic(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, wResult, MCAP_FILE_TRANSFER); - - sendServPacket(&packet); -} - - -void CIcqProto::oft_sendFileAccept(DWORD dwUin, char *szUid, oscar_filetransfer *ft) -{ - oft_sendFileReply(dwUin, szUid, ft, 0x02); -} - - -void CIcqProto::oft_sendFileResponse(DWORD dwUin, char *szUid, oscar_filetransfer *ft, WORD wResponse) -{ - icq_packet packet; - - packServAdvancedReply(&packet, dwUin, szUid, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, 4); - packWord(&packet, 0x02); // Length of following data - packWord(&packet, wResponse); // Response code - - sendServPacket(&packet); -} - - -void CIcqProto::oft_sendFileDeny(DWORD dwUin, char *szUid, oscar_filetransfer *ft) -{ - if (dwUin) - { // ICQ clients uses special deny file transfer - oft_sendFileResponse(dwUin, szUid, ft, 0x01); - } - else - oft_sendFileReply(dwUin, szUid, ft, 0x01); -} - - -void CIcqProto::oft_sendFileCancel(DWORD dwUin, char *szUid, oscar_filetransfer *ft) -{ - oft_sendFileReply(dwUin, szUid, ft, 0x01); -} - - -void CIcqProto::oft_sendFileRedirect(DWORD dwUin, char *szUid, oscar_filetransfer *ft, DWORD dwIP, WORD wPort, int bProxy) -{ - icq_packet packet; - - packServMsgSendHeader(&packet, 0, ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, dwUin, szUid, 2, (WORD)(bProxy ? 0x4a : 0x4e)); - packServTLV5HeaderBasic(&packet, (WORD)(bProxy ? 0x2C : 0x30), ft->pMessage.dwMsgID1, ft->pMessage.dwMsgID2, 0, MCAP_FILE_TRANSFER); - // Connection point data - packTLVWord(&packet, 0x0A, ++ft->wReqNum); // Ack Type - packTLVWord(&packet, 0x14, 0x0A); // Unknown ? - packTLVDWord(&packet, 0x02, dwIP); // Internal IP / Proxy IP - packTLVDWord(&packet, 0x16, dwIP ^ 0x0FFFFFFFF); // IP Check ? - if (!bProxy) - packTLVDWord(&packet, 0x03, dwIP); - packTLVWord(&packet, 0x05, wPort); // Listening Port - packTLVWord(&packet, 0x17, (WORD)(wPort ^ 0x0FFFF)); // Port Check ? - if (bProxy) - packDWord(&packet, 0x00100000); // Proxy Flag - - sendServPacket(&packet); -} diff --git a/protocols/IcqOscarJ/stdpackets.h b/protocols/IcqOscarJ/stdpackets.h deleted file mode 100644 index b656d713c6..0000000000 --- a/protocols/IcqOscarJ/stdpackets.h +++ /dev/null @@ -1,43 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Low-level functions that really sends data to server -// -// ----------------------------------------------------------------------------- -#ifndef __STDPACKETS_H -#define __STDPACKETS_H - -struct icq_contactsend_s -{ - DWORD uin; - char *uid; - char *szNick; -}; - - -void packMsgColorInfo(icq_packet *packet); - -#endif /* __STDPACKETS_H */ diff --git a/protocols/IcqOscarJ/tlv.cpp b/protocols/IcqOscarJ/tlv.cpp deleted file mode 100644 index 7c4eafca3a..0000000000 --- a/protocols/IcqOscarJ/tlv.cpp +++ /dev/null @@ -1,391 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2009 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Helper functions for Oscar TLV chains -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - - -/* set maxTlvs<=0 to get all TLVs in length, or a positive integer to get at most the first n */ -oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs) -{ - oscar_tlv_chain *now, *last, *chain = NULL; - WORD now_tlv_len; - int len = wLen; - - if (!buf || !wLen) return NULL; - - while (len > 0) /* don't use unsigned variable for this check */ - { - now = (oscar_tlv_chain *)SAFE_MALLOC(sizeof(oscar_tlv_chain)); - - if (!now) - { - disposeChain(&chain); - return NULL; - } - - unpackWord(buf, &(now->tlv.wType)); - unpackWord(buf, &now_tlv_len); - now->tlv.wLen = now_tlv_len; - len -= 4; - - if (now_tlv_len < 1) - { - now->tlv.pData = NULL; - } - else if (now_tlv_len <= len) - { - now->tlv.pData = (BYTE *)SAFE_MALLOC(now_tlv_len); - if (now->tlv.pData) - memcpy(now->tlv.pData, *buf, now_tlv_len); - } - else - { // the packet is shorter than it should be - SAFE_FREE((void**)&now); - return chain; // give at least the rest of chain - } - - if (chain) // keep the original order - last->next = now; - else - chain = now; - - last = now; - - len -= now_tlv_len; - *buf += now_tlv_len; - - if (--maxTlvs == 0) - break; - } - - return chain; -} - -// Returns a pointer to the TLV with type wType and number wIndex in the chain -// If wIndex = 1, the first matching TLV will be returned, if wIndex = 2, -// the second matching one will be returned. -// wIndex must be > 0 -oscar_tlv* oscar_tlv_chain::getTLV(WORD wType, WORD wIndex) -{ - int i = 0; - oscar_tlv_chain *list = this; - - while (list) - { - if (list->tlv.wType == wType) - i++; - if (i >= wIndex) - return &list->tlv; - list = list->next; - } - - return NULL; -} - - -WORD oscar_tlv_chain::getChainLength() -{ - int len = 0; - oscar_tlv_chain *list = this; - - while (list) - { - len += list->tlv.wLen + 4; - list = list->next; - } - return len; -} - - -oscar_tlv* oscar_tlv_chain::putTLV(WORD wType, WORD wLen, BYTE *pData, BOOL bReplace) -{ - oscar_tlv *tlv = getTLV(wType, 1); - - if (tlv && bReplace) - { - SAFE_FREE((void**)&tlv->pData); - } - else - { - oscar_tlv_chain *last = this; - - while (last && last->next) - last = last->next; - - if (last) - { - last->next = (oscar_tlv_chain*)SAFE_MALLOC(sizeof(oscar_tlv_chain)); - tlv = &last->next->tlv; - tlv->wType = wType; - } - } - if (tlv) - { - tlv->wLen = wLen; - tlv->pData = (PBYTE)SAFE_MALLOC(wLen); - memcpy(tlv->pData, pData, wLen); - } - return tlv; -} - - -oscar_tlv_chain* oscar_tlv_chain::removeTLV(oscar_tlv *tlv) -{ - oscar_tlv_chain *list = this, *prev = NULL, *chain = this; - - while (list) - { - if (&list->tlv == tlv) - { - if (prev) // relink - prev->next = list->next; - else if (list->next) - { // move second item's tlv to the first item - list->tlv = list->next->tlv; - list = list->next; - } - else // result is an empty chain (NULL) - chain = NULL; - // release chain item memory - SAFE_FREE((void**)&list->tlv.pData); - SAFE_FREE((void**)&list); - } - prev = list; - list = list->next; - } - - return chain; -} - - -WORD oscar_tlv_chain::getLength(WORD wType, WORD wIndex) -{ - oscar_tlv *tlv = getTLV(wType, wIndex); - if (tlv) - return tlv->wLen; - - return 0; -} - - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* Values are returned in MSB format */ -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -DWORD oscar_tlv_chain::getDWord(WORD wType, WORD wIndex) -{ - DWORD dw = 0; - - oscar_tlv *tlv = getTLV(wType, wIndex); - if (tlv && tlv->wLen >= 4) - { - dw |= (*((tlv->pData)+0) << 24); - dw |= (*((tlv->pData)+1) << 16); - dw |= (*((tlv->pData)+2) << 8); - dw |= (*((tlv->pData)+3)); - } - - return dw; -} - - -WORD oscar_tlv_chain::getWord(WORD wType, WORD wIndex) -{ - WORD w = 0; - - oscar_tlv *tlv = getTLV(wType, wIndex); - if (tlv && tlv->wLen >= 2) - { - w |= (*((tlv->pData)+0) << 8); - w |= (*((tlv->pData)+1)); - } - - return w; -} - - -BYTE oscar_tlv_chain::getByte(WORD wType, WORD wIndex) -{ - BYTE b = 0; - - oscar_tlv *tlv = getTLV(wType, wIndex); - if (tlv && tlv->wLen) - { - b = *(tlv->pData); - } - - return b; -} - - -int oscar_tlv_chain::getNumber(WORD wType, WORD wIndex) -{ - oscar_tlv *tlv = getTLV(wType, wIndex); - - if (tlv) - { - if (tlv->wLen == 1) - return getByte(wType, wIndex); - else if (tlv->wLen == 2) - return getWord(wType, wIndex); - else if (tlv->wLen == 4) - return getDWord(wType, wIndex); - } - return 0; -} - - -double oscar_tlv_chain::getDouble(WORD wType, WORD wIndex) -{ - oscar_tlv *tlv = getTLV(wType, wIndex); - - if (tlv && tlv->wLen == 8) - { - BYTE *buf = tlv->pData; - double d = 0; - - unpackQWord(&buf, (DWORD64*)&d); - - return d; - } - return 0; -} - - -char* oscar_tlv_chain::getString(WORD wType, WORD wIndex) -{ - char *str = NULL; - - oscar_tlv *tlv = getTLV(wType, wIndex); - if (tlv) - { - str = (char*)SAFE_MALLOC(tlv->wLen + 1); /* For \0 */ - - if (!str) return NULL; - - memcpy(str, tlv->pData, tlv->wLen); - str[tlv->wLen] = '\0'; - } - - return str; -} - - -void disposeChain(oscar_tlv_chain **chain) -{ - if (!chain || !*chain) - return; - - oscar_tlv_chain *now = *chain; - - while (now) - { - oscar_tlv_chain *next = now->next; - - SAFE_FREE((void**)&now->tlv.pData); - SAFE_FREE((void**)&now); - now = next; - } - - *chain = NULL; -} - - -oscar_tlv_record_list* readIntoTLVRecordList(BYTE **buf, WORD wLen, int nCount) -{ - oscar_tlv_record_list *list = NULL, *last; - - while (wLen >= 2) - { - WORD wRecordSize; - - unpackWord(buf, &wRecordSize); - wLen -= 2; - if (wRecordSize && wRecordSize <= wLen) - { - oscar_tlv_record_list *pRecord = (oscar_tlv_record_list*)SAFE_MALLOC(sizeof(oscar_tlv_record_list)); - BYTE *pData = *buf; - - *buf += wRecordSize; - wLen -= wRecordSize; - - pRecord->item = readIntoTLVChain(&pData, wRecordSize, 0); - if (pRecord->item) - { // keep the order - if (list) - last->next = pRecord; - else - list = pRecord; - - last = pRecord; - } - else - SAFE_FREE((void**)&pRecord); - } - - if (--nCount == 0) break; - } - return list; -} - - -void disposeRecordList(oscar_tlv_record_list** list) -{ - if (!list || !*list) - return; - - oscar_tlv_record_list *now = *list; - - while (now) - { - oscar_tlv_record_list *next = now->next; - - disposeChain(&now->item); - SAFE_FREE((void**)&now); - now = next; - } - - *list = NULL; -} - - -oscar_tlv_chain* oscar_tlv_record_list::getRecordByTLV(WORD wType, int nValue) -{ - oscar_tlv_record_list *list = this; - - while (list) - { - if (list->item && list->item->getTLV(wType, 1) && list->item->getNumber(wType, 1) == nValue) - return list->item; - list = list->next; - } - - return NULL; -} diff --git a/protocols/IcqOscarJ/tlv.h b/protocols/IcqOscarJ/tlv.h deleted file mode 100644 index 5cee00c7c4..0000000000 --- a/protocols/IcqOscarJ/tlv.h +++ /dev/null @@ -1,81 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2008 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __TLV_H -#define __TLV_H - -/*---------* Structures *--------------*/ - -struct oscar_tlv -{ - WORD wType; - WORD wLen; - BYTE *pData; -}; - - -struct oscar_tlv_chain -{ - oscar_tlv tlv; - oscar_tlv_chain *next; - - WORD getChainLength(); - - oscar_tlv* getTLV(WORD wType, WORD wIndex); - oscar_tlv* putTLV(WORD wType, WORD wLen, BYTE *pData, BOOL bReplace); - oscar_tlv_chain* removeTLV(oscar_tlv *tlv); - WORD getLength(WORD wType, WORD wIndex); - - DWORD getDWord(WORD wType, WORD wIndex); - WORD getWord(WORD wType, WORD wIndex); - BYTE getByte(WORD wType, WORD wIndex); - int getNumber(WORD wType, WORD wIndex); - double getDouble(WORD wType, WORD wIndex); - char* getString(WORD wType, WORD wIndex); -}; - - -struct oscar_tlv_record_list -{ - oscar_tlv_chain *item; - oscar_tlv_record_list *next; - - oscar_tlv_chain* getRecordByTLV(WORD wType, int nValue); -}; - -/*---------* Functions *---------------*/ - -oscar_tlv_chain* readIntoTLVChain(BYTE **buf, WORD wLen, int maxTlvs); -void disposeChain(oscar_tlv_chain** chain); - -oscar_tlv_record_list* readIntoTLVRecordList(BYTE **buf, WORD wLen, int nCount); -void disposeRecordList(oscar_tlv_record_list** list); - - -#endif /* __TLV_H */ diff --git a/protocols/IcqOscarJ/utilities.cpp b/protocols/IcqOscarJ/utilities.cpp deleted file mode 100644 index 70f7547108..0000000000 --- a/protocols/IcqOscarJ/utilities.cpp +++ /dev/null @@ -1,2183 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -struct gateway_index -{ - HANDLE hConn; - DWORD dwIndex; -}; - -static icq_critical_section *gatewayMutex = NULL; - -static gateway_index *gateways = NULL; -static int gatewayCount = 0; - -static DWORD *spammerList = NULL; -static int spammerListCount = 0; - - -void MoveDlgItem(HWND hwndDlg, int iItem, int left, int top, int width, int height) -{ - RECT rc; - - rc.left = left; - rc.top = top; - rc.right = left + width; - rc.bottom = top + height; - MapDialogRect(hwndDlg, &rc); - MoveWindow(GetDlgItem(hwndDlg, iItem), rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); -} - - -void EnableDlgItem(HWND hwndDlg, UINT control, int state) -{ - EnableWindow(GetDlgItem(hwndDlg, control), state); -} - - -void ShowDlgItem(HWND hwndDlg, UINT control, int state) -{ - ShowWindow(GetDlgItem(hwndDlg, control), state); -} - - -void icq_EnableMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state) -{ - for (int i = 0; i < cControls; i++) - EnableDlgItem(hwndDlg, controls[i], state); -} - - -void icq_ShowMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state) -{ - for (int i = 0; i < cControls; i++) - ShowDlgItem(hwndDlg, controls[i], state); -} - - -// Maps the ICQ status flag (as seen in the status change SNACS) and returns -// a Miranda style status. -int IcqStatusToMiranda(WORD nIcqStatus) -{ - int nMirandaStatus; - - // :NOTE: The order in which the flags are compared are important! - // I dont like this method but it works. - - if (nIcqStatus & ICQ_STATUSF_INVISIBLE) - nMirandaStatus = ID_STATUS_INVISIBLE; - else - if (nIcqStatus & ICQ_STATUSF_DND) - nMirandaStatus = ID_STATUS_DND; - else - if (nIcqStatus & ICQ_STATUSF_OCCUPIED) - nMirandaStatus = ID_STATUS_OCCUPIED; - else - if (nIcqStatus & ICQ_STATUSF_NA) - nMirandaStatus = ID_STATUS_NA; - else - if (nIcqStatus & ICQ_STATUSF_AWAY) - nMirandaStatus = ID_STATUS_AWAY; - else - if (nIcqStatus & ICQ_STATUSF_FFC) - nMirandaStatus = ID_STATUS_FREECHAT; - else - // Can be discussed, but I think 'online' is the most generic ICQ status - nMirandaStatus = ID_STATUS_ONLINE; - - return nMirandaStatus; -} - -WORD MirandaStatusToIcq(int nMirandaStatus) -{ - WORD nIcqStatus; - - switch (nMirandaStatus) { -case ID_STATUS_ONLINE: - nIcqStatus = ICQ_STATUS_ONLINE; - break; - -case ID_STATUS_AWAY: - nIcqStatus = ICQ_STATUS_AWAY; - break; - -case ID_STATUS_OUTTOLUNCH: -case ID_STATUS_NA: - nIcqStatus = ICQ_STATUS_NA; - break; - -case ID_STATUS_ONTHEPHONE: -case ID_STATUS_OCCUPIED: - nIcqStatus = ICQ_STATUS_OCCUPIED; - break; - -case ID_STATUS_DND: - nIcqStatus = ICQ_STATUS_DND; - break; - -case ID_STATUS_INVISIBLE: - nIcqStatus = ICQ_STATUS_INVISIBLE; - break; - -case ID_STATUS_FREECHAT: - nIcqStatus = ICQ_STATUS_FFC; - break; - -case ID_STATUS_OFFLINE: - // Oscar doesnt have anything that maps to this status. This should never happen. - _ASSERTE(nMirandaStatus != ID_STATUS_OFFLINE); - nIcqStatus = 0; - break; - -default: - // Online seems to be a good default. - // Since it cant be offline, it must be a new type of online status. - nIcqStatus = ICQ_STATUS_ONLINE; - break; - } - - return nIcqStatus; -} - -int MirandaStatusToSupported(int nMirandaStatus) -{ - int nSupportedStatus; - - switch (nMirandaStatus) { - - // These status mode does not need any mapping -case ID_STATUS_ONLINE: -case ID_STATUS_AWAY: -case ID_STATUS_NA: -case ID_STATUS_OCCUPIED: -case ID_STATUS_DND: -case ID_STATUS_INVISIBLE: -case ID_STATUS_OFFLINE: - nSupportedStatus = nMirandaStatus; - break; - -case ID_STATUS_FREECHAT: - nSupportedStatus = ID_STATUS_ONLINE; - break; - - // This mode is not support and must be mapped to something else -case ID_STATUS_OUTTOLUNCH: - nSupportedStatus = ID_STATUS_NA; - break; - - // This mode is not support and must be mapped to something else -case ID_STATUS_ONTHEPHONE: - nSupportedStatus = ID_STATUS_OCCUPIED; - break; - - // This is not supposed to happen. -default: - _ASSERTE(0); - // Online seems to be a good default. - nSupportedStatus = ID_STATUS_ONLINE; - break; - } - - return nSupportedStatus; -} - -char *MirandaStatusToString(int mirandaStatus) -{ - return (char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, mirandaStatus, 0); -} - -char *MirandaStatusToStringUtf(int mirandaStatus) -{ // return miranda status description in utf-8, use unicode service is possible - return tchar_to_utf8((TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, mirandaStatus, GSMDF_TCHAR)); -} - -char** CIcqProto::MirandaStatusToAwayMsg(int nStatus) -{ - switch (nStatus) { - -case ID_STATUS_ONLINE: - return &m_modeMsgs.szOnline; - -case ID_STATUS_AWAY: - return &m_modeMsgs.szAway; - -case ID_STATUS_NA: - return &m_modeMsgs.szNa; - -case ID_STATUS_OCCUPIED: - return &m_modeMsgs.szOccupied; - -case ID_STATUS_DND: - return &m_modeMsgs.szDnd; - -case ID_STATUS_FREECHAT: - return &m_modeMsgs.szFfc; - -default: - return NULL; - } -} - -int AwayMsgTypeToStatus(int nMsgType) -{ - switch (nMsgType) { -case MTYPE_AUTOONLINE: - return ID_STATUS_ONLINE; - -case MTYPE_AUTOAWAY: - return ID_STATUS_AWAY; - -case MTYPE_AUTOBUSY: - return ID_STATUS_OCCUPIED; - -case MTYPE_AUTONA: - return ID_STATUS_NA; - -case MTYPE_AUTODND: - return ID_STATUS_DND; - -case MTYPE_AUTOFFC: - return ID_STATUS_FREECHAT; - -default: - return ID_STATUS_OFFLINE; - } -} - - -void SetGatewayIndex(HANDLE hConn, DWORD dwIndex) -{ - icq_lock l(gatewayMutex); - - for (int i = 0; i < gatewayCount; i++) - { - if (hConn == gateways[i].hConn) - { - gateways[i].dwIndex = dwIndex; - return; - } - } - - gateways = (gateway_index *)SAFE_REALLOC(gateways, sizeof(gateway_index) * (gatewayCount + 1)); - gateways[gatewayCount].hConn = hConn; - gateways[gatewayCount].dwIndex = dwIndex; - gatewayCount++; -} - - -DWORD GetGatewayIndex(HANDLE hConn) -{ - icq_lock l(gatewayMutex); - - for (int i = 0; i < gatewayCount; i++) - { - if (hConn == gateways[i].hConn) - return gateways[i].dwIndex; - } - - return 1; // this is default -} - - -void FreeGatewayIndex(HANDLE hConn) -{ - icq_lock l(gatewayMutex); - - for (int i = 0; i < gatewayCount; i++) - { - if (hConn == gateways[i].hConn) - { - gatewayCount--; - memmove(&gateways[i], &gateways[i+1], sizeof(gateway_index) * (gatewayCount - i)); - gateways = (gateway_index*)SAFE_REALLOC(gateways, sizeof(gateway_index) * gatewayCount); - - // Gateway found, exit loop - break; - } - } -} - - -void CIcqProto::AddToSpammerList(DWORD dwUIN) -{ - icq_lock l(gatewayMutex); - - spammerList = (DWORD *)SAFE_REALLOC(spammerList, sizeof(DWORD) * (spammerListCount + 1)); - spammerList[spammerListCount] = dwUIN; - spammerListCount++; -} - - -BOOL CIcqProto::IsOnSpammerList(DWORD dwUIN) -{ - icq_lock l(gatewayMutex); - - for (int i = 0; i < spammerListCount; i++) - { - if (dwUIN == spammerList[i]) - return TRUE; - } - - return FALSE; -} - - -// ICQ contacts cache - -void CIcqProto::AddToContactsCache(HANDLE hContact, DWORD dwUin, const char *szUid) -{ - if (!hContact || (!dwUin && !szUid)) - return; - -#ifdef _DEBUG - NetLog_Server("Adding contact to cache: %u%s%s", dwUin, dwUin ? "" : " - ", dwUin ? "" : szUid); -#endif - - icq_contacts_cache *cache_item = (icq_contacts_cache*)SAFE_MALLOC(sizeof(icq_contacts_cache)); - cache_item->hContact = hContact; - cache_item->dwUin = dwUin; - if (!dwUin) - cache_item->szUid = null_strdup(szUid); - - icq_lock l(contactsCacheMutex); - contactsCache.insert(cache_item); -} - - -void CIcqProto::InitContactsCache() -{ - if (!gatewayMutex) - gatewayMutex = new icq_critical_section(); - else - gatewayMutex->_Lock(); - - contactsCacheMutex = new icq_critical_section(); - - // build cache - icq_lock l(contactsCacheMutex); - - HANDLE hContact = FindFirstContact(); - - while (hContact) - { - DWORD dwUin; - uid_str szUid; - - if (!getContactUid(hContact, &dwUin, &szUid)) - AddToContactsCache(hContact, dwUin, szUid); - - hContact = FindNextContact(hContact); - } -} - - -void CIcqProto::UninitContactsCache(void) -{ - contactsCacheMutex->Enter(); - - // cleanup the cache - for (int i = 0; i < contactsCache.getCount(); i++) - { - icq_contacts_cache *cache_item = contactsCache[i]; - - SAFE_FREE((void**)&cache_item->szUid); - SAFE_FREE((void**)&cache_item); - } - - contactsCache.destroy(); - - contactsCacheMutex->Leave(); - - SAFE_DELETE(&contactsCacheMutex); - - if (gatewayMutex && gatewayMutex->getLockCount() > 1) - gatewayMutex->_Release(); - else - SAFE_DELETE(&gatewayMutex); -} - - -void CIcqProto::DeleteFromContactsCache(HANDLE hContact) -{ - icq_lock l(contactsCacheMutex); - - for (int i = 0; i < contactsCache.getCount(); i++) - { - icq_contacts_cache *cache_item = contactsCache[i]; - - if (cache_item->hContact == hContact) - { -#ifdef _DEBUG - NetLog_Server("Removing contact from cache: %u%s%s, position: %u", cache_item->dwUin, cache_item->dwUin ? "" : " - ", cache_item->dwUin ? "" : cache_item->szUid, i); -#endif - contactsCache.remove(i); - // Release memory - SAFE_FREE((void**)&cache_item->szUid); - SAFE_FREE((void**)&cache_item); - break; - } - } -} - - -HANDLE CIcqProto::HandleFromCacheByUid(DWORD dwUin, const char *szUid) -{ - icq_contacts_cache cache_item = {NULL, dwUin, szUid}; - - icq_lock l(contactsCacheMutex); - // find in list - int i = contactsCache.getIndex(&cache_item); - if (i != -1) - return contactsCache[i]->hContact; - - return NULL; -} - - -HANDLE CIcqProto::HContactFromUIN(DWORD dwUin, int *Added) -{ - if (Added) *Added = 0; - - HANDLE hContact = HandleFromCacheByUid(dwUin, NULL); - if (hContact) return hContact; - - hContact = FindFirstContact(); - while (hContact) - { - DWORD dwContactUin; - - dwContactUin = getContactUin(hContact); - if (dwContactUin == dwUin) - { - AddToContactsCache(hContact, dwUin, NULL); - return hContact; - } - - hContact = FindNextContact(hContact); - } - - //not present: add - if (Added) - { - hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); - if (!hContact) - { - NetLog_Server("Failed to create ICQ contact %u", dwUin); - return INVALID_HANDLE_VALUE; - } - - if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName) != 0) - { - // For some reason we failed to register the protocol to this contact - CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); - NetLog_Server("Failed to register ICQ contact %u", dwUin); - return INVALID_HANDLE_VALUE; - } - - setSettingDword(hContact, UNIQUEIDSETTING, dwUin); - - if (!bIsSyncingCL) - { - DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); - setContactHidden(hContact, 1); - - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - - icq_QueueUser(hContact); - - if (icqOnline()) - icq_sendNewContact(dwUin, NULL); - } - AddToContactsCache(hContact, dwUin, NULL); - *Added = 1; - - return hContact; - } - - // not in list, check that uin do not belong to us - if (getContactUin(NULL) == dwUin) - return NULL; - - return INVALID_HANDLE_VALUE; -} - - -HANDLE CIcqProto::HContactFromUID(DWORD dwUin, const char *szUid, int *Added) -{ - if (dwUin) - return HContactFromUIN(dwUin, Added); - - if (Added) *Added = 0; - - if (!m_bAimEnabled) return INVALID_HANDLE_VALUE; - - HANDLE hContact = HandleFromCacheByUid(dwUin, szUid); - if (hContact) return hContact; - - hContact = FindFirstContact(); - while (hContact) - { - DWORD dwContactUin; - uid_str szContactUid; - - if (!getContactUid(hContact, &dwContactUin, &szContactUid)) - { - if (!dwContactUin && !stricmpnull(szContactUid, szUid)) - { - if (strcmpnull(szContactUid, szUid)) - { // fix case in SN - setSettingString(hContact, UNIQUEIDSETTING, szUid); - } - return hContact; - } - } - hContact = FindNextContact(hContact); - } - - //not present: add - if (Added) - { - hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); - CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName); - - setSettingString(hContact, UNIQUEIDSETTING, szUid); - - if (!bIsSyncingCL) - { - DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); - setContactHidden(hContact, 1); - - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - - if (icqOnline()) - icq_sendNewContact(0, szUid); - } - AddToContactsCache(hContact, 0, szUid); - *Added = 1; - - return hContact; - } - - return INVALID_HANDLE_VALUE; -} - - -HANDLE CIcqProto::HContactFromAuthEvent(HANDLE hEvent) -{ - DBEVENTINFO dbei = { sizeof(dbei) }; - DWORD body[3]; - - dbei.cbBlob = sizeof(DWORD)*2; - dbei.pBlob = (PBYTE)&body; - - if (CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei)) - return INVALID_HANDLE_VALUE; - - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) - return INVALID_HANDLE_VALUE; - - if (strcmpnull(dbei.szModule, m_szModuleName)) - return INVALID_HANDLE_VALUE; - - return DbGetAuthEventContact(&dbei); -} - -char *NickFromHandle(HANDLE hContact) -{ - if (hContact == INVALID_HANDLE_VALUE) - return null_strdup(Translate("")); - - return null_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0)); -} - -char *NickFromHandleUtf(HANDLE hContact) -{ - if (hContact == INVALID_HANDLE_VALUE) - return ICQTranslateUtf(LPGEN("")); - - return tchar_to_utf8((TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); -} - -char *strUID(DWORD dwUIN, char *pszUID) -{ - if (dwUIN && pszUID) - _ltoa(dwUIN, pszUID, 10); - - return pszUID; -} - - -/* a strlen() that likes NULL */ -int __fastcall strlennull(const char *string) -{ - if (string) - return (int)strlen(string); - - return 0; -} - - -/* a wcslen() that likes NULL */ -int __fastcall strlennull(const WCHAR *string) -{ - if (string) - return (int)wcslen(string); - - return 0; -} - - -/* a strcmp() that likes NULL */ -int __fastcall strcmpnull(const char *str1, const char *str2) -{ - if (str1 && str2) - return strcmp(str1, str2); - - if (!str1 && !str2) - return 0; - - return 1; -} - -/* a stricmp() that likes NULL */ -int __fastcall stricmpnull(const char *str1, const char *str2) -{ - if (str1 && str2) - return _stricmp(str1, str2); - - if (!str1 && !str2) - return 0; - - return 1; -} - -char* __fastcall strstrnull(const char *str, const char *substr) -{ - if (str) - return (char*)strstr(str, substr); - - return NULL; -} - -int null_snprintf(char *buffer, size_t count, const char *fmt, ...) -{ - va_list va; - int len; - - ZeroMemory(buffer, count); - va_start(va, fmt); - len = _vsnprintf(buffer, count-1, fmt, va); - va_end(va); - return len; -} - -int null_snprintf(WCHAR *buffer, size_t count, const WCHAR *fmt, ...) -{ - va_list va; - int len; - - ZeroMemory(buffer, count * sizeof(WCHAR)); - va_start(va, fmt); - len = _vsnwprintf(buffer, count, fmt, va); - va_end(va); - return len; -} - - -char* __fastcall null_strdup(const char *string) -{ - if (string) - return _strdup(string); - - return NULL; -} - - -WCHAR* __fastcall null_strdup(const WCHAR *string) -{ - if (string) - return wcsdup(string); - - return NULL; -} - - -char* __fastcall null_strcpy(char *dest, const char *src, size_t maxlen) -{ - if (!dest) - return NULL; - - if (src && src[0]) - { - strncpy(dest, src, maxlen); - dest[maxlen] = '\0'; - } - else - dest[0] = '\0'; - - return dest; -} - - -WCHAR* __fastcall null_strcpy(WCHAR *dest, const WCHAR *src, size_t maxlen) -{ - if (!dest) - return NULL; - - if (src && src[0]) - { - wcsncpy(dest, src, maxlen); - dest[maxlen] = '\0'; - } - else - dest[0] = '\0'; - - return dest; -} - - -int __fastcall null_strcut(char *string, int maxlen) -{ // limit the string to max length (null & utf-8 strings ready) - int len = (int)strlennull(string); - - if (len < maxlen) - return len; - - len = maxlen; - - if (UTF8_IsValid(string)) // handle utf-8 string - { // find the first byte of possible multi-byte character - while ((string[len] & 0xc0) == 0x80) len--; - } - // simply cut the string - string[len] = '\0'; - - return len; -} - - -void parseServerAddress(char* szServer, WORD* wPort) -{ - int i = 0; - - while (szServer[i] && szServer[i] != ':') i++; - if (szServer[i] == ':') - { // port included - *wPort = atoi(&szServer[i + 1]); - } // otherwise do not change port - - szServer[i] = '\0'; -} - -char *DemangleXml(const char *string, int len) -{ - char *szWork = (char*)SAFE_MALLOC(len+1), *szChar = szWork; - int i; - - for (i=0; i') l += 4; else if (string[i]=='&') l += 5; else if (string[i]=='"') l += 6; else l++; - } - szChar = szWork = (char*)SAFE_MALLOC(l + 1); - for (i = 0; i') - { - *(DWORD*)szChar = ';tg&'; - szChar += 4; - } - else if (string[i]=='&') - { - *(DWORD*)szChar = 'pma&'; - szChar += 4; - *szChar = ';'; - szChar++; - } - else if (string[i]=='"') - { - *(DWORD*)szChar = 'ouq&'; - szChar += 4; - *(WORD*)szChar = ';t'; - szChar += 2; - } - else - { - *szChar = string[i]; - szChar++; - } - } - *szChar = '\0'; - - return szWork; -} - -char *EliminateHtml(const char *string, int len) -{ - char *tmp = (char*)SAFE_MALLOC(len + 1); - int i,j; - BOOL tag = FALSE; - char *res; - - for (i=0,j=0;i", 4) || !_strnicmp(string + i, "
", 5))) - { // insert newline - tmp[j] = '\r'; - j++; - tmp[j] = '\n'; - j++; - } - tag = TRUE; - } - else if (tag && string[i] == '>') - { - tag = FALSE; - } - else if (!tag) - { - tmp[j] = string[i]; - j++; - } - tmp[j] = '\0'; - } - SAFE_FREE((void**)&string); - res = DemangleXml(tmp, strlennull(tmp)); - SAFE_FREE((void**)&tmp); - - return res; -} - -char *ApplyEncoding(const char *string, const char *pszEncoding) -{ // decode encoding to Utf-8 - if (string && pszEncoding) - { // we do only encodings known to icq5.1 // TODO: check if this is enough - if (!_strnicmp(pszEncoding, "utf-8", 5)) - { // it is utf-8 encoded - return null_strdup(string); - } - if (!_strnicmp(pszEncoding, "unicode-2-0", 11)) - { // it is UCS-2 encoded - int wLen = strlennull((WCHAR*)string) + 1; - WCHAR *szStr = (WCHAR*)_alloca(wLen*2); - BYTE *tmp = (BYTE*)string; - - unpackWideString(&tmp, szStr, (WORD)(wLen*2)); - - return make_utf8_string(szStr); - } - if (!_strnicmp(pszEncoding, "iso-8859-1", 10)) - { // we use "Latin I" instead - it does the job - return ansi_to_utf8_codepage(string, 1252); - } - } - if (string) - { // consider it CP_ACP - return ansi_to_utf8(string); - } - - return NULL; -} - -void CIcqProto::ResetSettingsOnListReload() -{ - // Reset a bunch of session specific settings - setSettingWord(NULL, DBSETTING_SERVLIST_PRIVACY, 0); - setSettingWord(NULL, DBSETTING_SERVLIST_METAINFO, 0); - setSettingWord(NULL, DBSETTING_SERVLIST_AVATAR, 0); - setSettingWord(NULL, DBSETTING_SERVLIST_PHOTO, 0); - setSettingWord(NULL, "SrvRecordCount", 0); - deleteSetting(NULL, DBSETTING_SERVLIST_UNHANDLED); - - HANDLE hContact = FindFirstContact(); - - while (hContact) - { - // All these values will be restored during the serv-list receive - setSettingWord(hContact, DBSETTING_SERVLIST_ID, 0); - setSettingWord(hContact, DBSETTING_SERVLIST_GROUP, 0); - setSettingWord(hContact, DBSETTING_SERVLIST_PERMIT, 0); - setSettingWord(hContact, DBSETTING_SERVLIST_DENY, 0); - deleteSetting(hContact, DBSETTING_SERVLIST_IGNORE); - setSettingByte(hContact, "Auth", 0); - deleteSetting(hContact, DBSETTING_SERVLIST_DATA); - - hContact = FindNextContact(hContact); - } - - FlushSrvGroupsCache(); -} - -void CIcqProto::ResetSettingsOnConnect() -{ - // Reset a bunch of session specific settings - setSettingByte(NULL, "SrvVisibility", 0); - setSettingDword(NULL, "IdleTS", 0); - - HANDLE hContact = FindFirstContact(); - - while (hContact) - { - setSettingDword(hContact, "LogonTS", 0); - setSettingDword(hContact, "IdleTS", 0); - setSettingDword(hContact, "TickTS", 0); - setSettingByte(hContact, "TemporaryVisible", 0); - - // All these values will be restored during the login - if (getContactStatus(hContact) != ID_STATUS_OFFLINE) - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - - hContact = FindNextContact(hContact); - } -} - -void CIcqProto::ResetSettingsOnLoad() -{ - setSettingDword(NULL, "IdleTS", 0); - setSettingDword(NULL, "LogonTS", 0); - - HANDLE hContact = FindFirstContact(); - - while (hContact) - { - setSettingDword(hContact, "LogonTS", 0); - setSettingDword(hContact, "IdleTS", 0); - setSettingDword(hContact, "TickTS", 0); - if (getContactStatus(hContact) != ID_STATUS_OFFLINE) - { - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - - deleteSetting(hContact, DBSETTING_XSTATUS_ID); - deleteSetting(hContact, DBSETTING_XSTATUS_NAME); - deleteSetting(hContact, DBSETTING_XSTATUS_MSG); - } - setSettingByte(hContact, "DCStatus", 0); - - hContact = FindNextContact(hContact); - } -} - -int RandRange(int nLow, int nHigh) -{ - return nLow + (int)((nHigh-nLow+1)*rand()/(RAND_MAX+1.0)); -} - - -BOOL IsStringUIN(const char *pszString) -{ - int i; - int nLen = strlennull(pszString); - - if (nLen > 0 && pszString[0] != '0') - { - for (i=0; i '9')) - return FALSE; - - return TRUE; - } - - return FALSE; -} - - -void __cdecl CIcqProto::ProtocolAckThread(icq_ack_args* pArguments) -{ - Sleep(150); - - if (pArguments->nAckResult == ACKRESULT_SUCCESS) - NetLog_Server("Sent fake message ack"); - else if (pArguments->nAckResult == ACKRESULT_FAILED) - NetLog_Server("Message delivery failed"); - - BroadcastAck(pArguments->hContact, pArguments->nAckType, pArguments->nAckResult, pArguments->hSequence, pArguments->pszMessage); - - SAFE_FREE((void**)(char **)&pArguments->pszMessage); - SAFE_FREE((void**)&pArguments); -} - -void CIcqProto::SendProtoAck(HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage) -{ - icq_ack_args* pArgs = (icq_ack_args*)SAFE_MALLOC(sizeof(icq_ack_args)); // This will be freed in the new thread - pArgs->hContact = hContact; - pArgs->hSequence = (HANDLE)dwCookie; - pArgs->nAckResult = nAckResult; - pArgs->nAckType = nAckType; - pArgs->pszMessage = (LPARAM)null_strdup(pszMessage); - - ForkThread(( IcqThreadFunc )&CIcqProto::ProtocolAckThread, pArgs ); -} - -void CIcqProto::SetCurrentStatus(int nStatus) -{ - int nOldStatus = m_iStatus; - - m_iStatus = nStatus; - BroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, nStatus); -} - - -int CIcqProto::IsMetaInfoChanged(HANDLE hContact) -{ - DBVARIANT infoToken = {DBVT_DELETED}; - int res = 0; - - if (!getSetting(hContact, DBSETTING_METAINFO_TOKEN, &infoToken)) - { // contact does have info from directory, check if it is not outdated - double dInfoTime = 0; - double dInfoSaved = 0; - - if ((dInfoTime = getSettingDouble(hContact, DBSETTING_METAINFO_TIME, 0)) > 0) - { - if ((dInfoSaved = getSettingDouble(hContact, DBSETTING_METAINFO_SAVED, 0)) > 0) - { - if (dInfoSaved < dInfoTime) - res = 2; // directory info outdated - } - else - res = 1; // directory info not saved at all - } - - ICQFreeVariant(&infoToken); - } - else - { // it cannot be detected if user info was not changed, so use a generic threshold - DBVARIANT infoSaved = {DBVT_DELETED}; - DWORD dwInfoTime = 0; - - if (!getSetting(hContact, DBSETTING_METAINFO_SAVED, &infoSaved)) - { - if (infoSaved.type == DBVT_BLOB && infoSaved.cpbVal == 8) - { - double dwTime = *(double*)infoSaved.pbVal; - - dwInfoTime = (dwTime - 25567) * 86400; - } - else if (infoSaved.type == DBVT_DWORD) - dwInfoTime = infoSaved.dVal; - - ICQFreeVariant(&infoSaved); - - if ((time(NULL) - dwInfoTime) > 14*3600*24) - { - res = 3; // threshold exceeded - } - } - else - res = 4; // no timestamp found - } - - return res; -} - - -void __cdecl CIcqProto::SetStatusNoteThread(void *pDelay) -{ - if (pDelay) - SleepEx((DWORD)pDelay, TRUE); - - cookieMutex->Enter(); - - if (icqOnline() && (setStatusNoteText || setStatusMoodData)) - { // send status note change packets, write status note to database - if (setStatusNoteText) - { // change status note in directory - m_ratesMutex->Enter(); - if (m_rates) - { // rate management - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); - - while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_LIMIT)) - { // we are over rate, need to wait before sending - int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_10); - - m_ratesMutex->Leave(); - cookieMutex->Leave(); -#ifdef _DEBUG - NetLog_Server("Rates: SetStatusNote delayed %dms", nDelay); -#endif - SleepEx(nDelay, TRUE); // do not keep things locked during sleep - cookieMutex->Enter(); - m_ratesMutex->Enter(); - if (!m_rates) // we lost connection when we slept, go away - break; - } - } - m_ratesMutex->Leave(); - - BYTE *pBuffer = NULL; - int cbBuffer = 0; - - ppackTLV(&pBuffer, &cbBuffer, 0x226, strlennull(setStatusNoteText), (BYTE*)setStatusNoteText); - icq_changeUserDirectoryInfoServ(pBuffer, cbBuffer, DIRECTORYREQUEST_UPDATENOTE); - - SAFE_FREE((void**)&pBuffer); - } - - if (setStatusNoteText || setStatusMoodData) - { // change status note and mood in session data - m_ratesMutex->Enter(); - if (m_rates) - { // rate management - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); - - while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_LIMIT)) - { // we are over rate, need to wait before sending - int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_10); - - m_ratesMutex->Leave(); - cookieMutex->Leave(); -#ifdef _DEBUG - NetLog_Server("Rates: SetStatusNote delayed %dms", nDelay); -#endif - SleepEx(nDelay, TRUE); // do not keep things locked during sleep - cookieMutex->Enter(); - m_ratesMutex->Enter(); - if (!m_rates) // we lost connection when we slept, go away - break; - } - } - m_ratesMutex->Leave(); - - // check if the session data were not updated already - char *szCurrentStatusNote = getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL); - char *szCurrentStatusMood = NULL; - DBVARIANT dbv = {DBVT_DELETED}; - - if (m_bMoodsEnabled && !getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) - szCurrentStatusMood = dbv.pszVal; - - if (!setStatusNoteText && szCurrentStatusNote) - setStatusNoteText = null_strdup(szCurrentStatusNote); - if (m_bMoodsEnabled && !setStatusMoodData && szCurrentStatusMood) - setStatusMoodData = null_strdup(szCurrentStatusMood); - - if (strcmpnull(szCurrentStatusNote, setStatusNoteText) || (m_bMoodsEnabled && strcmpnull(szCurrentStatusMood, setStatusMoodData))) - { - setSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, setStatusNoteText); - if (m_bMoodsEnabled) - setSettingString(NULL, DBSETTING_STATUS_MOOD, setStatusMoodData); - - WORD wStatusNoteLen = strlennull(setStatusNoteText); - WORD wStatusMoodLen = m_bMoodsEnabled ? strlennull(setStatusMoodData) : 0; - icq_packet packet; - WORD wDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4; - - serverPacketInit(&packet, wDataLen + 14); - packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS); - // Change only session data - packWord(&packet, 0x1D); // TLV 1D - packWord(&packet, wDataLen); // TLV length - packWord(&packet, 0x02); // Item Type - if (wStatusNoteLen) - { - packWord(&packet, 0x400 | (WORD)(wStatusNoteLen + 4)); // Flags + Item Length - packWord(&packet, wStatusNoteLen); // Text Length - packBuffer(&packet, (LPBYTE)setStatusNoteText, wStatusNoteLen); - packWord(&packet, 0); // Encoding not specified (utf-8 is default) - } - else - packWord(&packet, 0); // Flags + Item Length - packWord(&packet, 0x0E); // Item Type - packWord(&packet, wStatusMoodLen); // Flags + Item Length - if (wStatusMoodLen) - packBuffer(&packet, (LPBYTE)setStatusMoodData, wStatusMoodLen); // Mood - - sendServPacket(&packet); - } - SAFE_FREE(&szCurrentStatusNote); - ICQFreeVariant(&dbv); - } - } - SAFE_FREE(&setStatusNoteText); - SAFE_FREE(&setStatusMoodData); - - cookieMutex->Leave(); -} - - -int CIcqProto::SetStatusNote(const char *szStatusNote, DWORD dwDelay, int bForce) -{ - int bChanged = FALSE; - - // bForce is intended for login sequence - need to call this earlier than icqOnline() - // the process is delayed and icqOnline() is ready when needed inside SetStatusNoteThread() - if (!bForce && !icqOnline()) return bChanged; - - // reuse generic critical section (used for cookies list and object variables locks) - icq_lock l(cookieMutex); - - if (!setStatusNoteText && (!m_bMoodsEnabled || !setStatusMoodData)) - { // check if the status note was changed and if yes, create thread to change it - char *szCurrentStatusNote = getSettingStringUtf(NULL, DBSETTING_STATUS_NOTE, NULL); - - if (strcmpnull(szCurrentStatusNote, szStatusNote)) - { // status note was changed - // create thread to change status note on existing server connection - setStatusNoteText = null_strdup(szStatusNote); - - if (dwDelay) - ForkThread(&CIcqProto::SetStatusNoteThread, (void*)dwDelay); - else // we cannot afford any delay, so do not run in separate thread - SetStatusNoteThread(NULL); - - bChanged = TRUE; - } - SAFE_FREE(&szCurrentStatusNote); - } - else - { // only alter status note object with new status note, keep the thread waiting for execution - SAFE_FREE(&setStatusNoteText); - setStatusNoteText = null_strdup(szStatusNote); - - bChanged = TRUE; - } - - return bChanged; -} - - -int CIcqProto::SetStatusMood(const char *szMoodData, DWORD dwDelay) -{ - int bChanged = FALSE; - - if (!icqOnline()) return bChanged; - - // reuse generic critical section (used for cookies list and object variables locks) - icq_lock l(cookieMutex); - - if (!setStatusNoteText && !setStatusMoodData) - { // check if the status mood was changed and if yes, create thread to change it - char *szCurrentStatusMood = NULL; - DBVARIANT dbv = {DBVT_DELETED}; - - if (!getSettingString(NULL, DBSETTING_STATUS_MOOD, &dbv)) - szCurrentStatusMood = dbv.pszVal; - - if (strcmpnull(szCurrentStatusMood, szMoodData)) - { // status mood was changed - // create thread to change status mood on existing server connection - setStatusMoodData = null_strdup(szMoodData); - if (dwDelay) - ForkThread(&CIcqProto::SetStatusNoteThread, (void*)dwDelay); - else // we cannot afford any delay, so do not run in separate thread - SetStatusNoteThread(NULL); - - bChanged = TRUE; - } - ICQFreeVariant(&dbv); - } - else - { // only alter status mood object with new status mood, keep the thread waiting for execution - SAFE_FREE(&setStatusMoodData); - setStatusMoodData = null_strdup(szMoodData); - - bChanged = TRUE; - } - - return bChanged; -} - - -void CIcqProto::writeDbInfoSettingTLVStringUtf(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - oscar_tlv *pTLV = chain->getTLV(wTlv, 1); - - if (pTLV && pTLV->wLen > 0) - { - char *str = (char*)_alloca(pTLV->wLen + 1); - - memcpy(str, pTLV->pData, pTLV->wLen); - str[pTLV->wLen] = '\0'; - setSettingStringUtf(hContact, szSetting, str); - } - else - deleteSetting(hContact, szSetting); -} - - -void CIcqProto::writeDbInfoSettingTLVString(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - oscar_tlv *pTLV = chain->getTLV(wTlv, 1); - - if (pTLV && pTLV->wLen > 0) - { - char *str = (char*)_alloca(pTLV->wLen + 1); - - memcpy(str, pTLV->pData, pTLV->wLen); - str[pTLV->wLen] = '\0'; - setSettingString(hContact, szSetting, str); - } - else - deleteSetting(hContact, szSetting); -} - - -void CIcqProto::writeDbInfoSettingTLVWord(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - int num = chain->getNumber(wTlv, 1); - - if (num > 0) - setSettingWord(hContact, szSetting, num); - else - deleteSetting(hContact, szSetting); -} - - -void CIcqProto::writeDbInfoSettingTLVByte(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - int num = chain->getNumber(wTlv, 1); - - if (num > 0) - setSettingByte(hContact, szSetting, num); - else - deleteSetting(hContact, szSetting); -} - - -void CIcqProto::writeDbInfoSettingTLVDouble(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - double num = chain->getDouble(wTlv, 1); - - if (num > 0) - setSettingDouble(hContact, szSetting, num); - else - deleteSetting(hContact, szSetting); -} - -void CIcqProto::writeDbInfoSettingTLVDate(HANDLE hContact, const char* szSettingYear, const char* szSettingMonth, const char* szSettingDay, oscar_tlv_chain* chain, WORD wTlv) -{ - double time = chain->getDouble(wTlv, 1); - - if (time > 0) - { // date is stored as double with unit equal to a day, incrementing since 1/1/1900 0:00 GMT - SYSTEMTIME sTime = {0}; - if (VariantTimeToSystemTime(time + 2, &sTime)) - { - setSettingWord(hContact, szSettingYear, sTime.wYear); - setSettingByte(hContact, szSettingMonth, (BYTE)sTime.wMonth); - setSettingByte(hContact, szSettingDay, (BYTE)sTime.wDay); - } - else - { - deleteSetting(hContact, szSettingYear); - deleteSetting(hContact, szSettingMonth); - deleteSetting(hContact, szSettingDay); - } - } - else - { - deleteSetting(hContact, szSettingYear); - deleteSetting(hContact, szSettingMonth); - deleteSetting(hContact, szSettingDay); - } -} - - -void CIcqProto::writeDbInfoSettingTLVBlob(HANDLE hContact, const char *szSetting, oscar_tlv_chain *chain, WORD wTlv) -{ - oscar_tlv *pTLV = chain->getTLV(wTlv, 1); - - if (pTLV && pTLV->wLen > 0) - setSettingBlob(hContact, szSetting, pTLV->pData, pTLV->wLen); - else - deleteSetting(hContact, szSetting); -} - - -BOOL CIcqProto::writeDbInfoSettingString(HANDLE hContact, const char* szSetting, char** buf, WORD* pwLength) -{ - WORD wLen; - - if (*pwLength < 2) - return FALSE; - - unpackLEWord((LPBYTE*)buf, &wLen); - *pwLength -= 2; - - if (*pwLength < wLen) - return FALSE; - - if ((wLen > 0) && (**buf) && ((*buf)[wLen-1]==0)) // Make sure we have a proper string - { - WORD wCp = getSettingWord(hContact, "InfoCodePage", getSettingWord(hContact, "InfoCP", CP_ACP)); - - if (wCp != CP_ACP) - { - char *szUtf = ansi_to_utf8_codepage(*buf, wCp); - - if (szUtf) - { - setSettingStringUtf(hContact, szSetting, szUtf); - SAFE_FREE((void**)&szUtf); - } - else - setSettingString(hContact, szSetting, *buf); - } - else - setSettingString(hContact, szSetting, *buf); - } - else - deleteSetting(hContact, szSetting); - - *buf += wLen; - *pwLength -= wLen; - - return TRUE; -} - -BOOL CIcqProto::writeDbInfoSettingWord(HANDLE hContact, const char *szSetting, char **buf, WORD* pwLength) -{ - WORD wVal; - - - if (*pwLength < 2) - return FALSE; - - unpackLEWord((LPBYTE*)buf, &wVal); - *pwLength -= 2; - - if (wVal != 0) - setSettingWord(hContact, szSetting, wVal); - else - deleteSetting(hContact, szSetting); - - return TRUE; -} - -BOOL CIcqProto::writeDbInfoSettingWordWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength) -{ - WORD wVal; - char sbuf[MAX_PATH]; - char *text; - - if (*pwLength < 2) - return FALSE; - - unpackLEWord((LPBYTE*)buf, &wVal); - *pwLength -= 2; - - text = LookupFieldNameUtf(table, wVal, sbuf, MAX_PATH); - if (text) - setSettingStringUtf(hContact, szSetting, text); - else - deleteSetting(hContact, szSetting); - - return TRUE; -} - -BOOL CIcqProto::writeDbInfoSettingByte(HANDLE hContact, const char *pszSetting, char **buf, WORD* pwLength) -{ - BYTE byVal; - - if (*pwLength < 1) - return FALSE; - - unpackByte((LPBYTE*)buf, &byVal); - *pwLength -= 1; - - if (byVal != 0) - setSettingByte(hContact, pszSetting, byVal); - else - deleteSetting(hContact, pszSetting); - - return TRUE; -} - -BOOL CIcqProto::writeDbInfoSettingByteWithTable(HANDLE hContact, const char *szSetting, const FieldNamesItem *table, char **buf, WORD* pwLength) -{ - BYTE byVal; - char sbuf[MAX_PATH]; - char *text; - - if (*pwLength < 1) - return FALSE; - - unpackByte((LPBYTE*)buf, &byVal); - *pwLength -= 1; - - text = LookupFieldNameUtf(table, byVal, sbuf, MAX_PATH); - if (text) - setSettingStringUtf(hContact, szSetting, text); - else - deleteSetting(hContact, szSetting); - - return TRUE; -} - -char* time2text(time_t time) -{ - tm *local = localtime(&time); - - if (local) - { - char *str = asctime(local); - str[24] = '\0'; // remove new line - return str; - } - else - return ""; -} - - -BOOL CIcqProto::validateStatusMessageRequest(HANDLE hContact, WORD byMessageType) -{ - // Privacy control - if (getSettingByte(NULL, "StatusMsgReplyCList", 0)) - { - // Don't send statusmessage to unknown contacts - if (hContact == INVALID_HANDLE_VALUE) - return FALSE; - - // Don't send statusmessage to temporary contacts or hidden contacts - if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) || - DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) - return FALSE; - - // Don't send statusmessage to invisible contacts - if (getSettingByte(NULL, "StatusMsgReplyVisible", 0)) - { - WORD wStatus = getContactStatus(hContact); - if (wStatus == ID_STATUS_OFFLINE) - return FALSE; - } - } - - // Dont send messages to people you are hiding from - if (hContact != INVALID_HANDLE_VALUE && - getSettingWord(hContact, "ApparentMode", 0) == ID_STATUS_OFFLINE) - { - return FALSE; - } - - // Dont respond to request for other statuses than your current one - if ((byMessageType == MTYPE_AUTOONLINE && m_iStatus != ID_STATUS_ONLINE) || - (byMessageType == MTYPE_AUTOAWAY && m_iStatus != ID_STATUS_AWAY) || - (byMessageType == MTYPE_AUTOBUSY && m_iStatus != ID_STATUS_OCCUPIED) || - (byMessageType == MTYPE_AUTONA && m_iStatus != ID_STATUS_NA) || - (byMessageType == MTYPE_AUTODND && m_iStatus != ID_STATUS_DND) || - (byMessageType == MTYPE_AUTOFFC && m_iStatus != ID_STATUS_FREECHAT)) - { - return FALSE; - } - - if (hContact != INVALID_HANDLE_VALUE && m_iStatus==ID_STATUS_INVISIBLE && - getSettingWord(hContact, "ApparentMode", 0) != ID_STATUS_ONLINE) - { - if (!getSettingByte(hContact, "TemporaryVisible", 0)) - { // Allow request to temporary visible contacts - return FALSE; - } - } - - // All OK! - return TRUE; -} - - -void __fastcall SAFE_DELETE(MZeroedObject **p) -{ - if (*p) - { - delete *p; - *p = NULL; - } -} - - -void __fastcall SAFE_DELETE(lockable_struct **p) -{ - if (*p) - { - (*p)->_Release(); - *p = NULL; - } -} - - -void __fastcall SAFE_FREE(void** p) -{ - if (*p) - { - free(*p); - *p = NULL; - } -} - - -void* __fastcall SAFE_MALLOC(size_t size) -{ - void* p = NULL; - - if (size) - { - p = malloc(size); - - if (p) - ZeroMemory(p, size); - } - return p; -} - - -void* __fastcall SAFE_REALLOC(void* p, size_t size) -{ - if (p) - { - return realloc(p, size); - } - else - return SAFE_MALLOC(size); -} - - -DWORD ICQWaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds, int bWaitAlways) -{ - DWORD dwResult; - - do { // will get WAIT_IO_COMPLETION for QueueUserAPC(), ignore it unless terminating - dwResult = WaitForSingleObjectEx(hObject, dwMilliseconds, TRUE); - } while (dwResult == WAIT_IO_COMPLETION && (bWaitAlways || !Miranda_Terminated())); - - return dwResult; -} - - -HANDLE NetLib_OpenConnection(HANDLE hUser, const char* szIdent, NETLIBOPENCONNECTION* nloc) -{ - Netlib_Logf(hUser, "%sConnecting to %s:%u", szIdent?szIdent:"", nloc->szHost, nloc->wPort); - - nloc->cbSize = sizeof(NETLIBOPENCONNECTION); - nloc->flags |= NLOCF_V2; - - return (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hUser, (LPARAM)nloc); -} - - -HANDLE CIcqProto::NetLib_BindPort(NETLIBNEWCONNECTIONPROC_V2 pFunc, void* lParam, WORD* pwPort, DWORD* pdwIntIP) -{ - NETLIBBIND nlb = {0}; - - nlb.cbSize = sizeof(NETLIBBIND); - nlb.pfnNewConnectionV2 = pFunc; - nlb.pExtra = lParam; - SetLastError(ERROR_INVALID_PARAMETER); // this must be here - NetLib does not set any error :(( - - HANDLE hBoundPort = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hDirectNetlibUser, (LPARAM)&nlb); - - if (pwPort) *pwPort = nlb.wPort; - if (pdwIntIP) *pdwIntIP = nlb.dwInternalIP; - - return hBoundPort; -} - - -void NetLib_CloseConnection(HANDLE *hConnection, int bServerConn) -{ - if (*hConnection) - { - NetLib_SafeCloseHandle(hConnection); - - if (bServerConn) - FreeGatewayIndex(*hConnection); - } -} - - -void NetLib_SafeCloseHandle(HANDLE *hConnection) -{ - if (*hConnection) - { - Netlib_CloseHandle(*hConnection); - *hConnection = NULL; - } -} - - -int CIcqProto::NetLog_Server(const char *fmt,...) -{ - va_list va; - char szText[1024]; - - va_start(va,fmt); - mir_vsnprintf(szText,sizeof(szText),fmt,va); - va_end(va); - return CallService(MS_NETLIB_LOG,(WPARAM)m_hServerNetlibUser,(LPARAM)szText); -} - -int CIcqProto::NetLog_Direct(const char *fmt,...) -{ - va_list va; - char szText[1024]; - - va_start(va,fmt); - mir_vsnprintf(szText,sizeof(szText),fmt,va); - va_end(va); - return CallService(MS_NETLIB_LOG,(WPARAM)m_hDirectNetlibUser,(LPARAM)szText); -} - -int CIcqProto::NetLog_Uni(BOOL bDC, const char *fmt,...) -{ - va_list va; - char szText[1024]; - HANDLE hNetlib; - - va_start(va,fmt); - mir_vsnprintf(szText,sizeof(szText),fmt,va); - va_end(va); - - if (bDC) - hNetlib = m_hDirectNetlibUser; - else - hNetlib = m_hServerNetlibUser; - - return CallService(MS_NETLIB_LOG,(WPARAM)hNetlib,(LPARAM)szText); -} - -int CIcqProto::BroadcastAck(HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam) -{ - ACKDATA ack={0}; - - ack.cbSize = sizeof(ACKDATA); - ack.szModule = m_szModuleName; - ack.hContact = hContact; - ack.type = type; - ack.result = result; - ack.hProcess = hProcess; - ack.lParam = lParam; - return CallService(MS_PROTO_BROADCASTACK,0,(LPARAM)&ack); -} - -char* __fastcall ICQTranslateUtf(const char *src) -{ // this takes UTF-8 strings only!!! - char *szRes = NULL; - - if (!strlennull(src)) - { // for the case of empty strings - return null_strdup(src); - } - - { // we can use unicode translate (0.5+) - WCHAR* usrc = make_unicode_string(src); - - szRes = make_utf8_string(TranslateW(usrc)); - - SAFE_FREE((void**)&usrc); - } - return szRes; -} - -char* __fastcall ICQTranslateUtfStatic(const char *src, char *buf, size_t bufsize) -{ // this takes UTF-8 strings only!!! - if (strlennull(src)) - { // we can use unicode translate (0.5+) - WCHAR *usrc = make_unicode_string(src); - - make_utf8_string_static(TranslateW(usrc), buf, bufsize); - - SAFE_FREE((void**)&usrc); - } - else - buf[0] = '\0'; - - return buf; -} - -void CIcqProto::ForkThread( IcqThreadFunc pFunc, void* arg ) -{ - CloseHandle(( HANDLE )mir_forkthreadowner(( pThreadFuncOwner )*( void** )&pFunc, this, arg, NULL )); -} - -HANDLE CIcqProto::ForkThreadEx( IcqThreadFunc pFunc, void* arg, UINT* threadID ) -{ - return ( HANDLE )mir_forkthreadowner(( pThreadFuncOwner )*( void** )&pFunc, this, arg, threadID ); -} - - -char* CIcqProto::GetUserStoredPassword(char *szBuffer, int cbSize) -{ - if (!getSettingStringStatic(NULL, "Password", szBuffer, cbSize)) - { - CallService(MS_DB_CRYPT_DECODESTRING, strlennull(szBuffer) + 1, (LPARAM)szBuffer); - - if (strlennull(szBuffer)) - return szBuffer; - } - return NULL; -} - - -char* CIcqProto::GetUserPassword(BOOL bAlways) -{ - if (m_szPassword[0] != '\0' && (m_bRememberPwd || bAlways)) - return m_szPassword; - - if (GetUserStoredPassword(m_szPassword, sizeof(m_szPassword))) - { - m_bRememberPwd = TRUE; - - return m_szPassword; - } - - return NULL; -} - - -WORD CIcqProto::GetMyStatusFlags() -{ - WORD wFlags = 0; - - // Webaware setting bit flag - if (getSettingByte(NULL, "WebAware", 0)) - wFlags |= STATUS_WEBAWARE; - - // DC setting bit flag - switch (getSettingByte(NULL, "DCType", 0)) - { - case 0: - break; - - case 1: - wFlags |= STATUS_DCCONT; - break; - - case 2: - wFlags |= STATUS_DCAUTH; - break; - - default: - wFlags |= STATUS_DCDISABLED; - break; - } - return wFlags; -} - - -int IsValidRelativePath(const char *filename) -{ - if (strstrnull(filename, "..\\") || strstrnull(filename, "../") || - strstrnull(filename, ":\\") || strstrnull(filename, ":/") || - filename[0] == '\\' || filename[0] == '/') - return 0; // Contains malicious chars, Failure - - return 1; // Success -} - - -const char* ExtractFileName(const char *fullname) -{ - const char *szFileName; - - // already is only filename - if (((szFileName = strrchr(fullname, '\\')) == NULL) && ((szFileName = strrchr(fullname, '/')) == NULL)) - return fullname; - - return szFileName + 1; // skip backslash -} - - -char* FileNameToUtf(const TCHAR *filename) -{ - // reasonable only on NT systems - HINSTANCE hKernel = GetModuleHandle(_T("KERNEL32")); - DWORD (CALLBACK *RealGetLongPathName)(LPCWSTR, LPWSTR, DWORD); - - *(FARPROC *)&RealGetLongPathName = GetProcAddress(hKernel, "GetLongPathNameW"); - - if (RealGetLongPathName) - { // the function is available (it is not on old NT systems) - WCHAR *usFileName = NULL; - int wchars = RealGetLongPathName(filename, usFileName, 0); - usFileName = (WCHAR*)_alloca((wchars + 1) * sizeof(WCHAR)); - RealGetLongPathName(filename, usFileName, wchars); - - return make_utf8_string(usFileName); - } - return make_utf8_string(filename); -} - - -int FileAccessUtf(const char *path, int mode) -{ - int size = strlennull(path) + 2; - TCHAR *szPath = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(path, szPath, size)) - return _taccess(szPath, mode); - - return -1; -} - - -int FileStatUtf(const char *path, struct _stati64 *buffer) -{ - int size = strlennull(path) + 2; - TCHAR *szPath = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(path, szPath, size)) - return _tstati64(szPath, buffer); - - return -1; -} - - -int MakeDirUtf(const char *dir) -{ - int wRes = -1; - int size = strlennull(dir) + 2; - TCHAR *szDir = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(dir, szDir, size)) - { // _tmkdir can created only one dir at once - wRes = _tmkdir(szDir); - // check if dir not already existed - return success if yes - if (wRes == -1 && errno == 17 /* EEXIST */) - wRes = 0; - else if (wRes && errno == 2 /* ENOENT */) - { // failed, try one directory less first - char *szLast = (char*)strrchr(dir, '\\'); - if (!szLast) szLast = (char*)strrchr(dir, '/'); - if (szLast) - { - char cOld = *szLast; - - *szLast = '\0'; - if (!MakeDirUtf(dir)) - wRes = _tmkdir(szDir); - - *szLast = cOld; - } - } - } - - return wRes; -} - - -int OpenFileUtf(const char *filename, int oflag, int pmode) -{ - int size = strlennull(filename) + 2; - TCHAR *szFile = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(filename, szFile, size)) - return _topen(szFile, oflag, pmode); - - return -1; -} - - -WCHAR *GetWindowTextUcs(HWND hWnd) -{ - WCHAR *utext; - int nLen = GetWindowTextLengthW(hWnd); - utext = (WCHAR*)SAFE_MALLOC((nLen+2)*sizeof(WCHAR)); - GetWindowTextW(hWnd, utext, nLen + 1); - return utext; -} - - -void SetWindowTextUcs(HWND hWnd, WCHAR *text) -{ - SetWindowTextW(hWnd, text); -} - - -char* GetWindowTextUtf(HWND hWnd) -{ - int nLen = GetWindowTextLength(hWnd); - TCHAR *szText = (TCHAR*)_alloca((nLen + 2) * sizeof(TCHAR)); - - GetWindowText(hWnd, szText, nLen + 1); - - return tchar_to_utf8(szText); -} - - -char* GetDlgItemTextUtf(HWND hwndDlg, int iItem) -{ - return GetWindowTextUtf(GetDlgItem(hwndDlg, iItem)); -} - - -void SetWindowTextUtf(HWND hWnd, const char *szText) -{ - int size = strlennull(szText) + 2; - TCHAR *tszText = (TCHAR*)_alloca(size * sizeof(TCHAR)); - - if (utf8_to_tchar_static(szText, tszText, size)) - SetWindowText(hWnd, tszText); -} - - -void SetDlgItemTextUtf(HWND hwndDlg, int iItem, const char *szText) -{ - SetWindowTextUtf(GetDlgItem(hwndDlg, iItem), szText); -} - - -static int ControlAddStringUtf(HWND ctrl, DWORD msg, const char *szString) -{ - char str[MAX_PATH]; - char *szItem = ICQTranslateUtfStatic(szString, str, MAX_PATH); - int item = -1; - WCHAR *wItem = make_unicode_string(szItem); - item = SendMessage(ctrl, msg, 0, (LPARAM)wItem); - SAFE_FREE((void**)&wItem); - return item; -} - -int ComboBoxAddStringUtf(HWND hCombo, const char *szString, DWORD data) -{ - int item = ControlAddStringUtf(hCombo, CB_ADDSTRING, szString); - SendMessage(hCombo, CB_SETITEMDATA, item, data); - - return item; -} - -int ListBoxAddStringUtf(HWND hList, const char *szString) -{ - return ControlAddStringUtf(hList, LB_ADDSTRING, szString); -} - -int MessageBoxUtf(HWND hWnd, const char *szText, const char *szCaption, UINT uType) -{ - int res; - char str[1024]; - char cap[MAX_PATH]; - WCHAR *text = make_unicode_string(ICQTranslateUtfStatic(szText, str, 1024)); - WCHAR *caption = make_unicode_string(ICQTranslateUtfStatic(szCaption, cap, MAX_PATH)); - res = MessageBoxW(hWnd, text, caption, uType); - SAFE_FREE((void**)&caption); - SAFE_FREE((void**)&text); - return res; -} - -char* CIcqProto::ConvertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg) -{ // this takes utf-8 encoded message - WORD wCP = getSettingWord(hContact, "CodePage", m_wAnsiCodepage); - char* szAnsi = NULL; - - if (wCP != CP_ACP) // convert to proper codepage - if (!utf8_decode_codepage(szMsg, &szAnsi, wCP)) - return NULL; - - return szAnsi; -} - -// just broadcast generic send error with dummy cookie and return that cookie -DWORD CIcqProto::ReportGenericSendError(HANDLE hContact, int nType, const char* szErrorMsg) -{ - DWORD dwCookie = GenerateCookie(0); - SendProtoAck(hContact, dwCookie, ACKRESULT_FAILED, nType, Translate(szErrorMsg)); - return dwCookie; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CIcqProto::CreateProtoService(const char* szService, IcqServiceFunc serviceProc) -{ - char temp[MAX_PATH*2]; - - null_snprintf(temp, sizeof(temp), "%s%s", m_szModuleName, szService); - CreateServiceFunctionObj( temp, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this ); -} - -void CIcqProto::CreateProtoServiceParam(const char* szService, IcqServiceFuncParam serviceProc, LPARAM lParam) -{ - char temp[MAX_PATH*2]; - - null_snprintf(temp, sizeof(temp), "%s%s", m_szModuleName, szService); - CreateServiceFunctionObjParam( temp, ( MIRANDASERVICEOBJPARAM )*( void** )&serviceProc, this, lParam ); -} - - -HANDLE CIcqProto::HookProtoEvent(const char* szEvent, IcqEventFunc pFunc) -{ - return ::HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&pFunc, this); -} - - -HANDLE CIcqProto::CreateProtoEvent(const char* szEvent) -{ - char str[MAX_PATH + 32]; - strcpy(str, m_szModuleName); - strcat(str, szEvent); - return CreateHookableEvent(str); -} diff --git a/protocols/IcqOscarJ/utilities.h b/protocols/IcqOscarJ/utilities.h deleted file mode 100644 index 962ecce15f..0000000000 --- a/protocols/IcqOscarJ/utilities.h +++ /dev/null @@ -1,188 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Describe me here please... -// -// ----------------------------------------------------------------------------- -#ifndef __UTILITIES_H -#define __UTILITIES_H - - -struct icq_ack_args -{ - HANDLE hContact; - int nAckType; - int nAckResult; - HANDLE hSequence; - LPARAM pszMessage; -}; - -struct icq_contacts_cache -{ - HANDLE hContact; - DWORD dwUin; - const char *szUid; -}; - - -/*---------* Functions *---------------*/ - -void MoveDlgItem(HWND hwndDlg, int iItem, int left, int top, int width, int height); -void EnableDlgItem(HWND hwndDlg, UINT control, int state); -void ShowDlgItem(HWND hwndDlg, UINT control, int state); -void icq_EnableMultipleControls(HWND hwndDlg, const UINT* controls, int cControls, int state); -void icq_ShowMultipleControls(HWND hwndDlg, const UINT* controls, int cControls, int state); -int IcqStatusToMiranda(WORD wStatus); -WORD MirandaStatusToIcq(int nStatus); -int MirandaStatusToSupported(int nMirandaStatus); -char *MirandaStatusToString(int); -char *MirandaStatusToStringUtf(int); - -int AwayMsgTypeToStatus(int nMsgType); - -void SetGatewayIndex(HANDLE hConn, DWORD dwIndex); -DWORD GetGatewayIndex(HANDLE hConn); -void FreeGatewayIndex(HANDLE hConn); - -char *NickFromHandle(HANDLE hContact); -char *NickFromHandleUtf(HANDLE hContact); -char *strUID(DWORD dwUIN, char *pszUID); - -int __fastcall strlennull(const char *string); -int __fastcall strcmpnull(const char *str1, const char *str2); -int __fastcall stricmpnull(const char *str1, const char *str2); -char* __fastcall strstrnull(const char *str, const char *substr); -int null_snprintf(char *buffer, size_t count, const char *fmt, ...); -char* __fastcall null_strdup(const char *string); -char* __fastcall null_strcpy(char *dest, const char *src, size_t maxlen); -int __fastcall null_strcut(char *string, int maxlen); - -int __fastcall strlennull(const WCHAR *string); -int null_snprintf(WCHAR *buffer, size_t count, const WCHAR *fmt, ...); -WCHAR* __fastcall null_strdup(const WCHAR *string); -WCHAR* __fastcall null_strcpy(WCHAR *dest, const WCHAR *src, size_t maxlen); - -void parseServerAddress(char *szServer, WORD* wPort); - -char *DemangleXml(const char *string, int len); -char *MangleXml(const char *string, int len); -char *EliminateHtml(const char *string, int len); -char *ApplyEncoding(const char *string, const char *pszEncoding); - -int RandRange(int nLow, int nHigh); - -BOOL IsStringUIN(const char *pszString); - -char* time2text(time_t time); - -BOOL validateStatusMessageRequest(HANDLE hContact, WORD byMessageType); - -void __fastcall SAFE_FREE(void** p); -void* __fastcall SAFE_MALLOC(size_t size); -void* __fastcall SAFE_REALLOC(void* p, size_t size); - -__inline static void SAFE_FREE(char** str) { SAFE_FREE((void**)str); } -__inline static void SAFE_FREE(WCHAR** str) { SAFE_FREE((void**)str); } - -struct lockable_struct: public MZeroedObject -{ -private: - int nLockCount; -public: - lockable_struct() { _Lock(); }; - virtual ~lockable_struct() {}; - - void _Lock() { nLockCount++; }; - void _Release() { nLockCount--; if (!nLockCount) delete this; }; - - int getLockCount() { return nLockCount; }; -}; - -void __fastcall SAFE_DELETE(MZeroedObject **p); -void __fastcall SAFE_DELETE(lockable_struct **p); - -DWORD ICQWaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds, int bWaitAlways = FALSE); - - -struct icq_critical_section: public lockable_struct -{ -private: - HANDLE hMutex; - -public: - icq_critical_section() { hMutex = CreateMutex(NULL, FALSE, NULL); } - ~icq_critical_section() { CloseHandle(hMutex); } - - void Enter(void) { ICQWaitForSingleObject(hMutex, INFINITE, TRUE); } - void Leave(void) { ReleaseMutex(hMutex); } -}; - -__inline static void SAFE_DELETE(icq_critical_section **p) { SAFE_DELETE((lockable_struct**)p); } - -struct icq_lock -{ -private: - icq_critical_section *pMutex; -public: - icq_lock(icq_critical_section *mutex) { pMutex = mutex; pMutex->Enter(); }; - ~icq_lock() { pMutex->Leave(); pMutex = NULL; }; -}; - - -HANDLE NetLib_OpenConnection(HANDLE hUser, const char* szIdent, NETLIBOPENCONNECTION* nloc); -void NetLib_CloseConnection(HANDLE *hConnection, int bServerConn); -void NetLib_SafeCloseHandle(HANDLE *hConnection); - -char* __fastcall ICQTranslateUtf(const char *src); -char* __fastcall ICQTranslateUtfStatic(const char *src, char *buf, size_t bufsize); - -WORD GetMyStatusFlags(); - -/* Unicode FS utility functions */ - -int IsValidRelativePath(const char *filename); -const char* ExtractFileName(const char *fullname); -char* FileNameToUtf(const TCHAR *filename); - -int FileAccessUtf(const char *path, int mode); -int FileStatUtf(const char *path, struct _stati64 *buffer); -int MakeDirUtf(const char *dir); -int OpenFileUtf(const char *filename, int oflag, int pmode); - -/* Unicode UI utility functions */ -WCHAR* GetWindowTextUcs(HWND hWnd); -void SetWindowTextUcs(HWND hWnd, WCHAR *text); -char *GetWindowTextUtf(HWND hWnd); -char *GetDlgItemTextUtf(HWND hwndDlg, int iItem); -void SetWindowTextUtf(HWND hWnd, const char *szText); -void SetDlgItemTextUtf(HWND hwndDlg, int iItem, const char *szText); - -int ComboBoxAddStringUtf(HWND hCombo, const char *szString, DWORD data); -int ListBoxAddStringUtf(HWND hList, const char *szString); - -int MessageBoxUtf(HWND hWnd, const char *szText, const char *szCaption, UINT uType); - -#endif /* __UTILITIES_H */ diff --git a/protocols/IcqOscarJ/version.h b/protocols/IcqOscarJ/version.h deleted file mode 100644 index 0231d7a7ea..0000000000 --- a/protocols/IcqOscarJ/version.h +++ /dev/null @@ -1,3 +0,0 @@ -#define __FILEVERSION_STRING 0,11,0,1 -#define __VERSION_STRING "0.11.0.1" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 11, 0, 1) diff --git a/protocols/JabberG/MString.cpp b/protocols/JabberG/MString.cpp deleted file mode 100644 index 773871d1a5..0000000000 --- a/protocols/JabberG/MString.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "jabber.h" -#include "MString.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -CNilMStringData CMBaseString::m_nil; - -CMStringData* CMBaseString::Allocate( int nChars, int nCharSize ) -{ - CMStringData* pData; - nChars++; // nil char - size_t nDataBytes = nCharSize * nChars; - size_t nTotalSize = nDataBytes + sizeof(CMStringData); - - pData = static_cast(malloc(nTotalSize)); - if (pData == NULL) - return NULL; - - pData->nRefs = 1; - pData->nAllocLength = nChars - 1; - pData->nDataLength = 0; - return pData; -} - -void CMBaseString::Free(CMStringData* pData) -{ - free(pData); -} - -CMStringData* CMBaseString::Realloc(CMStringData* pData, int nChars, int nCharSize) -{ - CMStringData* pNewData; - nChars++; // nil char - ULONG nDataBytes = nCharSize * nChars; - ULONG nTotalSize = nDataBytes + sizeof(CMStringData); - - pNewData = static_cast(realloc(pData, nTotalSize)); - if (pNewData == NULL) - return NULL; - - pNewData->nAllocLength = nChars - 1; - return pNewData; -} - -CMStringData* CMBaseString::GetNilString() -{ - m_nil.AddRef(); - return &m_nil; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CMStringData - -void* CMStringData::data() -{ - return (this + 1); -} - -void CMStringData::AddRef() -{ - InterlockedIncrement(&nRefs); -} - -bool CMStringData::IsLocked() const -{ - return nRefs < 0; -} - -bool CMStringData::IsShared() const -{ - return (nRefs > 1); -} - -void CMStringData::Lock() -{ - nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary - if ( nRefs == 0 ) - nRefs = -1; -} - -void CMStringData::Release() -{ - if (InterlockedDecrement(&nRefs) <= 0) - CMBaseString::Free(this); -} - -void CMStringData::Unlock() -{ - if (IsLocked()) - { - nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary - if (nRefs == 0) - nRefs = 1; - } -} - -CNilMStringData::CNilMStringData() -{ - nRefs = 2; // Never gets freed - nDataLength = 0; - nAllocLength = 0; - achNil[0] = 0; - achNil[1] = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// ChTraitsCRT - -#if _MSC_VER < 1400 -static HINSTANCE hCrt = NULL; - -typedef int ( __cdecl *_vscprintf_func )( LPCSTR pszFormat, va_list args ); -static _vscprintf_func _vscprintf_ptr = NULL; - -typedef int ( __cdecl *_vscwprintf_func )( LPCWSTR pszFormat, va_list args ); -static _vscwprintf_func _vscwprintf_ptr = NULL; - -typedef int ( __cdecl *_vsnprintf_func )( char*, size_t, const char*, va_list ); -static _vsnprintf_func _vsnprintf_ptr = NULL; - -typedef int ( __cdecl *_vsnwprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); -static _vsnwprintf_func _vsnwprintf_ptr = NULL; - -typedef int ( __cdecl *vswprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); -static vswprintf_func vswprintf_ptr = NULL; - -typedef int ( __cdecl *vsprintf_func )( char*, size_t, const char*, va_list ); -static vsprintf_func vsprintf_ptr = NULL; - -static void checkCrt( void ) -{ - if ( hCrt == NULL ) { - hCrt = GetModuleHandleA( "msvcrt.dll" ); - _vscprintf_ptr = (_vscprintf_func)GetProcAddress( hCrt, "_vscprintf" ); - _vscwprintf_ptr = (_vscwprintf_func)GetProcAddress( hCrt, "_vscwprintf" ); - _vsnprintf_ptr = (_vsnprintf_func)GetProcAddress( hCrt, "_vsnprintf" ); - _vsnwprintf_ptr = (_vsnwprintf_func)GetProcAddress( hCrt, "_vsnwprintf" ); - vswprintf_ptr = (vswprintf_func)GetProcAddress( hCrt, "vswprintf" ); - vsprintf_ptr = (vsprintf_func)GetProcAddress( hCrt, "vsprintf" ); -} } -#endif - -int __stdcall ChTraitsCRT::GetFormattedLength( LPCWSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vscwprintf_ptr != NULL ) - return _vscwprintf_ptr( pszFormat, args ); - - WCHAR buf[ 4000 ]; - return vswprintf_ptr( buf, SIZEOF(buf), pszFormat, args ); - #else - return _vscwprintf( pszFormat, args ); - #endif -} - -int __stdcall ChTraitsCRT::Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vsnwprintf_ptr != NULL ) - return _vsnwprintf_ptr( pszBuffer, nLength, pszFormat, args ); - - return vswprintf_ptr( pszBuffer, nLength, pszFormat, args ); - #else - return _vsnwprintf( pszBuffer, nLength, pszFormat, args ); - #endif -} - -///////////////////////////////////////////////////////////////////////////////////////// -// ChTraitsCRT - -int __stdcall ChTraitsCRT::GetFormattedLength( LPCSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - if ( _vscprintf_ptr != NULL ) - return _vscprintf_ptr( pszFormat, args ); - - char buf[4000]; - return vsprintf_ptr( buf, sizeof(buf), pszFormat, args ); - #else - return _vscprintf( pszFormat, args ); - #endif -} - -int __stdcall ChTraitsCRT::Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ) -{ - #if _MSC_VER < 1400 - checkCrt(); - - return _vsnprintf( pszBuffer, nlength, pszFormat, args ); - #else - return vsprintf_s( pszBuffer, nlength, pszFormat, args ); - #endif -} - diff --git a/protocols/JabberG/MString.h b/protocols/JabberG/MString.h deleted file mode 100644 index 7cc16ff4a3..0000000000 --- a/protocols/JabberG/MString.h +++ /dev/null @@ -1,2300 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef __MINGW32__ -#include - -__inline size_t strnlen(const char *string, size_t maxlen) -{ - const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} -__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) -{ - const wchar_t *end = wmemchr (string, L'\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} - -/* FIXME: This may be wrong assumption about _AtlGetConversionACP */ -#define _AtlGetConversionACP() CP_THREAD_ACP -/* FIXME: This is unsafe */ -#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) -/* FIXME: This is quite silly implementation of _mbsstr */ -#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) -#define __max(x,y) (((x)<(y))?(y):(x)) -#endif /* __MINGW32__ */ - -struct CMStringData -{ - int nDataLength; // Length of currently used data in XCHARs (not including terminating null) - int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) - long nRefs; // Reference count: negative == locked - // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data - void* data(); - void AddRef(); - bool IsLocked() const; - bool IsShared() const; - void Lock(); - void Release(); - void Unlock(); -}; - -class CNilMStringData : public CMStringData -{ -public: - CNilMStringData(); - -public: - wchar_t achNil[2]; -}; - -template< typename BaseType = char > -class ChTraitsBase -{ -public: - typedef char XCHAR; - typedef LPSTR PXSTR; - typedef LPCSTR PCXSTR; - typedef wchar_t YCHAR; - typedef LPWSTR PYSTR; - typedef LPCWSTR PCYSTR; -}; - -template<> -class ChTraitsBase< wchar_t > -{ -public: - typedef wchar_t XCHAR; - typedef LPWSTR PXSTR; - typedef LPCWSTR PCXSTR; - typedef char YCHAR; - typedef LPSTR PYSTR; - typedef LPCSTR PCYSTR; -}; - -class CMBaseString -{ -public: - static CMStringData* Allocate(int nChars, int nCharSize); - static void Free(CMStringData* pData); - static CMStringData* Realloc(CMStringData* pData, int nChars, int nCharSize); - -protected: - static CMStringData* GetNilString(); - static CNilMStringData m_nil; -}; - -template< typename BaseType > -class CMSimpleStringT : public CMBaseString -{ -public: - typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; - typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; - typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; - typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; - typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; - typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; - -public: - explicit CMSimpleStringT() - { - CMStringData* pData = GetNilString(); - Attach(pData); - } - - CMSimpleStringT(const CMSimpleStringT& strSrc) - { - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pNewData = CloneData( pSrcData ); - Attach( pNewData ); - } - - CMSimpleStringT(PCXSTR pszSrc) - { - int nLength = StringLength( pszSrc ); - CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); - if (pData != NULL) - { - Attach( pData ); - SetLength( nLength ); - CopyChars( m_pszData, nLength, pszSrc, nLength ); - } - } - CMSimpleStringT(const XCHAR* pchSrc, int nLength) - { - CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); - if ( pData != NULL ) - { - Attach( pData ); - SetLength( nLength ); - CopyChars( m_pszData, nLength, pchSrc, nLength ); - } - } - ~CMSimpleStringT() - { - CMStringData* pData = GetData(); - pData->Release(); - } - - operator CMSimpleStringT&() - { - return *(CMSimpleStringT*)this; - } - - CMSimpleStringT& operator=(const CMSimpleStringT& strSrc ) - { - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pOldData = GetData(); - if ( pSrcData != pOldData) - { - if ( pOldData->IsLocked()) - SetString( strSrc.GetString(), strSrc.GetLength()); - else - { - CMStringData* pNewData = CloneData( pSrcData ); - pOldData->Release(); - Attach( pNewData ); - } - } - - return *this; - } - - CMSimpleStringT& operator=(PCXSTR pszSrc) - { - SetString( pszSrc ); - return *this; - } - - CMSimpleStringT& operator+=( const CMSimpleStringT& strSrc ) - { - Append( strSrc ); - - return *this; - } - - CMSimpleStringT& operator+=( PCXSTR pszSrc ) - { - Append( pszSrc ); - - return *this; - } - CMSimpleStringT& operator+=( char ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - CMSimpleStringT& operator+=( unsigned char ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - CMSimpleStringT& operator+=( wchar_t ch ) - { - AppendChar(XCHAR(ch)); - - return *this; - } - - XCHAR operator[]( int iChar ) const - { - return m_pszData[iChar]; - } - - operator PCXSTR() const - { - return m_pszData; - } - - PCXSTR c_str() const - { - return m_pszData; - } - - void Append( PCXSTR pszSrc ) - { - Append( pszSrc, StringLength( pszSrc )); - } - void Append( PCXSTR pszSrc, int nLength ) - { - // See comment in SetString() about why we do this - UINT_PTR nOffset = pszSrc - GetString(); - - UINT nOldLength = GetLength(); - if (nOldLength < 0) - { - // protects from underflow - nOldLength = 0; - } - - //Make sure we don't read pass end of the terminating NULL - int nSrcLength = StringLength(pszSrc); - nLength = nLength > nSrcLength ? nSrcLength: nLength; - - int nNewLength = nOldLength+nLength; - PXSTR pszBuffer = GetBuffer( nNewLength ); - if ( nOffset <= nOldLength ) - { - pszSrc = pszBuffer+nOffset; - // No need to call CopyCharsOverlapped, since the destination is - // beyond the end of the original buffer - } - CopyChars( pszBuffer+nOldLength, nLength, pszSrc, nLength ); - ReleaseBufferSetLength( nNewLength ); - } - void AppendChar( XCHAR ch ) - { - UINT nOldLength = GetLength(); - int nNewLength = nOldLength+1; - PXSTR pszBuffer = GetBuffer( nNewLength ); - pszBuffer[nOldLength] = ch; - ReleaseBufferSetLength( nNewLength ); - } - void Append( const CMSimpleStringT& strSrc ) - { - Append( strSrc.GetString(), strSrc.GetLength()); - } - void Empty() - { - CMStringData* pOldData = GetData(); - if ( pOldData->nDataLength == 0 ) - return; - - if ( pOldData->IsLocked()) - { - // Don't reallocate a locked buffer that's shrinking - SetLength( 0 ); - } - else - { - pOldData->Release(); - CMStringData* pNewData = GetNilString(); - Attach( pNewData ); - } - } - void FreeExtra() - { - CMStringData* pOldData = GetData(); - int nLength = pOldData->nDataLength; - if ( pOldData->nAllocLength == nLength ) - return; - - if ( !pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking - { - CMStringData* pNewData = Allocate( nLength, sizeof( XCHAR )); - if ( pNewData == NULL ) { - SetLength( nLength ); - return; - } - - CopyChars( PXSTR( pNewData->data()), nLength, PCXSTR( pOldData->data()), nLength ); - - pOldData->Release(); - Attach( pNewData ); - SetLength( nLength ); - } - } - - int GetAllocLength() const - { - return GetData()->nAllocLength; - } - XCHAR GetAt( int iChar ) const - { - return m_pszData[iChar]; - } - PXSTR GetBuffer() - { - CMStringData* pData = GetData(); - if ( pData->IsShared()) - Fork( pData->nDataLength ); - - return m_pszData; - } - PXSTR GetBuffer( int nMinBufferLength ) - { - return PrepareWrite( nMinBufferLength ); - } - PXSTR GetBufferSetLength( int nLength ) - { - PXSTR pszBuffer = GetBuffer( nLength ); - SetLength( nLength ); - - return pszBuffer; - } - int GetLength() const - { - return GetData()->nDataLength; - } - - PCXSTR GetString() const - { - return m_pszData; - } - bool IsEmpty() const - { - return GetLength() == 0; - } - PXSTR LockBuffer() - { - CMStringData* pData = GetData(); - if ( pData->IsShared()) - { - Fork( pData->nDataLength ); - pData = GetData(); // Do it again, because the fork might have changed it - } - pData->Lock(); - - return m_pszData; - } - void UnlockBuffer() - { - CMStringData* pData = GetData(); - pData->Unlock(); - } - void Preallocate( int nLength ) - { - PrepareWrite( nLength ); - } - void ReleaseBuffer( int nNewLength = -1 ) - { - if ( nNewLength == -1 ) - { - int nAlloc = GetData()->nAllocLength; - nNewLength = StringLengthN( m_pszData, nAlloc); - } - SetLength( nNewLength ); - } - void ReleaseBufferSetLength( int nNewLength ) - { - SetLength( nNewLength ); - } - void Truncate( int nNewLength ) - { - GetBuffer( nNewLength ); - ReleaseBufferSetLength( nNewLength ); - } - void SetAt( int iChar, XCHAR ch ) - { - int nLength = GetLength(); - PXSTR pszBuffer = GetBuffer(); - pszBuffer[iChar] = ch; - ReleaseBufferSetLength( nLength ); - - } - void SetString( PCXSTR pszSrc ) - { - SetString( pszSrc, StringLength( pszSrc )); - } - void SetString( PCXSTR pszSrc, int nLength ) - { - if ( nLength == 0 ) - { - Empty(); - } - else - { - - UINT nOldLength = GetLength(); - UINT_PTR nOffset = pszSrc - GetString(); - - PXSTR pszBuffer = GetBuffer( nLength ); - if ( nOffset <= nOldLength ) - { - CopyCharsOverlapped( pszBuffer, GetAllocLength(), - pszBuffer+nOffset, nLength ); - } - else - { - CopyChars( pszBuffer, GetAllocLength(), pszSrc, nLength ); - } - ReleaseBufferSetLength( nLength ); - } - } -public: - friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) - { - CMSimpleStringT s; - - Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength()); - - return s; - } - - friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, PCXSTR psz2) - { - CMSimpleStringT s; - - Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 )); - - return s; - } - - friend CMSimpleStringT __stdcall operator+(PCXSTR psz1, const CMSimpleStringT& str2) - { - CMSimpleStringT s; - - Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength()); - - return s; - } - - static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); -#pragma warning (pop) - } - static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars ) - { - #if _MSC_VER >= 1400 - memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); - #else - memcpy(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); - #endif - } - - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); -#pragma warning (pop) - } - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) - { - #if _MSC_VER >= 1400 - memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); - #else - memmove(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); - #endif - } - static int __stdcall StringLength(const char* psz) - { - if (psz == NULL) - { - return(0); - } - return (int(strlen(psz))); - } - static int __stdcall StringLength(const wchar_t* psz) - { - if (psz == NULL) - return 0; - - return int(wcslen(psz)); - } - static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar ) - { - if ( psz == NULL ) - return 0; - - return int( strnlen( psz, sizeInXChar )); - } - static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar ) - { - if ( psz == NULL ) - return 0; - - return int( wcsnlen( psz, sizeInXChar )); - } -protected: - static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) - { - int nNewLength = nLength1+nLength2; - PXSTR pszBuffer = strResult.GetBuffer(nNewLength); - CopyChars(pszBuffer, nLength1, psz1, nLength1 ); - CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); - strResult.ReleaseBufferSetLength(nNewLength); - } - // Implementation -private: - void Attach(CMStringData* pData) - { - m_pszData = static_cast(pData->data()); - } - void Fork(int nLength) - { - CMStringData* pOldData = GetData(); - int nOldLength = pOldData->nDataLength; - CMStringData* pNewData = Allocate(nLength, sizeof(XCHAR)); - if (pNewData != NULL) - { - int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0' - CopyChars( PXSTR( pNewData->data()), nCharsToCopy, PCXSTR( pOldData->data()), nCharsToCopy ); - pNewData->nDataLength = nOldLength; - pOldData->Release(); - Attach(pNewData); - } - } - CMStringData* GetData() const - { - return (reinterpret_cast(m_pszData) - 1); - } - PXSTR PrepareWrite( int nLength ) - { - CMStringData* pOldData = GetData(); - int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false - int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false - if ((nShared | nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data - PrepareWrite2(nLength); - - return m_pszData; - } - void PrepareWrite2(int nLength) - { - CMStringData* pOldData = GetData(); - if (pOldData->nDataLength > nLength) - nLength = pOldData->nDataLength; - - if (pOldData->IsShared()) - { - Fork(nLength); - } - else if (pOldData->nAllocLength < nLength) - { - // Grow exponentially, until we hit 1K. - int nNewLength = pOldData->nAllocLength; - if ( nNewLength > 1024 ) - nNewLength += 1024; - else - nNewLength *= 2; - - if ( nNewLength < nLength ) - nNewLength = nLength; - - Reallocate( nNewLength ); - } - } - void Reallocate( int nLength ) - { - CMStringData* pOldData = GetData(); - if ( pOldData->nAllocLength >= nLength || nLength <= 0) - return; - - CMStringData* pNewData = Realloc( pOldData, nLength, sizeof( XCHAR )); - if ( pNewData != NULL ) - Attach( pNewData ); - } - - void SetLength( int nLength ) - { - GetData()->nDataLength = nLength; - m_pszData[nLength] = 0; - } - - static CMStringData* __stdcall CloneData(CMStringData* pData) - { - CMStringData* pNewData = NULL; - - if (!pData->IsLocked()) { - pNewData = pData; - pNewData->AddRef(); - } - - return pNewData; - } - -public : - // typedef CStrBufT CStrBuf; -private: - PXSTR m_pszData; -}; - - -template< typename _CharType = char > -class ChTraitsCRT : public ChTraitsBase< _CharType > -{ -public: - static char* __stdcall CharNext( const char* p ) - { - return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ))); - } - - static int __stdcall IsDigit( char ch ) - { - return _ismbcdigit( ch ); - } - - static int __stdcall IsSpace( char ch ) - { - return _ismbcspace( ch ); - } - - static int __stdcall StringCompare( LPCSTR pszA, LPCSTR pszB ) - { - return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) - { - return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCollate( LPCSTR pszA, LPCSTR pszB ) - { - return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static int __stdcall StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) - { - return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); - } - - static LPCSTR __stdcall StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) - { - return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ), - reinterpret_cast< const unsigned char* >( pszMatch ))); - } - - static LPSTR __stdcall StringFindString( LPSTR pszBlock, LPCSTR pszMatch ) - { - return const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch )); - } - - static LPCSTR __stdcall StringFindChar( LPCSTR pszBlock, char chMatch ) - { - return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch )); - } - - static LPCSTR __stdcall StringFindCharRev( LPCSTR psz, char ch ) - { - return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch )); - } - - static LPCSTR __stdcall StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) - { - return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ), - reinterpret_cast< const unsigned char* >( pszMatch ))); - } - - static int __stdcall StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) - { - return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); - } - - static int __stdcall StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) - { - return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); - } - - static LPSTR __stdcall StringUppercase( LPSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz )) ); -#pragma warning (pop) - } - - static LPSTR __stdcall StringLowercase( LPSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz )) ); -#pragma warning (pop) - } - - static LPSTR __stdcall StringUppercase( LPSTR psz, size_t size ) - { - #if _MSC_VER >= 1400 - _mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size); - #else - _mbsupr(reinterpret_cast< unsigned char* >( psz )); - #endif - return psz; - } - - static LPSTR __stdcall StringLowercase( LPSTR psz, size_t size ) - { - #if _MSC_VER >= 1400 - _mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size ); - #else - _mbslwr(reinterpret_cast< unsigned char* >( psz )); - #endif - return psz; - } - - static LPSTR __stdcall StringReverse( LPSTR psz ) - { - return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz )) ); - } - - static int __stdcall GetFormattedLength( LPCSTR pszFormat, va_list args ); - - static int __stdcall Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return vsprintf( pszBuffer, pszFormat, args ); -#pragma warning (pop) - - } - - static int __stdcall Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ); - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) - { - // Returns required buffer length in XCHARs - return int( strlen( pszSrc )); - } - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) - { - (void)pszSrc; - // Returns required buffer length in XCHARs - return nLength; - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSource ) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1; - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSource, int nLength ) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL ); - } - - static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1 ) - { - if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } - // nLen is in XCHARs - memcpy_s( pszDest, nDestLength*sizeof( char ), - pszSrc, nSrcLength*sizeof( char )); - } - - static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) - { - // nLen is in XCHARs - ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL ); - } - - static void ConvertToOem( _CharType* pstrString) - { - BOOL fSuccess=::CharToOemA(pstrString, pstrString); - } - - static void ConvertToAnsi( _CharType* pstrString) - { - BOOL fSuccess=::OemToCharA(pstrString, pstrString); - } - - static void ConvertToOem( _CharType* pstrString, size_t size) - { - if(size>UINT_MAX) - { - return; - } - DWORD dwSize=static_cast(size); - BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize); - } - - static void ConvertToAnsi( _CharType* pstrString, size_t size) - { - if(size>UINT_MAX) - return; - - DWORD dwSize=static_cast(size); - BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize); - } - - static void __stdcall FloodCharacters( char ch, int nLength, char* pch ) - { - // nLength is in XCHARs - memset( pch, ch, nLength ); - } - - static BSTR __stdcall AllocSysString( const char* pchData, int nDataLength ) - { - int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); - BSTR bstr = ::SysAllocStringLen( NULL, nLen ); - if ( bstr != NULL ) - ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, bstr, nLen ); - - return bstr; - } - - static BOOL __stdcall ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) - { - int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); - BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen ); - if ( bSuccess ) - ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen ); - - return bSuccess; - } - - static int __stdcall SafeStringLen( LPCSTR psz ) - { - // returns length in bytes - return (psz != NULL) ? int( strlen( psz )) : 0; - } - - static int __stdcall SafeStringLen( LPCWSTR psz ) - { - // returns length in wchar_ts - return (psz != NULL) ? int( wcslen( psz )) : 0; - } - - static int __stdcall GetCharLen( const wchar_t* pch ) - { - // returns char length - return 1; - } - - static int __stdcall GetCharLen( const char* pch ) - { - // returns char length - return int( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); - } - - static DWORD __stdcall GetEnvironmentVariable( LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize ) - { - return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize ); - } -}; - -// specialization for wchar_t -template<> -class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > -{ - static DWORD __stdcall _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) - { - return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize ); - } - -public: - static LPWSTR __stdcall CharNext( LPCWSTR psz ) - { - return const_cast< LPWSTR >( psz+1 ); - } - - static int __stdcall IsDigit( wchar_t ch ) - { - return iswdigit( static_cast(ch)); - } - - static int __stdcall IsSpace( wchar_t ch ) - { - return iswspace( static_cast(ch)); - } - - static int __stdcall StringCompare( LPCWSTR pszA, LPCWSTR pszB ) - { - return wcscmp( pszA, pszB ); - } - - static int __stdcall StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) - { - return _wcsicmp( pszA, pszB ); - } - - static int __stdcall StringCollate( LPCWSTR pszA, LPCWSTR pszB ) - { - return wcscoll( pszA, pszB ); - } - - static int __stdcall StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) - { - return _wcsicoll( pszA, pszB ); - } - - static LPCWSTR __stdcall StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) - { - return wcsstr( pszBlock, pszMatch ); - } - - static LPWSTR __stdcall StringFindString( LPWSTR pszBlock, LPCWSTR pszMatch ) - { - return const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch )); - } - - static LPCWSTR __stdcall StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) - { - return wcschr( pszBlock, chMatch ); - } - - static LPCWSTR __stdcall StringFindCharRev( LPCWSTR psz, wchar_t ch ) - { - return wcsrchr( psz, ch ); - } - - static LPCWSTR __stdcall StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) - { - return wcspbrk( pszBlock, pszMatch ); - } - - static int __stdcall StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) - { - return (int)wcsspn( pszBlock, pszSet ); - } - - static int __stdcall StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) - { - return (int)wcscspn( pszBlock, pszSet ); - } - - static LPWSTR __stdcall StringUppercase( LPWSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return _wcsupr( psz ); -#pragma warning (pop) - } - - static LPWSTR __stdcall StringLowercase( LPWSTR psz ) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return _wcslwr( psz ); -#pragma warning (pop) - } - - static LPWSTR __stdcall StringUppercase( LPWSTR psz, size_t ) - { - return _wcsupr( psz ); - } - - static LPWSTR __stdcall StringLowercase( LPWSTR psz, size_t ) - { - return _wcslwr( psz ); - } - - static LPWSTR __stdcall StringReverse( LPWSTR psz ) - { - return _wcsrev( psz ); - } - - static int __stdcall GetFormattedLength( LPCWSTR pszFormat, va_list args); - - static int __stdcall Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) - { -#pragma warning (push) -#pragma warning(disable : 4996) - return vswprintf( pszBuffer, pszFormat, args ); -#pragma warning (pop) - } - - static int __stdcall Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args); - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, NULL, 0 )-1; - } - - static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nLength, NULL, 0 ); - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc ) - { - // Returns required buffer size in wchar_ts - return (int)wcslen( pszSrc ); - } - - static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) - { - (void)pszSrc; - // Returns required buffer size in wchar_ts - return nLength; - } - - static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) - { - // nLen is in wchar_ts - ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength ); - } - - static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1 ) - { - if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } - // nLen is in wchar_ts - #if _MSC_VER >= 1400 - wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); - #else - wmemcpy(pszDest, pszSrc, nDestLength); - #endif - } - - static void __stdcall FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) - { - // nLength is in XCHARs - for ( int i = 0; i < nLength; i++ ) - { - psz[i] = ch; - } - } - - static BSTR __stdcall AllocSysString( const wchar_t* pchData, int nDataLength ) - { - return ::SysAllocStringLen( pchData, nDataLength ); - } - - static BOOL __stdcall ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) - { - return ::SysReAllocStringLen( pbstr, pchData, nDataLength ); - } - - static int __stdcall SafeStringLen( LPCSTR psz ) - { - // returns length in bytes - return (psz != NULL) ? (int)strlen( psz ) : 0; - } - - static int __stdcall SafeStringLen( LPCWSTR psz ) - { - // returns length in wchar_ts - return (psz != NULL) ? (int)wcslen( psz ) : 0; - } - - static int __stdcall GetCharLen( const wchar_t* pch ) - { - (void)pch; - // returns char length - return 1; - } - - static int __stdcall GetCharLen( const char* pch ) - { - // returns char length - return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); - } - - static DWORD __stdcall GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) - { - return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize ); - } - - static void __stdcall ConvertToOem( LPWSTR /*psz*/ ) - { - } - - static void __stdcall ConvertToAnsi( LPWSTR /*psz*/ ) - { - } - - static void __stdcall ConvertToOem( LPWSTR /*psz*/, size_t ) - { - } - - static void __stdcall ConvertToAnsi( LPWSTR /*psz*/, size_t ) - { - } -}; - -template< typename BaseType, class StringTraits > -class CMStringT : public CMSimpleStringT< BaseType > -{ -public: - typedef CMSimpleStringT< BaseType> CThisSimpleString; - typedef typename CThisSimpleString::XCHAR XCHAR; - typedef typename CThisSimpleString::PXSTR PXSTR; - typedef typename CThisSimpleString::PCXSTR PCXSTR; - typedef typename CThisSimpleString::YCHAR YCHAR; - typedef typename CThisSimpleString::PYSTR PYSTR; - typedef typename CThisSimpleString::PCYSTR PCYSTR; - -public: - CMStringT() : CThisSimpleString() - { - } - - static void __stdcall Construct( CMStringT* pString ) - { - new( pString ) CMStringT; - } - - // Copy constructor - CMStringT( const CMStringT& strSrc ) : - CThisSimpleString( strSrc ) - { - } - - CMStringT( const XCHAR* pszSrc ) : - CThisSimpleString() - { - // nDestLength is in XCHARs - *this = pszSrc; - } - - CMStringT( const YCHAR* pszSrc ) : - CThisSimpleString() - { - *this = pszSrc; - } - - - CMStringT( const unsigned char* pszSrc ) : - CThisSimpleString() - { - *this = reinterpret_cast< const char* >( pszSrc ); - } - - CMStringT( char ch, int nLength = 1 ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer ); - this->ReleaseBufferSetLength( nLength ); - } - } - - CMStringT( wchar_t ch, int nLength = 1 ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - //Convert ch to the BaseType - wchar_t pszCh[2] = { ch , 0 }; - int nBaseTypeCharLen = 1; - - if(ch != L'\0') - { - nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); - } - - XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; - StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 ); - //Allocate enough characters in String and flood (replicate) with the (converted character)*nLength - PXSTR pszBuffer = this->GetBuffer( nLength*nBaseTypeCharLen ); - if (nBaseTypeCharLen == 1) - { //Optimization for a common case - wide char translates to 1 ansi/wide char. - StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer ); - } else - { - XCHAR* p=pszBuffer; - for (int i=0 ; i < nLength ;++i) - { - for (int j=0 ; j < nBaseTypeCharLen ;++j) - { - *p=buffBaseTypeChar[j]; - ++p; - } - } - } - this->ReleaseBufferSetLength( nLength*nBaseTypeCharLen ); - delete [] buffBaseTypeChar; - } - } - - CMStringT( const XCHAR* pch, int nLength ) : - CThisSimpleString( pch, nLength ) - { - } - - CMStringT( const YCHAR* pch, int nLength ) : - CThisSimpleString() - { - if ( nLength > 0 ) - { - int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength ); - PXSTR pszBuffer = this->GetBuffer( nDestLength ); - StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength ); - this->ReleaseBufferSetLength( nDestLength ); - } - } - - // Destructor - ~CMStringT() - { - } - - // Assignment operators - CMStringT& operator=( const CMStringT& strSrc ) - { - CThisSimpleString::operator=( strSrc ); - - return *this; - } - - CMStringT& operator=( PCXSTR pszSrc ) - { - CThisSimpleString::operator=( pszSrc ); - - return *this; - } - - CMStringT& operator=( PCYSTR pszSrc ) - { - // nDestLength is in XCHARs - int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0; - if ( nDestLength > 0 ) - { - PXSTR pszBuffer = this->GetBuffer( nDestLength ); - StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc); - this->ReleaseBufferSetLength( nDestLength ); - } - else - { - this->Empty(); - } - - return *this; - } - - CMStringT& operator=( const unsigned char* pszSrc ) - { - return operator=( reinterpret_cast< const char* >( pszSrc )); - } - - CMStringT& operator=( char ch ) - { - char ach[2] = { ch, 0 }; - - return operator=( ach ); - } - - CMStringT& operator=( wchar_t ch ) - { - wchar_t ach[2] = { ch, 0 }; - - return operator=( ach ); - } - -// CMStringT& operator=( const VARIANT& var ); - - CMStringT& operator+=( const CMStringT& str ) - { - CThisSimpleString::operator+=( str ); - return *this; - } - - CMStringT& operator+=( const CThisSimpleString& str ) - { - CThisSimpleString::operator+=( str ); - return *this; - } - - CMStringT& operator+=( PCXSTR pszSrc ) - { - CThisSimpleString::operator+=( pszSrc ); - return *this; - } -// template< int t_nSize > -// CMStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc ) -// { -// CThisSimpleString::operator+=( strSrc ); -// -// return *this; -// } - CMStringT& operator+=( PCYSTR pszSrc ) - { - CMStringT str( pszSrc ); - - return operator+=( str ); - } - - CMStringT& operator+=( char ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - CMStringT& operator+=( unsigned char ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - CMStringT& operator+=( wchar_t ch ) - { - CThisSimpleString::operator+=( ch ); - - return *this; - } - - // Comparison - - int Compare( PCXSTR psz ) const - { - return StringTraits::StringCompare( this->GetString(), psz ); - } - - int CompareNoCase( PCXSTR psz ) const - { - return StringTraits::StringCompareIgnore( this->GetString(), psz ); - } - - int Collate( PCXSTR psz ) const - { - return StringTraits::StringCollate( this->GetString(), psz ); - } - - int CollateNoCase( PCXSTR psz ) const - { - return StringTraits::StringCollateIgnore( this->GetString(), psz ); - } - - // Advanced manipulation - - // Delete 'nCount' characters, starting at index 'iIndex' - int Delete( int iIndex, int nCount = 1 ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( nCount < 0 ) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount + iIndex > nLength ) - { - nCount = nLength-iIndex; - } - if ( nCount > 0 ) - { - int nNewLength = nLength-nCount; - int nXCHARsToCopy = nLength-(iIndex+nCount)+1; - PXSTR pszBuffer = this->GetBuffer(); - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); - #endif - this->ReleaseBufferSetLength( nNewLength ); - } - - return this->GetLength(); - } - - // Insert character 'ch' before index 'iIndex' - int Insert( int iIndex, XCHAR ch ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( iIndex > this->GetLength()) - iIndex = this->GetLength(); - - int nNewLength = this->GetLength()+1; - - PXSTR pszBuffer = this->GetBuffer( nNewLength ); - - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); - #endif - pszBuffer[iIndex] = ch; - - this->ReleaseBufferSetLength( nNewLength ); - return nNewLength; - } - - // Insert string 'psz' before index 'iIndex' - int Insert( int iIndex, PCXSTR psz ) - { - if ( iIndex < 0 ) - iIndex = 0; - - if ( iIndex > this->GetLength()) - { - iIndex = this->GetLength(); - } - - // nInsertLength and nNewLength are in XCHARs - int nInsertLength = StringTraits::SafeStringLen( psz ); - int nNewLength = this->GetLength(); - if ( nInsertLength > 0 ) - { - nNewLength += nInsertLength; - - PXSTR pszBuffer = this->GetBuffer( nNewLength ); - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); - memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), psz, nInsertLength*sizeof( XCHAR )); - #else - memmove( pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); - memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR )); - #endif - this->ReleaseBufferSetLength( nNewLength ); - } - - return nNewLength; - } - - // Replace all occurrences of character 'chOld' with character 'chNew' - int Replace( XCHAR chOld, XCHAR chNew ) - { - int nCount = 0; - - // short-circuit the nop case - if ( chOld != chNew ) - { - // otherwise modify each character that matches in the string - bool bCopied = false; - PXSTR pszBuffer = const_cast< PXSTR >( this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). - - int nLength = this->GetLength(); - int iChar = 0; - while( iChar < nLength ) - { - // replace instances of the specified character only - if ( pszBuffer[iChar] == chOld ) - { - if ( !bCopied ) - { - bCopied = true; - pszBuffer = this->GetBuffer( nLength ); - } - pszBuffer[iChar] = chNew; - nCount++; - } - iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer ); - } - if ( bCopied ) - { - this->ReleaseBufferSetLength( nLength ); - } - } - - return nCount; - } - - // Replace all occurrences of string 'pszOld' with string 'pszNew' - int Replace( PCXSTR pszOld, PCXSTR pszNew ) - { - // can't have empty or NULL lpszOld - - // nSourceLen is in XCHARs - int nSourceLen = StringTraits::SafeStringLen( pszOld ); - if ( nSourceLen == 0 ) - return 0; - // nReplacementLen is in XCHARs - int nReplacementLen = StringTraits::SafeStringLen( pszNew ); - - // loop once to figure out the size of the result string - int nCount = 0; - { - PCXSTR pszStart = this->GetString(); - PCXSTR pszEnd = pszStart+this->GetLength(); - while( pszStart < pszEnd ) - { - PCXSTR pszTarget; - while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL) - { - nCount++; - pszStart = pszTarget+nSourceLen; - } - pszStart += StringTraits::SafeStringLen( pszStart )+1; - } - } - - // if any changes were made, make them - if ( nCount > 0 ) - { - // if the buffer is too small, just - // allocate a new buffer (slow but sure) - int nOldLength = this->GetLength(); - int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; - - PXSTR pszBuffer = this->GetBuffer( __max( nNewLength, nOldLength )); - - PXSTR pszStart = pszBuffer; - PXSTR pszEnd = pszStart+nOldLength; - - // loop again to actually do the work - while( pszStart < pszEnd ) - { - PXSTR pszTarget; - while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL ) - { - int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); - memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), - pszTarget+nSourceLen, nBalance*sizeof( XCHAR )); - memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), - pszNew, nReplacementLen*sizeof( XCHAR )); - pszStart = pszTarget+nReplacementLen; - pszTarget[nReplacementLen+nBalance] = 0; - nOldLength += (nReplacementLen-nSourceLen); - } - pszStart += StringTraits::SafeStringLen( pszStart )+1; - } - this->ReleaseBufferSetLength( nNewLength ); - } - - return nCount; - } - - // Remove all occurrences of character 'chRemove' - int Remove( XCHAR chRemove ) - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - - PXSTR pszSource = pszBuffer; - PXSTR pszDest = pszBuffer; - PXSTR pszEnd = pszBuffer+nLength; - - while( pszSource < pszEnd ) - { - PXSTR pszNewSource = StringTraits::CharNext( pszSource ); - if ( *pszSource != chRemove ) - { - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - size_t NewSourceGap = (pszNewSource-pszSource); - PXSTR pszNewDest = pszDest + NewSourceGap; - size_t i = 0; - for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) - { - *pszDest = *pszSource; - pszSource++; - pszDest++; - } - } - pszSource = pszNewSource; - } - *pszDest = 0; - int nCount = int( pszSource-pszDest ); - this->ReleaseBufferSetLength( nLength-nCount ); - - return nCount; - } - - CMStringT Tokenize( PCXSTR pszTokens, int& iStart ) const - { - if ( (pszTokens == NULL) || (*pszTokens == (XCHAR)0)) - { - if (iStart < this->GetLength()) - return CMStringT( this->GetString()+iStart ); - } - else - { - PCXSTR pszPlace = this->GetString()+iStart; - PCXSTR pszEnd = this->GetString()+this->GetLength(); - if ( pszPlace < pszEnd ) - { - int nIncluding = StringTraits::StringSpanIncluding( pszPlace, pszTokens ); - - if ( (pszPlace+nIncluding) < pszEnd ) - { - pszPlace += nIncluding; - int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens ); - - int iFrom = iStart+nIncluding; - int nUntil = nExcluding; - iStart = iFrom+nUntil+1; - - return Mid( iFrom, nUntil ); - } - } - } - - // return empty string, done tokenizing - iStart = -1; - - return CMStringT(); - } - - // find routines - - // Find the first occurrence of character 'ch', starting at index 'iStart' - int Find( XCHAR ch, int iStart = 0 ) const - { - // nLength is in XCHARs - int nLength = this->GetLength(); - if ( iStart < 0 || iStart >= nLength) - return -1; - - // find first single character - PCXSTR psz = StringTraits::StringFindChar( this->GetString()+iStart, ch ); - - // return -1 if not found and index otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // look for a specific sub-string - - // Find the first occurrence of string 'pszSub', starting at index 'iStart' - int Find( PCXSTR pszSub, int iStart = 0 ) const - { - // iStart is in XCHARs - if(pszSub == NULL) - return -1; - - // nLength is in XCHARs - int nLength = this->GetLength(); - if ( iStart < 0 || iStart > nLength ) - return -1; - - // find first matching substring - PCXSTR psz = StringTraits::StringFindString( this->GetString()+iStart, pszSub ); - - // return -1 for not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // Find the first occurrence of any of the characters in string 'pszCharSet' - int FindOneOf( PCXSTR pszCharSet ) const - { - PCXSTR psz = StringTraits::StringScanSet( this->GetString(), pszCharSet ); - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // Find the last occurrence of character 'ch' - int ReverseFind( XCHAR ch ) const - { - // find last single character - PCXSTR psz = StringTraits::StringFindCharRev( this->GetString(), ch ); - - // return -1 if not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int( psz-this->GetString()); - } - - // manipulation - - // Convert the string to uppercase - CMStringT& MakeUpper() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringUppercase( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // Convert the string to lowercase - CMStringT& MakeLower() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringLowercase( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // Reverse the string - CMStringT& MakeReverse() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::StringReverse( pszBuffer ); - this->ReleaseBufferSetLength( nLength ); - - return *this; - } - - // trimming - - // Remove all trailing whitespace - CMStringT& TrimRight() - { - // find beginning of trailing spaces by starting - // at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( StringTraits::IsSpace( *psz )) - { - if ( pszLast == NULL ) - pszLast = psz; - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at trailing space start - int iLast = int( pszLast-this->GetString()); - - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all leading whitespace - CMStringT& TrimLeft() - { - // find first non-space character - - PCXSTR psz = this->GetString(); - - while( StringTraits::IsSpace( *psz )) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Remove all leading and trailing whitespace - CMStringT& Trim() - { - return TrimRight().TrimLeft(); - } - - // Remove all leading and trailing occurrences of character 'chTarget' - CMStringT& Trim( XCHAR chTarget ) - { - return TrimRight( chTarget ).TrimLeft( chTarget ); - } - - // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' - CMStringT& Trim( PCXSTR pszTargets ) - { - return TrimRight( pszTargets ).TrimLeft( pszTargets ); - } - - // trimming anything (either side) - - // Remove all trailing occurrences of character 'chTarget' - CMStringT& TrimRight( XCHAR chTarget ) - { - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( *psz == chTarget ) - { - if ( pszLast == NULL ) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at left-most matching character - int iLast = int( pszLast-this->GetString()); - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all trailing occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimRight( PCXSTR pszTargets ) - { - // if we're not trimming anything, we're not doing any work - if ( (pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while( *psz != 0 ) - { - if ( StringTraits::StringFindChar( pszTargets, *psz ) != NULL ) - { - if ( pszLast == NULL ) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext( psz ); - } - - if ( pszLast != NULL ) - { - // truncate at left-most matching character - int iLast = int( pszLast-this->GetString()); - this->Truncate( iLast ); - } - - return *this; - } - - // Remove all leading occurrences of character 'chTarget' - CMStringT& TrimLeft( XCHAR chTarget ) - { - // find first non-matching character - PCXSTR psz = this->GetString(); - - while( chTarget == *psz ) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Remove all leading occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimLeft( PCXSTR pszTargets ) - { - // if we're not trimming anything, we're not doing any work - if ( (pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - PCXSTR psz = this->GetString(); - while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL)) - { - psz = StringTraits::CharNext( psz ); - } - - if ( psz != this->GetString()) - { - // fix up data and length - int iFirst = int( psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer( this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), - psz, (nDataLength+1)*sizeof( XCHAR )); - this->ReleaseBufferSetLength( nDataLength ); - } - - return *this; - } - - // Convert the string to the OEM character set - void AnsiToOem() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::ConvertToOem( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - } - - // Convert the string to the ANSI character set - void OemToAnsi() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::ConvertToAnsi( pszBuffer, nLength+1 ); - this->ReleaseBufferSetLength( nLength ); - } - - // Very simple sub-string extraction - - // Return the substring starting at index 'iFirst' - CMStringT Mid( int iFirst ) const - { - return Mid( iFirst, this->GetLength()-iFirst ); - } - - // Return the substring starting at index 'iFirst', with length 'nCount' - CMStringT Mid( int iFirst, int nCount ) const - { - // nCount is in XCHARs - - // out-of-bounds requests return sensible things - if (iFirst < 0) - iFirst = 0; - if (nCount < 0) - nCount = 0; - - if ( (iFirst + nCount) > this->GetLength()) - nCount = this->GetLength()-iFirst; - - if ( iFirst > this->GetLength()) - nCount = 0; - - // optimize case of returning entire string - if ( (iFirst == 0) && ((iFirst+nCount) == this->GetLength())) - return *this; - - return CMStringT( this->GetString()+iFirst, nCount ); - } - - // Return the substring consisting of the rightmost 'nCount' characters - CMStringT Right( int nCount ) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount >= nLength ) - { - return *this; - } - - return CMStringT( this->GetString()+nLength-nCount, nCount ); - } - - // Return the substring consisting of the leftmost 'nCount' characters - CMStringT Left( int nCount ) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if ( nCount >= nLength ) - return *this; - - return CMStringT( this->GetString(), nCount ); - } - - // Return the substring consisting of the leftmost characters in the set 'pszCharSet' - CMStringT SpanIncluding( PCXSTR pszCharSet ) const - { - return Left( StringTraits::StringSpanIncluding( this->GetString(), pszCharSet )); - } - - // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' - CMStringT SpanExcluding( PCXSTR pszCharSet ) const - { - return Left( StringTraits::StringSpanExcluding( this->GetString(), pszCharSet )); - } - - // Format data using format string 'pszFormat' - void Format( PCXSTR pszFormat, ... ); - - // Append formatted data using format string 'pszFormat' - void AppendFormat( PCXSTR pszFormat, ... ); - - void AppendFormatV( PCXSTR pszFormat, va_list args ) - { - int nCurrentLength = this->GetLength(); - int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args ); - PXSTR pszBuffer = this->GetBuffer( nCurrentLength+nAppendLength ); - StringTraits::Format( pszBuffer+nCurrentLength, - nAppendLength+1, pszFormat, args ); - this->ReleaseBufferSetLength( nCurrentLength+nAppendLength ); - } - - void FormatV( PCXSTR pszFormat, va_list args ) - { - int nLength = StringTraits::GetFormattedLength( pszFormat, args ); - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::Format( pszBuffer, nLength+1, pszFormat, args ); - this->ReleaseBufferSetLength( nLength ); - } - - // OLE BSTR support - - // Allocate a BSTR containing a copy of the string - BSTR AllocSysString() const - { - BSTR bstrResult = StringTraits::AllocSysString( this->GetString(), this->GetLength()); - return bstrResult; - } - - BSTR SetSysString( BSTR* pbstr ) const - { - StringTraits::ReAllocSysString( this->GetString(), pbstr, this->GetLength()); - return *pbstr; - } - - // Set the string to the value of environment variable 'pszVar' - BOOL GetEnvironmentVariable( PCXSTR pszVar ) - { - ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 ); - BOOL bRetVal = FALSE; - - if ( nLength == 0 ) - { - this->Empty(); - } - else - { - PXSTR pszBuffer = this->GetBuffer( nLength ); - StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength ); - this->ReleaseBuffer(); - bRetVal = TRUE; - } - - return bRetVal; - } - - // Load the string from resource 'nID' - BOOL LoadString( UINT nID ) - { - HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID ); - if ( hInst == NULL ) - return FALSE; - - return LoadString( hInst, nID ); - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, const CMStringT& str2 ) - { - CMStringT strResult; - - Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, PCXSTR psz2 ) - { - CMStringT strResult; - - Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 )); - - return strResult; - } - - friend CMStringT __stdcall operator+( PCXSTR psz1, const CMStringT& str2 ) - { - CMStringT strResult; - - Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, wchar_t ch2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch2 ); - - Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); - - return strResult; - } - - friend CMStringT __stdcall operator+( const CMStringT& str1, char ch2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch2 ); - - Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); - - return strResult; - } - - friend CMStringT __stdcall operator+( wchar_t ch1, const CMStringT& str2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch1 ); - - Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); - - return strResult; - } - - friend CMStringT __stdcall operator+( char ch1, const CMStringT& str2 ) - { - CMStringT strResult; - XCHAR chTemp = XCHAR( ch1 ); - - Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); - - return strResult; - } - - friend bool __stdcall operator==( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) == 0; - } - - friend bool __stdcall operator==( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) == 0; - } - - friend bool __stdcall operator==( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) == 0; - } - - friend bool __stdcall operator==( const CMStringT& str1, PCYSTR psz2 ) - { - CMStringT str2( psz2 ); - - return str1 == str2; - } - - friend bool __stdcall operator==( PCYSTR psz1, const CMStringT& str2 ) - { - CMStringT str1( psz1 ); - - return str1 == str2; - } - - friend bool __stdcall operator!=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) != 0; - } - - friend bool __stdcall operator!=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) != 0; - } - - friend bool __stdcall operator!=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) != 0; - } - - friend bool __stdcall operator!=( const CMStringT& str1, PCYSTR psz2 ) - { - CMStringT str2( psz2 ); - - return str1 != str2; - } - - friend bool __stdcall operator!=( PCYSTR psz1, const CMStringT& str2 ) - { - CMStringT str1( psz1 ); - - return str1 != str2; - } - - friend bool __stdcall operator<( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) < 0; - } - - friend bool __stdcall operator<( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) < 0; - } - - friend bool __stdcall operator<( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) > 0; - } - - friend bool __stdcall operator>( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) > 0; - } - - friend bool __stdcall operator>( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) > 0; - } - - friend bool __stdcall operator>( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) < 0; - } - - friend bool __stdcall operator<=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) <= 0; - } - - friend bool __stdcall operator<=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) <= 0; - } - - friend bool __stdcall operator<=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) >= 0; - } - - friend bool __stdcall operator>=( const CMStringT& str1, const CMStringT& str2 ) - { - return str1.Compare( str2 ) >= 0; - } - - friend bool __stdcall operator>=( const CMStringT& str1, PCXSTR psz2 ) - { - return str1.Compare( psz2 ) >= 0; - } - - friend bool __stdcall operator>=( PCXSTR psz1, const CMStringT& str2 ) - { - return str2.Compare( psz1 ) <= 0; - } - - friend bool __stdcall operator==( XCHAR ch1, const CMStringT& str2 ) - { - return (str2.GetLength() == 1) && (str2[0] == ch1); - } - - friend bool __stdcall operator==( const CMStringT& str1, XCHAR ch2 ) - { - return (str1.GetLength() == 1) && (str1[0] == ch2); - } - - friend bool __stdcall operator!=( XCHAR ch1, const CMStringT& str2 ) - { - return (str2.GetLength() != 1) || (str2[0] != ch1); - } - - friend bool __stdcall operator!=( const CMStringT& str1, XCHAR ch2 ) - { - return (str1.GetLength() != 1) || (str1[0] != ch2); - } -}; - -template< typename BaseType, class StringTraits > -inline void CMStringT::Format(PCXSTR pszFormat, ... ) -{ - va_list argList; - va_start( argList, pszFormat ); - FormatV( pszFormat, argList ); - va_end( argList ); -} - -template< typename BaseType, class StringTraits > -inline void CMStringT::AppendFormat(PCXSTR pszFormat, ... ) -{ - va_list argList; - va_start( argList, pszFormat ); - AppendFormatV( pszFormat, argList ); - va_end( argList ); -} - -typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; -typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; -typedef CMStringT< TCHAR, ChTraitsCRT< TCHAR > > CMString; diff --git a/protocols/JabberG/docs/jabberg-translation.txt b/protocols/JabberG/docs/jabberg-translation.txt new file mode 100644 index 0000000000..3e58b30b19 --- /dev/null +++ b/protocols/JabberG/docs/jabberg-translation.txt @@ -0,0 +1,835 @@ +; Common strings that belong to many files +;[OK] +;[Account] +;[Add] +;[Add to roster] +;[Are you sure?] +;[Authentication failed for] +;[Away] +;[Bookmarks] +;[Cancel] +;[Change Password] +;[Change nickname in] +;[Change password] +;[Close] +;[Conferences] +;[Connecting...] +;[Custom1] +;[Download] +;[Edit] +;[Free for chat] +;[General] +;[Grant authorization] +;[Home] +;[JID] +;[JID List] +;[Jabber] +;[Jabber Agent Registration] +;[Jabber Authentication] +;[Jabber Error] +;[Jabber Resource] +;[Loading...] +;[Login/logout] +;[Member Information] +;[No message] +;[Node] +;[None] +;[Notes] +;[Offline] +;[Online] +;[Photo] +;[Privacy Lists] +;[Reason to ban] +;[Register] +;[Registered transports] +;[Registration successful] +;[Remove] +;[Request authorization] +;[Resolve nicks] +;[Resource priority] +;[Revoke authorization] +;[Service Discovery] +;[Set activity...] +;[Set mood...] +;[Subscription] +;[Transports] +;[Upload] +;[View as list] +;[View as tree] +;[Work] +;[XML Console] +;[from] + +; ../../protocols/JabberG/jabber.cpp +;[Jabber Link Protocol] +;[Jabber protocol plugin for Miranda IM (%s)] + +; ../../protocols/JabberG/jabber.h +;[/me slaps %s around a bit with a large trout] +;[I'm happy Miranda IM user. Get it at http://miranda-im.org/.] + +; ../../protocols/JabberG/jabber.rc +;[&Accept] +;[&Invite] +;[\nIncoming groupchat invitation.] +;[\nSend groupchat invitation.] +;[Account type:] +;[Activate (Space)] +;[Add list... (Ins)] +;[Add rule (Ins)] +;[Address1:] +;[Address2:] +;[Advanced Mode] +;[Affiliation:] +;[Allow file sending through bytestream proxy server:] +;[Allow file sending through direct peer-to-peer connection] +;[Alternate nick:] +;[Apply Filter] +;[Authorization Request] +;[Authorize] +;[Auto-join (Automatically join Bookmarks must be enabled in Miranda options)] +;[Automatically delete contacts not in my roster] +;[BBS] +;[Back] +;[Bookmark Details] +;[Bookmark Name:] +;[Bookmark Type] +;[Bots Challenge Test] +;[Browse] +;[Browse/Join chat room...] +;[Cellular] +;[Change %s Message] +;[Chat options] +;[City:] +;[Closing in %d] +;[Command] +;[Company:] +;[Complete] +;[Conference] +;[Conference server:] +;[Confirm New Password:] +;[Country:] +;[Create or Join Groupchat] +;[Current Password:] +;[Custom messages] +;[Data form test] +;[Date of birth:] +;[Delete] +;[Deny] +;[Department:] +;[Description:] +;[Dialog] +;[Domain/Server:] +;[E-mail:] +;[Edit Note] +;[Edit rule... (F2)] +;[Email address:] +;[Enter the name of the new list:] +;[Expert] +;[Export to file] +;[Favourites] +;[Fax] +;[File Transfer] +;[First name:] +;[Full name:] +;[Gender:] +;[Go] +;[Groupchat Invitation] +;[HTTP Authorization\nAccept or reject incoming request] +;[Hint:] +;[Homepage:] +;[Host:] +;[ISDN] +;[If you wish to confirm this request, please click authorize. Otherwise, press deny to reject it.] +;[If:] +;[Import from file] +;[Incoming presence] +;[Instruction:] +;[Internet] +;[Invitation reason:] +;[Invite Users] +;[JID:] +;[Jabber Account Information:] +;[Jabber Account Registration] +;[Jabber Agents] +;[Jabber Bookmarks] +;[Jabber Form] +;[Jabber Multi-User Conference] +;[Jabber Multi-User Conference\nCreate or join existing conference room.] +;[Jabber Notebook] +;[Jabber Password] +;[Jabber notebook\nStore notes on server and access them from anywhere.] +;[Jabber server:] +;[Jabber vCard: Add Email Address] +;[Jabber vCard: Add Phone Number] +;[Keep connection alive] +;[Language for human-readable resources:] +;[Last name:] +;[List of public servers] +;[List4] +;[Lists:] +;[Load] +;[Log off] +;[Log on] +;[Login server:] +;[Manually specify connection host] +;[Member Information\n] +;[Messages] +;[Middle:] +;[Miscellaneous] +;[Modem] +;[Move rule down (Alt+Down)] +;[Move rule up (Alt+Up)] +;[New Password:] +;[New privacy list name:] +;[Next] +;[Nick name:] +;[Nickname:] +;[Node:] +;[Occupation:] +;[Other JID:] +;[Outgoing presence] +;[PCS] +;[Pager] +;[Password:] +;[Phone number:] +;[Phone:] +;[Port:] +;[Priority:] +;[Privacy Lists\nFlexible way to configure visibility and more.] +;[Privacy rule] +;[Progress1] +;[Queries] +;[Quit:] +;[Recently visited chatrooms:] +;[Refresh] +;[Register account now] +;[Register new user] +;[Register with a new service...] +;[Register...] +;[Register/Search Jabber Agents] +;[Registered Jabber Transports] +;[Remove list (Del)] +;[Remove rule (Del)] +;[Request method is:] +;[Request was sent from JID:] +;[Reset Filter] +;[Resource:] +;[Role:] +;[Room JID/ URL:] +;[Room:] +;[Roster Editor] +;[Roster editor\nView and modify your server-side contact list.] +;[Rules:] +;[Save] +;[Save password] +;[Save password for this session] +;[Search service] +;[Search...] +;[Server side bookmarks\nStore conference rooms and web links on server.] +;[Set affiliation] +;[Set as default (Ctrl+Space)] +;[Set role] +;[Simple Mode] +;[Slap:] +;[Someone (maybe you) has requested the following file:] +;[Specify external address:] +;[Spin1] +;[State:] +;[Status message:] +;[Submit] +;[Tags:] +;[Text/Messaging] +;[The transaction identifier is:] +;[Then:] +;[Title:] +;[Transport] +;[Try to uncheck all checkmarks above if you're experiencing troubles with sending files. But it can cause problems with transfer of large files.] +;[Type:] +;[URL] +;[Unregister] +;[Use Domain Login] +;[Use SSL] +;[Use TLS] +;[Use custom connection host and port:] +;[Use hostname as resource] +;[User directory:] +;[User:] +;[Username:] +;[Video] +;[Voice] +;[X400] +;[YYYY-MM-DD] +;[You are invited to conference room by] +;[ZIP:] +;[following stanza types:] +;[with following reason:] + +; ../../protocols/JabberG/jabber_adhoc.cpp +;[Done] +;[Error %s %s] +;[Execute] +;[In progress. Please Wait...] +;[Jabber Ad-Hoc commands at] +;[Not supported] +;[Requesting command list. Please wait...] +;[Select Command] +;[Sending Ad-Hoc command to] + +; ../../protocols/JabberG/jabber_agent.cpp +;[Please wait...] + +; ../../protocols/JabberG/jabber_bookmarks.cpp +;[Address (JID or URL)] +;[Bookmark Name] +;[Links] +;[Nickname] + +; ../../protocols/JabberG/jabber_byte.cpp +;[Bytestream Proxy not available] + +; ../../protocols/JabberG/jabber_captcha.cpp +;[Enter the text you see] + +; ../../protocols/JabberG/jabber_chat.cpp +;[&Add to roster] +;[&Admin] +;[&Admin list] +;[&Affiliations] +;[&Configure...] +;[&Copy to clipboard] +;[&Destroy room] +;[&Invite a user] +;[&Kick] +;[&Leave chat session] +;[&Member] +;[&Member list] +;[&Moderator] +;[&Moderator list] +;[&None] +;[&Owner] +;[&Owner list] +;[&Participant] +;[&Participant list] +;[&Roles] +;[&Room options] +;[&Send presence] +;[&Slap] +;[&User details] +;[&Visitor] +;[Add to &bookmarks] +;[Admin] +;[Affiliation of %s was changed to '%s'.] +;[Change &nickname] +;[Copy &nickname] +;[Copy in-room JID] +;[Copy real &JID] +;[Copy room &JID] +;[Copy room topic] +;[DND] +;[Invite %s to %s] +;[Invite to room] +;[Lin&ks] +;[Member] +;[Member &info] +;[Member Info:] +;[Moderator] +;[NA] +;[Outcast] +;[Outcast (&ban)] +;[Outcast list (&ban)] +;[Owner] +;[Participant] +;[Real &JID: %s] +;[Real JID not available] +;[Reason to destroy] +;[Reason to kick] +;[Role of %s was changed to '%s'.] +;[Room configuration was changed.] +;[Send groupchat invitation.] +;[Set &affiliation] +;[Set &role] +;[Set topic for] +;[User %s changed status to %s] +;[User %s changed status to %s with message: %s] +;[User %s in now banned.] +;[User &details] +;[View/change &topic] +;[Visitor] +;[because room is now members-only] +;[not on roster] +;[user banned] + +; ../../protocols/JabberG/jabber_console.cpp +;[Can't send data while you are offline.] +;[Outgoing XML parsing error] + +; ../../protocols/JabberG/jabber_disco.cpp +;[Browse all favorites] +;[Browse chatrooms] +;[Browse local transports] +;[Navigate] +;[Node hierarchy] +;[Remove all favorites] +;[request timeout.] + +; ../../protocols/JabberG/jabber_disco.h +;[Category] +;[Identities] +;[Info request error] +;[Items request error] +;[Supported features] +;[Type] +;[category] +;[type] + +; ../../protocols/JabberG/jabber_groupchat.cpp +;[] +;[Bookmarks...] +;[Failed to retrieve room list from server.] +;[Incoming groupchat invitation.] +;[No rooms available on server.] +;[Please specify groupchat directory first.] +;[Please wait for room list to download.] +;[Room list request timed out.] +;[has set the subject to:] + +; ../../protocols/JabberG/jabber_icolib.cpp +;[%s] +;[Accounts] +;[Active privacy list] +;[AdHoc Command] +;[Agents list] +;[Allow Messages] +;[Allow Presences (in)] +;[Allow Presences (out)] +;[Allow Queries] +;[Apply filter] +;[Browse node] +;[Convert to room] +;[Default privacy list] +;[Deny Messages] +;[Deny Presences (in)] +;[Deny Presences (out)] +;[Deny Queries] +;[Dialogs] +;[Dialogs/Discovery] +;[Dialogs/Privacy] +;[Discovery failed] +;[Discovery in progress] +;[Discovery succeeded] +;[Generic privacy list] +;[Move down] +;[Move up] +;[Multi-User Conference] +;[Navigate home] +;[OpenID Request] +;[Personal vCard] +;[Protocols] +;[RSS service] +;[Refresh node] +;[Reset filter] +;[Send note] +;[Server] +;[Storage service] +;[Weather service] + +; ../../protocols/JabberG/jabber_iq_handlers.cpp +;[Http authentication request received] + +; ../../protocols/JabberG/jabber_iqid.cpp +;[Jabber Bookmarks Error] +;[Password cannot be changed.] +;[Password is successfully changed. Don't forget to update your password in the Jabber protocol option.] + +; ../../protocols/JabberG/jabber_iqid_muc.cpp +;[%s, %d items (%s)] +;[Admin List] +;[Ban List] +;[Member List] +;[Moderator List] +;[Owner List] +;[Removing] +;[Voice List] + +; ../../protocols/JabberG/jabber_menu.cpp +;[&Convert to Chat Room] +;[&Convert to Contact] +;[Add to Bookmarks] +;[Browse Chatrooms] +;[Commands] +;[Convert] +;[Create/Join groupchat] +;[Highest priority (server's choice)] +;[Last Active] +;[Last active] +;[Local Server Transports] +;[No activity yet, use server's choice] +;[Options...] +;[Registered Transports] +;[Resource priority [%d]] +;[Roster editor] +;[Send Note] +;[Send Presence] +;[Server's Choice] +;[Services...] +;[Status Message] + +; ../../protocols/JabberG/jabber_misc.cpp +;[Both] +;[CHAT plugin is required for conferences. Install it before chatting] +;[Errors] +;[From] +;[To] + +; ../../protocols/JabberG/jabber_notes.cpp +;[All tags] +;[From: %s] +;[Incoming note] +;[Incoming note from %s] +;[Notes are not saved, close this window without uploading data to server?] +;[Send note to %s] + +; ../../protocols/JabberG/jabber_opt.cpp +;[Accept HTTP Authentication requests (XEP-0070)] +;[Accept only in band incoming filetransfers (don't disclose own IP)] +;[Account removal warning] +;[Advanced] +;[Affiliation changes] +;[Allow servers to request version (XEP-0092)] +;[Autoaccept multiuser chat invitations] +;[Automatically accept authorization requests] +;[Automatically add contact when accept authorization] +;[Automatically join bookmarks on login] +;[Automatically join conferences on login] +;[Automatically save received notes] +;[Ban notifications] +;[Confirm password] +;[Disable SASL authentication (for old servers)] +;[Disable frame] +;[Do not show multiuser chat invitations] +;[Downloading...] +;[Enable XMPP link processing (requires Association Manager)] +;[Enable avatars] +;[Enable remote controlling (from another resource of same JID only)] +;[Enable stream compression (if possible)] +;[Enable user activity receiving] +;[Enable user moods receiving] +;[Enable user tunes receiving] +;[Facebook Chat] +;[Filter history messages] +;[Fix incorrect timestamps in incoming messages] +;[Google Talk!] +;[Group] +;[Hide conference windows at startup] +;[Jabber Protocol Option] +;[Keep contacts assigned to local groups (ignore roster group)] +;[LiveJournal Talk] +;[Log chat state changes] +;[Log events] +;[Log presence errors] +;[Log presence subscription state changes] +;[Messaging] +;[Network] +;[Nick Name] +;[Other] +;[Passwords do not match.] +;[Public XMPP Network] +;[Receive notes] +;[Role changes] +;[Room configuration changes] +;[S.ms] +;[Secure XMPP Network] +;[Secure XMPP Network (old style)] +;[Security] +;[Send messages slower, but with full acknowledgement] +;[Server options] +;[Show information about operating system in version replies] +;[Show transport agents on contact list] +;[Some changes will take effect the next time you connect to the Jabber network.] +;[Status changes] +;[These changes will take effect the next time you connect to the Jabber network.] +;[This operation will kill your account, roster and all another information stored at the server. Are you ready to do that?] +;[Uploading...] +;[Vkontakte] +;[XML for MS Excel (UTF-8 encoded)] +;[You can change your password only when you are online] +;[You must be online] + +; ../../protocols/JabberG/jabber_password.cpp +;[Current password is incorrect.] +;[New password does not match.] +;[Set New Password for] + +; ../../protocols/JabberG/jabber_privacy.cpp +;[ (act., def.)] +;[ (active)] +;[ (default)] +;[ (nickname: ] +;[ and ] +;[** Default **] +;[** Subsription: both **] +;[** Subsription: from **] +;[** Subsription: none **] +;[** Subsription: to **] +;[] +;[Activate] +;[Active privacy list successfully declined] +;[Add JID] +;[Add list...] +;[Add rule] +;[Advanced mode] +;[Default privacy list successfully declined] +;[Delete rule] +;[Edit rule] +;[Else ] +;[Error occurred while applying changes] +;[Error occurred while setting active list] +;[Error occurred while setting default list] +;[First, save the list] +;[If group is '] +;[If jabber id is '] +;[If subscription is '] +;[List Editor...] +;[Move rule down] +;[Move rule up] +;[Please save list before activating] +;[Please save list before you make it the default list] +;[Privacy list %s set as active] +;[Privacy list %s set as default] +;[Privacy lists are not saved, discard any changes and exit?] +;[Privacy lists successfully saved] +;[Ready.] +;[Remove list] +;[Set default] +;[Simple mode] +;[Unable to save list because you are currently offline.] +;[Warning: privacy lists were changed on server.] +;[all.] +;[allow ] +;[deny ] +;[incoming presences] +;[messages] +;[outgoing presences] +;[queries] +;[then ] + +; ../../protocols/JabberG/jabber_proto.cpp +;[No compatible file transfer machanism exist] +;[Protocol is offline or no jid] + +; ../../protocols/JabberG/jabber_rc.cpp +;[%d message(s) forwarded] +;[%d message(s) to be forwarded] +;[Automatically Accept File Transfers] +;[Change Status] +;[Change global status] +;[Choose the groupchats you want to leave] +;[Choose the status and status message] +;[Command completed successfully] +;[Confirmation needed] +;[Disable remote controlling (check twice what you are doing)] +;[Do Not Disturb] +;[Error %d occured during workstation lock] +;[Error occured during processing command] +;[Extended Away (N/A)] +;[Forward options] +;[Forward unread messages] +;[Invisible] +;[Leave groupchats] +;[Lock workstation] +;[Mark messages as read] +;[Play sounds] +;[Please confirm Miranda IM shutdown] +;[Priority] +;[Quit Miranda IM] +;[Set Options] +;[Set options] +;[Set status] +;[Set the desired options] +;[Status] +;[Status message] +;[There is no groupchats to leave] +;[There is no messages to forward] +;[Workstation successfully locked] + +; ../../protocols/JabberG/jabber_search.cpp +;[Error %s %s\r\nPlease select other server] +;[Error %s %s\r\nTry to specify more detailed] +;[Error Unknown reply recieved\r\nPlease select other server] +;[Please wait...\r\nConnecting search server...] +;[Search error] +;[Select/type search service URL above and press ] +;[You have to be connected to server] + +; ../../protocols/JabberG/jabber_svc.cpp +;[approved subscription request] +;[closed chat session] +;[declined subscription] +;[sent error presence] +;[sent subscription request] +;[sent unknown presence type] + +; ../../protocols/JabberG/jabber_thread.cpp +;[Enter password for] +;[Error: Cannot connect to the server] +;[Error: Connection lost] +;[Error: Not enough memory] +;[Message redirected from: %s\r\n%s] +;[Requesting registration instruction...] +;[Sending registration information...] + +; ../../protocols/JabberG/jabber_userinfo.cpp +;[] +;[] +;[] +;[] +;[Activity] +;[Alpha build] +;[Client capabilities] +;[Copy] +;[Copy only this value] +;[Debug build] +;[Idle since] +;[Last active resource] +;[Last logoff time] +;[Logoff message] +;[Message] +;[Miranda IM core version] +;[Mood] +;[No] +;[Operating system] +;[Operating system version] +;[Please switch online to see more details.] +;[Resource] +;[Software] +;[Software information] +;[Software version] +;[System] +;[Tune] +;[Unicode build] +;[Unknown format] +;[Uptime] +;[Version] +;[Yes] +;[both] +;[format] +;[none] +;[to] +;[unknown] + +; ../../protocols/JabberG/jabber_util.cpp +;[Advanced Status] +;[Error] +;[Unknown error message] + +; ../../protocols/JabberG/jabber_vcard.cpp +;[Contacts] +;[Female] +;[Jabber vCard] +;[Jabber vCard: Edit Email Address] +;[Jabber vCard: Edit Phone Number] +;[Male] +;[Note] +;[Only JPG, GIF, and BMP image files smaller than 40 KB are supported.] + +; ../../protocols/JabberG/jabber_ws.cpp +;[%s connection] + +; ../../protocols/JabberG/jabber_xstatus.cpp +;[Activity: %s] +;[Afraid] +;[Amazed] +;[Amorous] +;[Angry] +;[Annoyed] +;[Anxious] +;[Aroused] +;[Ashamed] +;[Bored] +;[Brave] +;[Calm] +;[Cautious] +;[Cold] +;[Confident] +;[Confused] +;[Contemplative] +;[Contented] +;[Cranky] +;[Crazy] +;[Creative] +;[Curious] +;[Dejected] +;[Depressed] +;[Disappointed] +;[Disgusted] +;[Dismayed] +;[Distracted] +;[Embarrassed] +;[Envious] +;[Excited] +;[Flirtatious] +;[Frustrated] +;[Grateful] +;[Grieving] +;[Grumpy] +;[Guilty] +;[Happy] +;[Hopeful] +;[Hot] +;[Humbled] +;[Humiliated] +;[Hungry] +;[Hurt] +;[Impressed] +;[In awe] +;[In love] +;[Indignant] +;[Interested] +;[Intoxicated] +;[Invincible] +;[Jealous] +;[Listening To] +;[Lonely] +;[Lost] +;[Lucky] +;[Mean] +;[Mood: %s] +;[Moody] +;[Nervous] +;[Neutral] +;[Offended] +;[Outraged] +;[Playful] +;[Proud] +;[Relaxed] +;[Relieved] +;[Remorseful] +;[Restless] +;[Sad] +;[Sarcastic] +;[Satisfied] +;[Serious] +;[Set Activity] +;[Set Mood] +;[Shocked] +;[Shy] +;[Sick] +;[Sleepy] +;[Spontaneous] +;[Stressed] +;[Strong] +;[Surprised] +;[Thankful] +;[Thirsty] +;[Tired] +;[Undefined] +;[Weak] +;[Worried] + +; ../../protocols/JabberG/ui_utils.cpp +;[Set filter...] + +; ../../protocols/JabberG/version.rc +;[Reset log] +;[Send] diff --git a/protocols/JabberG/icos/add2roster.ico b/protocols/JabberG/icos/add2roster.ico deleted file mode 100644 index 0b0d1462c3..0000000000 Binary files a/protocols/JabberG/icos/add2roster.ico and /dev/null differ diff --git a/protocols/JabberG/icos/addcontact.ico b/protocols/JabberG/icos/addcontact.ico deleted file mode 100644 index 596593efb1..0000000000 Binary files a/protocols/JabberG/icos/addcontact.ico and /dev/null differ diff --git a/protocols/JabberG/icos/arrow_down.ico b/protocols/JabberG/icos/arrow_down.ico deleted file mode 100644 index 777cbfe161..0000000000 Binary files a/protocols/JabberG/icos/arrow_down.ico and /dev/null differ diff --git a/protocols/JabberG/icos/arrow_up.ico b/protocols/JabberG/icos/arrow_up.ico deleted file mode 100644 index 543644cbbc..0000000000 Binary files a/protocols/JabberG/icos/arrow_up.ico and /dev/null differ diff --git a/protocols/JabberG/icos/auth_revoke.ico b/protocols/JabberG/icos/auth_revoke.ico deleted file mode 100644 index 42dda06ce4..0000000000 Binary files a/protocols/JabberG/icos/auth_revoke.ico and /dev/null differ diff --git a/protocols/JabberG/icos/bookmarks.ico b/protocols/JabberG/icos/bookmarks.ico deleted file mode 100644 index e66ee868f9..0000000000 Binary files a/protocols/JabberG/icos/bookmarks.ico and /dev/null differ diff --git a/protocols/JabberG/icos/command.ico b/protocols/JabberG/icos/command.ico deleted file mode 100644 index 1138c0b882..0000000000 Binary files a/protocols/JabberG/icos/command.ico and /dev/null differ diff --git a/protocols/JabberG/icos/console.ico b/protocols/JabberG/icos/console.ico deleted file mode 100644 index ec2ea2159f..0000000000 Binary files a/protocols/JabberG/icos/console.ico and /dev/null differ diff --git a/protocols/JabberG/icos/delete.ico b/protocols/JabberG/icos/delete.ico deleted file mode 100644 index e4b674dcd5..0000000000 Binary files a/protocols/JabberG/icos/delete.ico and /dev/null differ diff --git a/protocols/JabberG/icos/disco_fail.ico b/protocols/JabberG/icos/disco_fail.ico deleted file mode 100644 index 39e5a1b800..0000000000 Binary files a/protocols/JabberG/icos/disco_fail.ico and /dev/null differ diff --git a/protocols/JabberG/icos/disco_in_progress.ico b/protocols/JabberG/icos/disco_in_progress.ico deleted file mode 100644 index c1c3e243c5..0000000000 Binary files a/protocols/JabberG/icos/disco_in_progress.ico and /dev/null differ diff --git a/protocols/JabberG/icos/disco_ok.ico b/protocols/JabberG/icos/disco_ok.ico deleted file mode 100644 index d117a9ab46..0000000000 Binary files a/protocols/JabberG/icos/disco_ok.ico and /dev/null differ diff --git a/protocols/JabberG/icos/filter.ico b/protocols/JabberG/icos/filter.ico deleted file mode 100644 index f4d5347cea..0000000000 Binary files a/protocols/JabberG/icos/filter.ico and /dev/null differ diff --git a/protocols/JabberG/icos/go.ico b/protocols/JabberG/icos/go.ico deleted file mode 100644 index 22abe8e7cc..0000000000 Binary files a/protocols/JabberG/icos/go.ico and /dev/null differ diff --git a/protocols/JabberG/icos/grant.ico b/protocols/JabberG/icos/grant.ico deleted file mode 100644 index 8e18fe3754..0000000000 Binary files a/protocols/JabberG/icos/grant.ico and /dev/null differ diff --git a/protocols/JabberG/icos/group.ico b/protocols/JabberG/icos/group.ico deleted file mode 100644 index 3e4cfcc606..0000000000 Binary files a/protocols/JabberG/icos/group.ico and /dev/null differ diff --git a/protocols/JabberG/icos/home.ico b/protocols/JabberG/icos/home.ico deleted file mode 100644 index 2328a8ef16..0000000000 Binary files a/protocols/JabberG/icos/home.ico and /dev/null differ diff --git a/protocols/JabberG/icos/jabber.ico b/protocols/JabberG/icos/jabber.ico deleted file mode 100644 index 61644cbfe9..0000000000 Binary files a/protocols/JabberG/icos/jabber.ico and /dev/null differ diff --git a/protocols/JabberG/icos/key.ico b/protocols/JabberG/icos/key.ico deleted file mode 100644 index 17f9bc23e8..0000000000 Binary files a/protocols/JabberG/icos/key.ico and /dev/null differ diff --git a/protocols/JabberG/icos/login.ico b/protocols/JabberG/icos/login.ico deleted file mode 100644 index 5b72f5e87a..0000000000 Binary files a/protocols/JabberG/icos/login.ico and /dev/null differ diff --git a/protocols/JabberG/icos/message_allow.ico b/protocols/JabberG/icos/message_allow.ico deleted file mode 100644 index b82dc84cb4..0000000000 Binary files a/protocols/JabberG/icos/message_allow.ico and /dev/null differ diff --git a/protocols/JabberG/icos/message_deny.ico b/protocols/JabberG/icos/message_deny.ico deleted file mode 100644 index 4f67487b7a..0000000000 Binary files a/protocols/JabberG/icos/message_deny.ico and /dev/null differ diff --git a/protocols/JabberG/icos/notes.ico b/protocols/JabberG/icos/notes.ico deleted file mode 100644 index 4a2eb48dfa..0000000000 Binary files a/protocols/JabberG/icos/notes.ico and /dev/null differ diff --git a/protocols/JabberG/icos/open.ico b/protocols/JabberG/icos/open.ico deleted file mode 100644 index bc56c4f149..0000000000 Binary files a/protocols/JabberG/icos/open.ico and /dev/null differ diff --git a/protocols/JabberG/icos/openid.ico b/protocols/JabberG/icos/openid.ico deleted file mode 100644 index d8e2f9f240..0000000000 Binary files a/protocols/JabberG/icos/openid.ico and /dev/null differ diff --git a/protocols/JabberG/icos/pages.ico b/protocols/JabberG/icos/pages.ico deleted file mode 100644 index 715b7a1bec..0000000000 Binary files a/protocols/JabberG/icos/pages.ico and /dev/null differ diff --git a/protocols/JabberG/icos/plist_active.ico b/protocols/JabberG/icos/plist_active.ico deleted file mode 100644 index 3cffd4d21d..0000000000 Binary files a/protocols/JabberG/icos/plist_active.ico and /dev/null differ diff --git a/protocols/JabberG/icos/plist_any.ico b/protocols/JabberG/icos/plist_any.ico deleted file mode 100644 index 052e670921..0000000000 Binary files a/protocols/JabberG/icos/plist_any.ico and /dev/null differ diff --git a/protocols/JabberG/icos/plist_default.ico b/protocols/JabberG/icos/plist_default.ico deleted file mode 100644 index f282227f9a..0000000000 Binary files a/protocols/JabberG/icos/plist_default.ico and /dev/null differ diff --git a/protocols/JabberG/icos/presence_in_allow.ico b/protocols/JabberG/icos/presence_in_allow.ico deleted file mode 100644 index 400b8b6f13..0000000000 Binary files a/protocols/JabberG/icos/presence_in_allow.ico and /dev/null differ diff --git a/protocols/JabberG/icos/presence_in_deny.ico b/protocols/JabberG/icos/presence_in_deny.ico deleted file mode 100644 index 99bd3a0ec7..0000000000 Binary files a/protocols/JabberG/icos/presence_in_deny.ico and /dev/null differ diff --git a/protocols/JabberG/icos/presence_out_allow.ico b/protocols/JabberG/icos/presence_out_allow.ico deleted file mode 100644 index b7d644e8fb..0000000000 Binary files a/protocols/JabberG/icos/presence_out_allow.ico and /dev/null differ diff --git a/protocols/JabberG/icos/presence_out_deny.ico b/protocols/JabberG/icos/presence_out_deny.ico deleted file mode 100644 index 8bfa078d5b..0000000000 Binary files a/protocols/JabberG/icos/presence_out_deny.ico and /dev/null differ diff --git a/protocols/JabberG/icos/privacy_lists.ico b/protocols/JabberG/icos/privacy_lists.ico deleted file mode 100644 index 2a55157ff7..0000000000 Binary files a/protocols/JabberG/icos/privacy_lists.ico and /dev/null differ diff --git a/protocols/JabberG/icos/query_allow.ico b/protocols/JabberG/icos/query_allow.ico deleted file mode 100644 index e6c3a4bfe6..0000000000 Binary files a/protocols/JabberG/icos/query_allow.ico and /dev/null differ diff --git a/protocols/JabberG/icos/query_deny.ico b/protocols/JabberG/icos/query_deny.ico deleted file mode 100644 index dd358a484e..0000000000 Binary files a/protocols/JabberG/icos/query_deny.ico and /dev/null differ diff --git a/protocols/JabberG/icos/refresh.ico b/protocols/JabberG/icos/refresh.ico deleted file mode 100644 index 81c6d95f4a..0000000000 Binary files a/protocols/JabberG/icos/refresh.ico and /dev/null differ diff --git a/protocols/JabberG/icos/refresh_node.ico b/protocols/JabberG/icos/refresh_node.ico deleted file mode 100644 index 6c7efc744f..0000000000 Binary files a/protocols/JabberG/icos/refresh_node.ico and /dev/null differ diff --git a/protocols/JabberG/icos/rename.ico b/protocols/JabberG/icos/rename.ico deleted file mode 100644 index fa8abc8785..0000000000 Binary files a/protocols/JabberG/icos/rename.ico and /dev/null differ diff --git a/protocols/JabberG/icos/request.ico b/protocols/JabberG/icos/request.ico deleted file mode 100644 index 94ee8e60c3..0000000000 Binary files a/protocols/JabberG/icos/request.ico and /dev/null differ diff --git a/protocols/JabberG/icos/reset_filter.ico b/protocols/JabberG/icos/reset_filter.ico deleted file mode 100644 index e1e54dbeb6..0000000000 Binary files a/protocols/JabberG/icos/reset_filter.ico and /dev/null differ diff --git a/protocols/JabberG/icos/roster.ico b/protocols/JabberG/icos/roster.ico deleted file mode 100644 index 89e9430443..0000000000 Binary files a/protocols/JabberG/icos/roster.ico and /dev/null differ diff --git a/protocols/JabberG/icos/rss.ico b/protocols/JabberG/icos/rss.ico deleted file mode 100644 index 9069672b7d..0000000000 Binary files a/protocols/JabberG/icos/rss.ico and /dev/null differ diff --git a/protocols/JabberG/icos/save.ico b/protocols/JabberG/icos/save.ico deleted file mode 100644 index fadf04c4da..0000000000 Binary files a/protocols/JabberG/icos/save.ico and /dev/null differ diff --git a/protocols/JabberG/icos/send_note.ico b/protocols/JabberG/icos/send_note.ico deleted file mode 100644 index c77fa5e35d..0000000000 Binary files a/protocols/JabberG/icos/send_note.ico and /dev/null differ diff --git a/protocols/JabberG/icos/server.ico b/protocols/JabberG/icos/server.ico deleted file mode 100644 index 1e4af66351..0000000000 Binary files a/protocols/JabberG/icos/server.ico and /dev/null differ diff --git a/protocols/JabberG/icos/service_discovery.ico b/protocols/JabberG/icos/service_discovery.ico deleted file mode 100644 index b361d5ab2a..0000000000 Binary files a/protocols/JabberG/icos/service_discovery.ico and /dev/null differ diff --git a/protocols/JabberG/icos/store.ico b/protocols/JabberG/icos/store.ico deleted file mode 100644 index 86efc4935e..0000000000 Binary files a/protocols/JabberG/icos/store.ico and /dev/null differ diff --git a/protocols/JabberG/icos/transport.ico b/protocols/JabberG/icos/transport.ico deleted file mode 100644 index 5082add068..0000000000 Binary files a/protocols/JabberG/icos/transport.ico and /dev/null differ diff --git a/protocols/JabberG/icos/transport_local.ico b/protocols/JabberG/icos/transport_local.ico deleted file mode 100644 index c1b79901a2..0000000000 Binary files a/protocols/JabberG/icos/transport_local.ico and /dev/null differ diff --git a/protocols/JabberG/icos/user2room.ico b/protocols/JabberG/icos/user2room.ico deleted file mode 100644 index 94c37db75e..0000000000 Binary files a/protocols/JabberG/icos/user2room.ico and /dev/null differ diff --git a/protocols/JabberG/icos/view_as_list.ico b/protocols/JabberG/icos/view_as_list.ico deleted file mode 100644 index 6baf9d9d3d..0000000000 Binary files a/protocols/JabberG/icos/view_as_list.ico and /dev/null differ diff --git a/protocols/JabberG/icos/view_as_tree.ico b/protocols/JabberG/icos/view_as_tree.ico deleted file mode 100644 index 0a1c408f34..0000000000 Binary files a/protocols/JabberG/icos/view_as_tree.ico and /dev/null differ diff --git a/protocols/JabberG/icos/weather.ico b/protocols/JabberG/icos/weather.ico deleted file mode 100644 index 6fa9c8f5a5..0000000000 Binary files a/protocols/JabberG/icos/weather.ico and /dev/null differ diff --git a/protocols/JabberG/jabber.cpp b/protocols/JabberG/jabber.cpp deleted file mode 100644 index a3dd31a3fa..0000000000 --- a/protocols/JabberG/jabber.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "jabber_rc.h" - -#include - -#include -#include - -#include "m_assocmgr.h" -#include "m_folders.h" -#include "m_toptoolbar.h" -#include "m_extraicons.h" - -HINSTANCE hInst; - -int hLangpack; - -int g_cbCountries; -struct CountryListEntry* g_countries; - -TCHAR szCoreVersion[100]; - -PLUGININFOEX pluginInfo = { - sizeof( PLUGININFOEX ), - "Jabber Protocol", - __VERSION_DWORD, - "Jabber protocol plugin for Miranda NG.", - "George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura", - "ghazan@miranda-im.org", - "(c) 2005-2012 George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura", - "http://miranda-ng.org/", - UNICODE_AWARE, - {0x144e80a2, 0xd198, 0x428b, {0xac, 0xbe, 0x9d, 0x55, 0xda, 0xcc, 0x7f, 0xde}} // {144E80A2-D198-428b-ACBE-9D55DACC7FDE} -}; - -XML_API xi; -TIME_API tmi; - -CLIST_INTERFACE* pcli; - -///////////////////////////////////////////////////////////////////////////// -// Theme API -BOOL (WINAPI *JabberAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION) = NULL; -BOOL (WINAPI *JabberIsThemeActive)() = NULL; -HRESULT (WINAPI *JabberDrawThemeParentBackground)(HWND, HDC, RECT *) = NULL; -///////////////////////////////////////////////////////////////////////////// - -BOOL jabberChatDllPresent = FALSE; -HANDLE hModulesLoaded, hModulesLoadedTB; - -HANDLE hExtraActivity = NULL; -HANDLE hExtraMood = NULL; - -void JabberUserInfoInit(void); - -int bSecureIM; - -///////////////////////////////////////////////////////////////////////////// -// Protocol instances -static int sttCompareProtocols(const CJabberProto *p1, const CJabberProto *p2) -{ - return lstrcmp(p1->m_tszUserName, p2->m_tszUserName); -} - -LIST g_Instances(1, sttCompareProtocols); -///////////////////////////////////////////////////////////////////////////// - -BOOL WINAPI DllMain( HINSTANCE hModule, DWORD, LPVOID ) -{ - hInst = hModule; - return TRUE; -} - -extern "C" __declspec( dllexport ) PLUGININFOEX *MirandaPluginInfoEx( DWORD mirandaVersion ) -{ - return &pluginInfo; -} - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - -/////////////////////////////////////////////////////////////////////////////// -// OnPreShutdown - prepares Miranda to be shut down - -int __cdecl CJabberProto::OnPreShutdown( WPARAM, LPARAM ) -{ - UI_SAFE_CLOSE_HWND(m_hwndAgentRegInput); - UI_SAFE_CLOSE_HWND(m_hwndRegProgress); - UI_SAFE_CLOSE_HWND(m_hwndMucVoiceList); - UI_SAFE_CLOSE_HWND(m_hwndMucMemberList); - UI_SAFE_CLOSE_HWND(m_hwndMucModeratorList); - UI_SAFE_CLOSE_HWND(m_hwndMucBanList); - UI_SAFE_CLOSE_HWND(m_hwndMucAdminList); - UI_SAFE_CLOSE_HWND(m_hwndMucOwnerList); - UI_SAFE_CLOSE_HWND(m_hwndJabberChangePassword); - UI_SAFE_CLOSE_HWND(m_hwndJabberAddBookmark); - UI_SAFE_CLOSE_HWND(m_hwndPrivacyRule); - - UI_SAFE_CLOSE(m_pDlgPrivacyLists); - UI_SAFE_CLOSE(m_pDlgBookmarks); - UI_SAFE_CLOSE(m_pDlgServiceDiscovery); - UI_SAFE_CLOSE(m_pDlgJabberJoinGroupchat); - UI_SAFE_CLOSE(m_pDlgNotes); - - m_iqManager.ExpireAll(); - m_iqManager.Shutdown(); - m_messageManager.Shutdown(); - m_presenceManager.Shutdown(); - m_sendManager.Shutdown(); - ConsoleUninit(); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnModulesLoaded - execute some code when all plugins are initialized - -static INT_PTR g_SvcParseXmppUri(WPARAM w, LPARAM l) -{ - if (CJabberProto *ppro = JabberChooseInstance(true)) - return ppro->JabberServiceParseXmppURI(w, l); - return 0; -} - -static int OnModulesLoaded( WPARAM, LPARAM ) -{ - hModulesLoadedTB = HookEvent(ME_TTB_MODULELOADED, g_OnToolbarInit); - - bSecureIM = (ServiceExists("SecureIM/IsContactSecured")); - - // file associations manager plugin support - if ( ServiceExists( MS_ASSOCMGR_ADDNEWURLTYPE )) { - CreateServiceFunction("JABBER/*" JS_PARSE_XMPP_URI, g_SvcParseXmppUri ); - AssocMgr_AddNewUrlTypeT( "xmpp:", TranslateT("Jabber Link Protocol"), hInst, IDI_JABBER, "JABBER/*" JS_PARSE_XMPP_URI, 0 ); - } - - // init fontservice for info frame - FontID fontid = {0}; - fontid.cbSize = sizeof(fontid); - strcpy(fontid.group, "Jabber"); - strcpy(fontid.dbSettingsGroup, GLOBAL_SETTING_MODULE); - strcpy(fontid.backgroundGroup, "Jabber"); - strcpy(fontid.backgroundName,"Background"); - fontid.flags = FIDF_DEFAULTVALID; - - fontid.deffontsettings.charset = DEFAULT_CHARSET; - fontid.deffontsettings.colour = GetSysColor(COLOR_WINDOWTEXT); - fontid.deffontsettings.size = -11; - lstrcpyA(fontid.deffontsettings.szFace, "MS Shell Dlg"); - fontid.deffontsettings.style = 0; - - strcpy(fontid.name, "Frame title"); - strcpy(fontid.prefix, "fntFrameTitle"); - fontid.deffontsettings.style = DBFONTF_BOLD; - FontRegister(&fontid); - - strcpy(fontid.name, "Frame text"); - strcpy(fontid.prefix, "fntFrameClock"); - fontid.deffontsettings.style = 0; - FontRegister(&fontid); - - ColourID colourid = {0}; - colourid.cbSize = sizeof(colourid); - strcpy(colourid.group, "Jabber"); - strcpy(colourid.dbSettingsGroup, GLOBAL_SETTING_MODULE); - - strcpy(colourid.name, "Background"); - strcpy(colourid.setting, "clFrameBack"); - colourid.defcolour = GetSysColor(COLOR_WINDOW); - ColourRegister(&colourid); - - // Init extra icons - hExtraActivity = ExtraIcon_Register("activity", "Jabber Activity" /* No icons registered, "working" */); - hExtraMood = ExtraIcon_Register("mood", "Jabber Mood" /* No icons registered, "amazed" */); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnLoad - initialize the plugin instance - -static CJabberProto* jabberProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) -{ - CJabberProto *ppro = new CJabberProto( pszProtoName, tszUserName ); - g_Instances.insert(ppro); - return ppro; -} - -static int jabberProtoUninit( CJabberProto* ppro ) -{ - g_Instances.remove(ppro); - delete ppro; - return 0; -} - -extern "C" int __declspec( dllexport ) Load() -{ - // set the memory, lists & utf8 managers - mir_getXI( &xi ); - mir_getTMI( &tmi ); - mir_getLP( &pluginInfo ); - - WORD v[4]; - CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)v); - mir_sntprintf(szCoreVersion, SIZEOF(szCoreVersion), _T("%d.%d.%d.%d"), v[0], v[1], v[2], v[3]); - - CallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM )&g_cbCountries, ( LPARAM )&g_countries ); - - setlocale(LC_ALL, ""); - - pcli = ( CLIST_INTERFACE* )CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, (LPARAM)hInst); - - // Register protocol module - PROTOCOLDESCRIPTOR pd; - ZeroMemory( &pd, sizeof( PROTOCOLDESCRIPTOR )); - pd.cbSize = sizeof( PROTOCOLDESCRIPTOR ); - pd.szName = "JABBER"; - pd.fnInit = ( pfnInitProto )jabberProtoInit; - pd.fnUninit = ( pfnUninitProto )jabberProtoUninit; - pd.type = PROTOTYPE_PROTOCOL; - CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd ); - - // Load some fuctions - HMODULE hDll; - if ( hDll = GetModuleHandleA( "gdi32.dll" )) - JabberAlphaBlend = (BOOL (WINAPI *)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION)) GetProcAddress(hDll, "GdiAlphaBlend"); - if ( JabberAlphaBlend == NULL && ( hDll = LoadLibraryA("msimg32.dll" ))) - JabberAlphaBlend = (BOOL (WINAPI *)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION)) GetProcAddress(hDll, "AlphaBlend"); - - if ( IsWinVerXPPlus()) { - if ( hDll = GetModuleHandleA("uxtheme")) { - JabberDrawThemeParentBackground = (HRESULT (WINAPI *)(HWND,HDC,RECT *))GetProcAddress(hDll, "DrawThemeParentBackground"); - JabberIsThemeActive = (BOOL (WINAPI *)())GetProcAddress(hDll, "IsThemeActive"); - } } - - g_IconsInit(); - g_MenuInit(); - hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); - JabberUserInfoInit(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Unload - destroy the plugin instance - -extern "C" int __declspec( dllexport ) Unload( void ) -{ - UnhookEvent(hModulesLoaded); - UnhookEvent(hModulesLoadedTB); - - g_MenuUninit(); - - g_Instances.destroy(); - return 0; -} diff --git a/protocols/JabberG/jabber.h b/protocols/JabberG/jabber.h deleted file mode 100644 index 957b7d66bf..0000000000 --- a/protocols/JabberG/jabber.h +++ /dev/null @@ -1,767 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_H_ -#define _JABBER_H_ - -#ifdef _MSC_VER - #pragma warning(disable:4706 4121 4127) -#endif - -#define MIRANDA_VER 0x0A00 - -#include "m_stdhdr.h" - -#define LISTFOREACH(var__, obj__, list__) \ - for (int var__ = 0; (var__ = obj__->ListFindNext(list__, var__)) >= 0; ++var__) -#define LISTFOREACH_NODEF(var__, obj__, list__) \ - for (var__ = 0; (var__ = obj__->ListFindNext(list__, var__)) >= 0; ++var__) - -/******************************************************************* - * Global header files - *******************************************************************/ -#define _WIN32_WINNT 0x501 -#define _WIN32_IE 0x501 -#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 -#include -#include -#include -#include -#include -#include -#include - -#include "../../plugins/zlib/zlib.h" - -#include "resource.h" -#include "version.h" - -#include "MString.h" - -#include "jabber_xml.h" -#include "jabber_byte.h" -#include "jabber_ibb.h" -#include "jabber_db_utils.h" -#include "ui_utils.h" - -struct CJabberProto; - -class CJabberDlgBase: public CProtoDlgBase -{ - typedef CProtoDlgBase CSuper; -protected: - __inline CJabberDlgBase(CJabberProto *proto, int idDialog, HWND parent, bool show_label=true ) : - CSuper( proto, idDialog, parent, show_label ) - { - } - - int Resizer(UTILRESIZECONTROL *urc) - { - switch (urc->wId) { - case IDC_HEADERBAR: - urc->rcItem.right = urc->dlgNewSize.cx; - return 0; - } - - return CSuper::Resizer(urc); - } -}; - -#if !defined(OPENFILENAME_SIZE_VERSION_400) - #define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME) -#endif - -/******************************************************************* - * Global constants - *******************************************************************/ - -#define GLOBAL_SETTING_PREFIX "JABBER" -#define GLOBAL_SETTING_MODULE "JABBER" - -#define JABBER_DEFAULT_PORT 5222 -#define JABBER_IQID "mir_" -#define JABBER_MAX_JID_LEN 1024 - -#define JABBER_GC_MSG_QUIT LPGENT("I'm happy Miranda NG user. Get it at http://miranda-ng.org/.") -#define JABBER_GC_MSG_SLAP LPGENT("/me slaps %s around a bit with a large trout") - -// registered db event types -#define JABBER_DB_EVENT_TYPE_CHATSTATES 2000 -#define JS_DB_GETEVENTTEXT_CHATSTATES "/GetEventText2000" -#define JABBER_DB_EVENT_CHATSTATES_GONE 1 -#define JABBER_DB_EVENT_TYPE_PRESENCE 2001 -#define JS_DB_GETEVENTTEXT_PRESENCE "/GetEventText2001" -#define JABBER_DB_EVENT_PRESENCE_SUBSCRIBE 1 -#define JABBER_DB_EVENT_PRESENCE_SUBSCRIBED 2 -#define JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE 3 -#define JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED 4 -#define JABBER_DB_EVENT_PRESENCE_ERROR 5 - -// User-defined message -#define WM_JABBER_REGDLG_UPDATE (WM_PROTO_LAST + 100) -#define WM_JABBER_AGENT_REFRESH (WM_PROTO_LAST + 101) -#define WM_JABBER_TRANSPORT_REFRESH (WM_PROTO_LAST + 102) -#define WM_JABBER_REGINPUT_ACTIVATE (WM_PROTO_LAST + 103) -#define WM_JABBER_REFRESH WM_PROTO_REFRESH -#define WM_JABBER_CHECK_ONLINE WM_PROTO_CHECK_ONLINE -#define WM_JABBER_ACTIVATE WM_PROTO_ACTIVATE -#define WM_JABBER_CHANGED (WM_PROTO_LAST + 106) -#define WM_JABBER_SET_FONT (WM_PROTO_LAST + 108) -#define WM_JABBER_FLASHWND (WM_PROTO_LAST + 109) -#define WM_JABBER_GC_MEMBER_ADD (WM_PROTO_LAST + 110) -#define WM_JABBER_GC_FORCE_QUIT (WM_PROTO_LAST + 111) -#define WM_JABBER_SHUTDOWN (WM_PROTO_LAST + 112) -#define WM_JABBER_SMILEY (WM_PROTO_LAST + 113) -#define WM_JABBER_JOIN (WM_PROTO_LAST + 114) -#define WM_JABBER_ADD_TO_ROSTER (WM_PROTO_LAST + 115) -#define WM_JABBER_ADD_TO_BOOKMARKS (WM_PROTO_LAST + 116) -#define WM_JABBER_REFRESH_VCARD (WM_PROTO_LAST + 117) - - -// Error code -#define JABBER_ERROR_REDIRECT 302 -#define JABBER_ERROR_BAD_REQUEST 400 -#define JABBER_ERROR_UNAUTHORIZED 401 -#define JABBER_ERROR_PAYMENT_REQUIRED 402 -#define JABBER_ERROR_FORBIDDEN 403 -#define JABBER_ERROR_NOT_FOUND 404 -#define JABBER_ERROR_NOT_ALLOWED 405 -#define JABBER_ERROR_NOT_ACCEPTABLE 406 -#define JABBER_ERROR_REGISTRATION_REQUIRED 407 -#define JABBER_ERROR_REQUEST_TIMEOUT 408 -#define JABBER_ERROR_CONFLICT 409 -#define JABBER_ERROR_INTERNAL_SERVER_ERROR 500 -#define JABBER_ERROR_NOT_IMPLEMENTED 501 -#define JABBER_ERROR_REMOTE_SERVER_ERROR 502 -#define JABBER_ERROR_SERVICE_UNAVAILABLE 503 -#define JABBER_ERROR_REMOTE_SERVER_TIMEOUT 504 - -// Vcard flags -#define JABBER_VCEMAIL_HOME 1 -#define JABBER_VCEMAIL_WORK 2 -#define JABBER_VCEMAIL_INTERNET 4 -#define JABBER_VCEMAIL_X400 8 - -#define JABBER_VCTEL_HOME 0x0001 -#define JABBER_VCTEL_WORK 0x0002 -#define JABBER_VCTEL_VOICE 0x0004 -#define JABBER_VCTEL_FAX 0x0008 -#define JABBER_VCTEL_PAGER 0x0010 -#define JABBER_VCTEL_MSG 0x0020 -#define JABBER_VCTEL_CELL 0x0040 -#define JABBER_VCTEL_VIDEO 0x0080 -#define JABBER_VCTEL_BBS 0x0100 -#define JABBER_VCTEL_MODEM 0x0200 -#define JABBER_VCTEL_ISDN 0x0400 -#define JABBER_VCTEL_PCS 0x0800 - -// File transfer setting -#define JABBER_OPTION_FT_DIRECT 0 // Direct connection -#define JABBER_OPTION_FT_PASS 1 // Use PASS server -#define JABBER_OPTION_FT_PROXY 2 // Use proxy with local port forwarding - -// Font style saved in DB -#define JABBER_FONT_BOLD 1 -#define JABBER_FONT_ITALIC 2 - -// Font for groupchat log dialog -#define JABBER_GCLOG_NUM_FONT 6 // 6 fonts ( 0:send, 1:msg, 2:time, 3:nick, 4:sys, 5:/me ) - -// Old SDK don't have this -#ifndef SPI_GETSCREENSAVERRUNNING -#define SPI_GETSCREENSAVERRUNNING 114 -#endif - -// Icon list -enum { - JABBER_IDI_GCOWNER = 0, - JABBER_IDI_GCADMIN, - JABBER_IDI_GCMODERATOR, - JABBER_IDI_GCVOICE, - JABBER_ICON_TOTAL -}; - -// Services and Events -#define JS_PARSE_XMPP_URI "/ParseXmppURI" - -// XEP-0224 support (Attention/Nudge) -#define JS_SEND_NUDGE "/SendNudge" -#define JE_NUDGE "/Nudge" - -// Called when contact changes custom status and extra icon is set to clist_mw -//wParam = hContact // contact changing status -//lParam = hIcon // HANDLE to clist extra icon set as custom status -#define JE_CUSTOMSTATUS_EXTRAICON_CHANGED "/XStatusExtraIconChanged" -#define JE_CUSTOMSTATUS_CHANGED "/XStatusChanged" - -#define LR_BIGICON 0x40 - -#define JS_SENDXML "/SendXML" // Warning: This service is obsolete. Use IJabberNetInterface::SendXmlNode() instead. -#define JS_GETADVANCEDSTATUSICON "/GetAdvancedStatusIcon" -#define JS_GETCUSTOMSTATUSICON "/GetXStatusIcon" -#define JS_GETXSTATUS "/GetXStatus" -#define JS_SETXSTATUS "/SetXStatus" - -#define JS_HTTP_AUTH "/HttpAuthRequest" -#define JS_INCOMING_NOTE_EVENT "/IncomingNoteEvent" - -#define DBSETTING_DISPLAY_UID "display_uid" -#define DBSETTING_XSTATUSID "XStatusId" -#define DBSETTING_XSTATUSNAME "XStatusName" -#define DBSETTING_XSTATUSMSG "XStatusMsg" - -#define ADVSTATUS_MOOD "mood" -#define ADVSTATUS_ACTIVITY "activity" -#define ADVSTATUS_TUNE "tune" - -#define ADVSTATUS_VAL_ID "id" -#define ADVSTATUS_VAL_ICON "icon" -#define ADVSTATUS_VAL_TITLE "title" -#define ADVSTATUS_VAL_TEXT "text" - -struct CJabberHttpAuthParams -{ - enum {IQ = 1, MSG = 2} m_nType; - TCHAR *m_szFrom; - TCHAR *m_szIqId; - TCHAR *m_szThreadId; - TCHAR *m_szId; - TCHAR *m_szMethod; - TCHAR *m_szUrl; - CJabberHttpAuthParams() - { - ZeroMemory(this, sizeof(CJabberHttpAuthParams)); - } - ~CJabberHttpAuthParams() - { - Free(); - } - void Free() - { - mir_free(m_szFrom); - mir_free(m_szIqId); - mir_free(m_szThreadId); - mir_free(m_szId); - mir_free(m_szMethod); - mir_free(m_szUrl); - ZeroMemory(this, sizeof(CJabberHttpAuthParams)); - } -}; - -/******************************************************************* - * Global data structures and data type definitions - *******************************************************************/ -typedef HANDLE JABBER_SOCKET; - -enum JABBER_SESSION_TYPE -{ - JABBER_SESSION_NORMAL, - JABBER_SESSION_REGISTER -}; - -#define CAPS_BOOKMARK 0x0001 -#define CAPS_BOOKMARKS_LOADED 0x8000 - -#define ZLIB_CHUNK_SIZE 2048 - -#include "jabber_caps.h" - -#define JABBER_LOGIN_ROSTER 0x0001 -#define JABBER_LOGIN_BOOKMARKS 0x0002 -#define JABBER_LOGIN_SERVERINFO 0x0004 -#define JABBER_LOGIN_BOOKMARKS_AJ 0x0008 - -struct ThreadData -{ - ThreadData( CJabberProto* _ppro, JABBER_SESSION_TYPE parType ); - ~ThreadData(); - - HANDLE hThread; - JABBER_SESSION_TYPE type; - - // network support - JABBER_SOCKET s; - BOOL useSSL; - HANDLE iomutex; // protects i/o operations - CJabberProto* proto; - - // XEP-0138 (Compression support) - BOOL useZlib; - z_stream zStreamIn,zStreamOut; - bool zRecvReady; - int zRecvDatalen; - char* zRecvData; - - void xmpp_client_query( void ); - - BOOL zlibInit( void ); - void zlibUninit(); - int zlibSend( char* data, int datalen ); - int zlibRecv( char* data, long datalen ); - - // for nick names resolving - int resolveID; - HANDLE resolveContact; - - // features & registration - HWND reg_hwndDlg; - BOOL reg_done, bIsSessionAvailable; - class TJabberAuth* auth; - JabberCapsBits jabberServerCaps; - BOOL bBookmarksLoaded; - DWORD dwLoginRqs; - - // connection & login data - TCHAR username[512]; - TCHAR password[512]; - char server[128]; - char manualHost[128]; - TCHAR resource[128]; - TCHAR fullJID[JABBER_MAX_JID_LEN]; - WORD port; - TCHAR newPassword[512]; - - void close( void ); - void shutdown( void ); - int recv( char* buf, size_t len ); - int send( char* buffer, int bufsize ); - int send( const char* fmt, ... ); - int send( HXML node ); - - int recvws( char* buffer, size_t bufsize, int flags ); - int sendws( char* buffer, size_t bufsize, int flags ); -}; - -struct JABBER_MODEMSGS -{ - TCHAR* szOnline; - TCHAR* szAway; - TCHAR* szNa; - TCHAR* szDnd; - TCHAR* szFreechat; -}; - -struct JABBER_REG_ACCOUNT -{ - TCHAR username[512]; - TCHAR password[512]; - char server[128]; - char manualHost[128]; - WORD port; - BOOL useSSL; -}; - -typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM, FT_IBB } JABBER_FT_TYPE; -typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED } JABBER_FILE_STATE; - -struct filetransfer -{ - filetransfer( CJabberProto* proto ); - ~filetransfer(); - - void close(); - void complete(); - int create(); - - PROTOFILETRANSFERSTATUS std; - -// HANDLE hContact; - JABBER_FT_TYPE type; - JABBER_SOCKET s; - JABBER_FILE_STATE state; - TCHAR* jid; - int fileId; - TCHAR* iqId; - TCHAR* sid; - int bCompleted; - HANDLE hWaitEvent; - - // For type == FT_BYTESTREAM - JABBER_BYTE_TRANSFER *jbt; - - JABBER_IBB_TRANSFER *jibb; - - // Used by file receiving only - char* httpHostName; - WORD httpPort; - TCHAR* httpPath; - unsigned __int64 dwExpectedRecvFileSize; - - // Used by file sending only - HANDLE hFileEvent; - unsigned __int64 *fileSize; - TCHAR* szDescription; - - CJabberProto* ppro; -}; - -struct JABBER_SEARCH_RESULT -{ - PROTOSEARCHRESULT hdr; - TCHAR jid[JABBER_MAX_JID_LEN]; -}; - -struct JABBER_GCLOG_FONT -{ - char face[LF_FACESIZE]; // LF_FACESIZE is from LOGFONT struct - BYTE style; - char size; // signed - BYTE charset; - COLORREF color; -}; - -struct JABBER_FIELD_MAP -{ - int id; - char* name; -}; - -enum JABBER_MUC_JIDLIST_TYPE -{ - MUC_VOICELIST, - MUC_MEMBERLIST, - MUC_MODERATORLIST, - MUC_BANLIST, - MUC_ADMINLIST, - MUC_OWNERLIST -}; - -struct JABBER_MUC_JIDLIST_INFO -{ - ~JABBER_MUC_JIDLIST_INFO(); - - JABBER_MUC_JIDLIST_TYPE type; - TCHAR* roomJid; // filled-in by the WM_JABBER_REFRESH code - HXML iqNode; - CJabberProto* ppro; - - TCHAR* type2str( void ) const; -}; - -typedef void ( CJabberProto::*JABBER_FORM_SUBMIT_FUNC )( HXML values, void *userdata ); - -//---- jabber_treelist.c ------------------------------------------------ - -typedef struct TTreeList_ItemInfo *HTREELISTITEM; -enum { TLM_TREE, TLM_REPORT }; - -//---- proto frame ------------------------------------------------ - -class CJabberInfoFrameItem; - -struct CJabberInfoFrame_Event -{ - enum { CLICK, DESTROY } m_event; - const char *m_pszName; - LPARAM m_pUserData; -}; - -class CJabberInfoFrame -{ -public: - CJabberInfoFrame(CJabberProto *proto); - ~CJabberInfoFrame(); - - void CreateInfoItem(char *pszName, bool bCompact=false, LPARAM pUserData=0); - void SetInfoItemCallback(char *pszName, void (CJabberProto::*onEvent)(CJabberInfoFrame_Event *)); - void UpdateInfoItem(char *pszName, HANDLE hIcolibItem, TCHAR *pszText); - void ShowInfoItem(char *pszName, bool bShow); - void RemoveInfoItem(char *pszName); - - void LockUpdates(); - void Update(); - -private: - CJabberProto *m_proto; - HWND m_hwnd; - int m_frameId; - bool m_compact; - OBJLIST m_pItems; - int m_hiddenItemCount; - int m_clickedItem; - bool m_bLocked; - int m_nextTooltipId; - HWND m_hwndToolTip; - - HANDLE m_hhkFontsChanged; - HFONT m_hfntTitle, m_hfntText; - COLORREF m_clTitle, m_clText, m_clBack; - - static void InitClass(); - static LRESULT CALLBACK GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam); - - void ReloadFonts(); - void UpdateSize(); - - void RemoveTooltip(int id); - void SetToolTip(int id, RECT *rc, TCHAR *pszText); - - void PaintSkinGlyph(HDC hdc, RECT *rc, char **glyphs, COLORREF fallback); - void PaintCompact(HDC hdc); - void PaintNormal(HDC hdc); - - enum - { - SZ_FRAMEPADDING = 2, // padding inside frame - SZ_LINEPADDING = 0, // line height will be incremented by this value - SZ_LINESPACING = 0, // between lines - SZ_ICONSPACING = 2, // between icon and text - }; -}; - -#include "jabber_list.h" -#include "jabber_proto.h" - -/******************************************************************* - * Global variables - *******************************************************************/ -extern HINSTANCE hInst; -extern BOOL jabberChatDllPresent; - -extern HANDLE hExtraMood; -extern HANDLE hExtraActivity; - -// Theme API -extern BOOL (WINAPI *JabberAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); -extern BOOL (WINAPI *JabberIsThemeActive)(); -extern HRESULT (WINAPI *JabberDrawThemeParentBackground)(HWND, HDC, RECT *); - -extern const TCHAR xmlnsOwner[]; -extern TCHAR szCoreVersion[]; - -extern int g_cbCountries; -extern struct CountryListEntry* g_countries; - -/******************************************************************* - * Function declarations - *******************************************************************/ - -//---- jabber_treelist.c ------------------------------------------------ - -void TreeList_Create(HWND hwnd); -void TreeList_Destroy(HWND hwnd); -void TreeList_Reset(HWND hwnd); -void TreeList_SetMode(HWND hwnd, int mode); -HTREELISTITEM TreeList_GetActiveItem(HWND hwnd); -void TreeList_SetSortMode(HWND hwnd, int col, BOOL descending); -void TreeList_SetFilter(HWND hwnd, TCHAR *filter); -HTREELISTITEM TreeList_AddItem(HWND hwnd, HTREELISTITEM hParent, TCHAR *text, LPARAM data); -void TreeList_ResetItem(HWND hwnd, HTREELISTITEM hParent); -void TreeList_MakeFakeParent(HTREELISTITEM hItem, BOOL flag); -void TreeList_AppendColumn(HTREELISTITEM hItem, TCHAR *text); -int TreeList_AddIcon(HWND hwnd, HICON hIcon, int iOverlay); -void TreeList_SetIcon(HTREELISTITEM hItem, int iIcon, int iOverlay); -LPARAM TreeList_GetData(HTREELISTITEM hItem); -HTREELISTITEM TreeList_GetRoot(HWND hwnd); -int TreeList_GetChildrenCount(HTREELISTITEM hItem); -HTREELISTITEM TreeList_GetChild(HTREELISTITEM hItem, int i); -void sttTreeList_RecursiveApply(HTREELISTITEM hItem, void (*func)(HTREELISTITEM, LPARAM), LPARAM data); -void TreeList_Update(HWND hwnd); -BOOL TreeList_ProcessMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT idc, BOOL *result); - -//---- jabber_form.c ------------------------------------------------ - -enum TJabberFormControlType -{ - JFORM_CTYPE_NONE, JFORM_CTYPE_TEXT_PRIVATE, JFORM_CTYPE_TEXT_MULTI, - JFORM_CTYPE_BOOLEAN, JFORM_CTYPE_LIST_SINGLE, JFORM_CTYPE_LIST_MULTI, - JFORM_CTYPE_FIXED, JFORM_CTYPE_HIDDEN, JFORM_CTYPE_TEXT_SINGLE -}; - -typedef struct TJabberFormControlInfo *HJFORMCTRL; -typedef struct TJabberFormLayoutInfo *HJFORMLAYOUT; - -void JabberFormCreateUI( HWND hwndStatic, HXML xNode, int *formHeight, BOOL bCompact = FALSE ); -void JabberFormDestroyUI(HWND hwndStatic); -void JabberFormSetInstruction( HWND hwndForm, const TCHAR *text ); -HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic); // use mir_free to destroy -HJFORMCTRL JabberFormAppendControl(HWND hwndStatic, HJFORMLAYOUT layout_info, TJabberFormControlType type, const TCHAR *labelStr, const TCHAR *valueStr); -void JabberFormAddListItem(HJFORMCTRL item, const TCHAR *text, bool selected); -void JabberFormLayoutControls(HWND hwndStatic, HJFORMLAYOUT layout_info, int *formHeight); - -void JabberFormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ); - -HXML JabberFormGetData( HWND hwndStatic, HXML xNode ); - -//---- jabber_icolib.c ---------------------------------------------- - -void g_IconsInit(); -HANDLE g_GetIconHandle( int iconId ); -HICON g_LoadIconEx( const char* name, bool big = false ); -void g_ReleaseIcon( HICON hIcon ); - -void ImageList_AddIcon_Icolib( HIMAGELIST hIml, HICON hIcon ); -void WindowSetIcon(HWND hWnd, CJabberProto *proto, const char* name); -void WindowFreeIcon(HWND hWnd); - -int ReloadIconsEventHook(WPARAM wParam, LPARAM lParam); - -//---- jabber_libstr.c ---------------------------------------------- - -int lstrcmp_null(const TCHAR *s1, const TCHAR *s2); - -//---- jabber_menu.c ------------------------------------------------ - -void g_MenuInit(); -void g_MenuUninit(); -int g_OnToolbarInit(WPARAM, LPARAM); - -//---- jabber_misc.c ------------------------------------------------ - -void JabberChatDllError( void ); -int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 ); -void JabberContactListCreateGroup( TCHAR* groupName ); -TCHAR* EscapeChatTags(TCHAR* pszText); -TCHAR* UnEscapeChatTags(TCHAR* str_in); - -//---- jabber_adhoc.cpp --------------------------------------------- - -struct CJabberAdhocStartupParams -{ - TCHAR* m_szJid; - TCHAR* m_szNode; - CJabberProto* m_pProto; - - CJabberAdhocStartupParams( CJabberProto* proto, TCHAR* szJid, TCHAR* szNode = NULL ) - { - m_pProto = proto; - m_szJid = mir_tstrdup( szJid ); - m_szNode = szNode ? mir_tstrdup( szNode ) : NULL; - } - ~CJabberAdhocStartupParams() - { - if ( m_szJid ) - mir_free( m_szJid ); - if ( m_szNode ) - mir_free( m_szNode ); - } -}; - -struct JabberAdHocData -{ - CJabberProto* proto; - int CurrentHeight; - int curPos; - int frameHeight; - RECT frameRect; - HXML AdHocNode; - HXML CommandsNode; - TCHAR* ResponderJID; -}; - -//---- jabber_std.cpp ------------------------------------------------------------------- - -void __fastcall JFreeVariant( DBVARIANT* dbv ); -char* __fastcall JTranslate( const char* str ); - -//---- jabber_util.cpp ------------------------------------------------------------------ - -struct TStringPairsElem -{ - const char *name, *value; -}; - -struct TStringPairs -{ - TStringPairs( char* ); - ~TStringPairs(); - - const char* operator[]( const char* name ) const; - - int numElems; - TStringPairsElem* elems; -}; - -TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid ); -TCHAR* JabberPrepareJid( LPCTSTR jid ); -char* __stdcall JabberUrlDecode( char* str ); -void __stdcall JabberUrlDecodeW( WCHAR* str ); -char* __stdcall JabberUrlEncode( const char* str ); -char* __stdcall JabberSha1( char* str ); -TCHAR* __stdcall JabberStrFixLines( const TCHAR* str ); -char* __stdcall JabberUnixToDos( const char* str ); -WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str ); -void __stdcall JabberHttpUrlDecode( TCHAR* str ); -TCHAR* __stdcall JabberHttpUrlEncode( const TCHAR* str ); -int __stdcall JabberCombineStatus( int status1, int status2 ); -TCHAR* __stdcall JabberErrorStr( int errorCode ); -TCHAR* __stdcall JabberErrorMsg( HXML errorNode, int* errorCode = NULL ); -void __stdcall JabberUtfToTchar( const char* str, size_t cbLen, LPTSTR& dest ); -char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen ); -char* __stdcall JabberBase64Decode( const char* buffer, int *resultLen ); -char* __stdcall JabberBase64DecodeW( const WCHAR* buffer, int *resultLen ); -time_t __stdcall JabberIsoToUnixTime( const TCHAR* stamp ); -void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ); -TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen ); -int __stdcall JabberGetPictureType( const char* buf ); -int __stdcall JabberGetPacketID( HXML n ); - -#define JabberUnixToDosT JabberUnixToDosW -#define JabberBase64DecodeT JabberBase64DecodeW - -const TCHAR *JabberStrIStr( const TCHAR *str, const TCHAR *substr); -void JabberCopyText(HWND hwnd, TCHAR *text); -void JabberBitmapPremultiplyChannels(HBITMAP hBitmap); -CJabberProto *JabberChooseInstance(bool bIsLink=false); - -//---- jabber_xml.cpp ------------------------------------------------------------------- - -void strdel( char* parBuffer, int len ); - -//---- jabber_userinfo.cpp -------------------------------------------------------------- - -void JabberUserInfoUpdate( HANDLE hContact ); - -//---- jabber_iq_handlers.cpp -BOOL GetOSDisplayString(LPTSTR pszOS, int BUFSIZE); - -#endif diff --git a/protocols/JabberG/jabber.rc b/protocols/JabberG/jabber.rc deleted file mode 100644 index a2daa20277..0000000000 --- a/protocols/JabberG/jabber.rc +++ /dev/null @@ -1,943 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -#include "richedit.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_NOTE_EDIT DIALOGEX 0, 0, 279, 241 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Edit Note" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_TXT_TITLE,7,7,266,12,ES_AUTOHSCROLL - EDITTEXT IDC_TXT_TEXT,7,24,266,150,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - LTEXT "Tags:",IDC_ST_TAGS,7,179,266,8 - EDITTEXT IDC_TXT_TAGS,7,190,266,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,168,207,50,14 - PUSHBUTTON "Cancel",IDCANCEL,223,207,50,14 -END - -IDD_ACCMGRUI DIALOGEX 0, 0, 189, 144 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,0,0,53,12,SS_CENTERIMAGE - COMBOBOX IDC_CB_TYPE,61,0,124,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "User:",IDC_STATIC,0,16,53,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_USERNAME,61,16,124,12,ES_AUTOHSCROLL - LTEXT "Domain/Server:",IDC_STATIC,0,31,60,12,SS_CENTERIMAGE - COMBOBOX IDC_EDIT_LOGIN_SERVER,61,31,124,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Password:",IDC_STATIC,0,46,53,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_PASSWORD,61,46,124,12,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,61,124,10 - LTEXT "Resource:",IDC_RESOURCE_T,0,83,53,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_RESOURCE,61,83,124,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,107,99,78,13 - CONTROL "Use custom connection host and port:",IDC_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,115,189,10 - EDITTEXT IDC_HOST,41,125,106,12,ES_AUTOHSCROLL | WS_DISABLED - CTEXT ":",IDC_STATIC,148,124,8,12,SS_CENTERIMAGE - EDITTEXT IDC_PORT,156,125,30,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,72,119,10 -END - -IDD_SEARCHUSER DIALOGEX 0, 0, 109, 148 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Go",IDC_GO,93,11,16,13,WS_DISABLED - LTEXT "Search service",IDC_STATIC,0,1,97,8 - SCROLLBAR IDC_VSCROLL,97,49,12,99,SBS_BOTTOMALIGN | SBS_VERT | NOT WS_VISIBLE - EDITTEXT IDC_INSTRUCTIONS,0,27,105,22,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP - LTEXT "",IDC_FRAME,0,49,97,99,NOT WS_GROUP - COMBOBOX IDC_SERVER,0,11,92,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP -END - -IDD_OPT_JABBER3 DIALOGEX 0, 0, 424, 288 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Roster Editor" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Roster editor\nView and modify your server-side contact list.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - CONTROL "",IDC_ROSTER,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,38,413,225 - PUSHBUTTON "Download",IDC_DOWNLOAD,5,268,60,15,WS_DISABLED - PUSHBUTTON "Upload",IDC_UPLOAD,70,268,60,15,WS_DISABLED - PUSHBUTTON "Import from file",IDC_IMPORT,347,268,71,15 - PUSHBUTTON "Export to file",IDC_EXPORT,272,268,71,15 -END - -IDD_OPT_JABBER DIALOGEX 0, 0, 304, 228 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Jabber",IDC_SIMPLE,4,3,295,114 - LTEXT "Username:",IDC_STATIC,12,18,50,8 - EDITTEXT IDC_EDIT_USERNAME,66,16,86,12,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,12,32,45,8 - EDITTEXT IDC_EDIT_PASSWORD,66,30,86,12,ES_PASSWORD | ES_AUTOHSCROLL - PUSHBUTTON "Change password",IDC_BUTTON_CHANGE_PASSWORD,156,30,78,13 - CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,66,45,89,10 - LTEXT "Priority:",IDC_PRIORITY_LABEL,12,59,41,8 - EDITTEXT IDC_PRIORITY,66,57,85,12,ES_AUTOHSCROLL - CONTROL "Spin1",IDC_PRIORITY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,151,57,12,12 - LTEXT "Resource:",IDC_RESOURCE_T,12,74,45,8 - COMBOBOX IDC_COMBO_RESOURCE,66,71,86,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - CONTROL "Use hostname as resource",IDC_HOSTNAME_AS_RESOURCE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,73,138,9 - LTEXT "Domain/Server:",IDC_STATIC,12,87,52,8 - COMBOBOX IDC_EDIT_LOGIN_SERVER,66,85,86,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER, - "Hyperlink",WS_TABSTOP,161,86,79,11 - LTEXT "Port:",IDC_STATIC,12,101,45,8 - EDITTEXT IDC_PORT,66,99,26,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Use SSL",IDC_USE_SSL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,100,82,10 - CONTROL "Use TLS",IDC_USE_TLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,189,100,97,10 - PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,156,16,78,13 - PUSHBUTTON "Unregister",IDC_UNREGISTER,235,16,56,13 - GROUPBOX "Expert",IDC_STATIC,4,120,295,105 - CONTROL "Manually specify connection host",IDC_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,134,223,10 - LTEXT "Host:",IDC_STATIC,26,147,30,8 - EDITTEXT IDC_HOST,57,145,90,12,ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Port:",IDC_STATIC,156,148,27,8 - EDITTEXT IDC_HOSTPORT,186,145,31,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED - CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,158,221,10 - CONTROL "Automatically delete contacts not in my roster",IDC_ROSTER_SYNC, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,221,10 - LTEXT "User directory:",IDC_JUD_LABEL,11,188,170,8 - EDITTEXT IDC_JUD,188,185,103,12,ES_AUTOHSCROLL - LTEXT "Language for human-readable resources:",IDC_MSGLANG_LABEL,11,203,170,8 - COMBOBOX IDC_MSGLANG,188,201,103,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,45,137,9 -END - -IDD_OPT_JABBER2 DIALOGEX 0, 0, 304, 228 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "File Transfer",IDC_STATIC,4,3,295,71 - CONTROL "Allow file sending through direct peer-to-peer connection",IDC_DIRECT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,14,284,10 - CONTROL "Specify external address:",IDC_DIRECT_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,27,166,10 - EDITTEXT IDC_DIRECT_ADDR,200,25,94,12,ES_AUTOHSCROLL - CONTROL "Allow file sending through bytestream proxy server:",IDC_PROXY_MANUAL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,41,183,10 - EDITTEXT IDC_PROXY_ADDR,200,39,94,12,ES_AUTOHSCROLL | WS_GROUP - GROUPBOX "Miscellaneous",IDC_STATIC,4,76,295,149 - RTEXT "Hint:",IDC_STATIC,12,56,27,8 - LTEXT "Try to uncheck all checkmarks above if you're experiencing troubles with sending files. But it can cause problems with transfer of large files.",IDC_STATIC,46,53,245,16 - CONTROL "",IDC_OPTTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | WS_BORDER | WS_HSCROLL | WS_TABSTOP,9,88,285,132 -END - -IDD_INFO_JABBER DIALOGEX 0, 0, 221, 152 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_TV_INFO,"SysTreeView32",TVS_HASBUTTONS | TVS_DISABLEDRAGDROP | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,5,5,211,141 -END - -IDD_DATAFORM_PAGE DIALOGEX 0, 0, 250, 239 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT | WS_EX_STATICEDGE -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN -END - -IDD_OPT_REGISTER DIALOGEX 0, 0, 173, 69 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION -CAPTION "Jabber Account Registration" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "",IDC_REG_STATUS,4,7,164,26 - CONTROL "Progress1",IDC_PROGRESS_REG,"msctls_progress32",NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,18,37,130,7 - DEFPUSHBUTTON "OK",IDOK,55,50,50,14 -END - -IDD_AGENTS DIALOGEX 0, 0, 294, 254 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Jabber Agents" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Register/Search Jabber Agents",IDC_STATIC,7,7,280,115 - LTEXT "Jabber server:",IDC_STATIC,13,20,47,8 - EDITTEXT IDC_AGENT_SERVER,65,19,136,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "Browse",IDC_AGENT_BROWSE,209,19,46,13,WS_DISABLED - CONTROL "List1",IDC_AGENT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,36,267,60 - PUSHBUTTON "Register...",IDC_AGENT_REGISTER,13,100,50,14,WS_DISABLED - PUSHBUTTON "Browse/Join chat room...",IDC_JOIN,69,100,93,14,WS_DISABLED - PUSHBUTTON "Search...",IDC_AGENT_SEARCH,171,100,50,14,NOT WS_VISIBLE | WS_DISABLED - GROUPBOX "Registered Jabber Transports",IDC_STATIC,7,128,280,99 - CONTROL "List1",IDC_AGENT_TRANSPORT,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,142,267,60 - PUSHBUTTON "Log on",IDC_AGENT_LOGON,13,206,50,14,WS_DISABLED - PUSHBUTTON "Log off",IDC_AGENT_LOGOFF,69,206,50,14,WS_DISABLED - PUSHBUTTON "Unregister",IDC_AGENT_UNREGISTER,125,206,50,14,WS_DISABLED - PUSHBUTTON "Register with a new service...",IDC_MANUAL_REGISTER,7,233,106,14 - PUSHBUTTON "Close",IDCLOSE,237,233,50,14 - PUSHBUTTON "Command",IDC_COMMANDS1,230,100,50,14,WS_DISABLED - PUSHBUTTON "Command",IDC_COMMANDS2,231,206,50,14,WS_DISABLED -END - -IDD_FORM DIALOGEX 0, 0, 258, 224 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Jabber Form" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25 - LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP - EDITTEXT IDC_INSTRUCTION,17,17,233,1,ES_MULTILINE | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1 - CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1 - LTEXT "",IDC_FRAME,0,27,250,169,NOT WS_GROUP - EDITTEXT IDC_FRAME_TEXT,18,101,220,33,ES_CENTER | ES_MULTILINE | ES_READONLY | NOT WS_BORDER - SCROLLBAR IDC_VSCROLL,246,28,11,167,SBS_VERT - DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14,WS_DISABLED - PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14 - DEFPUSHBUTTON "Next",IDC_NEXT,50,203,40,14,NOT WS_VISIBLE | WS_DISABLED - DEFPUSHBUTTON "Back",IDC_PREV,6,203,42,14,NOT WS_VISIBLE | WS_DISABLED - DEFPUSHBUTTON "Complete",IDC_COMPLETE,150,203,46,14,NOT WS_VISIBLE | WS_DISABLED -END - -IDD_PASSWORD DIALOGEX 0, 0, 286, 63 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION -CAPTION "Jabber Password" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_JID,7,7,272,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP - EDITTEXT IDC_PASSWORD,7,22,272,12,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Save password for this session",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,42,157,14 - DEFPUSHBUTTON "OK",IDOK,175,42,50,14 - PUSHBUTTON "Cancel",IDCANCEL,229,42,50,14 -END - -IDD_DATAFORM_TEST DIALOGEX 0, 0, 153, 148 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Data form test" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Custom1",IDC_DATAFORM,"JabberDataFormControl",WS_TABSTOP,7,6,139,135 -END - -IDD_VCARD_HOME DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Address1:",IDC_STATIC,5,7,59,8 - EDITTEXT IDC_ADDRESS1,67,5,148,12,ES_AUTOHSCROLL - LTEXT "Address2:",IDC_STATIC,5,21,59,8 - EDITTEXT IDC_ADDRESS2,67,19,148,12,ES_AUTOHSCROLL - LTEXT "City:",IDC_STATIC,5,35,59,8 - EDITTEXT IDC_CITY,67,33,75,12,ES_AUTOHSCROLL - LTEXT "State:",IDC_STATIC,5,49,59,8 - EDITTEXT IDC_STATE,67,47,75,12,ES_AUTOHSCROLL - LTEXT "ZIP:",IDC_STATIC,5,63,59,8 - EDITTEXT IDC_ZIP,67,61,58,12,ES_AUTOHSCROLL - LTEXT "Country:",IDC_STATIC,5,77,59,8 - COMBOBOX IDC_COUNTRY,67,75,91,172,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP -END - -IDD_VCARD_PERSONAL DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Full name:",IDC_STATIC,5,7,51,8 - EDITTEXT IDC_FULLNAME,58,5,159,12,ES_AUTOHSCROLL - LTEXT "Nick name:",IDC_STATIC,5,20,51,8 - EDITTEXT IDC_NICKNAME,58,19,82,12,ES_AUTOHSCROLL - LTEXT "First name:",IDC_STATIC,5,34,51,8 - EDITTEXT IDC_FIRSTNAME,58,33,82,12,ES_AUTOHSCROLL - RTEXT "Middle:",IDC_STATIC,142,35,35,8,0,WS_EX_RIGHT - EDITTEXT IDC_MIDDLE,178,33,39,12,ES_AUTOHSCROLL - LTEXT "Last name:",IDC_STATIC,5,48,51,8 - EDITTEXT IDC_LASTNAME,58,47,82,12,ES_AUTOHSCROLL - LTEXT "Date of birth:",IDC_STATIC,5,63,51,8 - EDITTEXT IDC_BIRTH,58,61,62,12,ES_AUTOHSCROLL - LTEXT "YYYY-MM-DD",IDC_STATIC,124,63,90,8 - LTEXT "Gender:",IDC_STATIC,5,77,51,8 - COMBOBOX IDC_GENDER,58,75,62,52,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - LTEXT "Occupation:",IDC_STATIC,5,90,51,8 - EDITTEXT IDC_OCCUPATION,58,89,159,12,ES_AUTOHSCROLL - LTEXT "Homepage:",IDC_STATIC,6,104,51,8 - EDITTEXT IDC_HOMEPAGE,58,102,159,12,ES_AUTOHSCROLL -END - -IDD_VCARD_WORK DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Company:",IDC_STATIC,6,7,60,8 - EDITTEXT IDC_COMPANY,67,5,148,12,ES_AUTOHSCROLL - LTEXT "Department:",IDC_STATIC,6,20,60,8 - EDITTEXT IDC_DEPARTMENT,67,19,148,12,ES_AUTOHSCROLL - LTEXT "Title:",IDC_STATIC,6,33,60,8 - EDITTEXT IDC_TITLE,67,32,75,12,ES_AUTOHSCROLL - LTEXT "Address1:",IDC_STATIC,5,47,60,8 - EDITTEXT IDC_ADDRESS1,67,45,148,12,ES_AUTOHSCROLL - LTEXT "Address2:",IDC_STATIC,5,61,60,8 - EDITTEXT IDC_ADDRESS2,67,59,148,12,ES_AUTOHSCROLL - LTEXT "City:",IDC_STATIC,5,75,60,8 - EDITTEXT IDC_CITY,67,73,75,12,ES_AUTOHSCROLL - LTEXT "State:",IDC_STATIC,5,88,60,8 - EDITTEXT IDC_STATE,67,87,75,12,ES_AUTOHSCROLL - LTEXT "ZIP:",IDC_STATIC,5,103,60,8 - EDITTEXT IDC_ZIP,67,101,58,12,ES_AUTOHSCROLL - LTEXT "Country:",IDC_STATIC,5,116,60,8 - COMBOBOX IDC_COUNTRY,67,115,91,172,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP -END - -IDD_VCARD_CONTACT DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "E-mail:",IDC_STATIC,5,5,212,8 - CONTROL "List1",IDC_EMAILS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,14,212,50 - LTEXT "Phone:",IDC_STATIC,5,68,212,8 - CONTROL "List1",IDC_PHONES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,77,212,50 -END - -IDD_VCARD_ADDEMAIL DIALOGEX 0, 0, 186, 89 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Jabber vCard: Add Email Address" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Email address:",IDC_STATIC,7,8,52,8 - EDITTEXT IDC_EMAIL,61,7,118,12,ES_AUTOHSCROLL - CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,23,110,10 - CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,33,111,10 - CONTROL "Internet",IDC_INTERNET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,43,110,10 - CONTROL "X400",IDC_X400,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,53,110,10 - DEFPUSHBUTTON "OK",IDOK,40,68,50,14 - PUSHBUTTON "Cancel",IDCANCEL,96,68,50,14 -END - -IDD_VCARD_ADDPHONE DIALOGEX 0, 0, 186, 110 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Jabber vCard: Add Phone Number" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Phone number:",IDC_STATIC,7,8,49,8 - EDITTEXT IDC_PHONE,61,7,118,12,ES_AUTOHSCROLL - CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,23,67,10 - CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,33,67,10 - CONTROL "Voice",IDC_VOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,43,67,10 - CONTROL "Fax",IDC_FAX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,53,67,10 - CONTROL "Pager",IDC_PAGER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,63,67,10 - CONTROL "Text/Messaging",IDC_MSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,73,67,10 - CONTROL "Cellular",IDC_CELL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,23,71,10 - CONTROL "Video",IDC_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,33,71,10 - CONTROL "BBS",IDC_BBS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,43,71,10 - CONTROL "Modem",IDC_MODEM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,53,71,10 - CONTROL "ISDN",IDC_ISDN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,63,71,10 - CONTROL "PCS",IDC_PCS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,73,71,10 - DEFPUSHBUTTON "OK",IDOK,40,88,50,14 - PUSHBUTTON "Cancel",IDCANCEL,96,88,50,14 -END - -IDD_VCARD_PHOTO DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Load",IDC_LOAD,"MButtonClass",WS_TABSTOP,200,5,17,14 - CONTROL "Save",IDC_SAVE,"MButtonClass",WS_TABSTOP,200,5,17,14 - CTEXT "",IDC_CANVAS,5,5,189,122,SS_CENTERIMAGE - CONTROL "Delete",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,200,23,17,14 -END - -IDD_VCARD_NOTE DIALOGEX 0, 0, 222, 132 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Description:",IDC_STATIC,5,5,212,8 - EDITTEXT IDC_DESC,5,15,212,112,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL -END - -IDD_CHANGEPASSWORD DIALOGEX 0, 0, 181, 79 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION -CAPTION "Change Password" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Current Password:",IDC_STATIC,7,8,81,8 - EDITTEXT IDC_OLDPASSWD,95,7,79,12,ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "New Password:",IDC_STATIC,7,22,81,8 - EDITTEXT IDC_NEWPASSWD,95,21,79,12,ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "Confirm New Password:",IDC_STATIC,7,36,81,8 - EDITTEXT IDC_NEWPASSWD2,95,35,79,12,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,38,58,50,14 - PUSHBUTTON "Cancel",IDCANCEL,92,58,50,14 -END - -IDD_GROUPCHAT DIALOGEX 0, 0, 306, 208 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Jabber Multi-User Conference" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Conference server:",-1,5,8,70,8 - COMBOBOX IDC_SERVER,80,7,168,79,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "Browse",IDC_BROWSE,253,7,46,13 - CONTROL "List1",IDC_ROOM,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,5,24,294,160 - PUSHBUTTON "Close",IDCLOSE,249,189,50,14 -END - -IDD_GROUPCHAT_JOIN DIALOGEX 0, 0, 258, 211 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Create or Join Groupchat" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Jabber Multi-User Conference\nCreate or join existing conference room.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - LTEXT "Conference server:",IDC_STATIC,7,38,63,12,SS_CENTERIMAGE,WS_EX_RIGHT - COMBOBOX IDC_SERVER,75,38,176,100,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Room:",IDC_STATIC,7,56,63,12,SS_CENTERIMAGE,WS_EX_RIGHT - COMBOBOX IDC_ROOM,75,56,176,158,CBS_DROPDOWN | CBS_OWNERDRAWVARIABLE | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - LTEXT "Nick name:",IDC_STATIC,7,73,63,12,SS_CENTERIMAGE,WS_EX_RIGHT - EDITTEXT IDC_NICK,75,73,176,12,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,7,90,63,12,SS_CENTERIMAGE,WS_EX_RIGHT - EDITTEXT IDC_PASSWORD,75,90,176,12,ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "Recently visited chatrooms:",IDC_TXT_RECENT,7,107,244,8 - CONTROL "",IDC_RECENT1,"Hyperlink",WS_TABSTOP,27,120,224,11 - CONTROL "",IDC_RECENT2,"Hyperlink",WS_TABSTOP,27,131,224,11 - CONTROL "",IDC_RECENT3,"Hyperlink",WS_TABSTOP,27,142,224,11 - CONTROL "",IDC_RECENT4,"Hyperlink",WS_TABSTOP,27,153,224,11 - CONTROL "",IDC_RECENT5,"Hyperlink",WS_TABSTOP,27,164,224,11 - CONTROL "Bookmarks",IDC_BOOKMARKS,"MButtonClass",WS_TABSTOP,7,179,16,14 - DEFPUSHBUTTON "OK",IDOK,145,179,50,14 - PUSHBUTTON "Cancel",IDCANCEL,201,179,50,14 -END - -IDD_JIDLIST DIALOGEX 0, 0, 208, 165 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT -CAPTION "JID List" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "List4",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,198,136 - EDITTEXT IDC_FILTER,5,147,161,12,ES_AUTOHSCROLL - CONTROL "Apply Filter",IDC_BTN_FILTERAPPLY,"MButtonClass",WS_TABSTOP,171,146,16,14 - CONTROL "Reset Filter",IDC_BTN_FILTERRESET,"MButtonClass",WS_TABSTOP,187,146,16,14 -END - -IDD_AGENT_MANUAL_REGISTER DIALOGEX 0, 0, 186, 45 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Jabber Agent Registration" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "JID:",IDC_STATIC,5,9,17,8 - EDITTEXT IDC_JID,29,7,150,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "Register",IDOK,75,24,50,14,WS_DISABLED - PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 -END - -IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 215, 275 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Invite Users" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "\nSend groupchat invitation.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,215,25 - CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,7,40,201,116,WS_EX_CLIENTEDGE - LTEXT "Other JID:",IDC_STATIC,7,162,46,8 - EDITTEXT IDC_NEWJID,59,160,127,12,ES_AUTOHSCROLL - CONTROL "Add",IDC_ADDJID,"MButtonClass",WS_TABSTOP,192,159,16,14 - CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,178,214,1 - LTEXT "Invitation reason:",IDC_STATIC,7,184,201,8 - EDITTEXT IDC_REASON,17,195,191,44,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL - DEFPUSHBUTTON "&Invite",IDC_INVITE,104,243,50,14 - PUSHBUTTON "Cancel",IDCANCEL,158,243,50,14 -END - -IDD_GROUPCHAT_INVITE_ACCEPT DIALOGEX 0, 0, 216, 174 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Groupchat Invitation" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "\nIncoming groupchat invitation.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,216,25 - LTEXT "You are invited to conference room by",IDC_STATIC,7,40,202,8 - EDITTEXT IDC_FROM,17,51,192,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "with following reason:",IDC_STATIC,7,69,202,8 - EDITTEXT IDC_REASON,17,80,192,34,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,119,215,1 - LTEXT "Nickname:",IDC_STATIC,7,125,52,12,SS_CENTERIMAGE - EDITTEXT IDC_NICK,62,125,147,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "&Accept",IDC_ACCEPT,104,142,50,14 - PUSHBUTTON "Cancel",IDCANCEL,159,142,50,14 -END - -IDD_BOOKMARKS DIALOGEX 0, 0, 295, 261 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Jabber Bookmarks" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Server side bookmarks\nStore conference rooms and web links on server.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - CONTROL "List1",IDC_BM_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,5,38,285,187 - CONTROL "Remove",IDC_REMOVE,"MButtonClass",WS_TABSTOP,37,229,16,14 - CONTROL "Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,21,229,16,14 - CONTROL "Add",IDC_ADD,"MButtonClass",WS_TABSTOP,5,229,16,14 - PUSHBUTTON "Close",IDCANCEL,240,229,50,14 -END - -IDD_BOOKMARK_ADD DIALOGEX 0, 0, 221, 143 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Bookmark Details" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Bookmark Type",IDC_BOOKMARK_TYPE,6,4,208,52 - CONTROL "Conference",IDC_ROOM_RADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,15,14,59,10 - CONTROL "Transport",IDC_AGENT_RADIO,"Button",BS_AUTORADIOBUTTON,79,14,66,10 - CONTROL "URL",IDC_URL_RADIO,"Button",BS_AUTORADIOBUTTON,157,14,48,10 - CONTROL "Auto-join (Automatically join Bookmarks must be enabled in Miranda options)",IDC_CHECK_BM_AUTOJOIN, - "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,28,191,24 - LTEXT "Room JID/ URL:",IDC_STATIC,7,62,65,8 - EDITTEXT IDC_ROOM_JID,76,62,138,12,ES_AUTOHSCROLL - LTEXT "Bookmark Name:",IDC_STATIC,7,77,65,8 - EDITTEXT IDC_NAME,76,75,138,12,ES_AUTOHSCROLL - LTEXT "Nick name:",IDC_STATIC,7,91,65,8 - EDITTEXT IDC_NICK,76,90,138,12,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,7,105,65,8 - EDITTEXT IDC_PASSWORD,76,104,138,12,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,51,122,50,14 - PUSHBUTTON "Cancel",IDCANCEL,117,122,50,14 -END - -IDD_PRIVACY_LISTS DIALOGEX 0, 0, 424, 287 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Privacy Lists" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Privacy Lists\nFlexible way to configure visibility and more.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - LTEXT "Lists:",IDC_TXT_LISTS,5,38,121,14,SS_CENTERIMAGE - LISTBOX IDC_LB_LISTS,5,55,122,196,LBS_SORT | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LTEXT "Rules:",IDC_TXT_RULES,135,38,58,14,SS_CENTERIMAGE - LISTBOX IDC_PL_RULES_LIST,135,55,283,196,LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,135,55,283,160,WS_EX_CLIENTEDGE - CONTROL "Simple Mode",IDC_BTN_SIMPLE,"MButtonClass",WS_TABSTOP,386,38,16,14 - CONTROL "Advanced Mode",IDC_BTN_ADVANCED,"MButtonClass",WS_TABSTOP,402,38,16,14 - RTEXT "Other JID:",IDC_TXT_OTHERJID,135,237,49,14,SS_CENTERIMAGE - EDITTEXT IDC_NEWJID,187,238,210,12,ES_AUTOHSCROLL - CONTROL "",IDC_ADDJID,"MButtonClass",WS_TABSTOP,402,237,16,14 - CONTROL "Add list... (Ins)",IDC_ADD_LIST,"MButtonClass",WS_TABSTOP,5,255,16,14 - CONTROL "Activate (Space)",IDC_ACTIVATE,"MButtonClass",WS_TABSTOP,26,255,16,14 - CONTROL "Set as default (Ctrl+Space)",IDC_SET_DEFAULT, - "MButtonClass",WS_TABSTOP,42,255,16,14 - CONTROL "Remove list (Del)",IDC_REMOVE_LIST,"MButtonClass",WS_TABSTOP,63,255,16,14 - CONTROL "Add rule (Ins)",IDC_ADD_RULE,"MButtonClass",WS_TABSTOP,135,255,16,14 - CONTROL "Edit rule... (F2)",IDC_EDIT_RULE,"MButtonClass",WS_TABSTOP,156,255,16,14 - CONTROL "Move rule up (Alt+Up)",IDC_UP_RULE,"MButtonClass",WS_TABSTOP,177,255,16,14 - CONTROL "Move rule down (Alt+Down)",IDC_DOWN_RULE,"MButtonClass",WS_TABSTOP,193,255,16,14 - CONTROL "Remove rule (Del)",IDC_REMOVE_RULE,"MButtonClass",WS_TABSTOP,214,255,16,14 - PUSHBUTTON "Save",IDC_APPLY,313,255,50,14 - PUSHBUTTON "Close",IDCANCEL,368,255,50,14 - CONTROL "",IDC_CANVAS,"Static",SS_OWNERDRAW,135,218,283,14,WS_EX_TRANSPARENT -END - -IDD_PRIVACY_RULE DIALOGEX 0, 0, 261, 90 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Privacy rule" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - RTEXT "If:",IDC_STATIC,5,5,35,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_TYPE,43,5,76,179,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO_VALUE,124,5,132,142,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO_VALUES,124,5,132,142,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - RTEXT "Then:",IDC_STATIC,5,21,35,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_ACTION,43,21,76,206,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "following stanza types:",IDC_STATIC,124,21,132,12,SS_CENTERIMAGE - ICON "",IDC_ICO_MESSAGE,43,38,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE - CONTROL "Messages",IDC_CHECK_MESSAGES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,38,89,14 - ICON "",IDC_ICO_QUERY,43,52,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE - CONTROL "Queries",IDC_CHECK_QUERIES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,52,89,14 - ICON "",IDC_ICO_PRESENCEIN,150,38,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE - CONTROL "Incoming presence",IDC_CHECK_PRESENCE_IN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,38,90,14 - ICON "",IDC_ICO_PRESENCEOUT,150,52,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE - CONTROL "Outgoing presence",IDC_CHECK_PRESENCE_OUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,52,90,14 - PUSHBUTTON "OK",IDOK,152,71,50,14 - PUSHBUTTON "Cancel",IDCANCEL,206,71,50,14 -END - -IDD_PRIVACY_ADD_LIST DIALOGEX 0, 0, 142, 54 -STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "New privacy list name:" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Enter the name of the new list:",IDC_STATIC,5,7,135,8 - EDITTEXT IDC_EDIT_NAME,5,18,130,14,ES_AUTOHSCROLL - PUSHBUTTON "OK",IDOK,31,35,50,14 - PUSHBUTTON "Cancel",IDCANCEL,85,35,50,14 -END - -IDD_SERVICE_DISCOVERY DIALOGEX 0, 0, 353, 221 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Service Discovery" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "View as tree",IDC_BTN_VIEWTREE,"MButtonClass",WS_TABSTOP,5,5,16,14 - CONTROL "View as list",IDC_BTN_VIEWLIST,"MButtonClass",WS_TABSTOP,21,5,16,14 - CONTROL "Home",IDC_BTN_NAVHOME,"MButtonClass",WS_TABSTOP,42,5,16,14 - CONTROL "Favourites",IDC_BTN_FAVORITE,"MButtonClass",WS_TABSTOP,58,5,16,14 - CONTROL "Refresh",IDC_BTN_REFRESH,"MButtonClass",WS_TABSTOP,74,5,16,14 - LTEXT "JID:",IDC_STATIC,95,5,14,14,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_JID,112,6,99,70,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Node:",IDC_TXT_NODELABEL,216,5,24,14,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_NODE,243,6,84,70,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "Go",IDC_BUTTON_BROWSE,"MButtonClass",WS_TABSTOP,332,5,16,14 - CONTROL "",IDC_TREE_DISCO,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,5,21,343,180 -END - -IDD_SETMOODMSG DIALOGEX 0, 0, 187, 72 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Change %s Message" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_MSG_MOOD,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL - DEFPUSHBUTTON "Closing in %d",IDOK,61,53,65,14 -END - -IDD_MODERNOPT DIALOGEX 0, 0, 260, 164 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - RTEXT "Account type:",IDC_STATIC,9,15,51,12,SS_CENTERIMAGE - RTEXT "Username:",IDC_STATIC,9,32,51,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_USERNAME,65,32,194,12,ES_AUTOHSCROLL - RTEXT "Password:",IDC_STATIC,9,49,51,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_PASSWORD,65,49,194,12,ES_PASSWORD | ES_AUTOHSCROLL - RTEXT "Login server:",IDC_STATIC,9,66,51,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_LOGIN_SERVER,65,66,194,12,ES_AUTOHSCROLL - RTEXT "Port:",IDC_STATIC,163,83,30,12,SS_CENTERIMAGE - EDITTEXT IDC_PORT,216,83,43,12,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "Register account now",IDC_BUTTON_REGISTER,65,83,92,13 - COMBOBOX IDC_COMBO_ACCTYPE,65,15,194,39,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER, - "Hyperlink",WS_TABSTOP,10,129,249,11 - COMBOBOX IDC_COMBO_RESOURCE,65,101,194,52,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - RTEXT "Resource:",IDC_STATIC,10,101,51,12,SS_CENTERIMAGE - LTEXT "Jabber Account Information:",IDC_TITLE1,0,0,255,8 -END - -IDD_GROUPCHAT_INFO DIALOGEX 0, 0, 183, 144 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Member Information" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Member Information\n",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,183,25 - ICON IDI_JABBER,IDC_ICO_STATUS,5,38,16,17,SS_CENTERIMAGE | SS_REALSIZEIMAGE - EDITTEXT IDC_TXT_NICK,26,38,152,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_TXT_JID,36,47,142,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - RTEXT "Role:",IDC_STATIC,5,59,36,12,SS_CENTERIMAGE - COMBOBOX IDC_TXT_ROLE,45,59,112,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Set role",IDC_BTN_ROLE,"MButtonClass",WS_TABSTOP,162,58,16,14 - RTEXT "Affiliation:",IDC_STATIC,5,73,36,12,SS_CENTERIMAGE - COMBOBOX IDC_TXT_AFFILIATION,45,73,112,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Set affiliation",IDC_BTN_AFFILIATION,"MButtonClass",WS_TABSTOP,162,72,16,14 - LTEXT "Status message:",IDC_STATIC,5,89,173,8 - EDITTEXT IDC_TXT_STATUS,26,99,152,40,ES_MULTILINE | ES_READONLY | WS_VSCROLL -END - -IDD_OPT_JABBER4 DIALOGEX 0, 0, 304, 228 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Chat options",IDC_STATIC,4,3,295,175 - CONTROL "",IDC_OPTTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | WS_BORDER | WS_HSCROLL | WS_TABSTOP,9,15,285,140 - LTEXT "Alternate nick:",IDC_STATIC,11,161,174,8 - EDITTEXT IDC_TXT_ALTNICK,190,159,104,14,ES_AUTOHSCROLL - GROUPBOX "Custom messages",IDC_STATIC,4,180,295,45 - EDITTEXT IDC_TXT_QUIT,45,192,249,12,ES_AUTOHSCROLL - EDITTEXT IDC_TXT_SLAP,45,208,249,12,ES_AUTOHSCROLL - RTEXT "Quit:",IDC_STATIC,9,192,31,12,SS_CENTERIMAGE - RTEXT "Slap:",IDC_STATIC,9,208,31,12,SS_CENTERIMAGE -END - -IDD_HTTP_AUTH DIALOGEX 0, 0, 217, 188 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Authorization Request" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "HTTP Authorization\nAccept or reject incoming request",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - LTEXT "Someone (maybe you) has requested the following file:",IDC_STATIC,7,38,203,8 - EDITTEXT IDC_TXT_URL,27,49,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Request was sent from JID:",IDC_STATIC,7,61,203,8 - EDITTEXT IDC_TXT_FROM,27,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "The transaction identifier is:",IDC_STATIC,7,84,203,8 - EDITTEXT IDC_TXT_ID,27,95,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Request method is:",IDC_STATIC,7,107,203,8 - EDITTEXT IDC_TXT_METHOD,27,118,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "If you wish to confirm this request, please click authorize. Otherwise, press deny to reject it.",IDC_STATIC,7,130,203,16 - PUSHBUTTON "Authorize",IDOK,104,156,50,14 - PUSHBUTTON "Deny",IDCANCEL,160,156,50,14 -END - -IDD_GROUPCHAT_INFO_TABS DIALOGEX 0, 0, 265, 242 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Data form test" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_TABS,"SysTabControl32",TCS_MULTILINE,7,6,251,203 -END - -IDD_GROUPCHAT_ADMLIST DIALOGEX 0, 0, 208, 165 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_FILTER,5,147,161,12,ES_AUTOHSCROLL - CONTROL "Apply Filter",IDC_BTN_FILTERAPPLY,"MButtonClass",WS_TABSTOP,171,146,16,14 - CONTROL "Reset Filter",IDC_BTN_FILTERRESET,"MButtonClass",WS_TABSTOP,187,146,16,14 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,5,5,198,136 -END - -IDD_PEP_SIMPLE DIALOGEX 0, 0, 201, 140 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_CB_MODES,5,5,191,78,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_TXT_DESCRIPTION,5,22,191,82,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - DEFPUSHBUTTON "OK",IDOK,90,109,50,14 - PUSHBUTTON "Cancel",IDCANCEL,145,109,51,14 -END - -IDD_NOTEBOOK DIALOGEX 0, 0, 353, 261 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Jabber Notebook" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Jabber notebook\nStore notes on server and access them from anywhere.",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,428,25 - CONTROL "Remove",IDC_REMOVE,"MButtonClass",WS_TABSTOP,37,229,16,14 - CONTROL "Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,21,229,16,14 - CONTROL "Add",IDC_ADD,"MButtonClass",WS_TABSTOP,5,229,16,14 - PUSHBUTTON "Close",IDCANCEL,297,229,50,14 - CONTROL "",IDC_TV_FILTER,"SysTreeView32",TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,5,38,100,187 - LISTBOX IDC_LST_NOTES,110,38,237,187,LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Save",IDC_APPLY,242,229,50,14 -END - -IDD_CAPTCHAFORM DIALOGEX 0, 0, 258, 224 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Bots Challenge Test" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_VALUE,4,203,137,14,ES_AUTOHSCROLL - CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25 - LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP - EDITTEXT IDC_INSTRUCTION,17,16,233,8,ES_MULTILINE | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1 - CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1 - DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14 - PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_NOTE_EDIT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 273 - TOPMARGIN, 7 - HORZGUIDE, 19 - HORZGUIDE, 24 - HORZGUIDE, 174 - HORZGUIDE, 179 - HORZGUIDE, 187 - HORZGUIDE, 202 - HORZGUIDE, 207 - HORZGUIDE, 221 - END - - IDD_ACCMGRUI, DIALOG - BEGIN - RIGHTMARGIN, 184 - END - - IDD_OPT_REGISTER, DIALOG - BEGIN - RIGHTMARGIN, 165 - BOTTOMMARGIN, 61 - END - - IDD_PASSWORD, DIALOG - BEGIN - VERTGUIDE, 7 - VERTGUIDE, 279 - HORZGUIDE, 42 - HORZGUIDE, 56 - END - - IDD_BOOKMARK_ADD, DIALOG - BEGIN - BOTTOMMARGIN, 137 - END - - IDD_NOTEBOOK, DIALOG - BEGIN - VERTGUIDE, 292 - VERTGUIDE, 297 - HORZGUIDE, 229 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_JABBER ICON "icos/jabber.ico" -IDI_ARROW_DOWN ICON "icos/arrow_down.ico" -IDI_ARROW_UP ICON "icos/arrow_up.ico" -IDI_DISCO_PROGRESS ICON "icos/disco_in_progress.ico" -IDI_NODE_RSS ICON "icos/rss.ico" -IDI_NODE_SERVER ICON "icos/server.ico" -IDI_NODE_STORE ICON "icos/store.ico" -IDI_NODE_WEATHER ICON "icos/weather.ico" -IDI_DISCO_OK ICON "icos/disco_ok.ico" -IDI_DISCO_FAIL ICON "icos/disco_fail.ico" -IDI_GROUP ICON "icos/group.ico" -IDI_KEYS ICON "icos/key.ico" -IDI_ADDCONTACT ICON "icos/addcontact.ico" -IDI_ADDROSTER ICON "icos/add2roster.ico" -IDI_AGENTS ICON "icos/roster.ico" -IDI_VCARD ICON "icos/pages.ico" -IDI_DELETE ICON "icos/delete.ico" -IDI_EDIT ICON "icos/rename.ico" -IDI_GRANT ICON "icos/grant.ico" -IDI_OPEN ICON "icos/open.ico" -IDI_REQUEST ICON "icos/request.ico" -IDI_USER2ROOM ICON "icos/user2room.ico" -IDI_SAVE ICON "icos/save.ico" -IDI_LOGIN ICON "icos/login.ico" -IDI_AUTHREVOKE ICON "icos/auth_revoke.ico" -IDI_REFRESH ICON "icos/refresh.ico" -IDI_COMMAND ICON "icos/command.ico" -IDI_BOOKMARKS ICON "icos/bookmarks.ico" -IDI_PRIVACY_LISTS ICON "icos/privacy_lists.ico" -IDI_SERVICE_DISCOVERY ICON "icos/service_discovery.ico" -IDI_VIEW_LIST ICON "icos/view_as_list.ico" -IDI_VIEW_TREE ICON "icos/view_as_tree.ico" -IDI_FILTER_APPLY ICON "icos/filter.ico" -IDI_BROWSE ICON "icos/go.ico" -IDI_NAV_HOME ICON "icos/home.ico" -IDI_NAV_REFRESH ICON "icos/refresh_node.ico" -IDI_FILTER_RESET ICON "icos/reset_filter.ico" -IDI_CONSOLE ICON "icos/console.ico" -IDI_PL_MSG_ALLOW ICON "icos/message_allow.ico" -IDI_PL_MSG_DENY ICON "icos/message_deny.ico" -IDI_PL_PRIN_ALLOW ICON "icos/presence_in_allow.ico" -IDI_PL_PRIN_DENY ICON "icos/presence_in_deny.ico" -IDI_PL_PROUT_ALLOW ICON "icos/presence_out_allow.ico" -IDI_PL_PROUT_DENY ICON "icos/presence_out_deny.ico" -IDI_PL_QUERY_ALLOW ICON "icos/query_allow.ico" -IDI_PL_QUERY_DENY ICON "icos/query_deny.ico" -IDI_PL_LIST_ACTIVE ICON "icos/plist_active.ico" -IDI_PL_LIST_ANY ICON "icos/plist_any.ico" -IDI_PL_LIST_DEFAULT ICON "icos/plist_default.ico" -IDI_TRANSPORT ICON "icos/transport.ico" -IDI_TRANSPORTL ICON "icos/transport_local.ico" -IDI_HTTP_AUTH ICON "icos/openid.ico" -IDI_NOTES ICON "icos\\notes.ico" -IDI_SEND_NOTE ICON "icos\\send_note.ico" - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "#include ""richedit.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/protocols/JabberG/jabber_10.vcxproj b/protocols/JabberG/jabber_10.vcxproj index ae333da2a6..2003650b39 100644 --- a/protocols/JabberG/jabber_10.vcxproj +++ b/protocols/JabberG/jabber_10.vcxproj @@ -199,150 +199,92 @@ - + Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/protocols/JabberG/jabber_10.vcxproj.filters b/protocols/JabberG/jabber_10.vcxproj.filters index e5d93e91ba..d671a671c9 100644 --- a/protocols/JabberG/jabber_10.vcxproj.filters +++ b/protocols/JabberG/jabber_10.vcxproj.filters @@ -15,414 +15,248 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - - + Resource Files - + Resource Files diff --git a/protocols/JabberG/jabber_adhoc.cpp b/protocols/JabberG/jabber_adhoc.cpp deleted file mode 100644 index 09884e79df..0000000000 --- a/protocols/JabberG/jabber_adhoc.cpp +++ /dev/null @@ -1,609 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2007 Artem Shpynov -Copyright ( C ) 2005-12 George Hazan - -Module implements an XMPP protocol extension for reporting and executing ad-hoc, -human-oriented commands according to XEP-0050: Ad-Hoc Commands -http://www.xmpp.org/extensions/xep-0050.html - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include -#include "jabber_iq.h" -#include "m_clui.h" -#include "jabber_caps.h" - - -#define ShowDlgItem( a, b, c ) ShowWindow( GetDlgItem( a, b ), c ) -#define EnableDlgItem( a, b, c ) EnableWindow( GetDlgItem( a, b ), c ) - -enum -{ - JAHM_COMMANDLISTRESULT = WM_USER+1, - JAHM_PROCESSRESULT -}; - -//Declarations -static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ); - -//implementations - -// convert iqID to dialog hwnd -HWND CJabberProto::GetWindowFromIq( HXML iqNode ) -{ - const TCHAR* id = xmlGetAttrValue( iqNode, _T( "id" )); - if (_tcslen(id)>4) - return (HWND)_tcstol(id+4,NULL,10); - return m_hwndCommandWindow; - -} -// Callback to clear form content -static BOOL CALLBACK sttDeleteChildWindowsProc( HWND hwnd, LPARAM ) -{ - DestroyWindow( hwnd ); - return TRUE; -} - -static void sttEnableControls( HWND hwndDlg, BOOL bEnable, const int * controlsID ) -{ - int i=0; - while ( controlsID[i]!=0 ) - EnableDlgItem( hwndDlg, controlsID[i++], bEnable ); -} - -static void sttShowControls( HWND hwndDlg, BOOL bShow, int * controlsID ) -{ - int i=0; - while ( controlsID[i]!=0 ) - ShowDlgItem( hwndDlg, controlsID[i++], (bShow) ? SW_SHOW : SW_HIDE ); -} - -static void JabberAdHoc_RefreshFrameScroll(HWND hwndDlg, JabberAdHocData * dat) -{ - HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); - HWND hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); - RECT rc; - RECT rcScrollRc; - GetClientRect( hFrame, &rc ); - GetClientRect( hFrame, &dat->frameRect ); - GetWindowRect( hwndScroll, &rcScrollRc ); - dat->frameRect.right-=(rcScrollRc.right-rcScrollRc.left); - dat->frameHeight = rc.bottom-rc.top; - if ( dat->frameHeight < dat->CurrentHeight) { - ShowWindow( hwndScroll, SW_SHOW ); - EnableWindow( hwndScroll, TRUE ); - } - else ShowWindow( hwndScroll, SW_HIDE ); - - SetScrollRange( hwndScroll, SB_CTL, 0, dat->CurrentHeight-dat->frameHeight, FALSE ); - -} - -////////////////////////////////////////////////////////////////////////// -// Iq handlers -// Forwards to dialog window procedure - -void CJabberProto::OnIqResult_ListOfCommands( HXML iqNode ) -{ - SendMessage( GetWindowFromIq( iqNode ), JAHM_COMMANDLISTRESULT, 0, (LPARAM)xi.copyNode( iqNode )); -} - -void CJabberProto::OnIqResult_CommandExecution( HXML iqNode ) -{ - SendMessage( GetWindowFromIq( iqNode ), JAHM_PROCESSRESULT, (WPARAM)xi.copyNode( iqNode ), 0 ); -} - -int CJabberProto::AdHoc_RequestListOfCommands( TCHAR * szResponder, HWND hwndDlg ) -{ - int iqId = (int)hwndDlg; - IqAdd( iqId, IQ_PROC_DISCOCOMMANDS, &CJabberProto::OnIqResult_ListOfCommands ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szResponder ) << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)) - << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS))); - return iqId; -} - -int CJabberProto::AdHoc_ExecuteCommand( HWND hwndDlg, TCHAR*, JabberAdHocData* dat ) -{ - for ( int i = 1; ; i++ ) { - HXML itemNode = xmlGetNthChild( dat->CommandsNode, _T("item"), i ); - if ( !itemNode) - break; - if ( !IsDlgButtonChecked( GetDlgItem( hwndDlg, IDC_FRAME ), i )) - continue; - const TCHAR* node = xmlGetAttrValue( itemNode, _T("node")); - if ( node ) { - const TCHAR *jid2 = xmlGetAttrValue( itemNode, _T("jid")); - - int iqId = (int)hwndDlg; - IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); - m_ThreadInfo->send( - XmlNodeIq( _T("set"), iqId, jid2 ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), node ) << XATTR( _T("action"), _T("execute"))); - - EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE ); - SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" )); - } } - - xi.destroyNode( dat->CommandsNode ); dat->CommandsNode = NULL; - return TRUE; -} - -//Messages handlers -int CJabberProto::AdHoc_OnJAHMCommandListResult( HWND hwndDlg, HXML iqNode, JabberAdHocData* dat ) -{ - int nodeIdx = 0; - const TCHAR * type = xmlGetAttrValue( iqNode, _T("type")); - if ( !type || !_tcscmp( type, _T( "error" )) ) { - // error occurred here - TCHAR buff[255]; - const TCHAR* code = NULL; - const TCHAR* description = NULL; - - HXML errorNode = xmlGetChild( iqNode, "error" ); - if ( errorNode ) { - code = xmlGetAttrValue( errorNode, _T("code")); - description = xmlGetText( errorNode ); - } - _sntprintf( buff, SIZEOF(buff), TranslateT( "Error %s %s" ), (code) ? code : _T(""), (description) ? description : _T("")); - JabberFormSetInstruction( hwndDlg, buff ); - } - else if ( !_tcscmp( type, _T("result")) ) { - BOOL validResponse = FALSE; - EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 ); - dat->CurrentHeight = 0; - dat->curPos = 0; - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode ) { - const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T( "xmlns" )); - const TCHAR* node = xmlGetAttrValue( queryNode, _T( "node" )); - if ( xmlns && node - && !_tcscmp( xmlns, _T( JABBER_FEAT_DISCO_ITEMS )) - && !_tcscmp( node, _T( JABBER_FEAT_COMMANDS )) ) - validResponse = TRUE; - } - if ( queryNode && xmlGetChild( queryNode ,0) && validResponse ) { - dat->CommandsNode = xi.copyNode( queryNode ); - - nodeIdx = 1; - int ypos = 20; - for (nodeIdx = 1; ; nodeIdx++ ) { - HXML itemNode = xmlGetNthChild( queryNode, _T("item"), nodeIdx ); - if ( itemNode ) { - const TCHAR *name = xmlGetAttrValue( itemNode, _T("name")); - if (!name) name = xmlGetAttrValue( itemNode, _T("node")); - ypos = AdHoc_AddCommandRadio( GetDlgItem( hwndDlg,IDC_FRAME ), TranslateTS(name), nodeIdx, ypos, (nodeIdx==1) ? 1 : 0); - dat->CurrentHeight = ypos; - } - else break; - } } - - if (nodeIdx>1) { - JabberFormSetInstruction( hwndDlg, TranslateT("Select Command")); - ShowDlgItem( hwndDlg, IDC_FRAME, SW_SHOW); - ShowDlgItem( hwndDlg, IDC_VSCROLL, SW_SHOW); - EnableDlgItem( hwndDlg, IDC_SUBMIT, TRUE); - } else { - JabberFormSetInstruction(hwndDlg, TranslateT("Not supported")); - } } - - JabberAdHoc_RefreshFrameScroll( hwndDlg, dat ); - return (TRUE); -} - -int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, HXML workNode, JabberAdHocData* dat) -{ - EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 ); - dat->CurrentHeight = 0; - dat->curPos = 0; - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); - - if ( workNode == NULL ) - return TRUE; - - dat->AdHocNode = xi.copyNode( workNode ); - - const TCHAR *type; - if (( type = xmlGetAttrValue( workNode, _T("type"))) == NULL ) return TRUE; - if ( !lstrcmp( type, _T("result")) ) { - // wParam = node from responder as a result of command execution - HXML commandNode, xNode, n; - if (( commandNode = xmlGetChild( dat->AdHocNode, _T("command"))) == NULL ) - return TRUE; - - const TCHAR * status = xmlGetAttrValue( commandNode, _T("status")); - if (!status) status = _T("completed"); - - if (( xNode = xmlGetChild( commandNode , "x" ))) { - // use jabber:x:data form - HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); - ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE ); - if (( n = xmlGetChild( xNode , "instructions" )) != NULL && xmlGetText( n )!=NULL ) - JabberFormSetInstruction( hwndDlg, xmlGetText( n )); - else if (( n = xmlGetChild( xNode , "title" )) != NULL && xmlGetText( n )!=NULL ) - JabberFormSetInstruction( hwndDlg, xmlGetText( n )); - else - JabberFormSetInstruction(hwndDlg, TranslateTS(status)); - JabberFormCreateUI( hFrame, xNode, &dat->CurrentHeight ); - ShowDlgItem( hwndDlg, IDC_FRAME , SW_SHOW); - } - else { - //NO X FORM - int toHide[]={ IDC_FRAME_TEXT, IDC_FRAME, IDC_VSCROLL, 0}; - sttShowControls(hwndDlg, FALSE, toHide ); - - const TCHAR * noteText=NULL; - HXML noteNode = xmlGetChild( commandNode , "note"); - if (noteNode) - noteText = xmlGetText( noteNode ); - - JabberFormSetInstruction(hwndDlg, noteText ? noteText : TranslateTS(status)); - } - - //check actions - HXML actionsNode = xmlGetChild( commandNode , "actions"); - if ( actionsNode != NULL ) { - ShowDlgItem( hwndDlg, IDC_PREV, ( xmlGetChild( actionsNode , "prev")!=NULL) ? SW_SHOW : SW_HIDE); - ShowDlgItem( hwndDlg, IDC_NEXT, ( xmlGetChild( actionsNode , "next")!=NULL) ? SW_SHOW : SW_HIDE); - ShowDlgItem( hwndDlg, IDC_COMPLETE, ( xmlGetChild( actionsNode , "complete")!=NULL) ? SW_SHOW : SW_HIDE); - ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE); - - int toEnable[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; - sttEnableControls( hwndDlg, TRUE, toEnable ); - } else { - int toHide[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; - sttShowControls(hwndDlg, FALSE, toHide ); - - ShowDlgItem(hwndDlg,IDC_SUBMIT, SW_SHOW); - EnableDlgItem(hwndDlg,IDC_SUBMIT, TRUE); - } - - if (!status || _tcscmp(status,_T("executing"))) { - ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE); - SetWindowText(GetDlgItem(hwndDlg,IDCANCEL), TranslateT("Done")); - } } - else if ( !lstrcmp( type, _T("error"))) { - // error occurred here - int toHide[]={ IDC_FRAME, IDC_FRAME_TEXT, IDC_VSCROLL, - IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_SUBMIT, 0}; - - sttShowControls(hwndDlg, FALSE, toHide ); - - const TCHAR* code=NULL; - const TCHAR* description=NULL; - TCHAR buff[255]; - HXML errorNode = xmlGetChild( workNode , "error"); - if ( errorNode ) { - code = xmlGetAttrValue( errorNode, _T("code")); - description = xmlGetText( errorNode ); - } - _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s"),code ? code : _T(""),description?description:_T("")); - JabberFormSetInstruction(hwndDlg,buff); - } - JabberAdHoc_RefreshFrameScroll( hwndDlg, dat ); - return TRUE; -} - -int CJabberProto::AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData* dat, TCHAR* action) -{ - HXML commandNode = xmlGetChild( dat->AdHocNode, "command" ); - HXML xNode = xmlGetChild( commandNode , "x" ); - HXML dataNode = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), xNode); - - int iqId = (int)hwndDlg; - XmlNodeIq iq( _T("set"), iqId, xmlGetAttrValue( dat->AdHocNode, _T("from"))); - HXML command = iq << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)); - - const TCHAR* sessionId = xmlGetAttrValue( commandNode, _T("sessionid")); - if ( sessionId ) - command << XATTR( _T("sessionid"), sessionId ); - - const TCHAR* node = xmlGetAttrValue( commandNode, _T("node")); - if ( node ) - command << XATTR( _T("node"), node ); - - if ( action ) - command << XATTR( _T("action"), action ); - - xmlAddChild( command, dataNode ); - IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); - m_ThreadInfo->send( iq ); - - xi.destroyNode( dataNode ); - - JabberFormSetInstruction(hwndDlg,TranslateT("In progress. Please Wait...")); - - static const int toDisable[]={IDC_SUBMIT, IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; - sttEnableControls( hwndDlg, FALSE, toDisable); - - return TRUE; -} - - -int CJabberProto::AdHoc_AddCommandRadio(HWND hFrame, TCHAR * labelStr, int id, int ypos, int value) -{ - int labelHeight; - RECT strRect={0}; - - int verticalStep=4; - int ctrlMinHeight=18; - HWND hCtrl=NULL; - - RECT rcFrame; - GetClientRect(hFrame,&rcFrame); - - int ctrlOffset=20; - int ctrlWidth=rcFrame.right-ctrlOffset; - - HDC hdc = GetDC( hFrame ); - labelHeight = max(ctrlMinHeight, DrawText( hdc , labelStr, -1, &strRect, DT_CALCRECT )); - ctrlWidth=min( ctrlWidth, strRect.right-strRect.left+20 ); - ReleaseDC( hFrame, hdc ); - - hCtrl = CreateWindowEx( 0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTORADIOBUTTON, ctrlOffset, ypos, ctrlWidth, labelHeight, hFrame, ( HMENU ) id, hInst, NULL ); - SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) SendMessage( GetParent(hFrame), WM_GETFONT, 0, 0 ), 0 ); - SendMessage( hCtrl, BM_SETCHECK, value, 0 ); - return (ypos + labelHeight + verticalStep); - -} - -static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JabberAdHocData* dat = ( JabberAdHocData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - switch (msg) - { - case WM_INITDIALOG: - { - CJabberAdhocStartupParams* pStartupParams = (CJabberAdhocStartupParams *)lParam; - dat=(JabberAdHocData *)mir_alloc(sizeof(JabberAdHocData)); - memset(dat,0,sizeof(JabberAdHocData)); - - //hmmm, useless code? if (dat->ResponderJID) mir_free(dat->ResponderJID); - dat->ResponderJID = mir_tstrdup(pStartupParams->m_szJid); - dat->proto = pStartupParams->m_pProto; - - SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat); - WindowSetIcon( hwndDlg, dat->proto, "adhoc" ); - dat->proto->m_hwndCommandWindow = hwndDlg; - TranslateDialogDefault( hwndDlg ); - - //Firstly hide frame - LONG frameExStyle = GetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE ); - frameExStyle |= WS_EX_CONTROLPARENT; - - SetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); - - int toHide[]={ IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_FRAME_TEXT, 0}; - sttShowControls(hwndDlg, FALSE, toHide ); - - int toShow[]={ IDC_INSTRUCTION, IDC_SUBMIT, IDCANCEL, 0}; - sttShowControls(hwndDlg, TRUE, toShow ); - - EnableDlgItem(hwndDlg,IDC_VSCROLL,TRUE); - - SetWindowPos(GetDlgItem(hwndDlg,IDC_VSCROLL),HWND_BOTTOM,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); - - SetDlgItemText(hwndDlg,IDC_SUBMIT, TranslateT("Execute")); - JabberFormSetInstruction(hwndDlg,TranslateT("Requesting command list. Please wait...")); - - if ( !pStartupParams->m_szNode ) { - dat->proto->AdHoc_RequestListOfCommands(pStartupParams->m_szJid, hwndDlg); - - TCHAR Caption[ 512 ]; - _sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Jabber Ad-Hoc commands at"), dat->ResponderJID ); - SetWindowText(hwndDlg, Caption); - } - else - { - int iqId = (int)hwndDlg; - dat->proto->IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); - dat->proto->m_ThreadInfo->send( - XmlNodeIq( _T("set"), iqId, pStartupParams->m_szJid ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) - << XATTR( _T("node"), pStartupParams->m_szNode ) << XATTR( _T("action"), _T("execute"))); - - EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE ); - SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" )); - - TCHAR Caption[ 512 ]; - _sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Sending Ad-Hoc command to"), dat->ResponderJID ); - SetWindowText(hwndDlg, Caption); - } - - delete pStartupParams; - - return TRUE; - } - case WM_CTLCOLORSTATIC: - if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) - { - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } else - { - return NULL; - } - case WM_COMMAND: - { - switch ( LOWORD( wParam )) - { - - case IDC_PREV: - return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("prev")); - case IDC_NEXT: - return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("next")); - case IDC_COMPLETE: - return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("complete")); - case IDC_SUBMIT: - if (!dat->AdHocNode && dat->CommandsNode && LOWORD( wParam )==IDC_SUBMIT) - return dat->proto->AdHoc_ExecuteCommand(hwndDlg,dat->ResponderJID, dat); - else - return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat, NULL); - case IDCLOSE: - case IDCANCEL: - xi.destroyNode( dat->AdHocNode ); dat->AdHocNode = NULL; - DestroyWindow( hwndDlg ); - return TRUE; - } - break; - } - case JAHM_COMMANDLISTRESULT: - return dat->proto->AdHoc_OnJAHMCommandListResult(hwndDlg,(HXML)lParam,dat); - case JAHM_PROCESSRESULT: - return dat->proto->AdHoc_OnJAHMProcessResult(hwndDlg, (HXML)wParam,dat); - - case WM_MOUSEWHEEL: - { - int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); - if ( zDelta ) { - int nScrollLines=0; - SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,(void*)&nScrollLines,0); - for (int i=0; i<(nScrollLines+1)/2; i++) - SendMessage(hwndDlg,WM_VSCROLL, (zDelta<0)?SB_LINEDOWN:SB_LINEUP,0); - } } - return TRUE; - - case WM_VSCROLL: - { - int pos; - if ( dat != NULL ) { - pos = dat->curPos; - switch ( LOWORD( wParam )) - { - case SB_LINEDOWN: - pos += 10; - break; - case SB_LINEUP: - pos -= 10; - break; - case SB_PAGEDOWN: - pos += ( dat->CurrentHeight - 10 ); - break; - case SB_PAGEUP: - pos -= ( dat->CurrentHeight - 10 ); - break; - case SB_THUMBTRACK: - pos = HIWORD( wParam ); - break; - } - if ( pos > ( dat->CurrentHeight - dat->frameHeight )) - pos = dat->CurrentHeight - dat->frameHeight; - if ( pos < 0 ) - pos = 0; - if ( dat->curPos != pos ) { - ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL , &( dat->frameRect )); - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); - RECT Invalid=dat->frameRect; - if (dat->curPos - pos >0) - Invalid.bottom=Invalid.top+(dat->curPos - pos); - else - Invalid.top=Invalid.bottom+(dat->curPos - pos); - - RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_UPDATENOW |RDW_ALLCHILDREN); - dat->curPos = pos; - } } - break; - } - case WM_DESTROY: - { - JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME)); - WindowFreeIcon(hwndDlg); - - dat->proto->m_hwndCommandWindow = NULL; - mir_free( dat->ResponderJID ); - xi.destroyNode( dat->CommandsNode ); - xi.destroyNode( dat->AdHocNode ); - mir_free(dat); - dat=NULL; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - break; - } - } - return FALSE; -} - -int __cdecl CJabberProto::ContactMenuRunCommands(WPARAM wParam, LPARAM lParam ) -{ - HANDLE hContact; - DBVARIANT dbv; - int res = -1; - JABBER_LIST_ITEM * item=NULL; - - if ((( hContact=( HANDLE ) wParam )!=NULL || (lParam!=0)) && m_bJabberOnline ) { - if ( wParam && !JGetStringT( hContact, "jid", &dbv )) { - TCHAR jid[ JABBER_MAX_JID_LEN ]; - int selected = 0; - _tcsncpy(jid, dbv.ptszVal, SIZEOF(jid)); - - ListLock(); - { - item = ListGetItemPtr( LIST_ROSTER, jid); - if (item) - { - if (item->resourceCount>1) - { - HMENU hMenu=CreatePopupMenu(); - for (int i=0; iresourceCount; i++) - AppendMenu(hMenu,MF_STRING,i+1, item->resource[i].resourceName); - HWND hwndTemp=CreateWindowEx(WS_EX_TOOLWINDOW,_T("button"),_T("PopupMenuHost"),0,0,0,10,10,NULL,NULL,hInst,NULL); - SetForegroundWindow(hwndTemp); - POINT pt; - GetCursorPos(&pt); - RECT rc; - selected=TrackPopupMenu(hMenu,TPM_RETURNCMD,pt.x,pt.y,0,hwndTemp,&rc); - DestroyMenu(hMenu); - DestroyWindow(hwndTemp); - } - else selected=1; - - if (selected>0) - { - selected--; - if (item->resource) - { - _tcsncat(jid,_T("/"),SIZEOF(jid)); - _tcsncat(jid,item->resource[selected].resourceName,SIZEOF(jid)); - } - selected=1; - } - } - } - ListUnlock(); - - if (!item || selected) { - CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams( this, jid, NULL ); - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, ( LPARAM )(pStartupParams)); - } - JFreeVariant( &dbv ); - - } - else if (lParam!=0) - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, lParam ); - } - return res; -} - -void CJabberProto::ContactMenuAdhocCommands( CJabberAdhocStartupParams* param ) -{ - if ( param ) - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, (LPARAM)param ); -} diff --git a/protocols/JabberG/jabber_agent.cpp b/protocols/JabberG/jabber_agent.cpp deleted file mode 100644 index b0ad17e8a0..0000000000 --- a/protocols/JabberG/jabber_agent.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// Agent registration progress dialog - -class CAgentRegProgressDlg : public CJabberDlgBase -{ - CCtrlButton m_ok; - -public: - CAgentRegProgressDlg( CJabberProto* _ppro, HWND _owner ) : - CJabberDlgBase( _ppro, IDD_OPT_REGISTER, _owner, false ), - m_ok( this, IDOK ) - { - m_ok.OnClick = Callback( this, &CAgentRegProgressDlg::OnOk ); - } - - virtual void OnInitDialog() - { - m_proto->m_hwndRegProgress = m_hwnd; - SetWindowTextA( m_hwnd, "Jabber Agent Registration" ); - TranslateDialogDefault( m_hwnd ); - } - - virtual INT_PTR DlgProc( UINT msg, WPARAM wParam, LPARAM lParam ) - { - if ( msg == WM_JABBER_REGDLG_UPDATE ) { - if (( TCHAR* )lParam == NULL ) - SetDlgItemText( m_hwnd, IDC_REG_STATUS, TranslateT( "No message" )); - else - SetDlgItemText( m_hwnd, IDC_REG_STATUS, ( TCHAR* )lParam ); - if ( wParam >= 0 ) - SendMessage( GetDlgItem( m_hwnd, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 ); - if ( wParam >= 100 ) - m_ok.SetText( TranslateT( "OK" )); - } - - return CJabberDlgBase::DlgProc( msg, wParam, lParam ); - } - - void OnOk( CCtrlButton* ) - { - m_proto->m_hwndRegProgress = NULL; - EndDialog( m_hwnd, 0 ); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Transport registration form - -class CAgentRegDlg : public CJabberDlgBase -{ - int m_curPos; - int m_formHeight, m_frameHeight; - RECT m_frameRect; - HXML m_agentRegIqNode; - TCHAR* m_jid; - - CCtrlButton m_submit; - -public: - CAgentRegDlg( CJabberProto* _ppro, TCHAR* _jid ) : - CJabberDlgBase( _ppro, IDD_FORM, NULL, false ), - m_submit( this, IDC_SUBMIT ), - m_jid( _jid ), - m_agentRegIqNode( NULL ) - { - m_submit.OnClick = Callback( this, &CAgentRegDlg::OnSubmit ); - } - - virtual void OnInitDialog() - { - EnableWindow( GetParent( m_hwnd ), FALSE ); - m_proto->m_hwndAgentRegInput = m_hwnd; - SetWindowText( m_hwnd, TranslateT( "Jabber Agent Registration" )); - SetDlgItemText( m_hwnd, IDC_SUBMIT, TranslateT( "Register" )); - SetDlgItemText( m_hwnd, IDC_FRAME_TEXT, TranslateT( "Please wait..." )); - - int iqId = m_proto->SerialNext(); - m_proto->IqAdd( iqId, IQ_PROC_GETREGISTER, &CJabberProto::OnIqResultGetRegister ); - m_proto->m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, m_jid ) << XQUERY( _T(JABBER_FEAT_REGISTER))); - - // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children ) - LONG frameExStyle = GetWindowLongPtr( GetDlgItem( m_hwnd, IDC_FRAME ), GWL_EXSTYLE ); - frameExStyle |= WS_EX_CONTROLPARENT; - SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); - } - - virtual void OnDestroy() - { - xi.destroyNode( m_agentRegIqNode ); - JabberFormDestroyUI(GetDlgItem(m_hwnd, IDC_FRAME)); - m_proto->m_hwndAgentRegInput = NULL; - EnableWindow( GetParent( m_hwnd ), TRUE ); - SetActiveWindow( GetParent( m_hwnd )); - } - - virtual INT_PTR DlgProc( UINT msg, WPARAM wParam, LPARAM lParam ) - { - switch( msg ) { - case WM_CTLCOLORSTATIC: - switch( GetDlgCtrlID(( HWND )lParam )) { - case IDC_WHITERECT: case IDC_INSTRUCTION: case IDC_TITLE: - return (INT_PTR)GetStockObject(WHITE_BRUSH); - default: - return NULL; - } - - case WM_JABBER_REGINPUT_ACTIVATE: - if ( wParam == 1 ) { // success - // lParam = node from agent JID as a result of "get jabber:iq:register" - HWND hFrame = GetDlgItem( m_hwnd, IDC_FRAME ); - ShowWindow( GetDlgItem( m_hwnd, IDC_FRAME_TEXT ), SW_HIDE ); - - HXML queryNode, xNode; - if (( m_agentRegIqNode = ( HXML )lParam ) == NULL ) return TRUE; - if (( queryNode = xmlGetChild( m_agentRegIqNode , "query" )) == NULL ) return TRUE; - - RECT rect; - - m_curPos = 0; - GetClientRect( GetDlgItem( m_hwnd, IDC_FRAME ), &( m_frameRect )); - GetClientRect( GetDlgItem( m_hwnd, IDC_VSCROLL ), &rect ); - m_frameRect.right -= ( rect.right - rect.left ); - GetClientRect( GetDlgItem( m_hwnd, IDC_FRAME ), &rect ); - m_frameHeight = rect.bottom - rect.top; - - if (( xNode=xmlGetChild( queryNode , "x" )) != NULL ) { - // use new jabber:x:data form - HXML n = xmlGetChild( xNode , "instructions" ); - if ( n != NULL && xmlGetText( n )!=NULL ) - JabberFormSetInstruction( m_hwnd, xmlGetText( n )); - - JabberFormCreateUI( hFrame, xNode, &m_formHeight /*dummy*/ ); - } - else { - // use old registration information form - HJFORMLAYOUT layout_info = JabberFormCreateLayout(hFrame); - for ( int i=0; ; i++ ) { - HXML n = xmlGetChild( queryNode ,i); - if ( !n ) - break; - - if ( xmlGetName( n )) { - if ( !lstrcmp( xmlGetName( n ), _T("instructions"))) { - JabberFormSetInstruction( m_hwnd, xmlGetText( n )); - } - else if ( !lstrcmp( xmlGetName( n ), _T("key")) || !lstrcmp( xmlGetName( n ), _T("registered"))) { - // do nothing - } - else if ( !lstrcmp( xmlGetName( n ), _T("password"))) - JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_PRIVATE, xmlGetName( n ), xmlGetText( n )); - else // everything else is a normal text field - JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_SINGLE, xmlGetName( n ), xmlGetText( n )); - } } - JabberFormLayoutControls(hFrame, layout_info, &m_formHeight); - mir_free(layout_info); - } - - if ( m_formHeight > m_frameHeight ) { - HWND hwndScroll; - - hwndScroll = GetDlgItem( m_hwnd, IDC_VSCROLL ); - EnableWindow( hwndScroll, TRUE ); - SetScrollRange( hwndScroll, SB_CTL, 0, m_formHeight - m_frameHeight, FALSE ); - m_curPos = 0; - } - - EnableWindow( GetDlgItem( m_hwnd, IDC_SUBMIT ), TRUE ); - } - else if ( wParam == 0 ) { - // lParam = error message - SetDlgItemText( m_hwnd, IDC_FRAME_TEXT, ( LPCTSTR ) lParam ); - } - return TRUE; - - case WM_VSCROLL: - int pos = m_curPos; - switch ( LOWORD( wParam )) { - case SB_LINEDOWN: pos += 10; break; - case SB_LINEUP: pos -= 10; break; - case SB_PAGEDOWN: pos += ( m_frameHeight - 10 ); break; - case SB_PAGEUP: pos -= ( m_frameHeight - 10 ); break; - case SB_THUMBTRACK: pos = HIWORD( wParam ); break; - } - if ( pos > ( m_formHeight - m_frameHeight )) - pos = m_formHeight - m_frameHeight; - if ( pos < 0 ) - pos = 0; - if ( m_curPos != pos ) { - ScrollWindow( GetDlgItem( m_hwnd, IDC_FRAME ), 0, m_curPos - pos, NULL, &( m_frameRect )); - SetScrollPos( GetDlgItem( m_hwnd, IDC_VSCROLL ), SB_CTL, pos, TRUE ); - m_curPos = pos; - } } - - return CJabberDlgBase::DlgProc( msg, wParam, lParam ); - } - - void OnSubmit( CCtrlButton* ) - { - HXML queryNode, xNode; - const TCHAR *from; - - if ( m_agentRegIqNode == NULL ) return; - if (( from = xmlGetAttrValue( m_agentRegIqNode, _T("from"))) == NULL ) return; - if (( queryNode = xmlGetChild( m_agentRegIqNode , "query" )) == NULL ) return; - HWND hFrame = GetDlgItem( m_hwnd, IDC_FRAME ); - - TCHAR *str2 = ( TCHAR* )alloca( sizeof(TCHAR) * 128 ); - int id = 0; - - int iqId = m_proto->SerialNext(); - m_proto->IqAdd( iqId, IQ_PROC_SETREGISTER, &CJabberProto::OnIqResultSetRegister ); - - XmlNodeIq iq( _T("set"), iqId, from ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); - - if (( xNode = xmlGetChild( queryNode , "x" )) != NULL ) { - // use new jabber:x:data form - HXML n = JabberFormGetData( hFrame, xNode ); - xmlAddChild( query, n ); - xi.destroyNode( n ); - } - else { - // use old registration information form - for ( int i=0; ; i++ ) { - HXML n = xmlGetChild( queryNode ,i); - if ( !n ) - break; - - if ( xmlGetName( n )) { - if ( !lstrcmp( xmlGetName( n ), _T("key"))) { - // field that must be passed along with the registration - if ( xmlGetText( n )) - xmlAddChild( query, xmlGetName( n ), xmlGetText( n )); - else - xmlAddChild( query, xmlGetName( n )); - } - else if ( !lstrcmp( xmlGetName( n ), _T("registered")) || !lstrcmp( xmlGetName( n ), _T("instructions"))) { - // do nothing, we will skip these - } - else { - GetDlgItemText( hFrame, id, str2, 128 ); - xmlAddChild( query, xmlGetName( n ), str2 ); - id++; - } } } } - - m_proto->m_ThreadInfo->send( iq ); - - CAgentRegProgressDlg( m_proto, m_hwnd ).DoModal(); - - Close(); - } -}; - -void CJabberProto::RegisterAgent( HWND /*hwndDlg*/, TCHAR* jid ) -{ - ( new CAgentRegDlg( this, jid ))->Show(); -} diff --git a/protocols/JabberG/jabber_bookmarks.cpp b/protocols/JabberG/jabber_bookmarks.cpp deleted file mode 100644 index 158f83e669..0000000000 --- a/protocols/JabberG/jabber_bookmarks.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2007 Michael Stepura, George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// Bookmarks editor window - -struct JabberAddBookmarkDlgParam { - CJabberProto* ppro; - JABBER_LIST_ITEM* m_item; -}; - -static INT_PTR CALLBACK JabberAddBookmarkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JabberAddBookmarkDlgParam* param = (JabberAddBookmarkDlgParam*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - TCHAR text[512]; - JABBER_LIST_ITEM *item; - - switch ( msg ) { - case WM_INITDIALOG: - param = (JabberAddBookmarkDlgParam*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - param->ppro->m_hwndJabberAddBookmark = hwndDlg; - TranslateDialogDefault( hwndDlg ); - if ( item = param->m_item ) { - if ( !lstrcmp( item->type, _T("conference"))) { - if (!_tcschr( item->jid, _T( '@' ))) { //no room name - consider it is transport - SendDlgItemMessage(hwndDlg, IDC_AGENT_RADIO, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); - } - else SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_SETCHECK, BST_CHECKED, 0); - } - else { - SendDlgItemMessage(hwndDlg, IDC_URL_RADIO, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); - SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_UNCHECKED, 0); - EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); - } - - EnableWindow( GetDlgItem( hwndDlg, IDC_ROOM_RADIO), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_URL_RADIO), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_RADIO), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); - - if ( item->jid ) SetDlgItemText( hwndDlg, IDC_ROOM_JID, item->jid ); - if ( item->name ) SetDlgItemText( hwndDlg, IDC_NAME, item->name ); - if ( item->nick ) SetDlgItemText( hwndDlg, IDC_NICK, item->nick ); - if ( item->password ) SetDlgItemText( hwndDlg, IDC_PASSWORD, item->password ); - if ( item->bAutoJoin ) SendDlgItemMessage( hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_CHECKED, 0 ); - if ( SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_GETCHECK,0, 0) == BST_CHECKED ) - EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), TRUE ); - } - else { - EnableWindow( GetDlgItem( hwndDlg, IDOK ), FALSE ); - SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_SETCHECK, BST_CHECKED, 0); - } - return TRUE; - - case WM_COMMAND: - switch ( HIWORD(wParam)) { - case BN_CLICKED: - switch (LOWORD (wParam)) { - case IDC_ROOM_RADIO: - EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), TRUE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), TRUE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), TRUE ); - break; - case IDC_AGENT_RADIO: - case IDC_URL_RADIO: - EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); - EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); - SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_UNCHECKED, 0); - EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); - break; - } - } - - switch ( LOWORD( wParam )) { - case IDC_ROOM_JID: - if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) - EnableWindow( GetDlgItem( hwndDlg, IDOK ), GetDlgItemText( hwndDlg, IDC_ROOM_JID, text, SIZEOF( text ))); - break; - - case IDOK: - { - GetDlgItemText( hwndDlg, IDC_ROOM_JID, text, SIZEOF( text )); - TCHAR* roomJID = NEWTSTR_ALLOCA( text ); - - if ( param->m_item ) - param->ppro->ListRemove( LIST_BOOKMARK, param->m_item->jid ); - - item = param->ppro->ListAdd( LIST_BOOKMARK, roomJID ); - item->bUseResource = TRUE; - - if ( SendDlgItemMessage(hwndDlg, IDC_URL_RADIO, BM_GETCHECK,0, 0) == BST_CHECKED ) - replaceStrT( item->type, _T( "url" )); - else - replaceStrT( item->type, _T( "conference" )); - - GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text )); - replaceStrT( item->nick, text ); - - GetDlgItemText( hwndDlg, IDC_PASSWORD, text, SIZEOF( text )); - replaceStrT( item->password, text ); - - GetDlgItemText( hwndDlg, IDC_NAME, text, SIZEOF( text )); - replaceStrT( item->name, ( text[0] == 0 ) ? roomJID : text ); - - item->bAutoJoin = (SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_GETCHECK,0, 0) == BST_CHECKED ); - { - int iqId = param->ppro->SerialNext(); - param->ppro->IqAdd( iqId, IQ_PROC_SETBOOKMARKS, &CJabberProto::OnIqResultSetBookmarks); - - XmlNodeIq iq( _T("set"), iqId); - param->ppro->SetBookmarkRequest(iq); - param->ppro->m_ThreadInfo->send( iq ); - } - } - // fall through - case IDCANCEL: - EndDialog( hwndDlg, 0 ); - break; - } - break; - - case WM_JABBER_CHECK_ONLINE: - if ( !param->ppro->m_bJabberOnline ) - EndDialog( hwndDlg, 0 ); - break; - - case WM_DESTROY: - param->ppro->m_hwndJabberAddBookmark = NULL; - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Bookmarks manager window - -class CJabberDlgBookmarks : public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgBookmarks(CJabberProto *proto); - - void UpdateData(); - -protected: - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - int Resizer(UTILRESIZECONTROL *urc); - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - void OnProtoCheckOnline(WPARAM wParam, LPARAM lParam); - void OnProtoRefresh(WPARAM wParam, LPARAM lParam); - void OpenBookmark(); - -private: - CCtrlMButton m_btnAdd; - CCtrlMButton m_btnEdit; - CCtrlMButton m_btnRemove; - CCtrlFilterListView m_lvBookmarks; - - void lvBookmarks_OnDoubleClick(CCtrlFilterListView *) - { - OpenBookmark(); - } - - void btnAdd_OnClick(CCtrlFilterListView *) - { - if (!m_proto->m_bJabberOnline) return; - - JabberAddBookmarkDlgParam param; - param.ppro = m_proto; - param.m_item = NULL; - DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), m_hwnd, JabberAddBookmarkDlgProc, (LPARAM)¶m); - } - - void btnEdit_OnClick(CCtrlFilterListView *) - { - if (!m_proto->m_bJabberOnline) return; - - int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); - if (iItem < 0) return; - - TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); - if (!address) return; - - JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); - if (!item) return; - - JabberAddBookmarkDlgParam param; - param.ppro = m_proto; - param.m_item = item; - DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), m_hwnd, JabberAddBookmarkDlgProc, (LPARAM)¶m); - } - - void btnRemove_OnClick(CCtrlFilterListView *) - { - if (!m_proto->m_bJabberOnline) return; - - int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); - if (iItem < 0) return; - - TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); - if (!address) return; - - JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); - if (!item) return; - - m_btnAdd.Disable(); - m_btnEdit.Disable(); - m_btnRemove.Disable(); - - m_proto->ListRemove(LIST_BOOKMARK, address); - - m_lvBookmarks.SetItemState(iItem, 0, LVIS_SELECTED); // Unselect the item - - int iqId = m_proto->SerialNext(); - m_proto->IqAdd(iqId, IQ_PROC_SETBOOKMARKS, &CJabberProto::OnIqResultSetBookmarks); - - XmlNodeIq iq( _T("set"), iqId); - m_proto->SetBookmarkRequest(iq); - m_proto->m_ThreadInfo->send(iq); - } - -}; - -CJabberDlgBookmarks::CJabberDlgBookmarks(CJabberProto *proto) : - CSuper(proto, IDD_BOOKMARKS, NULL), - m_btnAdd(this, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add")), - m_btnEdit(this, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit")), - m_btnRemove(this, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove")), - m_lvBookmarks(this, IDC_BM_LIST, true, true) -{ - m_lvBookmarks.OnItemActivate = Callback(this, &CJabberDlgBookmarks::lvBookmarks_OnDoubleClick); - m_btnAdd.OnClick = Callback(this, &CJabberDlgBookmarks::btnAdd_OnClick); - m_btnEdit.OnClick = Callback(this, &CJabberDlgBookmarks::btnEdit_OnClick); - m_btnRemove.OnClick = Callback(this, &CJabberDlgBookmarks::btnRemove_OnClick); -} - -void CJabberDlgBookmarks::UpdateData() -{ - if (!m_proto->m_bJabberOnline) return; - - int iqId = m_proto->SerialNext(); - m_proto->IqAdd( iqId, IQ_PROC_DISCOBOOKMARKS, &CJabberProto::OnIqResultDiscoBookmarks); - m_proto->m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) - << XCHILDNS( _T("storage"), _T("storage:bookmarks"))); -} - -void CJabberDlgBookmarks::OnInitDialog() -{ - CSuper::OnInitDialog(); - - WindowSetIcon( m_hwnd, m_proto, "bookmarks" ); - - m_btnAdd.Disable(); - m_btnEdit.Disable(); - m_btnRemove.Disable(); - - m_lvBookmarks.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP | (IsWinVerXPPlus() ? LVS_EX_DOUBLEBUFFER : 0)); - - HIMAGELIST hIml = m_lvBookmarks.CreateImageList(LVSIL_SMALL); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("group")); - ImageList_AddIcon_Icolib(hIml, LoadSkinnedIcon(SKINICON_EVENT_URL)); - - m_lvBookmarks.AddColumn(0, TranslateT("Bookmark Name"), m_proto->JGetWord(NULL, "bookmarksWnd_cx0", 120)); - m_lvBookmarks.AddColumn(1, TranslateT("Address (JID or URL)"), m_proto->JGetWord(NULL, "bookmarksWnd_cx1", 210)); - m_lvBookmarks.AddColumn(2, TranslateT("Nickname"), m_proto->JGetWord(NULL, "bookmarksWnd_cx2", 90)); - - m_lvBookmarks.EnableGroupView(TRUE); - m_lvBookmarks.AddGroup(0, TranslateT("Conferences")); - m_lvBookmarks.AddGroup(1, TranslateT("Links")); - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "bookmarksWnd_"); -} - -void CJabberDlgBookmarks::OnClose() -{ - LVCOLUMN lvc = {0}; - lvc.mask = LVCF_WIDTH; - m_lvBookmarks.GetColumn(0, &lvc); - m_proto->JSetWord(NULL, "bookmarksWnd_cx0", lvc.cx); - m_lvBookmarks.GetColumn(1, &lvc); - m_proto->JSetWord(NULL, "bookmarksWnd_cx1", lvc.cx); - m_lvBookmarks.GetColumn(2, &lvc); - m_proto->JSetWord(NULL, "bookmarksWnd_cx2", lvc.cx); - - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "bookmarksWnd_"); - - CSuper::OnClose(); -} - -void CJabberDlgBookmarks::OnDestroy() -{ - m_proto->m_pDlgBookmarks = NULL; - - CSuper::OnDestroy(); -} - -void CJabberDlgBookmarks::OpenBookmark() -{ - int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); - if (iItem < 0) return; - - TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); - if (!address) return; - - JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); - if (!item) return; - - if (!lstrcmpi(item->type, _T("conference"))) - { - if (!jabberChatDllPresent) - { - JabberChatDllError(); - return; - } - - m_lvBookmarks.SetItemState(iItem, 0, LVIS_SELECTED); // Unselect the item - - /* some hack for using bookmark to transport not under XEP-0048 */ - if (!_tcschr(item->jid, _T('@'))) - { //the room name is not provided let consider that it is transport and send request to registration - m_proto->RegisterAgent(NULL, item->jid); - } else - { - TCHAR *room = NEWTSTR_ALLOCA(item->jid); - TCHAR *server = _tcschr(room, _T('@')); - *(server++) = 0; - - if (item->nick && *item->nick) - { - m_proto->GroupchatJoinRoom(server, room, item->nick, item->password); - } else - { - TCHAR* nick = JabberNickFromJID(m_proto->m_szJabberJID); - m_proto->GroupchatJoinRoom(server, room, nick, item->password); - mir_free(nick); - } - } - } else - { - char *szUrl = mir_t2a(item->jid); - CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl); - mir_free(szUrl); - } -} - -INT_PTR CJabberDlgBookmarks::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 451; - lpmmi->ptMinTrackSize.y = 320; - return 0; - } - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - OpenBookmark(); - return TRUE; - } - } - break; - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -void CJabberDlgBookmarks::OnProtoCheckOnline(WPARAM, LPARAM) -{ - if (!m_proto->m_bJabberOnline) - { - m_btnAdd.Disable(); - m_btnEdit.Disable(); - m_btnRemove.Disable(); - } else - { - UpdateData(); - } - -} - -void CJabberDlgBookmarks::OnProtoRefresh(WPARAM, LPARAM) -{ - m_lvBookmarks.DeleteAllItems(); - - JABBER_LIST_ITEM *item = NULL; - LISTFOREACH(i, m_proto, LIST_BOOKMARK) - { - if (item = m_proto->ListGetItemPtrFromIndex(i)) - { - int itemType = lstrcmpi(item->type, _T("conference")) ? 1 : 0; - int iItem = m_lvBookmarks.AddItem(item->name, itemType, (LPARAM)item->jid, itemType); - m_lvBookmarks.SetItem(iItem, 1, item->jid); - if (itemType == 0) - m_lvBookmarks.SetItem(iItem, 2, item->nick); - } - } - - if (item) - { - m_btnEdit.Enable(); - m_btnRemove.Enable(); - } - - m_btnAdd.Enable(); -} - -int CJabberDlgBookmarks::Resizer(UTILRESIZECONTROL *urc) -{ - switch ( urc->wId ) { - case IDC_BM_LIST: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - - case IDC_ADD: - case IDC_EDIT: - case IDC_REMOVE: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - } - return CSuper::Resizer(urc); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Launches the Bookmarks manager window - -INT_PTR __cdecl CJabberProto::OnMenuHandleBookmarks( WPARAM, LPARAM) -{ - UI_SAFE_OPEN_EX(CJabberDlgBookmarks, m_pDlgBookmarks, pDlg); - pDlg->UpdateData(); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Launches the Bookmark details window, lParam is JABBER_BOOKMARK_ITEM* -int CJabberProto::AddEditBookmark( JABBER_LIST_ITEM* item ) -{ - if ( m_bJabberOnline) { - JabberAddBookmarkDlgParam param; - param.ppro = this; - param.m_item = item;//(JABBER_LIST_ITEM*)lParam; - DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), NULL, JabberAddBookmarkDlgProc, (LPARAM)¶m ); - } - return 0; -} diff --git a/protocols/JabberG/jabber_byte.cpp b/protocols/JabberG/jabber_byte.cpp deleted file mode 100644 index 9e86b51388..0000000000 --- a/protocols/JabberG/jabber_byte.cpp +++ /dev/null @@ -1,778 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_byte.h" -#include "jabber_caps.h" - -#define JABBER_NETWORK_BUFFER_SIZE 4096 - -///////////////// Bytestream sending ///////////////////////// - -JABBER_BYTE_TRANSFER::~JABBER_BYTE_TRANSFER() -{ - filetransfer* pft = ft; - if ( pft ) - pft->jbt = NULL; - - mir_free( srcJID ); - mir_free( dstJID ); - mir_free( streamhostJID ); - mir_free( iqId ); - mir_free( sid ); - - xi.destroyNode( iqNode ); - - // XEP-0065 proxy support - mir_free( szProxyHost ); - mir_free( szProxyPort ); - mir_free( szProxyJid ); - mir_free( szStreamhostUsed ); -} - -void CJabberProto::IqResultProxyDiscovery( HXML iqNode, CJabberIqInfo* pInfo ) -{ - JABBER_BYTE_TRANSFER *jbt = ( JABBER_BYTE_TRANSFER * )pInfo->GetUserData(); - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode ) { - const TCHAR *queryXmlns = xmlGetAttrValue( queryNode, _T( "xmlns" )); - if (queryXmlns && !_tcscmp( queryXmlns, _T(JABBER_FEAT_BYTESTREAMS))) { - HXML streamHostNode = xmlGetChild( queryNode , "streamhost" ); - if ( streamHostNode ) { - const TCHAR *streamJid = xmlGetAttrValue( streamHostNode, _T( "jid" )); - const TCHAR *streamHost = xmlGetAttrValue( streamHostNode, _T( "host" )); - const TCHAR *streamPort = xmlGetAttrValue( streamHostNode, _T( "port" )); - if ( streamJid && streamHost && streamPort ) { - jbt->szProxyHost = mir_tstrdup( streamHost ); - jbt->szProxyJid = mir_tstrdup( streamJid ); - jbt->szProxyPort = mir_tstrdup( streamPort ); - jbt->bProxyDiscovered = TRUE; - } } } } } - else if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) - jbt->state = JBT_ERROR; - - if ( jbt->hProxyEvent ) - SetEvent( jbt->hProxyEvent ); -} - -void JabberByteSendConnection( HANDLE hConn, DWORD /*dwRemoteIP*/, void* extra ) -{ - CJabberProto* ppro = ( CJabberProto* )extra; - TCHAR szPort[8]; - JABBER_BYTE_TRANSFER *jbt; - int recvResult, bytesParsed; - HANDLE hListen; - JABBER_LIST_ITEM *item; - char* buffer; - int datalen; - - NETLIBCONNINFO connInfo = { sizeof(connInfo) }; - CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hConn, (LPARAM)&connInfo); - - mir_sntprintf( szPort, SIZEOF( szPort ), _T("%u"), connInfo.wPort ); - ppro->Log( "bytestream_send_connection incoming connection accepted: %s", connInfo.szIpPort ); - - if (( item = ppro->ListGetItemPtr( LIST_BYTE, szPort )) == NULL ) { - ppro->Log( "No bytestream session is currently active, connection closed." ); - Netlib_CloseHandle( hConn ); - return; - } - - jbt = item->jbt; - - if (( buffer = ( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { - ppro->Log( "bytestream_send cannot allocate network buffer, connection closed." ); - jbt->state = JBT_ERROR; - Netlib_CloseHandle( hConn ); - if ( jbt->hEvent != NULL ) SetEvent( jbt->hEvent ); - return; - } - - hListen = jbt->hConn; - jbt->hConn = hConn; - jbt->state = JBT_INIT; - datalen = 0; - while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR ) { - recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); - if ( recvResult <= 0 ) - break; - - datalen += recvResult; - bytesParsed = ppro->ByteSendParse( hConn, jbt, buffer, datalen ); - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - } - - if ( jbt->hConn ) - Netlib_CloseHandle( jbt->hConn ); - - ppro->Log( "bytestream_send_connection closing connection" ); - jbt->hConn = hListen; - mir_free( buffer ); - - if ( jbt->hEvent != NULL ) - SetEvent( jbt->hEvent ); -} - -void CJabberProto::ByteSendThread( JABBER_BYTE_TRANSFER *jbt ) -{ - char* localAddr = NULL; - DBVARIANT dbv; - TCHAR szPort[8]; - HANDLE hEvent = NULL; - TCHAR* proxyJid; - CJabberIqInfo* pInfo = NULL; - int nIqId = 0; - - Log( "Thread started: type=bytestream_send" ); - - BOOL bDirect = m_options.BsDirect; - - if ( m_options.BsProxyManual ) { - proxyJid = NULL; - if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsProxyServer", &dbv )) { - proxyJid = mir_a2t( dbv.pszVal ); - JFreeVariant( &dbv ); - } - - if ( proxyJid ) { - jbt->bProxyDiscovered = FALSE; - jbt->szProxyHost = NULL; - jbt->szProxyPort = NULL; - jbt->szProxyJid = NULL; - jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - - pInfo = m_iqManager.AddHandler( &CJabberProto::IqResultProxyDiscovery, JABBER_IQ_TYPE_GET, proxyJid, 0, -1, jbt ); - nIqId = pInfo->GetIqId(); - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)); - m_ThreadInfo->send( iq ); - - WaitForSingleObject( jbt->hProxyEvent, INFINITE ); - m_iqManager.ExpireIq ( nIqId ); - CloseHandle( jbt->hProxyEvent ); - jbt->hProxyEvent = NULL; - - mir_free( proxyJid ); - - if ( jbt->state == JBT_ERROR && !bDirect ) { - Log( "Bytestream proxy failure" ); - MsgPopup( pInfo->GetHContact(), TranslateT("Bytestream Proxy not available"), pInfo->GetReceiver()); - jbt->ft->state = FT_DENIED; - (this->*jbt->pfnFinal)( FALSE, jbt->ft ); - jbt->ft = NULL; - delete jbt; - return; - } - } } - - pInfo = m_iqManager.AddHandler( &CJabberProto::ByteInitiateResult, JABBER_IQ_TYPE_SET, jbt->dstJID, 0, -1, jbt ); - nIqId = pInfo->GetIqId(); - { - XmlNodeIq iq( pInfo ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) << XATTR( _T("sid"), jbt->sid ); - - if ( bDirect ) { - if ( m_options.BsDirectManual ) { - if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsDirectAddr", &dbv )) - localAddr = dbv.pszVal; - } - - NETLIBBIND nlb = {0}; - nlb.cbSize = sizeof( NETLIBBIND ); - nlb.pfnNewConnectionV2 = JabberByteSendConnection; - nlb.pExtra = this; - nlb.wPort = 0; // Use user-specified incoming port ranges, if available - jbt->hConn = ( HANDLE ) CallService( MS_NETLIB_BINDPORT, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nlb ); - if ( jbt->hConn == NULL ) { - Log( "Cannot allocate port for bytestream_send thread, thread ended." ); - delete jbt; - return; - } - - if ( localAddr == NULL ) - localAddr = (char*)CallService( MS_NETLIB_ADDRESSTOSTRING, 1, nlb.dwExternalIP ); - - mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort ); - JABBER_LIST_ITEM *item = ListAdd( LIST_BYTE, szPort ); - item->jbt = jbt; - hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - jbt->hEvent = hEvent; - jbt->hSendEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(localAddr)) << XATTRI( _T("port"), nlb.wPort ); - - NETLIBIPLIST* ihaddr = ( NETLIBIPLIST* )CallService( MS_NETLIB_GETMYIP, 1, 0 ); - for ( unsigned i = 0; i < ihaddr->cbNum; ++i ) - if ( strcmp( localAddr, ihaddr->szIp[i] )) - query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(ihaddr->szIp[i])) << XATTRI( _T("port"), nlb.wPort ); - - mir_free( ihaddr ); - mir_free( localAddr ); - } - - if ( jbt->bProxyDiscovered ) - query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), jbt->szProxyJid ) << XATTR( _T("host"), jbt->szProxyHost ) << XATTR( _T("port"), jbt->szProxyPort ); - - jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - jbt->szStreamhostUsed = NULL; - - m_ThreadInfo->send( iq ); - } - - WaitForSingleObject( jbt->hProxyEvent, INFINITE ); - m_iqManager.ExpireIq( nIqId ); - CloseHandle( jbt->hProxyEvent ); - jbt->hProxyEvent = NULL; - - if ( !jbt->szStreamhostUsed ) { - if ( bDirect ) { - SetEvent( jbt->hSendEvent ); - CloseHandle( jbt->hSendEvent ); - CloseHandle( hEvent ); - jbt->hEvent = NULL; - if ( jbt->hConn != NULL ) - Netlib_CloseHandle( jbt->hConn ); - jbt->hConn = NULL; - ListRemove( LIST_BYTE, szPort ); - } - (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); - jbt->ft = NULL; - // stupid fix: wait for listening thread exit - Sleep( 100 ); - delete jbt; - return; - } - - if ( jbt->bProxyDiscovered && !_tcscmp( jbt->szProxyJid, jbt->szStreamhostUsed )) { - // jabber proxy used - if ( bDirect ) { - SetEvent( jbt->hSendEvent ); - CloseHandle( jbt->hSendEvent ); - CloseHandle( hEvent ); - jbt->hEvent = NULL; - if ( jbt->hConn != NULL ) - Netlib_CloseHandle( jbt->hConn ); - jbt->hConn = NULL; - ListRemove( LIST_BYTE, szPort ); - } - ByteSendViaProxy( jbt ); - } - else { - SetEvent( jbt->hSendEvent ); - WaitForSingleObject( hEvent, INFINITE ); - CloseHandle( hEvent ); - CloseHandle( jbt->hSendEvent ); - jbt->hEvent = NULL; - (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); - jbt->ft = NULL; - if ( jbt->hConn != NULL ) - Netlib_CloseHandle( jbt->hConn ); - jbt->hConn = NULL; - ListRemove( LIST_BYTE, szPort ); - } - - // stupid fix: wait for listening connection thread exit - Sleep( 100 ); - delete jbt; - Log( "Thread ended: type=bytestream_send" ); -} - -void CJabberProto::ByteInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ) -{ - JABBER_BYTE_TRANSFER *jbt = ( JABBER_BYTE_TRANSFER * )pInfo->GetUserData(); - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode ) { - const TCHAR* queryXmlns = xmlGetAttrValue( queryNode, _T("xmlns")); - if ( queryXmlns && !_tcscmp( queryXmlns, _T( JABBER_FEAT_BYTESTREAMS ))) { - HXML streamHostNode = xmlGetChild( queryNode , "streamhost-used" ); - if ( streamHostNode ) { - const TCHAR* streamJid = xmlGetAttrValue( streamHostNode, _T("jid")); - if ( streamJid ) - jbt->szStreamhostUsed = mir_tstrdup( streamJid ); - } } } } - - if ( jbt->hProxyEvent ) - SetEvent( jbt->hProxyEvent ); -} - -int CJabberProto::ByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) -{ - int nMethods; - BYTE data[10]; - int i; - char* str; - - switch ( jbt->state ) { - case JBT_INIT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 nmethods - // 02-xx list of methods ( nmethods bytes ) - // send: - // 00-00 ver ( 0x05 ) - // 01-01 select method ( 0=no auth required ) - if ( datalen>=2 && buffer[0]==5 && buffer[1]+2==datalen ) { - nMethods = buffer[1]; - for ( i=0; istate = JBT_CONNECT; - } - else { - data[1] = 0xff; - jbt->state = JBT_ERROR; - } - data[0] = 5; - Netlib_Send( hConn, ( char* )data, 2, 0 ); - } - else jbt->state = JBT_ERROR; - break; - - case JBT_CONNECT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 cmd ( 1=connect ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 3 ) - // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) - // 45-46 dst.port ( 0 ) - // send: - // 00-00 ver ( 0x05 ) - // 01-01 reply ( 0=success,2=not allowed ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 1=IPv4 address ) - // 04-07 bnd.addr server bound address - // 08-09 bnd.port server bound port - if ( datalen == 47 && *(( DWORD* )buffer )==0x03000105 && buffer[4]==40 && *(( WORD* )( buffer+45 ))==0 ) { - TCHAR text[256]; - - TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); - TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); - mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); - mir_free(szInitiatorJid); - mir_free(szTargetJid); - - char* szAuthString = mir_utf8encodeT( text ); - Log( "Auth: '%s'", szAuthString ); - if (( str = JabberSha1( szAuthString )) != NULL ) { - for ( i=0; i<40 && buffer[i+5]==str[i]; i++ ); - mir_free( str ); - - ZeroMemory( data, 10 ); - data[1] = ( i>=20 )?0:2; - data[0] = 5; - data[3] = 1; - Netlib_Send( hConn, ( char* )data, 10, 0 ); - - // wait stream activation - WaitForSingleObject( jbt->hSendEvent, INFINITE ); - - if ( jbt->state == JBT_ERROR ) - break; - - if ( i>=20 && (this->*jbt->pfnSend)( hConn, jbt->ft )==TRUE ) - jbt->state = JBT_DONE; - else - jbt->state = JBT_ERROR; - } - mir_free( szAuthString ); - } - else - jbt->state = JBT_ERROR; - break; - } - - return datalen; -} - -///////////////// Bytestream receiving ///////////////////////// - -void CJabberProto::IqResultStreamActivate( HXML iqNode ) -{ - int id = JabberGetPacketID( iqNode ); - - TCHAR listJid[JABBER_MAX_JID_LEN]; - mir_sntprintf(listJid, SIZEOF( listJid ), _T("ftproxy_%d"), id); - - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTIQID, listJid ); - if ( !item ) - return; - - if ( !lstrcmp( xmlGetAttrValue( iqNode, _T("type")), _T( "result" ))) - item->jbt->bStreamActivated = TRUE; - - if ( item->jbt->hProxyEvent ) - SetEvent( item->jbt->hProxyEvent ); -} - - -void CJabberProto::ByteSendViaProxy( JABBER_BYTE_TRANSFER *jbt ) -{ - TCHAR *szHost, *szPort; - WORD port; - HANDLE hConn; - char data[3]; - char* buffer; - int datalen, bytesParsed, recvResult; - BOOL validStreamhost; - - if ( jbt == NULL ) return; - if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { - m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 406 ) << XATTR( _T("type"), _T("auth")) - << XCHILDNS( _T("not-acceptable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - return; - } - - jbt->state = JBT_INIT; - validStreamhost = FALSE; - szPort = jbt->szProxyPort; - szHost = jbt->szProxyHost; - - port = ( WORD )_ttoi( szPort ); - if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); - jbt->streamhostJID = mir_tstrdup( jbt->szProxyJid ); - - NETLIBOPENCONNECTION nloc = { 0 }; - nloc.cbSize = sizeof( nloc ); - nloc.szHost = mir_t2a(szHost); - nloc.wPort = port; - hConn = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); - mir_free((void*)nloc.szHost); - - if ( hConn != NULL ) { - jbt->hConn = hConn; - - data[0] = 5; - data[1] = 1; - data[2] = 0; - Netlib_Send( hConn, data, 3, 0 ); - - jbt->state = JBT_INIT; - datalen = 0; - while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { - recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); - if ( recvResult <= 0 ) - break; - - datalen += recvResult; - bytesParsed = ByteSendProxyParse( hConn, jbt, buffer, datalen ); - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - if ( jbt->state == JBT_DONE ) validStreamhost = TRUE; - } - Netlib_CloseHandle( hConn ); - } - mir_free( buffer ); - (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); - jbt->ft = NULL; - if ( !validStreamhost ) - m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); -} - -int CJabberProto::ByteSendProxyParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) -{ - int num = datalen; - - switch ( jbt->state ) { - case JBT_INIT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 selected method ( 0=no auth, 0xff=error ) - // send: - // 00-00 ver ( 0x05 ) - // 01-01 cmd ( 1=connect ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 3 ) - // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) - // 45-46 dst.port ( 0 ) - if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { - BYTE data[47]; - ZeroMemory( data, sizeof( data )); - *(( DWORD* )data ) = 0x03000105; - data[4] = 40; - - TCHAR text[256]; - - TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); - TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); - mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); - mir_free(szInitiatorJid); - mir_free(szTargetJid); - - char* szAuthString = mir_utf8encodeT( text ); - Log( "Auth: '%s'", szAuthString ); - char* szHash = JabberSha1( szAuthString ); - strncpy(( char* )( data+5 ), szHash, 40 ); - mir_free( szHash ); - Netlib_Send( hConn, ( char* )data, 47, 0 ); - jbt->state = JBT_CONNECT; - mir_free( szAuthString ); - } - else jbt->state = JBT_SOCKSERR; - break; - - case JBT_CONNECT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 reply ( 0=success,2=not allowed ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 1=IPv4 address,3=host address ) - // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) - // nn-nn+1 bnd.port server bound port - if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { - if ( buffer[3]==1 && datalen>=10 ) - num = 10; - else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) - num = buffer[4] + 7; - else if ( buffer[3]==0 && datalen>=6 ) - num = 6; - else { - jbt->state = JBT_SOCKSERR; - break; - } - jbt->state = JBT_SENDING; - - jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - jbt->bStreamActivated = FALSE; - - int iqId = SerialNext(); - - TCHAR listJid[256]; - mir_sntprintf(listJid, SIZEOF( listJid ), _T("ftproxy_%d"), iqId); - - JABBER_LIST_ITEM *item = ListAdd( LIST_FTIQID, listJid ); - item->jbt = jbt; - - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::IqResultStreamActivate ); - m_ThreadInfo->send( - XmlNodeIq( _T("set"), iqId, jbt->streamhostJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) - << XATTR( _T("sid"), jbt->sid ) << XCHILD( _T("activate"), jbt->dstJID )); - - WaitForSingleObject( jbt->hProxyEvent, INFINITE ); - - CloseHandle( jbt->hProxyEvent ); - jbt->hProxyEvent = NULL; - - ListRemove( LIST_FTIQID, listJid ); - - if ( jbt->bStreamActivated) - jbt->state = (this->*jbt->pfnSend)( hConn, jbt->ft ) ? JBT_DONE : JBT_ERROR; - else - jbt->state = JBT_ERROR; - } - else jbt->state = JBT_SOCKSERR; - break; - } - - return num; -} - - -void __cdecl CJabberProto::ByteReceiveThread( JABBER_BYTE_TRANSFER *jbt ) -{ - HXML iqNode, queryNode = NULL, n; - const TCHAR *sid = NULL, *from = NULL, *to = NULL, *szId = NULL, *szHost, *szPort, *str; - int i; - WORD port; - HANDLE hConn; - char data[3]; - char* buffer; - int datalen, bytesParsed, recvResult; - BOOL validStreamhost = FALSE; - - if ( jbt == NULL ) return; - - jbt->state = JBT_INIT; - - if ( iqNode = jbt->iqNode ) { - from = xmlGetAttrValue( iqNode, _T("from")); - to = xmlGetAttrValue( iqNode, _T("to")); - szId = xmlGetAttrValue( iqNode, _T("id")); - - queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode ) - sid = xmlGetAttrValue( queryNode, _T("sid")); - } - - if ( szId && from && to && sid && ( n = xmlGetChild( queryNode , "streamhost" ))!=NULL ) { - jbt->iqId = mir_tstrdup( szId ); - jbt->srcJID = mir_tstrdup( from ); - jbt->dstJID = mir_tstrdup( to ); - jbt->sid = mir_tstrdup( sid ); - - if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE ))) { - for ( i=1; ( n = xmlGetNthChild( queryNode, _T("streamhost"), i ))!=NULL; i++ ) { - if (( szHost = xmlGetAttrValue( n, _T("host"))) != NULL && - ( szPort = xmlGetAttrValue( n, _T("port"))) != NULL && - ( str = xmlGetAttrValue( n, _T("jid"))) != NULL ) { - - port = ( WORD )_ttoi( szPort ); - if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); - jbt->streamhostJID = mir_tstrdup( str ); - - Log( "bytestream_recv connecting to " TCHAR_STR_PARAM ":%d", szHost, port ); - NETLIBOPENCONNECTION nloc = { 0 }; - nloc.cbSize = sizeof( nloc ); - nloc.szHost = mir_t2a(szHost); - nloc.wPort = port; - hConn = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); - mir_free((void*)nloc.szHost); - - if ( hConn == NULL ) { - Log( "bytestream_recv_connection connection failed ( %d ), try next streamhost", WSAGetLastError()); - continue; - } - - jbt->hConn = hConn; - - data[0] = 5; - data[1] = 1; - data[2] = 0; - Netlib_Send( hConn, data, 3, 0 ); - - jbt->state = JBT_INIT; - datalen = 0; - while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { - recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); - if ( recvResult <= 0 ) break; - datalen += recvResult; - bytesParsed = ByteReceiveParse( hConn, jbt, buffer, datalen ); - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - if ( jbt->state == JBT_RECVING ) validStreamhost = TRUE; - } - Netlib_CloseHandle( hConn ); - Log( "bytestream_recv_connection closing connection" ); - } - if ( jbt->state==JBT_ERROR || validStreamhost==TRUE ) - break; - Log( "bytestream_recv_connection stream cannot be established, try next streamhost" ); - } - mir_free( buffer ); - } - } - - (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); - jbt->ft = NULL; - if ( !validStreamhost && szId && from ) { - Log( "bytestream_recv_connection session not completed" ); - - m_ThreadInfo->send( XmlNodeIq( _T("error"), szId, from ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - } - - delete jbt; - Log( "Thread ended: type=bytestream_recv" ); -} - -int CJabberProto::ByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) -{ - int bytesReceived, num = datalen; - - switch ( jbt->state ) { - case JBT_INIT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 selected method ( 0=no auth, 0xff=error ) - // send: - // 00-00 ver ( 0x05 ) - // 01-01 cmd ( 1=connect ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 3 ) - // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) - // 45-46 dst.port ( 0 ) - if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { - BYTE data[47]; - ZeroMemory( data, sizeof( data )); - *(( DWORD* )data ) = 0x03000105; - data[4] = 40; - - TCHAR text[JABBER_MAX_JID_LEN*2]; - TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); - TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); - mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); - mir_free(szInitiatorJid); - mir_free(szTargetJid); - char* szAuthString = mir_utf8encodeT( text ); - Log( "Auth: '%s'", szAuthString ); - char* szHash = JabberSha1( szAuthString ); - strncpy(( char* )( data+5 ), szHash, 40 ); - mir_free( szHash ); - Netlib_Send( hConn, ( char* )data, 47, 0 ); - jbt->state = JBT_CONNECT; - mir_free( szAuthString ); - } - else jbt->state = JBT_SOCKSERR; - break; - - case JBT_CONNECT: - // received: - // 00-00 ver ( 0x05 ) - // 01-01 reply ( 0=success,2=not allowed ) - // 02-02 reserved ( 0 ) - // 03-03 address type ( 1=IPv4 address,3=host address ) - // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) - // nn-nn+1 bnd.port server bound port - if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { - if ( buffer[3]==1 && datalen>=10 ) - num = 10; - else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) - num = buffer[4] + 7; - else if ( buffer[3]==0 && datalen>=6 ) - num = 6; - else { - jbt->state = JBT_SOCKSERR; - break; - } - jbt->state = JBT_RECVING; - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), jbt->iqId, jbt->srcJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) - << XCHILD( _T("streamhost-used")) << XATTR( _T("jid"), jbt->streamhostJID )); - } - else jbt->state = JBT_SOCKSERR; - break; - - case JBT_RECVING: - bytesReceived = (this->*jbt->pfnRecv)( hConn, jbt->ft, buffer, datalen ); - if ( bytesReceived < 0 ) - jbt->state = JBT_ERROR; - else if ( bytesReceived == 0 ) - jbt->state = JBT_DONE; - break; - } - - return num; -} diff --git a/protocols/JabberG/jabber_byte.h b/protocols/JabberG/jabber_byte.h deleted file mode 100644 index 657d797fce..0000000000 --- a/protocols/JabberG/jabber_byte.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_BYTE_H_ -#define _JABBER_BYTE_H_ - -typedef enum { JBT_INIT, JBT_AUTH, JBT_CONNECT, JBT_SOCKSERR, JBT_SENDING, JBT_RECVING, JBT_DONE, JBT_ERROR } JABBER_BYTE_STATE; - -struct CJabberProto; -struct filetransfer; - -struct JABBER_BYTE_TRANSFER -{ - ~JABBER_BYTE_TRANSFER(); - - TCHAR* sid; - TCHAR* srcJID; - TCHAR* dstJID; - TCHAR* streamhostJID; - TCHAR* iqId; - JABBER_BYTE_STATE state; - HANDLE hConn; - HANDLE hEvent; - HXML iqNode; - BOOL ( CJabberProto::*pfnSend )( HANDLE hConn, filetransfer* ft ); - int ( CJabberProto::*pfnRecv )( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); - void ( CJabberProto::*pfnFinal )( BOOL success, filetransfer* ft ); - filetransfer* ft; - - // XEP-0065 proxy support - BOOL bProxyDiscovered; - HANDLE hProxyEvent; - TCHAR* szProxyHost; - TCHAR* szProxyPort; - TCHAR* szProxyJid; - TCHAR* szStreamhostUsed; - BOOL bStreamActivated; - HANDLE hSendEvent; -}; - -#endif diff --git a/protocols/JabberG/jabber_caps.cpp b/protocols/JabberG/jabber_caps.cpp deleted file mode 100644 index 380cf03087..0000000000 --- a/protocols/JabberG/jabber_caps.cpp +++ /dev/null @@ -1,697 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "version.h" - -const JabberFeatCapPair g_JabberFeatCapPairs[] = { - { _T(JABBER_FEAT_DISCO_INFO), JABBER_CAPS_DISCO_INFO, _T("Supports Service Discovery info"), }, - { _T(JABBER_FEAT_DISCO_ITEMS), JABBER_CAPS_DISCO_ITEMS, _T("Supports Service Discovery items list"), }, - { _T(JABBER_FEAT_ENTITY_CAPS), JABBER_CAPS_ENTITY_CAPS, _T("Can inform about its Jabber capabilities"), }, - { _T(JABBER_FEAT_SI), JABBER_CAPS_SI, _T("Supports stream initiation (for filetransfers for ex.)"), }, - { _T(JABBER_FEAT_SI_FT), JABBER_CAPS_SI_FT, _T("Supports stream initiation for file transfers"), }, - { _T(JABBER_FEAT_BYTESTREAMS), JABBER_CAPS_BYTESTREAMS, _T("Supports file transfers via SOCKS5 Bytestreams"), }, - { _T(JABBER_FEAT_IBB), JABBER_CAPS_IBB, _T("Supports file transfers via In-Band Bytestreams"), }, - { _T(JABBER_FEAT_OOB), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), }, - { _T(JABBER_FEAT_OOB2), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), }, - { _T(JABBER_FEAT_COMMANDS), JABBER_CAPS_COMMANDS, _T("Supports execution of Ad-Hoc commands"), }, - { _T(JABBER_FEAT_REGISTER), JABBER_CAPS_REGISTER, _T("Supports in-band registration"), }, - { _T(JABBER_FEAT_MUC), JABBER_CAPS_MUC, _T("Supports multi-user chat"), }, - { _T(JABBER_FEAT_CHATSTATES), JABBER_CAPS_CHATSTATES, _T("Can report chat state in a chat session"), }, - { _T(JABBER_FEAT_LAST_ACTIVITY), JABBER_CAPS_LAST_ACTIVITY, _T("Can report information about the last activity of the user"), }, - { _T(JABBER_FEAT_VERSION), JABBER_CAPS_VERSION, _T("Can report own version information"), }, - { _T(JABBER_FEAT_ENTITY_TIME), JABBER_CAPS_ENTITY_TIME, _T("Can report local time of the user"), }, - { _T(JABBER_FEAT_PING), JABBER_CAPS_PING, _T("Can send and receive ping requests"), }, - { _T(JABBER_FEAT_DATA_FORMS), JABBER_CAPS_DATA_FORMS, _T("Supports data forms"), }, - { _T(JABBER_FEAT_MESSAGE_EVENTS), JABBER_CAPS_MESSAGE_EVENTS, _T("Can request and respond to events relating to the delivery, display, and composition of messages"), }, - { _T(JABBER_FEAT_VCARD_TEMP), JABBER_CAPS_VCARD_TEMP, _T("Supports vCard"), }, - { _T(JABBER_FEAT_AVATAR), JABBER_CAPS_AVATAR, _T("Supports iq-based avatars"), }, - { _T(JABBER_FEAT_XHTML), JABBER_CAPS_XHTML, _T("Supports XHTML formatting of chat messages"), }, - { _T(JABBER_FEAT_AGENTS), JABBER_CAPS_AGENTS, _T("Supports Jabber Browsing"), }, - { _T(JABBER_FEAT_BROWSE), JABBER_CAPS_BROWSE, _T("Supports Jabber Browsing"), }, - { _T(JABBER_FEAT_FEATURE_NEG), JABBER_CAPS_FEATURE_NEG, _T("Can negotiate options for specific features"), }, - { _T(JABBER_FEAT_AMP), JABBER_CAPS_AMP, _T("Can request advanced processing of message stanzas"), }, - { _T(JABBER_FEAT_USER_MOOD), JABBER_CAPS_USER_MOOD, _T("Can report information about user moods"), }, - { _T(JABBER_FEAT_USER_MOOD_NOTIFY), JABBER_CAPS_USER_MOOD_NOTIFY, _T("Receives information about user moods"), }, - { _T(JABBER_FEAT_PUBSUB), JABBER_CAPS_PUBSUB, _T("Supports generic publish-subscribe functionality"), }, - { _T(JABBER_FEAT_SECUREIM), JABBER_CAPS_SECUREIM, _T("Supports SecureIM plugin for Miranda NG"), }, - { _T(JABBER_FEAT_PRIVACY_LISTS), JABBER_CAPS_PRIVACY_LISTS, _T("Can block communications from particular other users using Privacy lists"), }, - { _T(JABBER_FEAT_MESSAGE_RECEIPTS), JABBER_CAPS_MESSAGE_RECEIPTS, _T("Supports Message Receipts"), }, - { _T(JABBER_FEAT_USER_TUNE), JABBER_CAPS_USER_TUNE, _T("Can report information about the music to which a user is listening"), }, - { _T(JABBER_FEAT_USER_TUNE_NOTIFY), JABBER_CAPS_USER_TUNE_NOTIFY, _T("Receives information about the music to which a user is listening"), }, - { _T(JABBER_FEAT_PRIVATE_STORAGE), JABBER_CAPS_PRIVATE_STORAGE, _T("Supports private XML Storage (for bookmakrs and other)"), }, - { _T(JABBER_FEAT_ATTENTION), JABBER_CAPS_ATTENTION, _T("Supports attention requests ('nudge')"), }, - { _T(JABBER_FEAT_ATTENTION_0), JABBER_CAPS_ATTENTION_0, _T("Supports attention requests ('nudge')"), }, - { _T(JABBER_FEAT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY, _T("Can report information about user activity"), }, - { _T(JABBER_FEAT_USER_ACTIVITY_NOTIFY), JABBER_CAPS_USER_ACTIVITY_NOTIFY, _T("Receives information about user activity"), }, - { _T(JABBER_FEAT_MIRANDA_NOTES), JABBER_CAPS_MIRANDA_NOTES, _T("Supports Miranda NG notes extension"), }, - { _T(JABBER_FEAT_JINGLE), JABBER_CAPS_JINGLE, _T("Supports Jingle"), }, - { _T(JABBER_FEAT_ROSTER_EXCHANGE), JABBER_CAPS_ROSTER_EXCHANGE, _T("Supports Roster Exchange"), }, - { _T(JABBER_FEAT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC, _T("Supports GTalk private multi-user chat"), }, - { NULL, 0, NULL} -}; - -const JabberFeatCapPair g_JabberFeatCapPairsExt[] = { - { _T(JABBER_EXT_SECUREIM), JABBER_CAPS_SECUREIM }, - { _T(JABBER_EXT_COMMANDS), JABBER_CAPS_COMMANDS }, - { _T(JABBER_EXT_USER_MOOD), JABBER_CAPS_USER_MOOD_NOTIFY }, - { _T(JABBER_EXT_USER_TUNE), JABBER_CAPS_USER_TUNE_NOTIFY }, - { _T(JABBER_EXT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY_NOTIFY }, - { _T(JABBER_EXT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC }, - { _T(JABBER_EXT_MIR_NOTES), JABBER_CAPS_MIRANDA_NOTES, }, - { szCoreVersion, JABBER_CAPS_MIRANDA_PARTIAL }, - { NULL, 0 } -}; - -void CJabberProto::OnIqResultCapsDiscoInfoSI( HXML, CJabberIqInfo* pInfo ) -{ - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); - if ( !r ) - return; - - if ( r->szCapsNode == NULL ) - OnIqResultCapsDiscoInfo( NULL, pInfo ); - - HXML query = pInfo->GetChildNode(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && query ) { - // XEP-0232 support - HXML xform; - for ( int i = 1; ( xform = xmlGetNthChild( query, _T("x"), i)) != NULL; i++ ) { - TCHAR *szFormTypeValue = XPath( xform, _T("field[@var='FORM_TYPE']/value")); - if ( szFormTypeValue && !_tcscmp( szFormTypeValue, _T("urn:xmpp:dataforms:softwareinfo"))) { - if ( r->pSoftwareInfo ) - delete r->pSoftwareInfo; - r->pSoftwareInfo = new JABBER_XEP0232_SOFTWARE_INFO; - if ( r->pSoftwareInfo ) { - TCHAR *szTmp = XPath( xform, _T("field[@var='os']/value")); - if ( szTmp ) - r->pSoftwareInfo->szOs = mir_tstrdup( szTmp ); - szTmp = XPath( xform, _T("field[@var='os_version']/value")); - if ( szTmp ) - r->pSoftwareInfo->szOsVersion = mir_tstrdup( szTmp ); - szTmp = XPath( xform, _T("field[@var='software']/value")); - if ( szTmp ) - r->pSoftwareInfo->szSoftware = mir_tstrdup( szTmp ); - szTmp = XPath( xform, _T("field[@var='software_version']/value")); - if ( szTmp ) - r->pSoftwareInfo->szSoftwareVersion = mir_tstrdup( szTmp ); - szTmp = XPath( xform, _T("field[@var='x-miranda-core-version']/value")); - if ( szTmp ) - r->pSoftwareInfo->szXMirandaCoreVersion = mir_tstrdup( szTmp ); - szTmp = XPath( xform, _T("field[@var='x-miranda-core-is-unicode']/value")); - if ( !szTmp ) // old deprecated format - szTmp = XPath( xform, _T("field[@var='x-miranda-is-unicode']/value")); - if ( szTmp && _ttoi( szTmp )) - r->pSoftwareInfo->bXMirandaIsUnicode = TRUE; - szTmp = XPath( xform, _T("field[@var='x-miranda-core-is-alpha']/value")); - if ( !szTmp ) // old deprecated format - szTmp = XPath( xform, _T("field[@var='x-miranda-is-alpha']/value")); - if ( szTmp && _ttoi( szTmp )) - r->pSoftwareInfo->bXMirandaIsAlpha = TRUE; - szTmp = XPath( xform, _T("field[@var='x-miranda-jabber-is-debug']/value")); - if ( szTmp && _ttoi( szTmp )) - r->pSoftwareInfo->bXMirandaIsDebug = TRUE; - } - JabberUserInfoUpdate( pInfo->GetHContact()); - } - } - } -} - -void CJabberProto::OnIqResultCapsDiscoInfo( HXML, CJabberIqInfo* pInfo ) -{ - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); - - HXML query = pInfo->GetChildNode(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && query ) { - JabberCapsBits jcbCaps = 0; - HXML feature; - for ( int i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { - const TCHAR *featureName = xmlGetAttrValue( feature, _T("var")); - if ( featureName ) { - for ( int j = 0; g_JabberFeatCapPairs[j].szFeature; j++ ) { - if ( !_tcscmp( g_JabberFeatCapPairs[j].szFeature, featureName )) { - jcbCaps |= g_JabberFeatCapPairs[j].jcbCap; - break; - } } } } - - // no version info support and no XEP-0115 support? - if ( r && r->dwVersionRequestTime == -1 && !r->version && !r->software && !r->szCapsNode ) { - r->jcbCachedCaps = jcbCaps; - r->dwDiscoInfoRequestTime = -1; - return; - } - - if (!m_clientCapsManager.SetClientCaps( pInfo->GetIqId(), jcbCaps )) - if ( r ) - r->jcbCachedCaps = jcbCaps; - JabberUserInfoUpdate( pInfo->GetHContact()); - } - else { - // no version info support and no XEP-0115 support? - if ( r && r->dwVersionRequestTime == -1 && !r->version && !r->software && !r->szCapsNode ) { - r->jcbCachedCaps = JABBER_RESOURCE_CAPS_NONE; - r->dwDiscoInfoRequestTime = -1; - return; - } - m_clientCapsManager.SetClientCaps( pInfo->GetIqId(), JABBER_RESOURCE_CAPS_ERROR ); - } -} - -JabberCapsBits CJabberProto::GetTotalJidCapabilites( const TCHAR *jid ) -{ - if ( !jid ) - return JABBER_RESOURCE_CAPS_NONE; - - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( jid, szBareJid, SIZEOF( szBareJid )); - - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, szBareJid ); - if ( !item ) - item = ListGetItemPtr( LIST_VCARD_TEMP, szBareJid ); - - JabberCapsBits jcbToReturn = JABBER_RESOURCE_CAPS_NONE; - - // get bare jid info only if where is no resources - if ( !item || ( item && !item->resourceCount )) { - jcbToReturn = GetResourceCapabilites( szBareJid, FALSE ); - if ( jcbToReturn & JABBER_RESOURCE_CAPS_ERROR) - jcbToReturn = JABBER_RESOURCE_CAPS_NONE; - } - - if ( item ) { - for ( int i = 0; i < item->resourceCount; i++ ) { - TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; - mir_sntprintf( szFullJid, JABBER_MAX_JID_LEN, _T("%s/%s"), szBareJid, item->resource[i].resourceName ); - JabberCapsBits jcb = GetResourceCapabilites( szFullJid, FALSE ); - if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) - jcbToReturn |= jcb; - } - } - return jcbToReturn; -} - -JabberCapsBits CJabberProto::GetResourceCapabilites( const TCHAR *jid, BOOL appendBestResource ) -{ - TCHAR fullJid[ JABBER_MAX_JID_LEN ]; - if ( appendBestResource ) - GetClientJID( jid, fullJid, SIZEOF( fullJid )); - else - _tcsncpy( fullJid, jid, SIZEOF( fullJid )); - - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( fullJid ); - if ( r == NULL ) - return JABBER_RESOURCE_CAPS_ERROR; - - // XEP-0115 mode - if ( r->szCapsNode && r->szCapsVer ) { - JabberCapsBits jcbCaps = 0, jcbExtCaps = 0; - BOOL bRequestSent = FALSE; - JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps( r->szCapsNode, r->szCapsVer ); - - if ( jcbMainCaps == JABBER_RESOURCE_CAPS_TIMEOUT && !r->dwDiscoInfoRequestTime ) - jcbMainCaps = JABBER_RESOURCE_CAPS_ERROR; - - if ( jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT ) { - // send disco#info query - - CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); - pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); - m_clientCapsManager.SetClientCaps( r->szCapsNode, r->szCapsVer, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); - r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); - - TCHAR queryNode[512]; - mir_sntprintf( queryNode, SIZEOF(queryNode), _T("%s#%s"), r->szCapsNode, r->szCapsVer ); - m_ThreadInfo->send( XmlNodeIq( pInfo ) << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), queryNode )); - - bRequestSent = TRUE; - } - else if ( jcbMainCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS ) - bRequestSent = TRUE; - else if ( jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT ) - jcbCaps |= jcbMainCaps; - - if ( jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT && r->szCapsExt ) { - TCHAR *caps = mir_tstrdup( r->szCapsExt ); - - TCHAR *token = _tcstok( caps, _T(" ")); - while ( token ) { - switch ( jcbExtCaps = m_clientCapsManager.GetClientCaps( r->szCapsNode, token )) { - case JABBER_RESOURCE_CAPS_ERROR: - break; - - case JABBER_RESOURCE_CAPS_UNINIT: - { - // send disco#info query - - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); - pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); - m_clientCapsManager.SetClientCaps( r->szCapsNode, token, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); - - TCHAR queryNode[512]; - mir_sntprintf( queryNode, SIZEOF(queryNode), _T("%s#%s"), r->szCapsNode, token ); - m_ThreadInfo->send( - XmlNodeIq( pInfo ) << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), queryNode )); - - bRequestSent = TRUE; - break; - } - case JABBER_RESOURCE_CAPS_IN_PROGRESS: - bRequestSent = TRUE; - break; - - default: - jcbCaps |= jcbExtCaps; - } - - token = _tcstok( NULL, _T(" ")); - } - - mir_free(caps); - } - - if ( bRequestSent ) - return JABBER_RESOURCE_CAPS_IN_PROGRESS; - - return jcbCaps | r->jcbManualDiscoveredCaps; - } - - // capability mode (version request + service discovery) - - // no version info: - if ( !r->version && !r->software ) { - // version request not sent: - if ( !r->dwVersionRequestTime ) { - // send version query - - CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE ); - pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); - r->dwVersionRequestTime = pInfo->GetRequestTime(); - - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_VERSION)); - m_ThreadInfo->send( iq ); - return JABBER_RESOURCE_CAPS_IN_PROGRESS; - } - // version not received: - else if ( r->dwVersionRequestTime != -1 ) { - // no timeout? - if ( GetTickCount() - r->dwVersionRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) - return JABBER_RESOURCE_CAPS_IN_PROGRESS; - - // timeout - r->dwVersionRequestTime = -1; - } - // no version information, try direct service discovery - if ( !r->dwDiscoInfoRequestTime ) { - // send disco#info query - - CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); - pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); - r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); - - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); - m_ThreadInfo->send( iq ); - - return JABBER_RESOURCE_CAPS_IN_PROGRESS; - } - else if ( r->dwDiscoInfoRequestTime == -1 ) - return r->jcbCachedCaps | r->jcbManualDiscoveredCaps; - else if ( GetTickCount() - r->dwDiscoInfoRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) - return JABBER_RESOURCE_CAPS_IN_PROGRESS; - else - r->dwDiscoInfoRequestTime = -1; - // version request timeout: - return JABBER_RESOURCE_CAPS_NONE; - } - - // version info available: - if ( r->software && r->version ) { - JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps( r->software, r->version ); - if ( jcbMainCaps == JABBER_RESOURCE_CAPS_ERROR ) { - // Bombus hack: - if ( !_tcscmp( r->software, _T( "Bombus" )) || !_tcscmp( r->software, _T( "BombusMod" ))) { - jcbMainCaps = JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_IBB|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_VERSION|JABBER_CAPS_COMMANDS|JABBER_CAPS_VCARD_TEMP; - m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); - } - // Neos hack: - else if ( !_tcscmp( r->software, _T( "neos" ))) { - jcbMainCaps = JABBER_CAPS_OOB|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_VERSION; - m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); - } - // sim hack: - else if ( !_tcscmp( r->software, _T( "sim" ))) { - jcbMainCaps = JABBER_CAPS_OOB|JABBER_CAPS_VERSION|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY; - m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); - } } - - else if ( jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT ) { - // send disco#info query - - CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); - pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); - m_clientCapsManager.SetClientCaps( r->software, r->version, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); - r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); - - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); - m_ThreadInfo->send( iq ); - - jcbMainCaps = JABBER_RESOURCE_CAPS_IN_PROGRESS; - } - return jcbMainCaps | r->jcbManualDiscoveredCaps; - } - - return JABBER_RESOURCE_CAPS_NONE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CJabberClientPartialCaps class members - -CJabberClientPartialCaps::CJabberClientPartialCaps( const TCHAR *szVer ) -{ - m_szVer = mir_tstrdup( szVer ); - m_jcbCaps = JABBER_RESOURCE_CAPS_UNINIT; - m_pNext = NULL; - m_nIqId = -1; - m_dwRequestTime = 0; -} - -CJabberClientPartialCaps::~CJabberClientPartialCaps() -{ - mir_free( m_szVer ); - if ( m_pNext ) - delete m_pNext; -} - -CJabberClientPartialCaps* CJabberClientPartialCaps::SetNext( CJabberClientPartialCaps *pCaps ) -{ - CJabberClientPartialCaps *pRetVal = m_pNext; - m_pNext = pCaps; - return pRetVal; -} - -void CJabberClientPartialCaps::SetCaps( JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) -{ - if ( jcbCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS ) - m_dwRequestTime = GetTickCount(); - else - m_dwRequestTime = 0; - m_jcbCaps = jcbCaps; - m_nIqId = nIqId; -} - -JabberCapsBits CJabberClientPartialCaps::GetCaps() -{ - if ( m_jcbCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS && GetTickCount() - m_dwRequestTime > JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) { - m_jcbCaps = JABBER_RESOURCE_CAPS_TIMEOUT; - m_dwRequestTime = 0; - } - return m_jcbCaps; -} - -CJabberClientPartialCaps* CJabberClientCaps::FindByVersion( const TCHAR *szVer ) -{ - if ( !m_pCaps || !szVer ) - return NULL; - - CJabberClientPartialCaps *pCaps = m_pCaps; - while ( pCaps ) { - if ( !_tcscmp( szVer, pCaps->GetVersion())) - break; - pCaps = pCaps->GetNext(); - } - return pCaps; -} - -CJabberClientPartialCaps* CJabberClientCaps::FindById( int nIqId ) -{ - if ( !m_pCaps || nIqId == -1 ) - return NULL; - - CJabberClientPartialCaps *pCaps = m_pCaps; - while ( pCaps ) { - if ( pCaps->GetIqId() == nIqId ) - break; - pCaps = pCaps->GetNext(); - } - return pCaps; -} - -CJabberClientCaps::CJabberClientCaps( const TCHAR *szNode ) -{ - m_szNode = mir_tstrdup( szNode ); - m_pCaps = NULL; - m_pNext= NULL; -} - -CJabberClientCaps::~CJabberClientCaps() { - mir_free( m_szNode ); - if ( m_pCaps ) - delete m_pCaps; - if ( m_pNext ) - delete m_pNext; -} - -CJabberClientCaps* CJabberClientCaps::SetNext( CJabberClientCaps *pClient ) -{ - CJabberClientCaps *pRetVal = m_pNext; - m_pNext = pClient; - return pRetVal; -} - -JabberCapsBits CJabberClientCaps::GetPartialCaps( TCHAR *szVer ) { - CJabberClientPartialCaps *pCaps = FindByVersion( szVer ); - if ( !pCaps ) - return JABBER_RESOURCE_CAPS_UNINIT; - return pCaps->GetCaps(); -} - -BOOL CJabberClientCaps::SetPartialCaps( const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) { - CJabberClientPartialCaps *pCaps = FindByVersion( szVer ); - if ( !pCaps ) { - pCaps = new CJabberClientPartialCaps( szVer ); - if ( !pCaps ) - return FALSE; - pCaps->SetNext( m_pCaps ); - m_pCaps = pCaps; - } - if ( !(jcbCaps & JABBER_RESOURCE_CAPS_ERROR) && m_szNode && szVer ) { - if ( !_tcscmp( m_szNode, _T( "http://miranda-im.org/caps" )) && !_tcscmp( szVer, _T( "0.7.0.13" ))) - jcbCaps = jcbCaps & ( ~JABBER_CAPS_MESSAGE_RECEIPTS ); - } - pCaps->SetCaps( jcbCaps, nIqId ); - return TRUE; -} - -BOOL CJabberClientCaps::SetPartialCaps( int nIqId, JabberCapsBits jcbCaps ) { - CJabberClientPartialCaps *pCaps = FindById( nIqId ); - if ( !pCaps ) - return FALSE; - if ( !(jcbCaps & JABBER_RESOURCE_CAPS_ERROR) && m_szNode && pCaps->GetVersion()) { - if ( !_tcscmp( m_szNode, _T( "http://miranda-im.org/caps" )) && !_tcscmp( pCaps->GetVersion(), _T( "0.7.0.13" ))) - jcbCaps = jcbCaps & ( ~JABBER_CAPS_MESSAGE_RECEIPTS ); - } - pCaps->SetCaps( jcbCaps, -1 ); - return TRUE; -} - -CJabberClientCapsManager::CJabberClientCapsManager( CJabberProto* proto ) -{ - ppro = proto; - InitializeCriticalSection( &m_cs ); - m_pClients = NULL; -} - -CJabberClientCapsManager::~CJabberClientCapsManager() -{ - if ( m_pClients ) - delete m_pClients; - DeleteCriticalSection( &m_cs ); -} - -CJabberClientCaps * CJabberClientCapsManager::FindClient( const TCHAR *szNode ) -{ - if ( !m_pClients || !szNode ) - return NULL; - - CJabberClientCaps *pClient = m_pClients; - while ( pClient ) { - if ( !_tcscmp( szNode, pClient->GetNode())) - break; - pClient = pClient->GetNext(); - } - return pClient; -} - -void CJabberClientCapsManager::AddDefaultCaps() { - SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), szCoreVersion, JABBER_CAPS_MIRANDA_ALL ); - - for ( int i = 0; g_JabberFeatCapPairsExt[i].szFeature; i++ ) - SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), g_JabberFeatCapPairsExt[i].szFeature, g_JabberFeatCapPairsExt[i].jcbCap ); -} - -JabberCapsBits CJabberClientCapsManager::GetClientCaps( TCHAR *szNode, TCHAR *szVer ) -{ - Lock(); - CJabberClientCaps *pClient = FindClient( szNode ); - if ( !pClient ) { - Unlock(); - ppro->Log( "CAPS: get no caps for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, szNode, szVer ); - return JABBER_RESOURCE_CAPS_UNINIT; - } - JabberCapsBits jcbCaps = pClient->GetPartialCaps( szVer ); - Unlock(); - ppro->Log( "CAPS: get caps %I64x for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, jcbCaps, szNode, szVer ); - return jcbCaps; -} - -BOOL CJabberClientCapsManager::SetClientCaps( const TCHAR *szNode, const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) -{ - Lock(); - CJabberClientCaps *pClient = FindClient( szNode ); - if (!pClient) { - pClient = new CJabberClientCaps( szNode ); - if ( !pClient ) { - Unlock(); - return FALSE; - } - pClient->SetNext( m_pClients ); - m_pClients = pClient; - } - BOOL bOk = pClient->SetPartialCaps( szVer, jcbCaps, nIqId ); - Unlock(); - ppro->Log( "CAPS: set caps %I64x for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, jcbCaps, szNode, szVer ); - return bOk; -} - -BOOL CJabberClientCapsManager::SetClientCaps( int nIqId, JabberCapsBits jcbCaps ) -{ - Lock(); - if ( !m_pClients ) { - Unlock(); - return FALSE; - } - BOOL bOk = FALSE; - CJabberClientCaps *pClient = m_pClients; - while ( pClient ) { - if ( pClient->SetPartialCaps( nIqId, jcbCaps )) { - ppro->Log( "CAPS: set caps %I64x for iq %d", jcbCaps, nIqId ); - bOk = TRUE; - break; - } - pClient = pClient->GetNext(); - } - Unlock(); - return bOk; -} - -BOOL CJabberClientCapsManager::HandleInfoRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) -{ - int i; - JabberCapsBits jcb = 0; - - if ( szNode ) { - for ( i = 0; g_JabberFeatCapPairsExt[i].szFeature; i++ ) { - TCHAR szExtCap[ 512 ]; - mir_sntprintf( szExtCap, SIZEOF(szExtCap), _T("%s#%s"), _T(JABBER_CAPS_MIRANDA_NODE), g_JabberFeatCapPairsExt[i].szFeature ); - if ( !_tcscmp( szNode, szExtCap )) { - jcb = g_JabberFeatCapPairsExt[i].jcbCap; - break; - } - } - - // check features registered through IJabberNetInterface::RegisterFeature() and IJabberNetInterface::AddFeatures() - for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { - TCHAR szExtCap[ 512 ]; - mir_sntprintf( szExtCap, SIZEOF(szExtCap), _T("%s#%s"), _T(JABBER_CAPS_MIRANDA_NODE), ppro->m_lstJabberFeatCapPairsDynamic[i]->szExt ); - if ( !_tcscmp( szNode, szExtCap )) { - jcb = ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; - break; - } - } - - // unknown node, not XEP-0115 request - if ( !jcb ) - return FALSE; - } - else { - jcb = JABBER_CAPS_MIRANDA_ALL; - for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) - jcb |= ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; - } - - if (!ppro->m_options.AllowVersionRequests) - jcb &= ~JABBER_CAPS_VERSION; - - XmlNodeIq iq( _T("result"), pInfo ); - - HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); - if ( szNode ) - query << XATTR( _T("node"), szNode ); - - query << XCHILD( _T("identity")) << XATTR( _T("category"), _T("client")) - << XATTR( _T("type"), _T("pc")) << XATTR( _T("name"), _T("Miranda")); - - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) - if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) - query << XCHILD( _T("feature")) << XATTR( _T("var"), g_JabberFeatCapPairs[i].szFeature ); - - for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) - if ( jcb & ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) - query << XCHILD( _T("feature")) << XATTR( _T("var"), ppro->m_lstJabberFeatCapPairsDynamic[i]->szFeature ); - - if ( ppro->m_options.AllowVersionRequests && !szNode ) { - TCHAR szOsBuffer[256] = {0}; - TCHAR *os = szOsBuffer; - - if ( ppro->m_options.ShowOSVersion ) { - if (!GetOSDisplayString(szOsBuffer, SIZEOF(szOsBuffer))) - lstrcpyn(szOsBuffer, _T(""), SIZEOF(szOsBuffer)); - else { - TCHAR *szOsWindows = _T("Microsoft Windows"); - size_t nOsWindowsLength = _tcslen( szOsWindows ); - if (!_tcsnicmp(szOsBuffer, szOsWindows, nOsWindowsLength)) - os += nOsWindowsLength + 1; - } - } - - HXML form = query << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("result")); - form << XCHILD( _T("field")) << XATTR( _T("var"), _T("FORM_TYPE")) << XATTR( _T("type"), _T("hidden")) - << XCHILD( _T("value"), _T("urn:xmpp:dataforms:softwareinfo")); - - if ( ppro->m_options.ShowOSVersion ) { - form << XCHILD( _T("field")) << XATTR( _T("var"), _T("os")) << XCHILD( _T("value"), _T("Microsoft Windows")); - form << XCHILD( _T("field")) << XATTR( _T("var"), _T("os_version")) << XCHILD( _T("value"), os ); - } - form << XCHILD( _T("field")) << XATTR( _T("var"), _T("software")) << XCHILD( _T("value"), _T("Miranda NG Jabber Protocol")); - form << XCHILD( _T("field")) << XATTR( _T("var"), _T("software_version")) << XCHILD( _T("value"), szCoreVersion); - } - - ppro->m_ThreadInfo->send( iq ); - - return TRUE; -} diff --git a/protocols/JabberG/jabber_caps.h b/protocols/JabberG/jabber_caps.h deleted file mode 100644 index e0525f2a16..0000000000 --- a/protocols/JabberG/jabber_caps.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_CAPS_H_ -#define _JABBER_CAPS_H_ - -#include "jabber_iq.h" - -typedef unsigned __int64 JabberCapsBits; - -#define JABBER_RESOURCE_CAPS_QUERY_TIMEOUT 10000 - -#ifdef __GNUC__ -#define JABBER_RESOURCE_CAPS_ERROR 0x8000000000000000ULL -#define JABBER_RESOURCE_CAPS_IN_PROGRESS 0x8000000000000001ULL -#define JABBER_RESOURCE_CAPS_TIMEOUT 0x8000000000000002ULL -#define JABBER_RESOURCE_CAPS_UNINIT 0x8000000000000003ULL -#define JABBER_RESOURCE_CAPS_NONE 0x0000000000000000ULL -#else -#define JABBER_RESOURCE_CAPS_ERROR 0x8000000000000000 -#define JABBER_RESOURCE_CAPS_IN_PROGRESS 0x8000000000000001 -#define JABBER_RESOURCE_CAPS_TIMEOUT 0x8000000000000002 -#define JABBER_RESOURCE_CAPS_UNINIT 0x8000000000000003 -#define JABBER_RESOURCE_CAPS_NONE 0x0000000000000000 -#endif - -#define JABBER_FEAT_DISCO_INFO "http://jabber.org/protocol/disco#info" -#define JABBER_CAPS_DISCO_INFO ((JabberCapsBits)1) -#define JABBER_FEAT_DISCO_ITEMS "http://jabber.org/protocol/disco#items" -#define JABBER_CAPS_DISCO_ITEMS ((JabberCapsBits)1<<1) -#define JABBER_FEAT_ENTITY_CAPS "http://jabber.org/protocol/caps" -#define JABBER_CAPS_ENTITY_CAPS ((JabberCapsBits)1<<2) -#define JABBER_FEAT_SI "http://jabber.org/protocol/si" -#define JABBER_CAPS_SI ((JabberCapsBits)1<<3) -#define JABBER_FEAT_SI_FT "http://jabber.org/protocol/si/profile/file-transfer" -#define JABBER_CAPS_SI_FT ((JabberCapsBits)1<<4) -#define JABBER_FEAT_BYTESTREAMS "http://jabber.org/protocol/bytestreams" -#define JABBER_CAPS_BYTESTREAMS ((JabberCapsBits)1<<5) -#define JABBER_FEAT_IBB "http://jabber.org/protocol/ibb" -#define JABBER_CAPS_IBB ((JabberCapsBits)1<<6) -#define JABBER_FEAT_OOB "jabber:iq:oob" -#define JABBER_FEAT_OOB2 "jabber:x:oob" -#define JABBER_CAPS_OOB ((JabberCapsBits)1<<7) -#define JABBER_FEAT_COMMANDS "http://jabber.org/protocol/commands" -#define JABBER_CAPS_COMMANDS ((JabberCapsBits)1<<8) -#define JABBER_FEAT_REGISTER "jabber:iq:register" -#define JABBER_CAPS_REGISTER ((JabberCapsBits)1<<9) -#define JABBER_FEAT_MUC "http://jabber.org/protocol/muc" -#define JABBER_CAPS_MUC ((JabberCapsBits)1<<10) -#define JABBER_FEAT_CHATSTATES "http://jabber.org/protocol/chatstates" -#define JABBER_CAPS_CHATSTATES ((JabberCapsBits)1<<11) -#define JABBER_FEAT_LAST_ACTIVITY "jabber:iq:last" -#define JABBER_CAPS_LAST_ACTIVITY ((JabberCapsBits)1<<12) -#define JABBER_FEAT_VERSION "jabber:iq:version" -#define JABBER_CAPS_VERSION ((JabberCapsBits)1<<13) -#define JABBER_FEAT_ENTITY_TIME "urn:xmpp:time" -#define JABBER_CAPS_ENTITY_TIME ((JabberCapsBits)1<<14) -#define JABBER_FEAT_PING "urn:xmpp:ping" -#define JABBER_CAPS_PING ((JabberCapsBits)1<<15) -#define JABBER_FEAT_DATA_FORMS "jabber:x:data" -#define JABBER_CAPS_DATA_FORMS ((JabberCapsBits)1<<16) -#define JABBER_FEAT_MESSAGE_EVENTS "jabber:x:event" -#define JABBER_CAPS_MESSAGE_EVENTS ((JabberCapsBits)1<<17) -#define JABBER_FEAT_VCARD_TEMP "vcard-temp" -#define JABBER_CAPS_VCARD_TEMP ((JabberCapsBits)1<<18) -#define JABBER_FEAT_AVATAR "jabber:iq:avatar" -#define JABBER_FEAT_SERVER_AVATAR "storage:client:avatar" -#define JABBER_CAPS_AVATAR ((JabberCapsBits)1<<19) -#define JABBER_FEAT_XHTML "http://jabber.org/protocol/xhtml-im" -#define JABBER_CAPS_XHTML ((JabberCapsBits)1<<20) -#define JABBER_FEAT_AGENTS "jabber:iq:agents" -#define JABBER_CAPS_AGENTS ((JabberCapsBits)1<<21) -#define JABBER_FEAT_BROWSE "jabber:iq:browse" -#define JABBER_CAPS_BROWSE ((JabberCapsBits)1<<22) -#define JABBER_FEAT_FEATURE_NEG "http://jabber.org/protocol/feature-neg" -#define JABBER_CAPS_FEATURE_NEG ((JabberCapsBits)1<<23) -#define JABBER_FEAT_AMP "http://jabber.org/protocol/amp" -#define JABBER_CAPS_AMP ((JabberCapsBits)1<<24) -#define JABBER_FEAT_USER_MOOD "http://jabber.org/protocol/mood" -#define JABBER_CAPS_USER_MOOD ((JabberCapsBits)1<<25) -#define JABBER_FEAT_USER_MOOD_NOTIFY "http://jabber.org/protocol/mood+notify" -#define JABBER_CAPS_USER_MOOD_NOTIFY ((JabberCapsBits)1<<26) -#define JABBER_FEAT_PUBSUB "http://jabber.org/protocol/pubsub" -#define JABBER_CAPS_PUBSUB ((JabberCapsBits)1<<27) -#define JABBER_FEAT_SECUREIM "http://miranda-ng.org/caps/secureim" -#define JABBER_CAPS_SECUREIM ((JabberCapsBits)1<<28) -#define JABBER_FEAT_PRIVACY_LISTS "jabber:iq:privacy" -#define JABBER_CAPS_PRIVACY_LISTS ((JabberCapsBits)1<<29) -#define JABBER_FEAT_MESSAGE_RECEIPTS "urn:xmpp:receipts" -#define JABBER_CAPS_MESSAGE_RECEIPTS ((JabberCapsBits)1<<30) -#define JABBER_FEAT_USER_TUNE "http://jabber.org/protocol/tune" -#define JABBER_CAPS_USER_TUNE ((JabberCapsBits)1<<31) -#define JABBER_FEAT_USER_TUNE_NOTIFY "http://jabber.org/protocol/tune+notify" -#define JABBER_CAPS_USER_TUNE_NOTIFY ((JabberCapsBits)1<<32) -#define JABBER_FEAT_PRIVATE_STORAGE "jabber:iq:private" -#define JABBER_CAPS_PRIVATE_STORAGE ((JabberCapsBits)1<<33) -#define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha" -// deferred -#define JABBER_FEAT_ATTENTION "http://www.xmpp.org/extensions/xep-0224.html#ns" -#define JABBER_CAPS_ATTENTION ((JabberCapsBits)1<<34) -#define JABBER_FEAT_USER_ACTIVITY "http://jabber.org/protocol/activity" -#define JABBER_CAPS_USER_ACTIVITY ((JabberCapsBits)1<<35) -#define JABBER_FEAT_USER_ACTIVITY_NOTIFY "http://jabber.org/protocol/activity+notify" -#define JABBER_CAPS_USER_ACTIVITY_NOTIFY ((JabberCapsBits)1<<36) -#define JABBER_FEAT_ATTENTION_0 "urn:xmpp:attention:0" -#define JABBER_CAPS_ATTENTION_0 ((JabberCapsBits)1<<37) -#define JABBER_FEAT_MIRANDA_NOTES "http://miranda-ng.org/storage#notes" -#define JABBER_CAPS_MIRANDA_NOTES ((JabberCapsBits)1<<38) -#define JABBER_FEAT_JINGLE "urn:xmpp:jingle:1" -#define JABBER_CAPS_JINGLE ((JabberCapsBits)1<<39) -#define JABBER_FEAT_ROSTER_EXCHANGE "http://jabber.org/protocol/rosterx" -#define JABBER_CAPS_ROSTER_EXCHANGE ((JabberCapsBits)1<<40) -#define JABBER_FEAT_GTALK_PMUC "http://www.google.com/xmpp/protocol/pmuc/v1" -#define JABBER_CAPS_GTALK_PMUC ((JabberCapsBits)1<<41) - -#define JABBER_FEAT_PUBSUB_EVENT "http://jabber.org/protocol/pubsub#event" -#define JABBER_FEAT_PUBSUB_NODE_CONFIG "http://jabber.org/protocol/pubsub#node_config" - -#define JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY ((JabberCapsBits)1<<62) -#define JABBER_CAPS_OTHER_SPECIAL (JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_RESOURCE_CAPS_ERROR) // must contain all the caps not listed in g_JabberFeatCapPairs, to prevent using these bits for features registered through IJabberNetInterface::RegisterFeature() - -#define JABBER_CAPS_MIRANDA_NODE "http://miranda-ng.org/caps" -#define JABBER_CAPS_MIRANDA_ALL (JABBER_CAPS_DISCO_INFO|JABBER_CAPS_DISCO_ITEMS|JABBER_CAPS_MUC|JABBER_CAPS_ENTITY_CAPS|JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_BYTESTREAMS|JABBER_CAPS_IBB|JABBER_CAPS_OOB|JABBER_CAPS_CHATSTATES|JABBER_CAPS_AGENTS|JABBER_CAPS_BROWSE|JABBER_CAPS_VERSION|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_VCARD_TEMP|JABBER_CAPS_ENTITY_TIME|JABBER_CAPS_PING|JABBER_CAPS_PRIVACY_LISTS|JABBER_CAPS_MESSAGE_RECEIPTS|JABBER_CAPS_PRIVATE_STORAGE|JABBER_CAPS_ATTENTION_0|JABBER_CAPS_JINGLE|JABBER_CAPS_ROSTER_EXCHANGE|JABBER_CAPS_SECUREIM|JABBER_CAPS_COMMANDS|JABBER_CAPS_USER_MOOD_NOTIFY|JABBER_CAPS_USER_TUNE_NOTIFY|JABBER_CAPS_USER_ACTIVITY_NOTIFY) - -#define JABBER_CAPS_MIRANDA_PARTIAL (JABBER_CAPS_DISCO_INFO|JABBER_CAPS_DISCO_ITEMS|JABBER_CAPS_MUC|JABBER_CAPS_ENTITY_CAPS|JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_BYTESTREAMS|JABBER_CAPS_IBB|JABBER_CAPS_OOB|JABBER_CAPS_CHATSTATES|JABBER_CAPS_AGENTS|JABBER_CAPS_BROWSE|JABBER_CAPS_VERSION|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_VCARD_TEMP|JABBER_CAPS_ENTITY_TIME|JABBER_CAPS_PING|JABBER_CAPS_PRIVACY_LISTS|JABBER_CAPS_MESSAGE_RECEIPTS|JABBER_CAPS_PRIVATE_STORAGE|JABBER_CAPS_ATTENTION_0|JABBER_CAPS_JINGLE|JABBER_CAPS_ROSTER_EXCHANGE) - -#define JABBER_EXT_SECUREIM "secureim" -#define JABBER_EXT_COMMANDS "cmds" -#define JABBER_EXT_USER_MOOD "mood" -#define JABBER_EXT_USER_TUNE "tune" -#define JABBER_EXT_USER_ACTIVITY "activity" -#define JABBER_EXT_GTALK_PMUC "pmuc-v1" -#define JABBER_EXT_MIR_NOTES "mir_notes" - -#define JABBER_FEAT_EXT_ADDRESSING "http://jabber.org/protocol/address" -#define JABBER_FEAT_NESTED_ROSTER_GROUPS "roster:delimiter" - -#define JABBER_FEAT_RC "http://jabber.org/protocol/rc" -#define JABBER_FEAT_RC_SET_STATUS "http://jabber.org/protocol/rc#set-status" -#define JABBER_FEAT_RC_SET_OPTIONS "http://jabber.org/protocol/rc#set-options" -#define JABBER_FEAT_RC_FORWARD "http://jabber.org/protocol/rc#forward" -#define JABBER_FEAT_RC_LEAVE_GROUPCHATS "http://jabber.org/protocol/rc#leave-groupchats" -#define JABBER_FEAT_RC_WS_LOCK "http://miranda-ng.org/rc#lock_workstation" -#define JABBER_FEAT_RC_QUIT_MIRANDA "http://miranda-ng.org/rc#quit" - -#define JABBER_FEAT_IQ_ROSTER "jabber:iq:roster" -#define JABBER_FEAT_DELAY "jabber:x:delay" -#define JABBER_FEAT_ENTITY_TIME_OLD "jabber:iq:time" -#define JABBER_FEAT_GTALK_SHARED_STATUS "google:shared-status" - -#define JABBER_FEAT_MUC_USER "http://jabber.org/protocol/muc#user" -#define JABBER_FEAT_NICK "http://jabber.org/protocol/nick" - -#define JABBER_FEAT_HTTP_AUTH "http://jabber.org/protocol/http-auth" - - -class CJabberClientPartialCaps -{ - -protected: - TCHAR *m_szVer; - JabberCapsBits m_jcbCaps; - CJabberClientPartialCaps *m_pNext; - int m_nIqId; - DWORD m_dwRequestTime; - -public: - CJabberClientPartialCaps( const TCHAR *szVer ); - ~CJabberClientPartialCaps(); - - CJabberClientPartialCaps* SetNext( CJabberClientPartialCaps *pCaps ); - __inline CJabberClientPartialCaps* GetNext() - { return m_pNext; - } - - void SetCaps( JabberCapsBits jcbCaps, int nIqId = -1 ); - JabberCapsBits GetCaps(); - - __inline TCHAR* GetVersion() - { return m_szVer; - } - - __inline int GetIqId() - { return m_nIqId; - } -}; - -class CJabberClientCaps -{ - -protected: - TCHAR *m_szNode; - CJabberClientPartialCaps *m_pCaps; - CJabberClientCaps *m_pNext; - -protected: - CJabberClientPartialCaps* FindByVersion( const TCHAR *szVer ); - CJabberClientPartialCaps* FindById( int nIqId ); - -public: - CJabberClientCaps( const TCHAR *szNode ); - ~CJabberClientCaps(); - - CJabberClientCaps* SetNext( CJabberClientCaps *pClient ); - __inline CJabberClientCaps* GetNext() - { return m_pNext; - } - - JabberCapsBits GetPartialCaps( TCHAR *szVer ); - BOOL SetPartialCaps( const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId = -1 ); - BOOL SetPartialCaps( int nIqId, JabberCapsBits jcbCaps ); - - __inline TCHAR* GetNode() - { return m_szNode; - } -}; - -class CJabberClientCapsManager -{ - -protected: - CRITICAL_SECTION m_cs; - CJabberClientCaps *m_pClients; - CJabberProto* ppro; - -protected: - CJabberClientCaps *FindClient( const TCHAR *szNode ); - -public: - CJabberClientCapsManager( CJabberProto* proto ); - ~CJabberClientCapsManager(); - - __inline void Lock() - { EnterCriticalSection( &m_cs ); - } - __inline void Unlock() - { LeaveCriticalSection( &m_cs ); - } - - void AddDefaultCaps(); - - JabberCapsBits GetClientCaps( TCHAR *szNode, TCHAR *szVer ); - BOOL SetClientCaps( const TCHAR *szNode, const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId = -1 ); - BOOL SetClientCaps( int nIqId, JabberCapsBits jcbCaps ); - - BOOL HandleInfoRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); -}; - -struct JabberFeatCapPair -{ - const TCHAR *szFeature; - JabberCapsBits jcbCap; - const TCHAR *szDescription; -}; - -struct JabberFeatCapPairDynamic -{ - TCHAR *szExt; - TCHAR *szFeature; - JabberCapsBits jcbCap; - TCHAR *szDescription; -}; - -extern const JabberFeatCapPair g_JabberFeatCapPairs[]; -extern const JabberFeatCapPair g_JabberFeatCapPairsExt[]; - -#endif diff --git a/protocols/JabberG/jabber_captcha.cpp b/protocols/JabberG/jabber_captcha.cpp deleted file mode 100644 index 88d3038ab7..0000000000 --- a/protocols/JabberG/jabber_captcha.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -struct CAPTCHA_FORM_PARAMS -{ - LPCTSTR from; - LPCTSTR challenge; - LPCTSTR fromjid; - LPCTSTR sid; - LPCTSTR to; - LPCTSTR hint; - HBITMAP bmp; - int w,h; - TCHAR Result[MAX_PATH]; -}; - -INT_PTR CALLBACK JabberCaptchaFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - CAPTCHA_FORM_PARAMS *params = (CAPTCHA_FORM_PARAMS*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - switch (msg) { - case WM_INITDIALOG: { - TranslateDialogDefault( hwndDlg ); - SendMessage( hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(IDI_KEYS)); - SendMessage( hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(IDI_KEYS)); - params = (CAPTCHA_FORM_PARAMS*)lParam; - - LPCTSTR hint = params->hint; - if ( hint == NULL ) - hint = TranslateT("Enter the text you see"); - SetDlgItemText( hwndDlg, IDC_INSTRUCTION, TranslateTS( hint )); - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG )params ); - - return TRUE; - } - case WM_CTLCOLORSTATIC: - switch( GetWindowLongPtr((HWND)lParam, GWL_ID)) { - case IDC_WHITERECT: - case IDC_INSTRUCTION: - case IDC_TITLE: - return (BOOL)GetStockObject(WHITE_BRUSH); - } - return NULL; - - case WM_PAINT: - if ( params ) { - PAINTSTRUCT ps; - HDC hdc, hdcMem; - RECT rc; - - GetClientRect( hwndDlg, &rc ); - hdc = BeginPaint( hwndDlg, &ps ); - hdcMem = CreateCompatibleDC( hdc ); - HGDIOBJ hOld = SelectObject( hdcMem, params->bmp ); - - int y = ( rc.bottom + rc.top - params->h ) / 2; - int x = ( rc.right + rc.left - params->w ) / 2; - BitBlt( hdc, x, y, params->w, params->h, hdcMem, 0,0, SRCCOPY ); - SelectObject( hdcMem, hOld ); - DeleteDC( hdcMem ); - - EndPaint( hwndDlg, &ps ); - } - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDCANCEL: - EndDialog( hwndDlg, 0 ); - return TRUE; - - case IDC_SUBMIT: - GetDlgItemText( hwndDlg, IDC_VALUE, params->Result, SIZEOF(params->Result)); - EndDialog( hwndDlg, 1 ); - return TRUE; - } - break; - - case WM_CLOSE: - EndDialog( hwndDlg, 0 ); - break; - - case WM_DESTROY: - WindowFreeIcon( hwndDlg ); - break; - } - return FALSE; -} - -bool CJabberProto::ProcessCaptcha (HXML node, HXML parentNode, ThreadData* info ) { - CAPTCHA_FORM_PARAMS param; - char *ImageBuf = 0; - const TCHAR *PicType = 0; - TCHAR *CaptchaPath = 0; - - HXML x = xmlGetChildByTag( node, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( x == NULL ) - return false; - - HXML y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("from")); - if ( y == NULL ) - return false; - if (( y = xmlGetChild( y, "value" )) == NULL ) - return false; - param.fromjid = xmlGetText( y ); - - if (( y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("sid"))) == NULL ) - return false; - if (( y = xmlGetChild( y, "value" )) == NULL ) - return false; - param.sid = xmlGetText( y ); - - if (( y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("ocr"))) == NULL ) - return false; - param.hint = xmlGetAttrValue (y, _T("label")); - - param.from = xmlGetAttrValue( parentNode, _T("from")); - param.to = xmlGetAttrValue( parentNode, _T("to")); - param.challenge = xmlGetAttrValue( parentNode, _T("id")); - HXML o = xmlGetChild( parentNode, "data" ); - if ( o == NULL || xmlGetText( o ) == NULL ) - return false; - - GetCaptchaImage(parentNode, ImageBuf, PicType, CaptchaPath); - char* p = mir_t2a( CaptchaPath ); - param.bmp = ( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p ); - DeleteFile(CaptchaPath); - mir_free(CaptchaPath); - mir_free(p); - - BITMAP bmp = {0}; - GetObject( param.bmp, sizeof(bmp), &bmp ); - param.w = bmp.bmWidth; - param.h = bmp.bmHeight; - int res = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CAPTCHAFORM), NULL, JabberCaptchaFormDlgProc, (LPARAM)¶m); - if (lstrcmp(param.Result, _T("")) == 0 || !res) - sendCaptchaError(info, param.from, param.to, param.challenge); - else - sendCaptchaResult (param.Result, info, param.from, param.challenge, param.fromjid, param.sid); - return true; -} - -void CJabberProto::GetCaptchaImage ( HXML node, char *ImageBuf, const TCHAR *PicType, TCHAR*& CaptchaPath ) { - HXML o = xmlGetChild( node , "data" ); - int bufferLen; - char* buffer = JabberBase64DecodeT(xmlGetText( o ), &bufferLen ); - if ( buffer == NULL ) - return; - - const TCHAR* szPicType; - HXML m = xmlGetChild( node , "TYPE" ); - if ( m == NULL || xmlGetText( m ) == NULL ) { - LBL_NoTypeSpecified: - switch( JabberGetPictureType( buffer )) { - case PA_FORMAT_GIF: szPicType = _T("image/gif"); break; - case PA_FORMAT_BMP: szPicType = _T("image/bmp"); break; - case PA_FORMAT_PNG: szPicType = _T("image/png"); break; - case PA_FORMAT_JPEG: szPicType = _T("image/jpeg"); break; - default: - goto LBL_Ret; - } - } - else { - const TCHAR* tszType = xmlGetText( m ); - if ( !_tcscmp( tszType, _T("image/jpeg")) || - !_tcscmp( tszType, _T("image/png")) || - !_tcscmp( tszType, _T("image/gif")) || - !_tcscmp( tszType, _T("image/bmp"))) - szPicType = tszType; - else - goto LBL_NoTypeSpecified; - } - - DWORD nWritten; - -LBL_Ret: - TCHAR* ext = _tcsstr((TCHAR*)szPicType, _T("/"))+1; - TCHAR filename[MAX_PATH]; - mir_sntprintf(filename, SIZEOF(filename), _T("%%TEMP%%\\captcha.%s"), ext); - CaptchaPath = Utils_ReplaceVarsT(filename); - HANDLE hFile = CreateFile( CaptchaPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if ( hFile == INVALID_HANDLE_VALUE ) - goto LBL_Ret; - - if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL )) - goto LBL_Ret; - - CloseHandle( hFile ); - - ImageBuf = buffer; - PicType = szPicType; -} - -void CJabberProto::sendCaptchaResult(TCHAR* buf, ThreadData* info, LPCTSTR from, LPCTSTR challenge, LPCTSTR fromjid, LPCTSTR sid){ - XmlNodeIq iq( _T("set"), SerialNext()); - HXML query= iq < send (iq); -} - -void CJabberProto::sendCaptchaError(ThreadData* info, LPCTSTR from, LPCTSTR to, LPCTSTR challenge ) { - XmlNode message( _T("message")); - HXML query= message << XATTR(_T("type"), _T("error")) << XATTR(_T("to"), from) << XATTR(_T("id"), challenge) << XATTR(_T("from"), to) - << XCHILD(_T("error")) << XATTR(_T("type"), _T("modify")) - << XCHILD(_T("not-acceptable")) << XATTR(_T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - info -> send (message); -} diff --git a/protocols/JabberG/jabber_chat.cpp b/protocols/JabberG/jabber_chat.cpp deleted file mode 100644 index 8dacc24619..0000000000 --- a/protocols/JabberG/jabber_chat.cpp +++ /dev/null @@ -1,1628 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" - -#include - -const TCHAR xmlnsAdmin[] = _T("http://jabber.org/protocol/muc#admin"); -const TCHAR xmlnsOwner[] = _T("http://jabber.org/protocol/muc#owner"); - -///////////////////////////////////////////////////////////////////////////////////////// -// Global definitions - -enum { - IDM_CANCEL, - - IDM_ROLE, IDM_AFFLTN, - - IDM_CONFIG, IDM_NICK, IDM_DESTROY, IDM_INVITE, IDM_BOOKMARKS, IDM_LEAVE, IDM_TOPIC, - IDM_LST_PARTICIPANT, IDM_LST_MODERATOR, - IDM_LST_MEMBER, IDM_LST_ADMIN, IDM_LST_OWNER, IDM_LST_BAN, - - IDM_MESSAGE, IDM_SLAP, IDM_VCARD, IDM_INFO, IDM_KICK, - IDM_RJID, IDM_RJID_ADD, IDM_RJID_VCARD, IDM_RJID_COPY, - IDM_SET_VISITOR, IDM_SET_PARTICIPANT, IDM_SET_MODERATOR, - IDM_SET_NONE, IDM_SET_MEMBER, IDM_SET_ADMIN, IDM_SET_OWNER, IDM_SET_BAN, - IDM_CPY_NICK, IDM_CPY_TOPIC, IDM_CPY_RJID, IDM_CPY_INROOMJID, - - IDM_LINK0, IDM_LINK1, IDM_LINK2, IDM_LINK3, IDM_LINK4, IDM_LINK5, IDM_LINK6, IDM_LINK7, IDM_LINK8, IDM_LINK9, - - IDM_PRESENCE_ONLINE = ID_STATUS_ONLINE, - IDM_PRESENCE_AWAY = ID_STATUS_AWAY, - IDM_PRESENCE_NA = ID_STATUS_NA, - IDM_PRESENCE_DND = ID_STATUS_DND, - IDM_PRESENCE_FREE4CHAT = ID_STATUS_FREECHAT, -}; - -struct TRoleOrAffiliationInfo -{ - int value; - int id; - TCHAR *title_en; - int min_role; - int min_affiliation; - - TCHAR *title; - - BOOL check(JABBER_RESOURCE_STATUS *me, JABBER_RESOURCE_STATUS *him) - { - if (me->affiliation == AFFILIATION_OWNER) return TRUE; - if (me == him) return FALSE; - if (me->affiliation <= him->affiliation) return FALSE; - if (me->role < this->min_role) return FALSE; - if (me->affiliation < this->min_affiliation) return FALSE; - return TRUE; - } - void translate() - { - this->title = TranslateTS(this->title_en); - } -}; - -static TRoleOrAffiliationInfo sttAffiliationItems[] = -{ - { AFFILIATION_NONE, IDM_SET_NONE, LPGENT("None"), ROLE_NONE, AFFILIATION_ADMIN }, - { AFFILIATION_MEMBER, IDM_SET_MEMBER, LPGENT("Member"), ROLE_NONE, AFFILIATION_ADMIN }, - { AFFILIATION_ADMIN, IDM_SET_ADMIN, LPGENT("Admin"), ROLE_NONE, AFFILIATION_OWNER }, - { AFFILIATION_OWNER, IDM_SET_OWNER, LPGENT("Owner"), ROLE_NONE, AFFILIATION_OWNER }, -}; - -static TRoleOrAffiliationInfo sttRoleItems[] = -{ - { ROLE_VISITOR, IDM_SET_VISITOR, LPGENT("Visitor"), ROLE_MODERATOR, AFFILIATION_NONE }, - { ROLE_PARTICIPANT, IDM_SET_PARTICIPANT, LPGENT("Participant"), ROLE_MODERATOR, AFFILIATION_NONE }, - { ROLE_MODERATOR, IDM_SET_MODERATOR, LPGENT("Moderator"), ROLE_MODERATOR, AFFILIATION_ADMIN }, -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGcInit - initializes the new chat - -static const TCHAR* sttStatuses[] = { _T("Visitors"), _T("Participants"), _T("Moderators"), _T("Owners") }; - -int JabberGcGetStatus(JABBER_GC_AFFILIATION a, JABBER_GC_ROLE r) -{ - switch (a) { - case AFFILIATION_OWNER: return 3; - - default: - switch (r) { - case ROLE_MODERATOR: return 2; - case ROLE_PARTICIPANT: return 1; - } } - - return 0; -} - -int JabberGcGetStatus(JABBER_RESOURCE_STATUS *r) -{ - return JabberGcGetStatus(r->affiliation, r->role); -} - -int CJabberProto::JabberGcInit( WPARAM wParam, LPARAM ) -{ - int i; - JABBER_LIST_ITEM* item = ( JABBER_LIST_ITEM* )wParam; - GCSESSION gcw = {0}; - GCEVENT gce = {0}; - - // translate string for menus (this can't be done in initializer) - for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) sttAffiliationItems[i].translate(); - for (i = 0; i < SIZEOF(sttRoleItems); ++i) sttRoleItems[i].translate(); - - TCHAR* szNick = JabberNickFromJID( item->jid ); - gcw.cbSize = sizeof(GCSESSION); - gcw.iType = GCW_CHATROOM; - gcw.pszModule = m_szModuleName; - gcw.ptszName = szNick; - gcw.ptszID = item->jid; - gcw.dwFlags = GC_TCHAR; - CallServiceSync( MS_GC_NEWSESSION, NULL, (LPARAM)&gcw ); - - HANDLE hContact = HContactFromJID( item->jid ); - if ( hContact != NULL ) { - DBVARIANT dbv; - if ( JABBER_LIST_ITEM* bookmark = ListGetItemPtr( LIST_BOOKMARK, item->jid )) - if ( bookmark->name ) { - if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) - JFreeVariant( &dbv ); - else - DBWriteContactSettingTString( hContact, "CList", "MyHandle", bookmark->name ); - } - - if ( !JGetStringT( hContact, "MyNick", &dbv )) { - if ( !lstrcmp( dbv.ptszVal, szNick )) - JDeleteSetting( hContact, "MyNick" ); - else - JSetStringT( hContact, "MyNick", item->nick ); - JFreeVariant( &dbv ); - } - else JSetStringT( hContact, "MyNick", item->nick ); - - TCHAR *passw = JGetStringCrypt( hContact, "LoginPassword" ); - if ( lstrcmp_null( passw, item->password )) { - if ( !item->password || !item->password[0] ) - JDeleteSetting( hContact, "LoginPassword" ); - else - JSetStringCrypt( hContact, "LoginPassword", item->password ); - } - mir_free(passw); - } - mir_free( szNick ); - - item->bChatActive = TRUE; - - GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_ADDGROUP }; - gcd.ptszID = item->jid; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - gce.dwFlags = GC_TCHAR; - for (i = SIZEOF(sttStatuses)-1; i >= 0; i-- ) { - gce.ptszStatus = TranslateTS( sttStatuses[i] ); - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - } - - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - gcd.iType = GC_EVENT_CONTROL; - CallServiceSync( MS_GC_EVENT, (item->bAutoJoin && m_options.AutoJoinHidden) ? WINDOW_HIDDEN : SESSION_INITDONE, (LPARAM)&gce ); - CallServiceSync( MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce ); - return 0; -} - -void CJabberProto::GcLogCreate( JABBER_LIST_ITEM* item ) -{ - if ( item->bChatActive ) - return; - - NotifyEventHooks( m_hInitChat, (WPARAM)item, 0 ); -} - -void CJabberProto::GcLogShowInformation( JABBER_LIST_ITEM *item, JABBER_RESOURCE_STATUS *user, TJabberGcLogInfoType type ) -{ - if (!item || !user || (item->bChatActive != 2)) return; - - TCHAR buf[512] = _T(""); - - switch (type) - { - case INFO_BAN: - if (m_options.GcLogBans) - { - mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s in now banned."), user->resourceName); - } - break; - case INFO_STATUS: - if (m_options.GcLogStatuses) - { - if (user->statusMessage) - { - mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s changed status to %s with message: %s"), - user->resourceName, - CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, user->status, GSMDF_TCHAR), - user->statusMessage); - } else - { - mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s changed status to %s"), - user->resourceName, - CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, user->status, GSMDF_TCHAR)); - } - } - break; - case INFO_CONFIG: - if (m_options.GcLogConfig) - { - mir_sntprintf(buf, SIZEOF(buf), TranslateT("Room configuration was changed.")); - } - break; - case INFO_AFFILIATION: - if (m_options.GcLogAffiliations) - { - TCHAR *name = NULL; - switch (user->affiliation) - { - case AFFILIATION_NONE: name = TranslateT("None"); break; - case AFFILIATION_MEMBER: name = TranslateT("Member"); break; - case AFFILIATION_ADMIN: name = TranslateT("Admin"); break; - case AFFILIATION_OWNER: name = TranslateT("Owner"); break; - case AFFILIATION_OUTCAST: name = TranslateT("Outcast"); break; - } - if (name) mir_sntprintf(buf, SIZEOF(buf), TranslateT("Affiliation of %s was changed to '%s'."), user->resourceName, name); - } - break; - case INFO_ROLE: - if (m_options.GcLogRoles) - { - TCHAR *name = NULL; - switch (user->role) - { - case ROLE_NONE: name = TranslateT("None"); break; - case ROLE_VISITOR: name = TranslateT("Visitor"); break; - case ROLE_PARTICIPANT: name = TranslateT("Participant"); break; - case ROLE_MODERATOR: name = TranslateT("Moderator"); break; - } - if (name) mir_sntprintf(buf, SIZEOF(buf), TranslateT("Role of %s was changed to '%s'."), user->resourceName, name); - } - break; - } - - if (*buf) - { - GCDEST gcd = { m_szModuleName, 0, 0 }; - gcd.ptszID = item->jid; - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - gce.ptszNick = user->resourceName; - gce.ptszUID = user->resourceName; - gce.ptszText = EscapeChatTags( buf ); - gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; - gce.pDest = &gcd; - gce.time = time(0); - gcd.iType = GC_EVENT_INFORMATION; - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - - mir_free( (void*)gce.ptszText ); // Since we processed msgText and created a new string - } -} - -void CJabberProto::GcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, const TCHAR* resource, const TCHAR* nick, const TCHAR* jid, int action, HXML reason, int nStatusCode ) -{ - int statusToSet = 0; - const TCHAR* szReason = NULL; - if ( reason != NULL && xmlGetText( reason ) != NULL ) - szReason = xmlGetText( reason ); - - if ( !szReason ) { - if ( nStatusCode == 322 ) - szReason = TranslateT( "because room is now members-only" ); - else if ( nStatusCode == 301 ) - szReason = TranslateT( "user banned" ); - } - - TCHAR* myNick = (item->nick == NULL) ? NULL : mir_tstrdup( item->nick ); - if ( myNick == NULL ) - myNick = JabberNickFromJID( m_szJabberJID ); - - GCDEST gcd = { m_szModuleName, 0, 0 }; - gcd.ptszID = item->jid; - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - gce.ptszNick = nick; - gce.ptszUID = resource; - if (jid != NULL) - gce.ptszUserInfo = jid; - gce.ptszText = szReason; - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - if ( item->bChatActive == 2 ) { - gce.dwFlags |= GCEF_ADDTOLOG; - gce.time = time(0); - } - - switch( gcd.iType = action ) { - case GC_EVENT_PART: break; - case GC_EVENT_KICK: - gce.ptszStatus = TranslateT( "Moderator" ); - break; - default: - for ( int i=0; i < item->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& JS = item->resource[i]; - if ( !lstrcmp( resource, JS.resourceName )) { - if ( action != GC_EVENT_JOIN ) { - switch( action ) { - case 0: - gcd.iType = GC_EVENT_ADDSTATUS; - case GC_EVENT_REMOVESTATUS: - gce.dwFlags &= ~GCEF_ADDTOLOG; - } - gce.ptszText = TranslateT( "Moderator" ); - } - gce.ptszStatus = TranslateTS( sttStatuses[JabberGcGetStatus(&JS)] ); - gce.bIsMe = ( lstrcmp( nick, myNick ) == 0 ); - statusToSet = JS.status; - break; - } } } - - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - - if ( statusToSet != 0 ) { - gce.ptszText = nick; - if ( statusToSet == ID_STATUS_AWAY || statusToSet == ID_STATUS_NA || statusToSet == ID_STATUS_DND ) - gce.dwItemData = 3; - else - gce.dwItemData = 1; - gcd.iType = GC_EVENT_SETSTATUSEX; - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - - gce.ptszUID = resource; - gce.dwItemData = statusToSet; - gcd.iType = GC_EVENT_SETCONTACTSTATUS; - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - } - - mir_free( myNick ); -} - -void CJabberProto::GcQuit( JABBER_LIST_ITEM* item, int code, HXML reason ) -{ - TCHAR *szMessage = NULL; - - const TCHAR* szReason = NULL; - if ( reason != NULL && xmlGetText( reason ) != NULL ) - szReason = xmlGetText( reason ); - - GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_CONTROL }; - gcd.ptszID = item->jid; - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - gce.ptszUID = item->jid; - gce.ptszText = szReason; - gce.dwFlags = GC_TCHAR; - gce.pDest = &gcd; - - if ( code != 307 && code != 301 ) { - CallServiceSync( MS_GC_EVENT, SESSION_TERMINATE, ( LPARAM )&gce ); - CallServiceSync( MS_GC_EVENT, WINDOW_CLEARLOG, ( LPARAM )&gce ); - - DBVARIANT dbvMessage; - if (!DBGetContactSettingTString( NULL, m_szModuleName, "GcMsgQuit", &dbvMessage)) { - szMessage = NEWTSTR_ALLOCA(dbvMessage.ptszVal); - DBFreeVariant(&dbvMessage); - } - else szMessage = TranslateTS(JABBER_GC_MSG_QUIT); - } - else { - TCHAR* myNick = JabberNickFromJID( m_szJabberJID ); - GcLogUpdateMemberStatus( item, myNick, myNick, NULL, GC_EVENT_KICK, reason ); - mir_free( myNick ); - CallServiceSync( MS_GC_EVENT, SESSION_OFFLINE, ( LPARAM )&gce ); - } - - DBDeleteContactSetting( HContactFromJID( item->jid ), "CList", "Hidden" ); - item->bChatActive = FALSE; - - if ( m_bJabberOnline ) { - TCHAR szPresenceTo[ JABBER_MAX_JID_LEN ]; - mir_sntprintf( szPresenceTo, SIZEOF( szPresenceTo ), _T("%s/%s"), item->jid, item->nick ); - - m_ThreadInfo->send( - XmlNode( _T("presence")) << XATTR( _T("to"), szPresenceTo ) << XATTR( _T("type"), _T("unavailable")) - << XCHILD( _T("status"), szMessage)); - - ListRemove( LIST_CHATROOM, item->jid ); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// Context menu hooks - -static struct gc_item *sttFindGcMenuItem(GCMENUITEMS *items, DWORD id) -{ - for (int i = 0; i < items->nItems; ++i) - if (items->Item[i].dwID == id) - return items->Item + i; - return NULL; -} - -static void sttSetupGcMenuItem(GCMENUITEMS *items, DWORD id, bool disabled) -{ - for (int i = 0; i < items->nItems; ++i) - if (!id || (items->Item[i].dwID == id)) - items->Item[i].bDisabled = disabled; -} - -static void sttShowGcMenuItem(GCMENUITEMS *items, DWORD id, int type) -{ - for (int i = 0; i < items->nItems; ++i) - if (!id || (items->Item[i].dwID == id)) - items->Item[i].uType = type; -} - -static void sttSetupGcMenuItems(GCMENUITEMS *items, DWORD *ids, bool disabled) -{ - for ( ; *ids; ++ids) - sttSetupGcMenuItem(items, *ids, disabled); -} - -static void sttShowGcMenuItems(GCMENUITEMS *items, DWORD *ids, int type) -{ - for ( ; *ids; ++ids) - sttShowGcMenuItem(items, *ids, type); -} - -static gc_item sttLogListItems[] = -{ - { LPGENT("Change &nickname"), IDM_NICK, MENU_ITEM }, - { LPGENT("&Invite a user"), IDM_INVITE, MENU_ITEM }, - { NULL, 0, MENU_SEPARATOR }, - - { LPGENT("&Roles"), IDM_ROLE, MENU_NEWPOPUP }, - { LPGENT("&Participant list"), IDM_LST_PARTICIPANT, MENU_POPUPITEM }, - { LPGENT("&Moderator list"), IDM_LST_MODERATOR, MENU_POPUPITEM }, - - { LPGENT("&Affiliations"), IDM_AFFLTN, MENU_NEWPOPUP }, - { LPGENT("&Member list"), IDM_LST_MEMBER, MENU_POPUPITEM }, - { LPGENT("&Admin list"), IDM_LST_ADMIN, MENU_POPUPITEM }, - { LPGENT("&Owner list"), IDM_LST_OWNER, MENU_POPUPITEM }, - { NULL, 0, MENU_POPUPSEPARATOR }, - { LPGENT("Outcast list (&ban)"), IDM_LST_BAN, MENU_POPUPITEM }, - - { LPGENT("&Room options"), 0, MENU_NEWPOPUP }, - { LPGENT("View/change &topic"), IDM_TOPIC, MENU_POPUPITEM }, - { LPGENT("Add to &bookmarks"), IDM_BOOKMARKS, MENU_POPUPITEM }, - { LPGENT("&Configure..."), IDM_CONFIG, MENU_POPUPITEM }, - { LPGENT("&Destroy room"), IDM_DESTROY, MENU_POPUPITEM }, - - { NULL, 0, MENU_SEPARATOR }, - - { LPGENT("Lin&ks"), 0, MENU_NEWPOPUP }, - { NULL, IDM_LINK0, 0 }, - { NULL, IDM_LINK1, 0 }, - { NULL, IDM_LINK2, 0 }, - { NULL, IDM_LINK3, 0 }, - { NULL, IDM_LINK4, 0 }, - { NULL, IDM_LINK5, 0 }, - { NULL, IDM_LINK6, 0 }, - { NULL, IDM_LINK7, 0 }, - { NULL, IDM_LINK8, 0 }, - { NULL, IDM_LINK9, 0 }, - - { LPGENT("Copy room &JID"), IDM_CPY_RJID, MENU_ITEM }, - { LPGENT("Copy room topic"), IDM_CPY_TOPIC, MENU_ITEM }, - { NULL, 0, MENU_SEPARATOR }, - - { LPGENT("&Send presence"), 0, MENU_NEWPOPUP}, - { LPGENT("Online"), IDM_PRESENCE_ONLINE, MENU_POPUPITEM }, - { LPGENT("Away"), IDM_PRESENCE_AWAY, MENU_POPUPITEM }, - { LPGENT("NA"), IDM_PRESENCE_NA, MENU_POPUPITEM }, - { LPGENT("DND"), IDM_PRESENCE_DND, MENU_POPUPITEM }, - { LPGENT("Free for chat"), IDM_PRESENCE_FREE4CHAT, MENU_POPUPITEM }, - - { LPGENT("&Leave chat session"), IDM_LEAVE, MENU_ITEM } -}; - -static TCHAR sttRJidBuf[JABBER_MAX_JID_LEN] = {0}; -static struct gc_item sttListItems[] = -{ - { LPGENT("&Slap"), IDM_SLAP, MENU_ITEM }, // 0 - { LPGENT("&User details"), IDM_VCARD, MENU_ITEM }, // 1 - { LPGENT("Member &info"), IDM_INFO, MENU_ITEM }, // 2 - - { sttRJidBuf, 0, MENU_NEWPOPUP }, // 3 -> accessed explicitly by index!!! - { LPGENT("User &details"), IDM_RJID_VCARD, MENU_POPUPITEM }, - { LPGENT("&Add to roster"), IDM_RJID_ADD, MENU_POPUPITEM }, - { LPGENT("&Copy to clipboard"), IDM_RJID_COPY, MENU_POPUPITEM }, - - { LPGENT("Invite to room"), 0, MENU_NEWPOPUP }, - { NULL, IDM_LINK0, 0 }, - { NULL, IDM_LINK1, 0 }, - { NULL, IDM_LINK2, 0 }, - { NULL, IDM_LINK3, 0 }, - { NULL, IDM_LINK4, 0 }, - { NULL, IDM_LINK5, 0 }, - { NULL, IDM_LINK6, 0 }, - { NULL, IDM_LINK7, 0 }, - { NULL, IDM_LINK8, 0 }, - { NULL, IDM_LINK9, 0 }, - - { NULL, 0, MENU_SEPARATOR }, - - { LPGENT("Set &role"), IDM_ROLE, MENU_NEWPOPUP }, - { LPGENT("&Visitor"), IDM_SET_VISITOR, MENU_POPUPITEM }, - { LPGENT("&Participant"), IDM_SET_PARTICIPANT, MENU_POPUPITEM }, - { LPGENT("&Moderator"), IDM_SET_MODERATOR, MENU_POPUPITEM }, - - { LPGENT("Set &affiliation"), IDM_AFFLTN, MENU_NEWPOPUP }, - { LPGENT("&None"), IDM_SET_NONE, MENU_POPUPITEM }, - { LPGENT("&Member"), IDM_SET_MEMBER, MENU_POPUPITEM }, - { LPGENT("&Admin"), IDM_SET_ADMIN, MENU_POPUPITEM }, - { LPGENT("&Owner"), IDM_SET_OWNER, MENU_POPUPITEM }, - { NULL, 0, MENU_POPUPSEPARATOR }, - { LPGENT("Outcast (&ban)"), IDM_SET_BAN, MENU_POPUPITEM }, - - { LPGENT("&Kick"), IDM_KICK, MENU_ITEM }, - { NULL, 0, MENU_SEPARATOR }, - { LPGENT("Copy &nickname"), IDM_CPY_NICK, MENU_ITEM }, - { LPGENT("Copy real &JID"), IDM_CPY_RJID, MENU_ITEM }, - { LPGENT("Copy in-room JID"), IDM_CPY_INROOMJID, MENU_ITEM } -}; - -int CJabberProto::JabberGcMenuHook( WPARAM, LPARAM lParam ) -{ - GCMENUITEMS* gcmi = ( GCMENUITEMS* )lParam; - if ( gcmi == NULL ) - return 0; - - if ( lstrcmpiA( gcmi->pszModule, m_szModuleName )) - return 0; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, gcmi->pszID ); - if ( item == NULL ) - return 0; - - JABBER_RESOURCE_STATUS *me = NULL, *him = NULL; - for ( int i=0; i < item->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& p = item->resource[i]; - if ( !lstrcmp( p.resourceName, item->nick )) me = &p; - if ( !lstrcmp( p.resourceName, gcmi->pszUID )) him = &p; - } - - if ( gcmi->Type == MENU_ON_LOG ) { - static TCHAR url_buf[1024] = {0}; - - gcmi->nItems = SIZEOF( sttLogListItems ); - gcmi->Item = sttLogListItems; - - static DWORD sttModeratorItems[] = { IDM_LST_PARTICIPANT, 0 }; - static DWORD sttAdminItems[] = { IDM_LST_MODERATOR, IDM_LST_MEMBER, IDM_LST_ADMIN, IDM_LST_OWNER, IDM_LST_BAN, 0 }; - static DWORD sttOwnerItems[] = { IDM_CONFIG, IDM_DESTROY, 0 }; - - sttSetupGcMenuItem(gcmi, 0, FALSE); - - int idx = IDM_LINK0; - if (item->itemResource.statusMessage && *item->itemResource.statusMessage) { - TCHAR *bufPtr = url_buf; - for (TCHAR *p = _tcsstr(item->itemResource.statusMessage, _T("http://")); p && *p; p = _tcsstr(p+1, _T("http://"))) { - lstrcpyn(bufPtr, p, SIZEOF(url_buf) - (bufPtr - url_buf)); - gc_item *pItem = sttFindGcMenuItem(gcmi, idx); - pItem->pszDesc = bufPtr; - pItem->uType = MENU_POPUPITEM; - for ( ; *bufPtr && !_istspace(*bufPtr); ++bufPtr) ; - *bufPtr++ = 0; - - if (++idx > IDM_LINK9) break; - } - } - for ( ; idx <= IDM_LINK9; ++idx) - sttFindGcMenuItem(gcmi, idx)->uType = 0; - - if ( !GetAsyncKeyState(VK_CONTROL)) { - if (me) { - sttSetupGcMenuItems(gcmi, sttModeratorItems, (me->role < ROLE_MODERATOR)); - sttSetupGcMenuItems(gcmi, sttAdminItems, (me->affiliation < AFFILIATION_ADMIN)); - sttSetupGcMenuItems(gcmi, sttOwnerItems, (me->affiliation < AFFILIATION_OWNER)); - } - if (m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE) - sttSetupGcMenuItem(gcmi, IDM_BOOKMARKS, FALSE); - } - } - else if ( gcmi->Type == MENU_ON_NICKLIST ) { - gcmi->nItems = SIZEOF(sttListItems); - gcmi->Item = sttListItems; - - static DWORD sttRJidItems[] = { IDM_RJID_VCARD, IDM_RJID_ADD, IDM_RJID_COPY, 0 }; - - if (me && him) { - int i, idx; - BOOL force = GetAsyncKeyState(VK_CONTROL); - sttSetupGcMenuItem(gcmi, 0, FALSE); - - idx = IDM_LINK0; - LISTFOREACH_NODEF(i, this, LIST_CHATROOM) - if (item = ListGetItemPtrFromIndex(i)) { - gc_item *pItem = sttFindGcMenuItem(gcmi, idx); - pItem->pszDesc = item->jid; - pItem->uType = MENU_POPUPITEM; - if (++idx > IDM_LINK9) break; - } - - for ( ; idx <= IDM_LINK9; ++idx) - sttFindGcMenuItem(gcmi, idx)->uType = 0; - - for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) { - struct gc_item *item = sttFindGcMenuItem(gcmi, sttAffiliationItems[i].id); - item->uType = (him->affiliation == sttAffiliationItems[i].value) ? MENU_POPUPCHECK : MENU_POPUPITEM; - item->bDisabled = !(force || sttAffiliationItems[i].check(me, him)); - } - - for (i = 0; i < SIZEOF(sttRoleItems); ++i) { - struct gc_item *item = sttFindGcMenuItem(gcmi, sttRoleItems[i].id); - item->uType = (him->role == sttRoleItems[i].value) ? MENU_POPUPCHECK : MENU_POPUPITEM; - item->bDisabled = !(force || sttRoleItems[i].check(me, him)); - } - - if (him->szRealJid && *him->szRealJid) { - mir_sntprintf(sttRJidBuf, SIZEOF(sttRJidBuf), TranslateT("Real &JID: %s"), him->szRealJid); - if (TCHAR *tmp = _tcschr(sttRJidBuf, _T('/'))) *tmp = 0; - - if (HANDLE hContact = HContactFromJID(him->szRealJid)) { - gcmi->Item[3].uType = MENU_HMENU; - gcmi->Item[3].dwID = CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); - sttShowGcMenuItems(gcmi, sttRJidItems, 0); - } - else { - gcmi->Item[3].uType = MENU_NEWPOPUP; - sttShowGcMenuItems(gcmi, sttRJidItems, MENU_POPUPITEM); - } - - sttSetupGcMenuItem(gcmi, IDM_CPY_RJID, FALSE); - } - else { - gcmi->Item[3].uType = 0; - sttShowGcMenuItems(gcmi, sttRJidItems, 0); - - sttSetupGcMenuItem(gcmi, IDM_CPY_RJID, TRUE); - } - - if (!force) { - if (me->role < ROLE_MODERATOR || (me->affiliation <= him->affiliation)) - sttSetupGcMenuItem(gcmi, IDM_KICK, TRUE); - - if ((me->affiliation < AFFILIATION_ADMIN) || - (me->affiliation == AFFILIATION_ADMIN) && (me->affiliation <= him->affiliation)) - sttSetupGcMenuItem(gcmi, IDM_SET_BAN, TRUE); - } - } - else { - sttSetupGcMenuItem(gcmi, 0, TRUE); - gcmi->Item[2].uType = 0; - sttShowGcMenuItems(gcmi, sttRJidItems, 0); - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Conference invitation dialog - -class CGroupchatInviteDlg : public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - struct JabberGcLogInviteDlgJidData - { - int hItem; - TCHAR jid[JABBER_MAX_JID_LEN]; - }; - - LIST m_newJids; - TCHAR *m_room; - - CCtrlButton m_btnInvite; - CCtrlEdit m_txtNewJid; - CCtrlMButton m_btnAddJid; - CCtrlEdit m_txtReason; - CCtrlClc m_clc; - - void FilterList(CCtrlClc *) - { - for (HANDLE hContact = db_find_first(); - hContact; - hContact = db_find_next(hContact)) - { - char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (lstrcmpA(proto, m_proto->m_szModuleName) || DBGetContactSettingByte(hContact, proto, "ChatRoom", 0)) - if (HANDLE hItem = m_clc.FindContact(hContact)) - m_clc.DeleteItem(hItem); - } } - - void ResetListOptions(CCtrlClc *) - { - m_clc.SetBkBitmap(0, NULL); - m_clc.SetBkColor(GetSysColor(COLOR_WINDOW)); - m_clc.SetGreyoutFlags(0); - m_clc.SetLeftMargin(4); - m_clc.SetIndent(10); - m_clc.SetHideEmptyGroups(1); - m_clc.SetHideOfflineRoot(1); - for (int i=0; i <= FONTID_MAX; i++) - m_clc.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT)); - } - - void InviteUser(TCHAR *pUser, TCHAR *text) - { - XmlNode msg( _T("message")); - HXML invite = msg << XATTR( _T("to"), m_room ) << XATTRID( m_proto->SerialNext()) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_MUC_USER)) - << XCHILD( _T("invite")) << XATTR( _T("to"), pUser ); - if ( text ) - invite << XCHILD( _T("reason"), text ); - - m_proto->m_ThreadInfo->send( msg ); - } - -public: - CGroupchatInviteDlg(CJabberProto* ppro, TCHAR *room) : - CSuper(ppro, IDD_GROUPCHAT_INVITE, NULL), - m_newJids(1), - m_btnInvite(this, IDC_INVITE), - m_txtNewJid(this, IDC_NEWJID), - m_btnAddJid(this, IDC_ADDJID, ppro->LoadIconEx("addroster"), "Add"), - m_txtReason(this, IDC_REASON), - m_clc(this, IDC_CLIST) - { - m_room = mir_tstrdup(room); - m_btnAddJid.OnClick = Callback( this, &CGroupchatInviteDlg::OnCommand_AddJid ); - m_btnInvite.OnClick = Callback( this, &CGroupchatInviteDlg::OnCommand_Invite ); - m_clc.OnNewContact = - m_clc.OnListRebuilt = Callback( this, &CGroupchatInviteDlg::FilterList ); - m_clc.OnOptionsChanged = Callback( this, &CGroupchatInviteDlg::ResetListOptions ); - } - - ~CGroupchatInviteDlg() - { - for (int i = 0; i < m_newJids.getCount(); ++i) - mir_free(m_newJids[i]); - mir_free(m_room); - } - - void OnInitDialog() - { - CSuper::OnInitDialog(); - - TCHAR buf[256]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s"), m_room, TranslateT("Send groupchat invitation.")); - SetDlgItemText(m_hwnd, IDC_HEADERBAR, buf); - WindowSetIcon(m_hwnd, m_proto, "group"); - - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE, - GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE)|CLS_HIDEOFFLINE|CLS_CHECKBOXES|CLS_HIDEEMPTYGROUPS|CLS_USEGROUPS|CLS_GREYALTERNATE|CLS_GROUPCHECKBOXES); - SendMessage(GetDlgItem(m_hwnd, IDC_CLIST), CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP|CLS_EX_TRACKSELECT, 0); - ResetListOptions(&m_clc); - FilterList(&m_clc); - } - - void OnCommand_AddJid( CCtrlButton* ) - { - TCHAR buf[JABBER_MAX_JID_LEN]; - m_txtNewJid.GetText(buf, SIZEOF(buf)); - m_txtNewJid.SetTextA(""); - - HANDLE hContact = m_proto->HContactFromJID(buf); - if ( hContact ) - { - int hItem = SendDlgItemMessage( m_hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0 ); - if ( hItem ) - SendDlgItemMessage( m_hwnd, IDC_CLIST, CLM_SETCHECKMARK, hItem, 1 ); - return; - } - - int i; - for (i = 0; i < m_newJids.getCount(); ++i) - if (!lstrcmp(m_newJids[i]->jid, buf)) - break; - if (i != m_newJids.getCount()) - return; - - JabberGcLogInviteDlgJidData *jidData = (JabberGcLogInviteDlgJidData *)mir_alloc(sizeof(JabberGcLogInviteDlgJidData)); - lstrcpy(jidData->jid, buf); - CLCINFOITEM cii = {0}; - cii.cbSize = sizeof(cii); - cii.flags = CLCIIF_CHECKBOX; - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%s)"), jidData->jid, TranslateT("not on roster")); - cii.pszText = buf; - jidData->hItem = SendDlgItemMessage(m_hwnd,IDC_CLIST,CLM_ADDINFOITEM,0,(LPARAM)&cii); - SendDlgItemMessage(m_hwnd, IDC_CLIST, CLM_SETCHECKMARK, jidData->hItem, 1); - m_newJids.insert(jidData); - } - - void OnCommand_Invite( CCtrlButton* ) - { - if (!m_room) return; - - TCHAR *text = m_txtReason.GetText(); - HWND hwndList = GetDlgItem(m_hwnd, IDC_CLIST); - - // invite users from roster - for (HANDLE hContact = db_find_first(); - hContact; - hContact = db_find_next(hContact)) - { - char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (!lstrcmpA(proto, m_proto->m_szModuleName) && !DBGetContactSettingByte(hContact, proto, "ChatRoom", 0)) - { - if (int hItem = SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0)) - { - if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) - { - DBVARIANT dbv={0}; - m_proto->JGetStringT(hContact, "jid", &dbv); - if (dbv.ptszVal && ( dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR )) - InviteUser(dbv.ptszVal, text); - JFreeVariant(&dbv); - } - } - } - } - - // invite others - for (int i = 0; i < m_newJids.getCount(); ++i) - if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)m_newJids[i]->hItem, 0)) - InviteUser(m_newJids[i]->jid, text); - - mir_free(text); - Close(); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Context menu processing - -void CJabberProto::AdminSet( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal ) -{ - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( szItem, itemVal ) << XATTR( var, varVal )); -} - -void CJabberProto::AdminSetReason( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal , const TCHAR* rsn) -{ m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( szItem, itemVal ) << XATTR( var, varVal ) << XCHILD( _T("reason"), rsn)); -} - -void CJabberProto::AdminGet( const TCHAR* to, const TCHAR* ns, const TCHAR* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo ) -{ - int id = SerialNext(); - IqAdd( id, IQ_PROC_NONE, foo ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), id, to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( var, varVal )); -} - -// Member info dialog -struct TUserInfoData -{ - CJabberProto* ppro; - JABBER_LIST_ITEM *item; - JABBER_RESOURCE_STATUS *me, *him; -}; - -static INT_PTR CALLBACK sttUserInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - TUserInfoData *dat = (TUserInfoData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch (msg) { - case WM_INITDIALOG: - { - int i, idx; - TCHAR buf[256]; - - TranslateDialogDefault(hwndDlg); - - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - dat = (TUserInfoData *)lParam; - - WindowSetIcon( hwndDlg, dat->ppro, "group" ); - - LOGFONT lf; - GetObject((HFONT)SendDlgItemMessage(hwndDlg, IDC_TXT_NICK, WM_GETFONT, 0, 0), sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - HFONT hfnt = CreateFontIndirect(&lf); - SendDlgItemMessage(hwndDlg, IDC_TXT_NICK, WM_SETFONT, (WPARAM)hfnt, TRUE); - - SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE)); - SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BUTTONADDTOOLTIP, (WPARAM)"Apply", 0); - - SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE)); - SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BUTTONADDTOOLTIP, (WPARAM)"Apply", 0); - - SendDlgItemMessage(hwndDlg, IDC_ICO_STATUS, STM_SETICON, (WPARAM)LoadSkinnedProtoIcon(dat->ppro->m_szModuleName, dat->him->status), 0); - - mir_sntprintf(buf, SIZEOF(buf), _T("%s %s"), TranslateT("Member Info:"), dat->him->resourceName); - SetWindowText(hwndDlg, buf); - - mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s %s %s"), TranslateT("Member Information"), dat->him->resourceName, TranslateT("from"), dat->item->jid); - SetDlgItemText(hwndDlg, IDC_HEADERBAR, buf); - - SetDlgItemText(hwndDlg, IDC_TXT_NICK, dat->him->resourceName); - SetDlgItemText(hwndDlg, IDC_TXT_JID, dat->him->szRealJid ? dat->him->szRealJid : TranslateT("Real JID not available")); - SetDlgItemText(hwndDlg, IDC_TXT_STATUS, dat->him->statusMessage); - - for (i = 0; i < SIZEOF(sttRoleItems); ++i) - { - if ((sttRoleItems[i].value == dat->him->role) || sttRoleItems[i].check(dat->me, dat->him)) - { - SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_SETITEMDATA, - idx = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_ADDSTRING, 0, (LPARAM)sttRoleItems[i].title), - sttRoleItems[i].value); - if (sttRoleItems[i].value == dat->him->role) - SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_SETCURSEL, idx, 0); - } - } - for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) - { - if ((sttAffiliationItems[i].value == dat->him->affiliation) || sttAffiliationItems[i].check(dat->me, dat->him)) - { - SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_SETITEMDATA, - idx = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_ADDSTRING, 0, (LPARAM)sttAffiliationItems[i].title), - sttAffiliationItems[i].value); - if (sttAffiliationItems[i].value == dat->him->affiliation) - SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_SETCURSEL, idx, 0); - } - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_ROLE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_AFFILIATION), FALSE); - - break; - } - - case WM_COMMAND: - if (!dat)break; - - switch ( LOWORD( wParam )) { - case IDCANCEL: - PostMessage(hwndDlg, WM_CLOSE, 0, 0); - break; - - case IDC_TXT_AFFILIATION: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - int value = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETITEMDATA, - SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETCURSEL, 0, 0), 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_AFFILIATION), dat->him->affiliation != value); - } - break; - - case IDC_BTN_AFFILIATION: - { - int value = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETITEMDATA, - SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETCURSEL, 0, 0), 0); - if (dat->him->affiliation == value) break; - - switch (value) - { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( dat->him->szRealJid, szBareJid, SIZEOF(szBareJid)); - case AFFILIATION_NONE: - if (dat->him->szRealJid) - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("none")); - else - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("none")); - break; - case AFFILIATION_MEMBER: - if (dat->him->szRealJid) - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("member")); - else - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("member")); - break; - case AFFILIATION_ADMIN: - if (dat->him->szRealJid) - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("admin")); - else - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("admin")); - break; - case AFFILIATION_OWNER: - if (dat->him->szRealJid) - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("owner")); - else - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("owner")); - break; - } - } - break; - - case IDC_TXT_ROLE: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - int value = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETITEMDATA, - SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETCURSEL, 0, 0), 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_ROLE), dat->him->role != value); - } - break; - - case IDC_BTN_ROLE: - { - int value = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETITEMDATA, - SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETCURSEL, 0, 0), 0); - if (dat->him->role == value) break; - - switch (value) { - case ROLE_VISITOR: - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("visitor")); - break; - case ROLE_PARTICIPANT: - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("participant")); - break; - case ROLE_MODERATOR: - dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("moderator")); - break; - } - } - break; - } - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - - case WM_DESTROY: - { - WindowFreeIcon( hwndDlg ); - g_ReleaseIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_BTN_AFFILIATION, BM_SETIMAGE, IMAGE_ICON, 0 )); - g_ReleaseIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_BTN_ROLE, BM_SETIMAGE, IMAGE_ICON, 0 )); - TUserInfoData *dat = (TUserInfoData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - if (!dat)break; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - mir_free(dat); - break; - } - } - return FALSE; -} - -static void sttNickListHook( CJabberProto* ppro, JABBER_LIST_ITEM* item, GCHOOK* gch ) -{ - JABBER_RESOURCE_STATUS *me = NULL, *him = NULL; - for ( int i=0; i < item->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& p = item->resource[i]; - if ( !lstrcmp( p.resourceName, item->nick )) me = &p; - if ( !lstrcmp( p.resourceName, gch->ptszUID )) him = &p; - } - - if ( him == NULL || me == NULL ) - return; - - // 1 kick per second, prevents crashes... - enum { BAN_KICK_INTERVAL = 1000 }; - static DWORD dwLastBanKickTime = 0; - - TCHAR szBuffer[1024]; - TCHAR szTitle[256]; - - if ((gch->dwData >= CLISTMENUIDMIN) && (gch->dwData <= CLISTMENUIDMAX)) - { - if (him->szRealJid && *him->szRealJid) - if (HANDLE hContact = ppro->HContactFromJID(him->szRealJid)) - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(gch->dwData, MPCF_CONTACTMENU), (LPARAM)hContact); - return; - } - - switch( gch->dwData ) { - case IDM_SLAP: - { - if ( ppro->m_bJabberOnline ) { - DBVARIANT dbv = {0}; - TCHAR *szMessage = DBGetContactSettingTString( NULL, ppro->m_szModuleName, "GcMsgSlap", &dbv) ? - NEWTSTR_ALLOCA(TranslateTS(JABBER_GC_MSG_SLAP)) : dbv.ptszVal; - - TCHAR buf[256]; - // do not use snprintf to avoid possible problems with % symbol - if (TCHAR *p = _tcsstr(szMessage, _T("%s"))) { - *p = 0; - mir_sntprintf(buf, SIZEOF(buf), _T("%s%s%s"), szMessage, him->resourceName, p+2); - } - else lstrcpyn(buf, szMessage, SIZEOF(buf)); - UnEscapeChatTags( buf ); - - ppro->m_ThreadInfo->send( - XmlNode( _T("message")) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("groupchat")) - << XCHILD( _T("body"), buf )); - - if (szMessage == dbv.ptszVal) - DBFreeVariant(&dbv); - } - break; - } - case IDM_VCARD: - { - HANDLE hContact; - JABBER_SEARCH_RESULT jsr = {0}; - mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s/%s"), item->jid, him->resourceName ); - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - - JABBER_LIST_ITEM* item = ppro->ListAdd( LIST_VCARD_TEMP, jsr.jid ); - item->bUseResource = TRUE; - ppro->ListAddResource( LIST_VCARD_TEMP, jsr.jid, him->status, him->statusMessage, him->priority ); - - hContact = ( HANDLE )CallProtoService( ppro->m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); - CallService( MS_USERINFO_SHOWDIALOG, ( WPARAM )hContact, 0 ); - break; - } - case IDM_INFO: - { - TUserInfoData *dat = (TUserInfoData *)mir_alloc(sizeof(TUserInfoData)); - dat->me = me; - dat->him = him; - dat->item = item; - dat->ppro = ppro; - HWND hwndInfo = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_GROUPCHAT_INFO), NULL, sttUserInfoDlgProc, (LPARAM)dat); - ShowWindow(hwndInfo, SW_SHOW); - break; - } - case IDM_KICK: - { - if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) - { - dwLastBanKickTime = GetTickCount(); - mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s: "), me->resourceName ); - mir_sntprintf( szTitle, SIZEOF(szTitle), _T("%s %s"), TranslateT( "Reason to kick" ), him->resourceName ); - TCHAR *resourceName_copy = mir_tstrdup(him->resourceName); // copy resource name to prevent possible crash if user list rebuilds - if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE, "gcReason_" )) - ppro->m_ThreadInfo->send( - XmlNodeIq( _T("set"), ppro->SerialNext(), item->jid ) << XQUERY( xmlnsAdmin ) - << XCHILD( _T("item")) << XATTR( _T("nick"), resourceName_copy ) << XATTR( _T("role"), _T("none")) - << XCHILD( _T("reason"), szBuffer )); - - mir_free(resourceName_copy); - } - dwLastBanKickTime = GetTickCount(); - break; - } - - case IDM_SET_VISITOR: - if (him->role != ROLE_VISITOR) - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("visitor")); - break; - case IDM_SET_PARTICIPANT: - if (him->role != ROLE_PARTICIPANT) - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("participant")); - break; - case IDM_SET_MODERATOR: - if (him->role != ROLE_MODERATOR) - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("moderator")); - break; - - case IDM_SET_NONE: - if (him->affiliation != AFFILIATION_NONE) - { - if (him->szRealJid) - { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); - ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("none")); - } - else - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("none")); - } - break; - case IDM_SET_MEMBER: - if (him->affiliation != AFFILIATION_MEMBER) - { - if (him->szRealJid) - { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); - ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("member")); - } - else - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("member")); - } - break; - case IDM_SET_ADMIN: - if (him->affiliation != AFFILIATION_ADMIN) - { - if (him->szRealJid) - { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); - ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("admin")); - } - else - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("admin")); - } - break; - case IDM_SET_OWNER: - if (him->affiliation != AFFILIATION_OWNER) - { - if (him->szRealJid) - { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); - ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("owner")); - } - else - ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("owner")); - } - break; - - case IDM_SET_BAN: - if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) { - if ( him->szRealJid && *him->szRealJid ) { - TCHAR szVictimBareJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( him->szRealJid, szVictimBareJid, SIZEOF(szVictimBareJid)); - - mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s: "), me->resourceName ); - mir_sntprintf( szTitle, SIZEOF(szTitle), _T("%s %s"), TranslateT( "Reason to ban" ), him->resourceName ); - - if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE, "gcReason_" )) { - ppro->m_ThreadInfo->send( - XmlNodeIq( _T("set"), ppro->SerialNext(), item->jid ) << XQUERY( xmlnsAdmin ) - << XCHILD( _T("item")) << XATTR( _T("jid"), szVictimBareJid ) << XATTR( _T("affiliation"), _T("outcast")) - << XCHILD( _T("reason"), szBuffer )); - } - } - } - dwLastBanKickTime = GetTickCount(); - break; - - case IDM_LINK0: case IDM_LINK1: case IDM_LINK2: case IDM_LINK3: case IDM_LINK4: - case IDM_LINK5: case IDM_LINK6: case IDM_LINK7: case IDM_LINK8: case IDM_LINK9: - { - if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) - { - TCHAR *resourceName_copy = NEWTSTR_ALLOCA(him->resourceName); // copy resource name to prevent possible crash if user list rebuilds - - TCHAR *szInviteTo = 0; - int idx = gch->dwData - IDM_LINK0; - LISTFOREACH(i, ppro, LIST_CHATROOM) - if (JABBER_LIST_ITEM *item = ppro->ListGetItemPtrFromIndex(i)) - if (!idx--) - { - szInviteTo = item->jid; - break; - } - - if (!szInviteTo) break; - - mir_sntprintf( szTitle, SIZEOF(szTitle), TranslateT("Invite %s to %s"), him->resourceName, szInviteTo ); - *szBuffer = 0; - if (!ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE)) - break; - - mir_sntprintf(szTitle, SIZEOF(szTitle), _T("%s/%s"), item->jid, resourceName_copy); - - XmlNode msg( _T("message")); - HXML invite = msg << XATTR( _T("to"), szTitle ) << XATTRID(ppro->SerialNext()) - << XCHILD(_T("x"), szBuffer) - << XATTR(_T("xmlns"), _T("jabber:x:conference")) - << XATTR( _T("jid"), szInviteTo ) - << XCHILD(_T("invite")) << XATTR(_T("from"), item->nick); - ppro->m_ThreadInfo->send( msg ); - } - dwLastBanKickTime = GetTickCount(); - break; - } - - case IDM_CPY_NICK: - JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), him->resourceName); - break; - case IDM_RJID_COPY: - case IDM_CPY_RJID: - JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), him->szRealJid); - break; - case IDM_CPY_INROOMJID: - mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s/%s"), item->jid, him->resourceName); - JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), szBuffer); - break; - - case IDM_RJID_VCARD: - if (him->szRealJid && *him->szRealJid) - { - HANDLE hContact; - JABBER_SEARCH_RESULT jsr ={0}; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s"), him->szRealJid); - if (TCHAR *tmp = _tcschr(jsr.jid, _T('/'))) *tmp = 0; - - JABBER_LIST_ITEM* item = ppro->ListAdd( LIST_VCARD_TEMP, jsr.jid ); - item->bUseResource = TRUE; - ppro->ListAddResource( LIST_VCARD_TEMP, jsr.jid, him->status, him->statusMessage, him->priority ); - - hContact = ( HANDLE )CallProtoService( ppro->m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); - CallService( MS_USERINFO_SHOWDIALOG, ( WPARAM )hContact, 0 ); - break; - } - - case IDM_RJID_ADD: - if (him->szRealJid && *him->szRealJid) - { - JABBER_SEARCH_RESULT jsr={0}; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - jsr.hdr.flags = PSR_TCHAR; - mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s"), him->szRealJid); - if (TCHAR *tmp = _tcschr(jsr.jid, _T('/'))) *tmp = 0; - jsr.hdr.nick = jsr.jid; - - ADDCONTACTSTRUCT acs={0}; - acs.handleType = HANDLE_SEARCHRESULT; - acs.szProto = ppro->m_szModuleName; - acs.psr = (PROTOSEARCHRESULT *)&jsr; - CallService(MS_ADDCONTACT_SHOW, (WPARAM)CallService(MS_CLUI_GETHWND, 0, 0), (LPARAM)&acs); - break; - } - } -} - -static void sttLogListHook( CJabberProto* ppro, JABBER_LIST_ITEM* item, GCHOOK* gch ) -{ - TCHAR szBuffer[ 1024 ]; - TCHAR szCaption[ 1024 ]; - szBuffer[ 0 ] = _T('\0'); - - switch( gch->dwData ) { - case IDM_LST_PARTICIPANT: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("role"), _T("participant"), &CJabberProto::OnIqResultMucGetVoiceList ); - break; - - case IDM_LST_MEMBER: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("member"), &CJabberProto::OnIqResultMucGetMemberList ); - break; - - case IDM_LST_MODERATOR: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("role"), _T("moderator"), &CJabberProto::OnIqResultMucGetModeratorList ); - break; - - case IDM_LST_BAN: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList ); - break; - - case IDM_LST_ADMIN: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("admin"), &CJabberProto::OnIqResultMucGetAdminList ); - break; - - case IDM_LST_OWNER: - ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("owner"), &CJabberProto::OnIqResultMucGetOwnerList ); - break; - - case IDM_TOPIC: - mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s %s"), TranslateT( "Set topic for" ), gch->pDest->ptszID ); - TCHAR szTmpBuff[ SIZEOF(szBuffer) * 2 ]; - if ( item->itemResource.statusMessage ) { - int j = 0; - for ( int i = 0; i < SIZEOF(szTmpBuff); i++ ) { - if ( item->itemResource.statusMessage[ i ] != _T('\n') || ( i && item->itemResource.statusMessage[ i - 1 ] == _T('\r'))) - szTmpBuff[ j++ ] = item->itemResource.statusMessage[ i ]; - else { - szTmpBuff[ j++ ] = _T('\r'); - szTmpBuff[ j++ ] = _T('\n'); - } - if ( !item->itemResource.statusMessage[ i ] ) - break; - } - } - else szTmpBuff[ 0 ] = _T('\0'); - - if ( ppro->EnterString( szTmpBuff, SIZEOF(szTmpBuff), szCaption, JES_RICHEDIT, "gcTopic_" )) - ppro->m_ThreadInfo->send( - XmlNode( _T("message")) << XATTR( _T("to"), gch->pDest->ptszID ) << XATTR( _T("type"), _T("groupchat")) - << XCHILD( _T("subject"), szTmpBuff )); - - break; - - case IDM_NICK: - mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s %s"), TranslateT( "Change nickname in" ), gch->pDest->ptszID ); - if ( item->nick ) - mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s"), item->nick ); - if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szCaption, JES_COMBO, "gcNick_" )) { - JABBER_LIST_ITEM* item = ppro->ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); - if ( item != NULL ) { - TCHAR text[ 1024 ]; - mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), gch->pDest->ptszID, szBuffer ); - ppro->SendPresenceTo( ppro->m_iStatus == ID_STATUS_INVISIBLE ? ID_STATUS_ONLINE : ppro->m_iStatus, text, NULL ); - } } - break; - - case IDM_INVITE: - { - CGroupchatInviteDlg *dlg = new CGroupchatInviteDlg( ppro, gch->pDest->ptszID ); - dlg->Show(); - break; - } - - case IDM_CONFIG: - { - int iqId = ppro->SerialNext(); - ppro->IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); - - XmlNodeIq iq( _T("get"), iqId, gch->pDest->ptszID ); - iq << XQUERY( xmlnsOwner ); - ppro->m_ThreadInfo->send( iq ); - break; - } - case IDM_BOOKMARKS: - { - JABBER_LIST_ITEM* item = ppro->ListGetItemPtr( LIST_BOOKMARK, gch->pDest->ptszID ); - if ( item == NULL ) { - item = ppro->ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); - if (item != NULL) { - item->type = _T("conference"); - HANDLE hContact = ppro->HContactFromJID( item->jid ); - item->name = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR ); - ppro->AddEditBookmark( item ); - } - } - break; - } - case IDM_DESTROY: - mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to destroy" ), gch->pDest->ptszID ); - if ( !ppro->EnterString(szBuffer, SIZEOF(szBuffer), NULL, JES_MULTINE, "gcReason_" )) - break; - - ppro->m_ThreadInfo->send( - XmlNodeIq( _T("set"), ppro->SerialNext(), gch->pDest->ptszID ) << XQUERY( xmlnsOwner ) - << XCHILD( _T("destroy")) << XCHILD( _T("reason"), szBuffer )); - - case IDM_LEAVE: - ppro->GcQuit( item, 0, NULL ); - break; - - case IDM_PRESENCE_ONLINE: - case IDM_PRESENCE_AWAY: - case IDM_PRESENCE_NA: - case IDM_PRESENCE_DND: - case IDM_PRESENCE_FREE4CHAT: - { - if ( HANDLE h = ppro->HContactFromJID( item->jid )) - ppro->OnMenuHandleDirectPresence( (WPARAM)h, 0, gch->dwData ); - break; - } - - - case IDM_LINK0: case IDM_LINK1: case IDM_LINK2: case IDM_LINK3: case IDM_LINK4: - case IDM_LINK5: case IDM_LINK6: case IDM_LINK7: case IDM_LINK8: case IDM_LINK9: - { - unsigned idx = IDM_LINK0; - for (TCHAR *p = _tcsstr(item->itemResource.statusMessage, _T("http://")); p && *p; p = _tcsstr(p+1, _T("http://"))) - { - if (idx == gch->dwData) - { - char *bufPtr, *url = mir_t2a(p); - for (bufPtr = url; *bufPtr && !isspace(*bufPtr); ++bufPtr) ; - *bufPtr++ = 0; - CallService(MS_UTILS_OPENURL, 1, (LPARAM)url); - mir_free(url); - break; - } - - if (++idx > IDM_LINK9) break; - } - - break; - } - - case IDM_CPY_RJID: - JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), item->jid); - break; - case IDM_CPY_TOPIC: - JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), item->itemResource.statusMessage); - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Sends a private message to a chat user - -static void sttSendPrivateMessage( CJabberProto* ppro, JABBER_LIST_ITEM* item, const TCHAR* nick ) -{ - TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; - mir_sntprintf( szFullJid, SIZEOF(szFullJid), _T("%s/%s"), item->jid, nick ); - HANDLE hContact = ppro->DBCreateContact( szFullJid, NULL, TRUE, FALSE ); - if ( hContact != NULL ) { - for ( int i=0; i < item->resourceCount; i++ ) { - if ( _tcsicmp( item->resource[i].resourceName, nick ) == 0 ) { - ppro->JSetWord( hContact, "Status", item->resource[i].status ); - break; - } } - - DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 ); - ppro->JSetStringT( hContact, "Nick", nick ); - DBWriteContactSettingDword( hContact, "Ignore", "Mask1", 0 ); - CallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact, 0 ); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// General chat event processing hook - -int CJabberProto::JabberGcEventHook(WPARAM, LPARAM lParam) -{ - GCHOOK* gch = ( GCHOOK* )lParam; - if ( gch == NULL ) - return 0; - - if ( lstrcmpiA( gch->pDest->pszModule, m_szModuleName )) - return 0; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); - if ( item == NULL ) - return 0; - - switch ( gch->pDest->iType ) { - case GC_USER_MESSAGE: - if ( gch->pszText && lstrlen( gch->ptszText) > 0 ) { - trtrim( gch->ptszText ); - - if ( m_bJabberOnline ) { - TCHAR* buf = NEWTSTR_ALLOCA(gch->ptszText); - UnEscapeChatTags( buf ); - m_ThreadInfo->send( - XmlNode( _T("message")) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("groupchat")) - << XCHILD( _T("body"), buf )); - } } - break; - - case GC_USER_PRIVMESS: - sttSendPrivateMessage( this, item, gch->ptszUID ); - break; - - case GC_USER_LOGMENU: - sttLogListHook( this, item, gch ); - break; - - case GC_USER_NICKLISTMENU: - sttNickListHook( this, item, gch ); - break; - - case GC_USER_CHANMGR: - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, item->jid ) << XQUERY( xmlnsOwner )); - break; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// -void CJabberProto::AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str , TCHAR* rsn) -{ - const TCHAR* field = ( jidListInfo->type == MUC_BANLIST || _tcschr(str,'@')) ? _T("jid") : _T("nick"); - TCHAR* roomJid = jidListInfo->roomJid; - if ( jidListInfo->type == MUC_BANLIST ) { - AdminSetReason( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("outcast"), rsn); - AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList); -} } - -void CJabberProto::AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str ) -{ - const TCHAR* field = ( jidListInfo->type == MUC_BANLIST || _tcschr(str,'@')) ? _T("jid") : _T("nick"); - TCHAR* roomJid = jidListInfo->roomJid; - - switch (jidListInfo->type) { - case MUC_VOICELIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("role"), _T("participant")); - AdminGet( roomJid, xmlnsAdmin, _T("role"), _T("participant"), &CJabberProto::OnIqResultMucGetVoiceList); - break; - case MUC_MEMBERLIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("member")); - AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("member"), &CJabberProto::OnIqResultMucGetMemberList); - break; - case MUC_MODERATORLIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("role"), _T("moderator")); - AdminGet( roomJid, xmlnsAdmin, _T("role"), _T("moderator"), &CJabberProto::OnIqResultMucGetModeratorList); - break; - case MUC_BANLIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("outcast")); - AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList); - break; - case MUC_ADMINLIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("admin")); - AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("admin"), &CJabberProto::OnIqResultMucGetAdminList); - break; - case MUC_OWNERLIST: - AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("owner")); - AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("owner"), &CJabberProto::OnIqResultMucGetOwnerList); - break; -} } - -void CJabberProto::DeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid ) -{ - TCHAR* roomJid = jidListInfo->roomJid; - - switch ( jidListInfo->type ) { - case MUC_VOICELIST: // change role to visitor ( from participant ) - AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("role"), _T("visitor")); - break; - case MUC_BANLIST: // change affiliation to none ( from outcast ) - case MUC_MEMBERLIST: // change affiliation to none ( from member ) - AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("none")); - break; - case MUC_MODERATORLIST: // change role to participant ( from moderator ) - AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("role"), _T("participant")); - break; - case MUC_ADMINLIST: // change affiliation to member ( from admin ) - AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("member")); - break; - case MUC_OWNERLIST: // change affiliation to admin ( from owner ) - AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("admin")); - break; -} } diff --git a/protocols/JabberG/jabber_console.cpp b/protocols/JabberG/jabber_console.cpp deleted file mode 100644 index ca2c82b3e4..0000000000 --- a/protocols/JabberG/jabber_console.cpp +++ /dev/null @@ -1,716 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2007 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include - -#define JCPF_IN 0x01UL -#define JCPF_OUT 0x02UL -#define JCPF_ERROR 0x04UL - -#define JCPF_TCHAR 0x00UL - -#define WM_CREATECONSOLE WM_USER+1000 - -#ifndef SES_EXTENDBACKCOLOR -#define SES_EXTENDBACKCOLOR 4 -#endif - -/* increment buffer with 1K steps */ -#define STRINGBUF_INCREMENT 1024 - -struct StringBuf -{ - char *buf; - int size; - int offset; - int streamOffset; -}; - -static void sttAppendBufRaw(StringBuf *buf, const char *str); -static void sttAppendBufW(StringBuf *buf, const WCHAR *str); -#define sttAppendBufT(a,b) (sttAppendBufW((a),(b))) -static void sttEmptyBuf(StringBuf *buf); - -#define RTF_HEADER \ - "{\\rtf1\\ansi{\\colortbl;" \ - "\\red128\\green0\\blue0;" \ - "\\red0\\green0\\blue128;" \ - "\\red245\\green255\\blue245;" \ - "\\red245\\green245\\blue255;" \ - "\\red128\\green128\\blue128;" \ - "\\red255\\green235\\blue235;" \ - "}" -#define RTF_FOOTER "}" -#define RTF_BEGINTAG "\\pard " -#define RTF_INDENT_FMT "\\fi-100\\li%d " -#define RTF_ENDTAG "\\par" -#define RTF_BEGINTAGNAME "\\cf1\\b " -#define RTF_ENDTAGNAME "\\cf0\\b0 " -#define RTF_BEGINATTRNAME "\\cf2\\b " -#define RTF_ENDATTRNAME "\\cf0\\b0 " -#define RTF_BEGINATTRVAL "\\b0 " -#define RTF_ENDATTRVAL "" -#define RTF_BEGINTEXT "\\pard " -#define RTF_TEXTINDENT_FMT "\\fi0\\li%d " -#define RTF_ENDTEXT "\\par" -#define RTF_BEGINPLAINXML "\\pard\\fi0\\li100\\highlight6\\cf0 " -#define RTF_ENDPLAINXML "\\par" -#define RTF_SEPARATOR "\\sl-1\\slmult0\\highlight5\\cf5\\-\\par\\sl0" - -static void sttRtfAppendXml(StringBuf *buf, HXML node, DWORD flags, int indent); - -void CJabberProto::OnConsoleProcessXml(HXML node, DWORD flags) -{ - if ( node && m_pDlgConsole ) { - if ( xmlGetName( node )) { - if ( FilterXml( node, flags )) { - StringBuf buf = {0}; - sttAppendBufRaw(&buf, RTF_HEADER); - sttRtfAppendXml(&buf, node, flags, 1); - sttAppendBufRaw(&buf, RTF_SEPARATOR); - sttAppendBufRaw(&buf, RTF_FOOTER); - SendMessage(m_pDlgConsole->GetHwnd(), WM_JABBER_REFRESH, 0, (LPARAM)&buf); - sttEmptyBuf(&buf); - } - } - else { - for ( int i = 0; i < xmlGetChildCount( node ); i++ ) - OnConsoleProcessXml( xmlGetChild( node, i), flags ); - } - } -} - -bool CJabberProto::RecursiveCheckFilter(HXML node, DWORD flags) -{ - int i; - - for (i = 0; i < xmlGetAttrCount(node); ++i) - { - if ( JabberStrIStr( xmlGetAttr( node,i ), m_filterInfo.pattern )) - return true; - } - - for (i = 0; i < xmlGetChildCount( node ); ++i) { - if (RecursiveCheckFilter( xmlGetChild( node, i ), flags)) - return true; - } - - return false; -} - -bool CJabberProto::FilterXml(HXML node, DWORD flags) -{ - if (!m_filterInfo.msg && !lstrcmp(xmlGetName( node ), _T("message"))) return false; - if (!m_filterInfo.presence && !lstrcmp(xmlGetName( node ), _T("presence"))) return false; - if (!m_filterInfo.iq && !lstrcmp(xmlGetName( node ), _T("iq"))) return false; - if (m_filterInfo.type == TFilterInfo::T_OFF) return true; - - bool result = false; - EnterCriticalSection(&m_filterInfo.csPatternLock); - - switch (m_filterInfo.type) - { - case TFilterInfo::T_JID: - { - const TCHAR *attrValue = xmlGetAttrValue( node,(flags&JCPF_OUT)?_T("to"):_T("from")); - if (!attrValue) break; - - result = JabberStrIStr(attrValue, m_filterInfo.pattern) ? true : false; - break; - } - case TFilterInfo::T_XMLNS: - { - if ( !xmlGetChildCount( node )) break; - - const TCHAR *attrValue = xmlGetAttrValue( xmlGetChild( node, 0 ), _T("xmlns")); - if ( !attrValue ) - break; - - result = JabberStrIStr(attrValue, m_filterInfo.pattern) ? true : false; - break; - } - - case TFilterInfo::T_ANY: - { - result = RecursiveCheckFilter(node, flags); - break; - } - } - - LeaveCriticalSection(&m_filterInfo.csPatternLock); - return result; -} - -static void sttAppendBufRaw(StringBuf *buf, const char *str) -{ - if (!str) return; - - int length = lstrlenA(str); - if (buf->size - buf->offset < length+1) - { - buf->size += (length + STRINGBUF_INCREMENT); - buf->buf = (char *)mir_realloc(buf->buf, buf->size); - } - lstrcpyA(buf->buf + buf->offset, str); - buf->offset += length; -} - -static void sttAppendBufW(StringBuf *buf, const WCHAR *str) -{ - char tmp[32]; - - if (!str) return; - - sttAppendBufRaw(buf, "{\\uc1 "); - for (const WCHAR *p = str; *p; ++p) - { - if ((*p == '\\') || (*p == '{') || (*p == '}')) - { - tmp[0] = '\\'; - tmp[1] = (char)*p; - tmp[2] = 0; - } else - if (*p < 128) - { - tmp[0] = (char)*p; - tmp[1] = 0; - } else - { - mir_snprintf(tmp, sizeof(tmp), "\\u%d ?", (int)*p); - } - sttAppendBufRaw(buf, tmp); - } - sttAppendBufRaw(buf, "}"); -} - -static void sttEmptyBuf(StringBuf *buf) -{ - if (buf->buf) mir_free(buf->buf); - buf->buf = 0; - buf->size = 0; - buf->offset = 0; -} - -static void sttRtfAppendXml(StringBuf *buf, HXML node, DWORD flags, int indent) -{ - int i; - char *indentLevel = (char *)mir_alloc(128); - mir_snprintf(indentLevel, 128, RTF_INDENT_FMT, - (int)(indent*200) - ); - - sttAppendBufRaw(buf, RTF_BEGINTAG); - sttAppendBufRaw(buf, indentLevel); - if (flags&JCPF_IN) sttAppendBufRaw(buf, "\\highlight3 "); - if (flags&JCPF_OUT) sttAppendBufRaw(buf, "\\highlight4 "); - sttAppendBufRaw(buf, "<"); - sttAppendBufRaw(buf, RTF_BEGINTAGNAME); - sttAppendBufW(buf, (TCHAR*)xmlGetName( node )); - sttAppendBufRaw(buf, RTF_ENDTAGNAME); - - for (i = 0; i < xmlGetAttrCount( node); i++) - { - TCHAR* attr = ( TCHAR* )xmlGetAttrName( node, i ); - sttAppendBufRaw(buf, " "); - sttAppendBufRaw(buf, RTF_BEGINATTRNAME); - sttAppendBufW(buf, attr); - sttAppendBufRaw(buf, RTF_ENDATTRNAME); - sttAppendBufRaw(buf, "=\""); - sttAppendBufRaw(buf, RTF_BEGINATTRVAL); - sttAppendBufT(buf, ( TCHAR* )xmlGetAttr( node, i)); - sttAppendBufRaw(buf, "\""); - sttAppendBufRaw(buf, RTF_ENDATTRVAL); - } - - if ( xmlGetChild( node ) || xmlGetText( node )) - { - sttAppendBufRaw(buf, ">"); - if ( xmlGetChild( node )) - sttAppendBufRaw(buf, RTF_ENDTAG); - } - - if (xmlGetText( node )) - { - if ( xmlGetChildCount( node )) - { - sttAppendBufRaw(buf, RTF_BEGINTEXT); - char *indentTextLevel = (char *)mir_alloc(128); - mir_snprintf( indentTextLevel, 128, RTF_TEXTINDENT_FMT, (int)(( indent + 1) * 200 )); - sttAppendBufRaw(buf, indentTextLevel); - mir_free(indentTextLevel); - } - - sttAppendBufT(buf, xmlGetText( node )); - if ( xmlGetChild( node )) - sttAppendBufRaw(buf, RTF_ENDTEXT); - } - - for (i = 0; i < xmlGetChildCount( node ) ; ++i) - sttRtfAppendXml(buf, xmlGetChild( node ,i), flags & ~(JCPF_IN|JCPF_OUT), indent+1); - - if (xmlGetChildCount( node ) || xmlGetText( node )) - { - sttAppendBufRaw(buf, RTF_BEGINTAG); - sttAppendBufRaw(buf, indentLevel); - sttAppendBufRaw(buf, ""); - } else - { - sttAppendBufRaw(buf, " />"); - } - - sttAppendBufRaw(buf, RTF_ENDTAG); - mir_free(indentLevel); -} - -DWORD CALLBACK sttStreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) -{ - StringBuf *buf = (StringBuf *)dwCookie; - *pcb = 0; - - if (buf->streamOffset < buf->offset) - { - *pcb = min(cb, buf->offset - buf->streamOffset); - memcpy(pbBuff, buf->buf + buf->streamOffset, *pcb); - buf->streamOffset += *pcb; - } - - return 0; -} - -static void sttJabberConsoleRebuildStrings(CJabberProto* ppro, HWND hwndCombo) -{ - int i; - JABBER_LIST_ITEM *item = NULL; - - int len = GetWindowTextLength(hwndCombo) + 1; - TCHAR *buf = (TCHAR *)_alloca(len * sizeof(TCHAR)); - GetWindowText(hwndCombo, buf, len); - - SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); - - for (i = 0; g_JabberFeatCapPairs[i].szFeature; ++i) - SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)g_JabberFeatCapPairs[i].szFeature); - for (i = 0; g_JabberFeatCapPairsExt[i].szFeature; ++i) - SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)g_JabberFeatCapPairsExt[i].szFeature); - - LISTFOREACH_NODEF(i, ppro, LIST_ROSTER) - if (item = ppro->ListGetItemPtrFromIndex(i)) - SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)item->jid); - LISTFOREACH_NODEF(i, ppro, LIST_CHATROOM) - if (item = ppro->ListGetItemPtrFromIndex(i)) - SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)item->jid); - - SetWindowText(hwndCombo, buf); -} - -/////////////////////////////////////////////////////////////////////////////// -// CJabberDlgConsole class -static struct -{ - int type; - TCHAR *title; - char *icon; -} filter_modes[] = -{ - { TFilterInfo::T_JID, _T("JID"), "main" }, - { TFilterInfo::T_XMLNS, _T("xmlns"), "xmlconsole" }, - { TFilterInfo::T_ANY, _T("all attributes"), "sd_filter_apply" }, - { TFilterInfo::T_OFF, _T("disabled"), "sd_filter_reset" }, -}; - -class CJabberDlgConsole: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgConsole(CJabberProto *proto); - -protected: - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - void OnProtoRefresh(WPARAM wParam, LPARAM lParam); - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - int Resizer(UTILRESIZECONTROL *urc); -}; - -CJabberDlgConsole::CJabberDlgConsole(CJabberProto *proto): - CJabberDlgBase(proto, IDD_CONSOLE, NULL) -{ -} - -void CJabberDlgConsole::OnInitDialog() -{ - CSuper::OnInitDialog(); - - int i; - - WindowSetIcon( m_hwnd, m_proto, "xmlconsole" ); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXLIMITTEXT, 0, 0x80000000); - - m_proto->m_filterInfo.msg = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_msg", TRUE); - m_proto->m_filterInfo.presence = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_presence", TRUE); - m_proto->m_filterInfo.iq = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_iq", TRUE); - m_proto->m_filterInfo.type = (TFilterInfo::Type)DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_ftype", TFilterInfo::T_OFF); - - DBVARIANT dbv; - *m_proto->m_filterInfo.pattern = 0; - if ( !m_proto->JGetStringT(NULL, "consoleWnd_fpattern", &dbv)) { - lstrcpyn(m_proto->m_filterInfo.pattern, dbv.ptszVal, SIZEOF(m_proto->m_filterInfo.pattern)); - JFreeVariant(&dbv); - } - - sttJabberConsoleRebuildStrings(m_proto, GetDlgItem(m_hwnd, IDC_CB_FILTER)); - SetWindowText(GetDlgItem(m_hwnd, IDC_CB_FILTER), m_proto->m_filterInfo.pattern); - - static struct - { - int idc; - char *title; - char *icon; - bool push; - BOOL pushed; - } buttons[] = - { - {IDC_BTN_MSG, "Messages", "pl_msg_allow", true, m_proto->m_filterInfo.msg}, - {IDC_BTN_PRESENCE, "Presences", "pl_prin_allow", true, m_proto->m_filterInfo.presence}, - {IDC_BTN_IQ, "Queries", "pl_iq_allow", true, m_proto->m_filterInfo.iq}, - {IDC_BTN_FILTER, "Filter mode", "sd_filter_apply", true, FALSE}, - {IDC_BTN_FILTER_REFRESH, "Refresh list", "sd_nav_refresh", false, FALSE}, - }; - for (i = 0; i < SIZEOF(buttons); ++i) - { - SendDlgItemMessage(m_hwnd, buttons[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(buttons[i].icon)); - SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONADDTOOLTIP, (WPARAM)buttons[i].title, 0); - if (buttons[i].push) SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONSETASPUSHBTN, TRUE, 0); - if (buttons[i].pushed) CheckDlgButton(m_hwnd, buttons[i].idc, TRUE); - } - - for (i = 0; i < SIZEOF(filter_modes); ++i) - if (filter_modes[i].type == m_proto->m_filterInfo.type) - { - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon))); - SendDlgItemMessage(m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon)); - break; - } - EnableWindow(GetDlgItem(m_hwnd, IDC_CB_FILTER), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTER_REFRESH), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "consoleWnd_"); -} - -void CJabberDlgConsole::OnClose() -{ - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_msg", m_proto->m_filterInfo.msg); - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_presence", m_proto->m_filterInfo.presence); - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_iq", m_proto->m_filterInfo.iq); - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_ftype", m_proto->m_filterInfo.type); - m_proto->JSetStringT(NULL, "consoleWnd_fpattern", m_proto->m_filterInfo.pattern); - - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "consoleWnd_"); - DestroyWindow(m_hwnd); - CSuper::OnClose(); -} - -void CJabberDlgConsole::OnDestroy() -{ - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_MSG, BM_SETIMAGE, IMAGE_ICON, 0 )); - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_PRESENCE, BM_SETIMAGE, IMAGE_ICON, 0 )); - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_IQ, BM_SETIMAGE, IMAGE_ICON, 0 )); - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, 0 )); - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER_REFRESH, BM_SETIMAGE, IMAGE_ICON, 0 )); - - m_proto->m_pDlgConsole = NULL; - CSuper::OnDestroy(); -} - -void CJabberDlgConsole::OnProtoRefresh(WPARAM, LPARAM lParam) -{ - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_SETREDRAW, FALSE, 0); - - StringBuf *buf = (StringBuf *)lParam; - buf->streamOffset = 0; - - EDITSTREAM es = {0}; - es.dwCookie = (DWORD_PTR)buf; - es.pfnCallback = sttStreamInCallback; - - SCROLLINFO si = {0}; - si.cbSize = sizeof(si); - si.fMask = SIF_ALL; - GetScrollInfo(GetDlgItem(m_hwnd, IDC_CONSOLE), SB_VERT, &si); - - CHARRANGE oldSel, sel; - POINT ptScroll; - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_GETSCROLLPOS, 0, (LPARAM)&ptScroll); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXGETSEL, 0, (LPARAM)&oldSel); - sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLE)); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&sel); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_STREAMIN, SF_RTF|SFF_SELECTION, (LPARAM)&es); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&oldSel); - - // magic expression from tabsrmm :) - if ((UINT)si.nPos >= (UINT)si.nMax-si.nPage-5 || si.nMax-si.nMin-si.nPage < 50) - { - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); - sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLE)); - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&sel); - } else - { - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_SETSCROLLPOS, 0, (LPARAM)&ptScroll); - } - - SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_SETREDRAW, TRUE, 0); - InvalidateRect(GetDlgItem(m_hwnd, IDC_CONSOLE), NULL, FALSE); -} - -int CJabberDlgConsole::Resizer(UTILRESIZECONTROL *urc) -{ - switch ( urc->wId ) - { - case IDC_CONSOLE: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - case IDC_CONSOLEIN: - return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; - - case IDC_BTN_MSG: - case IDC_BTN_PRESENCE: - case IDC_BTN_IQ: - case IDC_BTN_FILTER: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - - case IDC_CB_FILTER: - { - RECT rc; - GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); - urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx); - urc->rcItem.top += (urc->dlgNewSize.cy - urc->dlgOriginalSize.cy); - urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; - return 0; - } - - case IDC_RESET: - case IDOK: - case IDC_BTN_FILTER_REFRESH: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - return CSuper::Resizer(urc); -} - -INT_PTR CJabberDlgConsole::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch ( msg ) - { - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 300; - lpmmi->ptMinTrackSize.y = 400; - return 0; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDOK: - { - if (!m_proto->m_bJabberOnline) - { - MessageBox(m_hwnd, TranslateT("Can't send data while you are offline."), TranslateT("Jabber Error"), MB_ICONSTOP|MB_OK); - return TRUE; - } - - int length = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLEIN)) + 1; - TCHAR *textToSend = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); - GetWindowText(GetDlgItem(m_hwnd, IDC_CONSOLEIN), textToSend, length); - - int bytesProcessed = 0; - XmlNode xmlTmp( textToSend, &bytesProcessed, NULL); - if (xmlTmp) - { - m_proto->m_ThreadInfo->send( xmlTmp ); - } - else - { - StringBuf buf = {0}; - sttAppendBufRaw(&buf, RTF_HEADER); - sttAppendBufRaw(&buf, RTF_BEGINPLAINXML); - sttAppendBufT(&buf, TranslateT("Outgoing XML parsing error")); - sttAppendBufRaw(&buf, RTF_ENDPLAINXML); - sttAppendBufRaw(&buf, RTF_SEPARATOR); - sttAppendBufRaw(&buf, RTF_FOOTER); - SendMessage(m_hwnd, WM_JABBER_REFRESH, 0, (LPARAM)&buf); - sttEmptyBuf(&buf); - } - - mir_free(textToSend); - - SendDlgItemMessage(m_hwnd, IDC_CONSOLEIN, WM_SETTEXT, 0, (LPARAM)_T("")); - return TRUE; - } - - case IDC_RESET: - { - SetDlgItemText(m_hwnd, IDC_CONSOLE, _T("")); - break; - } - - case IDC_BTN_MSG: - case IDC_BTN_PRESENCE: - case IDC_BTN_IQ: - { - m_proto->m_filterInfo.msg = IsDlgButtonChecked(m_hwnd, IDC_BTN_MSG); - m_proto->m_filterInfo.presence = IsDlgButtonChecked(m_hwnd, IDC_BTN_PRESENCE); - m_proto->m_filterInfo.iq = IsDlgButtonChecked(m_hwnd, IDC_BTN_IQ); - break; - } - - case IDC_BTN_FILTER_REFRESH: - { - sttJabberConsoleRebuildStrings(m_proto, GetDlgItem(m_hwnd, IDC_CB_FILTER)); - break; - } - - case IDC_BTN_FILTER: - { - int i; - HMENU hMenu = CreatePopupMenu(); - for (i = 0; i < SIZEOF(filter_modes); ++i) - { - AppendMenu(hMenu, - MF_STRING | ((filter_modes[i].type == m_proto->m_filterInfo.type) ? MF_CHECKED : 0), - filter_modes[i].type+1, TranslateTS(filter_modes[i].title)); - } - RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BTN_FILTER), &rc); - CheckDlgButton(m_hwnd, IDC_BTN_FILTER, TRUE); - int res = TrackPopupMenu(hMenu, TPM_RETURNCMD|TPM_BOTTOMALIGN, rc.left, rc.top, 0, m_hwnd, NULL); - CheckDlgButton(m_hwnd, IDC_BTN_FILTER, FALSE); - DestroyMenu(hMenu); - - if (res) - { - m_proto->m_filterInfo.type = (TFilterInfo::Type)(res - 1); - for (i = 0; i < SIZEOF(filter_modes); ++i) - if (filter_modes[i].type == m_proto->m_filterInfo.type) - { - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon))); - break; - } - EnableWindow(GetDlgItem(m_hwnd, IDC_CB_FILTER), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTER_REFRESH), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); - } - - break; - } - - case IDC_CB_FILTER: - { - if (HIWORD(wParam) == CBN_SELCHANGE) - { - int idx = SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETCURSEL, 0, 0); - int len = SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXTLEN, idx, 0) + 1; - - EnterCriticalSection(&m_proto->m_filterInfo.csPatternLock); - if (len > SIZEOF(m_proto->m_filterInfo.pattern)) - { - TCHAR *buf = (TCHAR *)_alloca(len * sizeof(TCHAR)); - SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXT, idx, (LPARAM)buf); - lstrcpyn(m_proto->m_filterInfo.pattern, buf, SIZEOF(m_proto->m_filterInfo.pattern)); - } else - { - SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXT, idx, (LPARAM)m_proto->m_filterInfo.pattern); - } - LeaveCriticalSection(&m_proto->m_filterInfo.csPatternLock); - } else - if (HIWORD(wParam) == CBN_EDITCHANGE) - { - EnterCriticalSection(&m_proto->m_filterInfo.csPatternLock); - GetWindowText(GetDlgItem(m_hwnd, IDC_CB_FILTER), m_proto->m_filterInfo.pattern, SIZEOF(m_proto->m_filterInfo.pattern)); - LeaveCriticalSection(&m_proto->m_filterInfo.csPatternLock); - } - break; - } - } - break; - } - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -void __cdecl CJabberProto::ConsoleThread( void* ) -{ - MSG msg; - while ( GetMessage(&msg, NULL, 0, 0 )) { - if ( msg.message == WM_CREATECONSOLE ) { - m_pDlgConsole = new CJabberDlgConsole( this ); - m_pDlgConsole->Show(); - continue; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - m_dwConsoleThreadId = 0; -} - -void CJabberProto::ConsoleInit() -{ - LoadLibraryA("riched20.dll"); - InitializeCriticalSection(&m_filterInfo.csPatternLock); - m_hThreadConsole = JForkThreadEx( &CJabberProto::ConsoleThread, 0, &m_dwConsoleThreadId ); -} - -void CJabberProto::ConsoleUninit() -{ - if ( m_hThreadConsole ) { - PostThreadMessage(m_dwConsoleThreadId, WM_QUIT, 0, 0); - if ( WaitForSingleObject( m_hThreadConsole, 5000 ) == WAIT_TIMEOUT) { - TerminateThread( m_hThreadConsole, 0 ); - } - CloseHandle( m_hThreadConsole ); - m_hThreadConsole = NULL; - } - - m_filterInfo.iq = m_filterInfo.msg = m_filterInfo.presence = FALSE; - m_filterInfo.type = TFilterInfo::T_OFF; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleConsole(WPARAM, LPARAM) -{ - if ( m_pDlgConsole ) - SetForegroundWindow( m_pDlgConsole->GetHwnd()); - else - if ( m_hThreadConsole ) - PostThreadMessage( m_dwConsoleThreadId, WM_CREATECONSOLE, 0, 0 ); - return 0; -} diff --git a/protocols/JabberG/jabber_db_utils.h b/protocols/JabberG/jabber_db_utils.h deleted file mode 100644 index ae9a6c9781..0000000000 --- a/protocols/JabberG/jabber_db_utils.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __jabber_db_utils_h__ -#define __jabber_db_utils_h__ - -template struct CMIntTraits { static __forceinline bool IsSigned() { return false; } }; -template<> struct CMIntTraits { static __forceinline bool IsSigned() { return true; } }; -template<> struct CMIntTraits { static __forceinline bool IsSigned() { return true; } }; -template<> struct CMIntTraits { static __forceinline bool IsSigned() { return true; } }; - -template -struct CMDBTraits -{ -}; - -template<> -struct CMDBTraits<1> -{ - typedef BYTE DBType; - enum { DBTypeId = DBVT_BYTE }; - static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) - { - return DBGetContactSettingByte(NULL, szModule, szSetting, value); - } - static __forceinline void Set(char *szModule, char *szSetting, DBType value) - { - DBWriteContactSettingByte(NULL, szModule, szSetting, value); - } -}; - -template<> -struct CMDBTraits<2> -{ - typedef WORD DBType; - enum { DBTypeId = DBVT_WORD }; - static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) - { - return DBGetContactSettingWord(NULL, szModule, szSetting, value); - } - static __forceinline void Set(char *szModule, char *szSetting, DBType value) - { - DBWriteContactSettingWord(NULL, szModule, szSetting, value); - } -}; - -template<> -struct CMDBTraits<4> -{ - typedef DWORD DBType; - enum { DBTypeId = DBVT_DWORD }; - static __forceinline BYTE GetDBType() - { - return DBVT_DWORD; - } - static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) - { - return DBGetContactSettingDword(NULL, szModule, szSetting, value); - } - static __forceinline void Set(char *szModule, char *szSetting, DBType value) - { - DBWriteContactSettingDword(NULL, szModule, szSetting, value); - } -}; - -class CMOptionBase -{ -public: - BYTE GetDBType() { return m_dbType; } - char *GetDBModuleName() { return m_proto->m_szModuleName; } - char *GetDBSettingName() { return m_szSetting; } - -protected: - CMOptionBase(PROTO_INTERFACE *proto, char *szSetting, BYTE dbType): m_proto(proto), m_szSetting(szSetting), m_dbType(dbType) {} - - PROTO_INTERFACE *m_proto; - char *m_szSetting; - BYTE m_dbType; - -private: - CMOptionBase(const CMOptionBase &) {} - void operator= (const CMOptionBase &) {} -}; - -template -class CMOption: public CMOptionBase -{ -public: - typedef T Type; - - __forceinline CMOption(PROTO_INTERFACE *proto, char *szSetting, Type defValue): - CMOptionBase(proto, szSetting, CMDBTraits::DBTypeId), m_default(defValue) {} - - __forceinline operator Type() - { - return (Type)CMDBTraits::Get(m_proto->m_szModuleName, m_szSetting, m_default); - } - __forceinline Type operator= (Type value) - { - CMDBTraits::Set(m_proto->m_szModuleName, m_szSetting, (CMDBTraits::DBType)value); - return value; - } - -private: - Type m_default; - - CMOption(const CMOption &): CMOptionBase(NULL, NULL, DBVT_DELETED) {} - void operator= (const CMOption &) {} -}; - -template<> -class CMOption: public CMOptionBase -{ -public: - typedef const TCHAR *Type; - - __forceinline CMOption(PROTO_INTERFACE *proto, char *szSetting, Type defValue, bool crypt=false): - CMOptionBase(proto, szSetting, DBVT_TCHAR), m_default(defValue), m_crypt(crypt) {} - - __forceinline operator CMString() - { - CMString result; - DBVARIANT dbv; - if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, m_szSetting, &dbv)) - { - result = dbv.ptszVal; - DBFreeVariant(&dbv); - } - return result; - } - __forceinline Type operator= (Type value) - { - DBWriteContactSettingTString(NULL, m_proto->m_szModuleName, m_szSetting, value); - return value; - } - -private: - Type m_default; - bool m_crypt; - - CMOption(const CMOption &): CMOptionBase(NULL, NULL, DBVT_DELETED) {} - void operator= (const CMOption &) {} -}; - -struct CJabberOptions -{ - CMOption AllowVersionRequests; - CMOption AcceptHttpAuth; - CMOption AddRoster2Bookmarks; - CMOption AutoAcceptAuthorization; - CMOption AutoAcceptMUC; - CMOption AutoAdd; - CMOption AutoJoinBookmarks; - CMOption AutoJoinConferences; - CMOption AutoJoinHidden; - CMOption AvatarType; - CMOption BsDirect; - CMOption BsDirectManual; - CMOption BsOnlyIBB; - CMOption BsProxyManual; - CMOption Disable3920auth; - CMOption DisableFrame; - CMOption EnableAvatars; - CMOption EnableRemoteControl; - CMOption EnableUserActivity; - CMOption EnableUserMood; - CMOption EnableUserTune; - CMOption EnableZlib; - CMOption ExtendedSearch; - CMOption FixIncorrectTimestamps; - CMOption GcLogAffiliations; - CMOption GcLogBans; - CMOption GcLogConfig; - CMOption GcLogRoles; - CMOption GcLogStatuses; - CMOption GcLogChatHistory; - CMOption HostNameAsResource; - CMOption IgnoreMUCInvites; - CMOption KeepAlive; - CMOption LogChatstates; - CMOption LogPresence; - CMOption LogPresenceErrors; - CMOption ManualConnect; - CMOption MsgAck; - CMOption RosterSync; - CMOption SavePassword; - CMOption UseDomainLogin; - CMOption ShowForeignResourceInMirVer; - CMOption ShowOSVersion; - CMOption ShowTransport; - CMOption UseSSL; - CMOption UseTLS; - CMOption AcceptNotes; - CMOption AutosaveNotes; - CMOption RcMarkMessagesAsRead; - CMOption ConnectionKeepAliveInterval; - CMOption ConnectionKeepAliveTimeout; - CMOption ProcessXMPPLinks; - CMOption IgnoreRosterGroups; - - CJabberOptions(PROTO_INTERFACE *proto): - BsDirect(proto, "BsDirect", TRUE), - AllowVersionRequests(proto, "AllowVersionRequests", TRUE), - AcceptHttpAuth(proto, "AcceptHttpAuth", TRUE), - AddRoster2Bookmarks(proto, "AddRoster2Bookmarks", TRUE), - AutoAcceptAuthorization(proto, "AutoAcceptAuthorization", FALSE), - AutoAcceptMUC(proto, "AutoAcceptMUC", FALSE), - AutoAdd(proto, "AutoAdd", TRUE), - AutoJoinBookmarks(proto, "AutoJoinBookmarks", TRUE), - AutoJoinConferences(proto, "AutoJoinConferences", 0), - AutoJoinHidden(proto, "AutoJoinHidden", TRUE), - AvatarType(proto, "AvatarType", PA_FORMAT_UNKNOWN), - BsDirectManual(proto, "BsDirectManual", FALSE), - BsOnlyIBB(proto, "BsOnlyIBB", FALSE), - BsProxyManual(proto, "BsProxyManual", FALSE), - Disable3920auth(proto, "Disable3920auth", FALSE), - DisableFrame(proto, "DisableFrame", TRUE), - EnableAvatars(proto, "EnableAvatars", TRUE), - EnableRemoteControl(proto, "EnableRemoteControl", FALSE), - EnableUserActivity(proto, "EnableUserActivity", TRUE), - EnableUserMood(proto, "EnableUserMood", TRUE), - EnableUserTune(proto, "EnableUserTune", FALSE), - EnableZlib(proto, "EnableZlib", TRUE), - ExtendedSearch(proto, "ExtendedSearch", TRUE), - FixIncorrectTimestamps(proto, "FixIncorrectTimestamps", TRUE), - GcLogAffiliations(proto, "GcLogAffiliations", FALSE), - GcLogBans(proto, "GcLogBans", TRUE), - GcLogConfig(proto, "GcLogConfig", FALSE), - GcLogRoles(proto, "GcLogRoles", FALSE), - GcLogStatuses(proto, "GcLogStatuses", FALSE), - GcLogChatHistory(proto, "GcLogChatHistory", FALSE), - HostNameAsResource(proto, "HostNameAsResource", FALSE), - IgnoreMUCInvites(proto, "IgnoreMUCInvites", FALSE), - KeepAlive(proto, "KeepAlive", TRUE), - LogChatstates(proto, "LogChatstates", FALSE), - LogPresence(proto, "LogPresence", TRUE), - LogPresenceErrors(proto, "LogPresenceErrors", FALSE), - ManualConnect(proto, "ManualConnect", FALSE), - MsgAck(proto, "MsgAck", FALSE), - RosterSync(proto, "RosterSync", FALSE), - SavePassword(proto, "SavePassword", TRUE), - ShowForeignResourceInMirVer(proto, "ShowForeignResourceInMirVer", FALSE), - ShowOSVersion(proto, "ShowOSVersion", TRUE), - ShowTransport(proto, "ShowTransport", TRUE), - UseSSL(proto, "UseSSL", FALSE), - UseTLS(proto, "UseTLS", TRUE), - UseDomainLogin(proto, "UseDomainLogin", FALSE), - AcceptNotes(proto, "AcceptNotes", TRUE), - AutosaveNotes(proto, "AutosaveNotes", FALSE), - RcMarkMessagesAsRead(proto, "RcMarkMessagesAsRead", 1), - ConnectionKeepAliveInterval(proto, "ConnectionKeepAliveInterval", 60000), - ConnectionKeepAliveTimeout(proto, "ConnectionKeepAliveTimeout", 50000), - ProcessXMPPLinks(proto, "ProcessXMPPLinks", FALSE), - IgnoreRosterGroups(proto, "IgnoreRosterGroups", FALSE) - {} -}; - -#endif // __jabber_db_utils_h__ diff --git a/protocols/JabberG/jabber_disco.cpp b/protocols/JabberG/jabber_disco.cpp deleted file mode 100644 index eadfd2d5d1..0000000000 --- a/protocols/JabberG/jabber_disco.cpp +++ /dev/null @@ -1,1529 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_disco.h" - -#define SD_FAKEJID_CONFERENCES "@@conferences" -#define SD_FAKEJID_MYAGENTS "@@my-transports" -#define SD_FAKEJID_AGENTS "@@transports" -#define SD_FAKEJID_FAVORITES "@@favorites" - -enum { - SD_BROWSE_NORMAL, - SD_BROWSE_MYAGENTS, - SD_BROWSE_AGENTS, - SD_BROWSE_CONFERENCES, - SD_BROWSE_FAVORITES -}; -static int sttBrowseMode = SD_BROWSE_NORMAL; - -#define REFRESH_TIMEOUT 500 -#define REFRESH_TIMER 1607 -static DWORD sttLastRefresh = 0; - -#define AUTODISCO_TIMEOUT 500 -#define AUTODISCO_TIMER 1608 -static DWORD sttLastAutoDisco = 0; - -enum { SD_OVERLAY_NONE, SD_OVERLAY_FAIL, SD_OVERLAY_PROGRESS, SD_OVERLAY_REGISTERED }; - -static struct -{ - TCHAR *feature; - TCHAR *category; - TCHAR *type; - char *iconName; - int iconIndex; - int listIndex; -} sttNodeIcons[] = -{ -// standard identities: http://www.xmpp.org/registrar/disco-categories.html#directory -// {NULL, _T("account"), _T("admin"), NULL, 0}, -// {NULL, _T("account"), _T("anonymous"), NULL, 0}, -// {NULL, _T("account"), _T("registered"), NULL, 0}, - {NULL, _T("account"), NULL, NULL, SKINICON_STATUS_ONLINE}, - -// {NULL, _T("auth"), _T("cert"), NULL, 0}, -// {NULL, _T("auth"), _T("generic"), NULL, 0}, -// {NULL, _T("auth"), _T("ldap"), NULL, 0}, -// {NULL, _T("auth"), _T("ntlm"), NULL, 0}, -// {NULL, _T("auth"), _T("pam"), NULL, 0}, -// {NULL, _T("auth"), _T("radius"), NULL, 0}, - {NULL, _T("auth"), NULL, "key", 0}, - -/// {NULL, _T("automation"), _T("command-list"), NULL, 0}, -/// {NULL, _T("automation"), _T("command-node"), NULL, 0}, -// {NULL, _T("automation"), _T("rpc"), NULL, 0}, -// {NULL, _T("automation"), _T("soap"), NULL, 0}, - {NULL, _T("automation"), NULL, "adhoc", 0}, - -// {NULL, _T("client"), _T("bot"), NULL, 0}, -// {NULL, _T("client"), _T("console"), NULL, 0}, -// {NULL, _T("client"), _T("handheld"), NULL, 0}, -// {NULL, _T("client"), _T("pc"), NULL, 0}, -// {NULL, _T("client"), _T("phone"), NULL, 0}, -// {NULL, _T("client"), _T("web"), NULL, 0}, - {NULL, _T("client"), NULL, NULL, SKINICON_STATUS_ONLINE}, - -// {NULL, _T("collaboration"), _T("whiteboard"), NULL, 0}, - {NULL, _T("collaboration"), NULL, "group", 0}, - -// {NULL, _T("component"), _T("archive"), NULL, 0}, -// {NULL, _T("component"), _T("c2s"), NULL, 0}, -// {NULL, _T("component"), _T("generic"), NULL, 0}, -// {NULL, _T("component"), _T("load"), NULL, 0}, -// {NULL, _T("component"), _T("log"), NULL, 0}, -// {NULL, _T("component"), _T("presence"), NULL, 0}, -// {NULL, _T("component"), _T("router"), NULL, 0}, -// {NULL, _T("component"), _T("s2s"), NULL, 0}, -// {NULL, _T("component"), _T("sm"), NULL, 0}, -// {NULL, _T("component"), _T("stats"), NULL, 0}, - -// {NULL, _T("conference"), _T("irc"), NULL, 0}, -// {NULL, _T("conference"), _T("text"), NULL, 0}, - {NULL, _T("conference"), NULL, "group", 0}, - - {NULL, _T("directory"), _T("chatroom"), "group", 0}, - {NULL, _T("directory"), _T("group"), "group", 0}, - {NULL, _T("directory"), _T("user"), NULL, SKINICON_OTHER_FINDUSER}, -// {NULL, _T("directory"), _T("waitinglist"), NULL, 0}, - {NULL, _T("directory"), NULL, NULL, SKINICON_OTHER_SEARCHALL}, - - {NULL, _T("gateway"), _T("aim"), "AIM", SKINICON_STATUS_ONLINE}, - {NULL, _T("gateway"), _T("gadu-gadu"), "GG", SKINICON_STATUS_ONLINE}, -// {NULL, _T("gateway"), _T("http-ws"), NUL, 0}, - {NULL, _T("gateway"), _T("icq"), "ICQ", SKINICON_STATUS_ONLINE}, - {NULL, _T("gateway"), _T("msn"), "MSN", SKINICON_STATUS_ONLINE}, - {NULL, _T("gateway"), _T("qq"), "QQ", SKINICON_STATUS_ONLINE}, -// {NULL, _T("gateway"), _T("sms"), NULL, 0}, -// {NULL, _T("gateway"), _T("smtp"), NULL, 0}, - {NULL, _T("gateway"), _T("tlen"), "TLEN", SKINICON_STATUS_ONLINE}, - {NULL, _T("gateway"), _T("yahoo"), "YAHOO", SKINICON_STATUS_ONLINE}, - {NULL, _T("gateway"), NULL, "Agents", 0}, - -// {NULL, _T("headline"), _T("newmail"), NULL, 0}, - {NULL, _T("headline"), _T("rss"), "node_rss", 0}, - {NULL, _T("headline"), _T("weather"), "node_weather", 0}, - -// {NULL, _T("hierarchy"), _T("branch"), NULL, 0}, -// {NULL, _T("hierarchy"), _T("leaf"), NULL, 0}, - -// {NULL, _T("proxy"), _T("bytestreams"), NULL, 0}, - {NULL, _T("proxy"), NULL, NULL, SKINICON_EVENT_FILE}, - -// {NULL, _T("pubsub"), _T("collection"), NULL, 0}, -// {NULL, _T("pubsub"), _T("leaf"), NULL, 0}, -// {NULL, _T("pubsub"), _T("pep"), NULL, 0}, -// {NULL, _T("pubsub"), _T("service"), NULL, 0}, - -// {NULL, _T("server"), _T("im"), NULL, 0}, - {NULL, _T("server"), NULL, "node_server", 0}, - -// {NULL, _T("store"), _T("berkeley"), NULL, 0}, -/// {NULL, _T("store"), _T("file"), NULL, 0}, -// {NULL, _T("store"), _T("generic"), NULL, 0}, -// {NULL, _T("store"), _T("ldap"), NULL, 0}, -// {NULL, _T("store"), _T("mysql"), NULL, 0}, -// {NULL, _T("store"), _T("oracle"), NULL, 0}, -// {NULL, _T("store"), _T("postgres"), NULL, 0}, - {NULL, _T("store"), NULL, "node_store", 0}, - -// icons for non-standard identities - {NULL, _T("x-service"), _T("x-rss"), "node_rss", 0}, - {NULL, _T("application"), _T("x-weather"), "node_weather", 0}, - {NULL, _T("user"), NULL, NULL, SKINICON_STATUS_ONLINE}, - -// icon suggestions based on supported features - {_T("jabber:iq:gateway"), NULL,NULL, "Agents", 0}, - {_T("jabber:iq:search"), NULL,NULL, NULL, SKINICON_OTHER_FINDUSER}, - {_T(JABBER_FEAT_COMMANDS), NULL,NULL, "adhoc", 0}, - {_T(JABBER_FEAT_REGISTER), NULL,NULL, "key", 0}, -}; - -static void sttApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode); - -void CJabberProto::OnIqResultServiceDiscoveryInfo( HXML iqNode, CJabberIqInfo* pInfo ) -{ - m_SDManager.Lock(); - CJabberSDNode* pNode = m_SDManager.FindByIqId( pInfo->GetIqId(), TRUE ); - if ( !pNode ) { - m_SDManager.Unlock(); - return; - } - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML query = xmlGetChild( iqNode , "query" ); - if ( !query ) - pNode->SetInfoRequestId( JABBER_DISCO_RESULT_ERROR ); - else { - HXML feature; - int i; - for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) - pNode->AddFeature( xmlGetAttrValue( feature, _T("var"))); - HXML identity; - for ( i = 1; ( identity = xmlGetNthChild( query, _T("identity"), i )) != NULL; i++ ) - pNode->AddIdentity( xmlGetAttrValue( identity, _T("category")), xmlGetAttrValue( identity, _T("type")), xmlGetAttrValue( identity, _T("name"))); - - pNode->SetInfoRequestId( JABBER_DISCO_RESULT_OK ); - pNode->SetInfoRequestErrorText( NULL ); - } - } - else { - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - pNode->SetInfoRequestErrorText( str ); - mir_free( str ); - } - else pNode->SetInfoRequestErrorText( TranslateT("request timeout.")); - - pNode->SetInfoRequestId( JABBER_DISCO_RESULT_ERROR ); - } - - m_SDManager.Unlock(); - - if ( m_pDlgServiceDiscovery ) { - ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); - PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); - } -} - -void CJabberProto::OnIqResultServiceDiscoveryItems( HXML iqNode, CJabberIqInfo* pInfo ) -{ - m_SDManager.Lock(); - CJabberSDNode* pNode = m_SDManager.FindByIqId( pInfo->GetIqId(), FALSE ); - if ( !pNode ) { - m_SDManager.Unlock(); - return; - } - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML query = xmlGetChild( iqNode , "query" ); - if ( !query ) - pNode->SetItemsRequestId( JABBER_DISCO_RESULT_ERROR ); - else { - HXML item; - for ( int i = 1; ( item = xmlGetNthChild( query, _T("item"), i )) != NULL; i++ ) { - pNode->AddChildNode( xmlGetAttrValue( item, _T("jid")), xmlGetAttrValue( item, _T("node")), xmlGetAttrValue( item, _T("name"))); - } - - pNode->SetItemsRequestId( JABBER_DISCO_RESULT_OK ); - pNode->SetItemsRequestErrorText( NULL ); - } - } - else { - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - pNode->SetItemsRequestErrorText( str ); - mir_free( str ); - } - else { - pNode->SetItemsRequestErrorText( _T("request timeout.")); - } - pNode->SetItemsRequestId( JABBER_DISCO_RESULT_ERROR ); - } - - m_SDManager.Unlock(); - - if ( m_pDlgServiceDiscovery ) { - ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); - PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); - } -} - -void CJabberProto::OnIqResultServiceDiscoveryRootInfo( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if (!pInfo->m_pUserData) return; - m_SDManager.Lock(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML query = xmlGetChild( iqNode , "query" ); - if ( query ) { - HXML feature; - int i; - for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { - if ( !lstrcmp( xmlGetAttrValue( feature, _T("var")), (TCHAR *)pInfo->m_pUserData)) { - CJabberSDNode *pNode = m_SDManager.AddPrimaryNode( pInfo->GetReceiver(), xmlGetAttrValue( iqNode, _T("node")), NULL); - SendBothRequests( pNode, NULL ); - break; - } } } } - m_SDManager.Unlock(); - - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_REFRESH); -} - -void CJabberProto::OnIqResultServiceDiscoveryRootItems( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if (!pInfo->m_pUserData) - return; - - XmlNode packet( NULL ); - m_SDManager.Lock(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML query = xmlGetChild( iqNode , "query" ); - if ( query ) { - HXML item; - for ( int i = 1; ( item = xmlGetNthChild( query, _T("item"), i )) != NULL; i++ ) { - const TCHAR *szJid = xmlGetAttrValue( item, _T("jid")); - const TCHAR *szNode = xmlGetAttrValue( item, _T("node")); - CJabberIqInfo* pNewInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootInfo, JABBER_IQ_TYPE_GET, szJid ); - pNewInfo->m_pUserData = pInfo->m_pUserData; - pNewInfo->SetTimeout( 30000 ); - - XmlNodeIq iq( pNewInfo ); - iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), szNode ); - xmlAddChild( packet, iq ); - } } } - m_SDManager.Unlock(); - - if ( xmlGetChild( packet ,0)) - m_ThreadInfo->send( packet ); -} - -BOOL CJabberProto::SendInfoRequest(CJabberSDNode* pNode, HXML parent) -{ - if ( !pNode || !m_bJabberOnline ) - return FALSE; - - // disco#info - if ( !pNode->GetInfoRequestId()) { - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryInfo, JABBER_IQ_TYPE_GET, pNode->GetJid()); - pInfo->SetTimeout( 30000 ); - pNode->SetInfoRequestId( pInfo->GetIqId()); - - XmlNodeIq iq( pInfo ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); - if ( pNode->GetNode()) - xmlAddAttr( query, _T("node"), pNode->GetNode()); - - if ( parent ) - xmlAddChild( parent, iq ); - else - m_ThreadInfo->send( iq ); - } - - if ( m_pDlgServiceDiscovery ) { - ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); - PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); - } - - return TRUE; -} - -BOOL CJabberProto::SendBothRequests(CJabberSDNode* pNode, HXML parent) -{ - if ( !pNode || !m_bJabberOnline ) - return FALSE; - - // disco#info - if ( !pNode->GetInfoRequestId()) { - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryInfo, JABBER_IQ_TYPE_GET, pNode->GetJid()); - pInfo->SetTimeout( 30000 ); - pNode->SetInfoRequestId( pInfo->GetIqId()); - - XmlNodeIq iq( pInfo ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); - if ( pNode->GetNode()) - xmlAddAttr( query, _T("node"), pNode->GetNode()); - - if ( parent ) - xmlAddChild( parent, iq ); - else - m_ThreadInfo->send( iq ); - } - - // disco#items - if ( !pNode->GetItemsRequestId()) { - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryItems, JABBER_IQ_TYPE_GET, pNode->GetJid()); - pInfo->SetTimeout( 30000 ); - pNode->SetItemsRequestId( pInfo->GetIqId()); - - XmlNodeIq iq( pInfo ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); - if ( pNode->GetNode()) - xmlAddAttr( query, _T("node"), pNode->GetNode()); - - if ( parent ) - xmlAddChild( parent, iq ); - else - m_ThreadInfo->send( iq ); - } - - if ( m_pDlgServiceDiscovery ) { - ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); - PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); - } - - return TRUE; -} - -void CJabberProto::PerformBrowse(HWND hwndDlg) -{ - TCHAR szJid[ JABBER_MAX_JID_LEN ]; - TCHAR szNode[ 512 ]; - if ( !GetDlgItemText( hwndDlg, IDC_COMBO_JID, szJid, SIZEOF( szJid ))) - szJid[ 0 ] = 0; - if ( !GetDlgItemText( hwndDlg, IDC_COMBO_NODE, szNode, SIZEOF( szNode ))) - szNode[ 0 ] = 0; - - ComboAddRecentString(hwndDlg, IDC_COMBO_JID, "discoWnd_rcJid", szJid); - ComboAddRecentString(hwndDlg, IDC_COMBO_NODE, "discoWnd_rcNode", szNode); - - if ( _tcslen( szJid )) { - HWND hwndList = GetDlgItem(hwndDlg, IDC_TREE_DISCO); - TreeList_Reset(hwndList); - - m_SDManager.Lock(); - m_SDManager.RemoveAll(); - if (!lstrcmp(szJid, _T(SD_FAKEJID_MYAGENTS))) { - sttBrowseMode = SD_BROWSE_MYAGENTS; - JABBER_LIST_ITEM *item = NULL; - LISTFOREACH(i, this, LIST_ROSTER) - { - if (( item=ListGetItemPtrFromIndex( i )) != NULL ) { - if ( _tcschr( item->jid, '@' )==NULL && _tcschr( item->jid, '/' )==NULL && item->subscription!=SUB_NONE ) { - HANDLE hContact = HContactFromJID( item->jid ); - if ( hContact != NULL ) - JSetByte( hContact, "IsTransport", TRUE ); - - if ( m_lstTransports.getIndex( item->jid ) == -1 ) - m_lstTransports.insert( mir_tstrdup( item->jid )); - - CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(item->jid, NULL, NULL); - SendBothRequests( pNode, NULL ); - } } - } } - else if (!lstrcmp(szJid, _T(SD_FAKEJID_CONFERENCES))) { - sttBrowseMode = SD_BROWSE_CONFERENCES; - TCHAR *szServerJid = mir_a2t(m_ThreadInfo->server); - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootItems, JABBER_IQ_TYPE_GET, szServerJid ); - pInfo->m_pUserData = (void *)_T(JABBER_FEAT_MUC); - pInfo->SetTimeout( 30000 ); - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); - m_ThreadInfo->send( iq ); - mir_free(szServerJid); - } - else if (!lstrcmp(szJid, _T(SD_FAKEJID_AGENTS))) { - sttBrowseMode = SD_BROWSE_AGENTS; - TCHAR *szServerJid = mir_a2t(m_ThreadInfo->server); - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootItems, JABBER_IQ_TYPE_GET, szServerJid ); - pInfo->m_pUserData = (void *)_T("jabber:iq:gateway"); - pInfo->SetTimeout( 30000 ); - XmlNodeIq iq( pInfo ); - iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); - m_ThreadInfo->send( iq ); - mir_free(szServerJid); - } - else if (!lstrcmp(szJid, _T(SD_FAKEJID_FAVORITES))) { - sttBrowseMode = SD_BROWSE_FAVORITES; - int count = JGetDword(NULL, "discoWnd_favCount", 0); - for (int i = 0; i < count; ++i) - { - DBVARIANT dbv; - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); - if (!JGetStringT(NULL, setting, &dbv)) { - DBVARIANT dbvJid, dbvNode; - mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", i); - JGetStringT(NULL, setting, &dbvJid); - mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", i); - JGetStringT(NULL, setting, &dbvNode); - CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(dbvJid.ptszVal, dbvNode.ptszVal, dbv.ptszVal); - SendBothRequests( pNode, NULL ); - JFreeVariant(&dbv); - JFreeVariant(&dbvJid); - JFreeVariant(&dbvNode); - } } } - else { - sttBrowseMode = SD_BROWSE_NORMAL; - CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(szJid, _tcslen( szNode ) ? szNode : NULL, NULL); - SendBothRequests( pNode, NULL ); - } - m_SDManager.Unlock(); - - PostMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 ); - } -} - -BOOL CJabberProto::IsNodeRegistered(CJabberSDNode *pNode) -{ - if (pNode->GetNode()) - return FALSE; - - JABBER_LIST_ITEM *item; - if (item = ListGetItemPtr(LIST_ROSTER, pNode->GetJid())) - return (item->subscription != SUB_NONE) ? TRUE : FALSE; - - if (item = ListGetItemPtr(LIST_BOOKMARK, pNode->GetJid())) - return TRUE; - - return FALSE; -} - -void CJabberProto::ApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode) -{ - if (!hItem || !pNode) return; - - int iIcon = -1, iOverlay = -1; - - if ((pNode->GetInfoRequestId() > 0) || (pNode->GetItemsRequestId() > 0)) - iOverlay = SD_OVERLAY_PROGRESS; - else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_ERROR) - iOverlay = SD_OVERLAY_FAIL; - else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_NOT_REQUESTED) { - if (IsNodeRegistered(pNode)) - iOverlay = SD_OVERLAY_REGISTERED; - else - iOverlay = SD_OVERLAY_NONE; - } else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_OK) { - if (IsNodeRegistered(pNode)) - iOverlay = SD_OVERLAY_REGISTERED; - else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_ERROR) - iOverlay = SD_OVERLAY_FAIL; - else - iOverlay = SD_OVERLAY_NONE; - } - - for (int i = 0; i < SIZEOF(sttNodeIcons); ++i) - { - if (!sttNodeIcons[i].iconIndex && !sttNodeIcons[i].iconName) continue; - - if (sttNodeIcons[i].category) - { - CJabberSDIdentity *iIdentity; - for (iIdentity = pNode->GetFirstIdentity(); iIdentity; iIdentity = iIdentity->GetNext()) - if (!lstrcmp(iIdentity->GetCategory(), sttNodeIcons[i].category) && - (!sttNodeIcons[i].type || !lstrcmp(iIdentity->GetType(), sttNodeIcons[i].type))) - { - iIcon = sttNodeIcons[i].listIndex; - break; - } - if (iIdentity) break; - } - - if (sttNodeIcons[i].feature) - { - CJabberSDFeature *iFeature; - for (iFeature = pNode->GetFirstFeature(); iFeature; iFeature = iFeature->GetNext()) - if (!lstrcmp(iFeature->GetVar(), sttNodeIcons[i].feature)) - { - iIcon = sttNodeIcons[i].listIndex; - break; - } - if (iFeature) break; - } - } - - TreeList_SetIcon(pNode->GetTreeItemHandle(), iIcon, iOverlay); -} - -BOOL CJabberProto::SyncTree(HTREELISTITEM hIndex, CJabberSDNode* pNode) -{ - if (!m_pDlgServiceDiscovery) return FALSE; - - CJabberSDNode* pTmp = pNode; - while (pTmp) { - if ( !pTmp->GetTreeItemHandle()) { - HTREELISTITEM hNewItem = TreeList_AddItem( - GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hIndex, - pTmp->GetName() ? pTmp->GetName() : pTmp->GetJid(), - (LPARAM)pTmp); - TreeList_AppendColumn(hNewItem, pTmp->GetJid()); - TreeList_AppendColumn(hNewItem, pTmp->GetNode()); - if (!pTmp->GetInfoRequestId()) - TreeList_MakeFakeParent(hNewItem, TRUE); - else - TreeList_MakeFakeParent(hNewItem, FALSE); - pTmp->SetTreeItemHandle( hNewItem ); - } - - ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); - - if ( pTmp->GetFirstChildNode()) - SyncTree( pTmp->GetTreeItemHandle(), pTmp->GetFirstChildNode()); - - pTmp = pTmp->GetNext(); - } - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////////// -// CJabberDlgDiscovery -class CJabberDlgDiscovery: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgDiscovery(CJabberProto *proto, TCHAR *jid); - -protected: - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - int Resizer(UTILRESIZECONTROL *urc); - -private: - TCHAR *m_jid; - bool m_focusEditAfterBrowse; - - CCtrlMButton m_btnViewAsTree; - CCtrlMButton m_btnViewAsList; - CCtrlMButton m_btnGoHome; - CCtrlMButton m_btnBookmarks; - CCtrlMButton m_btnRefresh; - CCtrlMButton m_btnBrowse; - CCtrlFilterListView m_lstDiscoTree; - - void btnViewAsTree_OnClick(CCtrlButton *); - void btnViewAsList_OnClick(CCtrlButton *); - void btnGoHome_OnClick(CCtrlButton *); - void btnBookmarks_OnClick(CCtrlButton *); - void btnRefresh_OnClick(CCtrlButton *); - void btnBrowse_OnClick(CCtrlButton *); - void lstDiscoTree_OnFilter(CCtrlFilterListView *); -}; - -CJabberDlgDiscovery::CJabberDlgDiscovery(CJabberProto *proto, TCHAR *jid) : - CJabberDlgBase(proto, IDD_SERVICE_DISCOVERY, NULL), - m_jid(jid), - m_btnViewAsTree(this, IDC_BTN_VIEWTREE, proto->LoadIconEx("sd_view_tree"), "View as tree"), - m_btnViewAsList(this, IDC_BTN_VIEWLIST, proto->LoadIconEx("sd_view_list"), "View as list"), - m_btnGoHome(this, IDC_BTN_NAVHOME, proto->LoadIconEx("sd_nav_home"), "Navigate home"), - m_btnBookmarks(this, IDC_BTN_FAVORITE, proto->LoadIconEx("bookmarks"), "Favorites"), - m_btnRefresh(this, IDC_BTN_REFRESH, proto->LoadIconEx("sd_nav_refresh"), "Refresh node"), - m_btnBrowse(this, IDC_BUTTON_BROWSE, proto->LoadIconEx("sd_browse"), "Browse"), - m_lstDiscoTree(this, IDC_TREE_DISCO, true, false) -{ - m_btnViewAsTree.OnClick = Callback(this, &CJabberDlgDiscovery::btnViewAsTree_OnClick); - m_btnViewAsList.OnClick = Callback(this, &CJabberDlgDiscovery::btnViewAsList_OnClick); - m_btnGoHome.OnClick = Callback(this, &CJabberDlgDiscovery::btnGoHome_OnClick); - m_btnBookmarks.OnClick = Callback(this, &CJabberDlgDiscovery::btnBookmarks_OnClick); - m_btnRefresh.OnClick = Callback(this, &CJabberDlgDiscovery::btnRefresh_OnClick); - m_btnBrowse.OnClick = Callback(this, &CJabberDlgDiscovery::btnBrowse_OnClick); - m_lstDiscoTree.OnFilterChanged = Callback(this, &CJabberDlgDiscovery::lstDiscoTree_OnFilter); -} - -void CJabberDlgDiscovery::OnInitDialog() -{ - CSuper::OnInitDialog(); - -// TranslateDialogDefault( m_hwnd ); - WindowSetIcon( m_hwnd, m_proto, "servicediscovery" ); - - int i; - - if ( m_jid ) { - SetDlgItemText( m_hwnd, IDC_COMBO_JID, m_jid ); - SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); - m_focusEditAfterBrowse = false; - } else { - SetDlgItemTextA( m_hwnd, IDC_COMBO_JID, m_proto->m_ThreadInfo->server ); - SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); - m_focusEditAfterBrowse = true; - } - - m_btnViewAsList.MakePush(); - m_btnViewAsTree.MakePush(); - m_btnBookmarks.MakePush(); - - CheckDlgButton(m_hwnd, - DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", 1) ? - IDC_BTN_VIEWTREE : IDC_BTN_VIEWLIST, - TRUE); - - EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTERRESET), FALSE); - - SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_CONFERENCES)); - SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_MYAGENTS)); - SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_AGENTS)); - SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_FAVORITES)); - m_proto->ComboLoadRecentStrings(m_hwnd, IDC_COMBO_JID, "discoWnd_rcJid"); - m_proto->ComboLoadRecentStrings(m_hwnd, IDC_COMBO_NODE, "discoWnd_rcNode"); - - HWND hwndList = m_lstDiscoTree.GetHwnd();//GetDlgItem(m_hwnd, IDC_TREE_DISCO); - LVCOLUMN lvc = {0}; - lvc.mask = LVCF_SUBITEM|LVCF_WIDTH|LVCF_TEXT; - lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx0", 200); - lvc.iSubItem = 0; - lvc.pszText = TranslateT("Node hierarchy"); - ListView_InsertColumn(hwndList, 0, &lvc); - lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx1", 200); - lvc.iSubItem = 1; - lvc.pszText = _T("JID"); - ListView_InsertColumn(hwndList, 1, &lvc); - lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx2", 200); - lvc.iSubItem = 2; - lvc.pszText = TranslateT("Node"); - ListView_InsertColumn(hwndList, 2, &lvc); - - TreeList_Create(hwndList); - TreeList_AddIcon(hwndList, m_proto->LoadIconEx("main"), 0); - for (i = 0; i < SIZEOF(sttNodeIcons); ++i) - { - bool needDestroy = false; - HICON hIcon; - if ((sttNodeIcons[i].iconIndex == SKINICON_STATUS_ONLINE) && sttNodeIcons[i].iconName) { - hIcon = (HICON)CallProtoService(sttNodeIcons[i].iconName, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); - needDestroy = true; - } - else if (sttNodeIcons[i].iconName) - hIcon = m_proto->LoadIconEx(sttNodeIcons[i].iconName); - else if (sttNodeIcons[i].iconIndex) - hIcon = LoadSkinnedIcon(sttNodeIcons[i].iconIndex); - else continue; - sttNodeIcons[i].listIndex = TreeList_AddIcon(hwndList, hIcon, 0); - if (needDestroy) DestroyIcon(hIcon); - } - TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_fail"), SD_OVERLAY_FAIL); - TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_progress"), SD_OVERLAY_PROGRESS); - TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_ok"), SD_OVERLAY_REGISTERED); - - TreeList_SetMode(hwndList, DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", 1) ? TLM_TREE : TLM_REPORT); - - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "discoWnd_"); -} - -void CJabberDlgDiscovery::OnClose() -{ - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", IsDlgButtonChecked(m_hwnd, IDC_BTN_VIEWTREE)); - - HWND hwndList = GetDlgItem(m_hwnd, IDC_TREE_DISCO); - LVCOLUMN lvc = {0}; - lvc.mask = LVCF_WIDTH; - ListView_GetColumn(hwndList, 0, &lvc); - DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx0", lvc.cx); - ListView_GetColumn(hwndList, 1, &lvc); - DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx1", lvc.cx); - ListView_GetColumn(hwndList, 2, &lvc); - DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx2", lvc.cx); - - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "discoWnd_"); - DestroyWindow( m_hwnd ); - - CSuper::OnClose(); -} - -void CJabberDlgDiscovery::OnDestroy() -{ - m_proto->m_pDlgServiceDiscovery = NULL; - m_proto->m_SDManager.Lock(); - m_proto->m_SDManager.RemoveAll(); - m_proto->m_SDManager.Unlock(); - TreeList_Destroy(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); - - CSuper::OnDestroy(); -} - -int CJabberDlgDiscovery::Resizer(UTILRESIZECONTROL *urc) -{ - RECT rc; - - switch ( urc->wId ) { - case IDC_COMBO_JID: - { - GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); - urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; - urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; - return 0; - } - case IDC_TXT_NODELABEL: - { - urc->rcItem.left += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; - urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; - return 0; - } - case IDC_COMBO_NODE: - { - GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); - urc->rcItem.left += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; - urc->rcItem.right += urc->dlgNewSize.cx - urc->dlgOriginalSize.cx; - urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; - return 0; - } - case IDC_BUTTON_BROWSE: - return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP; - - case IDC_TREE_DISCO: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - - case IDC_TXT_FILTER: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - case IDC_TXT_FILTERTEXT: - return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; - case IDC_BTN_FILTERAPPLY: - case IDC_BTN_FILTERRESET: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - return CSuper::Resizer(urc); -} - -void CJabberDlgDiscovery::btnViewAsTree_OnClick(CCtrlButton *) -{ - CheckDlgButton(m_hwnd, IDC_BTN_VIEWLIST, FALSE); - CheckDlgButton(m_hwnd, IDC_BTN_VIEWTREE, TRUE); - TreeList_SetMode(GetDlgItem(m_hwnd, IDC_TREE_DISCO), TLM_TREE); -} - -void CJabberDlgDiscovery::btnViewAsList_OnClick(CCtrlButton *) -{ - CheckDlgButton(m_hwnd, IDC_BTN_VIEWLIST, TRUE); - CheckDlgButton(m_hwnd, IDC_BTN_VIEWTREE, FALSE); - TreeList_SetMode(GetDlgItem(m_hwnd, IDC_TREE_DISCO), TLM_REPORT); -} - -void CJabberDlgDiscovery::btnGoHome_OnClick(CCtrlButton *) -{ - SetDlgItemTextA( m_hwnd, IDC_COMBO_JID, m_proto->m_ThreadInfo->server ); - SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); -} - -void CJabberDlgDiscovery::btnBookmarks_OnClick(CCtrlButton *) -{ - HMENU hMenu = CreatePopupMenu(); - int count = m_proto->JGetDword(NULL, "discoWnd_favCount", 0); - for (int i = 0; i < count; ++i) - { - DBVARIANT dbv; - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); - if (!m_proto->JGetStringT(NULL, setting, &dbv)) - { - HMENU hSubMenu = CreatePopupMenu(); - AppendMenu(hSubMenu, MF_STRING, 100+i*10+0, TranslateT("Navigate")); - AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hSubMenu, MF_STRING, 100+i*10+1, TranslateT("Remove")); - AppendMenu(hMenu, MF_POPUP|MF_STRING, (UINT_PTR)hSubMenu, dbv.ptszVal); - } - JFreeVariant(&dbv); - } - int res = 0; - if (GetMenuItemCount(hMenu)) { - AppendMenu(hMenu, MF_SEPARATOR, 1, NULL); - AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_FAVORITES, TranslateT("Browse all favorites")); - AppendMenu(hMenu, MF_STRING, 1, TranslateT("Remove all favorites")); - } - if (GetMenuItemCount(hMenu)) - AppendMenu(hMenu, MF_SEPARATOR, 1, NULL); - - AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_MYAGENTS, TranslateT("Registered transports")); - AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_AGENTS, TranslateT("Browse local transports")); - AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_CONFERENCES, TranslateT("Browse chatrooms")); - - RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BTN_FAVORITE), &rc); - CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, TRUE); - res = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, NULL); - CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, FALSE); - DestroyMenu(hMenu); - - if (res >= 100) - { - res -= 100; - if (res % 10) - { - res /= 10; - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", res); - m_proto->JDeleteSetting(NULL, setting); - mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", res); - m_proto->JDeleteSetting(NULL, setting); - mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", res); - m_proto->JDeleteSetting(NULL, setting); - } else - { - res /= 10; - - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T("")); - SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); - - DBVARIANT dbv; - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", res); - if (!m_proto->JGetStringT(NULL, setting, &dbv)) SetDlgItemText(m_hwnd, IDC_COMBO_JID, dbv.ptszVal); - JFreeVariant(&dbv); - mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", res); - if (!m_proto->JGetStringT(NULL, setting, &dbv)) SetDlgItemText(m_hwnd, IDC_COMBO_NODE, dbv.ptszVal); - JFreeVariant(&dbv); - - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - } - } else - if (res == 1) - { - int count = m_proto->JGetDword(NULL, "discoWnd_favCount", 0); - for (int i = 0; i < count; ++i) - { - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); - m_proto->JDeleteSetting(NULL, setting); - mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", i); - m_proto->JDeleteSetting(NULL, setting); - mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", i); - m_proto->JDeleteSetting(NULL, setting); - } - m_proto->JDeleteSetting(NULL, "discoWnd_favCount"); - } else - if ((res >= 10) && (res <= 20)) - { - switch (res-10) { - case SD_BROWSE_FAVORITES: - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_FAVORITES)); - break; - case SD_BROWSE_MYAGENTS: - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_MYAGENTS)); - break; - case SD_BROWSE_AGENTS: - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_AGENTS)); - break; - case SD_BROWSE_CONFERENCES: - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_CONFERENCES)); - break; - } - SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - } - - CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, FALSE); -} - -void CJabberDlgDiscovery::btnRefresh_OnClick(CCtrlButton *) -{ - HTREELISTITEM hItem = (HTREELISTITEM)TreeList_GetActiveItem(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); - if (!hItem) return; - - m_proto->m_SDManager.Lock(); - XmlNode packet( NULL ); - CJabberSDNode* pNode = (CJabberSDNode* )TreeList_GetData(hItem); - if ( pNode ) { - TreeList_ResetItem(GetDlgItem(m_hwnd, IDC_TREE_DISCO), hItem); - pNode->ResetInfo(); - m_proto->SendBothRequests( pNode, packet ); - TreeList_MakeFakeParent(hItem, FALSE); - } - m_proto->m_SDManager.Unlock(); - - if ( xmlGetChild( packet ,0)) - m_proto->m_ThreadInfo->send( packet ); -} - -void CJabberDlgDiscovery::btnBrowse_OnClick(CCtrlButton *) -{ - SetFocus(GetDlgItem(m_hwnd, m_focusEditAfterBrowse ? IDC_COMBO_JID : IDC_TREE_DISCO)); - m_focusEditAfterBrowse = false; - - m_proto->PerformBrowse(m_hwnd); -} - -void CJabberDlgDiscovery::lstDiscoTree_OnFilter(CCtrlFilterListView *) -{ - TreeList_SetFilter(GetDlgItem(m_hwnd, IDC_TREE_DISCO), m_lstDiscoTree.GetFilterText()); -} - -INT_PTR CJabberDlgDiscovery::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - BOOL result; - if (TreeList_ProcessMessage(m_hwnd, msg, wParam, lParam, IDC_TREE_DISCO, &result)) - return result; - - switch ( msg ) { - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 538; - lpmmi->ptMinTrackSize.y = 374; - return 0; - } - - case WM_JABBER_TRANSPORT_REFRESH: - if (m_proto->m_nSDBrowseMode == SD_BROWSE_MYAGENTS) { - SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_MYAGENTS)); - SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - } - break; - - case WM_JABBER_REFRESH: - KillTimer(m_hwnd, REFRESH_TIMER); - if (GetTickCount() - m_proto->m_dwSDLastRefresh < REFRESH_TIMEOUT) { - SetTimer(m_hwnd, REFRESH_TIMER, REFRESH_TIMEOUT, NULL); - return TRUE; - } - - wParam = REFRESH_TIMER; - // fall through - - case WM_TIMER: - if (wParam == REFRESH_TIMER) { - m_proto->m_SDManager.Lock(); - - CJabberSDNode* pNode = m_proto->m_SDManager.GetPrimaryNode(); - while (pNode) - { - if ( pNode->GetJid()) { - if ( !pNode->GetTreeItemHandle()) { - HTREELISTITEM hNewItem = TreeList_AddItem( - GetDlgItem( m_hwnd, IDC_TREE_DISCO), NULL, - pNode->GetName() ? pNode->GetName() : pNode->GetJid(), - (LPARAM)pNode); - TreeList_AppendColumn(hNewItem, pNode->GetJid()); - TreeList_AppendColumn(hNewItem, pNode->GetNode()); - pNode->SetTreeItemHandle( hNewItem ); - } } - m_proto->SyncTree( NULL, pNode ); - pNode = pNode->GetNext(); - } - m_proto->m_SDManager.Unlock(); - TreeList_Update(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); - KillTimer(m_hwnd, REFRESH_TIMER); - m_proto->m_dwSDLastRefresh = GetTickCount(); - return TRUE; - } - else if (wParam == AUTODISCO_TIMER) { - HWND hwndList = GetDlgItem(m_hwnd, IDC_TREE_DISCO); - RECT rcCtl; GetClientRect(hwndList, &rcCtl); - RECT rcHdr; GetClientRect(ListView_GetHeader(hwndList), &rcHdr); - LVHITTESTINFO lvhti = {0}; - lvhti.pt.x = rcCtl.left + 5; - lvhti.pt.y = rcHdr.bottom + 5; - int iFirst = ListView_HitTest(hwndList, &lvhti); - ZeroMemory(&lvhti, sizeof(lvhti)); - lvhti.pt.x = rcCtl.left + 5; - lvhti.pt.y = rcCtl.bottom - 5; - int iLast = ListView_HitTest(hwndList, &lvhti); - if (iFirst < 0) return FALSE; - if (iLast < 0) iLast = ListView_GetItemCount(hwndList) - 1; - - m_proto->m_SDManager.Lock(); - XmlNode packet( NULL ); - for (int i = iFirst; i <= iLast; ++i) - { - LVITEM lvi = {0}; - lvi.mask = LVIF_PARAM; - lvi.iItem = i; - ListView_GetItem(hwndList, &lvi); - if (!lvi.lParam) - continue; - - CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData((HTREELISTITEM)lvi.lParam); - if (!pNode || pNode->GetInfoRequestId()) - continue; - - m_proto->SendInfoRequest(pNode, packet); - } - m_proto->m_SDManager.Unlock(); - if ( xmlGetChild( packet, 0)) - m_proto->m_ThreadInfo->send( packet ); - - KillTimer(m_hwnd, AUTODISCO_TIMER); - m_proto->m_dwSDLastRefresh = GetTickCount(); - return TRUE; - } - break; - - case WM_CONTEXTMENU: - if (GetWindowLongPtr((HWND)wParam, GWL_ID) == IDC_TREE_DISCO) - { - HWND hwndList = (HWND)wParam; - POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; - - if (( pt.x == -1 ) && ( pt.y == -1 )) { - LVITEM lvi = {0}; - lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); - if (lvi.iItem < 0) return FALSE; - - RECT rc; - ListView_GetItemRect(hwndList, lvi.iItem, &rc, LVIR_LABEL); - pt.x = rc.left; - pt.y = rc.bottom; - ClientToScreen(hwndList, &pt); - } - - HTREELISTITEM hItem = TreeList_GetActiveItem(hwndList); - if (!hItem) break; - CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData(hItem); - if (!pNode) break; - - m_proto->ServiceDiscoveryShowMenu(pNode, hItem, pt); - } - break; - - case WM_NOTIFY: - if ( wParam == IDC_TREE_DISCO ) { - NMHDR* pHeader = (NMHDR* )lParam; - if ( pHeader->code == LVN_GETINFOTIP ) { - NMLVGETINFOTIP *pInfoTip = (NMLVGETINFOTIP *)lParam; - LVITEM lvi; - lvi.mask = LVIF_PARAM; - lvi.iItem = pInfoTip->iItem; - ListView_GetItem(pHeader->hwndFrom, &lvi); - HTREELISTITEM hItem = (HTREELISTITEM)lvi.lParam; - m_proto->m_SDManager.Lock(); - CJabberSDNode* pNode = (CJabberSDNode* )TreeList_GetData(hItem); - if ( pNode ) { - pNode->GetTooltipText( pInfoTip->pszText, pInfoTip->cchTextMax ); - } - m_proto->m_SDManager.Unlock(); - } - else if ( pHeader->code == TVN_ITEMEXPANDED ) { - NMTREEVIEW *pNmTreeView = (NMTREEVIEW *)lParam; - HTREELISTITEM hItem = (HTREELISTITEM)pNmTreeView->itemNew.hItem; - - m_proto->m_SDManager.Lock(); - XmlNode packet( NULL ); - CJabberSDNode* pNode; - pNode = (CJabberSDNode* )TreeList_GetData(hItem); - if ( pNode ) - { - m_proto->SendBothRequests( pNode, packet ); - TreeList_MakeFakeParent(hItem, FALSE); - } - m_proto->m_SDManager.Unlock(); - - if ( xmlGetChild( packet )) - m_proto->m_ThreadInfo->send( packet ); - } - else if ( pHeader->code == NM_CUSTOMDRAW ) { - LPNMLVCUSTOMDRAW lpnmlvcd = (LPNMLVCUSTOMDRAW)lParam; - if (lpnmlvcd->nmcd.dwDrawStage != CDDS_PREPAINT) - return CDRF_DODEFAULT; - - KillTimer(m_hwnd, AUTODISCO_TIMER); - if (GetTickCount() - sttLastAutoDisco < AUTODISCO_TIMEOUT) { - SetTimer(m_hwnd, AUTODISCO_TIMER, AUTODISCO_TIMEOUT, NULL); - return CDRF_DODEFAULT; - } - - SendMessage(m_hwnd, WM_TIMER, AUTODISCO_TIMER, 0); - - return CDRF_DODEFAULT; - } - return TRUE; - } - - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - HWND hwndFocus = GetFocus(); - if (!hwndFocus) return TRUE; - if (GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_TXT_FILTERTEXT) - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BTN_FILTERAPPLY, 0 ), 0 ); - else if (m_hwnd == (hwndFocus = GetParent(hwndFocus))) - break; - else if ((GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_COMBO_NODE) || (GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_COMBO_JID)) - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - return TRUE; - } - case IDCANCEL: - { - PostMessage(m_hwnd, WM_CLOSE, 0, 0); - return TRUE; - } - } - break; - - case WM_MEASUREITEM: - return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); - case WM_DRAWITEM: - return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); - - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -// extern references to used functions: -void SearchAddToRecent( TCHAR* szAddr, HWND hwndDialog = NULL ); - -void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM hItem, POINT pt) -{ - //ClientToScreen(GetDlgItem(hwndServiceDiscovery, IDC_TREE_DISCO), &pt); - - enum { // This values are below CLISTMENUIDMAX and won't overlap - SD_ACT_REFRESH = 1, SD_ACT_REFRESHCHILDREN, SD_ACT_FAVORITE, - SD_ACT_ROSTER, SD_ACT_COPYJID, SD_ACT_COPYNODE, SD_ACT_USERMENU, - SD_ACT_COPYINFO, - - SD_ACT_LOGON = 100, SD_ACT_LOGOFF, SD_ACT_UNREGISTER, - - SD_ACT_REGISTER = 200, SD_ACT_ADHOC, SD_ACT_ADDDIRECTORY, - SD_ACT_JOIN, SD_ACT_BOOKMARK, SD_ACT_PROXY, SD_ACT_VCARD - }; - - enum { - SD_FLG_NONODE = 0x001, - SD_FLG_NOTONROSTER = 0x002, - SD_FLG_ONROSTER = 0x004, - SD_FLG_SUBSCRIBED = 0x008, - SD_FLG_NOTSUBSCRIBED = 0x010, - SD_FLG_ONLINE = 0x020, - SD_FLG_NOTONLINE = 0x040, - SD_FLG_NORESOURCE = 0x080, - SD_FLG_HASUSER = 0x100 - }; - - static struct - { - TCHAR *feature; - TCHAR *title; - int action; - DWORD flags; - } items[] = - { - {NULL, _T("Contact Menu..."), SD_ACT_USERMENU, SD_FLG_NONODE}, - {NULL, _T("View vCard"), SD_ACT_VCARD, SD_FLG_NONODE}, - {_T(JABBER_FEAT_MUC), _T("Join chatroom"), SD_ACT_JOIN, SD_FLG_NORESOURCE}, - {0}, - {NULL, _T("Refresh Info"), SD_ACT_REFRESH}, - {NULL, _T("Refresh Children"), SD_ACT_REFRESHCHILDREN}, - {0}, - {NULL, _T("Add to favorites"), SD_ACT_FAVORITE}, - {NULL, _T("Add to roster"), SD_ACT_ROSTER, SD_FLG_NONODE|SD_FLG_NOTONROSTER}, - {_T(JABBER_FEAT_MUC), _T("Bookmark chatroom"), SD_ACT_BOOKMARK, SD_FLG_NORESOURCE|SD_FLG_HASUSER}, - {_T("jabber:iq:search"), _T("Add search directory"), SD_ACT_ADDDIRECTORY}, - {_T(JABBER_FEAT_BYTESTREAMS), _T("Use this proxy"), SD_ACT_PROXY}, - {0}, - {_T(JABBER_FEAT_REGISTER), _T("Register"), SD_ACT_REGISTER}, - {_T("jabber:iq:gateway"), _T("Unregister"), SD_ACT_UNREGISTER, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED}, - {_T(JABBER_FEAT_COMMANDS), _T("Commands..."), SD_ACT_ADHOC}, - {0}, - {_T("jabber:iq:gateway"), _T("Logon"), SD_ACT_LOGON, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED|SD_FLG_ONLINE}, - {_T("jabber:iq:gateway"), _T("Logoff"), SD_ACT_LOGOFF, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED|SD_FLG_NOTONLINE}, - {0}, - {NULL, _T("Copy JID"), SD_ACT_COPYJID}, - {NULL, _T("Copy node name"), SD_ACT_COPYNODE}, - {NULL, _T("Copy node information"),SD_ACT_COPYINFO}, - }; - - HMENU hMenu = CreatePopupMenu(); - BOOL lastSeparator = TRUE; - bool bFilterItems = !GetAsyncKeyState(VK_CONTROL); - for (int i = 0; i < SIZEOF(items); ++i) - { - JABBER_LIST_ITEM *rosterItem = NULL; - - if (bFilterItems) - { - if ((items[i].flags&SD_FLG_NONODE) && pNode->GetNode()) - continue; - if ((items[i].flags&SD_FLG_NOTONROSTER) && (rosterItem = ListGetItemPtr(LIST_ROSTER, pNode->GetJid()))) - continue; - if ((items[i].flags&SD_FLG_ONROSTER) && !(rosterItem = ListGetItemPtr(LIST_ROSTER, pNode->GetJid()))) - continue; - if ((items[i].flags&SD_FLG_SUBSCRIBED) && (!rosterItem || (rosterItem->subscription == SUB_NONE))) - continue; - if ((items[i].flags&SD_FLG_NOTSUBSCRIBED) && (rosterItem && (rosterItem->subscription != SUB_NONE))) - continue; - if ((items[i].flags&SD_FLG_ONLINE) && rosterItem && (rosterItem->itemResource.status != ID_STATUS_OFFLINE)) - continue; - if ((items[i].flags&SD_FLG_NOTONLINE) && rosterItem && (rosterItem->itemResource.status == ID_STATUS_OFFLINE)) - continue; - if ((items[i].flags&SD_FLG_NORESOURCE) && _tcschr(pNode->GetJid(), _T('/'))) - continue; - if ((items[i].flags&SD_FLG_HASUSER) && !_tcschr(pNode->GetJid(), _T('@'))) - continue; - } - - if (!items[i].feature) - { - if (items[i].title) - { - HANDLE hContact; - if ((items[i].action == SD_ACT_USERMENU) && (hContact = HContactFromJID(pNode->GetJid()))) { - HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); - AppendMenu(hMenu, MF_STRING|MF_POPUP, (UINT_PTR)hContactMenu, TranslateTS(items[i].title)); - } else - AppendMenu(hMenu, MF_STRING, items[i].action, TranslateTS(items[i].title)); - lastSeparator = FALSE; - } else - if (!lastSeparator) - { - AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); - lastSeparator = TRUE; - } - continue; - } - - bool bFeatureOk = !bFilterItems; - if (bFilterItems) - for (CJabberSDFeature *iFeature = pNode->GetFirstFeature(); iFeature; iFeature = iFeature->GetNext()) - if (!lstrcmp(iFeature->GetVar(), items[i].feature)) - { - bFeatureOk = true; - break; - } - - if (bFeatureOk) - { - if (items[i].title) - { - AppendMenu(hMenu, MF_STRING, items[i].action, TranslateTS(items[i].title)); - lastSeparator = FALSE; - } else - if (!lastSeparator) - { - AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); - lastSeparator = TRUE; - } - } - } - - if (!GetMenuItemCount(hMenu)) - { - DestroyMenu(hMenu); - return; - } - - int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlgServiceDiscovery->GetHwnd(), NULL); - DestroyMenu(hMenu); - - switch (res) - { - case SD_ACT_REFRESH: - { - m_SDManager.Lock(); - XmlNode packet( NULL ); - if ( pNode ) - { - TreeList_ResetItem(GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hItem); - pNode->ResetInfo(); - SendBothRequests( pNode, packet ); - TreeList_MakeFakeParent(hItem, FALSE); - } - m_SDManager.Unlock(); - - if ( xmlGetChild( packet )) - m_ThreadInfo->send( packet ); - break; - } - - case SD_ACT_REFRESHCHILDREN: - { - m_SDManager.Lock(); - XmlNode packet( NULL ); - for (int iChild = TreeList_GetChildrenCount(hItem); iChild--; ) { - HTREELISTITEM hNode = TreeList_GetChild(hItem, iChild); - CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData(hNode); - if ( pNode ) - { - TreeList_ResetItem(GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hNode); - pNode->ResetInfo(); - SendBothRequests( pNode, packet ); - TreeList_MakeFakeParent(hNode, FALSE); - } - - if ( xmlGetChildCount( packet ) > 50 ) { - m_ThreadInfo->send( packet ); - packet = XmlNode( NULL ); - } } - m_SDManager.Unlock(); - - if ( xmlGetChildCount( packet )) - m_ThreadInfo->send( packet ); - break; - } - - case SD_ACT_COPYJID: - JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); - break; - - case SD_ACT_COPYNODE: - JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetNode()); - break; - - case SD_ACT_COPYINFO: - { - TCHAR buf[8192]; - pNode->GetTooltipText(buf, SIZEOF(buf)); - JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), buf); - break; - } - - case SD_ACT_FAVORITE: - { - char setting[MAXMODULELABELLENGTH]; - int count = JGetDword(NULL, "discoWnd_favCount", 0); - mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", count); - JSetStringT(NULL, setting, pNode->GetName() ? pNode->GetName() : pNode->GetJid()); - mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", count); - JSetStringT(NULL, setting, pNode->GetJid()); - mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", count); - JSetStringT(NULL, setting, pNode->GetNode() ? pNode->GetNode() : _T("")); - JSetDword(NULL, "discoWnd_favCount", ++count); - break; - } - - case SD_ACT_REGISTER: - RegisterAgent(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); - break; - - case SD_ACT_ADHOC: - ContactMenuAdhocCommands( new CJabberAdhocStartupParams( this, pNode->GetJid(), pNode->GetNode())); - break; - - case SD_ACT_ADDDIRECTORY: - SearchAddToRecent(pNode->GetJid()); - break; - - case SD_ACT_PROXY: - m_options.BsDirect = FALSE; - m_options.BsProxyManual = TRUE; - JSetStringT( NULL, "BsProxyServer", pNode->GetJid()); - break; - - case SD_ACT_JOIN: - if ( jabberChatDllPresent ) - GroupchatJoinRoomByJid(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); - else - JabberChatDllError(); - break; - - case SD_ACT_BOOKMARK: - { - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_BOOKMARK, pNode->GetJid()); - if ( item == NULL ) { - item = ListGetItemPtr( LIST_BOOKMARK, pNode->GetJid()); - if ( item == NULL ) { - item = ListAdd( LIST_ROOM, pNode->GetJid()); - item->name = mir_tstrdup( pNode->GetName()); - } - if ( item != NULL ) { - item->type = _T("conference"); - AddEditBookmark( item ); - } } - break; - } - - case SD_ACT_USERMENU: - { - HANDLE hContact = HContactFromJID( pNode->GetJid()); - if ( !hContact ) { - hContact = DBCreateContact( pNode->GetJid(), pNode->GetName(), TRUE, FALSE ); - JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); - item->bUseResource = TRUE; - } - HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); - GetCursorPos(&pt); - int res = TrackPopupMenu(hContactMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlgServiceDiscovery->GetHwnd(), NULL); - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); - break; - } - - case SD_ACT_VCARD: - { - TCHAR * jid = pNode->GetJid(); - HANDLE hContact = HContactFromJID(pNode->GetJid()); - if ( !hContact ) { - JABBER_SEARCH_RESULT jsr={0}; - mir_sntprintf( jsr.jid, SIZEOF(jsr.jid), _T("%s"), jid ); - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - hContact = ( HANDLE )CallProtoService( m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); - } - if ( ListGetItemPtr( LIST_VCARD_TEMP, pNode->GetJid()) == NULL ) { - JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); - item->bUseResource = TRUE; - if ( item->resource == NULL ) - ListAddResource( LIST_VCARD_TEMP, jid, ID_STATUS_OFFLINE, NULL, 0); - } - CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); - break; - } - - case SD_ACT_ROSTER: - { - HANDLE hContact = DBCreateContact(pNode->GetJid(), pNode->GetName(), FALSE, FALSE); - DBDeleteContactSetting( hContact, "CList", "NotOnList" ); - JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); - item->bUseResource = TRUE; - break; - } - - case SD_ACT_LOGON: - case SD_ACT_LOGOFF: - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), pNode->GetJid()) << XATTR( _T("type"), ( res != SD_ACT_LOGON ) ? _T("unavailable") : NULL )); - break; - - case SD_ACT_UNREGISTER: - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), pNode->GetJid()) << XQUERY( _T(JABBER_FEAT_REGISTER)) << XCHILD( _T("remove"))); - - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) - << XCHILD( _T("item")) << XATTR( _T("jid"), pNode->GetJid()) << XATTR( _T("subscription"), _T("remove"))); - break; - - default: - if ((res >= CLISTMENUIDMIN) && (res <= CLISTMENUIDMAX)) { - HANDLE hContact = HContactFromJID(pNode->GetJid()); - if (hContact) - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); - } - break; - } -} - -void CJabberProto::LaunchServiceDiscovery(TCHAR *jid) -{ - if ( m_pDlgServiceDiscovery ) { - SetForegroundWindow( m_pDlgServiceDiscovery->GetHwnd()); - if (jid) { - SetDlgItemText( m_pDlgServiceDiscovery->GetHwnd(), IDC_COMBO_JID, jid); - SetDlgItemTextA( m_pDlgServiceDiscovery->GetHwnd(), IDC_COMBO_NODE, ""); - PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); - } - } else { - m_pDlgServiceDiscovery = new CJabberDlgDiscovery(this, jid); - m_pDlgServiceDiscovery->Show(); - } -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscovery( WPARAM, LPARAM ) -{ - LaunchServiceDiscovery(NULL); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryMyTransports( WPARAM, LPARAM ) -{ - LaunchServiceDiscovery(_T(SD_FAKEJID_MYAGENTS)); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryTransports( WPARAM, LPARAM ) -{ - LaunchServiceDiscovery(_T(SD_FAKEJID_AGENTS)); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryConferences( WPARAM, LPARAM ) -{ - LaunchServiceDiscovery(_T(SD_FAKEJID_CONFERENCES)); - return 0; -} diff --git a/protocols/JabberG/jabber_disco.h b/protocols/JabberG/jabber_disco.h deleted file mode 100644 index 79df12781e..0000000000 --- a/protocols/JabberG/jabber_disco.h +++ /dev/null @@ -1,493 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2005-07 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_DISCO_H_ -#define _JABBER_DISCO_H_ - -#define CHR_BULLET ((WCHAR)0x2022) -// #define STR_BULLET L" \u2022 " - -#define JABBER_DISCO_RESULT_NOT_REQUESTED 0 -#define JABBER_DISCO_RESULT_ERROR -1 -#define JABBER_DISCO_RESULT_OK -2 - -class CJabberSDIdentity; -class CJabberSDIdentity -{ -protected: - TCHAR *m_szCategory; - TCHAR *m_szType; - TCHAR *m_szName; - CJabberSDIdentity *m_pNext; -public: - CJabberSDIdentity(const TCHAR *szCategory, const TCHAR *szType, const TCHAR *szName) - { - m_szCategory = mir_tstrdup(szCategory); - m_szType = mir_tstrdup(szType); - m_szName = mir_tstrdup(szName); - m_pNext = NULL; - } - ~CJabberSDIdentity() - { - mir_free(m_szCategory); - mir_free(m_szType); - mir_free(m_szName); - if (m_pNext) - delete m_pNext; - } - TCHAR* GetCategory() - { - return m_szCategory; - } - TCHAR* GetType() - { - return m_szType; - } - TCHAR* GetName() - { - return m_szName; - } - CJabberSDIdentity* GetNext() - { - return m_pNext; - } - CJabberSDIdentity* SetNext(CJabberSDIdentity *pNext) - { - CJabberSDIdentity *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } -}; - -class CJabberSDFeature; -class CJabberSDFeature -{ -protected: - TCHAR *m_szVar; - CJabberSDFeature *m_pNext; -public: - CJabberSDFeature(const TCHAR *szVar) - { - m_szVar = szVar ? mir_tstrdup(szVar) : NULL; - m_pNext = NULL; - } - ~CJabberSDFeature() - { - mir_free(m_szVar); - if (m_pNext) - delete m_pNext; - } - TCHAR* GetVar() - { - return m_szVar; - } - CJabberSDFeature* GetNext() - { - return m_pNext; - } - CJabberSDFeature* SetNext(CJabberSDFeature *pNext) - { - CJabberSDFeature *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } -}; - -class CJabberSDNode; -class CJabberSDNode -{ -protected: - TCHAR *m_szJid; - TCHAR *m_szNode; - TCHAR *m_szName; - CJabberSDIdentity *m_pIdentities; - CJabberSDFeature *m_pFeatures; - CJabberSDNode *m_pNext; - CJabberSDNode *m_pChild; - DWORD m_dwInfoRequestTime; - DWORD m_dwItemsRequestTime; - int m_nInfoRequestId; - int m_nItemsRequestId; - HTREELISTITEM m_hTreeItem; - TCHAR *m_szInfoError; - TCHAR *m_szItemsError; -public: - CJabberSDNode( const TCHAR *szJid = NULL, const TCHAR *szNode = NULL, const TCHAR *szName = NULL) - { - m_szJid = mir_tstrdup(szJid); - m_szNode = mir_tstrdup(szNode); - m_szName = mir_tstrdup(szName); - m_pIdentities = NULL; - m_pFeatures = NULL; - m_pNext = NULL; - m_pChild = NULL; - m_dwInfoRequestTime = 0; - m_dwItemsRequestTime = 0; - m_nInfoRequestId = 0; - m_nItemsRequestId = 0; - m_hTreeItem = NULL; - m_szInfoError = NULL; - m_szItemsError = NULL; - } - ~CJabberSDNode() - { - RemoveAll(); - } - BOOL RemoveAll() - { - replaceStrT( m_szJid, NULL ); - replaceStrT( m_szNode, NULL ); - replaceStrT( m_szName, NULL ); - replaceStrT( m_szInfoError, NULL ); - replaceStrT( m_szItemsError, NULL ); - if ( m_pIdentities ) - delete m_pIdentities; - m_pIdentities = NULL; - if ( m_pFeatures ) - delete m_pFeatures; - m_pFeatures = NULL; - if ( m_pNext ) - delete m_pNext; - m_pNext = NULL; - if ( m_pChild ) - delete m_pChild; - m_pChild = NULL; - m_nInfoRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; - m_nItemsRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; - m_dwInfoRequestTime = 0; - m_dwItemsRequestTime = 0; - m_hTreeItem = NULL; - return TRUE; - } - BOOL ResetInfo() - { - replaceStrT( m_szInfoError, NULL ); - replaceStrT( m_szItemsError, NULL ); - if ( m_pIdentities ) - delete m_pIdentities; - m_pIdentities = NULL; - if ( m_pFeatures ) - delete m_pFeatures; - m_pFeatures = NULL; - if ( m_pChild ) - delete m_pChild; - m_pChild = NULL; - m_nInfoRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; - m_nItemsRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; - m_dwInfoRequestTime = 0; - m_dwItemsRequestTime = 0; - return TRUE; - } - BOOL SetTreeItemHandle(HTREELISTITEM hItem) - { - m_hTreeItem = hItem; - return TRUE; - } - HTREELISTITEM GetTreeItemHandle() - { - return m_hTreeItem; - } - BOOL SetInfoRequestId(int nId) - { - m_nInfoRequestId = nId; - m_dwInfoRequestTime = GetTickCount(); - return TRUE; - } - int GetInfoRequestId() - { - return m_nInfoRequestId; - } - BOOL SetItemsRequestId(int nId) - { - m_nItemsRequestId = nId; - m_dwItemsRequestTime = GetTickCount(); - return TRUE; - } - int GetItemsRequestId() - { - return m_nItemsRequestId; - } - BOOL SetJid(TCHAR *szJid) - { - replaceStrT(m_szJid, szJid); - return TRUE; - } - TCHAR* GetJid() - { - return m_szJid; - } - BOOL SetNode(TCHAR *szNode) - { - replaceStrT(m_szNode, szNode); - return TRUE; - } - TCHAR* GetNode() - { - return m_szNode; - } - TCHAR* GetName() - { - return m_szName; - } - CJabberSDIdentity* GetFirstIdentity() - { - return m_pIdentities; - } - CJabberSDFeature* GetFirstFeature() - { - return m_pFeatures; - } - CJabberSDNode* GetFirstChildNode() - { - return m_pChild; - } - CJabberSDNode* GetNext() - { - return m_pNext; - } - CJabberSDNode* SetNext(CJabberSDNode *pNext) - { - CJabberSDNode *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } - CJabberSDNode* FindByIqId(int nIqId, BOOL bInfoId = TRUE) - { - if (( m_nInfoRequestId == nIqId && bInfoId ) || ( m_nItemsRequestId == nIqId && !bInfoId )) - return this; - - CJabberSDNode *pNode = NULL; - if ( m_pChild && (pNode = m_pChild->FindByIqId( nIqId, bInfoId ))) - return pNode; - - CJabberSDNode *pTmpNode = NULL; - pNode = m_pNext; - while ( pNode ) { - if (( pNode->m_nInfoRequestId == nIqId && bInfoId ) || ( pNode->m_nItemsRequestId == nIqId && !bInfoId )) - return pNode; - if ( pNode->m_pChild && (pTmpNode = pNode->m_pChild->FindByIqId( nIqId, bInfoId ))) - return pTmpNode; - pNode = pNode->GetNext(); - } - return NULL; - } - BOOL AddFeature(const TCHAR *szFeature) - { - if ( !szFeature ) - return FALSE; - - CJabberSDFeature *pFeature = new CJabberSDFeature( szFeature ); - if ( !pFeature ) - return FALSE; - - pFeature->SetNext( m_pFeatures ); - m_pFeatures = pFeature; - - return TRUE; - } - BOOL AddIdentity(const TCHAR *szCategory, const TCHAR *szType, const TCHAR *szName) - { - if ( !szCategory || !szType ) - return FALSE; - - CJabberSDIdentity *pIdentity = new CJabberSDIdentity( szCategory, szType, szName ); - if ( !pIdentity ) - return FALSE; - - pIdentity->SetNext( m_pIdentities ); - m_pIdentities = pIdentity; - - return TRUE; - } - BOOL AddChildNode(const TCHAR *szJid, const TCHAR *szNode, const TCHAR *szName) - { - if ( !szJid ) - return FALSE; - - CJabberSDNode *pNode = new CJabberSDNode( szJid, szNode, szName ); - if ( !pNode ) - return FALSE; - - pNode->SetNext( m_pChild ); - m_pChild = pNode; - - return TRUE; - } - BOOL AppendString(TCHAR **ppBuffer, TCHAR *szString) - { - if ( !*ppBuffer ) { - *ppBuffer = mir_tstrdup( szString ); - return TRUE; - } - - *ppBuffer = (TCHAR *)mir_realloc( *ppBuffer, (_tcslen( *ppBuffer) + _tcslen(szString) + 1 ) * sizeof( TCHAR )); - _tcscat(*ppBuffer, szString); - - return TRUE; - } - BOOL SetItemsRequestErrorText(TCHAR *szError) - { - replaceStrT(m_szItemsError, szError); - return TRUE; - } - BOOL SetInfoRequestErrorText(TCHAR *szError) - { - replaceStrT(m_szInfoError, szError); - return TRUE; - } - BOOL GetTooltipText(TCHAR *szText, int nMaxLength) - { - TCHAR *szBuffer = NULL; - - TCHAR szTmp[ 8192 ]; - - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("Jid: %s\r\n"), m_szJid ); - AppendString( &szBuffer, szTmp ); - - if ( m_szNode ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("%s: %s\r\n"), TranslateT("Node"), m_szNode ); - AppendString( &szBuffer, szTmp ); - } - - if ( m_pIdentities ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s:\r\n"), TranslateT("Identities")); - AppendString( &szBuffer, szTmp ); - - CJabberSDIdentity *pIdentity = m_pIdentities; - while ( pIdentity ) { - if ( pIdentity->GetName()) - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s (%s: %s, %s: %s)\r\n"), - CHR_BULLET, pIdentity->GetName(), - TranslateT("category"), pIdentity->GetCategory(), - TranslateT("type"), pIdentity->GetType()); - else - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s: %s, %s: %s\r\n"), - CHR_BULLET, - TranslateT("Category"), pIdentity->GetCategory(), - TranslateT("Type"), pIdentity->GetType()); - - AppendString( &szBuffer, szTmp ); - - pIdentity = pIdentity->GetNext(); - } - } - - if ( m_pFeatures ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s:\r\n"), TranslateT("Supported features")); - AppendString( &szBuffer, szTmp ); - - CJabberSDFeature *pFeature = m_pFeatures; - while ( pFeature ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s\r\n"), CHR_BULLET, pFeature->GetVar()); - - AppendString( &szBuffer, szTmp ); - - pFeature = pFeature->GetNext(); - } - } - - if ( m_szInfoError ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s: %s\r\n"), TranslateT("Info request error"), m_szInfoError ); - AppendString( &szBuffer, szTmp ); - } - - if ( m_szItemsError ) { - mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s: %s\r\n"), TranslateT("Items request error"), m_szItemsError ); - AppendString( &szBuffer, szTmp ); - } - - szBuffer[lstrlen(szBuffer)-2] = 0; // remove CR/LF - mir_sntprintf( szText, nMaxLength, _T("%s"), szBuffer ); - - mir_free( szBuffer ); - - return TRUE; - } -}; - -class CJabberSDManager -{ -protected: - CRITICAL_SECTION m_cs; - CJabberSDNode *m_pPrimaryNodes; -public: - CJabberSDManager() - { - m_pPrimaryNodes = NULL; - InitializeCriticalSection(&m_cs); - } - ~CJabberSDManager() - { - DeleteCriticalSection(&m_cs); - RemoveAll(); - } - void RemoveAll() - { - delete m_pPrimaryNodes; - m_pPrimaryNodes = NULL; - } - BOOL Lock() - { - EnterCriticalSection(&m_cs); - return TRUE; - } - BOOL Unlock() - { - LeaveCriticalSection(&m_cs); - return TRUE; - } - CJabberSDNode* GetPrimaryNode() - { - return m_pPrimaryNodes; - } - CJabberSDNode* AddPrimaryNode(const TCHAR *szJid, const TCHAR *szNode, const TCHAR *szName) - { - if ( !szJid ) - return FALSE; - - CJabberSDNode *pNode = new CJabberSDNode( szJid, szNode, szName ); - if ( !pNode ) - return NULL; - - pNode->SetNext( m_pPrimaryNodes ); - m_pPrimaryNodes = pNode; - - return pNode; - } - CJabberSDNode* FindByIqId(int nIqId, BOOL bInfoId = TRUE) - { - CJabberSDNode *pNode = NULL; - CJabberSDNode *pTmpNode = NULL; - pNode = m_pPrimaryNodes; - while ( pNode ) { - if ( pTmpNode = pNode->FindByIqId( nIqId, bInfoId )) - return pTmpNode; - pNode = pNode->GetNext(); - } - return NULL; - } -}; - -#undef STR_BULLET // used for formatting - -#endif // _JABBER_DISCO_H_ diff --git a/protocols/JabberG/jabber_events.cpp b/protocols/JabberG/jabber_events.cpp deleted file mode 100644 index 3f416aa54b..0000000000 --- a/protocols/JabberG/jabber_events.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#include -#include -#include -#include - -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "m_file.h" -#include "m_addcontact.h" -#include "jabber_disco.h" -#include "m_proto_listeningto.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// OnContactDeleted - processes a contact deletion - -int CJabberProto::OnContactDeleted( WPARAM wParam, LPARAM ) -{ - if ( !m_bJabberOnline ) // should never happen - return 0; - - DBVARIANT dbv; - if ( !JGetStringT(( HANDLE ) wParam, JGetByte( (HANDLE ) wParam, "ChatRoom", 0 )?(char*)"ChatRoomID":(char*)"jid", &dbv )) { - if ( ListExist( LIST_ROSTER, dbv.ptszVal )) { - if ( !_tcschr( dbv.ptszVal, _T( '@' ))) { - TCHAR szStrippedJid[JABBER_MAX_JID_LEN]; - JabberStripJid( m_ThreadInfo->fullJID, szStrippedJid, SIZEOF(szStrippedJid)); - TCHAR *szDog = _tcschr( szStrippedJid, _T('@')); - if ( szDog && _tcsicmp( szDog + 1, dbv.ptszVal )) - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), dbv.ptszVal ) << XQUERY( _T(JABBER_FEAT_REGISTER)) << XCHILD( _T("remove"))); - } - - // Remove from roster, server also handles the presence unsubscription process. - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) - << XCHILD( _T("item")) << XATTR( _T("jid"), dbv.ptszVal ) << XATTR( _T("subscription"), _T("remove"))); - } - - JFreeVariant( &dbv ); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberDbSettingChanged - process database changes - -static TCHAR* sttSettingToTchar( DBCONTACTWRITESETTING* cws ) -{ - switch( cws->value.type ) { - case DBVT_ASCIIZ: - return mir_a2t( cws->value.pszVal ); - - case DBVT_UTF8: - return mir_utf8decodeT( cws->value.pszVal ); - - case DBVT_WCHAR: - return mir_u2t( cws->value.pwszVal ); - } - return NULL; -} - -void __cdecl CJabberProto::OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ) -{ - DBVARIANT jid, dbv; - if ( JGetStringT( hContact, "jid", &jid )) - return; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); - JFreeVariant( &jid ); - if ( item == NULL ) - return; - - TCHAR* nick; - if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) { - nick = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else if ( !JGetStringT( hContact, "Nick", &dbv )) { - nick = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else nick = JabberNickFromJID( item->jid ); - if ( nick == NULL ) - return; - - if ( cws->value.type == DBVT_DELETED ) { - if ( item->group != NULL ) { - Log( "Group set to nothing" ); - AddContactToRoster( item->jid, nick, NULL ); - } - } - else { - TCHAR* p = sttSettingToTchar( cws ); - if ( cws->value.pszVal != NULL && lstrcmp( p, item->group )) { - Log( "Group set to " TCHAR_STR_PARAM, p ); - if ( p ) - AddContactToRoster( item->jid, nick, p ); - } - mir_free( p ); - } - mir_free( nick ); -} - -void __cdecl CJabberProto::OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ) -{ - DBVARIANT jid; - if ( JGetStringT( hContact, "jid", &jid )) - return; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); - JFreeVariant( &jid ); - if ( item == NULL ) - return; - - if ( cws->value.type == DBVT_DELETED ) { - TCHAR* nick = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, GCDNF_NOMYHANDLE | GCDNF_TCHAR ); - AddContactToRoster( item->jid, nick, item->group ); - mir_free(nick); - return; - } - - TCHAR* newNick = sttSettingToTchar( cws ); - if ( newNick ) { - if ( lstrcmp( item->nick, newNick )) { - Log( "Renaming contact " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM " -> " TCHAR_STR_PARAM, item->jid, item->nick, newNick ); - AddContactToRoster( item->jid, newNick, item->group ); - } - mir_free( newNick ); -} } - -void __cdecl CJabberProto::OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ) -{ - if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 )) - return; - - DBVARIANT jid, dbv; - if ( JGetStringT( hContact, "jid", &jid )) - return; - - TCHAR *nick; - Log( "Add " TCHAR_STR_PARAM " permanently to list", jid.pszVal ); - if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) { - nick = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else if ( !JGetStringT( hContact, "Nick", &dbv )) { - nick = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else nick = JabberNickFromJID( jid.ptszVal ); - if ( nick == NULL ) { - JFreeVariant( &jid ); - return; - } - - if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) { - AddContactToRoster( jid.ptszVal, nick, dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else AddContactToRoster( jid.ptszVal, nick, NULL ); - - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), jid.ptszVal ) << XATTR( _T("type"), _T("subscribe"))); - - SendGetVcard( jid.ptszVal ); - - mir_free( nick ); - DBDeleteContactSetting( hContact, "CList", "Hidden" ); - JFreeVariant( &jid ); -} - -int __cdecl CJabberProto::OnDbSettingChanged( WPARAM wParam, LPARAM lParam ) -{ - HANDLE hContact = ( HANDLE ) wParam; - if ( hContact == NULL || !m_bJabberOnline ) - return 0; - - DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam; - if ( strcmp( cws->szModule, "CList" )) - return 0; - - if ( !strcmp( cws->szSetting, "Group" )) - OnRenameGroup( cws, hContact ); - else if ( !strcmp( cws->szSetting, "MyHandle" )) - OnRenameContact( cws, hContact ); - else if ( !strcmp( cws->szSetting, "NotOnList" )) - OnAddContactForever( cws, hContact ); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnIdleChanged - tracks idle start time for XEP-0012 support - -int CJabberProto::OnIdleChanged( WPARAM, LPARAM lParam ) -{ - // don't report idle time, if user disabled - if (lParam & IDF_PRIVACY) { - m_tmJabberIdleStartTime = 0; - return 0; - } - - if ( lParam & IDF_ISIDLE ) { - MIRANDA_IDLE_INFO mii = { 0 }; - mii.cbSize = sizeof( mii ); - CallService( MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii ); - m_tmJabberIdleStartTime = time( 0 ) - mii.idleTime * 60; - } else - m_tmJabberIdleStartTime = 0; - return 0; -} diff --git a/protocols/JabberG/jabber_file.cpp b/protocols/JabberG/jabber_file.cpp deleted file mode 100644 index 5db215d024..0000000000 --- a/protocols/JabberG/jabber_file.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include -#include -#include -#include -#include "jabber_caps.h" - -#define JABBER_NETWORK_BUFFER_SIZE 2048 - -void __cdecl CJabberProto::FileReceiveThread( filetransfer* ft ) -{ - char* buffer; - int datalen; - ThreadData info( this, JABBER_SESSION_NORMAL ); - - Log( "Thread started: type=file_receive server='%s' port='%d'", ft->httpHostName, ft->httpPort ); - - ft->type = FT_OOB; - - if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { - Log( "Cannot allocate network buffer, thread ended" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - delete ft; - return; - } - - NETLIBOPENCONNECTION nloc = { 0 }; - nloc.cbSize = sizeof( nloc ); - nloc.cbSize = sizeof( NETLIBOPENCONNECTION ); - nloc.szHost = ft->httpHostName; - nloc.wPort = ft->httpPort; - info.s = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); - if ( info.s == NULL ) { - Log( "Connection failed ( %d ), thread ended", WSAGetLastError()); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - mir_free( buffer ); - delete ft; - return; - } - - ft->s = info.s; - - info.send( "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", ft->httpPath, ft->httpHostName ); - ft->state = FT_CONNECTING; - - Log( "Entering file_receive recv loop" ); - datalen = 0; - - while ( ft->state != FT_DONE && ft->state != FT_ERROR ) { - int recvResult, bytesParsed; - - Log( "Waiting for data..." ); - recvResult = info.recv( buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen ); - if ( recvResult <= 0 ) - break; - datalen += recvResult; - - bytesParsed = FileReceiveParse( ft, buffer, datalen ); - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - } - - ft->s = NULL; - - if ( ft->state==FT_DONE || ( ft->state==FT_RECEIVING && ft->std.currentFileSize < 0 )) - ft->complete(); - - Log( "Thread ended: type=file_receive server='%s'", ft->httpHostName ); - - mir_free( buffer ); - delete ft; -} - -int CJabberProto::FileReceiveParse( filetransfer* ft, char* buffer, int datalen ) -{ - char* p, *q, *s, *eob; - char* str; - int num, code; - - eob = buffer + datalen; - p = buffer; - num = 0; - while ( true ) { - if ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) { - for ( q=p; q+1state == FT_CONNECTING ) { - // looking for "HTTP/1.1 200 OK" - if ( sscanf( str, "HTTP/%*d.%*d %d %*s", &code )==1 && code==200 ) { - ft->state = FT_INITIALIZING; - ft->std.currentFileSize = -1; - Log( "Change to FT_INITIALIZING" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0 ); - } - } - else { // FT_INITIALIZING - if ( str[0] == '\0' ) { - TCHAR* s; - if (( s = _tcsrchr( ft->httpPath, '/' )) != NULL ) - s++; - else - s = ft->httpPath; - ft->std.tszCurrentFile = mir_tstrdup( s ); - JabberHttpUrlDecode( ft->std.tszCurrentFile ); - if ( ft->create() == -1 ) { - ft->state = FT_ERROR; - break; - } - ft->state = FT_RECEIVING; - ft->std.currentFileProgress = 0; - Log( "Change to FT_RECEIVING" ); - } - else if (( s=strchr( str, ':' )) != NULL ) { - *s = '\0'; - if ( !strcmp( str, "Content-Length" )) - ft->std.totalBytes = ft->std.currentFileSize = _atoi64( s+1 ); - } } - - mir_free( str ); - q += 2; - num += ( q-p ); - p = q; - } - else { - ft->state = FT_ERROR; - break; - } - } - else { - break; - } - } - else if ( ft->state == FT_RECEIVING ) { - int bufferSize, writeSize; - __int64 remainingBytes; - - if ( ft->std.currentFileSize < 0 || ft->std.currentFileProgress < ft->std.currentFileSize ) { - bufferSize = eob - p; - remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress; - if ( remainingBytes < bufferSize ) - writeSize = remainingBytes; - else - writeSize = bufferSize; - if ( _write( ft->fileId, p, writeSize ) != writeSize ) { - Log( "_write() error" ); - ft->state = FT_ERROR; - } - else { - ft->std.currentFileProgress += writeSize; - ft->std.totalProgress += writeSize; - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); - if ( ft->std.currentFileProgress == ft->std.currentFileSize ) - ft->state = FT_DONE; - } - } - num = datalen; - break; - } - else break; - } - - return num; -} - -void JabberFileServerConnection( JABBER_SOCKET hConnection, DWORD /*dwRemoteIP*/, void* extra ) -{ - CJabberProto* ppro = ( CJabberProto* )extra; - - NETLIBCONNINFO connInfo = { sizeof(connInfo) }; - CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hConnection, (LPARAM)&connInfo); - - TCHAR szPort[10]; - mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), connInfo.wPort ); - ppro->Log( "File server incoming connection accepted: %s", connInfo.szIpPort ); - - JABBER_LIST_ITEM *item = ppro->ListGetItemPtr( LIST_FILE, szPort ); - if ( item == NULL ) { - ppro->Log( "No file is currently served, file server connection closed." ); - Netlib_CloseHandle( hConnection ); - return; - } - - filetransfer* ft = item->ft; - JABBER_SOCKET slisten = ft->s; - ft->s = hConnection; - ppro->Log( "Set ft->s to %d ( saving %d )", hConnection, slisten ); - - char* buffer = ( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE+1 ); - if ( buffer == NULL ) { - ppro->Log( "Cannot allocate network buffer, file server connection closed." ); - Netlib_CloseHandle( hConnection ); - ft->state = FT_ERROR; - if ( ft->hFileEvent != NULL ) - SetEvent( ft->hFileEvent ); - return; - } - - ppro->Log( "Entering recv loop for this file connection... ( ft->s is hConnection )" ); - int datalen = 0; - while ( ft->state!=FT_DONE && ft->state!=FT_ERROR ) { - int recvResult, bytesParsed; - - recvResult = Netlib_Recv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); - if ( recvResult <= 0 ) - break; - datalen += recvResult; - - buffer[datalen] = '\0'; - ppro->Log( "RECV:%s", buffer ); - - bytesParsed = ppro->FileSendParse( hConnection, ft, buffer, datalen ); - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - } - - ppro->Log( "Closing connection for this file transfer... ( ft->s is now hBind )" ); - Netlib_CloseHandle( hConnection ); - ft->s = slisten; - ppro->Log( "ft->s is restored to %d", ft->s ); - if ( ft->hFileEvent != NULL ) - SetEvent( ft->hFileEvent ); - mir_free( buffer ); -} - -void __cdecl CJabberProto::FileServerThread( filetransfer* ft ) -{ - Log( "Thread started: type=file_send" ); - - ThreadData info( this, JABBER_SESSION_NORMAL ); - ft->type = FT_OOB; - - NETLIBBIND nlb = {0}; - nlb.cbSize = sizeof( NETLIBBIND ); - nlb.pfnNewConnectionV2 = JabberFileServerConnection; - nlb.pExtra = this; - nlb.wPort = 0; // Use user-specified incoming port ranges, if available - info.s = ( HANDLE ) CallService( MS_NETLIB_BINDPORT, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nlb ); - if ( info.s == NULL ) { - Log( "Cannot allocate port to bind for file server thread, thread ended." ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - delete ft; - return; - } - - ft->s = info.s; - Log( "ft->s = %d", info.s ); - - HANDLE hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - ft->hFileEvent = hEvent; - - TCHAR szPort[20]; - mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort ); - JABBER_LIST_ITEM *item = ListAdd( LIST_FILE, szPort ); - item->ft = ft; - - TCHAR* ptszResource = ListGetBestClientResourceNamePtr( ft->jid ); - if ( ptszResource != NULL ) { - ft->state = FT_CONNECTING; - for ( int i=0; i < ft->std.totalFiles && ft->state != FT_ERROR && ft->state != FT_DENIED; i++ ) { - ft->std.currentFileNumber = i; - ft->state = FT_CONNECTING; - if ( ft->httpPath ) mir_free( ft->httpPath ); - ft->httpPath = NULL; - - TCHAR* p; - if (( p = _tcschr( ft->std.ptszFiles[i], '\\' )) != NULL ) - p++; - else - p = ft->std.ptszFiles[i]; - - TCHAR* pFileName = JabberHttpUrlEncode( p ); - if ( pFileName != NULL ) { - int id = SerialNext(); - if ( ft->iqId ) mir_free( ft->iqId ); - ft->iqId = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( strlen( JABBER_IQID )+20 )); - wsprintf( ft->iqId, _T(JABBER_IQID)_T("%d"), id ); - - char *myAddr = NULL; - DBVARIANT dbv; - if (m_options.BsDirect && m_options.BsDirectManual) { - if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsDirectAddr", &dbv )) - myAddr = dbv.pszVal; - } - - if ( myAddr == NULL ) - myAddr = (char*)CallService( MS_NETLIB_ADDRESSTOSTRING, 1, nlb.dwExternalIP ); - - char szAddr[ 256 ]; - mir_snprintf( szAddr, sizeof(szAddr), "http://%s:%d/%s", myAddr, nlb.wPort, pFileName ); - - mir_free( pFileName ); - mir_free( myAddr ); - - int len = lstrlen(ptszResource) + lstrlen(ft->jid) + 2; - TCHAR* fulljid = ( TCHAR* )alloca( sizeof( TCHAR )*len ); - wsprintf( fulljid, _T("%s/%s"), ft->jid, ptszResource ); - - XmlNodeIq iq( _T("set"), id, fulljid ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_OOB)); - query << XCHILD( _T("url"), _A2T(szAddr)); - query << XCHILD( _T("desc"), ft->szDescription); - m_ThreadInfo->send( iq ); - - Log( "Waiting for the file to be sent..." ); - WaitForSingleObject( hEvent, INFINITE ); - } - Log( "File sent, advancing to the next file..." ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 ); - } - CloseHandle( hEvent ); - ft->hFileEvent = NULL; - Log( "Finish all files" ); - } - - ft->s = NULL; - Log( "ft->s is NULL" ); - - ListRemove( LIST_FILE, szPort ); - - switch ( ft->state ) { - case FT_DONE: - Log( "Finish successfully" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 ); - break; - case FT_DENIED: - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0 ); - break; - default: // FT_ERROR: - Log( "Finish with errors" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - break; - } - - Log( "Thread ended: type=file_send" ); - delete ft; -} - -int CJabberProto::FileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen ) -{ - char* p, *q, *t, *eob; - char* str; - int num; - int currentFile; - int fileId; - int numRead; - - eob = buffer + datalen; - p = buffer; - num = 0; - while ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) { - for ( q=p; q+1= eob ) - break; - if (( str=( char* )mir_alloc( q-p+1 )) == NULL ) { - ft->state = FT_ERROR; - break; - } - strncpy( str, p, q-p ); - str[q-p] = '\0'; - Log( "FT Got: %s", str ); - if ( ft->state == FT_CONNECTING ) { - // looking for "GET filename.ext HTTP/1.1" - if ( !strncmp( str, "GET ", 4 )) { - for ( t=str+4; *t!='\0' && *t!=' '; t++ ); - *t = '\0'; - for ( t=str+4; *t!='\0' && *t=='/'; t++ ); - ft->httpPath = mir_a2t( t ); - JabberHttpUrlDecode( ft->httpPath ); - ft->state = FT_INITIALIZING; - Log( "Change to FT_INITIALIZING" ); - } - } - else { // FT_INITIALIZING - if ( str[0] == '\0' ) { - struct _stati64 statbuf; - - mir_free( str ); - num += 2; - - currentFile = ft->std.currentFileNumber; - TCHAR* t = _tcsrchr( ft->std.ptszFiles[ currentFile ], '\\' ); - if ( t != NULL ) - t++; - else - t = ft->std.ptszFiles[currentFile]; - - if ( ft->httpPath==NULL || lstrcmp( ft->httpPath, t )) { - if ( ft->httpPath == NULL ) - Log( "Requested file name does not matched ( httpPath==NULL )" ); - else - Log( "Requested file name does not matched ( '%s' vs. '%s' )", ft->httpPath, t ); - ft->state = FT_ERROR; - break; - } - Log( "Sending [%s]", ft->std.ptszFiles[ currentFile ] ); - _tstati64( ft->std.ptszFiles[ currentFile ], &statbuf ); // file size in statbuf.st_size - if (( fileId = _topen( ft->std.ptszFiles[currentFile], _O_BINARY|_O_RDONLY )) < 0 ) { - Log( "File cannot be opened" ); - ft->state = FT_ERROR; - mir_free( ft->httpPath ); - ft->httpPath = NULL; - break; - } - - char fileBuffer[ 2048 ]; - int bytes = mir_snprintf( fileBuffer, sizeof(fileBuffer), "HTTP/1.1 200 OK\r\nContent-Length: %I64u\r\n\r\n", statbuf.st_size ); - WsSend( s, fileBuffer, bytes, MSG_DUMPASTEXT ); - - ft->std.flags |= PFTS_SENDING; - ft->std.currentFileProgress = 0; - Log( "Sending file data..." ); - - while (( numRead = _read( fileId, fileBuffer, 2048 )) > 0 ) { - if ( Netlib_Send( s, fileBuffer, numRead, 0 ) != numRead ) { - ft->state = FT_ERROR; - break; - } - ft->std.currentFileProgress += numRead; - ft->std.totalProgress += numRead; - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); - } - _close( fileId ); - if ( ft->state != FT_ERROR ) - ft->state = FT_DONE; - Log( "Finishing this file..." ); - mir_free( ft->httpPath ); - ft->httpPath = NULL; - break; - } } - - mir_free( str ); - q += 2; - num += ( q-p ); - p = q; - } - - return num; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// filetransfer class members - -filetransfer::filetransfer( CJabberProto* proto ) -{ - memset( this, 0, sizeof( filetransfer )); - ppro = proto; - fileId = -1; - std.cbSize = sizeof( std ); - std.flags = PFTS_TCHAR; -} - -filetransfer::~filetransfer() -{ - ppro->Log( "Destroying file transfer session %08p", this ); - - if ( !bCompleted ) - ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0 ); - - close(); - - if ( hWaitEvent != INVALID_HANDLE_VALUE ) - CloseHandle( hWaitEvent ); - - if ( jid ) mir_free( jid ); - if ( sid ) mir_free( sid ); - if ( iqId ) mir_free( iqId ); - if ( fileSize ) mir_free( fileSize ); - if ( httpHostName ) mir_free( httpHostName ); - if ( httpPath ) mir_free( httpPath ); - if ( szDescription ) mir_free( szDescription ); - - if ( std.tszWorkingDir ) mir_free( std.tszWorkingDir ); - if ( std.tszCurrentFile ) mir_free( std.tszCurrentFile ); - - if ( std.ptszFiles ) { - for ( int i=0; i < std.totalFiles; i++ ) - if ( std.ptszFiles[i] ) mir_free( std.ptszFiles[i] ); - - mir_free( std.ptszFiles ); -} } - -void filetransfer::close() -{ - if ( fileId != -1 ) { - _close( fileId ); - fileId = -1; -} } - -void filetransfer::complete() -{ - close(); - - bCompleted = true; - ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0); -} - -int filetransfer::create() -{ - if ( fileId != -1 ) - return fileId; - - TCHAR filefull[ MAX_PATH ]; - mir_sntprintf( filefull, SIZEOF(filefull), _T("%s\\%s"), std.tszWorkingDir, std.tszCurrentFile ); - replaceStrT( std.tszCurrentFile, filefull ); - - if ( hWaitEvent != INVALID_HANDLE_VALUE ) - CloseHandle( hWaitEvent ); - hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - - if ( ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, this, ( LPARAM )&std )) - WaitForSingleObject( hWaitEvent, INFINITE ); - - if ( fileId == -1 ) { - ppro->Log( "Saving to [%s]", std.tszCurrentFile ); - fileId = _topen( std.tszCurrentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE ); - } - - if ( fileId == -1 ) - ppro->Log( "Cannot create file '%s' during a file transfer", filefull ); - else if ( std.currentFileSize != 0 ) - _chsize( fileId, std.currentFileSize ); - - return fileId; -} diff --git a/protocols/JabberG/jabber_form.cpp b/protocols/JabberG/jabber_form.cpp deleted file mode 100644 index a90dcf62fa..0000000000 --- a/protocols/JabberG/jabber_form.cpp +++ /dev/null @@ -1,905 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_caps.h" - - -static BOOL CALLBACK JabberFormMultiLineWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - switch ( msg ) { - //case WM_GETDLGCODE: - // return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTALLKEYS; - case WM_KEYDOWN: - if ( wParam == VK_TAB ) { - SetFocus( GetNextDlgTabItem( GetParent( GetParent( hwnd )), hwnd, GetKeyState( VK_SHIFT )<0?TRUE:FALSE )); - return TRUE; - }; - break; - } - return CallWindowProc(( WNDPROC ) GetWindowLongPtr( hwnd, GWLP_USERDATA ), hwnd, msg, wParam, lParam ); -} - -struct TJabberFormControlInfo -{ - TJabberFormControlType type; - SIZE szBlock; - POINT ptLabel, ptCtrl; - HWND hLabel, hCtrl; -}; -typedef LIST TJabberFormControlList; - -struct TJabberFormLayoutInfo -{ - int ctrlHeight; - int offset, width, maxLabelWidth; - int y_pos, y_spacing; - int id; - bool compact; -}; - -void JabberFormCenterContent(HWND hwndStatic) -{ - RECT rcWindow; - int minX; - GetWindowRect(hwndStatic,&rcWindow); - minX=rcWindow.right; - HWND oldChild=NULL; - HWND hWndChild=GetWindow(hwndStatic,GW_CHILD); - while (hWndChild!=oldChild && hWndChild!=NULL) - { - DWORD style=GetWindowLongPtr(hWndChild, GWL_STYLE); - RECT rc; - GetWindowRect(hWndChild,&rc); - if ((style&SS_RIGHT) && !(style&WS_TABSTOP)) - { - TCHAR * text; - RECT calcRect=rc; - int len=GetWindowTextLength(hWndChild); - text=(TCHAR*)malloc(sizeof(TCHAR)*(len+1)); - GetWindowText(hWndChild,text,len+1); - HDC hdc=GetDC(hWndChild); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hWndChild, WM_GETFONT, 0, 0)); - DrawText(hdc,text,-1,&calcRect,DT_CALCRECT|DT_WORDBREAK); - minX=min(minX, rc.right-(calcRect.right-calcRect.left)); - SelectObject(hdc, hfntSave); - ReleaseDC(hWndChild,hdc); - } - else - { - minX=min(minX,rc.left); - } - oldChild=hWndChild; - hWndChild=GetWindow(hWndChild,GW_HWNDNEXT); - } - if (minX>rcWindow.left+5) - { - int dx=(minX-rcWindow.left)/2; - oldChild=NULL; - hWndChild=GetWindow(hwndStatic,GW_CHILD); - while (hWndChild!=oldChild && hWndChild!=NULL ) - { - DWORD style=GetWindowLongPtr(hWndChild, GWL_STYLE); - RECT rc; - GetWindowRect(hWndChild,&rc); - if ((style&SS_RIGHT) && !(style&WS_TABSTOP)) - MoveWindow(hWndChild,rc.left-rcWindow.left,rc.top-rcWindow.top, rc.right-rc.left-dx, rc.bottom-rc.top, TRUE); - else - MoveWindow(hWndChild,rc.left-dx-rcWindow.left,rc.top-rcWindow.top, rc.right-rc.left, rc.bottom-rc.top, TRUE); - oldChild=hWndChild; - hWndChild=GetWindow(hWndChild,GW_HWNDNEXT); - } - } -} - -void JabberFormSetInstruction( HWND hwndForm, const TCHAR *text ) -{ - if (!text) text = _T(""); - - int len = lstrlen(text); - int fixedLen = len; - for (int i = 1; i < len; ++i) - if ((text[i - 1] == _T('\n')) && (text[i] != _T('\r'))) - ++fixedLen; - TCHAR *fixedText = NULL; - if (fixedLen != len) { - fixedText = (TCHAR *)mir_alloc(sizeof(TCHAR) * (fixedLen+1)); - TCHAR *p = fixedText; - for (int i = 0; i < len; ++i) { - *p = text[i]; - if (i && (text[i] == _T('\n')) && (text[i] != _T('\r'))) { - *p++ = _T('\r'); - *p = _T('\n'); - } - ++p; - } - *p = 0; - text = fixedText; - } - - SetDlgItemText( hwndForm, IDC_INSTRUCTION, text ); - - RECT rcText; - GetWindowRect(GetDlgItem(hwndForm, IDC_INSTRUCTION), &rcText); - int oldWidth = rcText.right-rcText.left; - int deltaHeight = -(rcText.bottom-rcText.top); - - SetRect(&rcText, 0, 0, rcText.right-rcText.left, 0); - HDC hdcEdit = GetDC(GetDlgItem(hwndForm, IDC_INSTRUCTION)); - HFONT hfntSave = (HFONT)SelectObject(hdcEdit, (HFONT)SendDlgItemMessage(hwndForm, IDC_INSTRUCTION, WM_GETFONT, 0, 0)); - DrawTextEx(hdcEdit, (TCHAR *)text, lstrlen(text), &rcText, - DT_CALCRECT|DT_EDITCONTROL|DT_TOP|DT_WORDBREAK, NULL); - SelectObject(hdcEdit, hfntSave); - ReleaseDC(GetDlgItem(hwndForm, IDC_INSTRUCTION), hdcEdit); - - RECT rcWindow; GetClientRect(hwndForm, &rcWindow); - if (rcText.bottom-rcText.top > (rcWindow.bottom-rcWindow.top)/5) { - HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); - SetWindowLongPtr(hwndEdit, GWL_STYLE, WS_VSCROLL | GetWindowLongPtr(hwndEdit, GWL_STYLE)); - rcText.bottom = rcText.top + (rcWindow.bottom-rcWindow.top)/5; - } else { - HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); - SetWindowLongPtr(hwndEdit, GWL_STYLE, ~WS_VSCROLL & GetWindowLongPtr(hwndEdit, GWL_STYLE)); - } - deltaHeight += rcText.bottom-rcText.top; - - SetWindowPos(GetDlgItem(hwndForm, IDC_INSTRUCTION), 0, 0, 0, - oldWidth, - rcText.bottom-rcText.top, - SWP_NOMOVE|SWP_NOZORDER); - - GetWindowRect(GetDlgItem(hwndForm, IDC_WHITERECT), &rcText); - MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); - rcText.bottom += deltaHeight; - SetWindowPos(GetDlgItem(hwndForm, IDC_WHITERECT), 0, 0, 0, - rcText.right-rcText.left, - rcText.bottom-rcText.top, - SWP_NOMOVE|SWP_NOZORDER); - - GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME1), &rcText); - MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); - rcText.top += deltaHeight; - SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME1), 0, - rcText.left, - rcText.top, - 0, 0, - SWP_NOSIZE|SWP_NOZORDER); - - GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME), &rcText); - MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); - rcText.top += deltaHeight; - SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME), 0, - rcText.left, - rcText.top, - rcText.right-rcText.left, - rcText.bottom-rcText.top, - SWP_NOZORDER); - - GetWindowRect(GetDlgItem(hwndForm, IDC_VSCROLL), &rcText); - MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); - rcText.top += deltaHeight; - SetWindowPos(GetDlgItem(hwndForm, IDC_VSCROLL), 0, - rcText.left, - rcText.top, - rcText.right-rcText.left, - rcText.bottom-rcText.top, - SWP_NOZORDER); - - if (fixedText) mir_free(fixedText); -} - -static TJabberFormControlType JabberFormTypeNameToId( const TCHAR *type ) -{ - if ( !_tcscmp( type, _T("text-private"))) - return JFORM_CTYPE_TEXT_PRIVATE; - if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) - return JFORM_CTYPE_TEXT_MULTI; - if ( !_tcscmp( type, _T("boolean"))) - return JFORM_CTYPE_BOOLEAN; - if ( !_tcscmp( type, _T("list-single"))) - return JFORM_CTYPE_LIST_SINGLE; - if ( !_tcscmp( type, _T("list-multi"))) - return JFORM_CTYPE_LIST_MULTI; - if ( !_tcscmp( type, _T("fixed"))) - return JFORM_CTYPE_FIXED; - if ( !_tcscmp( type, _T("hidden"))) - return JFORM_CTYPE_HIDDEN; - // else - return JFORM_CTYPE_TEXT_SINGLE; -} - -void JabberFormLayoutSingleControl(TJabberFormControlInfo *item, TJabberFormLayoutInfo *layout_info, const TCHAR *labelStr, const TCHAR *valueStr) -{ - RECT rcLabel = {0}, rcCtrl = {0}; - if (item->hLabel) - { - SetRect(&rcLabel, 0, 0, layout_info->width, 0); - HDC hdc = GetDC( item->hLabel ); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hLabel, WM_GETFONT, 0, 0)); - DrawText( hdc, labelStr, -1, &rcLabel, DT_CALCRECT|DT_WORDBREAK ); - SelectObject(hdc, hfntSave); - ReleaseDC(item->hLabel, hdc); - } - - int indent = layout_info->compact ? 10 : 20; - - if ((layout_info->compact && (item->type != JFORM_CTYPE_BOOLEAN) && (item->type != JFORM_CTYPE_FIXED))|| - (rcLabel.right >= layout_info->maxLabelWidth) || - (rcLabel.bottom > layout_info->ctrlHeight) || - (item->type == JFORM_CTYPE_LIST_MULTI) || - (item->type == JFORM_CTYPE_TEXT_MULTI)) - { - int height = layout_info->ctrlHeight; - if ((item->type == JFORM_CTYPE_LIST_MULTI) || (item->type == JFORM_CTYPE_TEXT_MULTI)) height *= 3; - SetRect(&rcCtrl, indent, rcLabel.bottom, layout_info->width, rcLabel.bottom + height); - } else - if (item->type == JFORM_CTYPE_BOOLEAN) - { - SetRect(&rcCtrl, 0, 0, layout_info->width-20, 0); - HDC hdc = GetDC( item->hCtrl ); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); - DrawText( hdc, labelStr, -1, &rcCtrl, DT_CALCRECT|DT_RIGHT|DT_WORDBREAK ); - SelectObject(hdc, hfntSave); - ReleaseDC(item->hCtrl, hdc); - rcCtrl.right += 20; - } else - if (item->type == JFORM_CTYPE_FIXED) - { - SetRect(&rcCtrl, 0, 0, layout_info->width, 0); - HDC hdc = GetDC( item->hCtrl ); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); - DrawText( hdc, valueStr, -1, &rcCtrl, DT_CALCRECT|DT_EDITCONTROL ); - rcCtrl.right += 20; - SelectObject(hdc, hfntSave); - ReleaseDC(item->hCtrl, hdc); - } else - { - SetRect(&rcCtrl, rcLabel.right+5, 0, layout_info->width, layout_info->ctrlHeight); - rcLabel.bottom = rcCtrl.bottom; - } - - if (item->hLabel) - SetWindowPos(item->hLabel, 0, - 0, 0, rcLabel.right-rcLabel.left, rcLabel.bottom-rcLabel.top, - SWP_NOZORDER|SWP_NOMOVE); - if (item->hCtrl) - SetWindowPos(item->hCtrl, 0, - 0, 0, rcCtrl.right-rcCtrl.left, rcCtrl.bottom-rcCtrl.top, - SWP_NOZORDER|SWP_NOMOVE); - - item->ptLabel.x = rcLabel.left; - item->ptLabel.y = rcLabel.top; - item->ptCtrl.x = rcCtrl.left; - item->ptCtrl.y = rcCtrl.top; - item->szBlock.cx = layout_info->width; - item->szBlock.cy = max(rcLabel.bottom, rcCtrl.bottom); -} - -#define JabberFormCreateLabel() \ - CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, \ - 0, 0, 0, 0, hwndStatic, ( HMENU )-1, hInst, NULL ) - -TJabberFormControlInfo *JabberFormAppendControl(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, TJabberFormControlType type, const TCHAR *labelStr, const TCHAR *valueStr) -{ - TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); - if (!controls) - { - controls = new TJabberFormControlList(5); - SetWindowLongPtr(hwndStatic, GWLP_USERDATA, (LONG_PTR)controls); - } - - TJabberFormControlInfo *item = (TJabberFormControlInfo *)mir_alloc(sizeof(TJabberFormControlInfo)); - item->type = type; - item->hLabel = item->hCtrl = NULL; - - switch (type) - { - case JFORM_CTYPE_TEXT_PRIVATE: - { - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - ++layout_info->id; - break; - } - case JFORM_CTYPE_TEXT_MULTI: - { - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - WNDPROC oldWndProc = ( WNDPROC ) SetWindowLongPtr( item->hCtrl, GWLP_WNDPROC, ( LONG_PTR )JabberFormMultiLineWndProc ); - SetWindowLongPtr( item->hCtrl, GWLP_USERDATA, ( LONG_PTR ) oldWndProc ); - ++layout_info->id; - break; - } - case JFORM_CTYPE_BOOLEAN: - { - item->hCtrl = CreateWindowEx( 0, _T("button"), labelStr, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - if ( valueStr && !_tcscmp( valueStr, _T("1"))) - SendMessage( item->hCtrl, BM_SETCHECK, 1, 0 ); - ++layout_info->id; - break; - } - case JFORM_CTYPE_LIST_SINGLE: - { - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "combobox", NULL, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - ++layout_info->id; - break; - } - case JFORM_CTYPE_LIST_MULTI: - { - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "listbox", - NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_MULTIPLESEL, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - ++layout_info->id; - break; - } - case JFORM_CTYPE_FIXED: - { - item->hCtrl = CreateWindow( _T("edit"), valueStr, - WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY|ES_AUTOHSCROLL, - 0, 0, 0, 0, - hwndStatic, ( HMENU )-1, hInst, NULL ); - break; - } - case JFORM_CTYPE_HIDDEN: - { - break; - } - case JFORM_CTYPE_TEXT_SINGLE: - { - item->hLabel = labelStr ? (JabberFormCreateLabel()) : NULL; - item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, - 0, 0, 0, 0, - hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); - ++layout_info->id; - break; - } - } - - HFONT hFont = ( HFONT ) SendMessage( GetParent(hwndStatic), WM_GETFONT, 0, 0 ); - if (item->hLabel) SendMessage( item->hLabel, WM_SETFONT, ( WPARAM ) hFont, 0 ); - if (item->hCtrl) SendMessage( item->hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 ); - - JabberFormLayoutSingleControl(item, layout_info, labelStr, valueStr); - - controls->insert(item); - return item; -} - -void JabberFormAddListItem(TJabberFormControlInfo *item, TCHAR *text, bool selected) -{ - DWORD dwIndex; - switch (item->type) - { - case JFORM_CTYPE_LIST_MULTI: - dwIndex = SendMessage(item->hCtrl, LB_ADDSTRING, 0, (LPARAM)text); - if (selected) SendMessage(item->hCtrl, LB_SETSEL, TRUE, dwIndex); - break; - case JFORM_CTYPE_LIST_SINGLE: - dwIndex = SendMessage(item->hCtrl, CB_ADDSTRING, 0, (LPARAM)text); - if (selected) SendMessage(item->hCtrl, CB_SETCURSEL, dwIndex, 0); - break; - } -} - -void JabberFormLayoutControls(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, int *formHeight) -{ - TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); - if (!controls) return; - - for (int i = 0; i < controls->getCount(); ++i) - { - if ((*controls)[i]->hLabel) - SetWindowPos((*controls)[i]->hLabel, 0, - layout_info->offset+(*controls)[i]->ptLabel.x, layout_info->y_pos+(*controls)[i]->ptLabel.y, 0, 0, - SWP_NOZORDER|SWP_NOSIZE); - if ((*controls)[i]->hCtrl) - SetWindowPos((*controls)[i]->hCtrl, 0, - layout_info->offset+(*controls)[i]->ptCtrl.x, layout_info->y_pos+(*controls)[i]->ptCtrl.y, 0, 0, - SWP_NOZORDER|SWP_NOSIZE); - - layout_info->y_pos += (*controls)[i]->szBlock.cy; - layout_info->y_pos += layout_info->y_spacing; - } - - *formHeight = layout_info->y_pos + (layout_info->compact ? 0 : 9); -} - -HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic) -{ - RECT frameRect; - GetClientRect( hwndStatic, &frameRect ); - - TJabberFormLayoutInfo *layout_info = (TJabberFormLayoutInfo *)mir_alloc(sizeof(TJabberFormLayoutInfo)); - layout_info->compact = false; - layout_info->ctrlHeight = 20; - layout_info->id = 0; - layout_info->width = frameRect.right - frameRect.left - 20 - 10; - layout_info->y_spacing = 5; - layout_info->maxLabelWidth = layout_info->width*2/5; - layout_info->offset = 10; - layout_info->y_pos = 14; - return layout_info; -} - -void JabberFormCreateUI( HWND hwndStatic, HXML xNode, int *formHeight, BOOL bCompact ) -{ - JabberFormDestroyUI(hwndStatic); - - HXML v, o, vs; - - int i, j, k; - const TCHAR* label, *typeName, *varStr, *str, *valueText; - TCHAR *labelStr, *valueStr, *p; - RECT frameRect; - - if ( xNode==NULL || xmlGetName( xNode )==NULL || lstrcmp( xmlGetName( xNode ), _T("x")) || hwndStatic==NULL ) return; - - GetClientRect( hwndStatic, &frameRect ); - - TJabberFormLayoutInfo layout_info; - layout_info.compact = bCompact ? true : false; - layout_info.ctrlHeight = 20; - layout_info.id = 0; - layout_info.width = frameRect.right - frameRect.left - 20; - if (!bCompact) layout_info.width -= 10; - layout_info.y_spacing = bCompact ? 1 : 5; - layout_info.maxLabelWidth = layout_info.width*2/5; - layout_info.offset = 10; - layout_info.y_pos = bCompact ? 0 : 14; - for ( i=0; ; i++ ) { - HXML n = xmlGetChild( xNode ,i); - if ( !n ) - break; - - if ( xmlGetName( n )) { - if ( !lstrcmp( xmlGetName( n ), _T("field"))) { - varStr = xmlGetAttrValue( n, _T("var")); - if (( typeName = xmlGetAttrValue( n, _T("type"))) != NULL ) { - if (( label = xmlGetAttrValue( n, _T("label"))) != NULL ) - labelStr = mir_tstrdup( label ); - else - labelStr = mir_tstrdup( varStr ); - - TJabberFormControlType type = JabberFormTypeNameToId(typeName); - - if (( v = xmlGetChild( n , "value" )) != NULL ) - { - valueText = xmlGetText( v ); - if (type != JFORM_CTYPE_TEXT_MULTI) - { - valueStr = mir_tstrdup( valueText ); - } else - { - size_t size = 1; - for ( j=0; ; j++ ) { - v = xmlGetChild( n ,j); - if ( !v ) - break; - if ( xmlGetName( v ) && !lstrcmp( xmlGetName( v ), _T("value")) && xmlGetText( v )) - size += _tcslen( xmlGetText( v )) + 2; - } - valueStr = ( TCHAR* )mir_alloc( sizeof(TCHAR)*size ); - valueStr[0] = '\0'; - for ( j=0; ; j++ ) { - v = xmlGetChild( n ,j); - if ( !v ) - break; - if ( xmlGetName( v ) && !lstrcmp( xmlGetName( v ), _T("value")) && xmlGetText( v )) { - if ( valueStr[0] ) - _tcscat( valueStr, _T("\r\n")); - _tcscat( valueStr, xmlGetText( v )); - } } - } - } else - { - valueText = valueStr = NULL; - } - - TJabberFormControlInfo *item = JabberFormAppendControl(hwndStatic, &layout_info, type, labelStr, valueStr); - - mir_free( labelStr ); - mir_free( valueStr ); - - if (type == JFORM_CTYPE_LIST_SINGLE) - { - for ( j=0; ; j++ ) { - o = xmlGetChild( n ,j); - if ( !o ) - break; - if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { - if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { - if (( str = xmlGetAttrValue( o, _T("label"))) == NULL ) - str = xmlGetText( v ); - if (( p = mir_tstrdup( str )) != NULL ) { - bool selected = false; - if ( valueText != NULL && !_tcscmp( valueText, xmlGetText( v ))) - selected = true; - JabberFormAddListItem(item, p, selected); - mir_free( p ); - } } } } - } else - if (type == JFORM_CTYPE_LIST_MULTI) - { - for ( j=0; ; j++ ) { - o = xmlGetChild( n ,j); - if ( !o ) - break; - if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { - if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { - if (( str = xmlGetAttrValue( o, _T("label"))) == NULL ) - str = xmlGetText( v ); - if (( p = mir_tstrdup( str )) != NULL ) { - bool selected = false; - for ( k=0; ; k++ ) { - vs = xmlGetChild( n ,k); - if ( !vs ) - break; - if ( !lstrcmp( xmlGetName( vs ), _T("value")) && xmlGetText( vs ) && !_tcscmp( xmlGetText( vs ), xmlGetText( v ))) - { - selected = true; - break; - } - } - JabberFormAddListItem( item, p, selected ); - mir_free( p ); - } } } } } } } } } - - JabberFormLayoutControls(hwndStatic, &layout_info, formHeight); -} - -void JabberFormDestroyUI(HWND hwndStatic) -{ - TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); - if (controls) - { - for ( int i = 0; i < controls->getCount(); i++ ) - mir_free((*controls)[i]); - controls->destroy(); - delete controls; - SetWindowLongPtr(hwndStatic, GWLP_USERDATA, 0); - } -} - -HXML JabberFormGetData( HWND hwndStatic, HXML xNode ) -{ - HWND hFrame, hCtrl; - HXML n, v, o; - int id, j, k, len; - const TCHAR *varName, *type, *fieldStr, *labelText, *str2; - TCHAR *p, *q, *str; - - if ( xNode == NULL || xmlGetName( xNode ) == NULL || lstrcmp( xmlGetName( xNode ), _T("x")) || hwndStatic == NULL ) - return NULL; - - hFrame = hwndStatic; - id = 0; - XmlNode x( _T("x")); - x << XATTR( _T("xmlns"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")); - - for ( int i=0; ; i++ ) { - n = xmlGetChild( xNode ,i); - if ( !n ) - break; - - fieldStr = NULL; - if ( lstrcmp( xmlGetName( n ), _T("field"))) - continue; - - if (( varName = xmlGetAttrValue( n, _T("var"))) == NULL || ( type = xmlGetAttrValue( n, _T("type"))) == NULL ) - continue; - - hCtrl = GetDlgItem( hFrame, id ); - HXML field = x << XCHILD( _T("field")) << XATTR( _T("var"), varName ); - - if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) { - len = GetWindowTextLength( GetDlgItem( hFrame, id )); - str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 )); - GetDlgItemText( hFrame, id, str, len+1 ); - p = str; - while ( p != NULL ) { - if (( q = _tcsstr( p, _T("\r\n"))) != NULL ) - *q = '\0'; - field << XCHILD( _T("value"), p ); - p = q ? q+2 : NULL; - } - mir_free( str ); - id++; - } - else if ( !_tcscmp( type, _T("boolean"))) { - TCHAR buf[ 10 ]; - _itot( IsDlgButtonChecked( hFrame, id ) == BST_CHECKED ? 1 : 0, buf, 10 ); - field << XCHILD( _T("value"), buf ); - id++; - } - else if ( !_tcscmp( type, _T("list-single"))) { - len = GetWindowTextLength( GetDlgItem( hFrame, id )); - str = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 )); - GetDlgItemText( hFrame, id, str, len+1 ); - v = NULL; - for ( j=0; ; j++ ) { - o = xmlGetChild( n ,j); - if ( !o ) - break; - - if ( !lstrcmp( xmlGetName( o ), _T("option"))) { - if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { - if (( str2 = xmlGetAttrValue( o, _T("label"))) == NULL ) - str2 = xmlGetText( v ); - if ( !lstrcmp( str2, str )) - break; - } } } - - if ( o ) - field << XCHILD( _T("value"), xmlGetText( v )); - - mir_free( str ); - id++; - } - else if ( !_tcscmp( type, _T("list-multi"))) { - int count = SendMessage( hCtrl, LB_GETCOUNT, 0, 0 ); - for ( j=0; j 0 ) { - // an entry is selected - len = SendMessage( hCtrl, LB_GETTEXTLEN, j, 0 ); - if (( str = ( TCHAR* )mir_alloc(( len+1 )*sizeof( TCHAR ))) != NULL ) { - SendMessage( hCtrl, LB_GETTEXT, j, ( LPARAM )str ); - for ( k=0; ; k++ ) { - o = xmlGetChild( n ,k); - if ( !o ) - break; - - if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { - if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { - if (( labelText = xmlGetAttrValue( o, _T("label"))) == NULL ) - labelText = xmlGetText( v ); - - if ( !lstrcmp( labelText, str )) - field << XCHILD( _T("value"), xmlGetText( v )); - } } } - mir_free( str ); - } } } - id++; - } - else if ( !_tcscmp( type, _T("fixed")) || !_tcscmp( type, _T("hidden"))) { - v = xmlGetChild( n , "value" ); - if ( v != NULL && xmlGetText( v ) != NULL ) - field << XCHILD( _T("value"), xmlGetText( v )); - } - else { // everything else is considered "text-single" or "text-private" - len = GetWindowTextLength( GetDlgItem( hFrame, id )); - str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 )); - GetDlgItemText( hFrame, id, str, len+1 ); - field << XCHILD( _T("value"), str ); - mir_free( str ); - id++; - } } - - return xi.copyNode( x ); -} - -struct JABBER_FORM_INFO -{ - ~JABBER_FORM_INFO(); - - CJabberProto* ppro; - HXML xNode; - TCHAR defTitle[128]; // Default title if no in xNode - RECT frameRect; // Clipping region of the frame to scroll - int frameHeight; // Height of the frame ( can be eliminated, redundant to frameRect ) - int formHeight; // Actual height of the form - int curPos; // Current scroll position - JABBER_FORM_SUBMIT_FUNC pfnSubmit; - void *userdata; -}; - -static INT_PTR CALLBACK JabberFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JABBER_FORM_INFO *jfi; - - switch ( msg ) { - case WM_INITDIALOG: - { - HXML n; - LONG frameExStyle; - - // lParam is ( JABBER_FORM_INFO * ) - TranslateDialogDefault( hwndDlg ); - ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE ); - jfi = ( JABBER_FORM_INFO * ) lParam; - if ( jfi != NULL ) { - // Set dialog title - if ( jfi->xNode!=NULL && ( n = xmlGetChild( jfi->xNode , "title" )) != NULL && xmlGetText( n ) != NULL ) - SetWindowText( hwndDlg, xmlGetText( n )); - else if ( jfi->defTitle != NULL ) - SetWindowText( hwndDlg, TranslateTS( jfi->defTitle )); - // Set instruction field - if ( jfi->xNode!=NULL && ( n = xmlGetChild( jfi->xNode , "instructions" )) != NULL && xmlGetText( n ) != NULL ) - JabberFormSetInstruction( hwndDlg, xmlGetText( n )); - else - { - if ( jfi->xNode != NULL && ( n = xmlGetChild( jfi->xNode , "title" )) != NULL && xmlGetText( n ) != NULL ) - JabberFormSetInstruction( hwndDlg, xmlGetText( n )); - else if ( jfi->defTitle != NULL ) - JabberFormSetInstruction( hwndDlg, TranslateTS( jfi->defTitle )); - } - - // Create form - if ( jfi->xNode != NULL ) { - RECT rect; - - GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &( jfi->frameRect )); - GetClientRect( GetDlgItem( hwndDlg, IDC_VSCROLL ), &rect ); - jfi->frameRect.right -= ( rect.right - rect.left ); - GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &rect ); - jfi->frameHeight = rect.bottom - rect.top; - JabberFormCreateUI( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode, &( jfi->formHeight )); - } - } - - if ( jfi->formHeight > jfi->frameHeight ) { - HWND hwndScroll; - - hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); - EnableWindow( hwndScroll, TRUE ); - SetScrollRange( hwndScroll, SB_CTL, 0, jfi->formHeight - jfi->frameHeight, FALSE ); - jfi->curPos = 0; - } - - // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children ) - frameExStyle = GetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE ); - frameExStyle |= WS_EX_CONTROLPARENT; - SetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); - - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) jfi ); - if ( jfi->pfnSubmit != NULL ) - EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE ); - } - return TRUE; - - case WM_CTLCOLORSTATIC: - if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) - { - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } - - return NULL; - - case WM_MOUSEWHEEL: - { - int zDelta = GET_WHEEL_DELTA_WPARAM( wParam ); - if ( zDelta ) { - int nScrollLines=0; - SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0 ); - for (int i = 0; i < ( nScrollLines + 1 ) / 2; i++ ) - SendMessage( hwndDlg, WM_VSCROLL, ( zDelta < 0 ) ? SB_LINEDOWN : SB_LINEUP, 0 ); - } - } - break; - - case WM_VSCROLL: - jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - if ( jfi != NULL ) { - int pos = jfi->curPos; - switch ( LOWORD( wParam )) { - case SB_LINEDOWN: - pos += 15; - break; - case SB_LINEUP: - pos -= 15; - break; - case SB_PAGEDOWN: - pos += ( jfi->frameHeight - 10 ); - break; - case SB_PAGEUP: - pos -= ( jfi->frameHeight - 10 ); - break; - case SB_THUMBTRACK: - pos = HIWORD( wParam ); - break; - } - if ( pos > ( jfi->formHeight - jfi->frameHeight )) - pos = jfi->formHeight - jfi->frameHeight; - if ( pos < 0 ) - pos = 0; - if ( jfi->curPos != pos ) { - ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, jfi->curPos - pos, NULL, &( jfi->frameRect )); - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); - jfi->curPos = pos; - } - } - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDC_SUBMIT: - jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - if ( jfi != NULL ) { - HXML n = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode ); - ( jfi->ppro->*(jfi->pfnSubmit))( n, jfi->userdata ); - xi.destroyNode( n ); - } - // fall through - case IDCANCEL: - case IDCLOSE: - DestroyWindow( hwndDlg ); - return TRUE; - } - break; - - case WM_CLOSE: - DestroyWindow( hwndDlg ); - break; - - case WM_DESTROY: - JabberFormDestroyUI( GetDlgItem( hwndDlg, IDC_FRAME )); - jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - delete jfi; - break; - } - - return FALSE; -} - -static VOID CALLBACK JabberFormCreateDialogApcProc( void* param ) -{ - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberFormDlgProc, ( LPARAM )param ); -} - -void CJabberProto::FormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ) -{ - JABBER_FORM_INFO *jfi = new JABBER_FORM_INFO; - memset( jfi, 0, sizeof( JABBER_FORM_INFO )); - jfi->ppro = this; - jfi->xNode = xi.copyNode( xNode ); - if ( defTitle ) - _tcsncpy( jfi->defTitle, defTitle, SIZEOF( jfi->defTitle )); - jfi->pfnSubmit = pfnSubmit; - jfi->userdata = userdata; - - CallFunctionAsync( JabberFormCreateDialogApcProc, jfi ); -} - -//======================================================================================= - -JABBER_FORM_INFO::~JABBER_FORM_INFO() -{ - xi.destroyNode( xNode ); - mir_free( userdata ); -} \ No newline at end of file diff --git a/protocols/JabberG/jabber_form2.cpp b/protocols/JabberG/jabber_form2.cpp deleted file mode 100644 index f1936c9e73..0000000000 --- a/protocols/JabberG/jabber_form2.cpp +++ /dev/null @@ -1,1198 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_caps.h" - -#include "jabber_form2.h" - - -///////////////////////////////////////////////////////////////////////////////////////// -// FORM_TYPE Registry -namespace NSJabberRegistry -{ - // http://jabber.org/network/serverinfo - static TJabberDataFormRegisry_Field form_type_serverinfo[] = - { - { _T("abuse-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to abusive traffic") }, - { _T("feedback-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for customer feedback") }, - { _T("sales-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to sales and marketing") }, - { _T("security-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to security concerns") }, - { _T("support-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for customer support") }, - }; - - // http://jabber.org/protocol/admin - static TJabberDataFormRegisry_Field form_type_admin[] = - { - { _T("accountjid"), JDFT_JID_SINGLE, _T("The Jabber ID of a single entity to which an operation applies") }, - { _T("accountjids"), JDFT_JID_MULTI, _T("The Jabber ID of one or more entities to which an operation applies") }, - { _T("activeuserjids"), JDFT_JID_MULTI, _T("The Jabber IDs associated with active sessions") }, - { _T("activeusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities that are active") }, - { _T("adminjids"), JDFT_JID_MULTI, _T("A list of entities with administrative privileges") }, - { _T("announcement"), JDFT_TEXT_MULTI, _T("The text of an announcement to be sent to active users or all users") }, - { _T("blacklistjids"), JDFT_JID_MULTI, _T("A list of entities with whom communication is blocked") }, - { _T("delay"), JDFT_LIST_MULTI, _T("The number of seconds to delay before applying a change") }, - { _T("disableduserjids"), JDFT_JID_MULTI, _T("The Jabber IDs that have been disabled") }, - { _T("disabledusersnum"), JDFT_TEXT_SINGLE, _T("The number of disabled entities") }, - { _T("email"), JDFT_TEXT_SINGLE, _T("The email address for a user") }, - { _T("given_name"), JDFT_TEXT_SINGLE, _T("The given (first) name of a user") }, - { _T("idleusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities that are idle") }, - { _T("ipaddresses"), JDFT_LIST_MULTI, _T("The IP addresses of an account's online sessions") }, - { _T("lastlogin"), JDFT_TEXT_SINGLE, _T("The last login time (per XEP-0082) of a user") }, - { _T("loginsperminute"), JDFT_TEXT_SINGLE, _T("The number of logins per minute for an account") }, - { _T("max_items"), JDFT_LIST_SINGLE, _T("The maximum number of items associated with a search or list") }, - { _T("motd"), JDFT_TEXT_MULTI, _T("The text of a message of the day") }, - { _T("onlineresources"), JDFT_TEXT_SINGLE, _T("The names of an account's online sessions") }, - { _T("onlineuserjids"), JDFT_JID_MULTI, _T("The Jabber IDs associated with online users") }, - { _T("onlineusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities") }, - { _T("password"), JDFT_TEXT_PRIVATE, _T("The password for an account") }, - { _T("password-verify"), JDFT_TEXT_PRIVATE, _T("Password verification") }, - { _T("registereduserjids"), JDFT_JID_MULTI, _T("A list of registered entities") }, - { _T("registeredusersnum"), JDFT_TEXT_SINGLE, _T("The number of registered entities") }, - { _T("rostersize"), JDFT_TEXT_SINGLE, _T("Number of roster items for an account") }, - { _T("stanzaspersecond"), JDFT_TEXT_SINGLE, _T("The number of stanzas being sent per second by an account") }, - { _T("surname"), JDFT_TEXT_SINGLE, _T("The family (last) name of a user") }, - { _T("welcome"), JDFT_TEXT_MULTI, _T("The text of a welcome message") }, - { _T("whitelistjids"), JDFT_JID_MULTI, _T("A list of entities with whom communication is allowed") }, - }; - - // http://jabber.org/protocol/muc#register - static TJabberDataFormRegisry_Field form_type_muc_register[] = - { - { _T("muc#register_first"), JDFT_TEXT_SINGLE, _T("First Name") }, - { _T("muc#register_last"), JDFT_TEXT_SINGLE, _T("Last Name") }, - { _T("muc#register_roomnick"), JDFT_TEXT_SINGLE, _T("Desired Nickname") }, - { _T("muc#register_url"), JDFT_TEXT_SINGLE, _T("Your URL") }, - { _T("muc#register_email"), JDFT_TEXT_SINGLE, _T("Email Address") }, - { _T("muc#register_faqentry"), JDFT_TEXT_MULTI, _T("FAQ Entry") }, - }; - - // http://jabber.org/protocol/muc#roomconfig - static TJabberDataFormRegisry_Field form_type_muc_roomconfig[] = - { - { _T("muc#roomconfig_allowinvites"), JDFT_BOOLEAN, _T("Whether to Allow Occupants to Invite Others") }, - { _T("muc#roomconfig_changesubject"), JDFT_BOOLEAN, _T("Whether to Allow Occupants to Change Subject") }, - { _T("muc#roomconfig_enablelogging"), JDFT_BOOLEAN, _T("Whether to Enable Logging of Room Conversations") }, - { _T("muc#roomconfig_lang"), JDFT_TEXT_SINGLE, _T("Natural Language for Room Discussions") }, - { _T("muc#roomconfig_maxusers"), JDFT_LIST_SINGLE, _T("Maximum Number of Room Occupants") }, - { _T("muc#roomconfig_membersonly"), JDFT_BOOLEAN, _T("Whether an Make Room Members-Only") }, - { _T("muc#roomconfig_moderatedroom"), JDFT_BOOLEAN, _T("Whether to Make Room Moderated") }, - { _T("muc#roomconfig_passwordprotectedroom"), JDFT_BOOLEAN, _T("Whether a Password is Required to Enter") }, - { _T("muc#roomconfig_persistentroom"), JDFT_BOOLEAN, _T("Whether to Make Room Persistent") }, - { _T("muc#roomconfig_presencebroadcast"), JDFT_LIST_MULTI, _T("Roles for which Presence is Broadcast") }, - { _T("muc#roomconfig_publicroom"), JDFT_BOOLEAN, _T("Whether to Allow Public Searching for Room") }, - { _T("muc#roomconfig_roomadmins"), JDFT_JID_MULTI, _T("Full List of Room Admins") }, - { _T("muc#roomconfig_roomdesc"), JDFT_TEXT_SINGLE, _T("Short Description of Room") }, - { _T("muc#roomconfig_roomname"), JDFT_TEXT_SINGLE, _T("Natural-Language Room Name") }, - { _T("muc#roomconfig_roomowners"), JDFT_JID_MULTI, _T("Full List of Room Owners") }, - { _T("muc#roomconfig_roomsecret"), JDFT_TEXT_PRIVATE, _T("The Room Password") }, - { _T("muc#roomconfig_whois"), JDFT_LIST_SINGLE, _T("Affiliations that May Discover Real JIDs of Occupants") }, - }; - - // http://jabber.org/protocol/pubsub#publish-options - static TJabberDataFormRegisry_Field form_type_publish_options[] = - { - { _T("pubsub#access_model"), JDFT_LIST_SINGLE, _T("Precondition: node configuration with the specified access model") }, - }; - - // http://jabber.org/protocol/pubsub#subscribe_authorization - static TJabberDataFormRegisry_Field form_type_subscribe_auth[] = - { - { _T("pubsub#allow"), JDFT_BOOLEAN, _T("Whether to allow the subscription") }, - { _T("pubsub#subid"), JDFT_TEXT_SINGLE, _T("The SubID of the subscription") }, - { _T("pubsub#node"), JDFT_TEXT_SINGLE, _T("The NodeID of the relevant node") }, - { _T("pubsub#subscriber_jid"), JDFT_JID_SINGLE, _T("The address (JID) of the subscriber") }, - }; - - // http://jabber.org/protocol/pubsub#subscribe_options - static TJabberDataFormRegisry_Field form_type_subscribe_options[] = - { - { _T("pubsub#deliver"), JDFT_BOOLEAN, _T("Whether an entity wants to receive or disable notifications") }, - { _T("pubsub#digest"), JDFT_BOOLEAN, _T("Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually") }, - { _T("pubsub#digest_frequency"), JDFT_TEXT_SINGLE, _T("The minimum number of milliseconds between sending any two notification digests") }, - { _T("pubsub#expire"), JDFT_TEXT_SINGLE, _T("The DateTime at which a leased subscription will end or has ended") }, - { _T("pubsub#include_body"), JDFT_BOOLEAN, _T("Whether an entity wants to receive an XMPP message body in addition to the payload format") }, - { _T("pubsub#show-values"), JDFT_LIST_MULTI, _T("The presence states for which an entity wants to receive notifications") }, - { _T("pubsub#subscription_type"), JDFT_LIST_SINGLE, _T("") }, - { _T("pubsub#subscription_depth"), JDFT_LIST_SINGLE, _T("") }, - }; - - // http://jabber.org/protocol/pubsub#node_config - static TJabberDataFormRegisry_Field form_type_node_config[] = - { - { _T("pubsub#access_model"), JDFT_LIST_SINGLE, _T("Who may subscribe and retrieve items") }, - { _T("pubsub#body_xslt"), JDFT_TEXT_SINGLE, _T("The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.") }, - { _T("pubsub#collection"), JDFT_TEXT_SINGLE, _T("The collection with which a node is affiliated") }, - { _T("pubsub#dataform_xslt"), JDFT_TEXT_SINGLE, _T("The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine") }, - { _T("pubsub#deliver_payloads"), JDFT_BOOLEAN, _T("Whether to deliver payloads with event notifications") }, - { _T("pubsub#itemreply"), JDFT_LIST_SINGLE, _T("Whether owners or publisher should receive replies to items") }, - { _T("pubsub#children_association_policy"), JDFT_LIST_SINGLE, _T("Who may associate leaf nodes with a collection") }, - { _T("pubsub#children_association_whitelist"), JDFT_JID_MULTI, _T("The list of JIDs that may associated leaf nodes with a collection") }, - { _T("pubsub#children"), JDFT_TEXT_MULTI, _T("The child nodes (leaf or collection) associated with a collection") }, - { _T("pubsub#children_max"), JDFT_TEXT_SINGLE, _T("The maximum number of child nodes that can be associated with a collection") }, - { _T("pubsub#max_items"), JDFT_TEXT_SINGLE, _T("The maximum number of items to persist") }, - { _T("pubsub#max_payload_size"), JDFT_TEXT_SINGLE, _T("The maximum payload size in bytes") }, - { _T("pubsub#node_type"), JDFT_LIST_SINGLE, _T("Whether the node is a leaf (default) or a collection") }, - { _T("pubsub#notify_config"), JDFT_BOOLEAN, _T("Whether to notify subscribers when the node configuration changes") }, - { _T("pubsub#notify_delete"), JDFT_BOOLEAN, _T("Whether to notify subscribers when the node is deleted") }, - { _T("pubsub#notify_retract"), JDFT_BOOLEAN, _T("Whether to notify subscribers when items are removed from the node") }, - { _T("pubsub#persist_items"), JDFT_BOOLEAN, _T("Whether to persist items to storage") }, - { _T("pubsub#presence_based_delivery"), JDFT_BOOLEAN, _T("Whether to deliver notifications to available users only") }, - { _T("pubsub#publish_model"), JDFT_LIST_SINGLE, _T("The publisher model") }, - { _T("pubsub#replyroom"), JDFT_JID_MULTI, _T("The specific multi-user chat rooms to specify for replyroom") }, - { _T("pubsub#replyto"), JDFT_JID_MULTI, _T("The specific JID(s) to specify for replyto") }, - { _T("pubsub#roster_groups_allowed"), JDFT_LIST_MULTI, _T("The roster group(s) allowed to subscribe and retrieve items") }, - { _T("pubsub#send_item_subscribe"), JDFT_BOOLEAN, _T("Whether to send items to new subscribers") }, - { _T("pubsub#subscribe"), JDFT_BOOLEAN, _T("Whether to allow subscriptions") }, - { _T("pubsub#title"), JDFT_TEXT_SINGLE, _T("A friendly name for the node") }, - { _T("pubsub#type"), JDFT_TEXT_SINGLE, _T("The type of node data, usually specified by the namespace of the payload (if any); MAY be list-single rather than text-single") }, - }; - - // http://jabber.org/protocol/pubsub#meta-data - static TJabberDataFormRegisry_Field form_type_metadata[] = - { - { _T("pubsub#contact"), JDFT_JID_MULTI, _T("The JIDs of those to contact with questions") }, - { _T("pubsub#creation_date"), JDFT_TEXT_SINGLE, _T("The datetime when the node was created") }, - { _T("pubsub#creator"), JDFT_JID_SINGLE, _T("The JID of the node creator") }, - { _T("pubsub#description"), JDFT_TEXT_SINGLE, _T("A description of the node") }, - { _T("pubsub#language"), JDFT_TEXT_SINGLE, _T("The default language of the node") }, - { _T("pubsub#num_subscribers"), JDFT_TEXT_SINGLE, _T("The number of subscribers to the node") }, - { _T("pubsub#owner"), JDFT_JID_MULTI, _T("The JIDs of those with an affiliation of owner") }, - { _T("pubsub#publisher"), JDFT_JID_MULTI, _T("The JIDs of those with an affiliation of publisher") }, - { _T("pubsub#title"), JDFT_TEXT_SINGLE, _T("The name of the node") }, - { _T("pubsub#type"), JDFT_TEXT_SINGLE, _T("Payload type") }, - }; - - // http://jabber.org/protocol/rc - static TJabberDataFormRegisry_Field form_type_rc[] = - { - { _T("auto-auth"), JDFT_BOOLEAN, _T("Whether to automatically authorize subscription requests") }, - { _T("auto-files"), JDFT_BOOLEAN, _T("Whether to automatically accept file transfers") }, - { _T("auto-msg"), JDFT_BOOLEAN, _T("Whether to automatically open new messages") }, - { _T("auto-offline"), JDFT_BOOLEAN, _T("Whether to automatically go offline when idle") }, - { _T("sounds"), JDFT_BOOLEAN, _T("Whether to play sounds") }, - { _T("files"), JDFT_LIST_MULTI, _T("A list of pending file transfers") }, - { _T("groupchats"), JDFT_LIST_MULTI, _T("A list of joined groupchat rooms") }, - { _T("status"), JDFT_LIST_SINGLE, _T("A presence or availability status") }, - { _T("status-message"), JDFT_TEXT_MULTI, _T("The status message text") }, - { _T("status-priority"), JDFT_TEXT_SINGLE, _T("The new priority for the client") }, - }; - - // jabber:iq:register - static TJabberDataFormRegisry_Field form_type_register[] = - { - { _T("username"), JDFT_TEXT_SINGLE, _T("Account name associated with the user") }, - { _T("nick"), JDFT_TEXT_SINGLE, _T("Familiar name of the user") }, - { _T("password"), JDFT_TEXT_PRIVATE, _T("Password or secret for the user") }, - { _T("name"), JDFT_TEXT_SINGLE, _T("Full name of the user") }, - { _T("first"), JDFT_TEXT_SINGLE, _T("First name or given name of the user") }, - { _T("last"), JDFT_TEXT_SINGLE, _T("Last name, surname, or family name of the user") }, - { _T("email"), JDFT_TEXT_SINGLE, _T("Email address of the user") }, - { _T("address"), JDFT_TEXT_SINGLE, _T("Street portion of a physical or mailing address") }, - { _T("city"), JDFT_TEXT_SINGLE, _T("Locality portion of a physical or mailing address") }, - { _T("state"), JDFT_TEXT_SINGLE, _T("Region portion of a physical or mailing address") }, - { _T("zip"), JDFT_TEXT_SINGLE, _T("Postal code portion of a physical or mailing address") }, - }; - - // jabber:iq:search - static TJabberDataFormRegisry_Field form_type_search[] = - { - { _T("first"), JDFT_TEXT_SINGLE, _T("First Name") }, - { _T("last"), JDFT_TEXT_SINGLE, _T("Family Name") }, - { _T("nick"), JDFT_TEXT_SINGLE, _T("Nickname") }, - { _T("email"), JDFT_TEXT_SINGLE, _T("Email Address") }, - }; - - // urn:xmpp:ssn - static TJabberDataFormRegisry_Field form_type_ssn[] = - { - { _T("accept"), JDFT_BOOLEAN, _T("Whether to accept the invitation") }, - { _T("continue"), JDFT_TEXT_SINGLE, _T("Another resource with which to continue the session") }, - { _T("disclosure"), JDFT_LIST_SINGLE, _T("Disclosure of content, decryption keys or identities") }, - { _T("http://jabber.org/protocol/chatstates"), JDFT_LIST_SINGLE, _T("Whether may send Chat State Notifications per XEP-0085") }, - { _T("http://jabber.org/protocol/xhtml-im"), JDFT_LIST_SINGLE, _T("Whether allowed to use XHTML-IM formatting per XEP-0071") }, - { _T("language"), JDFT_LIST_SINGLE, _T("Primary written language of the chat (each value appears in order of preference and conforms to RFC 4646 and the IANA registry)") }, - { _T("logging"), JDFT_LIST_SINGLE, _T("Whether allowed to log messages (i.e., whether Off-The-Record mode is required)") }, - { _T("renegotiate"), JDFT_BOOLEAN, _T("Whether to renegotiate the session") }, - { _T("security"), JDFT_LIST_SINGLE, _T("Minimum security level") }, - { _T("terminate"), JDFT_BOOLEAN, _T("Whether to terminate the session") }, - { _T("urn:xmpp:receipts"), JDFT_BOOLEAN, _T("Whether to enable Message Receipts per XEP-0184") }, - }; - - TJabberDataFormRegisry_Form form_types[] = - { - /*0157*/ { _T("http://jabber.org/network/serverinfo"), form_type_serverinfo, SIZEOF(form_type_serverinfo) }, - /*0133*/ { _T("http://jabber.org/protocol/admin"), form_type_admin, SIZEOF(form_type_admin) }, - /*0045*/ { _T("http://jabber.org/protocol/muc#register"), form_type_muc_register, SIZEOF(form_type_muc_register) }, - /*0045*/ { _T("http://jabber.org/protocol/muc#roomconfig"), form_type_muc_roomconfig, SIZEOF(form_type_muc_roomconfig) }, - /*0060*/ { _T("http://jabber.org/protocol/pubsub#publish-options"), form_type_publish_options, SIZEOF(form_type_publish_options) }, - /*0060*/ { _T("http://jabber.org/protocol/pubsub#subscribe_authorization"), form_type_subscribe_auth, SIZEOF(form_type_subscribe_auth) }, - /*0060*/ { _T("http://jabber.org/protocol/pubsub#subscribe_options"), form_type_subscribe_options, SIZEOF(form_type_subscribe_options) }, - /*0060*/ { _T("http://jabber.org/protocol/pubsub#node_config"), form_type_node_config, SIZEOF(form_type_node_config) }, - /*0060*/ { _T("http://jabber.org/protocol/pubsub#meta-data"), form_type_metadata, SIZEOF(form_type_metadata) }, - /*0146*/ { _T("http://jabber.org/protocol/rc"), form_type_rc, SIZEOF(form_type_rc) }, - /*0077*/ { _T("jabber:iq:register"), form_type_register, SIZEOF(form_type_register) }, - /*0055*/ { _T("jabber:iq:search"), form_type_search, SIZEOF(form_type_search) }, - /*0155*/ { _T("urn:xmpp:ssn"), form_type_ssn, SIZEOF(form_type_ssn) }, - }; -}; - -CJabberDataField::CJabberDataField(CJabberDataForm *form, XmlNode *node): - m_node(node), m_options(5), m_values(1), m_descriptions(1) -{ - m_typeName = JabberXmlGetAttrValue(m_node, "type"); - m_var = JabberXmlGetAttrValue(m_node, "var"); - m_label = JabberXmlGetAttrValue(m_node, "label"); - m_required = JabberXmlGetChild(m_node, "required") ? true : false; - - if (m_typeName) - { - if (!lstrcmp(m_typeName, _T("text-private"))) - m_type = JDFT_TEXT_PRIVATE; - else if (!lstrcmp(m_typeName, _T("text-multi")) || !lstrcmp(m_typeName, _T("jid-multi"))) - m_type = JDFT_TEXT_MULTI; - else if (!lstrcmp(m_typeName, _T("boolean"))) - m_type = JDFT_BOOLEAN; - else if (!lstrcmp(m_typeName, _T("list-single"))) - m_type = JDFT_LIST_SINGLE; - else if (!lstrcmp(m_typeName, _T("list-multi"))) - m_type = JDFT_LIST_MULTI; - else if (!lstrcmp(m_typeName, _T("fixed"))) - m_type = JDFT_FIXED; - else if (!lstrcmp(m_typeName, _T("hidden"))) - m_type = JDFT_HIDDEN; - else - m_type = JDFT_TEXT_SINGLE; - } else - { - m_typeName = _T("text-single"); - m_type = JDFT_TEXT_SINGLE; - } - - for (int i = 0; i < m_node->numChild; ++i) - { - if (!lstrcmpA(m_node->child[i]->name, "value")) - { - m_values.insert(m_node->child[i]->text, m_values.getCount()); - } else - if (!lstrcmpA(m_node->child[i]->name, "option")) - { - TOption *opt = new TOption; - opt->label = JabberXmlGetAttrValue(m_node->child[i], "label"); - opt->value = NULL; - if (XmlNode *p = JabberXmlGetChild(m_node->child[i], "value")) - opt->value = p->text; - m_options.insert(opt, m_options.getCount()); - } else - if (!lstrcmpA(m_node->child[i]->name, "desc")) - { - m_descriptions.insert(m_node->child[i]->text, m_descriptions.getCount()); - } - } -} - -CJabberDataField::~CJabberDataField() -{ - m_values.destroy(); - m_descriptions.destroy(); -} - -CJabberDataFieldSet::CJabberDataFieldSet(): - m_fields(5) -{ -} - -CJabberDataField *CJabberDataFieldSet::GetField(TCHAR *var) -{ - for (int i = 0; i < m_fields.getCount(); ++i) - if (!lstrcmp(m_fields[i].GetVar(), var)) - return &(m_fields[i]); - return NULL; -} - -CJabberDataForm::CJabberDataForm(XmlNode *node): - m_node(node), - m_form_type(0), - m_form_type_info(0), - m_title(0), - m_instructions(1), - m_items(1) -{ - m_typename = JabberXmlGetAttrValue(m_node, "type"); - - for (int i = 0; i < m_node->numChild; ++i) - { - XmlNode *child = m_node->child[i]; - if (!lstrcmpA(child->name, "field")) - { - CJabberDataField *field = new CJabberDataField(this, child); - m_fields.AddField(field); - - if ((field->GetType() == JDFT_HIDDEN) && !lstrcmp(field->GetVar(), _T("FORM_TYPE"))) - { - using NSJabberRegistry::form_types; - - m_form_type = field->GetValue(); - for (int j = 0; j < SIZEOF(form_types); ++j) - if (!lstrcmp(m_form_type, form_types[j].form_type)) - { - m_form_type_info = form_types + j; - break; - } - } - } else - if (!lstrcmpA(child->name, "title")) - { - m_title = child->text; - } else - if (!lstrcmpA(child->name, "instructions")) - { - m_instructions.insert(child->text, m_instructions.getCount()); - } else - if (!lstrcmpA(child->name, "reported")) - { - if (m_reported.GetCount()) - continue; // ignore second <reported/> -> error!!!!!!!!!!! - - for (int j = 0; j < child->numChild; ++j) - { - XmlNode *child2 = child->child[i]; - if (!lstrcmpA(child2->name, "field")) - { - CJabberDataField *field = new CJabberDataField(this, child2); - m_reported.AddField(field); - } - } - } else - if (!lstrcmpA(child->name, "item")) - { - CJabberDataFieldSet *item = new CJabberDataFieldSet; - m_items.insert(item); - - for (int j = 0; j < child->numChild; ++j) - { - XmlNode *child2 = child->child[i]; - if (!lstrcmpA(child2->name, "field")) - { - CJabberDataField *field = new CJabberDataField(this, child2); - item->AddField(field); - } - } - } - } -} - -CJabberDataForm::~CJabberDataForm() -{ -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// UI classes - -#define FORM_CONTROL_MINWIDTH 100 -#define FORM_CONTROL_HEIGHT 20 - -class CFormCtrlBase; - -class CJabberDlgDataPage -{ -public: - CJabberDlgDataPage(HWND hwndParent); - ~CJabberDlgDataPage(); - - void AddField(CJabberDataField *field); - XmlNode *FetchData(); - - HWND GetHwnd() { return m_hwnd; } - void Layout(); - - // internal usage - int AddControl(CFormCtrlBase *ctrl) - { - m_controls.insert(ctrl, m_controls.getCount()); - return m_controls.getCount(); - } - -private: - HWND m_hwnd; - OBJLIST<CFormCtrlBase> m_controls; - int m_scrollPos, m_height, m_dataHeight; - - BOOL DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - static BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -}; - -class CFormCtrlBase -{ -public: - CFormCtrlBase(CJabberDlgDataPage *parent, CJabberDataField *field): - m_field(field), m_parent(parent), - m_hwnd(NULL), m_hwndLabel(NULL) - { - } - - HWND GetHwnd() { return m_hwnd; } - void Init(); - - int Layout(HDWP hdwp, int x, int y, int w); - virtual XmlNode *FetchData() = 0; - -protected: - int m_id; - HWND m_hwnd, m_hwndLabel; - CJabberDataField *m_field; - CJabberDlgDataPage *m_parent; - - virtual void CreateControl() = 0; - virtual int GetHeight(int width) = 0; - SIZE GetControlTextSize(HWND hwnd, int w); - - void CreateLabel(); - void SetupFont(); - XmlNode *CreateNode(); -}; - -void CFormCtrlBase::Init() -{ - m_id = m_parent->AddControl(this); - CreateControl(); - SetupFont(); -} - -SIZE CFormCtrlBase::GetControlTextSize(HWND hwnd, int w) -{ - int length = GetWindowTextLength(hwnd) + 1; - TCHAR *text = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); - GetWindowText(hwnd, text, length); - - RECT rc; - SetRect(&rc, 0, 0, w, 0); - HDC hdc = GetDC(hwnd); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0)); - DrawText(hdc, text, -1, &rc, DT_CALCRECT|DT_WORDBREAK); - SelectObject(hdc, hfntSave); - ReleaseDC(hwnd, hdc); - - mir_free(text); - - SIZE res = { rc.right, rc.bottom }; - return res; -} - -int CFormCtrlBase::Layout(HDWP hdwp, int x, int y, int w) -{ - SIZE szLabel = {0}, szCtrl = {0}; - int h = 0; - - if (m_hwndLabel) - { - SIZE szLabel = GetControlTextSize(m_hwndLabel, w); - - szCtrl.cx = w - szLabel.cx - 5; - szCtrl.cy = GetHeight(szCtrl.cx); - if ((szCtrl.cx >= FORM_CONTROL_MINWIDTH) && (szCtrl.cy <= FORM_CONTROL_HEIGHT)) - { - DeferWindowPos(hdwp, m_hwndLabel, NULL, x, y + (szCtrl.cy - szLabel.cy) / 2, szLabel.cx, szLabel.cy, SWP_NOZORDER|SWP_SHOWWINDOW); - DeferWindowPos(hdwp, m_hwnd, NULL, x + szLabel.cx + 5, y, szCtrl.cx, szCtrl.cy, SWP_NOZORDER|SWP_SHOWWINDOW); - - h = szCtrl.cy; - } else - { - szCtrl.cx = w - 10; - szCtrl.cy = GetHeight(szCtrl.cx); - - DeferWindowPos(hdwp, m_hwndLabel, NULL, x, y, szLabel.cx, szLabel.cy, SWP_NOZORDER|SWP_SHOWWINDOW); - DeferWindowPos(hdwp, m_hwnd, NULL, x + 10, y + szLabel.cy + 2, szCtrl.cx, szCtrl.cy, SWP_NOZORDER|SWP_SHOWWINDOW); - - h = szLabel.cy + 2 + szCtrl.cy; - } - - } else - { - h = GetHeight(w); - DeferWindowPos(hdwp, m_hwnd, NULL, x, y, w, h, SWP_NOZORDER|SWP_SHOWWINDOW); - } - - return h; -} - -void CFormCtrlBase::CreateLabel() -{ - if (m_field->GetLabel()) - { - m_hwndLabel = CreateWindow(_T("static"), m_field->GetLabel(), - WS_CHILD|WS_VISIBLE/*|SS_CENTERIMAGE*/, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)-1, hInst, NULL); - } -} - -void CFormCtrlBase::SetupFont() -{ - if (m_hwnd) - { - HFONT hFont = (HFONT)SendMessage(GetParent(m_hwnd), WM_GETFONT, 0, 0); - if (m_hwnd) SendMessage(m_hwnd, WM_SETFONT, (WPARAM)hFont, 0); - if (m_hwndLabel) SendMessage(m_hwndLabel, WM_SETFONT, (WPARAM) hFont, 0); - } -} - -XmlNode *CFormCtrlBase::CreateNode() -{ - XmlNode* field = new XmlNode("field"); - field->addAttr("var", m_field->GetVar()); - field->addAttr("type", m_field->GetTypeName()); - return field; -} - -class CFormCtrlBoolean: public CFormCtrlBase -{ -public: - CFormCtrlBoolean(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - m_hwnd = CreateWindowEx(0, _T("button"), m_field->GetLabel(), - WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - if (m_field->GetValue() && !_tcscmp(m_field->GetValue(), _T("1"))) - SendMessage(m_hwnd, BM_SETCHECK, 1, 0); - } - - int GetHeight(int width) - { - return GetControlTextSize(m_hwnd, width - 20).cy; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - field->addChild("value", (SendMessage(m_hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) ? _T("1") : _T("0")); - return field; - } -}; - -class CFormCtrlFixed: public CFormCtrlBase -{ -public: - CFormCtrlFixed(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - m_hwnd = CreateWindow(_T("edit"), m_field->GetValue(), - WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)-1, hInst, NULL); - } - - int GetHeight(int width) - { - return GetControlTextSize(m_hwnd, width - 2).cy; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - for (int i = 0; i < m_field->GetValueCount(); ++i) - field->addChild("value", m_field->GetValue(i)); - return field; - } -}; - -class CFormCtrlHidden: public CFormCtrlBase -{ -public: - CFormCtrlHidden(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - } - - int GetHeight(int width) - { - return 0; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - for (int i = 0; i < m_field->GetValueCount(); ++i) - field->addChild("value", m_field->GetValue(i)); - return field; - } -}; -/* -class CFormCtrlJidMulti: public CFormCtrlBase -{ -public: - CFormCtrlJidMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - } - - int GetHeight(int width) - { - return 20; - } - - XmlNode *FetchData() - { - return NULL; - } -}; - -class CFormCtrlJidSingle: public CFormCtrlBase -{ -public: - CFormCtrlJidSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - } - - int GetHeight(int width) - { - return 20; - } - - XmlNode *FetchData() - { - return NULL; - } -}; -*/ -class CFormCtrlListMulti: public CFormCtrlBase -{ -public: - CFormCtrlListMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("listbox"), - NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_MULTIPLESEL, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - - for (int i = 0; i < m_field->GetOptionCount(); ++i) - { - DWORD dwIndex = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)m_field->GetOption(i)->label); - SendMessage(m_hwnd, LB_SETITEMDATA, dwIndex, (LPARAM)m_field->GetOption(i)->value); - for (int j = 0; j < m_field->GetValueCount(); ++j) - if (!lstrcmp_null(m_field->GetValue(j), m_field->GetOption(i)->value)) - { - SendMessage(m_hwnd, LB_SETSEL, TRUE, dwIndex); - break; - } - } - } - - int GetHeight(int width) - { - return 20 * 3; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - int count = SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); - for (int i = 0; i < count; ++i) - if (SendMessage(m_hwnd, LB_GETSEL, i, 0) > 0) - field->addChild("value", (TCHAR *)SendMessage(m_hwnd, LB_GETITEMDATA, i, 0)); - return field; - } -}; - -class CFormCtrlListSingle: public CFormCtrlBase -{ -public: - CFormCtrlListSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("combobox"), NULL, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - - for (int i = 0; i < m_field->GetOptionCount(); ++i) - { - DWORD dwIndex = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)m_field->GetOption(i)->label); - SendMessage(m_hwnd, CB_SETITEMDATA, dwIndex, (LPARAM)m_field->GetOption(i)->value); - if (!lstrcmp_null(m_field->GetValue(), m_field->GetOption(i)->value)) - SendMessage(m_hwnd, CB_SETCURSEL, dwIndex, 0); - } - } - - int GetHeight(int width) - { - return 20; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - int sel = SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); - if (sel != CB_ERR) - field->addChild("value", (TCHAR *)SendMessage(m_hwnd, CB_GETITEMDATA, sel, 0)); - return field; - } -}; - -class CFormCtrlTextMulti: public CFormCtrlBase -{ -public: - CFormCtrlTextMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - int i, length = 1; - for (i = 0; i < m_field->GetValueCount(); ++i) - length += lstrlen(m_field->GetValue(i)) + 2; - - TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); - *str = 0; - for (i = 0; i < m_field->GetValueCount(); ++i) - { - if (i) lstrcat(str, _T("\r\n")); - lstrcat(str, m_field->GetValue(i)); - } - - m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), str, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - // WNDPROC oldWndProc = (WNDPROC)SetWindowLongPtr(item->hCtrl, GWL_WNDPROC, (LPARAM)JabberFormMultiLineWndProc); - // SetWindowLongPtr(item->hCtrl, GWL_USERDATA, (LONG) oldWndProc); - - mir_free(str); - } - - int GetHeight(int width) - { - return 20 * 3; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - int len = GetWindowTextLength(m_hwnd); - TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); - GetWindowText(m_hwnd, str, len+1); - TCHAR *p = str; - while (p != NULL) - { - TCHAR *q = _tcsstr( p, _T("\r\n")); - if (q) *q = '\0'; - field->addChild("value", p); - p = q ? q+2 : NULL; - } - mir_free(str); - return field; - } -}; - -class CFormCtrlTextSingle: public CFormCtrlBase -{ -public: - CFormCtrlTextSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), m_field->GetValue(), - WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - } - - int GetHeight(int width) - { - return 20; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - int len = GetWindowTextLength(m_hwnd); - TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); - GetWindowText(m_hwnd, str, len+1); - field->addChild("value", str); - mir_free(str); - return field; - } -}; - -class CFormCtrlTextPrivate: public CFormCtrlBase -{ -public: - CFormCtrlTextPrivate(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} - - void CreateControl() - { - CreateLabel(); - m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), m_field->GetValue(), - WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, - 0, 0, 0, 0, - m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); - } - - int GetHeight(int width) - { - return 20; - } - - XmlNode *FetchData() - { - XmlNode *field = CreateNode(); - int len = GetWindowTextLength(m_hwnd); - TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); - GetWindowText(m_hwnd, str, len+1); - field->addChild("value", str); - mir_free(str); - return field; - } -}; - -CJabberDlgDataPage::CJabberDlgDataPage(HWND hwndParent): - m_controls(5) -{ - m_hwnd = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DATAFORM_PAGE), hwndParent, DlgProc, (LPARAM)this); - ShowWindow(m_hwnd, SW_SHOW); -} - -CJabberDlgDataPage::~CJabberDlgDataPage() -{ - DestroyWindow(m_hwnd); -} - -void CJabberDlgDataPage::AddField(CJabberDataField *field) -{ - CFormCtrlBase *ctrl = NULL; - - switch (field->GetType()) - { - case JDFT_BOOLEAN: ctrl = new CFormCtrlBoolean(this, field); break; - case JDFT_FIXED: ctrl = new CFormCtrlFixed(this, field); break; - case JDFT_HIDDEN: ctrl = new CFormCtrlHidden(this, field); break; - case JDFT_JID_MULTI: ctrl = new CFormCtrlTextMulti(this, field); break; - case JDFT_JID_SINGLE: ctrl = new CFormCtrlTextSingle(this, field); break; - case JDFT_LIST_MULTI: ctrl = new CFormCtrlListMulti(this, field); break; - case JDFT_LIST_SINGLE: ctrl = new CFormCtrlListSingle(this, field); break; - case JDFT_TEXT_MULTI: ctrl = new CFormCtrlTextMulti(this, field); break; - case JDFT_TEXT_PRIVATE: ctrl = new CFormCtrlTextPrivate(this, field); break; - case JDFT_TEXT_SINGLE: ctrl = new CFormCtrlTextSingle(this, field); break; - } - - if (ctrl) ctrl->Init(); -} - -XmlNode *CJabberDlgDataPage::FetchData() -{ - XmlNode *result = new XmlNode("x"); - result->addAttr("xmlns", JABBER_FEAT_DATA_FORMS); - result->addAttr("type", "submit"); - - for (int i = 0; i < m_controls.getCount(); ++i) - if (XmlNode *field = m_controls[i].FetchData()) - result->addChild(field); - - return result; -} - -void CJabberDlgDataPage::Layout() -{ - RECT rc; GetClientRect(m_hwnd, &rc); - int w = rc.right - 20; - int x = 10; - int y = 10; - - m_height = rc.bottom; - m_scrollPos = GetScrollPos(m_hwnd, SB_VERT); - - HDWP hdwp = BeginDeferWindowPos(m_controls.getCount()); - for (int i = 0; i < m_controls.getCount(); ++i) - if (int h = m_controls[i].Layout(hdwp, x, y - m_scrollPos, w)) - y += h + 5; - EndDeferWindowPos(hdwp); - - m_dataHeight = y + 5; - - SCROLLINFO si = {0}; - si.cbSize = sizeof(si); - si.fMask = SIF_DISABLENOSCROLL|SIF_PAGE|SIF_RANGE; - si.nPage = m_height; - si.nMin = 0; - si.nMax = m_dataHeight; - SetScrollInfo(m_hwnd, SB_VERT, &si, TRUE); -} - -BOOL CJabberDlgDataPage::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - { - SCROLLINFO si = {0}; - si.cbSize = sizeof(si); - si.fMask = SIF_DISABLENOSCROLL; - SetScrollInfo(m_hwnd, SB_VERT, &si, TRUE); - m_scrollPos = 0; - - break; - } - - case WM_MOUSEWHEEL: - { - int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); - if (zDelta) - { - int i, nScrollLines = 0; - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0); - for (i = 0; i < (nScrollLines + 1) / 2; i++ ) - SendMessage(m_hwnd, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0); - } - - SetWindowLongPtr(m_hwnd, DWL_MSGRESULT, 0); - return TRUE; - } - - case WM_VSCROLL: - { - int pos = m_scrollPos; - switch (LOWORD(wParam)) - { - case SB_LINEDOWN: - pos += 15; - break; - case SB_LINEUP: - pos -= 15; - break; - case SB_PAGEDOWN: - pos += m_height - 10; - break; - case SB_PAGEUP: - pos -= m_height - 10; - break; - case SB_THUMBTRACK: - pos = HIWORD(wParam); - break; - } - - if (pos > m_dataHeight - m_height) pos = m_dataHeight - m_height; - if (pos < 0) pos = 0; - - if (m_scrollPos != pos) - { - ScrollWindow(m_hwnd, 0, m_scrollPos - pos, NULL, NULL); - SetScrollPos(m_hwnd, SB_VERT, pos, TRUE); - m_scrollPos = pos; - } - break; - } - - case WM_SIZE: - Layout(); - break; - } - - return FALSE; -} - -BOOL CJabberDlgDataPage::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CJabberDlgDataPage *pThis = NULL; - - if (msg == WM_INITDIALOG) - { - if (pThis = (CJabberDlgDataPage *)lParam) - pThis->m_hwnd = hwnd; - SetWindowLongPtr(hwnd, GWL_USERDATA, lParam); - } else - { - pThis = (CJabberDlgDataPage *)GetWindowLongPtr(hwnd, GWL_USERDATA); - } - - if (pThis) - { - BOOL result = pThis->DlgProc(msg, wParam, lParam); - if (msg == WM_DESTROY) - { - pThis->m_hwnd = NULL; - SetWindowLongPtr(hwnd, GWL_USERDATA, 0); - } - return result; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////// -// Data form control -- Window class support -const TCHAR *CCtrlJabberForm::ClassName = _T("JabberDataFormControl"); -bool CCtrlJabberForm::ClassRegistered = false; - -bool CCtrlJabberForm::RegisterClass() -{ - if (ClassRegistered) return true; - - WNDCLASSEX wcx = {0}; - wcx.cbSize = sizeof(wcx); - wcx.lpszClassName = ClassName; - wcx.lpfnWndProc = DefWindowProc; - wcx.hCursor = LoadCursor(NULL, IDC_ARROW); - wcx.hbrBackground = 0; - wcx.style = CS_GLOBALCLASS; - - if (::RegisterClassEx(&wcx)) - ClassRegistered = true; - - return ClassRegistered; -} - -bool CCtrlJabberForm::UnregisterClass() -{ - if (!ClassRegistered) return true; - - if (::UnregisterClass(ClassName, hInst) == 0) - ClassRegistered = false; - - return !ClassRegistered; -} - -///////////////////////////////////////////////////////////////////////////////// -// Data form control -CCtrlJabberForm::CCtrlJabberForm(CDlgBase* dlg, int ctrlId): - CCtrlBase(dlg, ctrlId), m_pForm(NULL), m_pDlgPage(NULL) -{ -} - -CCtrlJabberForm::~CCtrlJabberForm() -{ - if (m_pDlgPage) delete m_pDlgPage; -} - -void CCtrlJabberForm::OnInit() -{ - CSuper::OnInit(); - Subclass(); - SetupForm(); -} - -void CCtrlJabberForm::SetDataForm(CJabberDataForm *pForm) -{ - if (m_pDlgPage) - { - delete m_pDlgPage; - m_pDlgPage = NULL; - } - - m_pForm = pForm; - SetupForm(); -} - -XmlNode *CCtrlJabberForm::FetchData() -{ - return m_pDlgPage ? m_pDlgPage->FetchData() : NULL; -} - -void CCtrlJabberForm::SetupForm() -{ - if (!m_pForm || !m_hwnd) return; - - m_pDlgPage = new CJabberDlgDataPage(m_hwnd); - for (int i = 0; i < m_pForm->GetFields()->GetCount(); ++i) - m_pDlgPage->AddField(m_pForm->GetFields()->GetField(i)); - - Layout(); -} - -void CCtrlJabberForm::Layout() -{ - if (!m_pDlgPage) return; - - RECT rc; - GetClientRect(m_hwnd, &rc); - SetWindowPos(m_pDlgPage->GetHwnd(), NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER); -} - -LRESULT CCtrlJabberForm::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_SIZE: - { - Layout(); - break; - } - } - - return CSuper::CustomWndProc(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////// -// testing -class CJabberDlgFormTest: public CDlgBase -{ -public: - CJabberDlgFormTest(CJabberDataForm *pForm): - CDlgBase(IDD_DATAFORM_TEST, NULL), - m_frm(this, IDC_DATAFORM) - { - m_frm.SetDataForm(pForm); - } - - int Resizer(UTILRESIZECONTROL *urc) - { - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - } - -private: - CCtrlJabberForm m_frm; -}; - -static VOID CALLBACK CreateDialogApcProc(void* param) -{ - XmlNode *node = (XmlNode *)param; - - CJabberDataForm form(node); - - CCtrlJabberForm::RegisterClass(); - CJabberDlgFormTest dlg(&form); - dlg.DoModal(); - - delete node; -} - -void LaunchForm(XmlNode *node) -{ - node = JabberXmlCopyNode(node); - CallFunctionAsync(CreateDialogApcProc, node); -} diff --git a/protocols/JabberG/jabber_form2.h b/protocols/JabberG/jabber_form2.h deleted file mode 100644 index 051eb8571f..0000000000 --- a/protocols/JabberG/jabber_form2.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -enum TJabberDataFormType -{ - JDFT_BOOLEAN, - JDFT_FIXED, - JDFT_HIDDEN, - JDFT_JID_MULTI, - JDFT_JID_SINGLE, - JDFT_LIST_MULTI, - JDFT_LIST_SINGLE, - JDFT_TEXT_MULTI, - JDFT_TEXT_PRIVATE, - JDFT_TEXT_SINGLE, -}; - -struct TJabberDataFormRegisry_Field -{ - TCHAR *field; - TJabberDataFormType type; - TCHAR *description_en; - TCHAR *description_tr; -}; - -struct TJabberDataFormRegisry_Form -{ - TCHAR *form_type; - TJabberDataFormRegisry_Field *fields; - int count; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Forwards -class CJabberDlgDataForm; -class CJabberDataField; -class CJabberDataFieldSet; -class CJabberDataForm; -class CJabberDlgDataPage; - -///////////////////////////////////////////////////////////////////////////////////////// -// Data form classes -class CJabberDataField -{ -public: - struct TOption - { - TCHAR *label; - TCHAR *value; - }; - - CJabberDataField(CJabberDataForm *form, XmlNode *node); - ~CJabberDataField(); - - XmlNode *GetNode() { return m_node; } - - TCHAR *GetTypeName() { return m_typeName; } - TJabberDataFormType GetType() { return m_type; } - - TCHAR *GetVar() { return m_var; } - - bool IsRequired() { return m_required; } - TCHAR *GetDescription(int i) { return m_descriptions[i]; } - TCHAR *GetLabel() { return m_label; } - - int GetValueCount() { return m_values.getCount(); } - TCHAR *GetValue(int i = 0) { return m_values[i]; } - - int GetOptionCount() { return m_options.getCount(); } - TOption *GetOption(int i) { return &(m_options[i]); } - -private: - XmlNode *m_node; - CJabberDataFieldSet *m_fieldset; - - bool m_required; - TCHAR *m_var; - TCHAR *m_label; - TCHAR *m_typeName; - TJabberDataFormType m_type; - - OBJLIST<TOption> m_options; - LIST<TCHAR> m_values; - LIST<TCHAR> m_descriptions; -}; - -class CJabberDataFieldSet -{ -public: - CJabberDataFieldSet(); - - int GetCount() { return m_fields.getCount(); } - CJabberDataField *GetField(int i) { return &(m_fields[i]); } - CJabberDataField *GetField(TCHAR *var); - - void AddField(CJabberDataField *field) { m_fields.insert(field, m_fields.getCount()); } - -private: - OBJLIST<CJabberDataField> m_fields; -}; - -class CJabberDataForm -{ -public: - enum TFormType { TYPE_NONE, TYPE_FORM, TYPE_SUBMIT, TYPE_CANCEL, TYPE_RESULT }; - - CJabberDataForm(XmlNode *node); - ~CJabberDataForm(); - - TCHAR *GetTypeName() const { return m_typename; } - TFormType GetType() const { return m_type; } - TCHAR *GetFormType() const { return m_form_type; } - TCHAR *GetTitle() const { return m_title; } - int GetInstructionsCount() const { return m_instructions.getCount(); } - TCHAR *GetInstructions(int idx=0) const { return m_instructions[idx]; } - - CJabberDataFieldSet *GetFields() { return &m_fields; } - - CJabberDataFieldSet *GetReported() { return &m_reported; } - int GetItemCount() { return m_items.getCount(); } - CJabberDataFieldSet *GetItem(int i) { return &(m_items[i]); } - -private: - XmlNode *m_node; - - TCHAR *m_typename; - TFormType m_type; - - TCHAR *m_form_type; - TJabberDataFormRegisry_Form *m_form_type_info; - - TCHAR *m_title; - LIST<TCHAR> m_instructions; - - CJabberDataFieldSet m_fields; - CJabberDataFieldSet m_reported; - OBJLIST<CJabberDataFieldSet> m_items; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// UI Control -class CCtrlJabberForm: public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - static const TCHAR *ClassName; - static bool RegisterClass(); - static bool UnregisterClass(); - - CCtrlJabberForm(CDlgBase* dlg, int ctrlId); - ~CCtrlJabberForm(); - - void OnInit(); - void SetDataForm(CJabberDataForm *pForm); - XmlNode *FetchData(); - -protected: - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - -private: - static bool ClassRegistered; - - CJabberDataForm *m_pForm; - CJabberDlgDataPage *m_pDlgPage; - - void SetupForm(); - void Layout(); -}; diff --git a/protocols/JabberG/jabber_ft.cpp b/protocols/JabberG/jabber_ft.cpp deleted file mode 100644 index 4ded28d84d..0000000000 --- a/protocols/JabberG/jabber_ft.cpp +++ /dev/null @@ -1,551 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include <io.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "jabber_iq.h" -#include "jabber_byte.h" -#include "jabber_ibb.h" -#include "jabber_caps.h" - -void CJabberProto::FtCancel( filetransfer* ft ) -{ - JABBER_LIST_ITEM *item; - JABBER_BYTE_TRANSFER *jbt; - JABBER_IBB_TRANSFER *jibb; - - Log( "Invoking JabberFtCancel()" ); - - // For file sending session that is still in si negotiation phase - if ( m_iqManager.ExpireByUserData( ft )) - return; - // For file receiving session that is still in si negotiation phase - LISTFOREACH(i, this, LIST_FTRECV) - { - item = ListGetItemPtrFromIndex( i ); - if ( item->ft == ft ) { - Log( "Canceling file receiving session while in si negotiation" ); - ListRemoveByIndex( i ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - delete ft; - return; - } - } - // For file transfer through bytestream - if (( jbt=ft->jbt ) != NULL ) { - Log( "Canceling bytestream session" ); - jbt->state = JBT_ERROR; - if ( jbt->hConn ) { - Log( "Force closing bytestream session" ); - Netlib_CloseHandle( jbt->hConn ); - jbt->hConn = NULL; - } - if ( jbt->hSendEvent ) SetEvent( jbt->hSendEvent ); - if ( jbt->hEvent ) SetEvent( jbt->hEvent ); - if ( jbt->hProxyEvent ) SetEvent( jbt->hProxyEvent ); - } - // For file transfer through IBB - if (( jibb=ft->jibb ) != NULL ) { - Log( "Canceling IBB session" ); - jibb->state = JIBB_ERROR; - m_iqManager.ExpireByUserData( jibb ); - } -} - -///////////////// File sending using stream initiation ///////////////////////// - -void CJabberProto::FtInitiate( TCHAR* jid, filetransfer* ft ) -{ - TCHAR *rs; - TCHAR *filename, *p; - int i; - TCHAR sid[9]; - - if ( jid==NULL || ft==NULL || !m_bJabberOnline || ( rs=ListGetBestClientResourceNamePtr( jid ))==NULL ) { - if ( ft ) { - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); - delete ft; - } - return; - } - ft->type = FT_SI; - for ( i=0; i<8; i++ ) - sid[i] = ( rand()%10 ) + '0'; - sid[8] = '\0'; - if ( ft->sid != NULL ) mir_free( ft->sid ); - ft->sid = mir_tstrdup( sid ); - filename = ft->std.ptszFiles[ ft->std.currentFileNumber ]; - if (( p = _tcsrchr( filename, '\\' )) != NULL ) - filename = p+1; - - TCHAR tszJid[ 512 ]; - mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), jid, rs ); - - XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnFtSiResult, JABBER_IQ_TYPE_SET, tszJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO, -1, ft )); - HXML si = iq << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) << XATTR( _T("id"), sid ) - << XATTR( _T("mime-type"), _T("binary/octet-stream")) << XATTR( _T("profile"), _T(JABBER_FEAT_SI_FT)); - si << XCHILDNS( _T("file"), _T(JABBER_FEAT_SI_FT)) << XATTR( _T("name"), filename) - << XATTRI64( _T("size"), ft->fileSize[ ft->std.currentFileNumber ] ) << XCHILD( _T("desc"), ft->szDescription); - - HXML field = si << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")) - << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) << XATTR( _T("type"), _T("list-single")); - - BOOL bDirect = m_options.BsDirect; - BOOL bProxy = m_options.BsProxyManual; - - // bytestreams support? - if ( bDirect || bProxy ) - field << XCHILD( _T("option")) << XCHILD( _T("value"), _T(JABBER_FEAT_BYTESTREAMS)); - - field << XCHILD( _T("option")) << XCHILD( _T("value"), _T(JABBER_FEAT_IBB)); - m_ThreadInfo->send( iq ); -} - -void CJabberProto::OnFtSiResult( HXML iqNode, CJabberIqInfo* pInfo ) -{ - HXML siNode, featureNode, xNode, fieldNode, valueNode; - filetransfer *ft = (filetransfer *)pInfo->GetUserData(); - if ( !ft ) return; - - if (( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) && pInfo->m_szFrom && pInfo->m_szTo ) { - if (( siNode = xmlGetChild( iqNode , "si" )) != NULL ) { - - // fix for very smart clients, like gajim - BOOL bDirect = m_options.BsDirect; - BOOL bProxy = m_options.BsProxyManual; - - if (( featureNode = xmlGetChild( siNode , "feature" )) != NULL ) { - if (( xNode = xmlGetChildByTag( featureNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS))) != NULL ) { - if (( fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("stream-method"))) != NULL ) { - if (( valueNode = xmlGetChild( fieldNode , "value" ))!=NULL && xmlGetText( valueNode )!=NULL ) { - if (( bDirect || bProxy ) && !_tcscmp( xmlGetText( valueNode ), _T(JABBER_FEAT_BYTESTREAMS))) { - // Start Bytestream session - JABBER_BYTE_TRANSFER *jbt = new JABBER_BYTE_TRANSFER; - ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER )); - jbt->srcJID = mir_tstrdup( pInfo->m_szTo ); - jbt->dstJID = mir_tstrdup( pInfo->m_szFrom ); - jbt->sid = mir_tstrdup( ft->sid ); - jbt->pfnSend = &CJabberProto::FtSend; - jbt->pfnFinal = &CJabberProto::FtSendFinal; - jbt->ft = ft; - ft->type = FT_BYTESTREAM; - ft->jbt = jbt; - JForkThread(( JThreadFunc )&CJabberProto::ByteSendThread, jbt ); - } else if ( !_tcscmp( xmlGetText( valueNode ), _T(JABBER_FEAT_IBB))) { - JABBER_IBB_TRANSFER *jibb = (JABBER_IBB_TRANSFER *) mir_alloc( sizeof ( JABBER_IBB_TRANSFER )); - ZeroMemory( jibb, sizeof( JABBER_IBB_TRANSFER )); - jibb->srcJID = mir_tstrdup( pInfo->m_szTo ); - jibb->dstJID = mir_tstrdup( pInfo->m_szFrom ); - jibb->sid = mir_tstrdup( ft->sid ); - jibb->pfnSend = &CJabberProto::FtIbbSend; - jibb->pfnFinal = &CJabberProto::FtSendFinal; - jibb->ft = ft; - ft->type = FT_IBB; - ft->jibb = jibb; - JForkThread(( JThreadFunc )&CJabberProto::IbbSendThread, jibb ); - } } } } } } } - else { - Log( "File transfer stream initiation request denied or failed" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ? ACKRESULT_DENIED : ACKRESULT_FAILED, ft, 0 ); - delete ft; - } -} - -BOOL CJabberProto::FtSend( HANDLE hConn, filetransfer* ft ) -{ - struct _stati64 statbuf; - int fd; - char* buffer; - int numRead; - - Log( "Sending [%s]", ft->std.ptszFiles[ ft->std.currentFileNumber ] ); - _tstati64( ft->std.ptszFiles[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size - if (( fd = _topen( ft->std.ptszFiles[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) { - Log( "File cannot be opened" ); - return FALSE; - } - - ft->std.flags |= PFTS_SENDING; - ft->std.currentFileSize = statbuf.st_size; - ft->std.currentFileProgress = 0; - - if (( buffer=( char* )mir_alloc( 2048 )) != NULL ) { - while (( numRead=_read( fd, buffer, 2048 )) > 0 ) { - if ( Netlib_Send( hConn, buffer, numRead, 0 ) != numRead ) { - mir_free( buffer ); - _close( fd ); - return FALSE; - } - ft->std.currentFileProgress += numRead; - ft->std.totalProgress += numRead; - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); - } - mir_free( buffer ); - } - _close( fd ); - return TRUE; -} - -BOOL CJabberProto::FtIbbSend( int blocksize, filetransfer* ft ) -{ - struct _stati64 statbuf; - int fd; - char* buffer; - int numRead; - - Log( "Sending [%s]", ft->std.ptszFiles[ ft->std.currentFileNumber ] ); - _tstati64( ft->std.ptszFiles[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size - if (( fd = _topen( ft->std.ptszFiles[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) { - Log( "File cannot be opened" ); - return FALSE; - } - - ft->std.flags |= PFTS_SENDING; - ft->std.currentFileSize = statbuf.st_size; - ft->std.currentFileProgress = 0; - - if (( buffer=( char* )mir_alloc( blocksize )) != NULL ) { - while (( numRead=_read( fd, buffer, blocksize )) > 0 ) { - int iqId = SerialNext(); - XmlNode msg( _T("message")); - xmlAddAttr( msg, _T("to"), ft->jibb->dstJID ); - msg << XATTRID( iqId ); - - // let others send data too - Sleep(2); - - char *encoded = JabberBase64Encode(buffer, numRead); - - msg << XCHILD( _T("data"), _A2T(encoded)) << XATTR( _T("xmlns"), _T(JABBER_FEAT_IBB)) - << XATTR( _T("sid"), ft->jibb->sid ) << XATTRI( _T("seq"), ft->jibb->wPacketId ); - - HXML ampNode = msg << XCHILDNS( _T("amp"), _T(JABBER_FEAT_AMP)); - ampNode << XCHILD( _T("rule")) << XATTR( _T("condition"), _T("deliver-at")) - << XATTR( _T("value"), _T("stored")) << XATTR( _T("action"), _T("error")); - ampNode << XCHILD( _T("rule")) << XATTR( _T("condition"), _T("match-resource")) - << XATTR( _T("value"), _T("exact")) << XATTR( _T("action"), _T("error")); - ft->jibb->wPacketId++; - - mir_free( encoded ); - - if ( ft->jibb->state == JIBB_ERROR || ft->jibb->bStreamClosed || m_ThreadInfo->send( msg ) == SOCKET_ERROR ) { - Log( "JabberFtIbbSend unsuccessful exit" ); - mir_free( buffer ); - _close( fd ); - return FALSE; - } - - ft->jibb->dwTransferredSize += (DWORD)numRead; - - ft->std.currentFileProgress += numRead; - ft->std.totalProgress += numRead; - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); - } - mir_free( buffer ); - } - _close( fd ); - return TRUE; -} - -void CJabberProto::FtSendFinal( BOOL success, filetransfer* ft ) -{ - if ( !success ) { - Log( "File transfer complete with error" ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ft->state == FT_DENIED ? ACKRESULT_DENIED : ACKRESULT_FAILED, ft, 0 ); - } - else { - if ( ft->std.currentFileNumber < ft->std.totalFiles-1 ) { - ft->std.currentFileNumber++; - replaceStrT( ft->std.tszCurrentFile, ft->std.ptszFiles[ ft->std.currentFileNumber ] ); - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 ); - FtInitiate( ft->jid, ft ); - return; - } - - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 ); - } - - delete ft; -} - -///////////////// File receiving through stream initiation ///////////////////////// - -void CJabberProto::FtHandleSiRequest( HXML iqNode ) -{ - const TCHAR* from, *sid, *str, *szId, *filename; - HXML siNode, fileNode, featureNode, xNode, fieldNode, n; - int i; - unsigned __int64 filesize; - - if ( !iqNode || - ( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL || - ( str = xmlGetAttrValue( iqNode, _T("type"))) == NULL || _tcscmp( str, _T("set")) || - ( siNode = xmlGetChildByTag( iqNode, "si", "xmlns", _T(JABBER_FEAT_SI))) == NULL ) - return; - - szId = xmlGetAttrValue( iqNode, _T("id")); - if (( sid = xmlGetAttrValue( siNode, _T("id"))) != NULL && - ( fileNode = xmlGetChildByTag( siNode, "file", "xmlns", _T(JABBER_FEAT_SI_FT))) != NULL && - ( filename = xmlGetAttrValue( fileNode, _T("name"))) != NULL && - ( str = xmlGetAttrValue( fileNode, _T("size"))) != NULL ) { - - filesize = _ttoi64( str ); - if (( featureNode = xmlGetChildByTag( siNode, "feature", "xmlns", _T(JABBER_FEAT_FEATURE_NEG))) != NULL && - ( xNode = xmlGetChildByTag( featureNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)))!=NULL && - ( fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("stream-method")))!=NULL ) { - - BOOL bIbbOnly = m_options.BsOnlyIBB; - HXML optionNode = NULL; - JABBER_FT_TYPE ftType = FT_OOB; - - if ( !bIbbOnly ) { - for ( i=0; ; i++ ) { - optionNode = xmlGetChild( fieldNode ,i); - if ( !optionNode ) - break; - - if ( !lstrcmp( xmlGetName( optionNode ), _T("option"))) { - if (( n = xmlGetChild( optionNode , "value" )) != NULL && xmlGetText( n )) { - if ( !_tcscmp( xmlGetText( n ), _T(JABBER_FEAT_BYTESTREAMS))) { - ftType = FT_BYTESTREAM; - break; - } } } } } - - // try IBB only if bytestreams support not found or BsOnlyIBB flag exists - if ( bIbbOnly || !optionNode ) { - for ( i=0; ; i++ ) { - optionNode = xmlGetChild( fieldNode ,i); - if ( !optionNode ) - break; - - if ( !lstrcmp( xmlGetName( optionNode ), _T("option"))) { - if (( n = xmlGetChild( optionNode , "value" )) != NULL && xmlGetText( n )) { - if ( !_tcscmp( xmlGetText( n ), _T(JABBER_FEAT_IBB))) { - ftType = FT_IBB; - break; - } } } } } - - if ( optionNode != NULL ) { - // Found known stream mechanism - filetransfer* ft = new filetransfer( this ); - ft->dwExpectedRecvFileSize = filesize; - ft->jid = mir_tstrdup( from ); - ft->std.hContact = HContactFromJID( from ); - ft->sid = mir_tstrdup( sid ); - ft->iqId = mir_tstrdup( szId ); - ft->type = ftType; - ft->std.totalFiles = 1; - ft->std.tszCurrentFile = mir_tstrdup( filename ); - ft->std.totalBytes = ft->std.currentFileSize = filesize; - - PROTORECVFILET pre = { 0 }; - pre.flags = PREF_TCHAR; - pre.fileCount = 1; - pre.timestamp = time( NULL ); - pre.ptszFiles = ( TCHAR** )&filename; - pre.lParam = ( LPARAM )ft; - if (( n = xmlGetChild( fileNode , "desc" )) != NULL ) - pre.tszDescription = ( TCHAR* )xmlGetText( n ); - - CCSDATA ccs = { ft->std.hContact, PSR_FILE, 0, ( LPARAM )&pre }; - CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); - return; - } - else { - // Unknown stream mechanism - XmlNodeIq iq( _T("error"), szId, from ); - HXML e = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); - e << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - e << XCHILDNS( _T("no-valid-streams"), _T(JABBER_FEAT_SI)); - m_ThreadInfo->send( iq ); - return; - } } } - - // Bad stream initiation, reply with bad-profile - XmlNodeIq iq( _T("error"), szId, from ); - HXML e = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); - e << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - e << XCHILDNS( _T("bad-profile"), _T(JABBER_FEAT_SI)); - m_ThreadInfo->send( iq ); -} - -void CJabberProto::FtAcceptSiRequest( filetransfer* ft ) -{ - if ( !m_bJabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return; - - JABBER_LIST_ITEM *item; - if (( item=ListAdd( LIST_FTRECV, ft->sid )) != NULL ) { - item->ft = ft; - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), ft->iqId, ft->jid ) - << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) - << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")) - << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) - << XCHILD( _T("value"), _T(JABBER_FEAT_BYTESTREAMS))); -} } - -void CJabberProto::FtAcceptIbbRequest( filetransfer* ft ) -{ - if ( !m_bJabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return; - - JABBER_LIST_ITEM *item; - if (( item=ListAdd( LIST_FTRECV, ft->sid )) != NULL ) { - item->ft = ft; - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), ft->iqId, ft->jid ) - << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) - << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")) - << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) - << XCHILD( _T("value"), _T(JABBER_FEAT_IBB))); -} } - -BOOL CJabberProto::FtHandleBytestreamRequest( HXML iqNode, CJabberIqInfo* pInfo ) -{ - HXML queryNode = pInfo->GetChildNode(); - - const TCHAR* sid; - JABBER_LIST_ITEM *item; - - if (( sid = xmlGetAttrValue( queryNode, _T("sid"))) != NULL && ( item = ListGetItemPtr( LIST_FTRECV, sid )) != NULL ) { - // Start Bytestream session - JABBER_BYTE_TRANSFER *jbt = new JABBER_BYTE_TRANSFER; - ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER )); - jbt->iqNode = xi.copyNode( iqNode ); - jbt->pfnRecv = &CJabberProto::FtReceive; - jbt->pfnFinal = &CJabberProto::FtReceiveFinal; - jbt->ft = item->ft; - item->ft->jbt = jbt; - JForkThread(( JThreadFunc )&CJabberProto::ByteReceiveThread, jbt ); - ListRemove( LIST_FTRECV, sid ); - return TRUE; - } - - Log( "File transfer invalid bytestream initiation request received" ); - return TRUE; -} - -BOOL CJabberProto::FtHandleIbbRequest( HXML iqNode, BOOL bOpen ) -{ - if ( !iqNode ) return FALSE; - - const TCHAR *id = xmlGetAttrValue( iqNode, _T("id")); - const TCHAR *from = xmlGetAttrValue( iqNode, _T("from")); - const TCHAR *to = xmlGetAttrValue( iqNode, _T("to")); - if ( !id || !from || !to ) return FALSE; - - HXML ibbNode = xmlGetChildByTag( iqNode, bOpen ? "open" : "close", "xmlns", _T(JABBER_FEAT_IBB)); - if ( !ibbNode ) return FALSE; - - const TCHAR *sid = xmlGetAttrValue( ibbNode, _T("sid")); - if ( !sid ) return FALSE; - - // already closed? - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTRECV, sid ); - if ( !item ) { - m_ThreadInfo->send( - XmlNodeIq( _T("error"), id, from ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - return FALSE; - } - - // open event - if ( bOpen ) { - if ( !item->jibb ) { - JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * ) mir_alloc( sizeof( JABBER_IBB_TRANSFER )); - ZeroMemory( jibb, sizeof( JABBER_IBB_TRANSFER )); - jibb->srcJID = mir_tstrdup( from ); - jibb->dstJID = mir_tstrdup( to ); - jibb->sid = mir_tstrdup( sid ); - jibb->pfnRecv = &CJabberProto::FtReceive; - jibb->pfnFinal = &CJabberProto::FtReceiveFinal; - jibb->ft = item->ft; - item->ft->jibb = jibb; - item->jibb = jibb; - JForkThread(( JThreadFunc )&CJabberProto::IbbReceiveThread, jibb ); - - m_ThreadInfo->send( XmlNodeIq( _T("result"), id, from )); - return TRUE; - } - // stream already open - m_ThreadInfo->send( - XmlNodeIq( _T("error"), id, from ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - return FALSE; - } - - // close event && stream already open - if ( item->jibb && item->jibb->hEvent ) { - item->jibb->bStreamClosed = TRUE; - SetEvent( item->jibb->hEvent ); - - m_ThreadInfo->send( XmlNodeIq( _T("result"), id, from )); - return TRUE; - } - - ListRemove( LIST_FTRECV, sid ); - - return FALSE; -} - -int CJabberProto::FtReceive( HANDLE, filetransfer* ft, char* buffer, int datalen ) -{ - if ( ft->create() == -1 ) - return -1; - - __int64 remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress; - if ( remainingBytes > 0 ) { - int writeSize = ( remainingBytes<datalen ) ? remainingBytes : datalen; - if ( _write( ft->fileId, buffer, writeSize ) != writeSize ) { - Log( "_write() error" ); - return -1; - } - - ft->std.currentFileProgress += writeSize; - ft->std.totalProgress += writeSize; - JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); - return ( ft->std.currentFileSize == ft->std.currentFileProgress ) ? 0 : writeSize; - } - - return 0; -} - -void CJabberProto::FtReceiveFinal( BOOL success, filetransfer* ft ) -{ - if ( success ) { - Log( "File transfer complete successfully" ); - ft->complete(); - } - else Log( "File transfer complete with error" ); - - delete ft; -} diff --git a/protocols/JabberG/jabber_groupchat.cpp b/protocols/JabberG/jabber_groupchat.cpp deleted file mode 100644 index b442588fc0..0000000000 --- a/protocols/JabberG/jabber_groupchat.cpp +++ /dev/null @@ -1,1374 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" - -#define GC_SERVER_LIST_SIZE 5 - -int JabberGcGetStatus(JABBER_GC_AFFILIATION a, JABBER_GC_ROLE r); -int JabberGcGetStatus(JABBER_RESOURCE_STATUS *r); - -struct JabberGcRecentInfo -{ - TCHAR *room, *server, *nick, *password; - CJabberProto* ppro; - - JabberGcRecentInfo( CJabberProto* proto ) - { - ppro = proto; - room = server = nick = password = NULL; - } - JabberGcRecentInfo( CJabberProto* proto, const TCHAR *_room, const TCHAR *_server, const TCHAR *_nick = NULL, const TCHAR *_password = NULL) - { - ppro = proto; - room = server = nick = password = NULL; - fillData(_room, _server, _nick, _password); - } - JabberGcRecentInfo( CJabberProto* proto, const TCHAR *jid) - { - ppro = proto; - room = server = nick = password = NULL; - fillData(jid); - } - JabberGcRecentInfo( CJabberProto* proto, int iRecent) - { - ppro = proto; - room = server = nick = password = NULL; - loadRecent(iRecent); - } - - ~JabberGcRecentInfo() - { - cleanup(); - } - - void cleanup() - { - mir_free(room); - mir_free(server); - mir_free(nick); - mir_free(password); - room = server = nick = password = NULL; - } - - BOOL equals(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL, const TCHAR *password = NULL) - { - return - null_strequals(this->room, room) && - null_strequals(this->server, server) && - null_strequals(this->nick, nick) && - null_strequals(this->password, password); - } - - BOOL equalsnp(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL) - { - return - null_strequals(this->room, room) && - null_strequals(this->server, server) && - null_strequals(this->nick, nick); - } - - void fillForm(HWND hwndDlg) - { - SetDlgItemText(hwndDlg, IDC_SERVER, server ? server : _T("")); - SetDlgItemText(hwndDlg, IDC_ROOM, room ? room : _T("")); - SetDlgItemText(hwndDlg, IDC_NICK, nick ? nick : _T("")); - SetDlgItemText(hwndDlg, IDC_PASSWORD, password ? password : _T("")); - } - - void fillData(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL, const TCHAR *password = NULL) - { - cleanup(); - this->room = room ? mir_tstrdup(room) : NULL; - this->server = server ? mir_tstrdup(server) : NULL; - this->nick = nick ? mir_tstrdup(nick) : NULL; - this->password = password ? mir_tstrdup(password) : NULL; - } - - void fillData(const TCHAR *jid) - { - TCHAR *room, *server, *nick=NULL; - room = NEWTSTR_ALLOCA(jid); - server = _tcschr(room, _T('@')); - if (server) - { - *server++ = 0; - nick = _tcschr(server, _T('/')); - if (nick) *nick++ = 0; - } else - { - server = room; - room = NULL; - } - - fillData(room, server, nick); - } - - BOOL loadRecent(int iRecent) - { - DBVARIANT dbv; - char setting[MAXMODULELABELLENGTH]; - - cleanup(); - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_server", iRecent); - if ( !ppro->JGetStringT( NULL, setting, &dbv )) { - server = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_room", iRecent); - if ( !ppro->JGetStringT( NULL, setting, &dbv )) { - room = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_nick", iRecent); - if ( !ppro->JGetStringT( NULL, setting, &dbv )) { - nick = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_passwordW", iRecent); - password = ppro->JGetStringCrypt(NULL, setting); - - return room || server || nick || password; - } - - void saveRecent(int iRecent) - { - char setting[MAXMODULELABELLENGTH]; - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_server", iRecent); - if (server) - ppro->JSetStringT(NULL, setting, server); - else - ppro->JDeleteSetting(NULL, setting); - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_room", iRecent); - if (room) - ppro->JSetStringT(NULL, setting, room); - else - ppro->JDeleteSetting(NULL, setting); - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_nick", iRecent); - if (nick) - ppro->JSetStringT(NULL, setting, nick); - else - ppro->JDeleteSetting(NULL, setting); - - mir_snprintf(setting, sizeof(setting), "rcMuc_%d_passwordW", iRecent); - if (password) - ppro->JSetStringCrypt(NULL, setting, password); - else - ppro->JDeleteSetting(NULL, setting); - } - -private: - BOOL null_strequals(const TCHAR *str1, const TCHAR *str2) - { - if (!str1 && !str2) return TRUE; - if (!str1 && str2 && !*str2) return TRUE; - if (!str2 && str1 && !*str1) return TRUE; - - if (!str1 && str2) return FALSE; - if (!str2 && str1) return FALSE; - - return !lstrcmp(str1, str2); - } -}; - -JABBER_RESOURCE_STATUS* CJabberProto::GcFindResource(JABBER_LIST_ITEM *item, const TCHAR *resource) -{ - JABBER_RESOURCE_STATUS *res = NULL; - - EnterCriticalSection( &m_csLists ); - JABBER_RESOURCE_STATUS *r = item->resource; - for ( int i=0; i<item->resourceCount; i++ ) { - if ( !_tcscmp( r[i].resourceName, resource )) { - res = &r[i]; - break; - } - } - LeaveCriticalSection( &m_csLists ); - - return res; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleJoinGroupchat( WPARAM, LPARAM ) -{ - if ( jabberChatDllPresent ) - GroupchatJoinRoomByJid( NULL, NULL ); - else - JabberChatDllError(); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnJoinChat( WPARAM wParam, LPARAM ) -{ - DBVARIANT nick, jid; - HANDLE hContact = ( HANDLE )wParam; - if ( JGetStringT( hContact, "ChatRoomID", &jid )) - return 0; - - if ( JGetStringT( hContact, "MyNick", &nick )) - if ( JGetStringT( NULL, "Nick", &nick )) { - JFreeVariant( &jid ); - return 0; - } - - TCHAR *password = JGetStringCrypt( hContact, "LoginPassword" ); - - if ( JGetWord( hContact, "Status", 0 ) != ID_STATUS_ONLINE ) { - if ( !jabberChatDllPresent ) - JabberChatDllError(); - else { - TCHAR* p = _tcschr( jid.ptszVal, '@' ); - if ( p != NULL ) { - *p++ = 0; - GroupchatJoinRoom( p, jid.ptszVal, nick.ptszVal, password ); - } } } - - mir_free( password ); - JFreeVariant( &nick ); - JFreeVariant( &jid ); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnLeaveChat( WPARAM wParam, LPARAM ) -{ - DBVARIANT jid; - HANDLE hContact = ( HANDLE )wParam; - if ( JGetStringT( hContact, "ChatRoomID", &jid )) - return 0; - - if ( JGetWord( hContact, "Status", 0 ) != ID_STATUS_OFFLINE ) { - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, jid.ptszVal ); - if ( item != NULL ) - GcQuit( item, 0, NULL ); - } - - JFreeVariant( &jid ); - return 0; -} - -void CJabberProto::GroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password, bool autojoin ) -{ - JabberGcRecentInfo info( this ); - - int i = 0; - bool found = false; - for (i = 0 ; i < 5; ++i) - { - if (!info.loadRecent(i)) - continue; - - if (info.equals(room, server, nick, password)) - { - found = true; - break; - } - } - - if (!found) - { - for (int i = 4; i--; ) - { - if (info.loadRecent(i)) - info.saveRecent(i + 1); - } - - info.fillData(room, server, nick, password); - info.saveRecent(0); - } - - TCHAR text[512]; - mir_sntprintf( text, SIZEOF(text), _T("%s@%s/%s"), room, server, nick ); - - JABBER_LIST_ITEM* item = ListAdd( LIST_CHATROOM, text ); - item->bAutoJoin = autojoin; - replaceStrT( item->nick, nick ); - replaceStrT( item->password, info.password ); - - int status = ( m_iStatus == ID_STATUS_INVISIBLE ) ? ID_STATUS_ONLINE : m_iStatus; - XmlNode x( _T("x")); x << XATTR( _T("xmlns"), _T(JABBER_FEAT_MUC)); - if ( info.password && info.password[0] ) - x << XCHILD( _T("password"), info.password ); - - if (m_options.GcLogChatHistory) { - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, SIZEOF(setting), "muc_%s@%s_lastevent", _T2A(room), _T2A(server)); - time_t lasteventtime = this->JGetDword( NULL, setting, 0 ); - if ( lasteventtime > 0 ) { - _tzset(); - lasteventtime += _timezone + 1; - struct tm* time = localtime(&lasteventtime); - TCHAR lasteventdate[40]; - mir_sntprintf(lasteventdate, SIZEOF(lasteventdate), _T("%04d-%02d-%02dT%02d:%02d:%02dZ"), - time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); - x << XCHILD( _T("history")) << XATTR( _T("since"), lasteventdate); - } - } - - SendPresenceTo( status, text, x ); -} - -//////////////////////////////////////////////////////////////////////////////// -// Join Dialog - -static int sttTextLineHeight = 16; - -struct RoomInfo -{ - enum Overlay { ROOM_WAIT, ROOM_FAIL, ROOM_BOOKMARK, ROOM_DEFAULT }; - Overlay overlay; - TCHAR *line1, *line2; -}; - -static int sttRoomListAppend(HWND hwndList, RoomInfo::Overlay overlay, const TCHAR *line1, const TCHAR *line2, const TCHAR *name) -{ - RoomInfo *info = (RoomInfo *)mir_alloc(sizeof(RoomInfo)); - info->overlay = overlay; - info->line1 = line1 ? mir_tstrdup(line1) : 0; - info->line2 = line2 ? mir_tstrdup(line2) : 0; - - int id = SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM)name); - SendMessage(hwndList, CB_SETITEMDATA, id, (LPARAM)info); - SendMessage(hwndList, CB_SETITEMHEIGHT, id, sttTextLineHeight * 2); - return id; -} - -void CJabberProto::OnIqResultDiscovery(HXML iqNode, CJabberIqInfo *pInfo) -{ - if (!iqNode || !pInfo) - return; - - HWND hwndList = (HWND)pInfo->GetUserData(); - SendMessage(hwndList, CB_SHOWDROPDOWN, FALSE, 0); - SendMessage(hwndList, CB_RESETCONTENT, 0, 0); - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) - { - HXML query = xmlGetChild( iqNode , "query" ); - if ( !query ) - { - sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, - TranslateT("Jabber Error"), - TranslateT("Failed to retrieve room list from server."), - _T("")); - } else - { - bool found = false; - HXML item; - for ( int i = 1; item = xmlGetNthChild( query, _T("item"), i ); i++ ) - { - const TCHAR *jid = xmlGetAttrValue( item, _T("jid")); - TCHAR *name = NEWTSTR_ALLOCA(jid); - if (name) - { - if (TCHAR *p = _tcschr(name, _T('@'))) - *p = 0; - } else - { - name = _T(""); - } - - sttRoomListAppend(hwndList, - ListGetItemPtr(LIST_BOOKMARK, jid) ? RoomInfo::ROOM_BOOKMARK : RoomInfo::ROOM_DEFAULT, - xmlGetAttrValue( item, _T("name")), - jid, name); - - found = true; - } - - if (!found) - { - sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, - TranslateT("Jabber Error"), - TranslateT("No rooms available on server."), - _T("")); - } - } - } else - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) - { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, - TranslateT("Jabber Error"), - str, - _T("")); - mir_free( str ); - } else - { - sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, - TranslateT("Jabber Error"), - TranslateT("Room list request timed out."), - _T("")); - } - - SendMessage(hwndList, CB_SHOWDROPDOWN, TRUE, 0); -} - -static void sttJoinDlgShowRecentItems(HWND hwndDlg, int newCount) -{ - RECT rcTitle, rcLastItem; - GetWindowRect(GetDlgItem(hwndDlg, IDC_TXT_RECENT), &rcTitle); - GetWindowRect(GetDlgItem(hwndDlg, IDC_RECENT5), &rcLastItem); - - ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_RECENT), newCount ? SW_SHOW : SW_HIDE); - - int oldCount = 5; - for (int idc = IDC_RECENT1; idc <= IDC_RECENT5; ++idc) - ShowWindow(GetDlgItem(hwndDlg, idc), (idc - IDC_RECENT1 < newCount) ? SW_SHOW : SW_HIDE); - - int curRecentHeight = rcLastItem.bottom - rcTitle.top - (5 - oldCount) * (rcLastItem.bottom - rcLastItem.top); - int newRecentHeight = rcLastItem.bottom - rcTitle.top - (5 - newCount) * (rcLastItem.bottom - rcLastItem.top); - if (!newCount) newRecentHeight = 0; - int offset = newRecentHeight - curRecentHeight; - - RECT rc; - int ctrls[] = { IDC_BOOKMARKS, IDOK, IDCANCEL }; - for (int i = 0; i < SIZEOF(ctrls); ++i) - { - GetWindowRect(GetDlgItem(hwndDlg, ctrls[i]), &rc); - MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2); - SetWindowPos(GetDlgItem(hwndDlg, ctrls[i]), NULL, rc.left, rc.top + offset, 0, 0, SWP_NOSIZE|SWP_NOZORDER); - } - - GetWindowRect(hwndDlg, &rc); - SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top+offset, SWP_NOMOVE|SWP_NOZORDER); -} - -class CJabberDlgGcJoin: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgGcJoin(CJabberProto *proto, TCHAR *jid); - -protected: - TCHAR *m_jid; - - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); -}; - -CJabberDlgGcJoin::CJabberDlgGcJoin(CJabberProto *proto, TCHAR *jid) : - CSuper(proto, IDD_GROUPCHAT_JOIN, NULL), - m_jid(mir_tstrdup(jid)) -{ - m_autoClose = 0; -} - -void CJabberDlgGcJoin::OnInitDialog() -{ - CSuper::OnInitDialog(); - - WindowSetIcon( m_hwnd, m_proto, "group" ); - - JabberGcRecentInfo *info = NULL; - if ( m_jid ) - info = new JabberGcRecentInfo( m_proto, m_jid ); - else - { - OpenClipboard(m_hwnd); - HANDLE hData = GetClipboardData(CF_UNICODETEXT); - - if (hData) - { - TCHAR *buf = (TCHAR *)GlobalLock(hData); - if (buf && _tcschr(buf, _T('@')) && !_tcschr(buf, _T(' '))) - info = new JabberGcRecentInfo( m_proto, buf ); - GlobalUnlock(hData); - } - CloseClipboard(); - } - - if (info) - { - info->fillForm(m_hwnd); - delete info; - } - - DBVARIANT dbv; - if ( !m_proto->JGetStringT( NULL, "Nick", &dbv )) { - SetDlgItemText( m_hwnd, IDC_NICK, dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else { - TCHAR* nick = JabberNickFromJID( m_proto->m_szJabberJID ); - SetDlgItemText( m_hwnd, IDC_NICK, nick ); - mir_free( nick ); - } - - { - TEXTMETRIC tm = {0}; - HDC hdc = GetDC(m_hwnd); - GetTextMetrics(hdc, &tm); - ReleaseDC(m_hwnd, hdc); - sttTextLineHeight = tm.tmHeight; - SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_SETITEMHEIGHT, -1, sttTextLineHeight-1); - } - - { - LOGFONT lf = {0}; - HFONT hfnt = (HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_GETFONT, 0, 0); - GetObject(hfnt, sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), TRUE); - } - - SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx("bookmarks")); - SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONADDTOOLTIP, (WPARAM)"Bookmarks", 0); - SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONSETASPUSHBTN, TRUE, 0); - - m_proto->ComboLoadRecentStrings(m_hwnd, IDC_SERVER, "joinWnd_rcSvr"); - - int i = 0; - for ( ; i < 5; ++i) - { - TCHAR jid[JABBER_MAX_JID_LEN]; - JabberGcRecentInfo info( m_proto ); - if (info.loadRecent(i)) - { - mir_sntprintf(jid, SIZEOF(jid), _T("%s@%s (%s)"), - info.room, info.server, - info.nick ? info.nick : TranslateT("<no nick>")); - SetDlgItemText(m_hwnd, IDC_RECENT1+i, jid); - } else - { - break; - } - } - sttJoinDlgShowRecentItems(m_hwnd, i); -} - -void CJabberDlgGcJoin::OnClose() -{ - CSuper::OnClose(); -} - -void CJabberDlgGcJoin::OnDestroy() -{ - g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BOOKMARKS, BM_SETIMAGE, IMAGE_ICON, 0 )); - m_proto->m_pDlgJabberJoinGroupchat = NULL; - DeleteObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_GETFONT, 0, 0)); - - CSuper::OnDestroy(); - - mir_free( m_jid ); m_jid = NULL; -} - -INT_PTR CJabberDlgGcJoin::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - TCHAR text[128]; - - switch ( msg ) { - case WM_DELETEITEM: - { - LPDELETEITEMSTRUCT lpdis = (LPDELETEITEMSTRUCT)lParam; - if (lpdis->CtlID != IDC_ROOM) - break; - - RoomInfo *info = (RoomInfo *)lpdis->itemData; - if (info->line1) mir_free(info->line1); - if (info->line2) mir_free(info->line2); - mir_free(info); - - break; - } - - case WM_MEASUREITEM: - { - LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; - if (lpmis->CtlID != IDC_ROOM) - break; - - lpmis->itemHeight = 2*sttTextLineHeight; - if (lpmis->itemID == -1) - lpmis->itemHeight = sttTextLineHeight-1; - - break; - } - - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; - if (lpdis->CtlID != IDC_ROOM) - break; - - if (lpdis->itemID < 0) - break; - - RoomInfo *info = (RoomInfo *)SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_GETITEMDATA, lpdis->itemID, 0); - COLORREF clLine1, clLine2, clBack; - - if (lpdis->itemState & ODS_SELECTED) - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - clBack = GetSysColor(COLOR_HIGHLIGHT); - clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); - } else - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); - clBack = GetSysColor(COLOR_WINDOW); - clLine1 = GetSysColor(COLOR_WINDOWTEXT); - } - clLine2 = RGB( - GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, - GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, - GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 - ); - - SetBkMode(lpdis->hDC, TRANSPARENT); - - RECT rc; - - rc = lpdis->rcItem; - rc.bottom -= (rc.bottom - rc.top) / 2; - rc.left += 20; - SetTextColor(lpdis->hDC, clLine1); - DrawText(lpdis->hDC, info->line1, lstrlen(info->line1), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); - - rc = lpdis->rcItem; - rc.top += (rc.bottom - rc.top) / 2; - rc.left += 20; - SetTextColor(lpdis->hDC, clLine2); - DrawText(lpdis->hDC, info->line2, lstrlen(info->line2), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); - - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("group"), 16, 16, 0, NULL, DI_NORMAL); - switch (info->overlay) { - case RoomInfo::ROOM_WAIT: - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_progress"), 16, 16, 0, NULL, DI_NORMAL); - break; - case RoomInfo::ROOM_FAIL: - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_fail"), 16, 16, 0, NULL, DI_NORMAL); - break; - case RoomInfo::ROOM_BOOKMARK: - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_ok"), 16, 16, 0, NULL, DI_NORMAL); - break; - } - } - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDC_SERVER: - switch (HIWORD(wParam)) { - case CBN_EDITCHANGE: - case CBN_SELCHANGE: - { - int iqid = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA); - if (iqid) - { - m_proto->m_iqManager.ExpireIq(iqid); - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, 0); - } - SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_RESETCONTENT, 0, 0); - } - break; - } - break; - - case IDC_ROOM: - switch (HIWORD(wParam)) { - case CBN_DROPDOWN: - if (!SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_GETCOUNT, 0, 0)) - { - int iqid = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA); - if (iqid) - { - m_proto->m_iqManager.ExpireIq(iqid); - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, 0); - } - - SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_RESETCONTENT, 0, 0); - - int len = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_SERVER)) + 1; - TCHAR *server = (TCHAR *)_alloca(len * sizeof(TCHAR)); - GetWindowText(GetDlgItem(m_hwnd, IDC_SERVER), server, len); - - if (*server) - { - sttRoomListAppend(GetDlgItem(m_hwnd, IDC_ROOM), RoomInfo::ROOM_WAIT, TranslateT("Loading..."), TranslateT("Please wait for room list to download."), _T("")); - - CJabberIqInfo *pInfo = m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultDiscovery, JABBER_IQ_TYPE_GET, server, 0, -1, (void *)GetDlgItem(m_hwnd, IDC_ROOM)); - pInfo->SetTimeout(30000); - XmlNodeIq iq(pInfo); - iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); - m_proto->m_ThreadInfo->send(iq); - - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, pInfo->GetIqId()); - } else - { - sttRoomListAppend(GetDlgItem(m_hwnd, IDC_ROOM), RoomInfo::ROOM_FAIL, - TranslateT("Jabber Error"), - TranslateT("Please specify groupchat directory first."), - _T("")); - } - } - break; - } - break; - - case IDC_BOOKMARKS: - { - HMENU hMenu = CreatePopupMenu(); - - LISTFOREACH(i, m_proto, LIST_BOOKMARK) - { - JABBER_LIST_ITEM *item = 0; - if (item = m_proto->ListGetItemPtrFromIndex(i)) - if (!lstrcmp(item->type, _T("conference"))) - AppendMenu(hMenu, MF_STRING, (UINT_PTR)item, item->name); - } - AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)-1, TranslateT("Bookmarks...")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - - RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BOOKMARKS), &rc); - CheckDlgButton(m_hwnd, IDC_BOOKMARKS, TRUE); - int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, NULL); - CheckDlgButton(m_hwnd, IDC_BOOKMARKS, FALSE); - DestroyMenu(hMenu); - - if ( res == -1 ) - m_proto->OnMenuHandleBookmarks( 0, 0 ); - else if (res) { - JABBER_LIST_ITEM *item = (JABBER_LIST_ITEM *)res; - TCHAR *room = NEWTSTR_ALLOCA(item->jid); - if (room) { - TCHAR *server = _tcschr(room, _T('@')); - if (server) { - *server++ = 0; - - SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_SERVER, CBN_EDITCHANGE), (LPARAM)GetDlgItem(m_hwnd, IDC_SERVER)); - - SetDlgItemText(m_hwnd, IDC_SERVER, server); - SetDlgItemText(m_hwnd, IDC_ROOM, room); - SetDlgItemText(m_hwnd, IDC_NICK, item->nick); - SetDlgItemText(m_hwnd, IDC_PASSWORD, item->password); - } } } } - break; - - case IDC_RECENT1: - case IDC_RECENT2: - case IDC_RECENT3: - case IDC_RECENT4: - case IDC_RECENT5: - { - JabberGcRecentInfo info( m_proto, LOWORD( wParam ) - IDC_RECENT1); - info.fillForm(m_hwnd); - if (GetAsyncKeyState(VK_CONTROL)) - break; - } - // fall through - - case IDOK: - { - GetDlgItemText( m_hwnd, IDC_SERVER, text, SIZEOF( text )); - TCHAR* server = NEWTSTR_ALLOCA( text ), *room; - - m_proto->ComboAddRecentString(m_hwnd, IDC_SERVER, "joinWnd_rcSvr", server); - - GetDlgItemText( m_hwnd, IDC_ROOM, text, SIZEOF( text )); - room = NEWTSTR_ALLOCA( text ); - - GetDlgItemText( m_hwnd, IDC_NICK, text, SIZEOF( text )); - TCHAR* nick = NEWTSTR_ALLOCA( text ); - - GetDlgItemText( m_hwnd, IDC_PASSWORD, text, SIZEOF( text )); - TCHAR* password = NEWTSTR_ALLOCA( text ); - m_proto->GroupchatJoinRoom( server, room, nick, password ); - } - // fall through - case IDCANCEL: - Close(); - break; - } - break; - case WM_JABBER_CHECK_ONLINE: - if ( !m_proto->m_bJabberOnline ) - EndDialog( m_hwnd, 0 ); - break; - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -void CJabberProto::GroupchatJoinRoomByJid( HWND, TCHAR *jid ) -{ - if (m_pDlgJabberJoinGroupchat) - SetForegroundWindow(m_pDlgJabberJoinGroupchat->GetHwnd()); - else { - m_pDlgJabberJoinGroupchat = new CJabberDlgGcJoin(this, jid); - m_pDlgJabberJoinGroupchat->Show(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGroupchatProcessPresence - handles the group chat presence packet - -struct JabberGroupchatChangeNicknameParam -{ - JabberGroupchatChangeNicknameParam( CJabberProto* ppro_, const TCHAR* jid_ ) : - ppro( ppro_ ), - jid( mir_tstrdup( jid_ )) - {} - - ~JabberGroupchatChangeNicknameParam() - { mir_free( jid ); - } - - CJabberProto* ppro; - TCHAR* jid; -}; - -static VOID CALLBACK JabberGroupchatChangeNickname( void* arg ) -{ - JabberGroupchatChangeNicknameParam* param = ( JabberGroupchatChangeNicknameParam* )arg; - if ( param == NULL ) - return; - - JABBER_LIST_ITEM* item = param->ppro->ListGetItemPtr( LIST_CHATROOM, param->jid ); - if ( item != NULL ) { - TCHAR szBuffer[ 1024 ]; - TCHAR szCaption[ 1024 ]; - szBuffer[ 0 ] = _T('\0'); - - TCHAR* roomName = item->name ? item->name : item->jid; - mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s <%s>"), TranslateT( "Change nickname in" ), roomName ); - if ( item->nick ) - mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s"), item->nick ); - - if ( param->ppro->EnterString( szBuffer, SIZEOF(szBuffer), szCaption, JES_COMBO, "gcNick_" )) { - TCHAR text[ 1024 ]; - replaceStrT( item->nick, szBuffer ); - mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, szBuffer ); - param->ppro->SendPresenceTo( param->ppro->m_iStatus, text, NULL ); - } } - - delete param; -} - -static int sttGetStatusCode( HXML node ) -{ - HXML statusNode = xmlGetChild( node , "status" ); - if ( statusNode == NULL ) - return -1; - - const TCHAR* statusCode = xmlGetAttrValue( statusNode, _T("code")); - if ( statusCode == NULL ) - return -1; - - return _ttol( statusCode ); -} - -void CJabberProto::RenameParticipantNick( JABBER_LIST_ITEM* item, const TCHAR* oldNick, HXML itemNode ) -{ - const TCHAR* newNick = xmlGetAttrValue( itemNode, _T("nick")); - const TCHAR* jid = xmlGetAttrValue( itemNode, _T("jid")); - if ( newNick == NULL ) - return; - - for ( int i=0; i < item->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& RS = item->resource[i]; - if ( !lstrcmp( RS.resourceName, oldNick )) { - replaceStrT( RS.resourceName, newNick ); - - if ( !lstrcmp( item->nick, oldNick )) { - replaceStrT( item->nick, newNick ); - - HANDLE hContact = HContactFromJID( item->jid ); - if ( hContact != NULL ) - JSetStringT( hContact, "MyNick", newNick ); - } - - GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_CHUID }; - gcd.ptszID = item->jid; - - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - gce.ptszNick = oldNick; - gce.ptszText = newNick; - if (jid != NULL) - gce.ptszUserInfo = jid; - gce.time = time(0); - gce.dwFlags = GC_TCHAR; - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - - gcd.iType = GC_EVENT_NICK; - gce.ptszNick = oldNick; - gce.ptszUID = newNick; - gce.ptszText = newNick; - CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); - break; -} } } - -void CJabberProto::GroupchatProcessPresence( HXML node ) -{ - HXML showNode, statusNode, itemNode, n, priorityNode; - const TCHAR* from; - int status, newRes = 0; - bool bStatusChanged = false; - BOOL roomCreated; - - if ( !node || !xmlGetName( node ) || lstrcmp( xmlGetName( node ), _T("presence"))) return; - if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; - - const TCHAR* resource = _tcschr( from, '/' ); - if ( resource == NULL || *++resource == '\0' ) - return; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, from ); - if ( item == NULL ) - return; - - JABBER_RESOURCE_STATUS* r = GcFindResource(item, resource); - - HXML nNode = xmlGetChildByTag( node, "nick", "xmlns", _T(JABBER_FEAT_NICK)); - if ( nNode == NULL ) - nNode = xmlGetChildByTag( node, "nick:nick", "xmlns:nick", _T(JABBER_FEAT_NICK)); - - const TCHAR* cnick = nNode ? xmlGetText( nNode ) : NULL; - const TCHAR* nick = cnick ? cnick : (r && r->nick ? r->nick : resource); - - // process custom nick change - if ( cnick && r && r->nick && _tcscmp( cnick, r->nick )) - replaceStrT( r->nick, cnick ); - - HXML xNode = xmlGetChildByTag( node, "x", "xmlns", _T(JABBER_FEAT_MUC_USER)); - HXML xUserNode = xmlGetChildByTag( node, "user:x", "xmlns:user", _T(JABBER_FEAT_MUC_USER)); - - itemNode = xmlGetChild( xNode , "item" ); - if ( itemNode == NULL ) - itemNode = xmlGetChild( xUserNode , "user:item" ); - - const TCHAR* type = xmlGetAttrValue( node, _T("type")); - - // entering room or a usual room presence - if ( type == NULL || !_tcscmp( type, _T("available"))) { - TCHAR* room = JabberNickFromJID( from ); - if ( room == NULL ) - return; - - GcLogCreate( item ); - item->iChatState = 0; - - // Update status of room participant - status = ID_STATUS_ONLINE; - if (( showNode = xmlGetChild( node , "show" )) != NULL ) { - if ( xmlGetText( showNode ) != NULL ) { - if ( !_tcscmp( xmlGetText( showNode ) , _T("away"))) status = ID_STATUS_AWAY; - else if ( !_tcscmp( xmlGetText( showNode ) , _T("xa"))) status = ID_STATUS_NA; - else if ( !_tcscmp( xmlGetText( showNode ) , _T("dnd"))) status = ID_STATUS_DND; - else if ( !_tcscmp( xmlGetText( showNode ) , _T("chat"))) status = ID_STATUS_FREECHAT; - } } - - statusNode = xmlGetChild( node , "status" ); - if ( statusNode == NULL ) - statusNode = xmlGetChild( node , "user:status" ); - - const TCHAR* str = statusNode ? xmlGetText( statusNode ) : NULL; - - char priority = 0; - if (( priorityNode = xmlGetChild( node , "priority" )) != NULL && xmlGetText( priorityNode ) != NULL ) - priority = (char)_ttoi( xmlGetText( priorityNode )); - - if (JABBER_RESOURCE_STATUS *oldRes = ListFindResource(LIST_CHATROOM, from)) - if ((oldRes->status != status) || lstrcmp_null(oldRes->statusMessage, str)) - bStatusChanged = true; - - newRes = ( ListAddResource( LIST_CHATROOM, from, status, str, priority, cnick ) == 0 ) ? 0 : GC_EVENT_JOIN; - - roomCreated = FALSE; - - bool bAffiliationChanged = false; - bool bRoleChanged = false; - - // Check additional MUC info for this user - if ( itemNode != NULL ) { - if ( r == NULL ) - r = GcFindResource(item, resource); - if ( r != NULL ) { - JABBER_GC_AFFILIATION affiliation = r->affiliation; - JABBER_GC_ROLE role = r->role; - - if (( str = xmlGetAttrValue( itemNode, _T("affiliation"))) != NULL ) { - if ( !_tcscmp( str, _T("owner"))) affiliation = AFFILIATION_OWNER; - else if ( !_tcscmp( str, _T("admin"))) affiliation = AFFILIATION_ADMIN; - else if ( !_tcscmp( str, _T("member"))) affiliation = AFFILIATION_MEMBER; - else if ( !_tcscmp( str, _T("none"))) affiliation = AFFILIATION_NONE; - else if ( !_tcscmp( str, _T("outcast"))) affiliation = AFFILIATION_OUTCAST; - } - if (( str = xmlGetAttrValue( itemNode, _T("role"))) != NULL ) { - if ( !_tcscmp( str, _T("moderator"))) role = ROLE_MODERATOR; - else if ( !_tcscmp( str, _T("participant"))) role = ROLE_PARTICIPANT; - else if ( !_tcscmp( str, _T("visitor"))) role = ROLE_VISITOR; - else role = ROLE_NONE; - } - - if ( (role != ROLE_NONE) && (JabberGcGetStatus(r) != JabberGcGetStatus(affiliation, role))) { - GcLogUpdateMemberStatus( item, resource, nick, NULL, GC_EVENT_REMOVESTATUS, NULL ); - if (!newRes) newRes = GC_EVENT_ADDSTATUS; - } - - if (affiliation != r->affiliation) { - r->affiliation = affiliation; - bAffiliationChanged = true; - } - - if (role != r->role) { - r->role = role; - if (r->role != ROLE_NONE) - bRoleChanged = true; - } - - if ( str = xmlGetAttrValue( itemNode, _T("jid"))) - replaceStrT( r->szRealJid, str ); - } - } - - if ( sttGetStatusCode( xNode ) == 201 ) - roomCreated = TRUE; - - // show status change if needed - if (bStatusChanged) - if (JABBER_RESOURCE_STATUS *res = ListFindResource(LIST_CHATROOM, from)) - GcLogShowInformation(item, res, INFO_STATUS); - - // Update groupchat log window - GcLogUpdateMemberStatus( item, resource, nick, str, newRes, NULL ); - if (r && bAffiliationChanged) GcLogShowInformation(item, r, INFO_AFFILIATION); - if (r && bRoleChanged) GcLogShowInformation(item, r, INFO_ROLE); - - // update clist status - HANDLE hContact = HContactFromJID( from ); - if ( hContact != NULL ) - JSetWord( hContact, "Status", status ); - - // Update room status - //if ( item->status != ID_STATUS_ONLINE ) { - // item->status = ID_STATUS_ONLINE; - // JSetWord( hContact, "Status", ( WORD )ID_STATUS_ONLINE ); - // JabberLog( "Room %s online", from ); - //} - - // Check <created/> - if ( roomCreated || - (( n = xmlGetChild( node , "created" ))!=NULL && - ( str = xmlGetAttrValue( n, _T("xmlns")))!=NULL && - !_tcscmp( str, _T("http://jabber.org/protocol/muc#owner")))) { - // A new room just created by me - // Request room config - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, item->jid ) << XQUERY( xmlnsOwner )); - } - - mir_free( room ); - } - - // leaving room - else if ( !_tcscmp( type, _T("unavailable"))) { - const TCHAR* str = 0; - if ( xNode != NULL && item->nick != NULL ) { - HXML reasonNode = xmlGetChild( itemNode , "reason" ); - str = xmlGetAttrValue( itemNode, _T( "jid" )); - - int iStatus = sttGetStatusCode( xNode ); - if (iStatus == 301 && r != NULL) - GcLogShowInformation(item, r, INFO_BAN); - - if ( !lstrcmp( resource, item->nick )) { - switch( iStatus ) { - case 301: - case 307: - GcQuit( item, iStatus, reasonNode ); - return; - - case 303: - RenameParticipantNick( item, resource, itemNode ); - return; - } } - else { - switch( iStatus ) { - case 303: - RenameParticipantNick( item, resource, itemNode ); - return; - - case 301: - case 307: - case 322: - ListRemoveResource( LIST_CHATROOM, from ); - GcLogUpdateMemberStatus( item, resource, nick, str, GC_EVENT_KICK, reasonNode, iStatus ); - return; - } } } - - statusNode = xmlGetChild( node , "status" ); - GcLogUpdateMemberStatus( item, resource, nick, str, GC_EVENT_PART, statusNode ); - ListRemoveResource( LIST_CHATROOM, from ); - - HANDLE hContact = HContactFromJID( from ); - if ( hContact != NULL ) - JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); - } - - // processing room errors - else if ( !_tcscmp( type, _T("error"))) { - int errorCode = 0; - HXML errorNode = xmlGetChild( node , "error" ); - TCHAR* str = JabberErrorMsg( errorNode, &errorCode ); - - if ( errorCode == JABBER_ERROR_CONFLICT ) { - TCHAR newNick[256] = { 0 }; - if (++item->iChatState == 1 && - JGetStringT(NULL, "GcAltNick", newNick, SIZEOF(newNick)) != NULL && - newNick[0] != _T('\0')) - { - replaceStrT(item->nick, newNick); - TCHAR text[1024] = { 0 }; - mir_sntprintf(text, SIZEOF(text), _T("%s/%s"), item->jid, newNick); - SendPresenceTo(m_iStatus, text, NULL); - } - else { - CallFunctionAsync( JabberGroupchatChangeNickname, new JabberGroupchatChangeNicknameParam( this, from )); - item->iChatState = 0; - } - mir_free( str ); - return; - } - - MsgPopup( NULL, str, TranslateT( "Jabber Error" )); - - if ( item != NULL) - if ( !item->bChatActive ) ListRemove( LIST_CHATROOM, from ); - mir_free( str ); -} } - -void CJabberProto::GroupchatProcessMessage( HXML node ) -{ - HXML n, xNode, m; - const TCHAR* from, *type, *p, *nick, *resource; - JABBER_LIST_ITEM *item; - - if ( !xmlGetName( node ) || lstrcmp( xmlGetName( node ), _T("message"))) return; - if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; - if (( item = ListGetItemPtr( LIST_CHATROOM, from )) == NULL ) return; - - if (( type = xmlGetAttrValue( node, _T("type"))) == NULL ) return; - if ( !lstrcmp( type, _T("error"))) - return; - - GCDEST gcd = { m_szModuleName, NULL, 0 }; - gcd.ptszID = item->jid; - - const TCHAR* msgText = NULL; - - resource = _tcschr( from, '/' ); - if ( resource != NULL && *++resource == '\0' ) - resource = NULL; - - if (( n = xmlGetChild( node , "subject" )) != NULL ) { - msgText = xmlGetText( n ); - - if ( msgText == NULL || msgText[0] == '\0' ) - return; - - gcd.iType = GC_EVENT_TOPIC; - - if ( resource == NULL && ( m = xmlGetChild( node, "body" )) != NULL ) { - const TCHAR* tmpnick = xmlGetText( m ); - if ( tmpnick == NULL || *tmpnick == 0 ) - return; - - const TCHAR* tmptr = _tcsstr( tmpnick, _T("has set the subject to:")); //ejabberd - if ( tmptr == NULL ) - tmptr = _tcsstr( tmpnick, TranslateT("has set the subject to:")); //ejabberd - if ( tmptr != NULL && *tmptr != 0 ) { - *(TCHAR*)(--tmptr) = 0; - resource = tmpnick; - } } - replaceStrT( item->itemResource.statusMessage, msgText ); - } - else { - if (( n = xmlGetChildByTag( node , "body", "xml:lang", m_tszSelectedLang )) == NULL ) - if (( n = xmlGetChild( node , "body" )) == NULL ) - return; - - msgText = xmlGetText( n ); - - if ( msgText == NULL ) - return; - - if ( resource == NULL) - gcd.iType = GC_EVENT_INFORMATION; - else if ( _tcsncmp( msgText, _T("/me "), 4 ) == 0 && _tcslen( msgText ) > 4 ) { - msgText += 4; - gcd.iType = GC_EVENT_ACTION; - } - else gcd.iType = GC_EVENT_MESSAGE; - } - - GcLogCreate( item ); - - time_t msgTime = 0; - for ( int i = 1; ( xNode = xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) - if (( p = xmlGetAttrValue( xNode, _T("xmlns"))) != NULL ) - if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime==0 ) - if (( p = xmlGetAttrValue( xNode, _T("stamp"))) != NULL ) { - msgTime = JabberIsoToUnixTime( p ); - if (m_options.GcLogChatHistory && msgTime > 0 ) { - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "muc_%s_lastevent", _T2A(gcd.ptszID)); - this->JSetDword(NULL, setting, msgTime); - } } - - time_t now = time( NULL ); - if ( msgTime == 0 || msgTime > now ) - msgTime = now; - - if ( resource != NULL ) { - JABBER_RESOURCE_STATUS* r = GcFindResource(item, resource); - nick = r && r->nick ? r->nick : resource; - } - else - nick = NULL; - - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - gce.ptszUID = resource; - gce.ptszNick = nick; - gce.time = msgTime; - gce.ptszText = EscapeChatTags( (TCHAR*)msgText ); - gce.bIsMe = nick == NULL ? FALSE : (lstrcmp( resource, item->nick ) == 0); - gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; - CallServiceSync( MS_GC_EVENT, NULL, (LPARAM)&gce ); - - item->bChatActive = 2; - - if ( gcd.iType == GC_EVENT_TOPIC ) { - gce.dwFlags &= ~GCEF_ADDTOLOG; - gcd.iType = GC_EVENT_SETSBTEXT; - CallServiceSync( MS_GC_EVENT, NULL, (LPARAM)&gce ); - } - - mir_free( (void*)gce.pszText ); // Since we processed msgText and created a new string -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Accepting groupchat invitations - -class CGroupchatInviteAcceptDlg : public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - CCtrlButton m_accept; - JABBER_GROUPCHAT_INVITE_INFO* m_info; - -public: - CGroupchatInviteAcceptDlg( CJabberProto* ppro, JABBER_GROUPCHAT_INVITE_INFO* pInfo ) : - CSuper( ppro, IDD_GROUPCHAT_INVITE_ACCEPT, NULL ), - m_info( pInfo ), - m_accept( this, IDC_ACCEPT ) - { - m_accept.OnClick = Callback( this, &CGroupchatInviteAcceptDlg::OnCommand_Accept ); - } - - void OnInitDialog() - { - CSuper::OnInitDialog(); - - TCHAR buf[256]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s"), m_info->roomJid, TranslateT("Incoming groupchat invitation.")); - SetDlgItemText( m_hwnd, IDC_HEADERBAR, buf ); - - SetDlgItemText( m_hwnd, IDC_FROM, m_info->from ); - - if ( m_info->reason != NULL ) - SetDlgItemText( m_hwnd, IDC_REASON, m_info->reason ); - - TCHAR* myNick = JabberNickFromJID( m_proto->m_szJabberJID ); - SetDlgItemText( m_hwnd, IDC_NICK, myNick ); - mir_free( myNick ); - - WindowSetIcon( m_hwnd, m_proto, "group" ); - - SetFocus(GetDlgItem(m_hwnd, IDC_NICK)); - } - - void OnCommand_Accept( CCtrlButton* ) - { - TCHAR text[128]; - GetDlgItemText( m_hwnd, IDC_NICK, text, SIZEOF( text )); - m_proto->AcceptGroupchatInvite( m_info->roomJid, text, m_info->password ); - EndDialog( m_hwnd, 0 ); - } -}; - -void __cdecl CJabberProto::GroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo ) -{ - CGroupchatInviteAcceptDlg( this, inviteInfo ).DoModal(); - - mir_free( inviteInfo->roomJid ); - mir_free( inviteInfo->from ); - mir_free( inviteInfo->reason ); - mir_free( inviteInfo->password ); - mir_free( inviteInfo ); -} - -void CJabberProto::GroupchatProcessInvite( const TCHAR* roomJid, const TCHAR* from, const TCHAR* reason, const TCHAR* password ) -{ - if ( roomJid == NULL ) - return; - - if (ListGetItemPtr( LIST_CHATROOM, roomJid )) - return; - - if ( m_options.AutoAcceptMUC == FALSE ) { - JABBER_GROUPCHAT_INVITE_INFO* inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) mir_alloc( sizeof( JABBER_GROUPCHAT_INVITE_INFO )); - inviteInfo->roomJid = mir_tstrdup( roomJid ); - inviteInfo->from = mir_tstrdup( from ); - inviteInfo->reason = mir_tstrdup( reason ); - inviteInfo->password = mir_tstrdup( password ); - JForkThread(( JThreadFunc )&CJabberProto::GroupchatInviteAcceptThread, inviteInfo ); - } - else { - TCHAR* myNick = JabberNickFromJID( m_szJabberJID ); - AcceptGroupchatInvite( roomJid, myNick, password ); - mir_free( myNick ); -} } - -void CJabberProto::AcceptGroupchatInvite( const TCHAR* roomJid, const TCHAR* reason, const TCHAR* password ) -{ - TCHAR room[256], *server, *p; - _tcsncpy( room, roomJid, SIZEOF( room )); - p = _tcstok( room, _T( "@" )); - server = _tcstok( NULL, _T( "@" )); - GroupchatJoinRoom( server, p, reason, password ); -} diff --git a/protocols/JabberG/jabber_ibb.cpp b/protocols/JabberG/jabber_ibb.cpp deleted file mode 100644 index 51719a696b..0000000000 --- a/protocols/JabberG/jabber_ibb.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_ibb.h" -#include "jabber_caps.h" - -#define JABBER_IBB_BLOCK_SIZE 2048 - -void JabberIbbFreeJibb( JABBER_IBB_TRANSFER *jibb ) -{ - if ( jibb ) { - filetransfer* pft = jibb->ft; - if ( pft ) - pft->jibb = NULL; - - mir_free( jibb->srcJID ); - mir_free( jibb->dstJID ); - mir_free( jibb->sid ); - - mir_free( jibb ); -} } - -BOOL CJabberProto::OnFtHandleIbbIq( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( !_tcscmp( pInfo->GetChildNodeName(), _T("open"))) - FtHandleIbbRequest( iqNode, TRUE ); - else if ( !_tcscmp( pInfo->GetChildNodeName(), _T("close"))) - FtHandleIbbRequest( iqNode, FALSE ); - else if ( !_tcscmp( pInfo->GetChildNodeName(), _T("data"))) { - BOOL bOk = FALSE; - const TCHAR *sid = xmlGetAttrValue( pInfo->GetChildNode(), _T("sid")); - const TCHAR *seq = xmlGetAttrValue( pInfo->GetChildNode(), _T("seq")); - if ( sid && seq && xmlGetText( pInfo->GetChildNode())) - bOk = OnIbbRecvdData( xmlGetText( pInfo->GetChildNode()), sid, seq ); - - if ( bOk ) - m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo )); - else - m_ThreadInfo->send( - XmlNodeIq( _T("error"), pInfo ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - } - return TRUE; -} - -void CJabberProto::OnIbbInitiateResult( HXML, CJabberIqInfo* pInfo ) -{ - JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * )pInfo->GetUserData(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) - jibb->bStreamInitialized = TRUE; - if ( jibb->hEvent ) - SetEvent( jibb->hEvent ); -} - -void CJabberProto::OnIbbCloseResult( HXML, CJabberIqInfo* pInfo ) -{ - JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * )pInfo->GetUserData(); - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) - jibb->bStreamClosed = TRUE; - if ( jibb->hEvent ) - SetEvent( jibb->hEvent ); -} - -void CJabberProto::IbbSendThread( JABBER_IBB_TRANSFER *jibb ) -{ - Log( "Thread started: type=ibb_send" ); - - jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - jibb->bStreamInitialized = FALSE; - jibb->bStreamClosed = FALSE; - jibb->state = JIBB_SENDING; - - m_ThreadInfo->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbInitiateResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) - << XCHILDNS( _T("open"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid ) << XATTRI( _T("block-size"), JABBER_IBB_BLOCK_SIZE ) - << XATTR( _T("stanza"), _T("message"))); - - WaitForSingleObject( jibb->hEvent, INFINITE ); - CloseHandle( jibb->hEvent ); - jibb->hEvent = NULL; - - if ( jibb->bStreamInitialized ) { - - jibb->wPacketId = 0; - - BOOL bSent = (this->*jibb->pfnSend)( JABBER_IBB_BLOCK_SIZE, jibb->ft ); - - if ( !jibb->bStreamClosed ) - { - jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - - m_ThreadInfo->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbCloseResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) - << XCHILDNS( _T("close"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid )); - - WaitForSingleObject( jibb->hEvent, INFINITE ); - CloseHandle( jibb->hEvent ); - jibb->hEvent = NULL; - - if ( jibb->bStreamClosed && bSent ) - jibb->state = JIBB_DONE; - - } else { - jibb->state = JIBB_ERROR; - } - } - - (this->*jibb->pfnFinal)(( jibb->state==JIBB_DONE )?TRUE:FALSE, jibb->ft ); - jibb->ft = NULL; - JabberIbbFreeJibb( jibb ); -} - -void __cdecl CJabberProto::IbbReceiveThread( JABBER_IBB_TRANSFER *jibb ) -{ - Log( "Thread started: type=ibb_recv" ); - - filetransfer *ft = jibb->ft; - - jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - jibb->bStreamClosed = FALSE; - jibb->wPacketId = 0; - jibb->dwTransferredSize = 0; - jibb->state = JIBB_RECVING; - - WaitForSingleObject( jibb->hEvent, INFINITE ); - - CloseHandle( jibb->hEvent ); - jibb->hEvent = NULL; - - if ( jibb->state == JIBB_ERROR ) - m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), jibb->dstJID ) << XCHILDNS( _T("close"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid )); - - if ( jibb->bStreamClosed && jibb->dwTransferredSize == ft->dwExpectedRecvFileSize ) - jibb->state = JIBB_DONE; - - (this->*jibb->pfnFinal)(( jibb->state==JIBB_DONE )?TRUE:FALSE, jibb->ft ); - jibb->ft = NULL; - - ListRemove( LIST_FTRECV, jibb->sid ); - - JabberIbbFreeJibb( jibb ); -} - -BOOL CJabberProto::OnIbbRecvdData( const TCHAR *data, const TCHAR *sid, const TCHAR *seq ) -{ - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTRECV, sid ); - if ( !item ) return FALSE; - - WORD wSeq = (WORD)_ttoi(seq); - if ( wSeq != item->jibb->wPacketId ) { - if ( item->jibb->hEvent ) - SetEvent( item->jibb->hEvent ); - return FALSE; - } - - item->jibb->wPacketId++; - - int length = 0; - char *decodedData = JabberBase64DecodeT( data, &length ); - if ( !decodedData ) - return FALSE; - - (this->*item->jibb->pfnRecv)( NULL, item->ft, decodedData, length ); - - item->jibb->dwTransferredSize += (DWORD)length; - - mir_free( decodedData ); - - return TRUE; -} diff --git a/protocols/JabberG/jabber_ibb.h b/protocols/JabberG/jabber_ibb.h deleted file mode 100644 index 37ecfd1a2e..0000000000 --- a/protocols/JabberG/jabber_ibb.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_IBB_H_ -#define _JABBER_IBB_H_ - -typedef enum { JIBB_INIT, JIBB_CONNECT, JIBB_SENDING, JIBB_RECVING, JIBB_DONE, JIBB_ERROR } JABBER_IBB_STATE; - -typedef struct { - TCHAR* sid; - TCHAR* srcJID; - TCHAR* dstJID; - unsigned __int64 dwTransferredSize; - JABBER_IBB_STATE state; - HANDLE hEvent; - BOOL bStreamInitialized; - BOOL bStreamClosed; - WORD wPacketId; - BOOL ( CJabberProto::*pfnSend )( int blocksize, filetransfer* ft ); - int ( CJabberProto::*pfnRecv )( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); - void ( CJabberProto::*pfnFinal )( BOOL success, filetransfer* ft ); - filetransfer* ft; -} - JABBER_IBB_TRANSFER; - -#endif diff --git a/protocols/JabberG/jabber_icolib.cpp b/protocols/JabberG/jabber_icolib.cpp deleted file mode 100644 index f29a827313..0000000000 --- a/protocols/JabberG/jabber_icolib.cpp +++ /dev/null @@ -1,733 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -Idea & portions of code by Artem Shpynov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" - -#include <m_icolib.h> - -#include <m_cluiframes.h> - -#define IDI_ONLINE 104 -#define IDI_OFFLINE 105 -#define IDI_AWAY 128 -#define IDI_FREE4CHAT 129 -#define IDI_INVISIBLE 130 -#define IDI_NA 131 -#define IDI_DND 158 -#define IDI_OCCUPIED 159 -#define IDI_ONTHEPHONE 1002 -#define IDI_OUTTOLUNCH 1003 - -HIMAGELIST hAdvancedStatusIcon = NULL; - -struct CTransportProtoTableItem -{ - TCHAR* mask; - char* proto; -}; - -static CTransportProtoTableItem TransportProtoTable[] = -{ - { _T("|*icq*|jit*"), "ICQ" }, - { _T("msn*"), "MSN" }, - { _T("yahoo*"), "YAHOO" }, - { _T("mrim*"), "MRA" }, - { _T("aim*"), "AIM" }, - //request #3094 - { _T("|gg*|gadu*"), "GaduGadu" }, - { _T("tv*"), "TV" }, - { _T("dict*"), "Dictionary" }, - { _T("weather*"), "Weather" }, - { _T("skype*"), "Skype" }, - { _T("sms*"), "SMS" }, - { _T("smtp*"), "SMTP" }, - //j2j - { _T("gtalk.*.*"), "GTalk" }, - { _T("|xmpp.*.*|j2j.*.*"),"Jabber2Jabber" }, - //jabbim.cz - services - { _T("disk*"), "Jabber Disk" }, - { _T("irc*"), "IRC" }, - { _T("rss*"), "RSS" }, - { _T("tlen*"), "Tlen" }, - - // German social networks - { _T("studivz*"), "StudiVZ" }, - { _T("schuelervz*"), "SchuelerVZ" }, - { _T("meinvz*"), "MeinVZ" }, - { _T("|fb*|facebook*"), "Facebook" }, -}; - -static int skinIconStatusToResourceId[] = {IDI_OFFLINE,IDI_ONLINE,IDI_AWAY,IDI_DND,IDI_NA,IDI_NA,/*IDI_OCCUPIED,*/IDI_FREE4CHAT,IDI_INVISIBLE,IDI_ONTHEPHONE,IDI_OUTTOLUNCH}; -static int skinStatusToJabberStatus[] = {0,1,2,3,4,4,6,7,2,2}; - -/////////////////////////////////////////////////////////////////////////////// -// CIconPool class -int CIconPool::CPoolItem::cmp(const CPoolItem *p1, const CPoolItem *p2) -{ - return lstrcmpA(p1->m_name, p2->m_name); -} - -CIconPool::CPoolItem::CPoolItem(): - m_name(NULL), m_szIcolibName(NULL), m_hIcolibItem(NULL), m_hClistItem(NULL) -{ -} - -CIconPool::CPoolItem::~CPoolItem() -{ - if (m_hIcolibItem && m_szIcolibName) - { - CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)m_szIcolibName); - mir_free(m_szIcolibName); - } - - if (m_name) mir_free(m_name); -} - -CIconPool::CIconPool(CJabberProto *proto): - m_proto(proto), - m_items(10, CIconPool::CPoolItem::cmp), - m_hOnExtraIconsRebuild(NULL) -{ -} - -CIconPool::~CIconPool() -{ - if (m_hOnExtraIconsRebuild) - { - UnhookEvent(m_hOnExtraIconsRebuild); - m_hOnExtraIconsRebuild = NULL; - } -} - -void CIconPool::RegisterIcon(const char *name, const char *filename, int iconid, TCHAR *szSection, TCHAR *szDescription) -{ - char szSettingName[128]; - mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", m_proto->m_szModuleName, name); - - CPoolItem *item = new CPoolItem; - item->m_name = mir_strdup(name); - item->m_szIcolibName = mir_strdup(szSettingName); - item->m_hClistItem = NULL; - - SKINICONDESC sid = {0}; - sid.cbSize = sizeof(SKINICONDESC); - sid.pszDefaultFile = (char *)filename; // kill const flag for compiler to shut up - sid.pszName = szSettingName; - sid.ptszSection = szSection; - sid.ptszDescription = szDescription; - sid.flags = SIDF_TCHAR; - sid.iDefaultIndex = iconid; - item->m_hIcolibItem = Skin_AddIcon(&sid); - - m_items.insert(item); -} - -HANDLE CIconPool::GetIcolibHandle(const char *name) -{ - if (CPoolItem *item = FindItemByName(name)) - return item->m_hIcolibItem; - - return NULL; -} - -char *CIconPool::GetIcolibName(const char *name) -{ - if (CPoolItem *item = FindItemByName(name)) - return item->m_szIcolibName; - - return NULL; -} - -HICON CIconPool::GetIcon(const char *name, bool big) -{ - if (CPoolItem *item = FindItemByName(name)) - return (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)item->m_hIcolibItem); - - return NULL; -} - -HANDLE CIconPool::GetClistHandle(const char *name) -{ - if (!name) - return (HANDLE)-1; - - if (!ExtraIconsSupported()) - return (HANDLE)-1; - - if (!m_hOnExtraIconsRebuild) - { - int (__cdecl CIconPool::*hookProc)(WPARAM, LPARAM); - hookProc = &CIconPool::OnExtraIconsRebuild; - m_hOnExtraIconsRebuild = HookEventObj(ME_CLIST_EXTRA_LIST_REBUILD, (MIRANDAHOOKOBJ)*(void **)&hookProc, this); - } - - if (CPoolItem *item = FindItemByName(name)) - { - if (item->m_hClistItem) - return item->m_hClistItem; - - HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item->m_hIcolibItem); - item->m_hClistItem = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)hIcon, 0); - g_ReleaseIcon(hIcon); - return item->m_hClistItem; - } - - return (HANDLE)-1; -} - -CIconPool::CPoolItem *CIconPool::FindItemByName(const char *name) -{ - CPoolItem item; - item.m_name = mir_strdup(name); - return m_items.find(&item); -} - -int CIconPool::OnExtraIconsRebuild(WPARAM, LPARAM) -{ - for (int i = 0; i < m_items.getCount(); ++i) - m_items[i].m_hClistItem = NULL; - - return 0; -} - -bool CIconPool::ExtraIconsSupported() -{ - static int res = -1; - if (res < 0) res = ServiceExists(MS_CLIST_EXTRA_ADD_ICON) ? 1 : 0; - return res ? true : false; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Icons init - -struct TIconListItem -{ - char* szDescr; - char* szName; - int defIconID; - char* szSection; - HANDLE hIcon; -}; - -static TIconListItem iconList[] = -{ - { LPGEN("%s"), "main", IDI_JABBER, NULL }, -}; - -void CJabberProto::IconsInit( void ) -{ - int i; - - m_transportProtoTableStartIndex = (int *)mir_alloc(sizeof(int) * SIZEOF(TransportProtoTable)); - for (i = 0; i < SIZEOF(TransportProtoTable); ++i) - m_transportProtoTableStartIndex[i] = -1; - - SKINICONDESC sid = {0}; - char szFile[MAX_PATH]; - GetModuleFileNameA(hInst, szFile, MAX_PATH); - - sid.cbSize = sizeof(SKINICONDESC); - sid.pszDefaultFile = szFile; - sid.flags = SIDF_TCHAR; - - char szSettingName[100]; - TCHAR szSectionName[100]; - TCHAR szDescription[100]; - TCHAR szRootSection[100]; - - sid.pszName = szSettingName; - sid.ptszSection = szSectionName; - sid.ptszDescription = szDescription; - - m_phIconLibItems = ( HANDLE* )mir_alloc( sizeof( HANDLE )*SIZEOF(iconList)); - - mir_sntprintf( szRootSection, SIZEOF(szRootSection), _T("%s/%s/%s"), LPGENT("Protocols"), LPGENT("Jabber"), LPGENT("Accounts")); - - for (i = 0; i < SIZEOF(iconList); i++ ) { - TCHAR tmp[100]; - - if ( iconList[i].szSection ) { - mir_sntprintf( szSectionName, SIZEOF(szSectionName), _T("%s/") _T(TCHAR_STR_PARAM), szRootSection, iconList[i].szSection ); - if (_tcsstr(szSectionName, _T("%s"))) { - mir_sntprintf(tmp, SIZEOF(tmp), szSectionName, m_tszUserName); - lstrcpy(szSectionName, tmp); - } - } - else { - mir_sntprintf( szSectionName, SIZEOF(szSectionName), _T("%s"), szRootSection ); - } - - if (strstr(iconList[i].szDescr, "%s")) { - mir_sntprintf( tmp, SIZEOF(tmp), _T(TCHAR_STR_PARAM), iconList[i].szDescr ); - mir_sntprintf( szDescription, SIZEOF(szDescription), tmp, m_tszUserName ); - } - else mir_sntprintf( szDescription, SIZEOF(szDescription), _T(TCHAR_STR_PARAM), iconList[i].szDescr ); - - mir_snprintf( szSettingName, SIZEOF(szSettingName), "%s_%s", m_szModuleName, iconList[i].szName ); - - sid.iDefaultIndex = -iconList[i].defIconID; - m_phIconLibItems[i] = Skin_AddIcon(&sid); -} } - -HANDLE CJabberProto::GetIconHandle( int iconId ) -{ - if (HANDLE result = g_GetIconHandle(iconId)) - return result; - - for ( int i=0; i < SIZEOF(iconList); i++ ) - if ( iconList[i].defIconID == iconId ) - return m_phIconLibItems[i]; - - return NULL; -} - -HICON CJabberProto::LoadIconEx( const char* name, bool big ) -{ - if (HICON result = g_LoadIconEx(name, big)) - return result; - - char szSettingName[100]; - mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", m_szModuleName, name ); - return ( HICON )CallService( MS_SKIN2_GETICON, big, (LPARAM)szSettingName ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// internal functions - -static inline TCHAR qtoupper( TCHAR c ) -{ - return ( c >= 'a' && c <= 'z' ) ? c - 'a' + 'A' : c; -} - -static BOOL WildComparei( const TCHAR* name, const TCHAR* mask ) -{ - const TCHAR* last='\0'; - for ( ;; mask++, name++) { - if ( *mask != '?' && qtoupper( *mask ) != qtoupper( *name )) - break; - if ( *name == '\0' ) - return ((BOOL)!*mask); - } - - if ( *mask != '*' ) - return FALSE; - - for (;; mask++, name++ ) { - while( *mask == '*' ) { - last = mask++; - if ( *mask == '\0' ) - return ((BOOL)!*mask); /* true */ - } - - if ( *name == '\0' ) - return ((BOOL)!*mask); /* *mask == EOS */ - if ( *mask != '?' && qtoupper( *mask ) != qtoupper( *name )) - name -= (size_t)(mask - last) - 1, mask = last; -} } - -static BOOL MatchMask( const TCHAR* name, const TCHAR* mask) -{ - if ( !mask || !name ) - return mask == name; - - if ( *mask != '|' ) - return WildComparei( name, mask ); - - TCHAR* temp = NEWTSTR_ALLOCA(mask); - for ( int e=1; mask[e] != '\0'; e++ ) { - int s = e; - while ( mask[e] != '\0' && mask[e] != '|') - e++; - - temp[e]= _T('\0'); - if ( WildComparei( name, temp+s )) - return TRUE; - - if ( mask[e] == 0 ) - return FALSE; - } - - return FALSE; -} - -static HICON ExtractIconFromPath(const char *path, BOOL * needFree) -{ - char *comma; - char file[MAX_PATH],fileFull[MAX_PATH]; - int n; - HICON hIcon; - lstrcpynA(file,path,sizeof(file)); - comma=strrchr(file,','); - if(comma==NULL) n=0; - else {n=atoi(comma+1); *comma=0;} - CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)file, (LPARAM)fileFull); - hIcon=NULL; - ExtractIconExA(fileFull,n,NULL,&hIcon,1); - if (needFree) - *needFree=(hIcon!=NULL); - - return hIcon; -} - -static HICON LoadTransportIcon(char *filename,int i,char *IconName,TCHAR *SectName,TCHAR *Description,int internalidx, BOOL * needFree) -{ - char szPath[MAX_PATH],szMyPath[MAX_PATH], szFullPath[MAX_PATH],*str; - BOOL has_proto_icon=FALSE; - SKINICONDESC sid={0}; - if (needFree) *needFree=FALSE; - GetModuleFileNameA(NULL, szPath, MAX_PATH); - str=strrchr(szPath,'\\'); - if(str!=NULL) *str=0; - _snprintf(szMyPath, sizeof(szMyPath), "%s\\Icons\\%s", szPath, filename); - _snprintf(szFullPath, sizeof(szFullPath), "%s\\Icons\\%s,%d", szPath, filename, i); - BOOL nf; - HICON hi=ExtractIconFromPath(szFullPath,&nf); - if (hi) has_proto_icon=TRUE; - if (hi && nf) DestroyIcon(hi); - if ( IconName != NULL && SectName != NULL) { - sid.cbSize = sizeof(sid); - sid.hDefaultIcon = (has_proto_icon)?NULL:(HICON)CallService(MS_SKIN_LOADPROTOICON,(WPARAM)NULL,(LPARAM)(-internalidx)); - sid.ptszSection = SectName; - sid.pszName = IconName; - sid.ptszDescription = Description; - sid.pszDefaultFile = szMyPath; - sid.iDefaultIndex = i; - sid.flags = SIDF_TCHAR; - Skin_AddIcon(&sid); - } - return ((HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)IconName)); -} - -static HICON LoadSmallIcon(HINSTANCE hInstance, LPCTSTR lpIconName) -{ - HICON hIcon=NULL; // icon handle - int index=-(int)lpIconName; - TCHAR filename[MAX_PATH]={0}; - GetModuleFileName(hInstance,filename,MAX_PATH); - ExtractIconEx(filename,index,NULL,&hIcon,1); - return hIcon; -} - -int CJabberProto::LoadAdvancedIcons(int iID) -{ - int i; - char *proto = TransportProtoTable[iID].proto; - char defFile[MAX_PATH] = {0}; - TCHAR Group[255]; - char Uname[255]; - int first=-1; - HICON empty=LoadSmallIcon(NULL,MAKEINTRESOURCE(102)); - - mir_sntprintf(Group, SIZEOF(Group), _T("Status Icons/%s/") _T(TCHAR_STR_PARAM) _T(" %s"), m_tszUserName, proto, TranslateT("transport")); - mir_snprintf(defFile, SIZEOF(defFile), "proto_%s.dll",proto); - if (!hAdvancedStatusIcon) - hAdvancedStatusIcon=(HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0); - - EnterCriticalSection( &m_csModeMsgMutex ); - for (i=0; i<ID_STATUS_ONTHEPHONE-ID_STATUS_OFFLINE; i++) { - HICON hicon; - BOOL needFree; - int n=skinStatusToJabberStatus[i]; - TCHAR *descr = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, n+ID_STATUS_OFFLINE, GSMDF_TCHAR); - mir_snprintf(Uname, SIZEOF(Uname), "%s_Transport_%s_%d", m_szModuleName, proto, n); - hicon=(HICON)LoadTransportIcon(defFile,-skinIconStatusToResourceId[i],Uname,Group,descr,-(n+ID_STATUS_OFFLINE),&needFree); - int index=(m_transportProtoTableStartIndex[iID] == -1)?-1:m_transportProtoTableStartIndex[iID]+n; - int added=ImageList_ReplaceIcon(hAdvancedStatusIcon,index,hicon?hicon:empty); - if (first == -1) first=added; - if (hicon && needFree) DestroyIcon(hicon); - } - - if ( m_transportProtoTableStartIndex[iID] == -1 ) - m_transportProtoTableStartIndex[iID] = first; - LeaveCriticalSection( &m_csModeMsgMutex ); - return 0; -} - -int CJabberProto::GetTransportProtoID( TCHAR* TransportDomain ) -{ - for ( int i=0; i<SIZEOF(TransportProtoTable); i++ ) - if ( MatchMask( TransportDomain, TransportProtoTable[i].mask )) - return i; - - return -1; -} - -int CJabberProto::GetTransportStatusIconIndex(int iID, int Status) -{ - if ( iID < 0 || iID >= SIZEOF( TransportProtoTable )) - return -1; - - //icons not loaded - loading icons - if ( m_transportProtoTableStartIndex[iID] == -1 ) - LoadAdvancedIcons( iID ); - - //some fault on loading icons - if ( m_transportProtoTableStartIndex[iID] == -1 ) - return -1; - - if ( Status < ID_STATUS_OFFLINE ) - Status = ID_STATUS_OFFLINE; - - return m_transportProtoTableStartIndex[iID] + skinStatusToJabberStatus[ Status - ID_STATUS_OFFLINE ]; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// a hook for the IcoLib plugin - -int CJabberProto::OnReloadIcons(WPARAM, LPARAM) -{ - for ( int i=0; i < SIZEOF(TransportProtoTable); i++ ) - if ( m_transportProtoTableStartIndex[i] != -1 ) - LoadAdvancedIcons(i); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Prototype for Jabber and other protocols to return index of Advanced status -// wParam - HCONTACT of called protocol -// lParam - should be 0 (reserverd for futher usage) -// return value: -1 - no Advanced status -// : other - index of icons in clcimagelist. -// if imagelist require advanced painting status overlay(like xStatus) -// index should be shifted to HIWORD, LOWORD should be 0 - -INT_PTR __cdecl CJabberProto::JGetAdvancedStatusIcon(WPARAM wParam, LPARAM) -{ - HANDLE hContact=(HANDLE) wParam; - if ( !hContact ) - return -1; - - if ( !JGetByte( hContact, "IsTransported", 0 )) - return -1; - - DBVARIANT dbv; - if ( JGetStringT( hContact, "Transport", &dbv )) - return -1; - - int iID = GetTransportProtoID( dbv.ptszVal ); - DBFreeVariant(&dbv); - if ( iID >= 0 ) { - WORD Status = ID_STATUS_OFFLINE; - Status = JGetWord( hContact, "Status", ID_STATUS_OFFLINE ); - if ( Status < ID_STATUS_OFFLINE ) - Status = ID_STATUS_OFFLINE; - else if (Status > ID_STATUS_INVISIBLE ) - Status = ID_STATUS_ONLINE; - return GetTransportStatusIconIndex( iID, Status ); - } - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Transport check functions - -BOOL CJabberProto::DBCheckIsTransportedContact(const TCHAR* jid, HANDLE hContact) -{ - // check if transport is already set - if ( !jid || !hContact ) - return FALSE; - - // strip domain part from jid - TCHAR* domain = _tcschr(( TCHAR* )jid, '@' ); - BOOL isAgent = (domain == NULL) ? TRUE : FALSE; - BOOL isTransported = FALSE; - if ( domain!=NULL ) - domain = NEWTSTR_ALLOCA(domain+1); - else - domain = NEWTSTR_ALLOCA(jid); - - TCHAR* resourcepos = _tcschr( domain, '/' ); - if ( resourcepos != NULL ) - *resourcepos = '\0'; - - for ( int i=0; i < SIZEOF(TransportProtoTable); i++ ) { - if ( MatchMask( domain, TransportProtoTable[i].mask )) { - GetTransportStatusIconIndex( GetTransportProtoID( domain ), ID_STATUS_OFFLINE ); - isTransported = TRUE; - break; - } } - - if ( m_lstTransports.getIndex( domain ) == -1 ) { - if ( isAgent ) { - m_lstTransports.insert( mir_tstrdup(domain)); - JSetByte( hContact, "IsTransport", 1 ); - } } - - if ( isTransported ) { - JSetStringT( hContact, "Transport", domain ); - JSetByte( hContact, "IsTransported", 1 ); - } - return isTransported; -} - -void CJabberProto::CheckAllContactsAreTransported() -{ - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( !lstrcmpA( m_szModuleName, szProto )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - DBCheckIsTransportedContact( dbv.ptszVal, hContact ); - JFreeVariant( &dbv ); - } } - - hContact = db_find_next(hContact); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// Cross-instance shared icons - -static TIconListItem sharedIconList[] = -{ - { LPGEN("Privacy Lists"), "privacylists", IDI_PRIVACY_LISTS, NULL }, - { LPGEN("Bookmarks"), "bookmarks", IDI_BOOKMARKS, NULL }, - { LPGEN("Notes"), "notes", IDI_NOTES, NULL }, - { LPGEN("Multi-User Conference"), "group", IDI_GROUP, NULL }, - { LPGEN("Agents list"), "Agents", IDI_AGENTS, NULL }, - - { LPGEN("Transports"), "transport", IDI_TRANSPORT, NULL }, - { LPGEN("Registered transports"), "transport_loc", IDI_TRANSPORTL, NULL }, - { LPGEN("Change password"), "key", IDI_KEYS, NULL }, - { LPGEN("Personal vCard"), "vcard", IDI_VCARD, NULL }, - { LPGEN("Request authorization"), "Request", IDI_REQUEST, NULL }, - { LPGEN("Grant authorization"), "Grant", IDI_GRANT, NULL }, - { LPGEN("Revoke authorization"), "Revoke", IDI_AUTHREVOKE, NULL }, - { LPGEN("Convert to room"), "convert", IDI_USER2ROOM, NULL }, - { LPGEN("Add to roster"), "addroster", IDI_ADDROSTER, NULL }, - { LPGEN("Login/logout"), "trlogonoff", IDI_LOGIN, NULL }, - { LPGEN("Resolve nicks"), "trresolve", IDI_REFRESH, NULL }, - { LPGEN("Send note"), "sendnote", IDI_SEND_NOTE, NULL }, - { LPGEN("Service Discovery"), "servicediscovery", IDI_SERVICE_DISCOVERY, NULL }, - { LPGEN("AdHoc Command"), "adhoc", IDI_COMMAND, NULL }, - { LPGEN("XML Console"), "xmlconsole", IDI_CONSOLE, NULL }, - { LPGEN("OpenID Request"), "openid", IDI_HTTP_AUTH, NULL }, - - { LPGEN("Discovery succeeded"), "disco_ok", IDI_DISCO_OK, LPGEN("Dialogs") }, - { LPGEN("Discovery failed"), "disco_fail", IDI_DISCO_FAIL, LPGEN("Dialogs") }, - { LPGEN("Discovery in progress"), "disco_progress", IDI_DISCO_PROGRESS, LPGEN("Dialogs") }, - { LPGEN("View as tree"), "sd_view_tree", IDI_VIEW_TREE, LPGEN("Dialogs") }, - { LPGEN("View as list"), "sd_view_list", IDI_VIEW_LIST, LPGEN("Dialogs") }, - { LPGEN("Apply filter"), "sd_filter_apply", IDI_FILTER_APPLY, LPGEN("Dialogs") }, - { LPGEN("Reset filter"), "sd_filter_reset", IDI_FILTER_RESET, LPGEN("Dialogs") }, - - { LPGEN("Navigate home"), "sd_nav_home", IDI_NAV_HOME, LPGEN("Dialogs/Discovery") }, - { LPGEN("Refresh node"), "sd_nav_refresh", IDI_NAV_REFRESH, LPGEN("Dialogs/Discovery") }, - { LPGEN("Browse node"), "sd_browse", IDI_BROWSE, LPGEN("Dialogs/Discovery") }, - { LPGEN("RSS service"), "node_rss", IDI_NODE_RSS, LPGEN("Dialogs/Discovery") }, - { LPGEN("Server"), "node_server", IDI_NODE_SERVER, LPGEN("Dialogs/Discovery") }, - { LPGEN("Storage service"), "node_store", IDI_NODE_STORE, LPGEN("Dialogs/Discovery") }, - { LPGEN("Weather service"), "node_weather", IDI_NODE_WEATHER, LPGEN("Dialogs/Discovery") }, - - { LPGEN("Generic privacy list"), "pl_list_any", IDI_PL_LIST_ANY, LPGEN("Dialogs/Privacy") }, - { LPGEN("Active privacy list"), "pl_list_active", IDI_PL_LIST_ACTIVE, LPGEN("Dialogs/Privacy") }, - { LPGEN("Default privacy list"), "pl_list_default", IDI_PL_LIST_DEFAULT, LPGEN("Dialogs/Privacy") }, - { LPGEN("Move up"), "arrow_up", IDI_ARROW_UP, LPGEN("Dialogs/Privacy") }, - { LPGEN("Move down"), "arrow_down", IDI_ARROW_DOWN, LPGEN("Dialogs/Privacy") }, - { LPGEN("Allow Messages"), "pl_msg_allow", IDI_PL_MSG_ALLOW, LPGEN("Dialogs/Privacy") }, - { LPGEN("Allow Presences (in)"), "pl_prin_allow", IDI_PL_PRIN_ALLOW, LPGEN("Dialogs/Privacy") }, - { LPGEN("Allow Presences (out)"), "pl_prout_allow", IDI_PL_PROUT_ALLOW, LPGEN("Dialogs/Privacy") }, - { LPGEN("Allow Queries"), "pl_iq_allow", IDI_PL_QUERY_ALLOW, LPGEN("Dialogs/Privacy") }, - { LPGEN("Deny Messages"), "pl_msg_deny", IDI_PL_MSG_DENY, LPGEN("Dialogs/Privacy") }, - { LPGEN("Deny Presences (in)"), "pl_prin_deny", IDI_PL_PRIN_DENY, LPGEN("Dialogs/Privacy") }, - { LPGEN("Deny Presences (out)"), "pl_prout_deny", IDI_PL_PROUT_DENY, LPGEN("Dialogs/Privacy") }, - { LPGEN("Deny Queries"), "pl_iq_deny", IDI_PL_QUERY_DENY, LPGEN("Dialogs/Privacy") }, -}; - -static void sttProcessIcons( int iAmount ) -{ - TCHAR szFile[MAX_PATH]; - GetModuleFileName(hInst, szFile, MAX_PATH); - - SKINICONDESC sid = {0}; - sid.cbSize = sizeof(SKINICONDESC); - sid.ptszDefaultFile = szFile; - sid.flags = SIDF_PATH_TCHAR; - - char szRootSection[100]; - mir_snprintf( szRootSection, SIZEOF(szRootSection), "%s/%s", LPGEN("Protocols"), LPGEN("Jabber")); - - for ( int i = 0; i < iAmount; i++ ) { - char szSettingName[100], szSectionName[100]; - - mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", - GLOBAL_SETTING_PREFIX, sharedIconList[i].szName); - - if ( sharedIconList[i].szSection ) { - mir_snprintf( szSectionName, sizeof( szSectionName ), "%s/%s", szRootSection, sharedIconList[i].szSection ); - sid.pszSection = szSectionName; - } - else sid.pszSection = szRootSection; - - sid.pszName = szSettingName; - sid.pszDescription = sharedIconList[i].szDescr; - sid.iDefaultIndex = -sharedIconList[i].defIconID; - sharedIconList[i].hIcon = Skin_AddIcon(&sid); -} } - -void g_IconsInit() -{ - sttProcessIcons( SIZEOF( sharedIconList )); -} - -HANDLE g_GetIconHandle( int iconId ) -{ - for ( int i=0; i < SIZEOF(sharedIconList); i++ ) - if ( sharedIconList[i].defIconID == iconId ) - return sharedIconList[i].hIcon; - - return NULL; -} - -HICON g_LoadIconEx( const char* name, bool big ) -{ - char szSettingName[100]; - mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", GLOBAL_SETTING_PREFIX, name ); - return ( HICON )CallService( MS_SKIN2_GETICON, big, (LPARAM)szSettingName ); -} - -void g_ReleaseIcon( HICON hIcon ) -{ - if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); -} - -void ImageList_AddIcon_Icolib( HIMAGELIST hIml, HICON hIcon ) -{ - ImageList_AddIcon( hIml, hIcon ); - g_ReleaseIcon( hIcon ); -} - -void WindowSetIcon(HWND hWnd, CJabberProto *proto, const char* name) -{ - SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )proto->LoadIconEx( name, true )); - SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )proto->LoadIconEx( name )); -} - -void WindowFreeIcon(HWND hWnd) -{ - g_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0)); - g_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0)); -} diff --git a/protocols/JabberG/jabber_icolib.h b/protocols/JabberG/jabber_icolib.h deleted file mode 100644 index 4b5f7d8e12..0000000000 --- a/protocols/JabberG/jabber_icolib.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_ICOLIB_H_ -#define _JABBER_ICOLIB_H_ - -struct CJabberProto; - -class CIconPool -{ -public: - CIconPool(CJabberProto *proto); - ~CIconPool(); - - void RegisterIcon(const char *name, const char *filename, int iconid, TCHAR *szSection, TCHAR *szDescription); - - HANDLE GetIcolibHandle(const char *name); - char *GetIcolibName(const char *name); - HICON GetIcon(const char *name, bool big = false); - HANDLE GetClistHandle(const char *name); - -private: - struct CPoolItem - { - char *m_name; - char *m_szIcolibName; - HANDLE m_hIcolibItem; - HANDLE m_hClistItem; - - static int cmp(const CPoolItem *p1, const CPoolItem *p2); - - CPoolItem(); - ~CPoolItem(); - }; - - CJabberProto *m_proto; - OBJLIST<CPoolItem> m_items; - HANDLE m_hOnExtraIconsRebuild; - - CPoolItem *FindItemByName(const char *name); - - int __cdecl OnExtraIconsRebuild(WPARAM, LPARAM); - static bool ExtraIconsSupported(); -}; - -#endif // _JABBER_ICOLIB_H_ diff --git a/protocols/JabberG/jabber_iq.cpp b/protocols/JabberG/jabber_iq.cpp deleted file mode 100644 index 43084114c2..0000000000 --- a/protocols/JabberG/jabber_iq.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "jabber_privacy.h" -#include "jabber_ibb.h" -#include "jabber_rc.h" - -void CJabberProto::IqInit() -{ - InitializeCriticalSection( &m_csIqList ); - m_ppIqList = NULL; - m_nIqCount = 0; - m_nIqAlloced = 0; -} - -void CJabberProto::IqUninit() -{ - if ( m_ppIqList ) mir_free( m_ppIqList ); - m_ppIqList = NULL; - m_nIqCount = 0; - m_nIqAlloced = 0; - DeleteCriticalSection( &m_csIqList ); -} - -void CJabberProto::IqRemove( int index ) -{ - EnterCriticalSection( &m_csIqList ); - if ( index>=0 && index<m_nIqCount ) { - memmove( m_ppIqList+index, m_ppIqList+index+1, sizeof( JABBER_IQ_FUNC )*( m_nIqCount-index-1 )); - m_nIqCount--; - } - LeaveCriticalSection( &m_csIqList ); -} - -void CJabberProto::IqExpire() -{ - int i; - time_t expire; - - EnterCriticalSection( &m_csIqList ); - expire = time( NULL ) - 120; // 2 minute - i = 0; - while ( i < m_nIqCount ) { - if ( m_ppIqList[i].requestTime < expire ) - IqRemove( i ); - else - i++; - } - LeaveCriticalSection( &m_csIqList ); -} - -JABBER_IQ_PFUNC CJabberProto::JabberIqFetchFunc( int iqId ) -{ - int i; - JABBER_IQ_PFUNC res; - - EnterCriticalSection( &m_csIqList ); - IqExpire(); -#ifdef _DEBUG - for ( i=0; i<m_nIqCount; i++ ) - Log( " %04d : %02d : 0x%x", m_ppIqList[i].iqId, m_ppIqList[i].procId, m_ppIqList[i].func ); -#endif - for ( i=0; i<m_nIqCount && m_ppIqList[i].iqId!=iqId; i++ ); - if ( i < m_nIqCount ) { - res = m_ppIqList[i].func; - IqRemove( i ); - } - else { - res = ( JABBER_IQ_PFUNC ) NULL; - } - LeaveCriticalSection( &m_csIqList ); - return res; -} - -void CJabberProto::IqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func ) -{ - int i; - - EnterCriticalSection( &m_csIqList ); - Log( "IqAdd id=%d, proc=%d, func=0x%x", iqId, procId, func ); - if ( procId == IQ_PROC_NONE ) - i = m_nIqCount; - else - for ( i=0; i<m_nIqCount && m_ppIqList[i].procId!=procId; i++ ); - - if ( i>=m_nIqCount && m_nIqCount>=m_nIqAlloced ) { - m_nIqAlloced = m_nIqCount + 8; - m_ppIqList = ( JABBER_IQ_FUNC * )mir_realloc( m_ppIqList, sizeof( JABBER_IQ_FUNC )*m_nIqAlloced ); - } - - if ( m_ppIqList != NULL ) { - m_ppIqList[i].iqId = iqId; - m_ppIqList[i].procId = procId; - m_ppIqList[i].func = func; - m_ppIqList[i].requestTime = time( NULL ); - if ( i == m_nIqCount ) m_nIqCount++; - } - LeaveCriticalSection( &m_csIqList ); -} - -BOOL CJabberIqManager::FillPermanentHandlers() -{ - // Google Shared Status (http://code.google.com/apis/talk/jep_extensions/shared_status.html) - AddPermanentHandler( &CJabberProto::OnIqSetGoogleSharedStatus, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR, _T("google:shared-status"), FALSE, _T("query")); - - // version requests (XEP-0092) - AddPermanentHandler( &CJabberProto::OnIqRequestVersion, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_VERSION), FALSE, _T("query")); - - // last activity (XEP-0012) - AddPermanentHandler( &CJabberProto::OnIqRequestLastActivity, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_LAST_ACTIVITY), FALSE, _T("query")); - - // ping requests (XEP-0199) - AddPermanentHandler( &CJabberProto::OnIqRequestPing, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_PING), FALSE, _T("ping")); - - // entity time (XEP-0202) - AddPermanentHandler( &CJabberProto::OnIqRequestTime, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_ENTITY_TIME), FALSE, _T("time")); - - // entity time (XEP-0090) - AddPermanentHandler( &CJabberProto::OnIqProcessIqOldTime, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_ENTITY_TIME_OLD), FALSE, _T("query")); - - // old avatars support (deprecated XEP-0008) - AddPermanentHandler( &CJabberProto::OnIqRequestAvatar, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_AVATAR), FALSE, _T("query")); - - // privacy lists (XEP-0016) - AddPermanentHandler( &CJabberProto::OnIqRequestPrivacyLists, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_PRIVACY_LISTS), FALSE, _T("query")); - - // in band bytestreams (XEP-0047) - AddPermanentHandler( &CJabberProto::OnFtHandleIbbIq, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE | JABBER_IQ_PARSE_CHILD_TAG_NAME | JABBER_IQ_PARSE_CHILD_TAG_XMLNS, _T(JABBER_FEAT_IBB), FALSE, NULL); - - // socks5-bytestreams (XEP-0065) - AddPermanentHandler( &CJabberProto::FtHandleBytestreamRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_BYTESTREAMS), FALSE, _T("query")); - - // session initiation (XEP-0095) - AddPermanentHandler( &CJabberProto::OnSiRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_SI), FALSE, _T("si")); - - // roster push requests - AddPermanentHandler( &CJabberProto::OnRosterPushRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_IQ_ROSTER), FALSE, _T("query")); - - // OOB file transfers - AddPermanentHandler( &CJabberProto::OnIqRequestOOB, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_OOB), FALSE, _T("query")); - - // disco#items requests (XEP-0030, XEP-0050) - AddPermanentHandler( &CJabberProto::OnHandleDiscoItemsRequest, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_DISCO_ITEMS), FALSE, _T("query")); - - // disco#info requests (XEP-0030, XEP-0050, XEP-0115) - AddPermanentHandler( &CJabberProto::OnHandleDiscoInfoRequest, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_DISCO_INFO), FALSE, _T("query")); - - // ad-hoc commands (XEP-0050) for remote controlling (XEP-0146) - AddPermanentHandler( &CJabberProto::HandleAdhocCommandRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_COMMANDS), FALSE, _T("command")); - - // http auth (XEP-0070) - AddPermanentHandler( &CJabberProto::OnIqHttpAuth, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_HTTP_AUTH), FALSE, _T("confirm")); - - return TRUE; -} - -BOOL CJabberIqManager::Start() -{ - if ( m_hExpirerThread || m_bExpirerThreadShutdownRequest ) - return FALSE; - - m_hExpirerThread = ppro->JForkThreadEx( &CJabberProto::ExpirerThread, this ); - if ( !m_hExpirerThread ) - return FALSE; - - return TRUE; -} - -void __cdecl CJabberProto::ExpirerThread( void* pParam ) -{ - CJabberIqManager *pManager = ( CJabberIqManager * )pParam; - pManager->ExpirerThread(); -} - -void CJabberIqManager::ExpirerThread() -{ - while (!m_bExpirerThreadShutdownRequest) - { - Lock(); - CJabberIqInfo* pInfo = DetachExpired(); - Unlock(); - if (!pInfo) - { - for (int i = 0; !m_bExpirerThreadShutdownRequest && (i < 10); i++) - Sleep(50); - - // -1 thread :) - ppro->m_adhocManager.ExpireSessions(); - continue; - } - ExpireInfo( pInfo ); - delete pInfo; - } - - if ( !m_bExpirerThreadShutdownRequest ) { - CloseHandle( m_hExpirerThread ); - m_hExpirerThread = NULL; - } -} - -void CJabberIqManager::ExpireInfo( CJabberIqInfo* pInfo, void*) -{ - if ( !pInfo ) - return; - - if ( pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM ) - pInfo->m_szFrom = pInfo->m_szReceiver; - if (( pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT ) && ( pInfo->m_szFrom )) - pInfo->m_hContact = ppro->HContactFromJID( pInfo->m_szFrom , 3); - - ppro->Log( "Expiring iq id %d, sent to " TCHAR_STR_PARAM, pInfo->m_nIqId, pInfo->m_szReceiver ? pInfo->m_szReceiver : _T("server")); - - pInfo->m_nIqType = JABBER_IQ_TYPE_FAIL; - (ppro->*(pInfo->m_pHandler))( NULL, pInfo ); -} - -CJabberIqInfo* CJabberIqManager::AddHandler(JABBER_IQ_HANDLER pHandler, int nIqType, const TCHAR *szReceiver, DWORD dwParamsToParse, int nIqId, void *pUserData, int iPriority) -{ - CJabberIqInfo* pInfo = new CJabberIqInfo(); - if (!pInfo) - return NULL; - - pInfo->m_pHandler = pHandler; - if (nIqId == -1) - nIqId = ppro->SerialNext(); - pInfo->m_nIqId = nIqId; - pInfo->m_nIqType = nIqType; - pInfo->m_dwParamsToParse = dwParamsToParse; - pInfo->m_pUserData = pUserData; - pInfo->m_dwRequestTime = GetTickCount(); - pInfo->m_dwTimeout = JABBER_DEFAULT_IQ_REQUEST_TIMEOUT; - pInfo->m_iPriority = iPriority; - pInfo->SetReceiver(szReceiver); - - InsertIq(pInfo); - - return pInfo; -} - -BOOL CJabberIqManager::HandleIq(int nIqId, HXML pNode ) -{ - if (nIqId == -1 || pNode == NULL) - return FALSE; - - const TCHAR *szType = xmlGetAttrValue( pNode, _T("type")); - if ( !szType ) - return FALSE; - - int nIqType = JABBER_IQ_TYPE_FAIL; - if (!_tcsicmp(szType, _T("result"))) - nIqType = JABBER_IQ_TYPE_RESULT; - else if (!_tcsicmp(szType, _T("error"))) - nIqType = JABBER_IQ_TYPE_ERROR; - else - return FALSE; - - Lock(); - CJabberIqInfo* pInfo = DetachInfo(nIqId); - Unlock(); - if (pInfo) - { - pInfo->m_nIqType = nIqType; - if (nIqType == JABBER_IQ_TYPE_RESULT) { - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_NODE) - pInfo->m_pChildNode = xmlGetChild( pNode , 0 ); - - if (pInfo->m_pChildNode && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_NAME)) - pInfo->m_szChildTagName = ( TCHAR* )xmlGetName( pInfo->m_pChildNode ); - if (pInfo->m_pChildNode && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_XMLNS)) - pInfo->m_szChildTagXmlns = ( TCHAR* )xmlGetAttrValue( pNode, _T("xmlns")); - } - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) - pInfo->m_szTo = ( TCHAR* )xmlGetAttrValue( pNode, _T("to")); - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM) - pInfo->m_szFrom = ( TCHAR* )xmlGetAttrValue( pNode, _T("from")); - if (pInfo->m_szFrom && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT)) - pInfo->m_hContact = ppro->HContactFromJID( pInfo->m_szFrom, 3 ); - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_ID_STR) - pInfo->m_szId = ( TCHAR* )xmlGetAttrValue( pNode, _T("id")); - - (ppro->*(pInfo->m_pHandler))(pNode, pInfo); - delete pInfo; - return TRUE; - } - return FALSE; -} - -BOOL CJabberIqManager::HandleIqPermanent( HXML pNode ) -{ - BOOL bStopHandling = FALSE; - Lock(); - CJabberIqPermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo ) { - // have to get all data here, in the loop, because there's always possibility that previous handler modified it - const TCHAR *szType = xmlGetAttrValue( pNode, _T("type")); - if ( !szType ) - break; - - CJabberIqInfo iqInfo; - - iqInfo.m_nIqType = JABBER_IQ_TYPE_FAIL; - if ( !_tcsicmp( szType, _T("get"))) - iqInfo.m_nIqType = JABBER_IQ_TYPE_GET; - else if ( !_tcsicmp( szType, _T("set"))) - iqInfo.m_nIqType = JABBER_IQ_TYPE_SET; - else - break; - - if ( pInfo->m_nIqTypes & iqInfo.m_nIqType ) - { - HXML pFirstChild = xmlGetChild( pNode , 0 ); - if ( !pFirstChild || !xmlGetName( pFirstChild )) - break; - - const TCHAR *szTagName = xmlGetName( pFirstChild ); - const TCHAR *szXmlns = xmlGetAttrValue( pFirstChild, _T("xmlns")); - - if ( (!pInfo->m_szXmlns || ( szXmlns && !_tcscmp( pInfo->m_szXmlns, szXmlns ))) && - ( !pInfo->m_szTag || !_tcscmp( pInfo->m_szTag, szTagName ))) { - // node suits handler criteria, call the handler - iqInfo.m_pChildNode = pFirstChild; - iqInfo.m_szChildTagName = ( TCHAR* )szTagName; - iqInfo.m_szChildTagXmlns = ( TCHAR* )szXmlns; - iqInfo.m_szId = ( TCHAR* )xmlGetAttrValue( pNode, _T("id")); - iqInfo.m_pUserData = pInfo->m_pUserData; - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) - iqInfo.m_szTo = ( TCHAR* )xmlGetAttrValue( pNode, _T("to")); - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM) - iqInfo.m_szFrom = ( TCHAR* )xmlGetAttrValue( pNode, _T("from")); - - if ((pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT) && (iqInfo.m_szFrom)) - iqInfo.m_hContact = ppro->HContactFromJID( iqInfo.m_szFrom, 3 ); - - ppro->Log( "Handling iq id " TCHAR_STR_PARAM ", type " TCHAR_STR_PARAM ", from " TCHAR_STR_PARAM, iqInfo.m_szId, szType, iqInfo.m_szFrom ); - if ((ppro->*(pInfo->m_pHandler))(pNode, &iqInfo)) { - bStopHandling = TRUE; - break; - } - } - } - - pInfo = pInfo->m_pNext; - } - Unlock(); - - return bStopHandling; -} diff --git a/protocols/JabberG/jabber_iq.h b/protocols/JabberG/jabber_iq.h deleted file mode 100644 index 6e145e7db0..0000000000 --- a/protocols/JabberG/jabber_iq.h +++ /dev/null @@ -1,526 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_IQ_H_ -#define _JABBER_IQ_H_ - -#include "jabber_xml.h" - -class CJabberIqInfo; - -typedef enum { - IQ_PROC_NONE, - IQ_PROC_GETAGENTS, - IQ_PROC_GETREGISTER, - IQ_PROC_SETREGISTER, - IQ_PROC_GETVCARD, - IQ_PROC_SETVCARD, - IQ_PROC_GETSEARCH, - IQ_PROC_GETSEARCHFIELDS, - IQ_PROC_BROWSEROOMS, - IQ_PROC_DISCOROOMSERVER, - IQ_PROC_DISCOAGENTS, - IQ_PROC_DISCOBOOKMARKS, - IQ_PROC_SETBOOKMARKS, - IQ_PROC_DISCOCOMMANDS, - IQ_PROC_EXECCOMMANDS, -} JABBER_IQ_PROCID; - -struct CJabberProto; -typedef void ( CJabberProto::*JABBER_IQ_PFUNC )( HXML iqNode ); -typedef void ( *IQ_USER_DATA_FREE_FUNC )( void *pUserData ); - -typedef struct { - TCHAR* xmlns; - JABBER_IQ_PFUNC func; - BOOL allowSubNs; // e.g. #info in disco#info -} JABBER_IQ_XMLNS_FUNC; - -// 2 minutes, milliseconds -#define JABBER_DEFAULT_IQ_REQUEST_TIMEOUT 120000 - -typedef void ( CJabberProto::*JABBER_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); -typedef BOOL ( CJabberProto::*JABBER_PERMANENT_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); - -#define JABBER_IQ_PARSE_CHILD_TAG_NODE (1) -#define JABBER_IQ_PARSE_CHILD_TAG_NAME ((1<<1)|JABBER_IQ_PARSE_CHILD_TAG_NODE) -#define JABBER_IQ_PARSE_CHILD_TAG_XMLNS ((1<<2)|JABBER_IQ_PARSE_CHILD_TAG_NODE) -#define JABBER_IQ_PARSE_FROM (1<<3) -#define JABBER_IQ_PARSE_HCONTACT ((1<<4)|JABBER_IQ_PARSE_FROM) -#define JABBER_IQ_PARSE_TO (1<<5) -#define JABBER_IQ_PARSE_ID_STR (1<<6) - -#define JABBER_IQ_PARSE_DEFAULT (JABBER_IQ_PARSE_CHILD_TAG_NODE|JABBER_IQ_PARSE_CHILD_TAG_NAME|JABBER_IQ_PARSE_CHILD_TAG_XMLNS) - -class CJabberIqInfo -{ -protected: - friend class CJabberIqManager; - JABBER_IQ_HANDLER m_pHandler; - CJabberIqInfo* m_pNext; - - int m_nIqId; - DWORD m_dwParamsToParse; - DWORD m_dwRequestTime; - DWORD m_dwTimeout; - TCHAR *m_szReceiver; - int m_iPriority; -public: - void *m_pUserData; -public:// parsed data - int m_nIqType; - TCHAR *m_szFrom; - TCHAR *m_szChildTagXmlns; - TCHAR *m_szChildTagName; - HXML m_pChildNode; - HANDLE m_hContact; - TCHAR *m_szTo; - TCHAR *m_szId; -public: - CJabberIqInfo() - { - ZeroMemory(this, sizeof(CJabberIqInfo)); - } - ~CJabberIqInfo() - { - if (m_szReceiver) - mir_free(m_szReceiver); - } - void SetReceiver(const TCHAR *szReceiver) - { - replaceStrT(m_szReceiver, szReceiver); - } - TCHAR* GetReceiver() - { - return m_szReceiver; - } - void SetParamsToParse(DWORD dwParamsToParse) - { - m_dwParamsToParse = dwParamsToParse; - } - void SetTimeout(DWORD dwTimeout) - { - m_dwTimeout = dwTimeout; - } - int GetIqId() - { - return m_nIqId; - } - DWORD GetRequestTime() - { - return m_dwRequestTime; - } - int GetIqType() - { - return m_nIqType; - } - void* GetUserData() - { - return m_pUserData; - } - TCHAR* GetFrom() - { - return m_szFrom; - } - TCHAR* GetTo() - { - return m_szTo; - } - TCHAR* GetIdStr() - { - return m_szId; - } - HANDLE GetHContact() - { - return m_hContact; - } - HXML GetChildNode() - { - return m_pChildNode; - } - TCHAR* GetChildNodeName() - { - return m_szChildTagName; - } - char* GetCharIqType() - { - switch (m_nIqType) - { - case JABBER_IQ_TYPE_SET: return "set"; - case JABBER_IQ_TYPE_GET: return "get"; - case JABBER_IQ_TYPE_ERROR: return "error"; - case JABBER_IQ_TYPE_RESULT: return "result"; - } - return NULL; - } -}; - -class CJabberIqPermanentInfo -{ - friend class CJabberIqManager; - - CJabberIqPermanentInfo* m_pNext; - - JABBER_PERMANENT_IQ_HANDLER m_pHandler; - DWORD m_dwParamsToParse; - int m_nIqTypes; - TCHAR* m_szXmlns; - TCHAR* m_szTag; - BOOL m_bAllowPartialNs; - void *m_pUserData; - IQ_USER_DATA_FREE_FUNC m_pUserDataFree; - int m_iPriority; -public: - CJabberIqPermanentInfo() - { - ZeroMemory(this, sizeof(CJabberIqPermanentInfo)); - } - ~CJabberIqPermanentInfo() - { - if ( m_pUserDataFree ) - m_pUserDataFree(m_pUserData); - mir_free(m_szXmlns); - mir_free(m_szTag); - } -}; - -class CJabberIqManager -{ -protected: - CJabberProto* ppro; - CRITICAL_SECTION m_cs; - DWORD m_dwLastUsedHandle; - CJabberIqInfo* m_pIqs; // list of iqs ordered by priority - HANDLE m_hExpirerThread; - BOOL m_bExpirerThreadShutdownRequest; - - CJabberIqPermanentInfo* m_pPermanentHandlers; - - CJabberIqInfo* DetachInfo(int nIqId) - { - if (!m_pIqs) - return NULL; - - CJabberIqInfo* pInfo = m_pIqs; - if (m_pIqs->m_nIqId == nIqId) - { - m_pIqs = pInfo->m_pNext; - pInfo->m_pNext = NULL; - return pInfo; - } - - while (pInfo->m_pNext) - { - if (pInfo->m_pNext->m_nIqId == nIqId) - { - CJabberIqInfo* pRetVal = pInfo->m_pNext; - pInfo->m_pNext = pInfo->m_pNext->m_pNext; - pRetVal->m_pNext = NULL; - return pRetVal; - } - pInfo = pInfo->m_pNext; - } - return NULL; - } - CJabberIqInfo* DetachInfo(void *pUserData) - { - if (!m_pIqs) - return NULL; - - CJabberIqInfo* pInfo = m_pIqs; - if (m_pIqs->m_pUserData == pUserData) - { - m_pIqs = pInfo->m_pNext; - pInfo->m_pNext = NULL; - return pInfo; - } - - while (pInfo->m_pNext) - { - if (pInfo->m_pNext->m_pUserData == pUserData) - { - CJabberIqInfo* pRetVal = pInfo->m_pNext; - pInfo->m_pNext = pInfo->m_pNext->m_pNext; - pRetVal->m_pNext = NULL; - return pRetVal; - } - pInfo = pInfo->m_pNext; - } - return NULL; - } - CJabberIqInfo* DetachExpired() - { - if (!m_pIqs) - return NULL; - - DWORD dwCurrentTime = GetTickCount(); - - CJabberIqInfo* pInfo = m_pIqs; - if (dwCurrentTime - pInfo->m_dwRequestTime > pInfo->m_dwTimeout ) - { - m_pIqs = pInfo->m_pNext; - pInfo->m_pNext = NULL; - return pInfo; - } - - while (pInfo->m_pNext) - { - if (dwCurrentTime - pInfo->m_pNext->m_dwRequestTime > pInfo->m_pNext->m_dwTimeout ) - { - CJabberIqInfo* pRetVal = pInfo->m_pNext; - pInfo->m_pNext = pInfo->m_pNext->m_pNext; - pRetVal->m_pNext = NULL; - return pRetVal; - } - pInfo = pInfo->m_pNext; - } - return NULL; - } - void ExpireInfo( CJabberIqInfo* pInfo, void *pUserData = NULL ); - BOOL InsertIq(CJabberIqInfo* pInfo) - { // inserts pInfo at a place determined by pInfo->m_iPriority - Lock(); - if (!m_pIqs) - m_pIqs = pInfo; - else - { - if (m_pIqs->m_iPriority > pInfo->m_iPriority) { - pInfo->m_pNext = m_pIqs; - m_pIqs = pInfo; - } else - { - CJabberIqInfo* pTmp = m_pIqs; - while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) - pTmp = pTmp->m_pNext; - pInfo->m_pNext = pTmp->m_pNext; - pTmp->m_pNext = pInfo; - } - } - Unlock(); - return TRUE; - } -public: - CJabberIqManager( CJabberProto* proto ) - { - InitializeCriticalSection(&m_cs); - m_dwLastUsedHandle = 0; - m_pIqs = NULL; - m_hExpirerThread = NULL; - m_pPermanentHandlers = NULL; - ppro = proto; - } - ~CJabberIqManager() - { - ExpireAll(); - Lock(); - CJabberIqPermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo ) - { - CJabberIqPermanentInfo *pTmp = pInfo->m_pNext; - delete pInfo; - pInfo = pTmp; - } - m_pPermanentHandlers = NULL; - Unlock(); - DeleteCriticalSection(&m_cs); - } - BOOL Start(); - BOOL Shutdown() - { - if ( m_bExpirerThreadShutdownRequest || !m_hExpirerThread ) - return TRUE; - - m_bExpirerThreadShutdownRequest = TRUE; - - WaitForSingleObject( m_hExpirerThread, INFINITE ); - CloseHandle( m_hExpirerThread ); - m_hExpirerThread = NULL; - - return TRUE; - } - void Lock() - { - EnterCriticalSection(&m_cs); - } - void Unlock() - { - LeaveCriticalSection(&m_cs); - } - // fucking params, maybe just return CJabberIqRequestInfo pointer ? - CJabberIqInfo* AddHandler(JABBER_IQ_HANDLER pHandler, int nIqType = JABBER_IQ_TYPE_GET, const TCHAR *szReceiver = NULL, DWORD dwParamsToParse = 0, int nIqId = -1, void *pUserData = NULL, int iPriority = JH_PRIORITY_DEFAULT); - CJabberIqPermanentInfo* AddPermanentHandler(JABBER_PERMANENT_IQ_HANDLER pHandler, int nIqTypes, DWORD dwParamsToParse, const TCHAR* szXmlns, BOOL bAllowPartialNs, const TCHAR* szTag, void *pUserData = NULL, IQ_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) - { - CJabberIqPermanentInfo* pInfo = new CJabberIqPermanentInfo(); - if (!pInfo) - return NULL; - - pInfo->m_pHandler = pHandler; - pInfo->m_nIqTypes = nIqTypes ? nIqTypes : JABBER_IQ_TYPE_ANY; - replaceStrT( pInfo->m_szXmlns, szXmlns ); - pInfo->m_bAllowPartialNs = bAllowPartialNs; - replaceStrT( pInfo->m_szTag, szTag ); - pInfo->m_dwParamsToParse = dwParamsToParse; - pInfo->m_pUserData = pUserData; - pInfo->m_pUserDataFree = pUserDataFree; - pInfo->m_iPriority = iPriority; - - Lock(); - if (!m_pPermanentHandlers) - m_pPermanentHandlers = pInfo; - else - { - if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { - pInfo->m_pNext = m_pPermanentHandlers; - m_pPermanentHandlers = pInfo; - } else - { - CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) - pTmp = pTmp->m_pNext; - pInfo->m_pNext = pTmp->m_pNext; - pTmp->m_pNext = pInfo; - } - } - Unlock(); - - return pInfo; - } - BOOL DeletePermanentHandler(CJabberIqPermanentInfo *pInfo) - { // returns TRUE when pInfo found, or FALSE otherwise - Lock(); - if (!m_pPermanentHandlers) - { - Unlock(); - return FALSE; - } - if (m_pPermanentHandlers == pInfo) // check first item - { - m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } else - { - CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext) - { - if (pTmp->m_pNext == pInfo) - { - pTmp->m_pNext = pTmp->m_pNext->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } - pTmp = pTmp->m_pNext; - } - } - Unlock(); - return FALSE; - } - BOOL DeleteHandler(CJabberIqInfo *pInfo) - { // returns TRUE when pInfo found, or FALSE otherwise - Lock(); - if (!m_pIqs) - { - Unlock(); - return FALSE; - } - if (m_pIqs == pInfo) // check first item - { - m_pIqs = m_pIqs->m_pNext; - Unlock(); - ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary - delete pInfo; - return TRUE; - } else - { - CJabberIqInfo* pTmp = m_pIqs; - while (pTmp->m_pNext) - { - if (pTmp->m_pNext == pInfo) - { - pTmp->m_pNext = pTmp->m_pNext->m_pNext; - Unlock(); - ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary - delete pInfo; - return TRUE; - } - pTmp = pTmp->m_pNext; - } - } - Unlock(); - return FALSE; - } - BOOL HandleIq(int nIqId, HXML pNode); - BOOL HandleIqPermanent(HXML pNode); - BOOL ExpireIq(int nIqId) - { - Lock(); - CJabberIqInfo* pInfo = DetachInfo(nIqId); - Unlock(); - if (pInfo) - { - ExpireInfo(pInfo); - delete pInfo; - return TRUE; - } - return FALSE; - } - void ExpirerThread( void ); - BOOL ExpireByUserData(void *pUserData) - { - BOOL bRetVal = FALSE; - while (1) - { - Lock(); - CJabberIqInfo* pInfo = DetachInfo(pUserData); - Unlock(); - if (!pInfo) - break; - ExpireInfo(pInfo, NULL); - delete pInfo; - bRetVal = TRUE; - } - return bRetVal; - } - BOOL ExpireAll(void *pUserData = NULL) - { - while (1) - { - Lock(); - CJabberIqInfo* pInfo = m_pIqs; - if (pInfo) - m_pIqs = m_pIqs->m_pNext; - Unlock(); - if (!pInfo) - break; - pInfo->m_pNext = NULL; - ExpireInfo(pInfo, pUserData); - delete pInfo; - } - return TRUE; - } - BOOL FillPermanentHandlers(); -}; - -#endif diff --git a/protocols/JabberG/jabber_iq_handlers.cpp b/protocols/JabberG/jabber_iq_handlers.cpp deleted file mode 100644 index 7f3385ff6e..0000000000 --- a/protocols/JabberG/jabber_iq_handlers.cpp +++ /dev/null @@ -1,775 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#include <io.h> -#include "version.h" -#include "jabber_iq.h" -#include "jabber_rc.h" - -extern int bSecureIM; - -#ifndef VER_SUITE_WH_SERVER - #define VER_SUITE_WH_SERVER 0x00008000 -#endif - -#ifndef PRODUCT_ULTIMATE - #define PRODUCT_UNDEFINED 0x00000000 - #define PRODUCT_ULTIMATE 0x00000001 - #define PRODUCT_HOME_BASIC 0x00000002 - #define PRODUCT_HOME_PREMIUM 0x00000003 - #define PRODUCT_ENTERPRISE 0x00000004 - #define PRODUCT_HOME_BASIC_N 0x00000005 - #define PRODUCT_BUSINESS 0x00000006 - #define PRODUCT_STANDARD_SERVER 0x00000007 - #define PRODUCT_DATACENTER_SERVER 0x00000008 - #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009 - #define PRODUCT_ENTERPRISE_SERVER 0x0000000A - #define PRODUCT_STARTER 0x0000000B - #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C - #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D - #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E - #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F - #define PRODUCT_BUSINESS_N 0x00000010 - #define PRODUCT_WEB_SERVER 0x00000011 - #define PRODUCT_CLUSTER_SERVER 0x00000012 - #define PRODUCT_HOME_SERVER 0x00000013 - #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014 - #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015 - #define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016 - #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017 - #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018 - #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x00000019 - #define PRODUCT_UNLICENSED 0xABCDABCD -#endif - -typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); -typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); - -#define StringCchCopy(x,y,z) lstrcpyn((x),(z),(y)) -#define StringCchCat(x,y,z) lstrcat((x),(z)) -#define StringCchPrintf mir_sntprintf - -// slightly modified sample from MSDN -BOOL GetOSDisplayString(LPTSTR pszOS, int BUFSIZE) -{ - OSVERSIONINFOEX osvi; - SYSTEM_INFO si; - PGNSI pGNSI; - PGPI pGPI; - - DWORD dwType; - - ZeroMemory(&si, sizeof(SYSTEM_INFO)); - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - BOOL bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi); - if ( !bOsVersionInfoEx ) - { - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (!GetVersionEx((OSVERSIONINFO*)&osvi)) - return FALSE; - } - - // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. - HMODULE hKernel = GetModuleHandle(TEXT("kernel32.dll")); - pGNSI = (PGNSI) GetProcAddress(hKernel,"GetNativeSystemInfo"); - if(NULL != pGNSI) - pGNSI(&si); - else GetSystemInfo(&si); - - //Some code from Crash Dumper Plugin :-) - if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion > 4 ) - { - StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft ")); - - // Test for the specific product. - if (osvi.dwMajorVersion == 6) - { - switch (osvi.dwMinorVersion) - { - case 0: - if (osvi.wProductType == VER_NT_WORKSTATION) - StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista ")); - else - StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 ")); - break; - - case 1: - if (osvi.wProductType == VER_NT_WORKSTATION) - StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 ")); - else - StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 ")); - break; - - default: - if (osvi.wProductType == VER_NT_WORKSTATION) - StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8 ")); - else - StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 ")); - break; - } - - pGPI = (PGPI) GetProcAddress(hKernel, "GetProductInfo"); - if(pGPI != NULL) pGPI( 6, 0, 0, 0, &dwType); - - switch( dwType ) - { - case PRODUCT_ULTIMATE: - StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" )); - break; - case PRODUCT_HOME_PREMIUM: - StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" )); - break; - case PRODUCT_HOME_BASIC: - StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" )); - break; - case PRODUCT_ENTERPRISE: - StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); - break; - case PRODUCT_BUSINESS: - StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" )); - break; - case PRODUCT_STARTER: - StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" )); - break; - case PRODUCT_CLUSTER_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" )); - break; - case PRODUCT_DATACENTER_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" )); - break; - case PRODUCT_DATACENTER_SERVER_CORE: - StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" )); - break; - case PRODUCT_ENTERPRISE_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); - break; - case PRODUCT_ENTERPRISE_SERVER_CORE: - StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" )); - break; - case PRODUCT_ENTERPRISE_SERVER_IA64: - StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" )); - break; - case PRODUCT_SMALLBUSINESS_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" )); - break; - case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: - StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" )); - break; - case PRODUCT_STANDARD_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" )); - break; - case PRODUCT_STANDARD_SERVER_CORE: - StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" )); - break; - case PRODUCT_WEB_SERVER: - StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" )); - break; - } - if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) - StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" )); - else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) - StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit")); - } - - if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) - { - if ( GetSystemMetrics(SM_SERVERR2)) - StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, ")); - else if ( osvi.wSuiteMask==VER_SUITE_STORAGE_SERVER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003")); - else if ( osvi.wSuiteMask==VER_SUITE_WH_SERVER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server")); - else if ( osvi.wProductType == VER_NT_WORKSTATION && - si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) - { - StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition")); - } - else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, ")); - - // Test for the server type. - if ( osvi.wProductType != VER_NT_WORKSTATION ) - { - if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) - { - if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" )); - else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" )); - } - - else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) - { - if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" )); - else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" )); - else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" )); - } - - else - { - if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" )); - else if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" )); - else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" )); - else if ( osvi.wSuiteMask & VER_SUITE_BLADE ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" )); - else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" )); - } - } - } - - if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) - { - StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP ")); - if ( osvi.wSuiteMask & VER_SUITE_PERSONAL ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" )); - else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); - } - - if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) - { - StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 ")); - - if ( osvi.wProductType == VER_NT_WORKSTATION ) - { - StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); - } - else - { - if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" )); - else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) - StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" )); - else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" )); - } - } - - // Include service pack (if any) and build number. - - if ( _tcslen(osvi.szCSDVersion) > 0 ) - { - StringCchCat(pszOS, BUFSIZE, TEXT(" ")); - StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion); - } - - TCHAR buf[80]; - - StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber); - StringCchCat(pszOS, BUFSIZE, buf); - - return TRUE; - } - else - { - return FALSE; - } -} - - -BOOL CJabberProto::OnIqRequestVersion( HXML, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->GetFrom()) - return TRUE; - - if ( !m_options.AllowVersionRequests ) - return FALSE; - - XmlNodeIq iq( _T("result"), pInfo ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_VERSION)); - query << XCHILD( _T("name"), _T("Miranda NG Jabber")); - query << XCHILD( _T("version"), szCoreVersion); - - if ( m_options.ShowOSVersion ) - { - TCHAR os[256] = {0}; - if (!GetOSDisplayString(os, SIZEOF(os))) - lstrcpyn(os, _T("Microsoft Windows"), SIZEOF(os)); - query << XCHILD( _T("os"), os ); - } - - m_ThreadInfo->send( iq ); - return TRUE; -} - -// last activity (XEP-0012) support -BOOL CJabberProto::OnIqRequestLastActivity( HXML, CJabberIqInfo *pInfo ) -{ - m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)) - << XATTRI( _T("seconds"), m_tmJabberIdleStartTime ? time( 0 ) - m_tmJabberIdleStartTime : 0 )); - return TRUE; -} - -// XEP-0199: XMPP Ping support -BOOL CJabberProto::OnIqRequestPing( HXML, CJabberIqInfo *pInfo ) -{ - m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo ) << XATTR( _T("from"), m_ThreadInfo->fullJID )); - return TRUE; -} - -// Returns the current GMT offset in seconds -int GetGMTOffset(void) -{ - TIME_ZONE_INFORMATION tzinfo; - int nOffset = 0; - - DWORD dwResult= GetTimeZoneInformation(&tzinfo); - - switch(dwResult) { - case TIME_ZONE_ID_STANDARD: - nOffset = tzinfo.Bias + tzinfo.StandardBias; - break; - case TIME_ZONE_ID_DAYLIGHT: - nOffset = tzinfo.Bias + tzinfo.DaylightBias; - break; - case TIME_ZONE_ID_UNKNOWN: - nOffset = tzinfo.Bias; - break; - case TIME_ZONE_ID_INVALID: - default: - nOffset = 0; - break; - } - - return -nOffset; -} - -// entity time (XEP-0202) support -BOOL CJabberProto::OnIqRequestTime( HXML, CJabberIqInfo *pInfo ) -{ - TCHAR stime[100]; - TCHAR szTZ[10]; - - tmi.printDateTime(UTC_TIME_HANDLE, _T("I"), stime, SIZEOF(stime), 0); - - int nGmtOffset = GetGMTOffset(); - mir_sntprintf(szTZ, SIZEOF(szTZ), _T("%+03d:%02d"), nGmtOffset / 60, nGmtOffset % 60 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML timeNode = iq << XCHILDNS( _T("time"), _T(JABBER_FEAT_ENTITY_TIME)); - timeNode << XCHILD( _T("utc"), stime); timeNode << XCHILD( _T("tzo"), szTZ ); - LPCTSTR szTZName = tmi.getTzName( NULL ); - if ( szTZName ) - timeNode << XCHILD( _T("tz"), szTZName ); - m_ThreadInfo->send( iq ); - return TRUE; -} - -BOOL CJabberProto::OnIqProcessIqOldTime( HXML, CJabberIqInfo *pInfo ) -{ - struct tm *gmt; - time_t ltime; - TCHAR stime[ 100 ], *dtime; - - _tzset(); - time( <ime ); - gmt = gmtime( <ime ); - mir_sntprintf( stime, SIZEOF(stime), _T("%.4i%.2i%.2iT%.2i:%.2i:%.2i"), - gmt->tm_year + 1900, gmt->tm_mon + 1, - gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec ); - dtime = _tctime( <ime ); - dtime[ 24 ] = 0; - - XmlNodeIq iq( _T("result"), pInfo ); - HXML queryNode = iq << XQUERY( _T(JABBER_FEAT_ENTITY_TIME_OLD)); - queryNode << XCHILD( _T("utc"), stime ); - LPCTSTR szTZName = tmi.getTzName( NULL ); - if ( szTZName ) - queryNode << XCHILD( _T("tz"), szTZName ); - queryNode << XCHILD( _T("display"), dtime ); - m_ThreadInfo->send( iq ); - return TRUE; -} - -BOOL CJabberProto::OnIqRequestAvatar( HXML, CJabberIqInfo *pInfo ) -{ - if ( !m_options.EnableAvatars ) - return TRUE; - - int pictureType = m_options.AvatarType; - if ( pictureType == PA_FORMAT_UNKNOWN ) - return TRUE; - - TCHAR* szMimeType; - switch( pictureType ) { - case PA_FORMAT_JPEG: szMimeType = _T("image/jpeg"); break; - case PA_FORMAT_GIF: szMimeType = _T("image/gif"); break; - case PA_FORMAT_PNG: szMimeType = _T("image/png"); break; - case PA_FORMAT_BMP: szMimeType = _T("image/bmp"); break; - default: return TRUE; - } - - TCHAR szFileName[ MAX_PATH ]; - GetAvatarFileName( NULL, szFileName, SIZEOF(szFileName)); - - FILE* in = _tfopen( szFileName, _T("rb")); - if ( in == NULL ) - return TRUE; - - long bytes = _filelength( _fileno( in )); - char* buffer = ( char* )mir_alloc( bytes*4/3 + bytes + 1000 ); - if ( buffer == NULL ) { - fclose( in ); - return TRUE; - } - - fread( buffer, bytes, 1, in ); - fclose( in ); - - char* str = JabberBase64Encode( buffer, bytes ); - m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo ) << XQUERY( _T(JABBER_FEAT_AVATAR)) << XCHILD( _T("query"), _A2T(str)) << XATTR( _T("mimetype"), szMimeType )); - mir_free( str ); - mir_free( buffer ); - return TRUE; -} - -BOOL CJabberProto::OnSiRequest( HXML node, CJabberIqInfo *pInfo ) -{ - const TCHAR* szProfile = xmlGetAttrValue( pInfo->GetChildNode(), _T("profile")); - - if ( szProfile && !_tcscmp( szProfile, _T(JABBER_FEAT_SI_FT))) - FtHandleSiRequest( node ); - else { - XmlNodeIq iq( _T("error"), pInfo ); - HXML error = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); - error << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - error << XCHILD( _T("bad-profile")); - m_ThreadInfo->send( iq ); - } - return TRUE; -} - -BOOL CJabberProto::OnRosterPushRequest( HXML, CJabberIqInfo *pInfo ) -{ - HXML queryNode = pInfo->GetChildNode(); - - // RFC 3921 #7.2 Business Rules - if ( pInfo->GetFrom()) { - TCHAR* szFrom = JabberPrepareJid( pInfo->GetFrom()); - if ( !szFrom ) - return TRUE; - - TCHAR* szTo = JabberPrepareJid( m_ThreadInfo->fullJID ); - if ( !szTo ) { - mir_free( szFrom ); - return TRUE; - } - - TCHAR* pDelimiter = _tcschr( szFrom, _T('/')); - if ( pDelimiter ) *pDelimiter = _T('\0'); - - pDelimiter = _tcschr( szTo, _T('/')); - if ( pDelimiter ) *pDelimiter = _T('\0'); - - BOOL bRetVal = _tcscmp( szFrom, szTo ) == 0; - - mir_free( szFrom ); - mir_free( szTo ); - - // invalid JID - if ( !bRetVal ) { - Log( "<iq/> attempt to hack via roster push from " TCHAR_STR_PARAM, pInfo->GetFrom()); - return TRUE; - } - } - - JABBER_LIST_ITEM *item; - HANDLE hContact = NULL; - const TCHAR *jid, *str, *name; - TCHAR* nick; - - Log( "<iq/> Got roster push, query has %d children", xmlGetChildCount( queryNode )); - for ( int i=0; ; i++ ) { - HXML itemNode = xmlGetChild( queryNode ,i); - if ( !itemNode ) - break; - - if ( _tcscmp( xmlGetName( itemNode ), _T("item")) != 0 ) - continue; - if (( jid = xmlGetAttrValue( itemNode, _T("jid"))) == NULL ) - continue; - if (( str = xmlGetAttrValue( itemNode, _T("subscription"))) == NULL ) - continue; - - // we will not add new account when subscription=remove - if ( !_tcscmp( str, _T("to")) || !_tcscmp( str, _T("both")) || !_tcscmp( str, _T("from")) || !_tcscmp( str, _T("none"))) { - if (( name = xmlGetAttrValue( itemNode, _T("name"))) != NULL ) - nick = mir_tstrdup( name ); - else - nick = JabberNickFromJID( jid ); - - if ( nick != NULL ) { - if (( item=ListAdd( LIST_ROSTER, jid )) != NULL ) { - replaceStrT( item->nick, nick ); - - HXML groupNode = xmlGetChild( itemNode , "group" ); - replaceStrT( item->group, ( groupNode ) ? xmlGetText( groupNode ) : NULL ); - - if (( hContact=HContactFromJID( jid, 0 )) == NULL ) { - // Received roster has a new JID. - // Add the jid ( with empty resource ) to Miranda contact list. - hContact = DBCreateContact( jid, nick, FALSE, FALSE ); - } - else JSetStringT( hContact, "jid", jid ); - - if ( name != NULL ) { - DBVARIANT dbnick; - if ( !JGetStringT( hContact, "Nick", &dbnick )) { - if ( _tcscmp( nick, dbnick.ptszVal ) != 0 ) - DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); - else - DBDeleteContactSetting( hContact, "CList", "MyHandle" ); - - JFreeVariant( &dbnick ); - } - else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); - } - else DBDeleteContactSetting( hContact, "CList", "MyHandle" ); - - if (!m_options.IgnoreRosterGroups) - { - if ( item->group != NULL ) { - JabberContactListCreateGroup( item->group ); - DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); - } - else - DBDeleteContactSetting( hContact, "CList", "Group" ); - } - } - mir_free( nick ); - } } - - if (( item=ListGetItemPtr( LIST_ROSTER, jid )) != NULL ) { - if ( !_tcscmp( str, _T("both"))) item->subscription = SUB_BOTH; - else if ( !_tcscmp( str, _T("to"))) item->subscription = SUB_TO; - else if ( !_tcscmp( str, _T("from"))) item->subscription = SUB_FROM; - else item->subscription = SUB_NONE; - Log( "Roster push for jid=" TCHAR_STR_PARAM ", set subscription to " TCHAR_STR_PARAM, jid, str ); - // subscription = remove is to remove from roster list - // but we will just set the contact to offline and not actually - // remove, so that history will be retained. - if ( !_tcscmp( str, _T("remove"))) { - if (( hContact=HContactFromJID( jid )) != NULL ) { - SetContactOfflineStatus( hContact ); - ListRemove( LIST_ROSTER, jid ); - } } - else if ( JGetByte( hContact, "ChatRoom", 0 )) - DBDeleteContactSetting( hContact, "CList", "Hidden" ); - else - UpdateSubscriptionInfo( hContact, item ); - } } - - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - RebuildInfoFrame(); - return TRUE; -} - -BOOL CJabberProto::OnIqRequestOOB( HXML, CJabberIqInfo *pInfo ) -{ - if ( !pInfo->GetFrom() || !pInfo->GetHContact()) - return TRUE; - - HXML n = xmlGetChild( pInfo->GetChildNode(), "url" ); - if ( !n || !xmlGetText( n )) - return TRUE; - - if ( m_options.BsOnlyIBB ) { - // reject - XmlNodeIq iq( _T("error"), pInfo ); - HXML e = xmlAddChild( iq, _T("error"), _T("File transfer refused")); xmlAddAttr( e, _T("code"), 406 ); - m_ThreadInfo->send( iq ); - return TRUE; - } - - TCHAR text[ 1024 ]; - TCHAR *str, *p, *q; - - str = ( TCHAR* )xmlGetText( n ); // URL of the file to get - filetransfer* ft = new filetransfer( this ); - ft->std.totalFiles = 1; - ft->jid = mir_tstrdup( pInfo->GetFrom()); - ft->std.hContact = pInfo->GetHContact(); - ft->type = FT_OOB; - ft->httpHostName = NULL; - ft->httpPort = 80; - ft->httpPath = NULL; - - // Parse the URL - if ( !_tcsnicmp( str, _T("http://"), 7 )) { - p = str + 7; - if (( q = _tcschr( p, '/' )) != NULL ) { - if ( q-p < SIZEOF( text )) { - _tcsncpy( text, p, q-p ); - text[q-p] = '\0'; - if (( p = _tcschr( text, ':' )) != NULL ) { - ft->httpPort = ( WORD )_ttoi( p+1 ); - *p = '\0'; - } - ft->httpHostName = mir_t2a( text ); - } } } - - if ( pInfo->GetIdStr()) - ft->iqId = mir_tstrdup( pInfo->GetIdStr()); - - if ( ft->httpHostName && ft->httpPath ) { - TCHAR* desc = NULL; - - Log( "Host=%s Port=%d Path=%s", ft->httpHostName, ft->httpPort, ft->httpPath ); - if (( n = xmlGetChild( pInfo->GetChildNode(), "desc" )) != NULL ) - desc = ( TCHAR* )xmlGetText( n ); - - TCHAR* str2; - Log( "description = %s", desc ); - if (( str2 = _tcsrchr( ft->httpPath, '/' )) != NULL ) - str2++; - else - str2 = ft->httpPath; - str2 = mir_tstrdup( str2 ); - JabberHttpUrlDecode( str2 ); - - PROTORECVFILET pre; - pre.flags = PREF_TCHAR; - pre.timestamp = time( NULL ); - pre.tszDescription = desc; - pre.ptszFiles = &str2; - pre.fileCount = 1; - pre.lParam = ( LPARAM )ft; - - CCSDATA ccs = { ft->std.hContact, PSR_FILE, 0, ( LPARAM )&pre }; - CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); - mir_free( str2 ); - } - else { - // reject - XmlNodeIq iq( _T("error"), pInfo ); - HXML e = xmlAddChild( iq, _T("error"), _T("File transfer refused")); xmlAddAttr( e, _T("code"), 406 ); - m_ThreadInfo->send( iq ); - delete ft; - } - return TRUE; -} - -BOOL CJabberProto::OnHandleDiscoInfoRequest( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->GetChildNode()) - return TRUE; - - const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); - // caps hack - if ( m_clientCapsManager.HandleInfoRequest( iqNode, pInfo, szNode )) - return TRUE; - - // ad-hoc hack: - if ( szNode && m_adhocManager.HandleInfoRequest( iqNode, pInfo, szNode )) - return TRUE; - - // another request, send empty result - m_ThreadInfo->send( - XmlNodeIq( _T("error"), pInfo ) - << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - return TRUE; -} - -BOOL CJabberProto::OnHandleDiscoItemsRequest( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->GetChildNode()) - return TRUE; - - // ad-hoc commands check: - const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); - if ( szNode && m_adhocManager.HandleItemsRequest( iqNode, pInfo, szNode )) - return TRUE; - - // another request, send empty result - XmlNodeIq iq( _T("result"), pInfo ); - HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); - if ( szNode ) - xmlAddAttr( resultQuery, _T("node"), szNode ); - - if ( !szNode && m_options.EnableRemoteControl ) - resultQuery << XCHILD( _T("item")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) - << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("name"), _T("Ad-hoc commands")); - - m_ThreadInfo->send( iq ); - return TRUE; -} - -BOOL CJabberProto::AddClistHttpAuthEvent( CJabberHttpAuthParams *pParams ) -{ - CLISTEVENT cle = {0}; - char szService[256]; - mir_snprintf( szService, sizeof(szService),"%s%s", m_szModuleName, JS_HTTP_AUTH ); - cle.cbSize = sizeof(CLISTEVENT); - cle.hIcon = (HICON) LoadIconEx("openid"); - cle.flags = CLEF_PROTOCOLGLOBAL | CLEF_TCHAR; - cle.hDbEvent = (HANDLE)("test"); - cle.lParam = (LPARAM) pParams; - cle.pszService = szService; - cle.ptszTooltip = TranslateT("Http authentication request received"); - CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); - - return TRUE; -} - -BOOL CJabberProto::OnIqHttpAuth( HXML node, CJabberIqInfo* pInfo ) -{ - if ( !m_options.AcceptHttpAuth ) - return TRUE; - - if ( !node || !pInfo->GetChildNode() || !pInfo->GetFrom() || !pInfo->GetIdStr()) - return TRUE; - - HXML pConfirm = xmlGetChild( node , "confirm" ); - if ( !pConfirm ) - return TRUE; - - const TCHAR *szId = xmlGetAttrValue( pConfirm, _T("id")); - const TCHAR *szMethod = xmlGetAttrValue( pConfirm, _T("method")); - const TCHAR *szUrl = xmlGetAttrValue( pConfirm, _T("url")); - - if ( !szId || !szMethod || !szUrl ) - return TRUE; - - CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)mir_alloc( sizeof( CJabberHttpAuthParams )); - if ( !pParams ) - return TRUE; - ZeroMemory( pParams, sizeof( CJabberHttpAuthParams )); - pParams->m_nType = CJabberHttpAuthParams::IQ; - pParams->m_szFrom = mir_tstrdup( pInfo->GetFrom()); - pParams->m_szId = mir_tstrdup( szId ); - pParams->m_szMethod = mir_tstrdup( szMethod ); - pParams->m_szUrl = mir_tstrdup( szUrl ); - - AddClistHttpAuthEvent( pParams ); - - return TRUE; -} diff --git a/protocols/JabberG/jabber_iqid.cpp b/protocols/JabberG/jabber_iqid.cpp deleted file mode 100644 index 7679450d59..0000000000 --- a/protocols/JabberG/jabber_iqid.cpp +++ /dev/null @@ -1,1742 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "jabber_privacy.h" - -#include "m_genmenu.h" -#include "m_clistint.h" - -void CJabberProto::OnIqResultServerDiscoInfo( HXML iqNode ) -{ - if ( !iqNode ) - return; - - const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); - int i; - - if ( !_tcscmp( type, _T("result"))) { - HXML query = xmlGetChildByTag( iqNode, "query", "xmlns", _T(JABBER_FEAT_DISCO_INFO)); - if ( !query ) - return; - - HXML identity; - for ( i = 1; ( identity = xmlGetNthChild( query, _T("identity"), i )) != NULL; i++ ) { - const TCHAR *identityCategory = xmlGetAttrValue( identity, _T("category")); - const TCHAR *identityType = xmlGetAttrValue( identity, _T("type")); - const TCHAR *identityName = xmlGetAttrValue( identity, _T("name")); - if ( identityCategory && identityType && !_tcscmp( identityCategory, _T("pubsub")) && !_tcscmp( identityType, _T("pep"))) { - m_bPepSupported = TRUE; - - EnableMenuItems( TRUE ); - RebuildInfoFrame(); - } - else if ( identityCategory && identityType && identityName && - !_tcscmp( identityCategory, _T("server")) && - !_tcscmp( identityType, _T("im")) && - !_tcscmp( identityName, _T("Google Talk"))) { - m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PING; - m_bGoogleTalk = true; - - // Google Shared Status - m_ThreadInfo->send( - XmlNodeIq(m_iqManager.AddHandler(&CJabberProto::OnIqResultGoogleSharedStatus, JABBER_IQ_TYPE_GET)) - << XQUERY(_T(JABBER_FEAT_GTALK_SHARED_STATUS)) << XATTR(_T("version"), _T("2"))); - } - } - if ( m_ThreadInfo ) { - HXML feature; - for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { - const TCHAR *featureName = xmlGetAttrValue( feature, _T("var")); - if ( featureName ) { - for ( int j = 0; g_JabberFeatCapPairs[j].szFeature; j++ ) { - if ( !_tcscmp( g_JabberFeatCapPairs[j].szFeature, featureName )) { - m_ThreadInfo->jabberServerCaps |= g_JabberFeatCapPairs[j].jcbCap; - break; - } } } } } - - OnProcessLoginRq( m_ThreadInfo, JABBER_LOGIN_SERVERINFO); -} } - -void CJabberProto::OnIqResultNestedRosterGroups( HXML iqNode, CJabberIqInfo* pInfo ) -{ - const TCHAR *szGroupDelimeter = NULL; - BOOL bPrivateStorageSupport = FALSE; - - if ( iqNode && pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - bPrivateStorageSupport = TRUE; - szGroupDelimeter = XPathFmt( iqNode, _T("query[@xmlns='%s']/roster[@xmlns='%s']"), _T(JABBER_FEAT_PRIVATE_STORAGE), _T( JABBER_FEAT_NESTED_ROSTER_GROUPS )); - if ( szGroupDelimeter && !szGroupDelimeter[0] ) - szGroupDelimeter = NULL; // "" as roster delimeter is not supported :) - } - - // global fuckup - if ( !m_ThreadInfo ) - return; - - // is our default delimiter? - if (( !szGroupDelimeter && bPrivateStorageSupport ) || ( szGroupDelimeter && _tcscmp( szGroupDelimeter, _T("\\")))) - m_ThreadInfo->send( - XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) - << XCHILD( _T("roster"), _T("\\")) << XATTR( _T("xmlns"), _T(JABBER_FEAT_NESTED_ROSTER_GROUPS))); - - // roster request - TCHAR *szUserData = mir_tstrdup( szGroupDelimeter ? szGroupDelimeter : _T("\\")); - m_ThreadInfo->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultGetRoster, JABBER_IQ_TYPE_GET, NULL, 0, -1, (void *)szUserData )) - << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER))); -} - -void CJabberProto::OnIqResultNotes( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( iqNode && pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { - HXML hXmlData = XPathFmt( iqNode, _T("query[@xmlns='%s']/storage[@xmlns='%s']"), - _T(JABBER_FEAT_PRIVATE_STORAGE), _T(JABBER_FEAT_MIRANDA_NOTES)); - if (hXmlData) m_notes.LoadXml(hXmlData); - } -} - -void CJabberProto::OnProcessLoginRq( ThreadData* info, DWORD rq ) -{ - if ( info == NULL ) - return; - - info->dwLoginRqs |= rq; - - if ((info->dwLoginRqs & JABBER_LOGIN_ROSTER) && (info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS) && - (info->dwLoginRqs & JABBER_LOGIN_SERVERINFO) && !(info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS_AJ)) - { - if ( jabberChatDllPresent && m_options.AutoJoinBookmarks) { - LIST<JABBER_LIST_ITEM> ll( 10 ); - LISTFOREACH(i, this, LIST_BOOKMARK) - { - JABBER_LIST_ITEM* item = ListGetItemPtrFromIndex( i ); - if ( item != NULL && !lstrcmp( item->type, _T("conference")) && item->bAutoJoin ) - ll.insert( item ); - } - - for ( int j=0; j < ll.getCount(); j++ ) { - JABBER_LIST_ITEM* item = ll[j]; - - TCHAR room[256], *server, *p; - TCHAR text[128]; - _tcsncpy( text, item->jid, SIZEOF( text )); - _tcsncpy( room, text, SIZEOF( room )); - p = _tcstok( room, _T( "@" )); - server = _tcstok( NULL, _T( "@" )); - if ( item->nick && item->nick[0] != 0 ) - GroupchatJoinRoom( server, p, item->nick, item->password, true ); - else { - TCHAR* nick = JabberNickFromJID( m_szJabberJID ); - GroupchatJoinRoom( server, p, nick, item->password, true ); - mir_free( nick ); - } } - - ll.destroy(); - } - - OnProcessLoginRq( info, JABBER_LOGIN_BOOKMARKS_AJ ); -} } - -void CJabberProto::OnLoggedIn() -{ - m_bJabberOnline = TRUE; - m_tmJabberLoggedInTime = time(0); - - m_ThreadInfo->dwLoginRqs = 0; - - // XEP-0083 support - { - CJabberIqInfo* pIqInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultNestedRosterGroups, JABBER_IQ_TYPE_GET ); - // ugly hack to prevent hangup during login process - pIqInfo->SetTimeout( 30000 ); - m_ThreadInfo->send( - XmlNodeIq( pIqInfo ) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) - << XCHILDNS( _T("roster"), _T(JABBER_FEAT_NESTED_ROSTER_GROUPS))); - } - - // Server-side notes - { - m_ThreadInfo->send( - XmlNodeIq(m_iqManager.AddHandler(&CJabberProto::OnIqResultNotes, JABBER_IQ_TYPE_GET)) - << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) - << XCHILDNS( _T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES))); - } - - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_DISCOBOOKMARKS, &CJabberProto::OnIqResultDiscoBookmarks); - m_ThreadInfo->send( - XmlNodeIq( _T("get"), iqId) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) - << XCHILDNS( _T("storage"), _T("storage:bookmarks"))); - - m_bPepSupported = FALSE; - m_ThreadInfo->jabberServerCaps = JABBER_RESOURCE_CAPS_NONE; - iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultServerDiscoInfo ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, _A2T(m_ThreadInfo->server)) << XQUERY( _T(JABBER_FEAT_DISCO_INFO))); - - QueryPrivacyLists( m_ThreadInfo ); - - char szServerName[ sizeof(m_ThreadInfo->server) ]; - if ( JGetStaticString( "LastLoggedServer", NULL, szServerName, sizeof(szServerName))) - SendGetVcard( m_szJabberJID ); - else if ( strcmp( m_ThreadInfo->server, szServerName )) - SendGetVcard( m_szJabberJID ); - JSetString( NULL, "LastLoggedServer", m_ThreadInfo->server ); - - m_pepServices.ResetPublishAll(); -} - -void CJabberProto::OnIqResultGetAuth( HXML iqNode ) -{ - // RECVED: result of the request for authentication method - // ACTION: send account authentication information to log in - Log( "<iq/> iqIdGetAuth" ); - - HXML queryNode; - const TCHAR* type; - if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; - - if ( !lstrcmp( type, _T("result"))) { - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultSetAuth ); - - XmlNodeIq iq( _T("set"), iqId ); - HXML query = iq << XQUERY( _T("jabber:iq:auth")); - query << XCHILD( _T("username"), m_ThreadInfo->username ); - if ( xmlGetChild( queryNode, "digest" ) != NULL && m_szStreamId ) { - char* str = mir_utf8encodeT( m_ThreadInfo->password ); - char text[200]; - mir_snprintf( text, SIZEOF(text), "%s%s", m_szStreamId, str ); - mir_free( str ); - if (( str=JabberSha1( text )) != NULL ) { - query << XCHILD( _T("digest"), _A2T(str)); - mir_free( str ); - } - } - else if ( xmlGetChild( queryNode, "password" ) != NULL ) - query << XCHILD( _T("password"), m_ThreadInfo->password ); - else { - Log( "No known authentication mechanism accepted by the server." ); - - m_ThreadInfo->send( "</stream:stream>" ); - return; - } - - if ( xmlGetChild( queryNode , "resource" ) != NULL ) - query << XCHILD( _T("resource"), m_ThreadInfo->resource ); - - m_ThreadInfo->send( iq ); - } - else if ( !lstrcmp( type, _T("error"))) { - m_ThreadInfo->send( "</stream:stream>" ); - - TCHAR text[128]; - mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), m_ThreadInfo->username ); - MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); - m_ThreadInfo = NULL; // To disallow auto reconnect -} } - -void CJabberProto::OnIqResultSetAuth( HXML iqNode ) -{ - const TCHAR* type; - - // RECVED: authentication result - // ACTION: if successfully logged in, continue by requesting roster list and set my initial status - Log( "<iq/> iqIdSetAuth" ); - if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - - if ( !lstrcmp( type, _T("result"))) { - DBVARIANT dbv; - if ( JGetStringT( NULL, "Nick", &dbv )) - JSetStringT( NULL, "Nick", m_ThreadInfo->username ); - else - JFreeVariant( &dbv ); - - OnLoggedIn(); - } - // What to do if password error? etc... - else if ( !lstrcmp( type, _T("error"))) { - TCHAR text[128]; - - m_ThreadInfo->send( "</stream:stream>" ); - mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), m_ThreadInfo->username ); - MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); - m_ThreadInfo = NULL; // To disallow auto reconnect -} } - -void CJabberProto::OnIqResultBind( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( !m_ThreadInfo || !iqNode ) - return; - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) { - LPCTSTR szJid = XPathT( iqNode, "bind[@xmlns='urn:ietf:params:xml:ns:xmpp-bind']/jid" ); - if ( szJid ) { - if ( !_tcsncmp( m_ThreadInfo->fullJID, szJid, SIZEOF( m_ThreadInfo->fullJID ))) - Log( "Result Bind: " TCHAR_STR_PARAM " confirmed ", m_ThreadInfo->fullJID ); - else { - Log( "Result Bind: " TCHAR_STR_PARAM " changed to " TCHAR_STR_PARAM, m_ThreadInfo->fullJID, szJid); - _tcsncpy( m_ThreadInfo->fullJID, szJid, SIZEOF( m_ThreadInfo->fullJID )); - } - } - if ( m_ThreadInfo->bIsSessionAvailable ) - m_ThreadInfo->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultSession, JABBER_IQ_TYPE_SET )) - << XCHILDNS( _T("session"), _T("urn:ietf:params:xml:ns:xmpp-session" ))); - else - OnLoggedIn(); - } - else { - //rfc3920 page 39 - m_ThreadInfo->send( "</stream:stream>" ); - m_ThreadInfo = NULL; // To disallow auto reconnect - } -} - -void CJabberProto::OnIqResultSession( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) - OnLoggedIn(); -} - -void CJabberProto::GroupchatJoinByHContact( HANDLE hContact, bool autojoin ) -{ - TCHAR* roomjid = JGetStringT( hContact, "ChatRoomID" ); - if ( !roomjid ) return; - - TCHAR* room = roomjid; - TCHAR* server = _tcschr( roomjid, '@' ); - if ( !server ) { - mir_free( roomjid ); - return; - } - server[0] = 0; server++; - - TCHAR *nick = JGetStringT( hContact, "MyNick" ); - if ( !nick ) { - nick = JabberNickFromJID( m_szJabberJID ); - if ( !nick ) { - mir_free( roomjid ); - return; - } - } - - TCHAR *password = JGetStringCrypt( hContact, "LoginPassword" ); - - GroupchatJoinRoom( server, room, nick, password, autojoin ); - - mir_free( password ); - mir_free( nick ); - mir_free( roomjid ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberIqResultGetRoster - populates LIST_ROSTER and creates contact for any new rosters - -void CJabberProto::OnIqResultGetRoster( HXML iqNode, CJabberIqInfo* pInfo ) -{ - Log( "<iq/> iqIdGetRoster" ); - TCHAR *szGroupDelimeter = (TCHAR *)pInfo->GetUserData(); - if ( pInfo->GetIqType() != JABBER_IQ_TYPE_RESULT ) { - mir_free( szGroupDelimeter ); - return; - } - - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode == NULL ) { - mir_free( szGroupDelimeter ); - return; - } - - if ( lstrcmp( xmlGetAttrValue( queryNode, _T("xmlns")), _T(JABBER_FEAT_IQ_ROSTER))) { - mir_free( szGroupDelimeter ); - return; - } - - if ( !_tcscmp( szGroupDelimeter, _T("\\"))) { - mir_free( szGroupDelimeter ); - szGroupDelimeter = NULL; - } - - TCHAR* nick; - int i; - LIST<void> chatRooms(10); - OBJLIST<JABBER_HTTP_AVATARS> *httpavatars = new OBJLIST<JABBER_HTTP_AVATARS>(20, JABBER_HTTP_AVATARS::compare); - - for ( i=0; ; i++ ) { - BOOL bIsTransport=FALSE; - - HXML itemNode = xmlGetChild( queryNode ,i); - if ( !itemNode ) - break; - - if ( _tcscmp( xmlGetName( itemNode ), _T("item"))) - continue; - - const TCHAR* str = xmlGetAttrValue( itemNode, _T("subscription")), *name; - - JABBER_SUBSCRIPTION sub; - if ( str == NULL ) sub = SUB_NONE; - else if ( !_tcscmp( str, _T("both"))) sub = SUB_BOTH; - else if ( !_tcscmp( str, _T("to"))) sub = SUB_TO; - else if ( !_tcscmp( str, _T("from"))) sub = SUB_FROM; - else sub = SUB_NONE; - - const TCHAR* jid = xmlGetAttrValue( itemNode, _T("jid")); - if ( jid == NULL ) - continue; - if ( _tcschr( jid, '@' ) == NULL ) - bIsTransport = TRUE; - - if (( name = xmlGetAttrValue( itemNode, _T("name"))) != NULL ) - nick = mir_tstrdup( name ); - else - nick = JabberNickFromJID( jid ); - - if ( nick == NULL ) - continue; - - JABBER_LIST_ITEM* item = ListAdd( LIST_ROSTER, jid ); - item->subscription = sub; - - mir_free( item->nick ); item->nick = nick; - - HXML groupNode = xmlGetChild( itemNode , "group" ); - replaceStrT( item->group, ( groupNode ) ? xmlGetText( groupNode ) : NULL ); - - // check group delimiters: - if ( item->group && szGroupDelimeter ) { - TCHAR *szPos = NULL; - while ( szPos = _tcsstr( item->group, szGroupDelimeter )) { - *szPos = 0; - szPos += _tcslen( szGroupDelimeter ); - TCHAR *szNewGroup = (TCHAR *)mir_alloc( sizeof(TCHAR) * ( _tcslen( item->group ) + _tcslen( szPos ) + 2)); - _tcscpy( szNewGroup, item->group ); - _tcscat( szNewGroup, _T("\\")); - _tcscat( szNewGroup, szPos ); - mir_free( item->group ); - item->group = szNewGroup; - } - } - - HANDLE hContact = HContactFromJID( jid ); - if ( hContact == NULL ) { - // Received roster has a new JID. - // Add the jid ( with empty resource ) to Miranda contact list. - hContact = DBCreateContact( jid, nick, FALSE, FALSE ); - } - - if ( name != NULL ) { - DBVARIANT dbNick; - if ( !JGetStringT( hContact, "Nick", &dbNick )) { - if ( lstrcmp( nick, dbNick.ptszVal ) != 0 ) - DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); - else - DBDeleteContactSetting( hContact, "CList", "MyHandle" ); - - JFreeVariant( &dbNick ); - } - else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); - } - else DBDeleteContactSetting( hContact, "CList", "MyHandle" ); - - if ( JGetByte( hContact, "ChatRoom", 0 )) { - GCSESSION gcw = {0}; - gcw.cbSize = sizeof(GCSESSION); - gcw.iType = GCW_CHATROOM; - gcw.pszModule = m_szModuleName; - gcw.dwFlags = GC_TCHAR; - gcw.ptszID = jid; - gcw.ptszName = NEWTSTR_ALLOCA( jid ); - - TCHAR* p = (TCHAR*)_tcschr( gcw.ptszName, '@' ); - if ( p ) - *p = 0; - - CallServiceSync( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw ); - - DBDeleteContactSetting( hContact, "CList", "Hidden" ); - chatRooms.insert( hContact ); - } else - { - UpdateSubscriptionInfo(hContact, item); - } - - if (!m_options.IgnoreRosterGroups) { - if ( item->group != NULL ) { - JabberContactListCreateGroup( item->group ); - - // Don't set group again if already correct, or Miranda may show wrong group count in some case - DBVARIANT dbv; - if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) { - if ( lstrcmp( dbv.ptszVal, item->group )) - DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); - JFreeVariant( &dbv ); - } - else DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); - } - else - DBDeleteContactSetting( hContact, "CList", "Group" ); - } - - if ( hContact != NULL ) { - if ( bIsTransport) - JSetByte( hContact, "IsTransport", TRUE ); - else - JSetByte( hContact, "IsTransport", FALSE ); - } - - const TCHAR* imagepath = xmlGetAttrValue(itemNode, _T("vz:img")); - if (imagepath) - httpavatars->insert(new JABBER_HTTP_AVATARS(imagepath, hContact)); - } - - if (httpavatars->getCount()) - JForkThread(&CJabberProto::LoadHttpAvatars, httpavatars); - else - delete httpavatars; - - // Delete orphaned contacts ( if roster sync is enabled ) - if ( m_options.RosterSync == TRUE ) { - int listSize = 0, listAllocSize = 0; - HANDLE* list = NULL; - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* str = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( str != NULL && !strcmp( str, m_szModuleName )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - if ( !ListExist( LIST_ROSTER, dbv.ptszVal )) { - Log( "Syncing roster: preparing to delete " TCHAR_STR_PARAM " ( hContact=0x%x )", dbv.ptszVal, hContact ); - if ( listSize >= listAllocSize ) { - listAllocSize = listSize + 100; - if (( list=( HANDLE * ) mir_realloc( list, listAllocSize * sizeof( HANDLE ))) == NULL ) { - listSize = 0; - break; - } } - - list[listSize++] = hContact; - } - JFreeVariant( &dbv ); - } } - - hContact = db_find_next(hContact); - } - - for ( i=0; i < listSize; i++ ) { - Log( "Syncing roster: deleting 0x%x", list[i] ); - CallService( MS_DB_CONTACT_DELETE, ( WPARAM ) list[i], 0 ); - } - if ( list != NULL ) - mir_free( list ); - } - - EnableMenuItems( TRUE ); - - Log( "Status changed via THREADSTART" ); - m_bModeMsgStatusChangePending = FALSE; - SetServerStatus( m_iDesiredStatus ); - - if ( m_options.AutoJoinConferences ) { - for ( i=0; i < chatRooms.getCount(); i++ ) - GroupchatJoinByHContact(( HANDLE )chatRooms[i], true); - } - chatRooms.destroy(); - - //UI_SAFE_NOTIFY(m_pDlgJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE); - //UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_CHECK_ONLINE); - UI_SAFE_NOTIFY_HWND(m_hwndJabberAddBookmark, WM_JABBER_CHECK_ONLINE); - WindowNotify(WM_JABBER_CHECK_ONLINE); - - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - - if ( szGroupDelimeter ) - mir_free( szGroupDelimeter ); - - OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_ROSTER); - RebuildInfoFrame(); -} - -void CJabberProto::OnIqResultGetRegister( HXML iqNode ) -{ - // RECVED: result of the request for ( agent ) registration mechanism - // ACTION: activate ( agent ) registration input dialog - Log( "<iq/> iqIdGetRegister" ); - - HXML queryNode; - const TCHAR *type; - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( queryNode = xmlGetChild( iqNode , "query" )) == NULL ) return; - - if ( !lstrcmp( type, _T("result"))) { - if ( m_hwndAgentRegInput ) - SendMessage( m_hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 1 /*success*/, ( LPARAM )xi.copyNode( iqNode )); - } - else if ( !lstrcmp( type, _T("error"))) { - if ( m_hwndAgentRegInput ) { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - SendMessage( m_hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 0 /*error*/, ( LPARAM )str ); - mir_free( str ); -} } } - -void CJabberProto::OnIqResultSetRegister( HXML iqNode ) -{ - // RECVED: result of registration process - // ACTION: notify of successful agent registration - Log( "<iq/> iqIdSetRegister" ); - - const TCHAR *type, *from; - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; - - if ( !lstrcmp( type, _T("result"))) { - HANDLE hContact = HContactFromJID( from ); - if ( hContact != NULL ) - JSetByte( hContact, "IsTransport", TRUE ); - - if ( m_hwndRegProgress ) - SendMessage( m_hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" )); - } - else if ( !lstrcmp( type, _T("error"))) { - if ( m_hwndRegProgress ) { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - SendMessage( m_hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str ); - mir_free( str ); -} } } - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberIqResultGetVcard - processes the server-side v-card - -void CJabberProto::OnIqResultGetVcardPhoto( const TCHAR* jid, HXML n, HANDLE hContact, BOOL& hasPhoto ) -{ - Log( "JabberIqResultGetVcardPhoto: %d", hasPhoto ); - if ( hasPhoto ) - return; - - HXML o = xmlGetChild( n , "BINVAL" ); - if ( o == NULL || xmlGetText( o ) == NULL ) - return; - - int bufferLen; - char* buffer = JabberBase64DecodeT( xmlGetText( o ), &bufferLen ); - if ( buffer == NULL ) - return; - - const TCHAR* szPicType; - HXML m = xmlGetChild( n , "TYPE" ); - if ( m == NULL || xmlGetText( m ) == NULL ) { -LBL_NoTypeSpecified: - switch( JabberGetPictureType( buffer )) { - case PA_FORMAT_GIF: szPicType = _T("image/gif"); break; - case PA_FORMAT_BMP: szPicType = _T("image/bmp"); break; - case PA_FORMAT_PNG: szPicType = _T("image/png"); break; - case PA_FORMAT_JPEG: szPicType = _T("image/jpeg"); break; - default: -LBL_Ret: - mir_free( buffer ); - return; - } - } - else { - const TCHAR* tszType = xmlGetText( m ); - if ( !_tcscmp( tszType, _T("image/jpeg")) || - !_tcscmp( tszType, _T("image/png")) || - !_tcscmp( tszType, _T("image/gif")) || - !_tcscmp( tszType, _T("image/bmp"))) - szPicType = tszType; - else - goto LBL_NoTypeSpecified; - } - - TCHAR szAvatarFileName[MAX_PATH]; - GetAvatarFileName( hContact, szAvatarFileName, SIZEOF( szAvatarFileName )); - - Log( "Picture file name set to " TCHAR_STR_PARAM, szAvatarFileName ); - HANDLE hFile = CreateFile( szAvatarFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if ( hFile == INVALID_HANDLE_VALUE ) - goto LBL_Ret; - - Log( "Writing %d bytes", bufferLen ); - DWORD nWritten; - if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL )) - goto LBL_Ret; - - CloseHandle( hFile ); - - Log( "%d bytes written", nWritten ); - if ( hContact == NULL ) { - hasPhoto = TRUE; - CallService( MS_AV_SETMYAVATART, ( WPARAM )m_szModuleName, ( LPARAM )szAvatarFileName ); - - Log( "My picture saved to " TCHAR_STR_PARAM, szAvatarFileName ); - } - else { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, jid ); - if ( item == NULL ) { - item = ListAdd( LIST_VCARD_TEMP, jid ); // adding to the temp list to store information about photo - item->bUseResource = TRUE; - } - if ( item != NULL ) { - hasPhoto = TRUE; - if ( item->photoFileName ) - DeleteFile( item->photoFileName ); - replaceStrT( item->photoFileName, szAvatarFileName ); - Log( "Contact's picture saved to " TCHAR_STR_PARAM, szAvatarFileName ); - - if (JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE) { - char szHashValue[ MAX_PATH ]; - if ( JGetStaticString( "AvatarHash", hContact, szHashValue, sizeof( szHashValue ))) - OnIqResultGotAvatar( hContact, o, xmlGetText( m )); - } } - - JFreeVariant( &dbv ); - } } - - if ( !hasPhoto ) - DeleteFile( szAvatarFileName ); - - goto LBL_Ret; -} - -static TCHAR* sttGetText( HXML node, char* tag ) -{ - HXML n = xmlGetChild( node , tag ); - if ( n == NULL ) - return NULL; - - return ( TCHAR* )xmlGetText( n ); -} - -void CJabberProto::OnIqResultGetVcard( HXML iqNode ) -{ - HXML vCardNode, m, n, o; - const TCHAR* type, *jid; - HANDLE hContact; - TCHAR text[128]; - DBVARIANT dbv; - - Log( "<iq/> iqIdGetVcard" ); - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( jid = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; - int id = JabberGetPacketID( iqNode ); - - if ( id == m_nJabberSearchID ) { - m_nJabberSearchID = -1; - - if (( vCardNode = xmlGetChild( iqNode , "vCard" )) != NULL ) { - if ( !lstrcmp( type, _T("result"))) { - JABBER_SEARCH_RESULT jsr = { 0 }; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - jsr.hdr.flags = PSR_TCHAR; - jsr.hdr.nick = sttGetText( vCardNode, "NICKNAME" ); - jsr.hdr.firstName = sttGetText( vCardNode, "FN" ); - jsr.hdr.lastName = _T(""); - jsr.hdr.email = sttGetText( vCardNode, "EMAIL" ); - _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid )); - jsr.jid[ SIZEOF( jsr.jid )-1 ] = '\0'; - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE )id, ( LPARAM )&jsr ); - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); - } - else if ( !lstrcmp( type, _T("error"))) - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); - } - else JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); - return; - } - - size_t len = _tcslen( m_szJabberJID ); - if ( !_tcsnicmp( jid, m_szJabberJID, len ) && ( jid[len]=='/' || jid[len]=='\0' )) { - hContact = NULL; - Log( "Vcard for myself" ); - } - else { - if (( hContact = HContactFromJID( jid )) == NULL ) - return; - Log( "Other user's vcard" ); - } - - if ( !lstrcmp( type, _T("result"))) { - BOOL hasFn, hasNick, hasGiven, hasFamily, hasMiddle, hasBday, hasGender; - BOOL hasPhone, hasFax, hasCell, hasUrl; - BOOL hasHome, hasHomeStreet, hasHomeStreet2, hasHomeLocality, hasHomeRegion, hasHomePcode, hasHomeCtry; - BOOL hasWork, hasWorkStreet, hasWorkStreet2, hasWorkLocality, hasWorkRegion, hasWorkPcode, hasWorkCtry; - BOOL hasOrgname, hasOrgunit, hasRole, hasTitle; - BOOL hasDesc, hasPhoto; - int nEmail, nPhone, nYear, nMonth, nDay; - - hasFn = hasNick = hasGiven = hasFamily = hasMiddle = hasBday = hasGender = FALSE; - hasPhone = hasFax = hasCell = hasUrl = FALSE; - hasHome = hasHomeStreet = hasHomeStreet2 = hasHomeLocality = hasHomeRegion = hasHomePcode = hasHomeCtry = FALSE; - hasWork = hasWorkStreet = hasWorkStreet2 = hasWorkLocality = hasWorkRegion = hasWorkPcode = hasWorkCtry = FALSE; - hasOrgname = hasOrgunit = hasRole = hasTitle = FALSE; - hasDesc = hasPhoto = FALSE; - nEmail = nPhone = 0; - - if (( vCardNode = xmlGetChild( iqNode , "vCard" )) != NULL ) { - for ( int i=0; ; i++ ) { - n = xmlGetChild( vCardNode ,i); - if ( !n ) - break; - if ( xmlGetName( n ) == NULL ) continue; - if ( !_tcscmp( xmlGetName( n ), _T("FN"))) { - if ( xmlGetText( n ) != NULL ) { - hasFn = TRUE; - JSetStringT( hContact, "FullName", xmlGetText( n )); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("NICKNAME"))) { - if ( xmlGetText( n ) != NULL ) { - hasNick = TRUE; - JSetStringT( hContact, "Nick", xmlGetText( n )); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("N"))) { - // First/Last name - if ( !hasGiven && !hasFamily && !hasMiddle ) { - if (( m=xmlGetChild( n , "GIVEN" )) != NULL && xmlGetText( m )!=NULL ) { - hasGiven = TRUE; - JSetStringT( hContact, "FirstName", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "FAMILY" )) != NULL && xmlGetText( m )!=NULL ) { - hasFamily = TRUE; - JSetStringT( hContact, "LastName", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "MIDDLE" )) != NULL && xmlGetText( m ) != NULL ) { - hasMiddle = TRUE; - JSetStringT( hContact, "MiddleName", xmlGetText( m )); - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("EMAIL"))) { - // E-mail address( es ) - if (( m=xmlGetChild( n , "USERID" )) == NULL ) // Some bad client put e-mail directly in <EMAIL/> instead of <USERID/> - m = n; - if ( xmlGetText( m ) != NULL ) { - char text[100]; - if ( hContact != NULL ) { - if ( nEmail == 0 ) - strcpy( text, "e-mail" ); - else - sprintf( text, "e-mail%d", nEmail-1 ); - } - else sprintf( text, "e-mail%d", nEmail ); - JSetStringT( hContact, text, xmlGetText( m )); - - if ( hContact == NULL ) { - sprintf( text, "e-mailFlag%d", nEmail ); - int nFlag = 0; - if ( xmlGetChild( n , "HOME" ) != NULL ) nFlag |= JABBER_VCEMAIL_HOME; - if ( xmlGetChild( n , "WORK" ) != NULL ) nFlag |= JABBER_VCEMAIL_WORK; - if ( xmlGetChild( n , "INTERNET" ) != NULL ) nFlag |= JABBER_VCEMAIL_INTERNET; - if ( xmlGetChild( n , "X400" ) != NULL ) nFlag |= JABBER_VCEMAIL_X400; - JSetWord( NULL, text, nFlag ); - } - nEmail++; - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("BDAY"))) { - // Birthday - if ( !hasBday && xmlGetText( n )!=NULL ) { - if ( hContact != NULL ) { - if ( _stscanf( xmlGetText( n ), _T("%d-%d-%d"), &nYear, &nMonth, &nDay ) == 3 ) { - hasBday = TRUE; - JSetWord( hContact, "BirthYear", ( WORD )nYear ); - JSetByte( hContact, "BirthMonth", ( BYTE ) nMonth ); - JSetByte( hContact, "BirthDay", ( BYTE ) nDay ); - - SYSTEMTIME sToday = {0}; - GetLocalTime(&sToday); - int nAge = sToday.wYear - nYear; - if (sToday.wMonth < nMonth || (sToday.wMonth == nMonth && sToday.wDay < nDay)) - nAge--; - if (nAge) - JSetWord( hContact, "Age", ( WORD )nAge ); - } - } - else { - hasBday = TRUE; - JSetStringT( NULL, "BirthDate", xmlGetText( n )); - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("GENDER"))) { - // Gender - if ( !hasGender && xmlGetText( n )!=NULL ) { - if ( hContact != NULL ) { - if ( xmlGetText( n )[0] && strchr( "mMfF", xmlGetText( n )[0] )!=NULL ) { - hasGender = TRUE; - JSetByte( hContact, "Gender", ( BYTE ) toupper( xmlGetText( n )[0] )); - } - } - else { - hasGender = TRUE; - JSetStringT( NULL, "GenderString", xmlGetText( n )); - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("ADR"))) { - if ( !hasHome && xmlGetChild( n , "HOME" )!=NULL ) { - // Home address - hasHome = TRUE; - if (( m=xmlGetChild( n , "STREET" )) != NULL && xmlGetText( m ) != NULL ) { - hasHomeStreet = TRUE; - if ( hContact != NULL ) { - if (( o=xmlGetChild( n , "EXTADR" )) != NULL && xmlGetText( o ) != NULL ) - mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); - else if (( o=xmlGetChild( n , "EXTADD" ))!=NULL && xmlGetText( o )!=NULL ) - mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); - else - _tcsncpy( text, xmlGetText( m ), SIZEOF( text )); - text[SIZEOF(text)-1] = '\0'; - JSetStringT( hContact, "Street", text ); - } - else { - JSetStringT( hContact, "Street", xmlGetText( m )); - if (( m=xmlGetChild( n , "EXTADR" )) == NULL ) - m = xmlGetChild( n , "EXTADD" ); - if ( m!=NULL && xmlGetText( m )!=NULL ) { - hasHomeStreet2 = TRUE; - JSetStringT( hContact, "Street2", xmlGetText( m )); - } } } - - if (( m=xmlGetChild( n , "LOCALITY" ))!=NULL && xmlGetText( m )!=NULL ) { - hasHomeLocality = TRUE; - JSetStringT( hContact, "City", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "REGION" ))!=NULL && xmlGetText( m )!=NULL ) { - hasHomeRegion = TRUE; - JSetStringT( hContact, "State", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "PCODE" ))!=NULL && xmlGetText( m )!=NULL ) { - hasHomePcode = TRUE; - JSetStringT( hContact, "ZIP", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "CTRY" ))==NULL || xmlGetText( m )==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/> - m = xmlGetChild( n , "COUNTRY" ); - if ( m!=NULL && xmlGetText( m )!=NULL ) { - hasHomeCtry = TRUE; - JSetStringT( hContact, "Country", xmlGetText( m )); - } } - - if ( !hasWork && xmlGetChild( n , "WORK" )!=NULL ) { - // Work address - hasWork = TRUE; - if (( m=xmlGetChild( n , "STREET" ))!=NULL && xmlGetText( m )!=NULL ) { - hasWorkStreet = TRUE; - if ( hContact != NULL ) { - if (( o=xmlGetChild( n , "EXTADR" ))!=NULL && xmlGetText( o )!=NULL ) - mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); - else if (( o=xmlGetChild( n , "EXTADD" ))!=NULL && xmlGetText( o )!=NULL ) - mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); - else - _tcsncpy( text, xmlGetText( m ), SIZEOF( text )); - text[SIZEOF( text )-1] = '\0'; - JSetStringT( hContact, "CompanyStreet", text ); - } - else { - JSetStringT( hContact, "CompanyStreet", xmlGetText( m )); - if (( m=xmlGetChild( n , "EXTADR" )) == NULL ) - m = xmlGetChild( n , "EXTADD" ); - if ( m!=NULL && xmlGetText( m )!=NULL ) { - hasWorkStreet2 = TRUE; - JSetStringT( hContact, "CompanyStreet2", xmlGetText( m )); - } } } - - if (( m=xmlGetChild( n , "LOCALITY" ))!=NULL && xmlGetText( m )!=NULL ) { - hasWorkLocality = TRUE; - JSetStringT( hContact, "CompanyCity", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "REGION" ))!=NULL && xmlGetText( m )!=NULL ) { - hasWorkRegion = TRUE; - JSetStringT( hContact, "CompanyState", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "PCODE" ))!=NULL && xmlGetText( m )!=NULL ) { - hasWorkPcode = TRUE; - JSetStringT( hContact, "CompanyZIP", xmlGetText( m )); - } - if (( m=xmlGetChild( n , "CTRY" ))==NULL || xmlGetText( m )==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/> - m = xmlGetChild( n , "COUNTRY" ); - if ( m!=NULL && xmlGetText( m )!=NULL ) { - hasWorkCtry = TRUE; - JSetStringT( hContact, "CompanyCountry", xmlGetText( m )); - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("TEL"))) { - // Telephone/Fax/Cellular - if (( m=xmlGetChild( n , "NUMBER" ))!=NULL && xmlGetText( m )!=NULL ) { - if ( hContact != NULL ) { - if ( !hasFax && xmlGetChild( n , "FAX" )!=NULL ) { - hasFax = TRUE; - JSetStringT( hContact, "Fax", xmlGetText( m )); - } - else if ( !hasCell && xmlGetChild( n , "CELL" )!=NULL ) { - hasCell = TRUE; - JSetStringT( hContact, "Cellular", xmlGetText( m )); - } - else if ( !hasPhone && - ( xmlGetChild( n , "HOME" )!=NULL || - xmlGetChild( n , "WORK" )!=NULL || - xmlGetChild( n , "VOICE" )!=NULL || - ( xmlGetChild( n , "FAX" )==NULL && - xmlGetChild( n , "PAGER" )==NULL && - xmlGetChild( n , "MSG" )==NULL && - xmlGetChild( n , "CELL" )==NULL && - xmlGetChild( n , "VIDEO" )==NULL && - xmlGetChild( n , "BBS" )==NULL && - xmlGetChild( n , "MODEM" )==NULL && - xmlGetChild( n , "ISDN" )==NULL && - xmlGetChild( n , "PCS" )==NULL ))) { - hasPhone = TRUE; - JSetStringT( hContact, "Phone", xmlGetText( m )); - } - } - else { - char text[ 100 ]; - sprintf( text, "Phone%d", nPhone ); - JSetStringT( NULL, text, xmlGetText( m )); - - sprintf( text, "PhoneFlag%d", nPhone ); - int nFlag = 0; - if ( xmlGetChild( n ,"HOME" ) != NULL ) nFlag |= JABBER_VCTEL_HOME; - if ( xmlGetChild( n ,"WORK" ) != NULL ) nFlag |= JABBER_VCTEL_WORK; - if ( xmlGetChild( n ,"VOICE" ) != NULL ) nFlag |= JABBER_VCTEL_VOICE; - if ( xmlGetChild( n ,"FAX" ) != NULL ) nFlag |= JABBER_VCTEL_FAX; - if ( xmlGetChild( n ,"PAGER" ) != NULL ) nFlag |= JABBER_VCTEL_PAGER; - if ( xmlGetChild( n ,"MSG" ) != NULL ) nFlag |= JABBER_VCTEL_MSG; - if ( xmlGetChild( n ,"CELL" ) != NULL ) nFlag |= JABBER_VCTEL_CELL; - if ( xmlGetChild( n ,"VIDEO" ) != NULL ) nFlag |= JABBER_VCTEL_VIDEO; - if ( xmlGetChild( n ,"BBS" ) != NULL ) nFlag |= JABBER_VCTEL_BBS; - if ( xmlGetChild( n ,"MODEM" ) != NULL ) nFlag |= JABBER_VCTEL_MODEM; - if ( xmlGetChild( n ,"ISDN" ) != NULL ) nFlag |= JABBER_VCTEL_ISDN; - if ( xmlGetChild( n ,"PCS" ) != NULL ) nFlag |= JABBER_VCTEL_PCS; - JSetWord( NULL, text, nFlag ); - nPhone++; - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("URL"))) { - // Homepage - if ( !hasUrl && xmlGetText( n )!=NULL ) { - hasUrl = TRUE; - JSetStringT( hContact, "Homepage", xmlGetText( n )); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("ORG"))) { - if ( !hasOrgname && !hasOrgunit ) { - if (( m=xmlGetChild( n ,"ORGNAME" ))!=NULL && xmlGetText( m )!=NULL ) { - hasOrgname = TRUE; - JSetStringT( hContact, "Company", xmlGetText( m )); - } - if (( m=xmlGetChild( n ,"ORGUNIT" ))!=NULL && xmlGetText( m )!=NULL ) { // The real vCard can have multiple <ORGUNIT/> but we will only display the first one - hasOrgunit = TRUE; - JSetStringT( hContact, "CompanyDepartment", xmlGetText( m )); - } } - } - else if ( !lstrcmp( xmlGetName( n ), _T("ROLE"))) { - if ( !hasRole && xmlGetText( n )!=NULL ) { - hasRole = TRUE; - JSetStringT( hContact, "Role", xmlGetText( n )); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("TITLE"))) { - if ( !hasTitle && xmlGetText( n )!=NULL ) { - hasTitle = TRUE; - JSetStringT( hContact, "CompanyPosition", xmlGetText( n )); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("DESC"))) { - if ( !hasDesc && xmlGetText( n )!=NULL ) { - hasDesc = TRUE; - TCHAR* szMemo = JabberUnixToDosT( xmlGetText( n )); - JSetStringT( hContact, "About", szMemo ); - mir_free( szMemo ); - } - } - else if ( !lstrcmp( xmlGetName( n ), _T("PHOTO"))) - OnIqResultGetVcardPhoto( jid, n, hContact, hasPhoto ); - } } - - if ( hasFn && !hasNick ) { - TCHAR *name = JGetStringT( hContact, "FullName" ); - TCHAR *nick = JGetStringT( hContact, "Nick" ); - TCHAR *jidNick = JabberNickFromJID(jid); - if ( !nick || ( jidNick && !_tcsicmp( nick, jidNick ))) - JSetStringT( hContact, "Nick", name ); - - mir_free( jidNick ); - mir_free( nick ); - mir_free( name ); - } - if ( !hasFn ) - JDeleteSetting( hContact, "FullName" ); - // We are not deleting "Nick" -// if ( !hasNick ) -// JDeleteSetting( hContact, "Nick" ); - if ( !hasGiven ) - JDeleteSetting( hContact, "FirstName" ); - if ( !hasFamily ) - JDeleteSetting( hContact, "LastName" ); - if ( !hasMiddle ) - JDeleteSetting( hContact, "MiddleName" ); - if ( hContact != NULL ) { - while ( true ) { - if ( nEmail <= 0 ) - JDeleteSetting( hContact, "e-mail" ); - else { - char text[ 100 ]; - sprintf( text, "e-mail%d", nEmail-1 ); - if ( DBGetContactSettingString( hContact, m_szModuleName, text, &dbv )) break; - JFreeVariant( &dbv ); - JDeleteSetting( hContact, text ); - } - nEmail++; - } - } - else { - while ( true ) { - char text[ 100 ]; - sprintf( text, "e-mail%d", nEmail ); - if ( DBGetContactSettingString( NULL, m_szModuleName, text, &dbv )) break; - JFreeVariant( &dbv ); - JDeleteSetting( NULL, text ); - sprintf( text, "e-mailFlag%d", nEmail ); - JDeleteSetting( NULL, text ); - nEmail++; - } } - - if ( !hasBday ) { - JDeleteSetting( hContact, "BirthYear" ); - JDeleteSetting( hContact, "BirthMonth" ); - JDeleteSetting( hContact, "BirthDay" ); - JDeleteSetting( hContact, "BirthDate" ); - JDeleteSetting( hContact, "Age" ); - } - if ( !hasGender ) { - if ( hContact != NULL ) - JDeleteSetting( hContact, "Gender" ); - else - JDeleteSetting( NULL, "GenderString" ); - } - if ( hContact != NULL ) { - if ( !hasPhone ) - JDeleteSetting( hContact, "Phone" ); - if ( !hasFax ) - JDeleteSetting( hContact, "Fax" ); - if ( !hasCell ) - JDeleteSetting( hContact, "Cellular" ); - } - else { - while ( true ) { - char text[ 100 ]; - sprintf( text, "Phone%d", nPhone ); - if ( DBGetContactSettingString( NULL, m_szModuleName, text, &dbv )) break; - JFreeVariant( &dbv ); - JDeleteSetting( NULL, text ); - sprintf( text, "PhoneFlag%d", nPhone ); - JDeleteSetting( NULL, text ); - nPhone++; - } } - - if ( !hasHomeStreet ) - JDeleteSetting( hContact, "Street" ); - if ( !hasHomeStreet2 && hContact==NULL ) - JDeleteSetting( hContact, "Street2" ); - if ( !hasHomeLocality ) - JDeleteSetting( hContact, "City" ); - if ( !hasHomeRegion ) - JDeleteSetting( hContact, "State" ); - if ( !hasHomePcode ) - JDeleteSetting( hContact, "ZIP" ); - if ( !hasHomeCtry ) - JDeleteSetting( hContact, "Country" ); - if ( !hasWorkStreet ) - JDeleteSetting( hContact, "CompanyStreet" ); - if ( !hasWorkStreet2 && hContact==NULL ) - JDeleteSetting( hContact, "CompanyStreet2" ); - if ( !hasWorkLocality ) - JDeleteSetting( hContact, "CompanyCity" ); - if ( !hasWorkRegion ) - JDeleteSetting( hContact, "CompanyState" ); - if ( !hasWorkPcode ) - JDeleteSetting( hContact, "CompanyZIP" ); - if ( !hasWorkCtry ) - JDeleteSetting( hContact, "CompanyCountry" ); - if ( !hasUrl ) - JDeleteSetting( hContact, "Homepage" ); - if ( !hasOrgname ) - JDeleteSetting( hContact, "Company" ); - if ( !hasOrgunit ) - JDeleteSetting( hContact, "CompanyDepartment" ); - if ( !hasRole ) - JDeleteSetting( hContact, "Role" ); - if ( !hasTitle ) - JDeleteSetting( hContact, "CompanyPosition" ); - if ( !hasDesc ) - JDeleteSetting( hContact, "About" ); - - if ( id == m_ThreadInfo->resolveID ) { - const TCHAR* p = _tcschr( jid, '@' ); - ResolveTransportNicks(( p != NULL ) ? p+1 : jid ); - } - else { - if (( hContact = HContactFromJID( jid )) != NULL ) - JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 ); - WindowNotify(WM_JABBER_REFRESH_VCARD); - } - } - else if ( !lstrcmp( type, _T("error"))) { - if (( hContact = HContactFromJID( jid )) != NULL ) - JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, ( HANDLE ) 1, 0 ); - } -} - -void CJabberProto::OnIqResultSetVcard( HXML iqNode ) -{ - Log( "<iq/> iqIdSetVcard" ); - if ( !xmlGetAttrValue( iqNode, _T("type"))) - return; - - WindowNotify(WM_JABBER_REFRESH_VCARD); -} - -void CJabberProto::OnIqResultSetSearch( HXML iqNode ) -{ - HXML queryNode, n; - const TCHAR* type, *jid; - int i, id; - JABBER_SEARCH_RESULT jsr; - - Log( "<iq/> iqIdGetSearch" ); - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( id = JabberGetPacketID( iqNode )) == -1 ) return; - - if ( !lstrcmp( type, _T("result"))) { - if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - for ( i=0; ; i++ ) { - HXML itemNode = xmlGetChild( queryNode ,i); - if ( !itemNode ) - break; - - if ( !lstrcmp( xmlGetName( itemNode ), _T("item"))) { - if (( jid=xmlGetAttrValue( itemNode, _T("jid"))) != NULL ) { - _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid )); - jsr.jid[ SIZEOF( jsr.jid )-1] = '\0'; - jsr.hdr.id = (TCHAR*)jid; - Log( "Result jid = " TCHAR_STR_PARAM, jid ); - if (( n=xmlGetChild( itemNode , "nick" ))!=NULL && xmlGetText( n )!=NULL ) - jsr.hdr.nick = ( TCHAR* )xmlGetText( n ); - else - jsr.hdr.nick = _T( "" ); - if (( n=xmlGetChild( itemNode , "first" ))!=NULL && xmlGetText( n )!=NULL ) - jsr.hdr.firstName = ( TCHAR* )xmlGetText( n ); - else - jsr.hdr.firstName = _T( "" ); - if (( n=xmlGetChild( itemNode , "last" ))!=NULL && xmlGetText( n )!=NULL ) - jsr.hdr.lastName = ( TCHAR* )xmlGetText( n ); - else - jsr.hdr.lastName = _T( "" ); - if (( n=xmlGetChild( itemNode , "email" ))!=NULL && xmlGetText( n )!=NULL ) - jsr.hdr.email = ( TCHAR* )xmlGetText( n ); - else - jsr.hdr.email = _T( "" ); - jsr.hdr.flags = PSR_TCHAR; - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); - } } } - - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); - } - else if ( !lstrcmp( type, _T("error"))) - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); -} - -void CJabberProto::OnIqResultExtSearch( HXML iqNode ) -{ - HXML queryNode; - const TCHAR* type; - int id; - - Log( "<iq/> iqIdGetExtSearch" ); - if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( id = JabberGetPacketID( iqNode )) == -1 ) return; - - if ( !lstrcmp( type, _T("result"))) { - if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; - if (( queryNode=xmlGetChild( queryNode , "x" )) == NULL ) return; - for ( int i=0; ; i++ ) { - HXML itemNode = xmlGetChild( queryNode ,i); - if ( !itemNode ) - break; - if ( lstrcmp( xmlGetName( itemNode ), _T("item"))) - continue; - - JABBER_SEARCH_RESULT jsr = { 0 }; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - jsr.hdr.flags = PSR_TCHAR; -// jsr.hdr.firstName = ""; - - for ( int j=0; ; j++ ) { - HXML fieldNode = xmlGetChild( itemNode ,j); - if ( !fieldNode ) - break; - - if ( lstrcmp( xmlGetName( fieldNode ), _T("field"))) - continue; - - const TCHAR* fieldName = xmlGetAttrValue( fieldNode, _T("var")); - if ( fieldName == NULL ) - continue; - - HXML n = xmlGetChild( fieldNode , "value" ); - if ( n == NULL ) - continue; - - if ( !lstrcmp( fieldName, _T("jid"))) { - _tcsncpy( jsr.jid, xmlGetText( n ), SIZEOF( jsr.jid )); - jsr.jid[SIZEOF( jsr.jid )-1] = '\0'; - Log( "Result jid = " TCHAR_STR_PARAM, jsr.jid ); - } - else if ( !lstrcmp( fieldName, _T("nickname"))) - jsr.hdr.nick = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); - else if ( !lstrcmp( fieldName, _T("fn"))) - jsr.hdr.firstName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); - else if ( !lstrcmp( fieldName, _T("given"))) - jsr.hdr.firstName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); - else if ( !lstrcmp( fieldName, _T("family"))) - jsr.hdr.lastName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); - else if ( !lstrcmp( fieldName, _T("email"))) - jsr.hdr.email = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); - } - - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); - } - - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); - } - else if ( !lstrcmp( type, _T("error"))) - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); -} - -void CJabberProto::OnIqResultSetPassword( HXML iqNode ) -{ - Log( "<iq/> iqIdSetPassword" ); - - const TCHAR* type = xmlGetAttrValue( iqNode, _T("type")); - if ( type == NULL ) - return; - - if ( !lstrcmp( type, _T("result"))) { - _tcsncpy( m_ThreadInfo->password, m_ThreadInfo->newPassword, SIZEOF( m_ThreadInfo->password )); - MessageBox( NULL, TranslateT( "Password is successfully changed. Don't forget to update your password in the Jabber protocol option." ), TranslateT( "Change Password" ), MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND ); - } - else if ( !lstrcmp( type, _T("error"))) - MessageBox( NULL, TranslateT( "Password cannot be changed." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); -} -/* -void CJabberProto::OnIqResultDiscoAgentItems( HXML iqNode, void *userdata ) -{ - if ( !m_options.EnableAvatars ) - return; -} -*/ -void CJabberProto::OnIqResultGetVCardAvatar( HXML iqNode ) -{ - const TCHAR* type; - - Log( "<iq/> OnIqResultGetVCardAvatar" ); - - const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); - if ( from == NULL ) - return; - HANDLE hContact = HContactFromJID( from ); - if ( hContact == NULL ) - return; - - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if ( _tcscmp( type, _T("result"))) return; - - HXML vCard = xmlGetChild( iqNode , "vCard" ); - if (vCard == NULL) return; - vCard = xmlGetChild( vCard , "PHOTO" ); - if (vCard == NULL) return; - - if ( xmlGetChildCount( vCard ) == 0 ) { - JDeleteSetting( hContact, "AvatarHash" ); - DBVARIANT dbv = {0}; - if ( !JGetStringT( hContact, "AvatarSaved", &dbv )) { - JFreeVariant( &dbv ); - JDeleteSetting( hContact, "AvatarSaved" ); - JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, NULL, NULL ); - } - - return; - } - - HXML typeNode = xmlGetChild( vCard , "TYPE" ); - const TCHAR* mimeType = NULL; - if (typeNode != NULL) mimeType = xmlGetText( typeNode ); - HXML n = xmlGetChild( vCard , "BINVAL" ); - if ( n == NULL ) - return; - - JSetByte( hContact, "AvatarXVcard", 1 ); - OnIqResultGotAvatar( hContact, n, mimeType); -} - -void CJabberProto::OnIqResultGetClientAvatar( HXML iqNode ) -{ - const TCHAR* type; - - Log( "<iq/> iqIdResultGetClientAvatar" ); - - const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); - if ( from == NULL ) - return; - HANDLE hContact = HContactFromJID( from ); - if ( hContact == NULL ) - return; - - HXML n = NULL; - if (( type = xmlGetAttrValue( iqNode, _T("type"))) != NULL && !_tcscmp( type, _T("result"))) { - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode != NULL ) { - const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); - if ( !lstrcmp( xmlns, _T(JABBER_FEAT_AVATAR))) { - n = xmlGetChild( queryNode , "data" ); - } - } - } - - if ( n == NULL ) { - TCHAR szJid[ JABBER_MAX_JID_LEN ]; - lstrcpyn(szJid, from, SIZEOF(szJid)); - TCHAR *res = _tcschr(szJid, _T('/')); - if ( res != NULL ) - *res = 0; - - // Try server stored avatar - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetServerAvatar ); - - XmlNodeIq iq( _T("get"), iqId, szJid ); - iq << XQUERY( _T(JABBER_FEAT_SERVER_AVATAR)); - m_ThreadInfo->send( iq ); - - return; - } - - const TCHAR* mimeType = mimeType = xmlGetAttrValue( n, _T("mimetype")); - - OnIqResultGotAvatar( hContact, n, mimeType); -} - - -void CJabberProto::OnIqResultGetServerAvatar( HXML iqNode ) -{ - const TCHAR* type; - - Log( "<iq/> iqIdResultGetServerAvatar" ); - - const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); - if ( from == NULL ) - return; - HANDLE hContact = HContactFromJID( from ); - if ( hContact == NULL ) - return; - - HXML n = NULL; - if (( type = xmlGetAttrValue( iqNode, _T("type"))) != NULL && !_tcscmp( type, _T("result"))) { - HXML queryNode = xmlGetChild( iqNode , "query" ); - if ( queryNode != NULL ) { - const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); - if ( !lstrcmp( xmlns, _T(JABBER_FEAT_SERVER_AVATAR))) { - n = xmlGetChild( queryNode , "data" ); - } - } - } - - if ( n == NULL ) { - TCHAR szJid[ JABBER_MAX_JID_LEN ]; - lstrcpyn(szJid, from, SIZEOF(szJid)); - TCHAR *res = _tcschr(szJid, _T('/')); - if ( res != NULL ) - *res = 0; - - // Try VCard photo - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetVCardAvatar ); - - XmlNodeIq iq( _T("get"), iqId, szJid ); - iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); - m_ThreadInfo->send( iq ); - - return; - } - - const TCHAR* mimeType = xmlGetAttrValue( n, _T("mimetype")); - - OnIqResultGotAvatar( hContact, n, mimeType); -} - - -void CJabberProto::OnIqResultGotAvatar( HANDLE hContact, HXML n, const TCHAR* mimeType ) -{ - int resultLen = 0; - char* body = JabberBase64DecodeT( xmlGetText( n ), &resultLen ); - - int pictureType; - if ( mimeType != NULL ) { - if ( !lstrcmp( mimeType, _T("image/jpeg"))) pictureType = PA_FORMAT_JPEG; - else if ( !lstrcmp( mimeType, _T("image/png"))) pictureType = PA_FORMAT_PNG; - else if ( !lstrcmp( mimeType, _T("image/gif"))) pictureType = PA_FORMAT_GIF; - else if ( !lstrcmp( mimeType, _T("image/bmp"))) pictureType = PA_FORMAT_BMP; - else { -LBL_ErrFormat: - Log( "Invalid mime type specified for picture: " TCHAR_STR_PARAM, mimeType ); - mir_free( body ); - return; - } } - else if (( pictureType = JabberGetPictureType( body )) == PA_FORMAT_UNKNOWN ) - goto LBL_ErrFormat; - - TCHAR tszFileName[ MAX_PATH ]; - - PROTO_AVATAR_INFORMATIONT AI; - AI.cbSize = sizeof AI; - AI.format = pictureType; - AI.hContact = hContact; - - if ( JGetByte( hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) { - GetAvatarFileName( hContact, tszFileName, SIZEOF(tszFileName)); - DeleteFile( tszFileName ); - } - - JSetByte( hContact, "AvatarType", pictureType ); - - char buffer[ 41 ]; - mir_sha1_byte_t digest[20]; - mir_sha1_ctx sha; - mir_sha1_init( &sha ); - mir_sha1_append( &sha, ( mir_sha1_byte_t* )body, resultLen ); - mir_sha1_finish( &sha, digest ); - for ( int i=0; i<20; i++ ) - sprintf( buffer+( i<<1 ), "%02x", digest[i] ); - - GetAvatarFileName( hContact, tszFileName, SIZEOF(tszFileName)); - _tcsncpy( AI.filename, tszFileName, SIZEOF(AI.filename)); - - FILE* out = _tfopen( tszFileName, _T("wb")); - if ( out != NULL ) { - fwrite( body, resultLen, 1, out ); - fclose( out ); - JSetString( hContact, "AvatarSaved", buffer ); - JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL ); - Log("Broadcast new avatar: %s",AI.filename); - } - else JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL ); - - mir_free( body ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Bookmarks - -void CJabberProto::OnIqResultDiscoBookmarks( HXML iqNode ) -{ - HXML storageNode;//, nickNode, passNode; - const TCHAR* type, *jid, *name; - - // RECVED: list of bookmarks - // ACTION: refresh bookmarks dialog - Log( "<iq/> iqIdGetBookmarks" ); - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - - if ( !lstrcmp( type, _T("result"))) { - if ( m_ThreadInfo && !( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE )) { - m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PRIVATE_STORAGE; - EnableMenuItems( TRUE ); - } - - if ( storageNode = XPathT( iqNode, "query/storage[@xmlns='storage:bookmarks']" )) { - ListRemoveList( LIST_BOOKMARK ); - - HXML itemNode; - for ( int i = 0; itemNode = xmlGetChild( storageNode, i ); i++ ) { - if ( name = xmlGetName( itemNode)) { - if ( !_tcscmp( name, _T("conference")) && (jid = xmlGetAttrValue( itemNode, _T("jid")))) { - JABBER_LIST_ITEM* item = ListAdd( LIST_BOOKMARK, jid ); - item->name = mir_tstrdup( xmlGetAttrValue( itemNode, _T("name"))); - item->type = mir_tstrdup( _T( "conference" )); - item->bUseResource = TRUE; - item->nick = mir_tstrdup( XPathT( itemNode, "nick" )); - item->password = mir_tstrdup( XPathT( itemNode, "password" )); - - const TCHAR* autoJ = xmlGetAttrValue( itemNode, _T("autojoin")); - if ( autoJ != NULL ) - item->bAutoJoin = ( !lstrcmp( autoJ, _T("true")) || !lstrcmp( autoJ, _T("1"))) ? true : false; - } - else if ( !_tcscmp( name, _T("url")) && (jid = xmlGetAttrValue( itemNode, _T("url") ))) { - JABBER_LIST_ITEM* item = ListAdd( LIST_BOOKMARK, jid ); - item->bUseResource = TRUE; - item->name = mir_tstrdup( xmlGetAttrValue( itemNode, _T("name"))); - item->type = mir_tstrdup( _T("url")); - } - } - } - - UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_REFRESH); - m_ThreadInfo->bBookmarksLoaded = TRUE; - OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_BOOKMARKS); - } - } - else if ( !lstrcmp( type, _T("error"))) { - if ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE ) { - m_ThreadInfo->jabberServerCaps &= ~JABBER_CAPS_PRIVATE_STORAGE; - EnableMenuItems( TRUE ); - UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_ACTIVATE); - return; - } -} } - -void CJabberProto::SetBookmarkRequest (XmlNodeIq& iq) -{ - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); - HXML storage = query << XCHILDNS( _T("storage"), _T("storage:bookmarks")); - - LISTFOREACH(i, this, LIST_BOOKMARK) - { - JABBER_LIST_ITEM* item = ListGetItemPtrFromIndex( i ); - if ( item == NULL ) - continue; - - if ( item->jid == NULL ) - continue; - if ( !lstrcmp( item->type, _T("conference"))) { - HXML itemNode = storage << XCHILD( _T("conference")) << XATTR( _T("jid"), item->jid ); - if ( item->name ) - itemNode << XATTR( _T("name"), item->name ); - if ( item->bAutoJoin ) - itemNode << XATTRI( _T("autojoin"), 1 ); - if ( item->nick ) - itemNode << XCHILD( _T("nick"), item->nick ); - if ( item->password ) - itemNode << XCHILD( _T("password"), item->password ); - } - if ( !lstrcmp( item->type, _T("url"))) { - HXML itemNode = storage << XCHILD( _T("url")) << XATTR( _T("url"), item->jid ); - if ( item->name ) - itemNode << XATTR( _T("name"), item->name ); - } - } -} - -void CJabberProto::OnIqResultSetBookmarks( HXML iqNode ) -{ - // RECVED: server's response - // ACTION: refresh bookmarks list dialog - - Log( "<iq/> iqIdSetBookmarks" ); - - const TCHAR* type = xmlGetAttrValue( iqNode, _T("type")); - if ( type == NULL ) - return; - - if ( !lstrcmp( type, _T("result"))) { - UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_REFRESH); - } - else if ( !lstrcmp( type, _T("error"))) { - HXML errorNode = xmlGetChild( iqNode , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - MessageBox( NULL, str, TranslateT( "Jabber Bookmarks Error" ), MB_OK|MB_SETFOREGROUND ); - mir_free( str ); - UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_ACTIVATE); -} } - -// last activity (XEP-0012) support -void CJabberProto::OnIqResultLastActivity( HXML iqNode, CJabberIqInfo* pInfo ) -{ - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->m_szFrom ); - if ( !r ) - return; - - time_t lastActivity = -1; - if ( pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT ) { - LPCTSTR szSeconds = XPathT( iqNode, "query[@xmlns='jabber:iq:last']/@seconds" ); - if ( szSeconds ) { - int nSeconds = _ttoi( szSeconds ); - if ( nSeconds > 0 ) - lastActivity = time( 0 ) - nSeconds; - } - - LPCTSTR szLastStatusMessage = XPathT( iqNode, "query[@xmlns='jabber:iq:last']" ); - if ( szLastStatusMessage ) // replace only if it exists - replaceStrT( r->statusMessage, szLastStatusMessage ); - } - - r->idleStartTime = lastActivity; - - JabberUserInfoUpdate(pInfo->GetHContact()); -} - -// entity time (XEP-0202) support -void CJabberProto::OnIqResultEntityTime( HXML pIqNode, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->m_hContact ) - return; - - if ( pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT ) { - LPCTSTR szTzo = XPathFmt( pIqNode, _T("time[@xmlns='%s']/tzo"), _T( JABBER_FEAT_ENTITY_TIME )); - if ( szTzo && szTzo[0] ) { - LPCTSTR szMin = _tcschr( szTzo, ':' ); - int nTz = _ttoi( szTzo ) * -2; - nTz += ( nTz < 0 ? -1 : 1 ) * ( szMin ? _ttoi( szMin + 1 ) / 30 : 0 ); - - TIME_ZONE_INFORMATION tzinfo; - if ( GetTimeZoneInformation( &tzinfo ) == TIME_ZONE_ID_DAYLIGHT ) - nTz -= tzinfo.DaylightBias / 30; - - JSetByte( pInfo->m_hContact, "Timezone", (signed char)nTz ); - - LPCTSTR szTz = XPathFmt( pIqNode, _T("time[@xmlns='%s']/tz"), _T( JABBER_FEAT_ENTITY_TIME )); - if (szTz) - JSetStringT( pInfo->m_hContact, "TzName", szTz ); - else - JDeleteSetting( pInfo->m_hContact, "TzName" ); - return; - } - } - else if ( pInfo->m_nIqType == JABBER_IQ_TYPE_ERROR ) - { - if ( JGetWord( pInfo->m_hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE ) - return; - } - - JDeleteSetting( pInfo->m_hContact, "Timezone" ); - JDeleteSetting( pInfo->m_hContact, "TzName" ); -} diff --git a/protocols/JabberG/jabber_iqid_muc.cpp b/protocols/JabberG/jabber_iqid_muc.cpp deleted file mode 100644 index 3621506d29..0000000000 --- a/protocols/JabberG/jabber_iqid_muc.cpp +++ /dev/null @@ -1,560 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" - -void CJabberProto::SetMucConfig( HXML node, void *from ) -{ - if ( m_ThreadInfo && from ) { - XmlNodeIq iq( _T("set"), SerialNext(), ( TCHAR* )from ); - HXML query = iq << XQUERY( xmlnsOwner ); - xmlAddChild( query, node ); - m_ThreadInfo->send( iq ); -} } - -void LaunchForm(HXML node); - -void CJabberProto::OnIqResultGetMuc( HXML iqNode ) -{ - HXML queryNode, xNode; - const TCHAR *type, *from, *str; - - // RECVED: room config form - // ACTION: show the form - Log( "<iq/> iqIdGetMuc" ); - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; - - if ( !_tcscmp( type, _T("result"))) { - if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { - str = xmlGetAttrValue( queryNode, _T("xmlns")); - if ( !lstrcmp( str, _T("http://jabber.org/protocol/muc#owner" ))) { - if (( xNode = xmlGetChild( queryNode , "x" )) != NULL ) { - str = xmlGetAttrValue( xNode, _T("xmlns")); - if ( !lstrcmp( str, _T(JABBER_FEAT_DATA_FORMS))) - //LaunchForm(xNode); - FormCreateDialog( xNode, _T("Jabber Conference Room Configuration"), &CJabberProto::SetMucConfig, mir_tstrdup( from )); -} } } } } - -static void sttFillJidList(HWND hwndDlg) -{ - JABBER_MUC_JIDLIST_INFO *jidListInfo; - HXML iqNode, queryNode; - const TCHAR* from, *jid, *reason, *nick; - LVITEM lvi; - HWND hwndList; - int count, i; - - TCHAR *filter = NULL; - if (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA)) - { - int filterLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_FILTER)) + 1; - filter = (TCHAR *)_alloca(filterLength * sizeof(TCHAR)); - GetDlgItemText(hwndDlg, IDC_FILTER, filter, filterLength); - } - - jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - if ( !jidListInfo ) - return; - - hwndList = GetDlgItem( hwndDlg, IDC_LIST ); - SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); - - count = ListView_GetItemCount( hwndList ); - lvi.mask = LVIF_PARAM; - lvi.iSubItem = 0; - for ( i=0; i<count; i++ ) { - lvi.iItem = i; - if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) { - if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) { - mir_free(( void * ) lvi.lParam ); - } - } - } - ListView_DeleteAllItems( hwndList ); - - // Populate displayed list from iqNode - if (( iqNode = jidListInfo->iqNode ) != NULL ) { - if (( from = xmlGetAttrValue( iqNode, _T("from"))) != NULL ) { - if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.iSubItem = 0; - lvi.iItem = 0; - for ( i=0; ; i++ ) { - HXML itemNode = xmlGetChild( queryNode ,i); - if ( !itemNode ) - break; - - if (( jid = xmlGetAttrValue( itemNode, _T("jid"))) != NULL ) { - lvi.pszText = ( TCHAR* )jid; - if ( jidListInfo->type == MUC_BANLIST ) { - if (( reason = xmlGetText(xmlGetChild( itemNode , "reason" ))) != NULL ) { - TCHAR jidreason[ JABBER_MAX_JID_LEN + 256 ]; - mir_sntprintf( jidreason, SIZEOF( jidreason ), _T("%s (%s)") , jid, reason ); - lvi.pszText = jidreason; - } } - - if ( jidListInfo->type == MUC_VOICELIST || jidListInfo->type == MUC_MODERATORLIST ) { - if (( nick = xmlGetAttrValue( itemNode, _T("nick"))) != NULL ) { - TCHAR nickjid[ JABBER_MAX_JID_LEN + 256 ]; - mir_sntprintf( nickjid, SIZEOF( nickjid ), _T("%s (%s)") , nick, jid ); - lvi.pszText = nickjid; - } } - - if (filter && *filter && !JabberStrIStr(lvi.pszText, filter)) - continue; - - lvi.lParam = ( LPARAM )mir_tstrdup( jid ); - - ListView_InsertItem( hwndList, &lvi ); - lvi.iItem++; - } } } } } - - lvi.mask = LVIF_PARAM; - lvi.lParam = ( LPARAM )( -1 ); - ListView_InsertItem( hwndList, &lvi ); - - SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); - RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE); -} - -static int sttJidListResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDC_LIST: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - case IDC_FILTER: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM|RD_ANCHORX_WIDTH; - case IDC_BTN_FILTERRESET: - case IDC_BTN_FILTERAPPLY: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; -} - -static INT_PTR CALLBACK JabberMucJidListDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JABBER_MUC_JIDLIST_INFO* dat = (JABBER_MUC_JIDLIST_INFO*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch( msg ) { - case WM_INITDIALOG: - { - LVCOLUMN lvc; - RECT rc; - HWND hwndList; - - TranslateDialogDefault( hwndDlg ); - - hwndList = GetDlgItem( hwndDlg, IDC_LIST ); - ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); - GetClientRect( hwndList, &rc ); - //rc.right -= GetSystemMetrics( SM_CXVSCROLL ); - lvc.mask = LVCF_WIDTH; - lvc.cx = rc.right - 20; - ListView_InsertColumn( hwndList, 0, &lvc ); - lvc.cx = 20; - ListView_InsertColumn( hwndList, 1, &lvc ); - SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, lParam ); - dat = (JABBER_MUC_JIDLIST_INFO*)lParam; - - static struct - { - int idc; - char *title; - char *icon; - bool push; - } buttons[] = - { - {IDC_BTN_FILTERAPPLY, "Apply filter", "sd_filter_apply", false}, - {IDC_BTN_FILTERRESET, "Reset filter", "sd_filter_reset", false}, - }; - for (int i = 0; i < SIZEOF(buttons); ++i) - { - SendDlgItemMessage(hwndDlg, buttons[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->ppro->LoadIconEx(buttons[i].icon)); - SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONADDTOOLTIP, (WPARAM)buttons[i].title, 0); - if (buttons[i].push) - SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASPUSHBTN, TRUE, 0); - } - - Utils_RestoreWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); - } - return TRUE; - case WM_SIZE: - { - UTILRESIZEDIALOG urd = {0}; - urd.cbSize = sizeof(urd); - urd.hInstance = hInst; - urd.hwndDlg = hwndDlg; - urd.lpTemplate = MAKEINTRESOURCEA(IDD_JIDLIST); - urd.pfnResizer = sttJidListResizer; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); - - RECT listrc; - LVCOLUMN lvc; - HWND hwndList = GetDlgItem( hwndDlg, IDC_LIST ); - GetClientRect( hwndList, &listrc ); - lvc.mask = LVCF_WIDTH; - //listrc.right -= GetSystemMetrics( SM_CXVSCROLL ); - lvc.cx = listrc.right - 20; - SendMessage(hwndList, LVM_SETCOLUMN, 0, (LPARAM)&lvc); - break; - } - break; - - case WM_JABBER_REFRESH: - { - // lParam is ( JABBER_MUC_JIDLIST_INFO * ) - HXML iqNode, queryNode; - const TCHAR* from; - TCHAR title[256]; - - // Clear current GWL_USERDATA, if any - if ( dat != NULL ) - delete dat; - - // Set new GWL_USERDATA - dat = ( JABBER_MUC_JIDLIST_INFO * ) lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) dat ); - - // Populate displayed list from iqNode - lstrcpyn( title, TranslateT( "JID List" ), SIZEOF( title )); - if (( dat=( JABBER_MUC_JIDLIST_INFO * ) lParam ) != NULL ) { - if (( iqNode = dat->iqNode ) != NULL ) { - if (( from = xmlGetAttrValue( iqNode, _T("from"))) != NULL ) { - dat->roomJid = mir_tstrdup( from ); - - if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { - TCHAR* localFrom = mir_tstrdup( from ); - mir_sntprintf( title, SIZEOF( title ), TranslateT("%s, %d items (%s)"), - ( dat->type == MUC_VOICELIST ) ? TranslateT( "Voice List" ) : - ( dat->type == MUC_MEMBERLIST ) ? TranslateT( "Member List" ) : - ( dat->type == MUC_MODERATORLIST ) ? TranslateT( "Moderator List" ) : - ( dat->type == MUC_BANLIST ) ? TranslateT( "Ban List" ) : - ( dat->type == MUC_ADMINLIST ) ? TranslateT( "Admin List" ) : - ( dat->type == MUC_OWNERLIST ) ? TranslateT( "Owner List" ) : - TranslateT( "JID List" ), xmlGetChildCount(queryNode), localFrom ); - mir_free( localFrom ); - } } } } - SetWindowText( hwndDlg, title ); - - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); - sttFillJidList(hwndDlg); - } - break; - case WM_NOTIFY: - if (( ( LPNMHDR )lParam )->idFrom == IDC_LIST ) { - switch (( ( LPNMHDR )lParam )->code ) { - case NM_CUSTOMDRAW: - { - NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam; - - switch ( nm->nmcd.dwDrawStage ) { - case CDDS_PREPAINT: - case CDDS_ITEMPREPAINT: - SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW ); - return TRUE; - case CDDS_SUBITEM|CDDS_ITEMPREPAINT: - { - RECT rc; - HICON hIcon; - - ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc ); - if ( nm->iSubItem == 1 ) { - if ( nm->nmcd.lItemlParam == ( LPARAM )( -1 )) - hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); - else - hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); - DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL ); - DestroyIcon( hIcon ); - SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT ); - return TRUE; - } } } } - break; - case NM_CLICK: - { - NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam; - LVITEM lvi; - LVHITTESTINFO hti; - TCHAR text[128]; - - if ( nm->iSubItem < 1 ) - break; - - hti.pt.x = ( short ) LOWORD( GetMessagePos()); - hti.pt.y = ( short ) HIWORD( GetMessagePos()); - ScreenToClient( nm->hdr.hwndFrom, &hti.pt ); - if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 ) - break; - - if ( hti.iSubItem != 1 ) - break; - - lvi.mask = LVIF_PARAM | LVIF_TEXT; - lvi.iItem = hti.iItem; - lvi.iSubItem = 0; - lvi.pszText = text; - lvi.cchTextMax = sizeof( text ); - ListView_GetItem( nm->hdr.hwndFrom, &lvi ); - if ( lvi.lParam == ( LPARAM )( -1 )) { - TCHAR szBuffer[ 1024 ]; - _tcscpy( szBuffer, dat->type2str()); - if ( !dat->ppro->EnterString(szBuffer, SIZEOF(szBuffer), NULL, JES_COMBO, "gcAddNick_")) - break; - - // Trim leading and trailing whitespaces - TCHAR *p = szBuffer, *q; - for ( p = szBuffer; *p!='\0' && isspace( BYTE( *p )); p++); - for ( q = p; *q!='\0' && !isspace( BYTE( *q )); q++); - if (*q != '\0') *q = '\0'; - if (*p == '\0') - break; - TCHAR rsn[ 1024 ]; - _tcscpy( rsn, dat->type2str()); - if ( dat->type == MUC_BANLIST ) { - dat->ppro->EnterString(rsn, SIZEOF(rsn), TranslateT("Reason to ban") , JES_COMBO, "gcAddReason_"); - if ( szBuffer ) - dat->ppro->AddMucListItem( dat, p , rsn); - else - dat->ppro->AddMucListItem( dat, p ); - } - else dat->ppro->AddMucListItem( dat, p ); - } - else { - //delete - TCHAR msgText[128]; - - mir_sntprintf( msgText, SIZEOF( msgText ), _T("%s %s?"), TranslateT( "Removing" ), text ); - if ( MessageBox( hwndDlg, msgText, dat->type2str(), MB_YESNO|MB_SETFOREGROUND ) == IDYES ) { - dat->ppro->DeleteMucListItem( dat, ( TCHAR* )lvi.lParam ); - mir_free(( void * )lvi.lParam ); - ListView_DeleteItem( nm->hdr.hwndFrom, hti.iItem ); - } } } - break; - } - break; - } - break; - case WM_COMMAND: - if ((LOWORD(wParam) == IDC_BTN_FILTERAPPLY) || - ((LOWORD(wParam) == IDOK) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) - { - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 1); - sttFillJidList(hwndDlg); - } else - if ((LOWORD(wParam) == IDC_BTN_FILTERRESET) || - ((LOWORD(wParam) == IDCANCEL) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) - { - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); - sttFillJidList(hwndDlg); - } - break; -/* case WM_SETCURSOR: - if ( LOWORD( LPARAM )!= HTCLIENT ) break; - if ( GetForegroundWindow() == GetParent( hwndDlg )) { - POINT pt; - GetCursorPos( &pt ); - ScreenToClient( hwndDlg,&pt ); - SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click - } - break; -*/ case WM_CLOSE: - { - HWND hwndList; - int count, i; - LVITEM lvi; - - // Free lParam of the displayed list items - hwndList = GetDlgItem( hwndDlg, IDC_LIST ); - count = ListView_GetItemCount( hwndList ); - lvi.mask = LVIF_PARAM; - lvi.iSubItem = 0; - for ( i=0; i<count; i++ ) { - lvi.iItem = i; - if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) { - if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) { - mir_free(( void * ) lvi.lParam ); - } - } - } - ListView_DeleteAllItems( hwndList ); - - CJabberProto* ppro = dat->ppro; - switch ( dat->type ) { - case MUC_VOICELIST: - ppro->m_hwndMucVoiceList = NULL; - break; - case MUC_MEMBERLIST: - ppro->m_hwndMucMemberList = NULL; - break; - case MUC_MODERATORLIST: - ppro->m_hwndMucModeratorList = NULL; - break; - case MUC_BANLIST: - ppro->m_hwndMucBanList = NULL; - break; - case MUC_ADMINLIST: - ppro->m_hwndMucAdminList = NULL; - break; - case MUC_OWNERLIST: - ppro->m_hwndMucOwnerList = NULL; - break; - } - - DestroyWindow( hwndDlg ); - } - break; - - case WM_DESTROY: - // Clear GWL_USERDATA - if ( dat != NULL ) { - Utils_SaveWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); - delete dat; - } - break; - } - return FALSE; -} - -static void CALLBACK JabberMucJidListCreateDialogApcProc( void* param ) -{ - HXML iqNode, queryNode; - const TCHAR* from; - HWND *pHwndJidList; - JABBER_MUC_JIDLIST_INFO *jidListInfo = (JABBER_MUC_JIDLIST_INFO *)param; - - if ( jidListInfo == NULL ) return; - if (( iqNode = jidListInfo->iqNode ) == NULL ) return; - if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; - if (( queryNode = xmlGetChild( iqNode , "query" )) == NULL ) return; - - CJabberProto* ppro = jidListInfo->ppro; - switch ( jidListInfo->type ) { - case MUC_VOICELIST: - pHwndJidList = &ppro->m_hwndMucVoiceList; - break; - case MUC_MEMBERLIST: - pHwndJidList = &ppro->m_hwndMucMemberList; - break; - case MUC_MODERATORLIST: - pHwndJidList = &ppro->m_hwndMucModeratorList; - break; - case MUC_BANLIST: - pHwndJidList = &ppro->m_hwndMucBanList; - break; - case MUC_ADMINLIST: - pHwndJidList = &ppro->m_hwndMucAdminList; - break; - case MUC_OWNERLIST: - pHwndJidList = &ppro->m_hwndMucOwnerList; - break; - default: - mir_free( jidListInfo ); - return; - } - - if ( *pHwndJidList!=NULL && IsWindow( *pHwndJidList )) { - SetForegroundWindow( *pHwndJidList ); - SendMessage( *pHwndJidList, WM_JABBER_REFRESH, 0, ( LPARAM )jidListInfo ); - } - else *pHwndJidList = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_JIDLIST ), GetForegroundWindow(), JabberMucJidListDlgProc, ( LPARAM )jidListInfo ); -} - -void CJabberProto::OnIqResultMucGetJidList( HXML iqNode, JABBER_MUC_JIDLIST_TYPE listType ) -{ - const TCHAR* type; - JABBER_MUC_JIDLIST_INFO *jidListInfo; - - if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; - - if ( !lstrcmp( type, _T("result" ))) { - if (( jidListInfo = new JABBER_MUC_JIDLIST_INFO ) != NULL ) { - jidListInfo->type = listType; - jidListInfo->ppro = this; - jidListInfo->roomJid = NULL; // Set in the dialog procedure - if (( jidListInfo->iqNode = xi.copyNode( iqNode )) != NULL ) - CallFunctionAsync( JabberMucJidListCreateDialogApcProc, jidListInfo ); - else - mir_free( jidListInfo ); -} } } - -void CJabberProto::OnIqResultMucGetVoiceList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetVoiceList" ); - OnIqResultMucGetJidList( iqNode, MUC_VOICELIST ); -} - -void CJabberProto::OnIqResultMucGetMemberList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetMemberList" ); - OnIqResultMucGetJidList( iqNode, MUC_MEMBERLIST ); -} - -void CJabberProto::OnIqResultMucGetModeratorList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetModeratorList" ); - OnIqResultMucGetJidList( iqNode, MUC_MODERATORLIST ); -} - -void CJabberProto::OnIqResultMucGetBanList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetBanList" ); - OnIqResultMucGetJidList( iqNode, MUC_BANLIST ); -} - -void CJabberProto::OnIqResultMucGetAdminList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetAdminList" ); - OnIqResultMucGetJidList( iqNode, MUC_ADMINLIST ); -} - -void CJabberProto::OnIqResultMucGetOwnerList( HXML iqNode ) -{ - Log( "<iq/> iqResultMucGetOwnerList" ); - OnIqResultMucGetJidList( iqNode, MUC_OWNERLIST ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -JABBER_MUC_JIDLIST_INFO::~JABBER_MUC_JIDLIST_INFO() -{ - xi.destroyNode( iqNode ); - mir_free( roomJid ); -} - -TCHAR* JABBER_MUC_JIDLIST_INFO::type2str() const -{ - switch( type ) { - case MUC_VOICELIST: return TranslateT( "Voice List" ); - case MUC_MEMBERLIST: return TranslateT( "Member List" ); - case MUC_MODERATORLIST: return TranslateT( "Moderator List" ); - case MUC_BANLIST: return TranslateT( "Ban List" ); - case MUC_ADMINLIST: return TranslateT( "Admin List" ); - case MUC_OWNERLIST: return TranslateT( "Owner List" ); - } - - return TranslateT( "JID List" ); -} diff --git a/protocols/JabberG/jabber_libstr.cpp b/protocols/JabberG/jabber_libstr.cpp deleted file mode 100644 index 4517d77272..0000000000 --- a/protocols/JabberG/jabber_libstr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -int lstrcmp_null(const TCHAR *s1, const TCHAR *s2) -{ - if (!s1 && !s2) return 0; - if (!s1) return -1; - if (!s2) return 1; - return lstrcmp(s1, s2); -} diff --git a/protocols/JabberG/jabber_list.cpp b/protocols/JabberG/jabber_list.cpp deleted file mode 100644 index 8a956ebc47..0000000000 --- a/protocols/JabberG/jabber_list.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" - -void MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item); - -///////////////////////////////////////////////////////////////////////////////////////// -// List item freeing - -static void JabberListFreeResourceInternal( JABBER_RESOURCE_STATUS *r) -{ - if ( r->resourceName ) mir_free( r->resourceName ); - if ( r->nick ) mir_free( r->nick ); - if ( r->statusMessage ) mir_free( r->statusMessage ); - if ( r->software ) mir_free( r->software ); - if ( r->version ) mir_free( r->version ); - if ( r->system ) mir_free( r->system ); - if ( r->szCapsNode ) mir_free( r->szCapsNode ); - if ( r->szCapsVer ) mir_free( r->szCapsVer ); - if ( r->szCapsExt ) mir_free( r->szCapsExt ); - if ( r->szRealJid ) mir_free( r->szRealJid ); - if ( r->pSoftwareInfo) delete r->pSoftwareInfo; -} - -static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item ) -{ - if ( item == NULL ) - return; - - if ( item->jid ) mir_free( item->jid ); - if ( item->nick ) mir_free( item->nick ); - - JABBER_RESOURCE_STATUS* r = item->resource; - for ( int i=0; i < item->resourceCount; i++, r++ ) - JabberListFreeResourceInternal( r ); - if ( item->resource ) mir_free( item->resource ); - - JabberListFreeResourceInternal( &item->itemResource ); - - if ( item->group ) mir_free( item->group ); - if ( item->photoFileName ) { - DeleteFile( item->photoFileName ); - mir_free( item->photoFileName ); - } - if ( item->messageEventIdStr ) mir_free( item->messageEventIdStr ); - if ( item->name ) mir_free( item->name ); - if ( item->type ) mir_free( item->type ); - if ( item->service ) mir_free( item->service ); - if ( item->password ) mir_free( item->password ); - if ( item->list==LIST_ROSTER && item->ft ) delete item->ft; - mir_free( item ); -} - -void CJabberProto::ListWipe( void ) -{ - int i; - - EnterCriticalSection( &m_csLists ); - for ( i=0; i < m_lstRoster.getCount(); i++ ) - JabberListFreeItemInternal( m_lstRoster[i] ); - - m_lstRoster.destroy(); - LeaveCriticalSection( &m_csLists ); -} - -int CJabberProto::ListExist( JABBER_LIST list, const TCHAR* jid ) -{ - JABBER_LIST_ITEM tmp; - tmp.list = list; - tmp.jid = (TCHAR*)jid; - tmp.bUseResource = FALSE; - - EnterCriticalSection( &m_csLists ); - - //fyr - if ( list == LIST_ROSTER ) - { - tmp.list = LIST_CHATROOM; - int id = m_lstRoster.getIndex( &tmp ); - if ( id != -1) - tmp.bUseResource = TRUE; - tmp.list = list; - } - - int idx = m_lstRoster.getIndex( &tmp ); - - if ( idx == -1 ) { - LeaveCriticalSection( &m_csLists ); - return 0; - } - - LeaveCriticalSection( &m_csLists ); - return idx+1; -} - -JABBER_LIST_ITEM *CJabberProto::ListAdd( JABBER_LIST list, const TCHAR* jid ) -{ - JABBER_LIST_ITEM* item; - BOOL bUseResource=FALSE; - EnterCriticalSection( &m_csLists ); - if (( item = ListGetItemPtr( list, jid )) != NULL ) { - LeaveCriticalSection( &m_csLists ); - return item; - } - - TCHAR *s = mir_tstrdup( jid ); - TCHAR *q = NULL; - // strip resource name if any - //fyr - if ( !((list== LIST_ROSTER ) && ListExist(LIST_CHATROOM, jid))) { // but only if it is not chat room contact - if ( list != LIST_VCARD_TEMP ) { - TCHAR *p; - if (( p = _tcschr( s, '@' )) != NULL ) - if (( q = _tcschr( p, '/' )) != NULL ) - *q = '\0'; - } - } else { - bUseResource=TRUE; - } - - if ( !bUseResource && list== LIST_ROSTER ) - { - //if it is a chat room keep resource and made it resource sensitive - if ( ChatRoomHContactFromJID( s )) - { - if (q != NULL) *q='/'; - bUseResource=TRUE; - } - } - item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); - ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); - item->list = list; - item->jid = s; - item->itemResource.status = ID_STATUS_OFFLINE; - item->resource = NULL; - item->resourceMode = RSMODE_LASTSEEN; - item->lastSeenResource = -1; - item->manualResource = -1; - item->bUseResource = bUseResource; - - m_lstRoster.insert( item ); - LeaveCriticalSection( &m_csLists ); - - MenuUpdateSrmmIcon(item); - return item; -} - -void CJabberProto::ListRemove( JABBER_LIST list, const TCHAR* jid ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( list, jid ); - if ( i != 0 ) { - JabberListFreeItemInternal( m_lstRoster[ --i ] ); - m_lstRoster.remove( i ); - } - LeaveCriticalSection( &m_csLists ); -} - -void CJabberProto::ListRemoveList( JABBER_LIST list ) -{ - int i = 0; - while (( i=ListFindNext( list, i )) >= 0 ) - ListRemoveByIndex( i ); -} - -void CJabberProto::ListRemoveByIndex( int index ) -{ - EnterCriticalSection( &m_csLists ); - if ( index >= 0 && index < m_lstRoster.getCount()) { - JabberListFreeItemInternal( m_lstRoster[index] ); - m_lstRoster.remove( index ); - } - LeaveCriticalSection( &m_csLists ); -} - -JABBER_RESOURCE_STATUS *CJabberProto::ListFindResource( JABBER_LIST list, const TCHAR* jid ) -{ - JABBER_RESOURCE_STATUS *result = NULL; - - EnterCriticalSection( &m_csLists ); - int i = ListExist( list, jid ); - if ( !i ) { - LeaveCriticalSection( &m_csLists ); - return 0; - } - - JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; - - const TCHAR* p = _tcschr( jid, '@' ); - const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); - if (q) - { - const TCHAR *resource = q+1; - if (*resource) - for ( int j=0; j < LI->resourceCount; j++ ) - if ( !_tcscmp( LI->resource[j].resourceName, resource )) - { - result = LI->resource + j; - break; - } - } - - LeaveCriticalSection( &m_csLists ); - - return result; -} - -int CJabberProto::ListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage, char priority, const TCHAR* nick ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( list, jid ); - if ( !i ) { - LeaveCriticalSection( &m_csLists ); - return 0; - } - - JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; - int bIsNewResource = false, j; - - const TCHAR* p = _tcschr( jid, '@' ); - const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); - if ( q ) { - const TCHAR* resource = q+1; - if ( resource[0] ) { - JABBER_RESOURCE_STATUS* r = LI->resource; - for ( j=0; j < LI->resourceCount; j++, r++ ) { - if ( !_tcscmp( r->resourceName, resource )) { - // Already exist, update status and statusMessage - r->status = status; - replaceStrT( r->statusMessage, statusMessage ); - r->priority = priority; - break; - } } - - if ( j >= LI->resourceCount ) { - // Not already exist, add new resource - LI->resource = ( JABBER_RESOURCE_STATUS * ) mir_realloc( LI->resource, ( LI->resourceCount+1 )*sizeof( JABBER_RESOURCE_STATUS )); - bIsNewResource = true; - r = LI->resource + LI->resourceCount++; - memset( r, 0, sizeof( JABBER_RESOURCE_STATUS )); - r->status = status; - r->affiliation = AFFILIATION_NONE; - r->role = ROLE_NONE; - r->resourceName = mir_tstrdup( resource ); - r->nick = mir_tstrdup( nick ); - if ( statusMessage ) - r->statusMessage = mir_tstrdup( statusMessage ); - r->priority = priority; - } } - } - // No resource, update the main statusMessage - else { - LI->itemResource.status = status; - replaceStrT( LI->itemResource.statusMessage, statusMessage ); - } - - LeaveCriticalSection( &m_csLists ); - - MenuUpdateSrmmIcon(LI); - return bIsNewResource; -} - -void CJabberProto::ListRemoveResource( JABBER_LIST list, const TCHAR* jid ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( list, jid ); - JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; - if ( !i || LI == NULL ) { - LeaveCriticalSection( &m_csLists ); - return; - } - - const TCHAR* p = _tcschr( jid, '@' ); - const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); - if ( q ) { - const TCHAR* resource = q+1; - if ( resource[0] ) { - JABBER_RESOURCE_STATUS* r = LI->resource; - int j; - for ( j=0; j < LI->resourceCount; j++, r++ ) { - if ( !_tcsicmp( r->resourceName, resource )) - break; - } - if ( j < LI->resourceCount ) { - // Found last seen resource ID to be removed - if ( LI->lastSeenResource == j ) - LI->lastSeenResource = -1; - else if ( LI->lastSeenResource > j ) - LI->lastSeenResource--; - // update manually selected resource ID - if (LI->resourceMode == RSMODE_MANUAL) - { - if ( LI->manualResource == j ) - { - LI->resourceMode = RSMODE_LASTSEEN; - LI->manualResource = -1; - } else if ( LI->manualResource > j ) - LI->manualResource--; - } - - // Update MirVer due to possible resource changes - UpdateMirVer(LI); - - JabberListFreeResourceInternal( r ); - - if ( LI->resourceCount-- == 1 ) { - mir_free( r ); - LI->resource = NULL; - } - else { - memmove( r, r+1, ( LI->resourceCount-j )*sizeof( JABBER_RESOURCE_STATUS )); - LI->resource = ( JABBER_RESOURCE_STATUS* )mir_realloc( LI->resource, LI->resourceCount*sizeof( JABBER_RESOURCE_STATUS )); - } } } } - - LeaveCriticalSection( &m_csLists ); - - MenuUpdateSrmmIcon(LI); -} - -TCHAR* CJabberProto::ListGetBestResourceNamePtr( const TCHAR* jid ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( LIST_ROSTER, jid ); - if ( !i ) { - LeaveCriticalSection( &m_csLists ); - return NULL; - } - - TCHAR* res = NULL; - - JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; - if ( LI->resourceCount > 1 ) { - if ( LI->resourceMode == RSMODE_LASTSEEN && LI->lastSeenResource>=0 && LI->lastSeenResource < LI->resourceCount ) - res = LI->resource[ LI->lastSeenResource ].resourceName; - else if (LI->resourceMode == RSMODE_MANUAL && LI->manualResource>=0 && LI->manualResource < LI->resourceCount ) - res = LI->resource[ LI->manualResource ].resourceName; - else { - int nBestPos = -1, nBestPri = -200, j; - for ( j = 0; j < LI->resourceCount; j++ ) { - if ( LI->resource[ j ].priority > nBestPri ) { - nBestPri = LI->resource[ j ].priority; - nBestPos = j; - } - } - if ( nBestPos != -1 ) - res = LI->resource[ nBestPos ].resourceName; - } - } - - if ( !res && LI->resource) - res = LI->resource[0].resourceName; - - LeaveCriticalSection( &m_csLists ); - return res; -} - -TCHAR* CJabberProto::ListGetBestClientResourceNamePtr( const TCHAR* jid ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( LIST_ROSTER, jid ); - if ( !i ) { - LeaveCriticalSection( &m_csLists ); - return NULL; - } - - JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; - TCHAR* res = ListGetBestResourceNamePtr( jid ); - if ( res == NULL ) { - JABBER_RESOURCE_STATUS* r = LI->resource; - int status = ID_STATUS_OFFLINE; - res = NULL; - for ( i=0; i < LI->resourceCount; i++ ) { - int s = r[i].status; - BOOL foundBetter = FALSE; - switch ( s ) { - case ID_STATUS_FREECHAT: - foundBetter = TRUE; - break; - case ID_STATUS_ONLINE: - if ( status != ID_STATUS_FREECHAT ) - foundBetter = TRUE; - break; - case ID_STATUS_DND: - if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE ) - foundBetter = TRUE; - break; - case ID_STATUS_AWAY: - if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND ) - foundBetter = TRUE; - break; - case ID_STATUS_NA: - if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND && status != ID_STATUS_AWAY ) - foundBetter = TRUE; - break; - } - if ( foundBetter ) { - res = r[i].resourceName; - status = s; - } } } - - LeaveCriticalSection( &m_csLists ); - return res; -} - -int CJabberProto::ListFindNext( JABBER_LIST list, int fromOffset ) -{ - EnterCriticalSection( &m_csLists ); - int i = ( fromOffset >= 0 ) ? fromOffset : 0; - for ( ; i<m_lstRoster.getCount(); i++ ) - if ( m_lstRoster[i]->list == list ) { - LeaveCriticalSection( &m_csLists ); - return i; - } - LeaveCriticalSection( &m_csLists ); - return -1; -} - -JABBER_LIST_ITEM *CJabberProto::ListGetItemPtr( JABBER_LIST list, const TCHAR* jid ) -{ - EnterCriticalSection( &m_csLists ); - int i = ListExist( list, jid ); - if ( !i ) { - LeaveCriticalSection( &m_csLists ); - return NULL; - } - i--; - LeaveCriticalSection( &m_csLists ); - return m_lstRoster[i]; -} - -JABBER_LIST_ITEM *CJabberProto::ListGetItemPtrFromIndex( int index ) -{ - EnterCriticalSection( &m_csLists ); - if ( index >= 0 && index < m_lstRoster.getCount()) { - LeaveCriticalSection( &m_csLists ); - return m_lstRoster[index]; - } - LeaveCriticalSection( &m_csLists ); - return NULL; -} - -BOOL CJabberProto::ListLock() -{ - EnterCriticalSection( &m_csLists ); - return TRUE; -} - -BOOL CJabberProto::ListUnlock() -{ - LeaveCriticalSection( &m_csLists ); - return TRUE; -} diff --git a/protocols/JabberG/jabber_list.h b/protocols/JabberG/jabber_list.h deleted file mode 100644 index 503a479ece..0000000000 --- a/protocols/JabberG/jabber_list.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_LIST_H_ -#define _JABBER_LIST_H_ - -#include "jabber_caps.h" - -typedef enum { - LIST_ROSTER, // Roster list - LIST_CHATROOM, // Groupchat room currently joined - LIST_ROOM, // Groupchat room list to show on the Jabber groupchat dialog - LIST_FILE, // Current file transfer session - LIST_BYTE, // Bytestream sending connection - LIST_FTRECV, - LIST_BOOKMARK, - LIST_VCARD_TEMP, - LIST_FTIQID -} JABBER_LIST; - -typedef enum { - SUB_NONE, - SUB_TO, - SUB_FROM, - SUB_BOTH -} JABBER_SUBSCRIPTION; - -typedef enum { - AFFILIATION_NONE, - AFFILIATION_OUTCAST, - AFFILIATION_MEMBER, - AFFILIATION_ADMIN, - AFFILIATION_OWNER -} JABBER_GC_AFFILIATION; - -typedef enum { - ROLE_NONE, - ROLE_VISITOR, - ROLE_PARTICIPANT, - ROLE_MODERATOR -} JABBER_GC_ROLE; - -typedef enum { // initial default to RSMODE_LASTSEEN - RSMODE_SERVER, // always let server decide ( always send correspondence without resouce name ) - RSMODE_LASTSEEN, // use the last seen resource ( or let server decide if haven't seen anything yet ) - RSMODE_MANUAL // specify resource manually ( see the defaultResource field - must not be NULL ) -} JABBER_RESOURCE_MODE; - - -struct JABBER_XEP0232_SOFTWARE_INFO -{ - TCHAR* szOs; - TCHAR* szOsVersion; - TCHAR* szSoftware; - TCHAR* szSoftwareVersion; - TCHAR* szXMirandaCoreVersion; - BOOL bXMirandaIsUnicode; - BOOL bXMirandaIsAlpha; - BOOL bXMirandaIsDebug; - JABBER_XEP0232_SOFTWARE_INFO() { - ZeroMemory( this, sizeof( JABBER_XEP0232_SOFTWARE_INFO )); - } - ~JABBER_XEP0232_SOFTWARE_INFO() { - mir_free(szOs); - mir_free(szOsVersion); - mir_free(szSoftware); - mir_free(szSoftwareVersion); - mir_free(szXMirandaCoreVersion); - } -}; - -struct JABBER_RESOURCE_STATUS -{ - int status; - TCHAR* resourceName; - TCHAR* nick; - TCHAR* statusMessage; - TCHAR* software; - TCHAR* version; - TCHAR* system; - signed char priority; // resource priority, -128..+127 - time_t idleStartTime;// XEP-0012 support - JABBER_GC_AFFILIATION affiliation; - JABBER_GC_ROLE role; - TCHAR* szRealJid; // real jid for jabber conferences - - // XEP-0115 support - TCHAR* szCapsNode; - TCHAR* szCapsVer; - TCHAR* szCapsExt; - DWORD dwVersionRequestTime; - DWORD dwDiscoInfoRequestTime; - JabberCapsBits jcbCachedCaps; - JabberCapsBits jcbManualDiscoveredCaps; - - // XEP-0085 gone event support - BOOL bMessageSessionActive; - JABBER_XEP0232_SOFTWARE_INFO* pSoftwareInfo; -}; - -struct JABBER_LIST_ITEM -{ - JABBER_LIST list; - TCHAR* jid; - - // LIST_ROSTER - // jid = jid of the contact - TCHAR* nick; - int resourceCount; - JABBER_RESOURCE_STATUS *resource; - JABBER_RESOURCE_STATUS itemResource; // resource for jids without /resource node - int lastSeenResource; // index to resource[x] which was last seen active - int manualResource; // manually set index to resource[x] -// int defaultResource; // index to resource[x] which is the default, negative ( -1 ) means no resource is chosen yet - JABBER_RESOURCE_MODE resourceMode; - JABBER_SUBSCRIPTION subscription; - TCHAR* group; - TCHAR* photoFileName; - TCHAR* messageEventIdStr; - - // LIST_AGENT - // jid = jid of the agent - TCHAR* name; - TCHAR* service; - - // LIST_ROOM - // jid = room JID - // char* name; // room name - TCHAR* type; // room type - - // LIST_CHATROOM - // jid = room JID - // char* nick; // my nick in this chat room ( SPECIAL: in TXT ) - // JABBER_RESOURCE_STATUS *resource; // participant nicks in this room - BOOL bChatActive; - HWND hwndGcListBan; - HWND hwndGcListAdmin; - HWND hwndGcListOwner; - int iChatState; - // BOOL bAutoJoin; // chat sessio was started via auto-join - - // LIST_FILE - // jid = string representation of port number - filetransfer* ft; - WORD port; - - // LIST_BYTE - // jid = string representation of port number - JABBER_BYTE_TRANSFER *jbt; - - JABBER_IBB_TRANSFER *jibb; - - // LIST_FTRECV - // jid = string representation of stream id ( sid ) - // ft = file transfer data - - //LIST_BOOKMARK - // jid = room JID - // TCHAR* nick; // my nick in this chat room - // TCHAR* name; // name of the bookmark - // TCHAR* type; // type of bookmark ("url" or "conference") - TCHAR* password; // password for room - BOOL bAutoJoin; - - BOOL bUseResource; -}; - -struct JABBER_HTTP_AVATARS -{ - char * Url; - HANDLE hContact; - - JABBER_HTTP_AVATARS(const TCHAR* tUrl, HANDLE thContact) - : Url(mir_t2a(tUrl)), hContact(thContact) {} - - ~JABBER_HTTP_AVATARS() { mir_free(Url); } - - static int compare(const JABBER_HTTP_AVATARS *p1, const JABBER_HTTP_AVATARS *p2) - { return strcmp(p1->Url, p2->Url); } -}; - -#endif diff --git a/protocols/JabberG/jabber_menu.cpp b/protocols/JabberG/jabber_menu.cpp deleted file mode 100644 index 6bc4c1f8c8..0000000000 --- a/protocols/JabberG/jabber_menu.cpp +++ /dev/null @@ -1,1324 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" -#include "jabber_caps.h" -#include "jabber_privacy.h" -#include "jabber_disco.h" - -#include <m_genmenu.h> -#include <m_contacts.h> -#include <m_hotkeys.h> -#include <m_icolib.h> - -#include "m_toptoolbar.h" - -#define MENUITEM_LASTSEEN 1 -#define MENUITEM_SERVER 2 -#define MENUITEM_RESOURCES 10 - -static HANDLE hChooserMenu; -static int iChooserMenuPos = 30000; - -static HANDLE hPrebuildMenuHook; -SortedList arServices; - -static HGENMENU g_hMenuRequestAuth; -static HGENMENU g_hMenuGrantAuth; -static HGENMENU g_hMenuRevokeAuth; -static HGENMENU g_hMenuConvert; -static HGENMENU g_hMenuRosterAdd; -static HGENMENU g_hMenuAddBookmark; -static HGENMENU g_hMenuLogin; -static HGENMENU g_hMenuRefresh; -static HGENMENU g_hMenuCommands; -static HGENMENU g_hMenuSendNote; -static HGENMENU g_hMenuResourcesRoot; -static HGENMENU g_hMenuResourcesActive; -static HGENMENU g_hMenuResourcesServer; - -static struct -{ - int icon; - int mode; -} PresenceModeArray[] = -{ - { SKINICON_STATUS_ONLINE, ID_STATUS_ONLINE }, - { SKINICON_STATUS_AWAY, ID_STATUS_AWAY }, - { SKINICON_STATUS_NA, ID_STATUS_NA }, - { SKINICON_STATUS_DND, ID_STATUS_DND }, - { SKINICON_STATUS_FREE4CHAT, ID_STATUS_FREECHAT }, -}; -static HGENMENU g_hMenuDirectPresence[SIZEOF(PresenceModeArray) + 1]; - -static INT_PTR JabberMenuChooseService( WPARAM wParam, LPARAM lParam ) -{ - if ( lParam ) - *( void** )lParam = ( void* )wParam; - return 0; -} - -static CJabberProto* JabberGetInstanceByHContact( HANDLE hContact ) -{ - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto == NULL ) - return NULL; - - for ( int i=0; i < g_Instances.getCount(); i++ ) - if ( !strcmp( szProto, g_Instances[i]->m_szModuleName )) - return g_Instances[i]; - - return NULL; -} - -static INT_PTR JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuHandleRequestAuth( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuHandleGrantAuth( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuRevokeAuth( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuRevokeAuth( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuConvertChatContact( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuConvertChatContact( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuRosterAdd( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuRosterAdd( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuBookmarkAdd( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuBookmarkAdd( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuTransportLogin( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuTransportLogin( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuTransportResolve( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuTransportResolve( wParam, lParam ) : 0; -} - -static INT_PTR JabberContactMenuRunCommands( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->ContactMenuRunCommands( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuSendNote( WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuSendNote( wParam, lParam ) : 0; -} - -static INT_PTR JabberMenuHandleResource( WPARAM wParam, LPARAM lParam, LPARAM lRes ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuHandleResource( wParam, lParam, lRes ) : 0; -} - -static INT_PTR JabberMenuHandleDirectPresence( WPARAM wParam, LPARAM lParam, LPARAM lRes ) -{ - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnMenuHandleDirectPresence( wParam, lParam, lRes ) : 0; -} - -static void sttEnableMenuItem( HANDLE hMenuItem, BOOL bEnable ) -{ - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_FLAGS; - if ( !bEnable ) - clmi.flags |= CMIF_HIDDEN; - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi ); -} - -static int JabberPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) -{ - sttEnableMenuItem( g_hMenuRequestAuth, FALSE ); - sttEnableMenuItem( g_hMenuGrantAuth, FALSE ); - sttEnableMenuItem( g_hMenuRevokeAuth, FALSE ); - sttEnableMenuItem( g_hMenuCommands, FALSE ); - sttEnableMenuItem( g_hMenuSendNote, FALSE ); - sttEnableMenuItem( g_hMenuConvert, FALSE ); - sttEnableMenuItem( g_hMenuRosterAdd, FALSE ); - sttEnableMenuItem( g_hMenuLogin, FALSE ); - sttEnableMenuItem( g_hMenuRefresh, FALSE ); - sttEnableMenuItem( g_hMenuAddBookmark, FALSE ); - sttEnableMenuItem( g_hMenuResourcesRoot, FALSE ); - sttEnableMenuItem( g_hMenuDirectPresence[0], FALSE ); - - CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); - return( ppro ) ? ppro->OnPrebuildContactMenu( wParam, lParam ) : 0; -} - -void g_MenuInit( void ) -{ - arServices.increment = 10; - - hPrebuildMenuHook = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, JabberPrebuildContactMenu ); - - List_InsertPtr( &arServices, CreateServiceFunction( "Jabber/MenuChoose", JabberMenuChooseService )); - - TMenuParam mnu = {0}; - mnu.cbSize = sizeof(mnu); - mnu.name = "JabberAccountChooser"; - mnu.ExecService = "Jabber/MenuChoose"; - hChooserMenu = (HANDLE)CallService( MO_CREATENEWMENUOBJECT, 0, (LPARAM)&mnu ); - - TMO_MenuItem tmi = { 0 }; - tmi.cbSize = sizeof( tmi ); - tmi.flags = CMIF_ICONFROMICOLIB; - tmi.pszName = "Cancel"; - tmi.position = 9999999; - tmi.hIcolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_DELETE); - CallService( MO_ADDNEWMENUITEM, (WPARAM)hChooserMenu, ( LPARAM )&tmi ); - - ////////////////////////////////////////////////////////////////////////////////////// - // Contact menu initialization - - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(CLISTMENUITEM); - - // "Request authorization" - mi.pszName = LPGEN("Request authorization"); - mi.flags = CMIF_ICONFROMICOLIB; - mi.position = -2000001000; - mi.icolibItem = g_GetIconHandle( IDI_REQUEST ); - mi.pszService = "Jabber/ReqAuth"; - g_hMenuRequestAuth = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuHandleRequestAuth )); - - // "Grant authorization" - mi.pszService = "Jabber/GrantAuth"; - mi.pszName = LPGEN("Grant authorization"); - mi.position = -2000001001; - mi.icolibItem = g_GetIconHandle( IDI_GRANT ); - g_hMenuGrantAuth = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuHandleGrantAuth )); - - // Revoke auth - mi.pszService = "Jabber/RevokeAuth"; - mi.pszName = LPGEN("Revoke authorization"); - mi.position = -2000001002; - mi.icolibItem = g_GetIconHandle( IDI_AUTHREVOKE ); - g_hMenuRevokeAuth = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuRevokeAuth )); - - // "Convert Chat/Contact" - mi.pszService = "Jabber/ConvertChatContact"; - mi.pszName = LPGEN("Convert"); - mi.position = -1999901004; - mi.icolibItem = g_GetIconHandle( IDI_USER2ROOM ); - g_hMenuConvert = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuConvertChatContact )); - - // "Add to roster" - mi.pszService = "Jabber/AddToRoster"; - mi.pszName = LPGEN("Add to roster"); - mi.position = -1999901005; - mi.icolibItem = g_GetIconHandle( IDI_ADDROSTER ); - g_hMenuRosterAdd = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuRosterAdd )); - - // "Add to Bookmarks" - mi.pszService = "Jabber/AddToBookmarks"; - mi.pszName = LPGEN("Add to Bookmarks"); - mi.position = -1999901006; - mi.icolibItem = g_GetIconHandle( IDI_BOOKMARKS); - g_hMenuAddBookmark = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuBookmarkAdd )); - - // Login/logout - mi.pszService = "Jabber/TransportLogin"; - mi.pszName = LPGEN("Login/logout"); - mi.position = -1999901007; - mi.icolibItem = g_GetIconHandle( IDI_LOGIN ); - g_hMenuLogin = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuTransportLogin )); - - // Retrieve nicks - mi.pszService = "Jabber/TransportGetNicks"; - mi.pszName = LPGEN("Resolve nicks"); - mi.position = -1999901008; - mi.icolibItem = g_GetIconHandle( IDI_REFRESH ); - g_hMenuRefresh = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuTransportResolve )); - - // Run Commands - mi.pszService = "Jabber/RunCommands"; - mi.pszName = LPGEN("Commands"); - mi.position = -1999901009; - mi.icolibItem = g_GetIconHandle( IDI_COMMAND ); - g_hMenuCommands = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberContactMenuRunCommands )); - - // Send Note - mi.pszService = "Jabber/SendNote"; - mi.pszName = LPGEN("Send Note"); - mi.position = -1999901010; - mi.icolibItem = g_GetIconHandle( IDI_SEND_NOTE); - g_hMenuSendNote = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuSendNote )); - - // Direct Presence - mi.pszService = "Jabber/DirectPresenceDummySvc"; - mi.pszName = LPGEN("Send Presence"); - mi.position = -1999901011; - mi.pszPopupName = (char *)-1; - mi.icolibItem = g_GetIconHandle( IDI_NOTES ); - g_hMenuDirectPresence[0] = Menu_AddContactMenuItem(&mi); - - mi.flags |= CMIF_ROOTHANDLE; - mi.flags &= ~CMIF_ICONFROMICOLIB; - - for (int i = 0; i < SIZEOF(PresenceModeArray); ++i) - { - char buf[] = "Jabber/DirectPresenceX"; - buf[SIZEOF(buf)-2] = '0' + i; - mi.pszService = buf; - mi.pszName = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, PresenceModeArray[i].mode, 0); - mi.position = -1999901000; - mi.hParentMenu = g_hMenuDirectPresence[0]; - mi.icolibItem = LoadSkinnedIcon(PresenceModeArray[i].icon); - g_hMenuDirectPresence[i+1] = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleDirectPresence, PresenceModeArray[i].mode )); - } - - mi.flags &= ~CMIF_ROOTHANDLE; - mi.flags |= CMIF_ICONFROMICOLIB; - - // Resource selector - mi.pszService = "Jabber/ResourceSelectorDummySvc"; - mi.pszName = LPGEN("Jabber Resource"); - mi.position = -1999901011; - mi.pszPopupName = (char *)-1; - mi.icolibItem = g_GetIconHandle( IDI_JABBER ); - g_hMenuResourcesRoot = Menu_AddContactMenuItem(&mi); - - mi.pszService = "Jabber/UseResource_last"; - mi.pszName = LPGEN("Last Active"); - mi.position = -1999901000; - mi.hParentMenu = g_hMenuResourcesRoot; - mi.icolibItem = g_GetIconHandle( IDI_JABBER ); - mi.flags |= CMIF_ROOTHANDLE; - g_hMenuResourcesActive = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleResource, MENUITEM_LASTSEEN )); - - mi.pszService = "Jabber/UseResource_server"; - mi.pszName = LPGEN("Server's Choice"); - mi.position = -1999901000; - mi.pszPopupName = (char *)g_hMenuResourcesRoot; - mi.icolibItem = g_GetIconHandle( IDI_NODE_SERVER ); - g_hMenuResourcesServer = Menu_AddContactMenuItem(&mi); - List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleResource, MENUITEM_SERVER )); -} - -void g_MenuUninit( void ) -{ - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRequestAuth, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuGrantAuth, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRevokeAuth, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuConvert, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRosterAdd, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuLogin, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRefresh, 0 ); - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuAddBookmark, 0 ); - - UnhookEvent( hPrebuildMenuHook ); - for (int i = 0; i < arServices.realCount; i++) - DestroyServiceFunction( arServices.items[i] ); - List_Destroy( &arServices ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// contact menu services - -int CJabberProto::OnPrebuildContactMenu( WPARAM wParam, LPARAM ) -{ - HANDLE hContact; - if (( hContact=( HANDLE )wParam ) == NULL ) - return 0; - - BYTE bIsChatRoom = (BYTE)JGetByte( hContact, "ChatRoom", 0 ); - BYTE bIsTransport = (BYTE)JGetByte( hContact, "IsTransport", 0 ); - - if ((bIsChatRoom == GCW_CHATROOM) || bIsChatRoom == 0 ) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, bIsChatRoom?(char*)"ChatRoomID":(char*)"jid", &dbv )) { - JFreeVariant( &dbv ); - CLISTMENUITEM clmi = { 0 }; - sttEnableMenuItem( g_hMenuConvert, TRUE ); - clmi.cbSize = sizeof( clmi ); - clmi.pszName = bIsChatRoom ? (char *)LPGEN("&Convert to Contact") : (char *)LPGEN("&Convert to Chat Room"); - clmi.flags = CMIM_NAME | CMIM_FLAGS; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuConvert, ( LPARAM )&clmi ); - } } - - if (!m_bJabberOnline) - return 0; - - sttEnableMenuItem( g_hMenuDirectPresence[0], TRUE ); - for (int i = 0; i < SIZEOF(PresenceModeArray); ++i) - { - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_ICON|CMIM_FLAGS; - clmi.hIcon = (HICON)LoadSkinnedProtoIcon(m_szModuleName, PresenceModeArray[i].mode); - CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuDirectPresence[i+1], ( LPARAM )&clmi ); - } - - if ( bIsChatRoom ) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "ChatRoomID", &dbv )) { - sttEnableMenuItem( g_hMenuRosterAdd, FALSE ); - - if ( ListGetItemPtr( LIST_BOOKMARK, dbv.ptszVal ) == NULL ) - if ( m_ThreadInfo && m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE ) - sttEnableMenuItem( g_hMenuAddBookmark, TRUE ); - - JFreeVariant( &dbv ); - } } - - if ( bIsChatRoom == GCW_CHATROOM ) - return 0; - - if ( bIsTransport ) { - sttEnableMenuItem( g_hMenuLogin, TRUE ); - sttEnableMenuItem( g_hMenuRefresh, TRUE ); - } - - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - JabberCapsBits jcb = GetTotalJidCapabilites(dbv.ptszVal ); - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); - JFreeVariant( &dbv ); - if ( item != NULL ) { - BOOL bCtrlPressed = ( GetKeyState( VK_CONTROL)&0x8000 ) != 0; - sttEnableMenuItem( g_hMenuRequestAuth, item->subscription == SUB_FROM || item->subscription == SUB_NONE || bCtrlPressed ); - sttEnableMenuItem( g_hMenuGrantAuth, bCtrlPressed ); - sttEnableMenuItem( g_hMenuRevokeAuth, item->subscription == SUB_FROM || item->subscription == SUB_BOTH || bCtrlPressed ); - sttEnableMenuItem( g_hMenuCommands, (( jcb & JABBER_CAPS_COMMANDS ) != 0) || bCtrlPressed); - sttEnableMenuItem( g_hMenuSendNote, TRUE ); - - if ( item->resourceCount >= 1 ) { - sttEnableMenuItem( g_hMenuResourcesRoot, TRUE ); - - CLISTMENUITEM mi = {0}; - mi.cbSize = sizeof(CLISTMENUITEM); - mi.flags = CMIM_ICON|CMIM_FLAGS; - mi.icolibItem = GetIconHandle( IDI_JABBER ); - CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesRoot, ( LPARAM )&mi ); - CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesActive, ( LPARAM )&mi ); - - int nMenuResourceItemsNew = m_nMenuResourceItems; - if ( m_nMenuResourceItems < item->resourceCount ) { - m_phMenuResourceItems = (HANDLE *)mir_realloc( m_phMenuResourceItems, item->resourceCount * sizeof(HANDLE)); - nMenuResourceItemsNew = item->resourceCount; - } - - char text[ 256 ]; - strcpy( text, m_szModuleName ); - size_t nModuleNameLength = strlen( text ); - char* tDest = text + nModuleNameLength; - - mi.cbSize = sizeof(CLISTMENUITEM); - mi.flags = CMIF_CHILDPOPUP; - mi.position = 0; - mi.icolibItem = GetIconHandle( IDI_REQUEST ); - mi.pszService = text; - mi.pszContactOwner = m_szModuleName; - - TCHAR szTmp[512]; - for (int i = 0; i < nMenuResourceItemsNew; ++i) { - mir_snprintf( tDest, SIZEOF(text) - nModuleNameLength, "/UseResource_%d", i ); - if ( i >= m_nMenuResourceItems ) { - JCreateServiceParam( tDest, &CJabberProto::OnMenuHandleResource, MENUITEM_RESOURCES+i ); - mi.pszName = ""; - mi.position = i; - mi.pszPopupName = (char *)g_hMenuResourcesRoot; - m_phMenuResourceItems[i] = Menu_AddContactMenuItem(&mi); - } - if ( i < item->resourceCount ) { - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_NAME|CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_TCHAR; - if ((item->resourceMode == RSMODE_MANUAL) && (item->manualResource == i)) - clmi.flags |= CMIF_CHECKED; - if (ServiceExists(MS_FP_GETCLIENTICONT)) { - clmi.flags |= CMIM_ICON; - FormatMirVer(&item->resource[i], szTmp, SIZEOF(szTmp)); - clmi.hIcon = (HICON)CallService( MS_FP_GETCLIENTICONT, (WPARAM)szTmp, 0 ); - } - mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s [%s, %d]"), - item->resource[i].resourceName, - (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, item->resource[i].status, GSMDF_TCHAR), - item->resource[i].priority); - clmi.ptszName = szTmp; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_phMenuResourceItems[i], ( LPARAM )&clmi ); - DestroyIcon(clmi.hIcon); - } - else sttEnableMenuItem( m_phMenuResourceItems[i], FALSE ); - } - - ZeroMemory(&mi, sizeof(mi)); - mi.cbSize = sizeof(CLISTMENUITEM); - - mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_ICONFROMICOLIB | - ((item->resourceMode == RSMODE_LASTSEEN) ? CMIF_CHECKED : 0); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesActive, ( LPARAM )&mi ); - - mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_ICONFROMICOLIB | - ((item->resourceMode == RSMODE_SERVER) ? CMIF_CHECKED : 0); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesServer, ( LPARAM )&mi ); - - m_nMenuResourceItems = nMenuResourceItemsNew; - } - - return 0; - } } - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuConvertChatContact( WPARAM wParam, LPARAM ) -{ - BYTE bIsChatRoom = (BYTE)JGetByte( (HANDLE ) wParam, "ChatRoom", 0 ); - if ((bIsChatRoom == GCW_CHATROOM) || bIsChatRoom == 0 ) { - DBVARIANT dbv; - if ( !JGetStringT( (HANDLE ) wParam, (bIsChatRoom == GCW_CHATROOM)?(char*)"ChatRoomID":(char*)"jid", &dbv )) { - JDeleteSetting( (HANDLE ) wParam, (bIsChatRoom == GCW_CHATROOM)?"ChatRoomID":"jid"); - JSetStringT( (HANDLE ) wParam, (bIsChatRoom != GCW_CHATROOM)?"ChatRoomID":"jid", dbv.ptszVal); - JFreeVariant( &dbv ); - JSetByte((HANDLE ) wParam, "ChatRoom", (bIsChatRoom == GCW_CHATROOM)?0:GCW_CHATROOM); - } } - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuRosterAdd( WPARAM wParam, LPARAM ) -{ - DBVARIANT dbv; - if ( !wParam ) return 0; // we do not add ourself to the roster. (buggy situation - should not happen) - if ( !JGetStringT( ( HANDLE ) wParam, "ChatRoomID", &dbv )) { - TCHAR *roomID = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - if ( ListGetItemPtr( LIST_ROSTER, roomID ) == NULL ) { - TCHAR *nick = 0; - TCHAR *group = 0; - if ( !DBGetContactSettingTString( ( HANDLE ) wParam, "CList", "Group", &dbv )) { - group = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - if ( !JGetStringT( ( HANDLE ) wParam, "Nick", &dbv )) { - nick = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - AddContactToRoster( roomID, nick, group ); - if ( m_options.AddRoster2Bookmarks == TRUE ) { - - JABBER_LIST_ITEM* item = NULL; - - item = ListGetItemPtr(LIST_BOOKMARK, roomID); - if (!item) { - item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); - ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); - item->jid = mir_tstrdup(roomID); - item->name = mir_tstrdup(nick); - if ( !JGetStringT( ( HANDLE ) wParam, "MyNick", &dbv )) { - item->nick = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - AddEditBookmark( item ); - mir_free(item); - } - } - if (nick) mir_free(nick); - if (nick) mir_free(group); - } - mir_free(roomID); - } - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleRequestAuth( WPARAM wParam, LPARAM ) -{ - HANDLE hContact; - DBVARIANT dbv; - - if (( hContact=( HANDLE ) wParam )!=NULL && m_bJabberOnline ) { - if ( !JGetStringT( hContact, "jid", &dbv )) { - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("subscribe"))); - JFreeVariant( &dbv ); - } } - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleGrantAuth( WPARAM wParam, LPARAM ) -{ - HANDLE hContact; - DBVARIANT dbv; - - if (( hContact=( HANDLE ) wParam )!=NULL && m_bJabberOnline ) { - if ( !JGetStringT( hContact, "jid", &dbv )) { - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("subscribed"))); - JFreeVariant( &dbv ); - } } - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuRevokeAuth( WPARAM wParam, LPARAM ) -{ - HANDLE hContact; - DBVARIANT dbv; - - if (( hContact=( HANDLE ) wParam ) != NULL && m_bJabberOnline ) { - if ( !JGetStringT( hContact, "jid", &dbv )) { - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("unsubscribed"))); - JFreeVariant( &dbv ); - } } - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuTransportLogin( WPARAM wParam, LPARAM ) -{ - HANDLE hContact = ( HANDLE )wParam; - if ( !JGetByte( hContact, "IsTransport", 0 )) - return 0; - - DBVARIANT jid; - if ( JGetStringT( hContact, "jid", &jid )) - return 0; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); - if ( item != NULL ) { - XmlNode p( _T("presence")); xmlAddAttr( p, _T("to"), item->jid ); - if ( item->itemResource.status == ID_STATUS_ONLINE ) - xmlAddAttr( p, _T("type"), _T("unavailable")); - m_ThreadInfo->send( p ); - } - - JFreeVariant( &jid ); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuTransportResolve( WPARAM wParam, LPARAM ) -{ - HANDLE hContact = ( HANDLE )wParam; - if ( !JGetByte( hContact, "IsTransport", 0 )) - return 0; - - DBVARIANT jid; - if ( !JGetStringT( hContact, "jid", &jid )) { - ResolveTransportNicks( jid.ptszVal ); - JFreeVariant( &jid ); - } - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuBookmarkAdd( WPARAM wParam, LPARAM ) -{ - DBVARIANT dbv; - if ( !wParam ) return 0; // we do not add ourself to the roster. (buggy situation - should not happen) - if ( !JGetStringT( ( HANDLE ) wParam, "ChatRoomID", &dbv )) { - TCHAR *roomID = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - if ( ListGetItemPtr( LIST_BOOKMARK, roomID ) == NULL ) { - TCHAR *nick = 0; - if ( !JGetStringT( ( HANDLE ) wParam, "Nick", &dbv )) { - nick = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - JABBER_LIST_ITEM* item = NULL; - - item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); - ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); - item->jid = mir_tstrdup(roomID); - item->name = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GCDNF_TCHAR ); - item->type = _T("conference"); - if ( !JGetStringT(( HANDLE ) wParam, "MyNick", &dbv )) { - item->nick = mir_tstrdup(dbv.ptszVal); - JFreeVariant( &dbv ); - } - AddEditBookmark( item ); - mir_free(item); - - if (nick) mir_free(nick); - } - mir_free(roomID); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// status menu - -void CJabberProto::MenuInit() -{ - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(CLISTMENUITEM); - - char text[ 200 ]; - strcpy( text, m_szModuleName ); - char* tDest = text + strlen( text ); - mi.pszService = text; - - HGENMENU hJabberRoot = MO_GetProtoRootMenu( m_szModuleName ); - if ( hJabberRoot == NULL ) { - mi.ptszName = m_tszUserName; - mi.position = -1999901006; - mi.hParentMenu = HGENMENU_ROOT; - mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - mi.icolibItem = GetIconHandle( IDI_JABBER ); - hJabberRoot = m_hMenuRoot = Menu_AddProtoMenuItem(&mi); - } - else { - if ( m_hMenuRoot ) - CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )m_hMenuRoot, 0 ); - m_hMenuRoot = NULL; - } - - // "Bookmarks..." - JCreateService( "/Bookmarks", &CJabberProto::OnMenuHandleBookmarks ); - strcpy( tDest, "/Bookmarks" ); - mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; - mi.hParentMenu = hJabberRoot; - mi.pszName = LPGEN("Bookmarks"); - mi.position = 200001; - mi.icolibItem = GetIconHandle( IDI_BOOKMARKS ); - m_hMenuBookmarks = Menu_AddProtoMenuItem(&mi); - - // "Options..." - JCreateService( "/Options", &CJabberProto::OnMenuOptions ); - strcpy( tDest, "/Options" ); - mi.pszName = LPGEN("Options..."); - mi.position = 200002; - mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_OPTIONS); - Menu_AddProtoMenuItem(&mi); - - // "Services..." - mi.pszName = LPGEN("Services..."); - strcpy( tDest, "/Services" ); - mi.position = 200003; - mi.icolibItem = GetIconHandle( IDI_SERVICE_DISCOVERY ); - HGENMENU hMenuServicesRoot = Menu_AddProtoMenuItem(&mi); - - // "Service Discovery..." - JCreateService( "/ServiceDiscovery", &CJabberProto::OnMenuHandleServiceDiscovery ); - strcpy( tDest, "/ServiceDiscovery" ); - mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTHANDLE; - mi.pszName = LPGEN("Service Discovery"); - mi.position = 2000050001; - mi.icolibItem = GetIconHandle( IDI_SERVICE_DISCOVERY ); - mi.hParentMenu = hMenuServicesRoot; - m_hMenuServiceDiscovery = Menu_AddProtoMenuItem(&mi); - - JCreateService( "/SD/MyTransports", &CJabberProto::OnMenuHandleServiceDiscoveryMyTransports ); - strcpy( tDest, "/SD/MyTransports" ); - mi.pszName = LPGEN("Registered Transports"); - mi.position = 2000050003; - mi.icolibItem = GetIconHandle( IDI_TRANSPORTL ); - m_hMenuSDMyTransports = Menu_AddProtoMenuItem(&mi); - - JCreateService( "/SD/Transports", &CJabberProto::OnMenuHandleServiceDiscoveryTransports ); - strcpy( tDest, "/SD/Transports" ); - mi.pszName = LPGEN("Local Server Transports"); - mi.position = 2000050004; - mi.icolibItem = GetIconHandle( IDI_TRANSPORT ); - m_hMenuSDTransports = Menu_AddProtoMenuItem(&mi); - - JCreateService( "/SD/Conferences", &CJabberProto::OnMenuHandleServiceDiscoveryConferences ); - strcpy( tDest, "/SD/Conferences" ); - mi.pszName = LPGEN("Browse Chatrooms"); - mi.position = 2000050005; - mi.icolibItem = GetIconHandle( IDI_GROUP ); - m_hMenuSDConferences = Menu_AddProtoMenuItem(&mi); - - JCreateService( "/Groupchat", &CJabberProto::OnMenuHandleJoinGroupchat ); - strcpy( tDest, "/Groupchat" ); - mi.pszName = LPGEN("Create/Join groupchat"); - mi.position = 2000050006; - mi.icolibItem = GetIconHandle( IDI_GROUP ); - m_hMenuGroupchat = Menu_AddProtoMenuItem(&mi); - - // "Change Password..." - JCreateService( "/ChangePassword", &CJabberProto::OnMenuHandleChangePassword ); - strcpy( tDest, "/ChangePassword" ); - mi.pszName = LPGEN("Change Password"); - mi.position = 2000050007; - mi.icolibItem = GetIconHandle( IDI_KEYS ); - m_hMenuChangePassword = Menu_AddProtoMenuItem(&mi); - - // "Roster editor" - JCreateService( "/RosterEditor", &CJabberProto::OnMenuHandleRosterControl ); - strcpy( tDest, "/RosterEditor" ); - mi.pszName = LPGEN("Roster editor"); - mi.position = 2000050009; - mi.icolibItem = GetIconHandle( IDI_AGENTS ); - m_hMenuRosterControl = Menu_AddProtoMenuItem(&mi); - - // "XML Console" - JCreateService( "/XMLConsole", &CJabberProto::OnMenuHandleConsole ); - strcpy( tDest, "/XMLConsole" ); - mi.pszName = LPGEN("XML Console"); - mi.position = 2000050010; - mi.icolibItem = GetIconHandle( IDI_CONSOLE ); - Menu_AddProtoMenuItem(&mi); - - JCreateService( "/Notes", &CJabberProto::OnMenuHandleNotes ); - strcpy( tDest, "/Notes" ); - mi.pszName = LPGEN("Notes"); - mi.position = 2000050011; - mi.icolibItem = GetIconHandle( IDI_NOTES); - m_hMenuNotes = Menu_AddProtoMenuItem(&mi); - - BuildPrivacyMenu(); - if ( m_menuItemsStatus ) - BuildPrivacyListsMenu( false ); - - ////////////////////////////////////////////////////////////////////////////////////// - // build priority menu - - m_priorityMenuVal = 0; - m_priorityMenuValSet = false; - - mi.position = 200006; - mi.pszContactOwner = m_szModuleName; - mi.hParentMenu = hJabberRoot; - mi.pszName = LPGEN("Resource priority"); - mi.flags = CMIF_ROOTPOPUP | CMIF_HIDDEN; - m_hMenuPriorityRoot = Menu_AddProtoMenuItem(&mi); - - char szName[128], srvFce[MAX_PATH + 64], *svcName = srvFce+strlen( m_szModuleName ); - mi.pszService = srvFce; - mi.pszName = szName; - mi.position = 2000040000; - mi.flags = CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB; - mi.hParentMenu = m_hMenuPriorityRoot; - - mir_snprintf(srvFce, sizeof(srvFce), "%s/menuSetPriority/0", m_szModuleName); - bool needServices = !ServiceExists(srvFce); - if ( needServices ) - JCreateServiceParam(svcName, &CJabberProto::OnMenuSetPriority, (LPARAM)0); - - int steps[] = { 10, 5, 1, 0, -1, -5, -10 }; - for (int i = 0; i < SIZEOF(steps); ++i) { - if ( !steps[i] ) { - mi.position += 100000; - continue; - } - - mi.icolibItem = (steps[i] > 0) ? GetIconHandle(IDI_ARROW_UP) : GetIconHandle(IDI_ARROW_DOWN); - - mir_snprintf(srvFce, sizeof(srvFce), "%s/menuSetPriority/%d", m_szModuleName, steps[i]); - mir_snprintf(szName, sizeof(szName), (steps[i] > 0) ? "Increase priority by %d" : "Decrease priority by %d", abs(steps[i])); - - if ( needServices ) - JCreateServiceParam(svcName, &CJabberProto::OnMenuSetPriority, (LPARAM)steps[i]); - - mi.position++; - Menu_AddProtoMenuItem(&mi); - } - - UpdatePriorityMenu((short)JGetWord(NULL, "Priority", 0)); - - ////////////////////////////////////////////////////////////////////////////////////// - // finalize status menu - - m_pepServices.RebuildMenu(); - CheckMenuItems(); -} - -////////////////////////////////////////////////////////////////////////// -// priority popup in status menu - -INT_PTR CJabberProto::OnMenuSetPriority(WPARAM, LPARAM, LPARAM dwDelta) -{ - int iDelta = (int)dwDelta; - short priority = 0; - priority = (short)JGetWord(NULL, "Priority", 0) + iDelta; - if (priority > 127) priority = 127; - else if (priority < -128) priority = -128; - JSetWord(NULL, "Priority", priority); - SendPresence(m_iStatus, true); - return 0; -} - -void CJabberProto::UpdatePriorityMenu(short priority) -{ - if (!m_hMenuPriorityRoot || m_priorityMenuValSet && (priority == m_priorityMenuVal)) - return; - - TCHAR szName[128]; - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(mi); - mi.flags = CMIF_TCHAR | CMIM_NAME; - mi.ptszName = szName; - mir_sntprintf(szName, SIZEOF(szName), TranslateT("Resource priority [%d]"), (int)priority); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)m_hMenuPriorityRoot, (LPARAM)&mi); - - m_priorityMenuVal = priority; - m_priorityMenuValSet = true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CJabberProto::GlobalMenuInit() -{ - ////////////////////////////////////////////////////////////////////////////////////// - // Account chooser menu - - TMO_MenuItem tmi = { 0 }; - tmi.cbSize = sizeof(tmi); - tmi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - tmi.ownerdata = this; - tmi.position = iChooserMenuPos++; - tmi.ptszName = m_tszUserName; - m_hChooseMenuItem = (HANDLE)CallService( MO_ADDNEWMENUITEM, (WPARAM)hChooserMenu, ( LPARAM )&tmi ); - - ////////////////////////////////////////////////////////////////////////////////////// - // Hotkeys - - char text[ 200 ]; - strcpy( text, m_szModuleName ); - char* tDest = text + strlen( text ); - - HOTKEYDESC hkd = {0}; - hkd.cbSize = sizeof(hkd); - hkd.pszName = text; - hkd.pszService = text; - hkd.ptszSection = m_tszUserName; - hkd.dwFlags = HKD_TCHAR; - - strcpy(tDest, "/Groupchat"); - hkd.ptszDescription = _T("Join conference"); - Hotkey_Register(&hkd); - - strcpy(tDest, "/Bookmarks"); - hkd.ptszDescription = _T("Open bookmarks"); - Hotkey_Register(&hkd); - - strcpy(tDest, "/PrivacyLists"); - hkd.ptszDescription = _T("Privacy lists"); - Hotkey_Register(&hkd); - - strcpy(tDest, "/ServiceDiscovery"); - hkd.ptszDescription = _T("Service discovery"); - Hotkey_Register(&hkd); -} - -static INT_PTR g_ToolbarHandleJoinGroupchat(WPARAM w, LPARAM l) -{ - if (CJabberProto *ppro = JabberChooseInstance()) - return ppro->OnMenuHandleJoinGroupchat(w, l); - return 0; -} - -static INT_PTR g_ToolbarHandleBookmarks(WPARAM w, LPARAM l) -{ - if (CJabberProto *ppro = JabberChooseInstance()) - return ppro->OnMenuHandleBookmarks(w, l); - return 0; -} - -static INT_PTR g_ToolbarHandleServiceDiscovery(WPARAM w, LPARAM l) -{ - if (CJabberProto *ppro = JabberChooseInstance()) - return ppro->OnMenuHandleServiceDiscovery(w, l); - return 0; -} - -int g_OnToolbarInit(WPARAM, LPARAM) -{ - if ( g_Instances.getCount() == 0 ) - return 0; - - TTBButton button = {0}; - button.cbSize = sizeof(button); - button.dwFlags = TTBBF_SHOWTOOLTIP | TTBBF_VISIBLE; - - List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/Groupchat", g_ToolbarHandleJoinGroupchat )); - button.pszService = "JABBER/*/Groupchat"; - button.pszTooltipUp = button.name = LPGEN("Join conference"); - button.hIconHandleUp = g_GetIconHandle(IDI_GROUP); - TopToolbar_AddButton(&button); - - List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/Bookmarks", g_ToolbarHandleBookmarks )); - button.pszService = "JABBER/*/Bookmarks"; - button.pszTooltipUp = button.name = LPGEN("Open bookmarks"); - button.hIconHandleUp = g_GetIconHandle(IDI_BOOKMARKS); - TopToolbar_AddButton(&button); - - List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/ServiceDiscovery", g_ToolbarHandleServiceDiscovery )); - button.pszService = "JABBER/*/ServiceDiscovery"; - button.pszTooltipUp = button.name = LPGEN("Service discovery"); - button.hIconHandleUp = g_GetIconHandle(IDI_SERVICE_DISCOVERY); - TopToolbar_AddButton(&button); - return 0; -} - -void CJabberProto::GlobalMenuUninit() -{ - if ( m_phMenuResourceItems ) { - for ( int i=0; i < m_nMenuResourceItems; i++ ) - CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )m_phMenuResourceItems[i], 0 ); - mir_free(m_phMenuResourceItems); - m_phMenuResourceItems = NULL; - } - m_nMenuResourceItems = 0; - - if ( m_hMenuRoot ) - CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )m_hMenuRoot, 0 ); - m_hMenuRoot = NULL; -} - -void CJabberProto::EnableMenuItems( BOOL bEnable ) -{ - m_menuItemsStatus = bEnable; - CheckMenuItems(); -} - -void CJabberProto::CheckMenuItems() -{ - CLISTMENUITEM clmi = { 0 }; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_FLAGS; - if ( !m_menuItemsStatus ) - clmi.flags |= CMIF_GRAYED; - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuChangePassword, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuGroupchat, ( LPARAM )&clmi ); - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuPrivacyLists, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuRosterControl, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuServiceDiscovery, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDMyTransports, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDTransports, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDConferences, ( LPARAM )&clmi ); - - clmi.flags = CMIM_FLAGS | (( m_ThreadInfo && ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE)) ? 0 : CMIF_HIDDEN ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuBookmarks, ( LPARAM )&clmi ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuNotes, ( LPARAM )&clmi ); - - clmi.flags = CMIM_FLAGS | (( m_ThreadInfo && ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVACY_LISTS)) ? 0 : CMIF_HIDDEN ); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hPrivacyMenuRoot, ( LPARAM )&clmi ); - - clmi.flags = CMIM_FLAGS | ( m_menuItemsStatus ? 0 : CMIF_HIDDEN); - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuPriorityRoot, ( LPARAM )&clmi ); - - if ( !m_bPepSupported ) - clmi.flags |= CMIF_HIDDEN; - for ( int i=0; i < m_pepServices.getCount(); i++ ) - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_pepServices[i].GetMenu(), ( LPARAM )&clmi ); - - JabberUpdateDialogs( m_menuItemsStatus ); -} - -////////////////////////////////////////////////////////////////////////// -// resource menu - -static HANDLE hDialogsList = NULL; - -void CJabberProto::MenuHideSrmmIcon(HANDLE hContact) -{ - StatusIconData sid = {0}; - sid.cbSize = sizeof(sid); - sid.szModule = m_szModuleName; - sid.flags = MBF_HIDDEN; - CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid); -} - -void CJabberProto::MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item) -{ - if ( item->list != LIST_ROSTER || !ServiceExists( MS_MSG_MODIFYICON )) - return; - - HANDLE hContact = HContactFromJID(item->jid); - if ( !hContact ) - return; - - StatusIconData sid = {0}; - sid.cbSize = sizeof(sid); - sid.szModule = m_szModuleName; - sid.flags = item->resourceCount ? 0 : MBF_HIDDEN; - CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid); -} - -int CJabberProto::OnProcessSrmmEvent( WPARAM, LPARAM lParam ) -{ - MessageWindowEventData *event = (MessageWindowEventData *)lParam; - - if ( event->uType == MSG_WINDOW_EVT_OPEN ) { - if ( !hDialogsList ) - hDialogsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); - WindowList_Add(hDialogsList, event->hwndWindow, event->hContact); - } - else if ( event->uType == MSG_WINDOW_EVT_CLOSING ) { - if (hDialogsList) - WindowList_Remove(hDialogsList, event->hwndWindow); - - DBVARIANT dbv; - BOOL bSupportTyping = FALSE; - if ( !DBGetContactSetting( event->hContact, "SRMsg", "SupportTyping", &dbv )) { - bSupportTyping = dbv.bVal == 1; - JFreeVariant( &dbv ); - } else if ( !DBGetContactSetting( NULL, "SRMsg", "DefaultTyping", &dbv )) { - bSupportTyping = dbv.bVal == 1; - JFreeVariant( &dbv ); - } - if ( bSupportTyping && !JGetStringT( event->hContact, "jid", &dbv )) { - TCHAR jid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, jid, SIZEOF( jid )); - JFreeVariant( &dbv ); - - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( jid ); - - if ( r && r->bMessageSessionActive ) { - r->bMessageSessionActive = FALSE; - JabberCapsBits jcb = GetResourceCapabilites( jid, TRUE ); - - if ( jcb & JABBER_CAPS_CHATSTATES ) { - int iqId = SerialNext(); - m_ThreadInfo->send( - XmlNode( _T("message")) << XATTR( _T("to"), jid ) << XATTR( _T("type"), _T("chat")) << XATTRID( iqId ) - << XCHILDNS( _T("gone"), _T(JABBER_FEAT_CHATSTATES))); - } } } } - - return 0; -} - -int CJabberProto::OnProcessSrmmIconClick( WPARAM wParam, LPARAM lParam ) -{ - StatusIconClickData *sicd = (StatusIconClickData *)lParam; - if (lstrcmpA(sicd->szModule, m_szModuleName)) - return 0; - - HANDLE hContact = (HANDLE)wParam; - if (!hContact) - return 0; - - DBVARIANT dbv; - if (JGetStringT(hContact, "jid", &dbv)) - return 0; - - JABBER_LIST_ITEM *LI = ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); - JFreeVariant( &dbv ); - - if ( !LI ) - return 0; - - HMENU hMenu = CreatePopupMenu(); - TCHAR buf[256]; - - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%s)"), TranslateT("Last active"), - ((LI->lastSeenResource>=0) && (LI->lastSeenResource < LI->resourceCount)) ? - LI->resource[LI->lastSeenResource].resourceName : TranslateT("No activity yet, use server's choice")); - AppendMenu(hMenu, MF_STRING, MENUITEM_LASTSEEN, buf); - - AppendMenu(hMenu, MF_STRING, MENUITEM_SERVER, TranslateT("Highest priority (server's choice)")); - - AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); - for (int i = 0; i < LI->resourceCount; ++i) - AppendMenu(hMenu, MF_STRING, MENUITEM_RESOURCES+i, LI->resource[i].resourceName); - - if (LI->resourceMode == RSMODE_LASTSEEN) - CheckMenuItem(hMenu, MENUITEM_LASTSEEN, MF_BYCOMMAND|MF_CHECKED); - else if (LI->resourceMode == RSMODE_SERVER) - CheckMenuItem(hMenu, MENUITEM_SERVER, MF_BYCOMMAND|MF_CHECKED); - else - CheckMenuItem(hMenu, MENUITEM_RESOURCES+LI->manualResource, MF_BYCOMMAND|MF_CHECKED); - - int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, sicd->clickLocation.x, sicd->clickLocation.y, 0, WindowList_Find(hDialogsList, hContact), NULL); - - if ( res == MENUITEM_LASTSEEN ) { - LI->manualResource = -1; - LI->resourceMode = RSMODE_LASTSEEN; - } - else if (res == MENUITEM_SERVER) { - LI->manualResource = -1; - LI->resourceMode = RSMODE_SERVER; - } - else if (res >= MENUITEM_RESOURCES) { - LI->manualResource = res - MENUITEM_RESOURCES; - LI->resourceMode = RSMODE_MANUAL; - } - - UpdateMirVer(LI); - MenuUpdateSrmmIcon(LI); - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleResource(WPARAM wParam, LPARAM, LPARAM res) -{ - if ( !m_bJabberOnline || !wParam ) - return 0; - - HANDLE hContact = (HANDLE)wParam; - - DBVARIANT dbv; - if (JGetStringT(hContact, "jid", &dbv)) - return 0; - - JABBER_LIST_ITEM *LI = ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); - JFreeVariant( &dbv ); - - if ( !LI ) - return 0; - - if ( res == MENUITEM_LASTSEEN ) { - LI->manualResource = -1; - LI->resourceMode = RSMODE_LASTSEEN; - } - else if (res == MENUITEM_SERVER) { - LI->manualResource = -1; - LI->resourceMode = RSMODE_SERVER; - } - else if (res >= MENUITEM_RESOURCES) { - LI->manualResource = res - MENUITEM_RESOURCES; - LI->resourceMode = RSMODE_MANUAL; - } - - UpdateMirVer(LI); - MenuUpdateSrmmIcon(LI); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleDirectPresence(WPARAM wParam, LPARAM lParam, LPARAM res) -{ - if ( !m_bJabberOnline || !wParam ) - return 0; - - HANDLE hContact = (HANDLE)wParam; - - TCHAR *jid, text[ 1024 ]; - - DBVARIANT dbv; - int result = JGetStringT( hContact, "jid", &dbv ); - if (result) - { - result = JGetStringT( hContact, "ChatRoomID", &dbv ); - if ( result ) return 0; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, dbv.ptszVal ); - if ( !item ) return 0; - - mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, item->nick ); - jid = text; - } - else - jid = dbv.ptszVal; - - TCHAR buf[1024] = _T(""); - EnterString(buf, SIZEOF(buf), TranslateT("Status Message"), JES_MULTINE); - - SendPresenceTo(res, jid, NULL, buf); - JFreeVariant(&dbv); - return 0; -} - -//////////////////////////////////////////////////////////////////////// -// Choose protocol instance -CJabberProto *JabberChooseInstance(bool bIsLink) -{ - if ( g_Instances.getCount() == 0 ) - return NULL; - - if ( g_Instances.getCount() == 1 ) { - if ( g_Instances[0]->m_iStatus != ID_STATUS_OFFLINE && g_Instances[0]->m_iStatus != ID_STATUS_CONNECTING ) - return g_Instances[0]; - return NULL; - } - - if ( bIsLink ) { - for ( int i = 0; i < g_Instances.getCount(); i++ ) - if ( g_Instances[i]->m_options.ProcessXMPPLinks ) - return g_Instances[i]; - } - - CLISTMENUITEM clmi = {0}; - clmi.cbSize = sizeof(CLISTMENUITEM); - - int nItems = 0, lastItemId = 0; - for (int i = 0; i < g_Instances.getCount(); ++i) { - clmi.flags = CMIM_FLAGS; - - CJabberProto* ppro = g_Instances[i]; - if ( ppro->m_iStatus != ID_STATUS_OFFLINE && ppro->m_iStatus != ID_STATUS_CONNECTING ) { - ++nItems; - lastItemId = i+1; - clmi.flags |= CMIM_ICON; - clmi.hIcon = LoadSkinnedProtoIcon(ppro->m_szModuleName, ppro->m_iStatus); - } - else clmi.flags |= CMIF_HIDDEN; - - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )ppro->m_hChooseMenuItem, ( LPARAM )&clmi ); - } - - if ( nItems > 1 ) { - ListParam param = { 0 }; - param.MenuObjectHandle = hChooserMenu; - HMENU hMenu = CreatePopupMenu(); - CallService( MO_BUILDMENU, ( WPARAM )hMenu, ( LPARAM )¶m ); - - POINT pt; - GetCursorPos(&pt); - - int res = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, pcli->hwndContactList, NULL ); - DestroyMenu( hMenu ); - - if ( res ) { - CJabberProto* pro = NULL; - CallService( MO_PROCESSCOMMANDBYMENUIDENT, res, ( LPARAM )&pro ); - return pro; - } - - return NULL; - } - - return lastItemId ? g_Instances[lastItemId-1] : NULL; -} diff --git a/protocols/JabberG/jabber_message_handlers.cpp b/protocols/JabberG/jabber_message_handlers.cpp deleted file mode 100644 index a3801f274f..0000000000 --- a/protocols/JabberG/jabber_message_handlers.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_message_manager.h" - -BOOL CJabberProto::OnMessageError( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) -{ - // we check if is message delivery failure - int id = JabberGetPacketID( node ); - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, pInfo->GetFrom()); - if ( item == NULL ) - item = ListGetItemPtr( LIST_CHATROOM, pInfo->GetFrom()); - if ( item != NULL ) { // yes, it is - TCHAR *szErrText = JabberErrorMsg( pInfo->GetChildNode()); - if ( id != -1 ) { - char *errText = mir_t2a(szErrText); - JSendBroadcast( pInfo->GetHContact(), ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) id, (LPARAM)errText ); - mir_free(errText); - } else { - TCHAR buf[512]; - HXML bodyNode = xmlGetChild( node, "body" ); - if (bodyNode) - mir_sntprintf( buf, SIZEOF( buf ), _T( "%s:\n%s\n%s" ), pInfo->GetFrom(), xmlGetText( bodyNode ), szErrText ); - else - mir_sntprintf( buf, SIZEOF( buf ), _T( "%s:\n%s" ), pInfo->GetFrom(), szErrText ); - - MsgPopup( NULL, buf, TranslateT( "Jabber Error" )); - } - mir_free(szErrText); - } - return TRUE; -} - -BOOL CJabberProto::OnMessageIbb( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) -{ - BOOL bOk = FALSE; - const TCHAR *sid = xmlGetAttrValue( pInfo->GetChildNode(), _T("sid")); - const TCHAR *seq = xmlGetAttrValue( pInfo->GetChildNode(), _T("seq")); - if ( sid && seq && xmlGetText( pInfo->GetChildNode()) ) { - bOk = OnIbbRecvdData( xmlGetText( pInfo->GetChildNode()), sid, seq ); - } - return TRUE; -} - -BOOL CJabberProto::OnMessagePubsubEvent( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) -{ - OnProcessPubsubEvent( node ); - return TRUE; -} - -BOOL CJabberProto::OnMessageGroupchat( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) -{ - JABBER_LIST_ITEM *chatItem = ListGetItemPtr( LIST_CHATROOM, pInfo->GetFrom()); - if ( chatItem ) - { // process GC message - GroupchatProcessMessage( node ); - } else - { // got message from unknown conference... let's leave it :) -// TCHAR *conference = NEWTSTR_ALLOCA(from); -// if (TCHAR *s = _tcschr(conference, _T('/'))) *s = 0; -// XmlNode p( "presence" ); xmlAddAttr( p, "to", conference ); xmlAddAttr( p, "type", "unavailable" ); -// info->send( p ); - } - return TRUE; -} diff --git a/protocols/JabberG/jabber_message_manager.cpp b/protocols/JabberG/jabber_message_manager.cpp deleted file mode 100644 index 67e9982eb3..0000000000 --- a/protocols/JabberG/jabber_message_manager.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_message_manager.h" - -BOOL CJabberMessageManager::FillPermanentHandlers() -{ - AddPermanentHandler( &CJabberProto::OnMessageError, JABBER_MESSAGE_TYPE_ERROR, JABBER_MESSAGE_PARSE_FROM | JABBER_MESSAGE_PARSE_HCONTACT, NULL, FALSE, _T("error")); - AddPermanentHandler( &CJabberProto::OnMessageIbb, 0, 0, _T(JABBER_FEAT_IBB), FALSE, _T("data")); - AddPermanentHandler( &CJabberProto::OnMessagePubsubEvent, 0, 0, _T(JABBER_FEAT_PUBSUB_EVENT), FALSE, _T("event")); - AddPermanentHandler( &CJabberProto::OnMessageGroupchat, JABBER_MESSAGE_TYPE_GROUPCHAT, JABBER_MESSAGE_PARSE_FROM, NULL, FALSE, NULL ); - return TRUE; -} - -BOOL CJabberMessageManager::HandleMessagePermanent(HXML node, ThreadData *pThreadData) -{ - BOOL bStopHandling = FALSE; - Lock(); - CJabberMessagePermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo && !bStopHandling ) { - // have to get all data here, in the loop, because there's always possibility that previous handler modified it - CJabberMessageInfo messageInfo; - - LPCTSTR szType = xmlGetAttrValue(node, _T("type")); - if ( szType ) - { - if ( !_tcsicmp( szType, _T("normal"))) - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_NORMAL; - else if ( !_tcsicmp( szType, _T("error"))) - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_ERROR; - else if ( !_tcsicmp( szType, _T("chat"))) - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_CHAT; - else if ( !_tcsicmp( szType, _T("groupchat"))) - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_GROUPCHAT; - else if ( !_tcsicmp( szType, _T("headline"))) - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_HEADLINE; - else - break; // m_nMessageType = JABBER_MESSAGE_TYPE_FAIL; - } - else { - messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_NORMAL; - } - - if ( (pInfo->m_nMessageTypes & messageInfo.m_nMessageType )) { - int i; - for ( i = xmlGetChildCount( node ) - 1; i >= 0; i-- ) { - // enumerate all children and see whether this node suits handler criteria - HXML child = xmlGetChild( node, i ); - - LPCTSTR szTagName = xmlGetName(child); - LPCTSTR szXmlns = xmlGetAttrValue( child, _T("xmlns")); - - if ( (!pInfo->m_szXmlns || ( szXmlns && !_tcscmp( pInfo->m_szXmlns, szXmlns ))) && - ( !pInfo->m_szTag || !_tcscmp( pInfo->m_szTag, szTagName ))) { - // node suits handler criteria, call the handler - messageInfo.m_hChildNode = child; - messageInfo.m_szChildTagName = szTagName; - messageInfo.m_szChildTagXmlns = szXmlns; - messageInfo.m_pUserData = pInfo->m_pUserData; - messageInfo.m_szFrom = xmlGetAttrValue( node, _T("from")); // is necessary for ppro->Log() below, that's why we must parse it even if JABBER_MESSAGE_PARSE_FROM flag is not set - - if (pInfo->m_dwParamsToParse & JABBER_MESSAGE_PARSE_ID_STR) - messageInfo.m_szId = xmlGetAttrValue( node, _T("id")); - - if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) - messageInfo.m_szTo = xmlGetAttrValue( node, _T("to")); - - if (pInfo->m_dwParamsToParse & JABBER_MESSAGE_PARSE_HCONTACT) - messageInfo.m_hContact = ppro->HContactFromJID( messageInfo.m_szFrom, 3 ); - - if (messageInfo.m_szFrom) - ppro->Log( "Handling message from " TCHAR_STR_PARAM, messageInfo.m_szFrom ); - if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &messageInfo)) { - bStopHandling = TRUE; - break; - } - } - } - } - pInfo = pInfo->m_pNext; - } - Unlock(); - - return bStopHandling; -} diff --git a/protocols/JabberG/jabber_message_manager.h b/protocols/JabberG/jabber_message_manager.h deleted file mode 100644 index dd52b50683..0000000000 --- a/protocols/JabberG/jabber_message_manager.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_MESSAGE_MANAGER_H_ -#define _JABBER_MESSAGE_MANAGER_H_ - -#include "jabber_xml.h" - -struct CJabberProto; -typedef void ( CJabberProto::*JABBER_MESSAGE_PFUNC )( HXML messageNode, void *usedata ); -typedef void ( *MESSAGE_USER_DATA_FREE_FUNC )( void *pUserData ); - -class CJabberMessageInfo; - -typedef BOOL ( CJabberProto::*JABBER_PERMANENT_MESSAGE_HANDLER )( HXML messageNode, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - -#define JABBER_MESSAGE_PARSE_FROM (1<<3) -#define JABBER_MESSAGE_PARSE_HCONTACT ((1<<4)|JABBER_MESSAGE_PARSE_FROM) -#define JABBER_MESSAGE_PARSE_TO (1<<5) -#define JABBER_MESSAGE_PARSE_ID_STR (1<<6) - -class CJabberMessageInfo -{ -protected: - friend class CJabberMessageManager; - JABBER_PERMANENT_MESSAGE_HANDLER m_pHandler; - CJabberMessageInfo* m_pNext; - -public: - void *m_pUserData; -// parsed data - int m_nMessageType; - LPCTSTR m_szFrom; - LPCTSTR m_szChildTagXmlns; - LPCTSTR m_szChildTagName; - HXML m_hChildNode; - HANDLE m_hContact; - LPCTSTR m_szTo; - LPCTSTR m_szId; - -public: - CJabberMessageInfo() - { - ZeroMemory(this, sizeof(*this)); - } - ~CJabberMessageInfo() - { - } - int GetMessageType() - { - return m_nMessageType; - } - void* GetUserData() - { - return m_pUserData; - } - LPCTSTR GetFrom() - { - return m_szFrom; - } - LPCTSTR GetTo() - { - return m_szTo; - } - LPCTSTR GetIdStr() - { - return m_szId; - } - HANDLE GetHContact() - { - return m_hContact; - } - HXML GetChildNode() - { - return m_hChildNode; - } - LPCTSTR GetChildNodeName() - { - return m_szChildTagName; - } -}; - -class CJabberMessagePermanentInfo -{ - friend class CJabberMessageManager; - - CJabberMessagePermanentInfo* m_pNext; - - JABBER_PERMANENT_MESSAGE_HANDLER m_pHandler; - DWORD m_dwParamsToParse; - int m_nMessageTypes; - LPTSTR m_szXmlns; - LPTSTR m_szTag; - BOOL m_bAllowPartialNs; - void *m_pUserData; - MESSAGE_USER_DATA_FREE_FUNC m_pUserDataFree; - int m_iPriority; -public: - CJabberMessagePermanentInfo() - { - ZeroMemory(this, sizeof(CJabberMessagePermanentInfo)); - } - ~CJabberMessagePermanentInfo() - { - if ( m_pUserDataFree ) - m_pUserDataFree(m_pUserData); - mir_free(m_szXmlns); - mir_free(m_szTag); - } -}; - -class CJabberMessageManager -{ -protected: - CJabberProto* ppro; - CRITICAL_SECTION m_cs; - CJabberMessagePermanentInfo* m_pPermanentHandlers; - -public: - CJabberMessageManager( CJabberProto* proto ) - { - InitializeCriticalSection(&m_cs); - m_pPermanentHandlers = NULL; - ppro = proto; - } - ~CJabberMessageManager() - { - Lock(); - CJabberMessagePermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo ) - { - CJabberMessagePermanentInfo *pTmp = pInfo->m_pNext; - delete pInfo; - pInfo = pTmp; - } - m_pPermanentHandlers = NULL; - Unlock(); - DeleteCriticalSection(&m_cs); - } - BOOL Start() - { - return TRUE; - } - BOOL Shutdown() - { - return TRUE; - } - void Lock() - { - EnterCriticalSection(&m_cs); - } - void Unlock() - { - LeaveCriticalSection(&m_cs); - } - CJabberMessagePermanentInfo* AddPermanentHandler(JABBER_PERMANENT_MESSAGE_HANDLER pHandler, int nMessageTypes, DWORD dwParamsToParse, const TCHAR* szXmlns, BOOL bAllowPartialNs, const TCHAR* szTag, void *pUserData = NULL, MESSAGE_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) - { - CJabberMessagePermanentInfo* pInfo = new CJabberMessagePermanentInfo(); - if (!pInfo) - return NULL; - - pInfo->m_pHandler = pHandler; - pInfo->m_nMessageTypes = nMessageTypes ? nMessageTypes : JABBER_MESSAGE_TYPE_ANY; - replaceStrT( pInfo->m_szXmlns, szXmlns ); - pInfo->m_bAllowPartialNs = bAllowPartialNs; - replaceStrT( pInfo->m_szTag, szTag ); - pInfo->m_dwParamsToParse = dwParamsToParse; - pInfo->m_pUserData = pUserData; - pInfo->m_pUserDataFree = pUserDataFree; - pInfo->m_iPriority = iPriority; - - Lock(); - if (!m_pPermanentHandlers) - m_pPermanentHandlers = pInfo; - else - { - if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { - pInfo->m_pNext = m_pPermanentHandlers; - m_pPermanentHandlers = pInfo; - } else - { - CJabberMessagePermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) - pTmp = pTmp->m_pNext; - pInfo->m_pNext = pTmp->m_pNext; - pTmp->m_pNext = pInfo; - } - } - Unlock(); - - return pInfo; - } - BOOL DeletePermanentHandler(CJabberMessagePermanentInfo *pInfo) - { // returns TRUE when pInfo found, or FALSE otherwise - Lock(); - if (!m_pPermanentHandlers) - { - Unlock(); - return FALSE; - } - if (m_pPermanentHandlers == pInfo) // check first item - { - m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } else - { - CJabberMessagePermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext) - { - if (pTmp->m_pNext == pInfo) - { - pTmp->m_pNext = pTmp->m_pNext->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } - pTmp = pTmp->m_pNext; - } - } - Unlock(); - return FALSE; - } - BOOL HandleMessagePermanent(HXML node, ThreadData *pThreadData); - BOOL FillPermanentHandlers(); -}; - -#endif diff --git a/protocols/JabberG/jabber_misc.cpp b/protocols/JabberG/jabber_misc.cpp deleted file mode 100644 index e13c0d450d..0000000000 --- a/protocols/JabberG/jabber_misc.cpp +++ /dev/null @@ -1,642 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" -#include "jabber_caps.h" - -#include <m_popup.h> -#include "m_folders.h" - -/////////////////////////////////////////////////////////////////////////////// -// JabberAddContactToRoster() - adds a contact to the roster - -void CJabberProto::AddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName ) -{ - XmlNodeIq iq( _T("set"), SerialNext()); - HXML query = iq << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) - << XCHILD( _T("item")) << XATTR( _T("jid"), jid ) << XATTR( _T("name"), nick ); - if ( grpName ) - query << XCHILD( _T("group"), grpName ); - m_ThreadInfo->send( iq ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberChatDllError() - missing CHAT.DLL - -void JabberChatDllError() -{ - MessageBox( NULL, - TranslateT( "CHAT plugin is required for conferences. Install it before chatting" ), - TranslateT( "Jabber Error" ), MB_OK|MB_SETFOREGROUND ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberCompareJids - -int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 ) -{ - if ( !lstrcmpi( jid1, jid2 )) - return 0; - - // match only node@domain part - TCHAR szTempJid1[ JABBER_MAX_JID_LEN ], szTempJid2[ JABBER_MAX_JID_LEN ]; - return lstrcmpi( - JabberStripJid( jid1, szTempJid1, SIZEOF(szTempJid1)), - JabberStripJid( jid2, szTempJid2, SIZEOF(szTempJid2))); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberContactListCreateGroup() - -static void JabberContactListCreateClistGroup( TCHAR* groupName ) -{ - char str[33]; - int i; - DBVARIANT dbv; - - for ( i=0;;i++ ) { - _itoa( i, str, 10 ); - if ( DBGetContactSettingTString( NULL, "CListGroups", str, &dbv )) - break; - TCHAR* name = dbv.ptszVal; - if ( name[0]!='\0' && !_tcscmp( name+1, groupName )) { - // Already exists, no need to create - JFreeVariant( &dbv ); - return; - } - JFreeVariant( &dbv ); - } - - // Create new group with id = i ( str is the text representation of i ) - TCHAR newName[128]; - newName[0] = 1 | GROUPF_EXPANDED; - _tcsncpy( newName+1, groupName, SIZEOF( newName )-1 ); - newName[ SIZEOF( newName )-1] = '\0'; - DBWriteContactSettingTString( NULL, "CListGroups", str, newName ); - CallService( MS_CLUI_GROUPADDED, i+1, 0 ); -} - -void JabberContactListCreateGroup( TCHAR* groupName ) -{ - TCHAR name[128], *p; - - if ( groupName==NULL || groupName[0]=='\0' || groupName[0]=='\\' ) return; - - _tcsncpy( name, groupName, SIZEOF( name )); - name[ SIZEOF( name )-1] = '\0'; - for ( p=name; *p!='\0'; p++ ) { - if ( *p == '\\' ) { - *p = '\0'; - JabberContactListCreateClistGroup( name ); - *p = '\\'; - } - } - JabberContactListCreateClistGroup( name ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberDBAddAuthRequest() - -void CJabberProto::DBAddAuthRequest( const TCHAR* jid, const TCHAR* nick ) -{ - HANDLE hContact = DBCreateContact( jid, NULL, TRUE, TRUE ); - JDeleteSetting( hContact, "Hidden" ); - //JSetStringT( hContact, "Nick", nick ); - - char* szJid = mir_utf8encodeT( jid ); - char* szNick = mir_utf8encodeT( nick ); - - //blob is: uin(DWORD), hContact(DWORD), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ) - //blob is: 0( DWORD ), hContact(DWORD), nick( ASCIIZ ), ""( ASCIIZ ), ""( ASCIIZ ), email( ASCIIZ ), ""( ASCIIZ ) - DBEVENTINFO dbei = { sizeof(DBEVENTINFO) }; - dbei.szModule = m_szModuleName; - dbei.timestamp = ( DWORD )time( NULL ); - dbei.flags = DBEF_UTF; - dbei.eventType = EVENTTYPE_AUTHREQUEST; - dbei.cbBlob = (DWORD)(sizeof(DWORD)*2 + strlen( szNick ) + strlen( szJid ) + 5); - PBYTE pCurBlob = dbei.pBlob = (PBYTE)mir_alloc(dbei.cbBlob); - *((PDWORD)pCurBlob) = 0; pCurBlob += sizeof(DWORD); - *((PDWORD)pCurBlob) = (DWORD)hContact; pCurBlob += sizeof(DWORD); - strcpy(( char* )pCurBlob, szNick ); pCurBlob += strlen( szNick )+1; - *pCurBlob = '\0'; pCurBlob++; //firstName - *pCurBlob = '\0'; pCurBlob++; //lastName - strcpy(( char* )pCurBlob, szJid ); pCurBlob += strlen( szJid )+1; - *pCurBlob = '\0'; //reason - - CallService( MS_DB_EVENT_ADD, ( WPARAM ) ( HANDLE ) NULL, ( LPARAM )&dbei ); - Log( "Setup DBAUTHREQUEST with nick='%s' jid='%s'", szNick, szJid ); - - mir_free( szJid ); - mir_free( szNick ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberDBCreateContact() - -HANDLE CJabberProto::DBCreateContact( const TCHAR* jid, const TCHAR* nick, BOOL temporary, BOOL stripResource ) -{ - TCHAR* s, *p, *q; - size_t len; - char* szProto; - - if ( jid==NULL || jid[0]=='\0' ) - return NULL; - - s = mir_tstrdup( jid ); - q = NULL; - // strip resource if present - if (( p = _tcschr( s, '@' )) != NULL ) - if (( q = _tcschr( p, '/' )) != NULL ) - *q = '\0'; - - if ( !stripResource && q!=NULL ) // so that resource is not stripped - *q = '/'; - len = _tcslen( s ); - - // We can't use JabberHContactFromJID() here because of the stripResource option - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto!=NULL && !strcmp( m_szModuleName, szProto )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - p = dbv.ptszVal; - if ( p && _tcslen( p )>=len && ( p[len]=='\0'||p[len]=='/' ) && !_tcsnicmp( p, s, len )) { - JFreeVariant( &dbv ); - break; - } - JFreeVariant( &dbv ); - } } - hContact = db_find_next(hContact); - } - - if ( hContact == NULL ) { - hContact = ( HANDLE ) CallService( MS_DB_CONTACT_ADD, 0, 0 ); - CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )m_szModuleName ); - JSetStringT( hContact, "jid", s ); - if ( nick != NULL && *nick != '\0' ) - JSetStringT( hContact, "Nick", nick ); - if ( temporary ) - DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); - else - SendGetVcard( s ); - Log( "Create Jabber contact jid=" TCHAR_STR_PARAM ", nick=" TCHAR_STR_PARAM, s, nick ); - DBCheckIsTransportedContact(s,hContact); - } - - mir_free( s ); - return hContact; -} - -BOOL CJabberProto::AddDbPresenceEvent(HANDLE hContact, BYTE btEventType) -{ - if ( !hContact ) - return FALSE; - - switch ( btEventType ) { - case JABBER_DB_EVENT_PRESENCE_SUBSCRIBE: - case JABBER_DB_EVENT_PRESENCE_SUBSCRIBED: - case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE: - case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED: - if ( !m_options.LogPresence ) - return FALSE; - break; - - case JABBER_DB_EVENT_PRESENCE_ERROR: - if ( !m_options.LogPresenceErrors ) - return FALSE; - break; - } - - DBEVENTINFO dbei; - dbei.cbSize = sizeof( dbei ); - dbei.pBlob = &btEventType; - dbei.cbBlob = sizeof( btEventType ); - dbei.eventType = JABBER_DB_EVENT_TYPE_PRESENCE; - dbei.flags = DBEF_READ; - dbei.timestamp = time( NULL ); - dbei.szModule = m_szModuleName; - CallService( MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei ); - - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberGetAvatarFileName() - gets a file name for the avatar image - -static HANDLE hJabberAvatarsFolder = NULL; -static bool bInitDone = false; - -void CJabberProto::InitCustomFolders( void ) -{ - if ( bInitDone ) - return; - - bInitDone = true; - if ( ServiceExists( MS_FOLDERS_REGISTER_PATH )) { - TCHAR AvatarsFolder[MAX_PATH]; - mir_sntprintf( AvatarsFolder, SIZEOF( AvatarsFolder ), _T("%%miranda_avatarcache%%\\Jabber")); - hJabberAvatarsFolder = FoldersRegisterCustomPathT( m_szModuleName, "Avatars", AvatarsFolder ); // title!!!!!!!!!!! -} } - -void CJabberProto::GetAvatarFileName( HANDLE hContact, TCHAR* pszDest, size_t cbLen ) -{ - size_t tPathLen; - TCHAR* path = ( TCHAR* )alloca( cbLen * sizeof( TCHAR )); - - InitCustomFolders(); - - if ( hJabberAvatarsFolder == NULL || FoldersGetCustomPathT( hJabberAvatarsFolder, path, (int)cbLen, _T(""))) { - TCHAR *tmpPath = Utils_ReplaceVarsT( _T("%miranda_avatarcache%")); - tPathLen = mir_sntprintf( pszDest, cbLen, _T("%s\\Jabber"), tmpPath ); - mir_free(tmpPath); - } - else tPathLen = mir_sntprintf( pszDest, cbLen, _T("%s"), path ); - - DWORD dwAttributes = GetFileAttributes( pszDest ); - if ( dwAttributes == 0xffffffff || ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) - CallService( MS_UTILS_CREATEDIRTREET, 0, ( LPARAM )pszDest ); - - pszDest[ tPathLen++ ] = '\\'; - - char* szFileType = NULL; - switch( JGetByte( hContact, "AvatarType", PA_FORMAT_PNG )) { - case PA_FORMAT_JPEG: szFileType = "jpg"; break; - case PA_FORMAT_PNG: szFileType = "png"; break; - case PA_FORMAT_GIF: szFileType = "gif"; break; - case PA_FORMAT_BMP: szFileType = "bmp"; break; - } - - if ( hContact != NULL ) { - char str[ 256 ]; - DBVARIANT dbv; - if ( !JGetStringUtf( hContact, "jid", &dbv )) { - strncpy( str, dbv.pszVal, sizeof str ); - str[ sizeof(str)-1 ] = 0; - JFreeVariant( &dbv ); - } - else _i64toa(( LONG_PTR )hContact, str, 10 ); - - char* hash = JabberSha1( str ); - mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T(TCHAR_STR_PARAM) _T(".") _T(TCHAR_STR_PARAM), hash, szFileType ); - mir_free( hash ); - } - else if ( m_ThreadInfo != NULL ) { - mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T("%s@") _T(TCHAR_STR_PARAM) _T(" avatar.") _T(TCHAR_STR_PARAM), - m_ThreadInfo->username, m_ThreadInfo->server, szFileType ); - } - else { - DBVARIANT dbv1, dbv2; - BOOL res1 = DBGetContactSettingString( NULL, m_szModuleName, "LoginName", &dbv1 ); - BOOL res2 = DBGetContactSettingString( NULL, m_szModuleName, "LoginServer", &dbv2 ); - mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T(TCHAR_STR_PARAM) _T("@") _T(TCHAR_STR_PARAM) _T(" avatar.") _T(TCHAR_STR_PARAM), - res1 ? "noname" : dbv1.pszVal, - res2 ? m_szModuleName : dbv2.pszVal, - szFileType ); - if (!res1) JFreeVariant( &dbv1 ); - if (!res2) JFreeVariant( &dbv2 ); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberResolveTransportNicks - massive vcard update - -void CJabberProto::ResolveTransportNicks( const TCHAR* jid ) -{ - // Set all contacts to offline - HANDLE hContact = m_ThreadInfo->resolveContact; - if ( hContact == NULL ) - hContact = ( HANDLE ) db_find_first(); - - for ( ; hContact != NULL; hContact = db_find_next(hContact)) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( lstrcmpA( szProto, m_szModuleName )) - continue; - - if ( !JGetByte( hContact, "IsTransported", 0 )) - continue; - - DBVARIANT dbv, nick; - if ( JGetStringT( hContact, "jid", &dbv )) - continue; - if ( JGetStringT( hContact, "Nick", &nick )) { - JFreeVariant( &dbv ); - continue; - } - - TCHAR* p = _tcschr( dbv.ptszVal, '@' ); - if ( p ) { - *p = 0; - if ( !lstrcmp( jid, p+1 ) && !lstrcmp( dbv.ptszVal, nick.ptszVal )) { - *p = '@'; - m_ThreadInfo->resolveID = SendGetVcard( dbv.ptszVal ); - m_ThreadInfo->resolveContact = hContact; - JFreeVariant( &dbv ); - JFreeVariant( &nick ); - return; - } } - - JFreeVariant( &dbv ); - JFreeVariant( &nick ); - } - - m_ThreadInfo->resolveID = -1; - m_ThreadInfo->resolveContact = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberSetServerStatus() - -void CJabberProto::SetServerStatus( int iNewStatus ) -{ - if ( !m_bJabberOnline ) - return; - - // change status - int oldStatus = m_iStatus; - switch ( iNewStatus ) { - case ID_STATUS_ONLINE: - case ID_STATUS_NA: - case ID_STATUS_FREECHAT: - case ID_STATUS_INVISIBLE: - m_iStatus = iNewStatus; - break; - case ID_STATUS_AWAY: - case ID_STATUS_ONTHEPHONE: - case ID_STATUS_OUTTOLUNCH: - m_iStatus = ID_STATUS_AWAY; - break; - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - m_iStatus = ID_STATUS_DND; - break; - default: - return; - } - - if ( m_iStatus == oldStatus ) - return; - - // send presence update - SendPresence( m_iStatus, true ); - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); -} - -// Process a string, and double all % characters, according to chat.dll's restrictions -// Returns a pointer to the new string (old one is not freed) -TCHAR* EscapeChatTags(TCHAR* pszText) -{ - int nChars = 0; - for ( TCHAR* p = pszText; ( p = _tcschr( p, '%' )) != NULL; p++ ) - nChars++; - - if ( nChars == 0 ) - return mir_tstrdup( pszText ); - - TCHAR* pszNewText = (TCHAR*)mir_alloc( sizeof(TCHAR)*(_tcslen( pszText ) + 1 + nChars )), *s, *d; - if ( pszNewText == NULL ) - return mir_tstrdup( pszText ); - - for ( s = pszText, d = pszNewText; *s; s++ ) { - if ( *s == '%' ) - *d++ = '%'; - *d++ = *s; - } - *d = 0; - return pszNewText; -} - -TCHAR* UnEscapeChatTags(TCHAR* str_in) -{ - TCHAR* s = str_in, *d = str_in; - while ( *s ) { - if ( *s == '%' && s[1] == '%' ) - s++; - *d++ = *s++; - } - *d = 0; - return str_in; -} - -////////////////////////////////////////////////////////////////////////// -// update MirVer with data for active resource - -struct -{ - TCHAR *node; - TCHAR *name; -} -static sttCapsNodeToName_Map[] = -{ - { _T("http://miranda-im.org"), _T("Miranda IM Jabber") }, - { _T("http://miranda-ng.org"), _T("Miranda NG Jabber") }, - { _T("http://www.google.com"), _T("GTalk") }, - { _T("http://mail.google.com"), _T("GMail") }, - { _T("http://talk.google.com/xmpp/bot"), _T("GTalk Bot") }, - { _T("http://www.android.com"), _T("Android") }, -}; - -void CJabberProto::UpdateMirVer(JABBER_LIST_ITEM *item) -{ - HANDLE hContact = HContactFromJID(item->jid); - if (!hContact) - return; - - Log("JabberUpdateMirVer: for jid " TCHAR_STR_PARAM, item->jid); - - int resource = -1; - if (item->resourceMode == RSMODE_LASTSEEN) - resource = item->lastSeenResource; - else if (item->resourceMode == RSMODE_MANUAL) - resource = item->manualResource; - if ((resource < 0) || (resource >= item->resourceCount)) - return; - - UpdateMirVer( hContact, &item->resource[resource] ); -} - -void CJabberProto::FormatMirVer(JABBER_RESOURCE_STATUS *resource, TCHAR *buf, int bufSize) -{ - if ( !buf || !bufSize ) return; - buf[ 0 ] = _T('\0'); - if ( !resource ) return; - - // jabber:iq:version info requested and exists? - if ( resource->dwVersionRequestTime && resource->software ) { - Log("JabberUpdateMirVer: for iq:version rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM, resource->resourceName, resource->software); - if ( !resource->version || _tcsstr(resource->software, resource->version)) - lstrcpyn(buf, resource->software, bufSize); - else - mir_sntprintf(buf, bufSize, _T("%s %s"), resource->software, resource->version); - } - // no version info and no caps info? set MirVer = resource name - else if ( !resource->szCapsNode || !resource->szCapsVer ) { - Log("JabberUpdateMirVer: for rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM, resource->resourceName, resource->resourceName); - if ( resource->resourceName ) - lstrcpyn(buf, resource->resourceName, bufSize); - } - // XEP-0115 caps mode - else { - Log("JabberUpdateMirVer: for rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM "#" TCHAR_STR_PARAM, resource->resourceName, resource->szCapsNode, resource->szCapsVer); - - int i; - - // search through known software list - for (i = 0; i < SIZEOF(sttCapsNodeToName_Map); ++i) - if ( _tcsstr( resource->szCapsNode, sttCapsNodeToName_Map[i].node )) - { - mir_sntprintf( buf, bufSize, _T("%s %s"), sttCapsNodeToName_Map[i].name, resource->szCapsVer ); - break; - } - - // unknown software - if (i == SIZEOF(sttCapsNodeToName_Map)) - mir_sntprintf( buf, bufSize, _T("%s %s"), resource->szCapsNode, resource->szCapsVer ); - } - - // attach additional info for fingerprint plguin - if (resource->resourceName && !_tcsstr(buf, resource->resourceName)) - { - if (_tcsstr(buf, _T("Miranda IM")) || _tcsstr(buf, _T("Miranda NG")) || m_options.ShowForeignResourceInMirVer ) - { - int offset = lstrlen(buf); - mir_sntprintf(buf + offset, bufSize - offset, _T(" [%s]"), resource->resourceName); - } - } - - if (resource->szCapsExt && _tcsstr(resource->szCapsExt, _T(JABBER_EXT_SECUREIM)) && !_tcsstr(buf, _T("(SecureIM)"))) - { - int offset = lstrlen(buf); - mir_sntprintf(buf + offset, bufSize - offset, _T(" (SecureIM)")); - } -} - - -void CJabberProto::UpdateMirVer(HANDLE hContact, JABBER_RESOURCE_STATUS *resource) -{ - TCHAR szMirVer[ 512 ]; - FormatMirVer(resource, szMirVer, SIZEOF(szMirVer)); - if ( szMirVer[0] ) - JSetStringT( hContact, "MirVer", szMirVer ); -// else -// JDeleteSetting( hContact, "MirVer" ); - - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; - if ( resource->resourceName ) - mir_sntprintf( szFullJid, SIZEOF( szFullJid ), _T("%s/%s"), dbv.ptszVal, resource->resourceName ); - else - lstrcpyn( szFullJid, dbv.ptszVal, SIZEOF(szFullJid)); - JSetStringT( hContact, DBSETTING_DISPLAY_UID, szFullJid ); - JFreeVariant( &dbv ); - } -} - -void CJabberProto::UpdateSubscriptionInfo(HANDLE hContact, JABBER_LIST_ITEM *item) -{ - switch (item->subscription) - { - case SUB_TO: - JSetStringT(hContact, "SubscriptionText", TranslateT("To")); - JSetString(hContact, "Subscription", "to"); - JSetByte(hContact, "Auth", 0); - JSetByte(hContact, "Grant", 1); - break; - case SUB_FROM: - JSetStringT(hContact, "SubscriptionText", TranslateT("From")); - JSetString(hContact, "Subscription", "from"); - JSetByte(hContact, "Auth", 1); - JSetByte(hContact, "Grant", 0); - break; - case SUB_BOTH: - JSetStringT(hContact, "SubscriptionText", TranslateT("Both")); - JSetString(hContact, "Subscription", "both"); - JSetByte(hContact, "Auth", 0); - JSetByte(hContact, "Grant", 0); - break; - case SUB_NONE: - JSetStringT(hContact, "SubscriptionText", TranslateT("None")); - JSetString(hContact, "Subscription", "none"); - JSetByte(hContact, "Auth", 1); - JSetByte(hContact, "Grant", 1); - break; - } -} - -void CJabberProto::SetContactOfflineStatus( HANDLE hContact ) -{ - if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) - JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); - - JDeleteSetting( hContact, DBSETTING_XSTATUSID ); - JDeleteSetting( hContact, DBSETTING_XSTATUSNAME ); - JDeleteSetting( hContact, DBSETTING_XSTATUSMSG ); - JDeleteSetting( hContact, DBSETTING_DISPLAY_UID ); - - ResetAdvStatus( hContact, ADVSTATUS_MOOD ); - ResetAdvStatus( hContact, ADVSTATUS_TUNE ); - - //JabberUpdateContactExtraIcon(hContact); -} - -void CJabberProto::InitPopups(void) -{ - TCHAR desc[256]; - char name[256]; - - POPUPCLASS ppc = {0}; - ppc.cbSize = sizeof(ppc); - ppc.flags = PCF_TCHAR; - - ppc.ptszDescription = desc; - ppc.pszName = name; - ppc.hIcon = LoadIconEx("main"); - ppc.colorBack = RGB(191, 0, 0); //Red - ppc.colorText = RGB(255, 245, 225); //Yellow - ppc.iSeconds = 60; - mir_sntprintf(desc, SIZEOF(desc), _T("%s %s"), m_tszUserName, TranslateT("Errors")); - mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Error"); - - CallService(MS_POPUP_REGISTERCLASS, 0, (WPARAM)&ppc); -} - -void CJabberProto::MsgPopup(HANDLE hContact, const TCHAR *szMsg, const TCHAR *szTitle) -{ - if (ServiceExists(MS_POPUP_ADDPOPUPCLASS)) { - char name[256]; - - POPUPDATACLASS ppd = { sizeof(ppd) }; - ppd.ptszTitle = szTitle; - ppd.ptszText = szMsg; - ppd.pszClassName = name; - ppd.hContact = hContact; - mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Error"); - - CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd); - } else { - DWORD mtype = MB_OK | MB_SETFOREGROUND | MB_ICONSTOP; - MessageBox(NULL, szMsg, szTitle, mtype); - } -} diff --git a/protocols/JabberG/jabber_notes.cpp b/protocols/JabberG/jabber_notes.cpp deleted file mode 100644 index d684541f0a..0000000000 --- a/protocols/JabberG/jabber_notes.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "jabber_privacy.h" -#include "jabber_notes.h" - -static TCHAR *StrTrimCopy(TCHAR *str) -{ - if (!str) return 0; - while (*str && _istspace(*str)) ++str; - if (!*str) return mir_tstrdup(str); - - TCHAR *res = mir_tstrdup(str); - for (TCHAR *p = res + lstrlen(res) - 1; p >= res; --p) - { - if (_istspace(*p)) - *p = 0; - else - break; - } - - return res; -} - -CNoteItem::CNoteItem() -{ - m_szTitle = - m_szFrom = - m_szText = - m_szTags = - m_szTagsStr = NULL; -} - -CNoteItem::CNoteItem(HXML hXml, TCHAR *szFrom) -{ - m_szTitle = - m_szFrom = - m_szText = - m_szTags = - m_szTagsStr = NULL; - - SetData( - XPathT(hXml, "title"), - szFrom ? szFrom : XPathT(hXml, "@from"), - XPathT(hXml, "text"), - XPathT(hXml, "@tags")); -} - -CNoteItem::~CNoteItem() -{ - mir_free(m_szTitle); - mir_free(m_szFrom); - mir_free(m_szText); - mir_free(m_szTags); - mir_free(m_szTagsStr); -} - -void CNoteItem::SetData(TCHAR *title, TCHAR *from, TCHAR *text, TCHAR *tags) -{ - mir_free(m_szTitle); - mir_free(m_szFrom); - mir_free(m_szText); - mir_free(m_szTags); - mir_free(m_szTagsStr); - - m_szTitle = StrTrimCopy(title); - m_szText = JabberStrFixLines(text); - m_szFrom = StrTrimCopy(from); - - const TCHAR *szTags = tags; - TCHAR *p = m_szTags = (TCHAR *)mir_alloc((lstrlen(szTags) + 2 /*for double zero*/) * sizeof(TCHAR)); - TCHAR *q = m_szTagsStr = (TCHAR *)mir_alloc((lstrlen(szTags) + 1) * sizeof(TCHAR)); - for ( ; szTags && *szTags; ++szTags) - { - if (_istspace(*szTags)) - continue; - - if (*szTags == _T(',')) - { - *q++ = _T(','); - *p++ = 0; - continue; - } - - *q++ = *p++ = *szTags; - } - - q[0] = p[0] = p[1] = 0; -} - -bool CNoteItem::HasTag(const TCHAR *szTag) -{ - if (!szTag || !*szTag) - return true; - - for (TCHAR *p = m_szTags; p && *p; p = p + lstrlen(p) + 1) - if (!lstrcmp(p, szTag)) - return true; - - return false; -} - -int CNoteItem::cmp(const CNoteItem *p1, const CNoteItem *p2) -{ - int ret = 0; - if (ret = lstrcmp(p1->m_szTitle, p2->m_szTitle)) return ret; - if (ret = lstrcmp(p1->m_szText, p2->m_szText)) return ret; - if (ret = lstrcmp(p1->m_szTagsStr, p2->m_szTagsStr)) return ret; - if (p1 < p2) return -1; - if (p1 > p2) return 1; - return 0; -} - -void CNoteList::AddNote(HXML hXml, TCHAR *szFrom) -{ - m_bIsModified = true; - insert(new CNoteItem(hXml, szFrom)); -} - -void CNoteList::LoadXml(HXML hXml) -{ - destroy(); - m_bIsModified = false; - - int count = xmlGetChildCount(hXml); - for (int i = 0; i < count; ++i) - { - CNoteItem *pNote = new CNoteItem(xi.getChild(hXml, i)); - if (pNote->IsNotEmpty()) - insert(pNote); - else - delete pNote; - } -} - -void CNoteList::SaveXml(HXML hXmlParent) -{ - m_bIsModified = false; - CNoteList &me = *this; - - for (int i = 0; i < getCount(); ++i) - { - HXML hXmlItem = hXmlParent << XCHILD(_T("note")); - hXmlItem << XATTR(_T("from"), me[i].GetFrom()) << XATTR(_T("tags"), me[i].GetTagsStr()); - hXmlItem << XCHILD(_T("title"), me[i].GetTitle()); - hXmlItem << XCHILD(_T("text"), me[i].GetText()); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Single note editor - -class CJabberDlgNoteItem : public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - typedef void (CJabberProto::*TFnProcessNote)(CNoteItem *, bool ok); - -public: - CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote); - CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess); - -protected: - void OnInitDialog(); - int Resizer(UTILRESIZECONTROL *urc); - -private: - CNoteItem *m_pNote; - TFnProcessNote m_fnProcess; - - CCtrlEdit m_txtTitle; - CCtrlEdit m_txtText; - CCtrlEdit m_txtTags; - CCtrlButton m_btnOk; - - void btnOk_OnClick(CCtrlButton *) - { - TCHAR *szTitle = m_txtTitle.GetText(); - TCHAR *szText = m_txtText.GetText(); - TCHAR *szTags = m_txtTags.GetText(); - TCHAR *szFrom = mir_tstrdup(m_pNote->GetFrom()); - m_pNote->SetData(szTitle, szFrom, szText, szTags); - mir_free(szTitle); - mir_free(szText); - mir_free(szTags); - mir_free(szFrom); - - m_autoClose = false; - if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, true); - EndDialog(m_hwnd, TRUE); - } - - void OnClose() - { - if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, false); - CSuper::OnClose(); - } -}; - -CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote): - CSuper(parent->GetProto(), IDD_NOTE_EDIT, parent->GetHwnd()), - m_pNote(pNote), - m_fnProcess(NULL), - m_txtTitle(this, IDC_TXT_TITLE), - m_txtText(this, IDC_TXT_TEXT), - m_txtTags(this, IDC_TXT_TAGS), - m_btnOk(this, IDOK) -{ - m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); -} - -CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess): - CSuper(proto, IDD_NOTE_EDIT, NULL), - m_pNote(pNote), - m_fnProcess(fnProcess), - m_txtTitle(this, IDC_TXT_TITLE), - m_txtText(this, IDC_TXT_TEXT), - m_txtTags(this, IDC_TXT_TAGS), - m_btnOk(this, IDOK) -{ - m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); -} - -void CJabberDlgNoteItem::OnInitDialog() -{ - CSuper::OnInitDialog(); - WindowSetIcon( m_hwnd, m_proto, "notes" ); - - if (m_fnProcess) - { - TCHAR buf[256]; - if (m_fnProcess == &CJabberProto::ProcessIncomingNote) - mir_sntprintf(buf, SIZEOF(buf), TranslateT("Incoming note from %s"), m_pNote->GetFrom()); - else - mir_sntprintf(buf, SIZEOF(buf), TranslateT("Send note to %s"), m_pNote->GetFrom()); - - SetWindowText(m_hwnd, buf); - } - - m_txtTitle.SetText(m_pNote->GetTitle()); - m_txtText.SetText(m_pNote->GetText()); - m_txtTags.SetText(m_pNote->GetTagsStr()); -} - -int CJabberDlgNoteItem::Resizer(UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDC_TXT_TITLE: - return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; - case IDC_TXT_TEXT: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - case IDC_ST_TAGS: - case IDC_TXT_TAGS: - return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; - - case IDOK: - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - - return CSuper::Resizer(urc); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Notebook window - -class CCtrlNotebookList: public CCtrlListBox -{ - typedef CCtrlListBox CSuper; - bool m_adding; - HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; - -public: - CCtrlNotebookList( CDlgBase* dlg, int ctrlId ): CCtrlListBox( dlg, ctrlId ) {} - void SetFonts(HFONT hfntNormal, HFONT hfntSmall, HFONT hfntBold) - { - m_hfntNormal = hfntNormal; - m_hfntSmall = hfntSmall; - m_hfntBold = hfntBold; - } - - int AddString(TCHAR *text, LPARAM data=0) - { - m_adding = true; - int idx = CCtrlListBox::AddString(text, data); - m_adding = false; - if (idx == LB_ERR) return idx; - - MEASUREITEMSTRUCT mis = {0}; - mis.CtlType = ODT_LISTBOX; - mis.CtlID = m_idCtrl; - mis.itemID = idx; - mis.itemData = data; - OnMeasureItem(&mis); - if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); - return idx; - } - - void OnInit() - { - CSuper::OnInit(); - Subclass(); - } - - LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - if (msg == WM_SIZE) - { - SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0); - int cnt = GetCount(); - for (int idx = 0; idx < cnt; ++idx) - { - MEASUREITEMSTRUCT mis = {0}; - mis.CtlType = ODT_LISTBOX; - mis.CtlID = m_idCtrl; - mis.itemID = idx; - mis.itemData = GetItemData(idx); - OnMeasureItem(&mis); - if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); - } - SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); - } - - return CSuper::CustomWndProc(msg, wParam, lParam); - } - - BOOL OnDrawItem(DRAWITEMSTRUCT *lps) - { - if (m_adding) return FALSE; - if (lps->itemID == -1) return TRUE; - if (!lps->itemData) return TRUE; - - HDC hdc = lps->hDC; - CNoteItem *pNote = (CNoteItem *)lps->itemData; - - SetBkMode(hdc, TRANSPARENT); - if (lps->itemState & ODS_SELECTED) - { - FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } else - { - FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_WINDOW)); - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - } - - if (lps->itemID) - { - RECT rcTmp = lps->rcItem; rcTmp.bottom = rcTmp.top+1; - FillRect(hdc, &rcTmp, GetSysColorBrush(COLOR_BTNSHADOW)); - } - - RECT rc = lps->rcItem; - rc.left += 5; - rc.right -= 5; - rc.top += 2; - - SelectObject(hdc, m_hfntBold); - rc.top += DrawText(hdc, pNote->GetTitle(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); - SelectObject(hdc, m_hfntNormal); - if (pNote->GetFrom()) - { - TCHAR buf[256]; - mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); - rc.top += DrawText(hdc, buf, -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); - } - rc.top += DrawText(hdc, pNote->GetText(), -1, &rc, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS); - SelectObject(hdc, m_hfntSmall); - rc.top += DrawText(hdc, pNote->GetTagsStr(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); - rc.top += 5; - - int h = min(255, max(0, rc.bottom - rc.top)); - if (SendMessage(m_hwnd, LB_GETITEMHEIGHT, lps->itemID, 0) != h) - SendMessage(m_hwnd, LB_SETITEMHEIGHT, lps->itemID, h); - - return TRUE; - } - - BOOL OnMeasureItem(MEASUREITEMSTRUCT *lps) - { - if (m_adding) return FALSE; - if (lps->itemID == -1) return TRUE; - if (!lps->itemData) return TRUE; - - HDC hdc = GetDC(m_hwnd); - CNoteItem *pNote = (CNoteItem *)lps->itemData; - - RECT rcTmp, rc; - GetClientRect(m_hwnd, &rc); - int maxHeight = rc.bottom - 10; - rc.bottom = 0; - - SelectObject(hdc, m_hfntBold); - rcTmp = rc; - DrawText(hdc, pNote->GetTitle(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); - lps->itemHeight += rcTmp.bottom; - SelectObject(hdc, m_hfntNormal); - if (pNote->GetFrom()) - { - TCHAR buf[256]; - mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); - rcTmp = rc; - DrawText(hdc, buf, -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); - lps->itemHeight += rcTmp.bottom; - } - rcTmp = rc; - DrawText(hdc, pNote->GetText(), -1, &rcTmp, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS|DT_CALCRECT); - lps->itemHeight += rcTmp.bottom; - SelectObject(hdc, m_hfntSmall); - rcTmp = rc; - DrawText(hdc, pNote->GetTagsStr(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); - lps->itemHeight += rcTmp.bottom; - lps->itemHeight += 5; - - ReleaseDC(m_hwnd, hdc); - - lps->itemWidth = rc.right; - lps->itemHeight = min(255, lps->itemHeight); // listbox can't make items taller then 255px - return TRUE; - } -}; - -class CJabberDlgNotes : public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgNotes(CJabberProto *proto); - void UpdateData(); - -protected: - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - int Resizer(UTILRESIZECONTROL *urc); - - void OnProtoCheckOnline(WPARAM wParam, LPARAM lParam); - void OnProtoRefresh(WPARAM wParam, LPARAM lParam); - -private: - CCtrlMButton m_btnAdd; - CCtrlMButton m_btnEdit; - CCtrlMButton m_btnRemove; - CCtrlNotebookList m_lstNotes; - CCtrlTreeView m_tvFilter; - CCtrlButton m_btnSave; - - HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; - - void EnableControls() - { - m_btnSave.Enable(m_proto->m_bJabberOnline && m_proto->m_notes.IsModified()); - m_btnEdit.Enable(m_lstNotes.GetCurSel() != LB_ERR); - m_btnRemove.Enable(m_lstNotes.GetCurSel() != LB_ERR); - } - - void InsertTag(HTREEITEM htiRoot, const TCHAR *tag, bool bSelect) - { - TVINSERTSTRUCT tvi = {0}; - tvi.hParent = htiRoot; - tvi.hInsertAfter = TVI_LAST; - tvi.itemex.mask = TVIF_TEXT|TVIF_PARAM; - tvi.itemex.pszText = (TCHAR *)tag; - tvi.itemex.lParam = (LPARAM)mir_tstrdup(tag); - HTREEITEM hti = m_tvFilter.InsertItem(&tvi); - if (bSelect) m_tvFilter.SelectItem(hti); - } - - void PopulateTags(HTREEITEM htiRoot, TCHAR *szActiveTag) - { - LIST<TCHAR> tagSet(5, _tcscmp); - for (int i = 0; i < m_proto->m_notes.getCount(); ++i) - { - TCHAR *tags = m_proto->m_notes[i].GetTags(); - for (TCHAR *tag = tags; tag && *tag; tag = tag + lstrlen(tag) + 1) - if (!tagSet.find(tag)) - tagSet.insert(tag); - } - - bool selected = false; - for (int j = 0; j < tagSet.getCount(); ++j) - { - bool select = !lstrcmp(szActiveTag, tagSet[j]); - selected |= select; - InsertTag(htiRoot, tagSet[j], select); - } - - if (!selected) - m_tvFilter.SelectItem(htiRoot); - - tagSet.destroy(); - } - - void RebuildTree() - { - TVITEMEX tvi = {0}; - tvi.mask = TVIF_HANDLE|TVIF_PARAM; - tvi.hItem = m_tvFilter.GetSelection(); - m_tvFilter.GetItem(&tvi); - TCHAR *szActiveTag = mir_tstrdup((TCHAR *)tvi.lParam); - - m_tvFilter.DeleteAllItems(); - - TVINSERTSTRUCT tvis = {0}; - tvis.hParent = NULL; - tvis.hInsertAfter = TVI_LAST; - tvis.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE; - tvis.itemex.stateMask = - tvis.itemex.state = TVIS_BOLD|TVIS_EXPANDED; - tvis.itemex.pszText = TranslateT("All tags"); - tvis.itemex.lParam = NULL; - - - PopulateTags(m_tvFilter.InsertItem(&tvis), szActiveTag); - mir_free(szActiveTag); - } - - void InsertItem(CNoteItem &item) - { - m_lstNotes.AddString((TCHAR *)item.GetTitle(), (LPARAM)&item); - EnableControls(); - } - - void ListItems(const TCHAR *tag) - { - m_lstNotes.ResetContent(); - for (int i = 0; i < m_proto->m_notes.getCount(); ++i) - if (m_proto->m_notes[i].HasTag(tag)) - InsertItem(m_proto->m_notes[i]); - EnableControls(); - } - - void btnAdd_OnClick(CCtrlFilterListView *) - { - CNoteItem *pNote = new CNoteItem(); - CJabberDlgNoteItem dlg(this, pNote); - dlg.DoModal(); - - if (pNote->IsNotEmpty()) - { - m_proto->m_notes.insert(pNote); - m_proto->m_notes.Modify(); - UpdateData(); - } else - { - delete pNote; - return; - } - EnableControls(); - } - - void btnEdit_OnClick(CCtrlFilterListView *) - { - int idx = m_lstNotes.GetCurSel(); - if (idx != LB_ERR) - { - if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) - { - CJabberDlgNoteItem dlg(this, pItem); - if (dlg.DoModal()) - { - m_proto->m_notes.Modify(); - RebuildTree(); - } - } - } - EnableControls(); - } - - void btnRemove_OnClick(CCtrlFilterListView *) - { - int idx = m_lstNotes.GetCurSel(); - if (idx != LB_ERR) - { - if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) - { - m_lstNotes.DeleteString(idx); - m_proto->m_notes.remove(pItem); - } - RebuildTree(); - } - EnableControls(); - } - - void lstNotes_OnSelChange(CCtrlListBox *) - { - EnableControls(); - } - - void tvFilter_OnDeleteItem(CCtrlTreeView::TEventInfo *e) - { - TCHAR *szText = (TCHAR *)e->nmtv->itemOld.lParam; - mir_free(szText); - EnableControls(); - } - - void tvFilter_OnSelChanged(CCtrlTreeView::TEventInfo *e) - { - TCHAR *szText = (TCHAR *)e->nmtv->itemNew.lParam; - ListItems(szText); - EnableControls(); - } - - void btnSave_OnClick(CCtrlButton *) - { - XmlNodeIq iq(_T("set")); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); - HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); - m_proto->m_notes.SaveXml(storage); - m_proto->m_ThreadInfo->send(iq); - EnableControls(); - } -}; - -CJabberDlgNotes::CJabberDlgNotes(CJabberProto *proto) : - CSuper(proto, IDD_NOTEBOOK, NULL), - m_btnAdd(this, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add")), - m_btnEdit(this, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit")), - m_btnRemove(this, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove")), - m_lstNotes(this, IDC_LST_NOTES), - m_tvFilter(this, IDC_TV_FILTER), - m_btnSave(this, IDC_APPLY) -{ - m_btnAdd.OnClick = Callback(this, &CJabberDlgNotes::btnAdd_OnClick); - m_btnEdit.OnClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); - m_btnRemove.OnClick = Callback(this, &CJabberDlgNotes::btnRemove_OnClick); - m_lstNotes.OnDblClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); - m_lstNotes.OnSelChange = Callback(this, &CJabberDlgNotes::lstNotes_OnSelChange); - m_btnSave.OnClick = Callback(this, &CJabberDlgNotes::btnSave_OnClick); - - m_tvFilter.OnSelChanged = Callback(this, &CJabberDlgNotes::tvFilter_OnSelChanged); - m_tvFilter.OnDeleteItem = Callback(this, &CJabberDlgNotes::tvFilter_OnDeleteItem); -} - -void CJabberDlgNotes::UpdateData() -{ - RebuildTree(); - //ListItems(NULL); - EnableControls(); -} - -void CJabberDlgNotes::OnInitDialog() -{ - CSuper::OnInitDialog(); - WindowSetIcon( m_hwnd, m_proto, "notes" ); - - LOGFONT lf, lfTmp; - m_hfntNormal = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - GetObject(m_hfntNormal, sizeof(lf), &lf); - lfTmp = lf; lfTmp.lfWeight = FW_BOLD; - m_hfntBold = CreateFontIndirect(&lfTmp); - lfTmp = lf; lfTmp.lfHeight *= 0.8; - m_hfntSmall = CreateFontIndirect(&lfTmp); - m_lstNotes.SetFonts(m_hfntNormal, m_hfntSmall, m_hfntBold); - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); -} - -void CJabberDlgNotes::OnClose() -{ - if (m_proto->m_notes.IsModified()) - { - if (IDYES != MessageBox(m_hwnd, TranslateT("Notes are not saved, close this window without uploading data to server?"), TranslateT("Are you sure?"), MB_ICONWARNING|MB_YESNO|MB_DEFBUTTON2)) - { - m_lresult = TRUE; - return; - } - } - - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); - DeleteObject(m_hfntSmall); - DeleteObject(m_hfntBold); - CSuper::OnClose(); -} - -void CJabberDlgNotes::OnDestroy() -{ - m_tvFilter.DeleteAllItems(); - m_proto->m_pDlgNotes = NULL; - CSuper::OnDestroy(); -} - -void CJabberDlgNotes::OnProtoCheckOnline(WPARAM, LPARAM) -{ - EnableControls(); -} - -void CJabberDlgNotes::OnProtoRefresh(WPARAM, LPARAM) -{ -} - -int CJabberDlgNotes::Resizer(UTILRESIZECONTROL *urc) -{ - switch ( urc->wId ) { - case IDC_TV_FILTER: - return RD_ANCHORX_LEFT|RD_ANCHORY_HEIGHT; - case IDC_LST_NOTES: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - case IDC_APPLY: - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - case IDC_ADD: - case IDC_EDIT: - case IDC_REMOVE: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - } - return CSuper::Resizer(urc); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Launches the incoming note window - -void CJabberProto::ProcessIncomingNote(CNoteItem *pNote, bool ok) -{ - if (ok && pNote->IsNotEmpty()) - { - m_notes.insert(pNote); - - XmlNodeIq iq(_T("set")); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); - HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); - m_notes.SaveXml(storage); - m_ThreadInfo->send(iq); - } else - { - delete pNote; - } -} - -void CJabberProto::ProcessOutgoingNote(CNoteItem *pNote, bool ok) -{ - if (!ok || !pNote->IsNotEmpty()) - { - delete pNote; - return; - } - - TCHAR buf[1024]; - mir_sntprintf(buf, SIZEOF(buf), _T("Incoming note: %s\n\n%s\nTags: %s"), - pNote->GetTitle(), pNote->GetText(), pNote->GetTagsStr()); - - JabberCapsBits jcb = GetResourceCapabilites( pNote->GetFrom(), TRUE ); - - if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) - jcb = JABBER_RESOURCE_CAPS_NONE; - - int nMsgId = SerialNext(); - - XmlNode m(_T("message")); - m << XATTR(_T("type"), _T("chat")) << XATTR( _T("to"), pNote->GetFrom()) << XATTRID( nMsgId ); - m << XCHILD(_T("body"), buf); - HXML hXmlItem = m << XCHILDNS(_T("x"), _T(JABBER_FEAT_MIRANDA_NOTES)) << XCHILD(_T("note")); - hXmlItem << XATTR(_T("tags"), pNote->GetTagsStr()); - hXmlItem << XCHILD(_T("title"), pNote->GetTitle()); - hXmlItem << XCHILD(_T("text"), pNote->GetText()); - - // message receipts XEP priority - if ( jcb & JABBER_CAPS_MESSAGE_RECEIPTS ) - m << XCHILDNS( _T("request"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)); - else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { - HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); - x << XCHILD( _T("delivered")); x << XCHILD( _T("offline")); - } - else - nMsgId = -1; - - m_ThreadInfo->send(m); - delete pNote; -} - -bool CJabberProto::OnIncomingNote(const TCHAR *szFrom, HXML hXml) -{ - if (!m_options.AcceptNotes) - return false; - - if (!szFrom || !hXml) return true; - CNoteItem *pItem = new CNoteItem(hXml, (TCHAR *)szFrom); - if (!pItem->IsNotEmpty()) - { - delete pItem; - return true; - } - - if (m_options.AutosaveNotes && HContactFromJID(szFrom)) - { - ProcessIncomingNote(pItem, true); - return false; - } - - CLISTEVENT cle = {0}; - char szService[256]; - mir_snprintf( szService, sizeof(szService),"%s%s", m_szModuleName, JS_INCOMING_NOTE_EVENT ); - cle.cbSize = sizeof(CLISTEVENT); - cle.hIcon = (HICON)LoadIconEx("notes"); - cle.flags = CLEF_PROTOCOLGLOBAL|CLEF_TCHAR; - cle.hDbEvent = (HANDLE)("test"); - cle.lParam = (LPARAM)pItem; - cle.pszService = szService; - cle.ptszTooltip = TranslateT("Incoming note"); - CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); - - return true; -} - -INT_PTR __cdecl CJabberProto::OnIncomingNoteEvent(WPARAM, LPARAM lParam) -{ - CLISTEVENT *pCle = (CLISTEVENT *)lParam; - CNoteItem *pNote = (CNoteItem *)pCle->lParam; - if ( !pNote ) - return 0; - - CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pNote, &CJabberProto::ProcessIncomingNote); - pDlg->Show(); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Menu handling - -INT_PTR __cdecl CJabberProto::OnMenuHandleNotes( WPARAM, LPARAM) -{ - UI_SAFE_OPEN_EX(CJabberDlgNotes, m_pDlgNotes, pDlg); - pDlg->UpdateData(); - return 0; -} - -INT_PTR __cdecl CJabberProto::OnMenuSendNote(WPARAM wParam, LPARAM) -{ - if (!wParam) return 0; - - TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; - GetClientJID( JGetStringT( (HANDLE)wParam, "jid"), szClientJid, SIZEOF( szClientJid )); - - CNoteItem *pItem = new CNoteItem( NULL, szClientJid ); - CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pItem, &CJabberProto::ProcessOutgoingNote); - pDlg->Show(); - - return 0; -} diff --git a/protocols/JabberG/jabber_notes.h b/protocols/JabberG/jabber_notes.h deleted file mode 100644 index de096943c2..0000000000 --- a/protocols/JabberG/jabber_notes.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __jabber_notes_h__ -#define __jabber_notes_h__ - -class CNoteItem -{ -private: - TCHAR *m_szTitle; - TCHAR *m_szFrom; - TCHAR *m_szText; - TCHAR *m_szTags; - TCHAR *m_szTagsStr; - -public: - CNoteItem(); - CNoteItem(HXML hXml, TCHAR *szFrom = 0); - ~CNoteItem(); - - void SetData(TCHAR *title, TCHAR *from, TCHAR *text, TCHAR *tags); - - TCHAR *GetTitle() const { return m_szTitle; } - TCHAR *GetFrom() const { return m_szFrom; } - TCHAR *GetText() const { return m_szText; } - TCHAR *GetTags() const { return m_szTags; } - TCHAR *GetTagsStr() const { return m_szTagsStr; } - - bool HasTag(const TCHAR *szTag); - - bool IsNotEmpty() - { - return (m_szTitle && *m_szTitle) || (m_szText && *m_szText); - } - - static int cmp(const CNoteItem *p1, const CNoteItem *p2); -}; - -class CNoteList: public OBJLIST<CNoteItem> -{ -private: - bool m_bIsModified; - -public: - CNoteList(): OBJLIST<CNoteItem>(10, CNoteItem::cmp) {} - - void remove(CNoteItem *p) - { - m_bIsModified = true; - OBJLIST<CNoteItem>::remove(p); - } - - void AddNote(HXML hXml, TCHAR *szFrom = 0); - void LoadXml(HXML hXml); - void SaveXml(HXML hXmlParent); - - bool IsModified() { return m_bIsModified; } - void Modify() { m_bIsModified = true; } -}; - -#endif // __jabber_notes_h__ diff --git a/protocols/JabberG/jabber_opt.cpp b/protocols/JabberG/jabber_opt.cpp deleted file mode 100644 index 1f1270a8a1..0000000000 --- a/protocols/JabberG/jabber_opt.cpp +++ /dev/null @@ -1,2331 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_list.h" - -#include "jabber_caps.h" -#include "jabber_opttree.h" -#include "m_modernopt.h" - -static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberRegisterDlgProc - the dialog proc for registering new account - -#define STR_FORMAT _T("%s %s@%S:%d?") - -struct { TCHAR *szCode; TCHAR *szDescription; } g_LanguageCodes[] = { - { _T("aa"), _T("Afar") }, - { _T("ab"), _T("Abkhazian") }, - { _T("af"), _T("Afrikaans") }, - { _T("ak"), _T("Akan") }, - { _T("sq"), _T("Albanian") }, - { _T("am"), _T("Amharic") }, - { _T("ar"), _T("Arabic") }, - { _T("an"), _T("Aragonese") }, - { _T("hy"), _T("Armenian") }, - { _T("as"), _T("Assamese") }, - { _T("av"), _T("Avaric") }, - { _T("ae"), _T("Avestan") }, - { _T("ay"), _T("Aymara") }, - { _T("az"), _T("Azerbaijani") }, - { _T("ba"), _T("Bashkir") }, - { _T("bm"), _T("Bambara") }, - { _T("eu"), _T("Basque") }, - { _T("be"), _T("Belarusian") }, - { _T("bn"), _T("Bengali") }, - { _T("bh"), _T("Bihari") }, - { _T("bi"), _T("Bislama") }, - { _T("bs"), _T("Bosnian") }, - { _T("br"), _T("Breton") }, - { _T("bg"), _T("Bulgarian") }, - { _T("my"), _T("Burmese") }, - { _T("ca"), _T("Catalan; Valencian") }, - { _T("ch"), _T("Chamorro") }, - { _T("ce"), _T("Chechen") }, - { _T("zh"), _T("Chinese") }, - { _T("cu"), _T("Church Slavic; Old Slavonic") }, - { _T("cv"), _T("Chuvash") }, - { _T("kw"), _T("Cornish") }, - { _T("co"), _T("Corsican") }, - { _T("cr"), _T("Cree") }, - { _T("cs"), _T("Czech") }, - { _T("da"), _T("Danish") }, - { _T("dv"), _T("Divehi; Dhivehi; Maldivian") }, - { _T("nl"), _T("Dutch; Flemish") }, - { _T("dz"), _T("Dzongkha") }, - { _T("en"), _T("English") }, - { _T("eo"), _T("Esperanto") }, - { _T("et"), _T("Estonian") }, - { _T("ee"), _T("Ewe") }, - { _T("fo"), _T("Faroese") }, - { _T("fj"), _T("Fijian") }, - { _T("fi"), _T("Finnish") }, - { _T("fr"), _T("French") }, - { _T("fy"), _T("Western Frisian") }, - { _T("ff"), _T("Fulah") }, - { _T("ka"), _T("Georgian") }, - { _T("de"), _T("German") }, - { _T("gd"), _T("Gaelic; Scottish Gaelic") }, - { _T("ga"), _T("Irish") }, - { _T("gl"), _T("Galician") }, - { _T("gv"), _T("Manx") }, - { _T("el"), _T("Greek, Modern (1453-)") }, - { _T("gn"), _T("Guarani") }, - { _T("gu"), _T("Gujarati") }, - { _T("ht"), _T("Haitian; Haitian Creole") }, - { _T("ha"), _T("Hausa") }, - { _T("he"), _T("Hebrew") }, - { _T("hz"), _T("Herero") }, - { _T("hi"), _T("Hindi") }, - { _T("ho"), _T("Hiri Motu") }, - { _T("hu"), _T("Hungarian") }, - { _T("ig"), _T("Igbo") }, - { _T("is"), _T("Icelandic") }, - { _T("io"), _T("Ido") }, - { _T("ii"), _T("Sichuan Yi") }, - { _T("iu"), _T("Inuktitut") }, - { _T("ie"), _T("Interlingue") }, - { _T("ia"), _T("Interlingua (International Auxiliary Language Association)") }, - { _T("id"), _T("Indonesian") }, - { _T("ik"), _T("Inupiaq") }, - { _T("it"), _T("Italian") }, - { _T("jv"), _T("Javanese") }, - { _T("ja"), _T("Japanese") }, - { _T("kl"), _T("Kalaallisut; Greenlandic") }, - { _T("kn"), _T("Kannada") }, - { _T("ks"), _T("Kashmiri") }, - { _T("kr"), _T("Kanuri") }, - { _T("kk"), _T("Kazakh") }, - { _T("km"), _T("Central Khmer") }, - { _T("ki"), _T("Kikuyu; Gikuyu") }, - { _T("rw"), _T("Kinyarwanda") }, - { _T("ky"), _T("Kirghiz; Kyrgyz") }, - { _T("kv"), _T("Komi") }, - { _T("kg"), _T("Kongo") }, - { _T("ko"), _T("Korean") }, - { _T("kj"), _T("Kuanyama; Kwanyama") }, - { _T("ku"), _T("Kurdish") }, - { _T("lo"), _T("Lao") }, - { _T("la"), _T("Latin") }, - { _T("lv"), _T("Latvian") }, - { _T("li"), _T("Limburgan; Limburger; Limburgish") }, - { _T("ln"), _T("Lingala") }, - { _T("lt"), _T("Lithuanian") }, - { _T("lb"), _T("Luxembourgish; Letzeburgesch") }, - { _T("lu"), _T("Luba-Katanga") }, - { _T("lg"), _T("Ganda") }, - { _T("mk"), _T("Macedonian") }, - { _T("mh"), _T("Marshallese") }, - { _T("ml"), _T("Malayalam") }, - { _T("mi"), _T("Maori") }, - { _T("mr"), _T("Marathi") }, - { _T("ms"), _T("Malay") }, - { _T("mg"), _T("Malagasy") }, - { _T("mt"), _T("Maltese") }, - { _T("mo"), _T("Moldavian") }, - { _T("mn"), _T("Mongolian") }, - { _T("na"), _T("Nauru") }, - { _T("nv"), _T("Navajo; Navaho") }, - { _T("nr"), _T("Ndebele, South; South Ndebele") }, - { _T("nd"), _T("Ndebele, North; North Ndebele") }, - { _T("ng"), _T("Ndonga") }, - { _T("ne"), _T("Nepali") }, - { _T("nn"), _T("Norwegian Nynorsk; Nynorsk, Norwegian") }, - { _T("nb"), _T("Bokmaal, Norwegian; Norwegian Bokmaal") }, - { _T("no"), _T("Norwegian") }, - { _T("ny"), _T("Chichewa; Chewa; Nyanja") }, - { _T("oc"), _T("Occitan (post 1500); Provencal") }, - { _T("oj"), _T("Ojibwa") }, - { _T("or"), _T("Oriya") }, - { _T("om"), _T("Oromo") }, - { _T("os"), _T("Ossetian; Ossetic") }, - { _T("pa"), _T("Panjabi; Punjabi") }, - { _T("fa"), _T("Persian") }, - { _T("pi"), _T("Pali") }, - { _T("pl"), _T("Polish") }, - { _T("pt"), _T("Portuguese") }, - { _T("ps"), _T("Pushto") }, - { _T("qu"), _T("Quechua") }, - { _T("rm"), _T("Romansh") }, - { _T("ro"), _T("Romanian") }, - { _T("rn"), _T("Rundi") }, - { _T("ru"), _T("Russian") }, - { _T("sg"), _T("Sango") }, - { _T("sa"), _T("Sanskrit") }, - { _T("sr"), _T("Serbian") }, - { _T("hr"), _T("Croatian") }, - { _T("si"), _T("Sinhala; Sinhalese") }, - { _T("sk"), _T("Slovak") }, - { _T("sl"), _T("Slovenian") }, - { _T("se"), _T("Northern Sami") }, - { _T("sm"), _T("Samoan") }, - { _T("sn"), _T("Shona") }, - { _T("sd"), _T("Sindhi") }, - { _T("so"), _T("Somali") }, - { _T("st"), _T("Sotho, Southern") }, - { _T("es"), _T("Spanish; Castilian") }, - { _T("sc"), _T("Sardinian") }, - { _T("ss"), _T("Swati") }, - { _T("su"), _T("Sundanese") }, - { _T("sw"), _T("Swahili") }, - { _T("sv"), _T("Swedish") }, - { _T("ty"), _T("Tahitian") }, - { _T("ta"), _T("Tamil") }, - { _T("tt"), _T("Tatar") }, - { _T("te"), _T("Telugu") }, - { _T("tg"), _T("Tajik") }, - { _T("tl"), _T("Tagalog") }, - { _T("th"), _T("Thai") }, - { _T("bo"), _T("Tibetan") }, - { _T("ti"), _T("Tigrinya") }, - { _T("to"), _T("Tonga (Tonga Islands)") }, - { _T("tn"), _T("Tswana") }, - { _T("ts"), _T("Tsonga") }, - { _T("tk"), _T("Turkmen") }, - { _T("tr"), _T("Turkish") }, - { _T("tw"), _T("Twi") }, - { _T("ug"), _T("Uighur; Uyghur") }, - { _T("uk"), _T("Ukrainian") }, - { _T("ur"), _T("Urdu") }, - { _T("uz"), _T("Uzbek") }, - { _T("ve"), _T("Venda") }, - { _T("vi"), _T("Vietnamese") }, - { _T("vo"), _T("Volapuk") }, - { _T("cy"), _T("Welsh") }, - { _T("wa"), _T("Walloon") }, - { _T("wo"), _T("Wolof") }, - { _T("xh"), _T("Xhosa") }, - { _T("yi"), _T("Yiddish") }, - { _T("yo"), _T("Yoruba") }, - { _T("za"), _T("Zhuang; Chuang") }, - { _T("zu"), _T("Zulu") }, - { NULL, NULL } -}; - -class CJabberDlgRegister: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; -public: - CJabberDlgRegister(CJabberProto *proto, HWND hwndParent, ThreadData *regInfo): - CJabberDlgBase(proto, IDD_OPT_REGISTER, hwndParent, false), - m_bProcessStarted(false), - m_regInfo(regInfo), - m_btnOk(this, IDOK) - { - m_autoClose = CLOSE_ON_CANCEL; - m_btnOk.OnClick = Callback(this, &CJabberDlgRegister::btnOk_OnClick); - } - -protected: - void OnInitDialog() - { - TCHAR text[256]; - mir_sntprintf( text, SIZEOF(text), STR_FORMAT, TranslateT( "Register" ), m_regInfo->username, m_regInfo->server, m_regInfo->port ); - SetDlgItemText( m_hwnd, IDC_REG_STATUS, text ); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - switch ( msg ) { - case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string - if (( TCHAR* )lParam == NULL ) - SetDlgItemText( m_hwnd, IDC_REG_STATUS, TranslateT( "No message" )); - else - SetDlgItemText( m_hwnd, IDC_REG_STATUS, ( TCHAR* )lParam ); - - if ( wParam >= 0 ) - SendMessage( GetDlgItem( m_hwnd, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 ); - if ( wParam >= 100 ) - m_btnOk.SetText(TranslateT("Close")); - else - SetFocus( GetDlgItem( m_hwnd, IDC_PROGRESS_REG )); - - return TRUE; - } - - return CSuper::DlgProc(msg, wParam, lParam); - } - -private: - bool m_bProcessStarted; - ThreadData *m_regInfo; - - CCtrlButton m_btnOk; - - void btnOk_OnClick(CCtrlButton *) - { - if ( m_bProcessStarted ) { - Close(); - return; - } - - ShowWindow(GetDlgItem(m_hwnd, IDC_PROGRESS_REG), SW_SHOW); - - ThreadData *thread = new ThreadData( m_regInfo->proto, JABBER_SESSION_REGISTER ); - _tcsncpy( thread->username, m_regInfo->username, SIZEOF( thread->username )); - _tcsncpy( thread->password, m_regInfo->password, SIZEOF( thread->password )); - strncpy( thread->server, m_regInfo->server, SIZEOF( thread->server )); - strncpy( thread->manualHost, m_regInfo->manualHost, SIZEOF( thread->manualHost )); - thread->port = m_regInfo->port; - thread->useSSL = m_regInfo->useSSL; - thread->reg_hwndDlg= m_hwnd; - m_proto->JForkThread(( JThreadFunc )&CJabberProto::ServerThread, thread ); - - m_btnOk.SetText(TranslateT("Cancel")); - m_bProcessStarted = true; - - m_lresult = TRUE; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberOptDlgProc - main options dialog procedure - -class CCtrlEditJid: public CCtrlEdit -{ - typedef CCtrlEdit CSuper; - -public: - CCtrlEditJid( CDlgBase* dlg, int ctrlId ); - - void OnInit() - { - CCtrlEdit::OnInit(); - Subclass(); - } - -protected: - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - if ( msg == WM_CHAR ) - { - switch( wParam ) - { - case '\"': case '&': case '\'': case '/': - case ':': case '<': case '>': case '@': - MessageBeep(MB_ICONASTERISK); - return 0; - } - } - return CCtrlEdit::CustomWndProc(msg, wParam, lParam); - } -}; - -CCtrlEditJid::CCtrlEditJid( CDlgBase* dlg, int ctrlId ): - CCtrlEdit( dlg, ctrlId ) -{ -} - -static void sttStoreJidFromUI(CJabberProto *ppro, CCtrlEdit &txtUsername, CCtrlCombo &cbServer) -{ - TCHAR *user = txtUsername.GetText(); - TCHAR *server = cbServer.GetText(); - int len = lstrlen(user) + lstrlen(server) + 2; - TCHAR *jid = (TCHAR *)mir_alloc(len * sizeof(TCHAR)); - mir_sntprintf(jid, len, _T("%s@%s"), user, server); - ppro->JSetStringT(NULL, "jid", jid); - mir_free(jid); - mir_free(server); - mir_free(user); -} - -class CDlgOptAccount: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - CCtrlEditJid m_txtUsername; - CCtrlEdit m_txtPassword; - CCtrlEdit m_txtPriority; - CCtrlCheck m_chkSavePassword; - CCtrlCombo m_cbResource; - CCtrlCheck m_chkUseHostnameAsResource; - CCtrlCheck m_chkUseDomainLogin; - CCtrlCombo m_cbServer; - CCtrlEdit m_txtPort; - CCtrlCheck m_chkUseSsl; - CCtrlCheck m_chkUseTls; - CCtrlCheck m_chkManualHost; - CCtrlEdit m_txtManualHost; - CCtrlEdit m_txtManualPort; - CCtrlCheck m_chkKeepAlive; - CCtrlCheck m_chkAutoDeleteContacts; - CCtrlEdit m_txtUserDirectory; - CCtrlCombo m_cbLocale; - CCtrlButton m_btnRegister; - CCtrlButton m_btnUnregister; - CCtrlButton m_btnChangePassword; - CCtrlHyperlink m_lnkServers; - -public: - CDlgOptAccount(CJabberProto *proto): - CJabberDlgBase(proto, IDD_OPT_JABBER, NULL, false ), - m_txtUsername(this, IDC_EDIT_USERNAME), - m_txtPassword(this, IDC_EDIT_PASSWORD), - m_txtPriority(this, IDC_PRIORITY), - m_chkSavePassword(this, IDC_SAVEPASSWORD), - m_cbResource(this, IDC_COMBO_RESOURCE), - m_chkUseHostnameAsResource(this,IDC_HOSTNAME_AS_RESOURCE), - m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), - m_cbServer(this, IDC_EDIT_LOGIN_SERVER), - m_txtPort(this, IDC_PORT), - m_chkUseSsl(this, IDC_USE_SSL), - m_chkUseTls(this, IDC_USE_TLS), - m_chkManualHost(this, IDC_MANUAL), - m_txtManualHost(this, IDC_HOST), - m_txtManualPort(this, IDC_HOSTPORT), - m_chkKeepAlive(this, IDC_KEEPALIVE), - m_chkAutoDeleteContacts(this, IDC_ROSTER_SYNC), - m_txtUserDirectory(this, IDC_JUD), - m_cbLocale(this, IDC_MSGLANG), - m_btnRegister(this, IDC_BUTTON_REGISTER), - m_btnUnregister(this, IDC_UNREGISTER), - m_btnChangePassword(this, IDC_BUTTON_CHANGE_PASSWORD), - m_lnkServers(this, IDC_LINK_PUBLIC_SERVER, "http://xmpp.org/services/") - - { - CreateLink(m_txtUsername, "LoginName", _T("")); - CreateLink(m_txtPriority, "Priority", DBVT_WORD, 0, true); - CreateLink(m_chkSavePassword, proto->m_options.SavePassword); - CreateLink(m_cbResource, "Resource", _T("Miranda")); - CreateLink(m_chkUseHostnameAsResource, proto->m_options.HostNameAsResource); - CreateLink(m_chkUseDomainLogin, proto->m_options.UseDomainLogin); - CreateLink(m_cbServer, "LoginServer", _T("jabber.org")); - CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); - CreateLink(m_chkUseSsl, proto->m_options.UseSSL); - CreateLink(m_chkUseTls, proto->m_options.UseTLS); - CreateLink(m_chkManualHost, proto->m_options.ManualConnect); - CreateLink(m_txtManualHost, "ManualHost", _T("")); - CreateLink(m_txtManualPort, "ManualPort", DBVT_WORD, 0); - CreateLink(m_chkKeepAlive, proto->m_options.KeepAlive); - CreateLink(m_chkAutoDeleteContacts, proto->m_options.RosterSync); - CreateLink(m_txtUserDirectory, "Jud", _T("")); - - // Bind events - m_cbServer.OnDropdown = Callback(this, &CDlgOptAccount::cbServer_OnDropdown); - m_chkManualHost.OnChange = Callback(this, &CDlgOptAccount::chkManualHost_OnChange); - m_chkUseHostnameAsResource.OnChange = Callback(this, &CDlgOptAccount::chkUseHostnameAsResource_OnChange); - m_chkUseDomainLogin.OnChange = Callback(this, &CDlgOptAccount::chkUseDomainLogin_OnChange); - m_chkUseSsl.OnChange = Callback(this, &CDlgOptAccount::chkUseSsl_OnChange); - m_chkUseTls.OnChange = Callback(this, &CDlgOptAccount::chkUseTls_OnChange); - - m_btnRegister.OnClick = Callback(this, &CDlgOptAccount::btnRegister_OnClick); - m_btnUnregister.OnClick = Callback(this, &CDlgOptAccount::btnUnregister_OnClick); - m_btnChangePassword.OnClick = Callback(this, &CDlgOptAccount::btnChangePassword_OnClick); - } - - static CDlgBase *Create(void *param) { return new CDlgOptAccount((CJabberProto *)param); } - -protected: - void OnInitDialog() - { - CSuper::OnInitDialog(); - - int i; - DBVARIANT dbv; - - m_gotservers = false; - - SendDlgItemMessage(m_hwnd, IDC_PRIORITY_SPIN, UDM_SETRANGE, 0, (LPARAM)MAKELONG(127, -128)); - - TCHAR *passw = m_proto->JGetStringCrypt(NULL, "LoginPassword"); - if (passw) - { - m_txtPassword.SetText(passw); - mir_free(passw); - } - - m_cbServer.AddString(TranslateT("Loading...")); - - // fill predefined resources - TCHAR* szResources[] = { _T("Home"), _T("Work"), _T("Office"), _T("Miranda") }; - for (i = 0; i < SIZEOF(szResources); ++i) - m_cbResource.AddString(szResources[i]); - - // append computer name to the resource list - TCHAR szCompName[ MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; - if (GetComputerName(szCompName, &dwCompNameLength)) - m_cbResource.AddString(szCompName); - - if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "Resource", &dbv)) - { - if (CB_ERR == m_cbResource.FindString(dbv.ptszVal, -1, true)) - m_cbResource.AddString(dbv.ptszVal); - - m_cbResource.SetText(dbv.ptszVal); - JFreeVariant(&dbv); - } - else m_cbResource.SetText(_T("Miranda")); - - for (i = 0; g_LanguageCodes[i].szCode; ++i) - { - int iItem = m_cbLocale.AddString(TranslateTS(g_LanguageCodes[i].szDescription), (LPARAM)g_LanguageCodes[i].szCode); - if (!_tcscmp(m_proto->m_tszSelectedLang, g_LanguageCodes[i].szCode)) - m_cbLocale.SetCurSel(iItem); - } - - EnableWindow(GetDlgItem(m_hwnd, IDC_COMBO_RESOURCE ), m_chkUseHostnameAsResource.GetState() != BST_CHECKED); - EnableWindow(GetDlgItem(m_hwnd, IDC_UNREGISTER), m_proto->m_bJabberOnline); - - m_chkUseTls.Enable(!m_proto->m_options.Disable3920auth && (m_proto->m_options.UseSSL ? false : true)); - if (m_proto->m_options.Disable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); - m_chkUseSsl.Enable(m_proto->m_options.Disable3920auth || (m_proto->m_options.UseTLS ? false : true)); - - if (m_proto->m_options.ManualConnect) - { - m_txtManualHost.Enable(); - m_txtManualPort.Enable(); - m_txtPort.Disable(); - } - - if (m_proto->m_options.UseDomainLogin) - chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); - - CheckRegistration(); - - } - - void OnApply() - { - // clear saved password - *m_proto->m_savedPassword = 0; - - if (m_chkSavePassword.GetState() == BST_CHECKED) - { - TCHAR *text = m_txtPassword.GetText(); - m_proto->JSetStringCrypt(NULL, "LoginPassword", text); - mir_free(text); - } - else m_proto->JDeleteSetting(NULL, "LoginPassword"); - - int index = m_cbLocale.GetCurSel(); - if ( index >= 0 ) - { - TCHAR *szLanguageCode = (TCHAR *)m_cbLocale.GetItemData(index); - if ( szLanguageCode ) { - m_proto->JSetStringT(NULL, "XmlLang", szLanguageCode); - - mir_free( m_proto->m_tszSelectedLang ); - m_proto->m_tszSelectedLang = mir_tstrdup( szLanguageCode ); - } } - - sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); - - if (m_proto->m_bJabberOnline) - { - if (m_txtUsername.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || - m_cbServer.IsChanged() || m_chkUseHostnameAsResource.IsChanged() || m_txtPort.IsChanged() || - m_txtManualHost.IsChanged() || m_txtManualPort.IsChanged() || m_cbLocale.IsChanged()) - { - MessageBox(m_hwnd, - TranslateT("These changes will take effect the next time you connect to the Jabber network."), - TranslateT( "Jabber Protocol Option" ), MB_OK|MB_SETFOREGROUND ); - } - - m_proto->SendPresence(m_proto->m_iStatus, true); - } - } - - void OnChange(CCtrlBase*) - { - if (m_initialized) - CheckRegistration(); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - switch (msg) - { - case WM_ACTIVATE: - m_chkUseTls.Enable(!m_proto->m_options.Disable3920auth && (m_proto->m_options.UseSSL ? false : true)); - if (m_proto->m_options.Disable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); - break; - - case WM_JABBER_REFRESH: - RefreshServers(( HXML )lParam ); - break; - } - return CSuper::DlgProc(msg, wParam, lParam); - } - -private: - bool m_gotservers; - - void btnRegister_OnClick(CCtrlButton *) - { - TCHAR buf[512] = _T(""), pass[512]; - if (!m_proto->EnterString(buf, SIZEOF(buf), TranslateT("Confirm password"), JES_PASSWORD)) - return; - - m_txtPassword.GetText(pass, SIZEOF(pass)); - if (lstrcmp(buf, pass)) - { - MessageBox(m_hwnd, TranslateT("Passwords do not match."), _T("Miranda NG"), MB_ICONSTOP|MB_OK); - return; - } - - ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); - m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); - m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); - m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); - if (m_chkManualHost.GetState() == BST_CHECKED) - { - regInfo.port = (WORD)m_txtManualPort.GetInt(); - m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); - } else - { - regInfo.port = (WORD)m_txtPort.GetInt(); - regInfo.manualHost[0] = '\0'; - } - - if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) - { - CJabberDlgRegister dlg(m_proto, m_hwnd, ®Info); - dlg.DoModal(); -// DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_OPT_REGISTER), m_hwnd, JabberRegisterDlgProc, (LPARAM)®Info); - } - } - - void btnUnregister_OnClick(CCtrlButton *) - { - int res = MessageBox(NULL, - TranslateT("This operation will kill your account, roster and all another information stored at the server. Are you ready to do that?"), - TranslateT("Account removal warning"), MB_YESNOCANCEL); - - if ( res == IDYES ) - m_proto->m_ThreadInfo->send( - XmlNodeIq( _T("set"), m_proto->SerialNext(), m_proto->m_szJabberJID ) << XQUERY( _T(JABBER_FEAT_REGISTER)) - << XCHILD( _T("remove"))); - } - - void btnChangePassword_OnClick(CCtrlButton *) - { - if ( !m_proto->m_bJabberOnline ) { - MessageBox( NULL, - TranslateT("You can change your password only when you are online"), - TranslateT("You must be online"), MB_OK | MB_ICONSTOP ); - return; - } - - m_proto->OnMenuHandleChangePassword(0, 0); - } - - void cbServer_OnDropdown(CCtrlCombo*) - { - if ( !m_gotservers ) - mir_forkthread(QueryServerListThread, this); - } - - void chkManualHost_OnChange(CCtrlData *sender) - { - CCtrlCheck *chk = (CCtrlCheck *)sender; - - if (chk->GetState() == BST_CHECKED) - { - m_txtManualHost.Enable(); - m_txtManualPort.Enable(); - m_txtPort.Disable(); - } else - { - m_txtManualHost.Disable(); - m_txtManualPort.Disable(); - m_txtPort.Enable(); - } - } - - void chkUseHostnameAsResource_OnChange(CCtrlData *sender) - { - CCtrlCheck *chk = (CCtrlCheck *)sender; - - m_cbResource.Enable(chk->GetState() != BST_CHECKED); - if (chk->GetState() == BST_CHECKED) - { - TCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; - if (GetComputerName(szCompName, &dwCompNameLength)) - m_cbResource.SetText(szCompName); - } - } - - void chkUseDomainLogin_OnChange(CCtrlData *sender) - { - CCtrlCheck *chk = (CCtrlCheck *)sender; - BOOL checked = chk->GetState() == BST_CHECKED; - - m_txtPassword.Enable(!checked); - m_txtUsername.Enable(!checked); - m_chkSavePassword.Enable(!checked); - if (checked) { - m_txtPassword.SetText(_T("")); - m_txtUsername.SetText(_T("")); - m_chkSavePassword.SetState(BST_CHECKED); - } - } - - void chkUseSsl_OnChange(CCtrlData*) - { - BOOL bManualHost = m_chkManualHost.GetState() == BST_CHECKED; - if (m_chkUseSsl.GetState() == BST_CHECKED) - { - m_chkUseTls.Disable(); - if (!bManualHost) - m_txtPort.SetInt(5223); - } else - { - if (!m_proto->m_options.Disable3920auth) m_chkUseTls.Enable(); - if (!bManualHost) - m_txtPort.SetInt(5222); - } - } - - void chkUseTls_OnChange(CCtrlData*) - { - if (m_chkUseTls.GetState() == BST_CHECKED) - m_chkUseSsl.Disable(); - else - m_chkUseSsl.Enable(); - } - - void CheckRegistration() - { - ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); - m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); - m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); - m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); - if (m_chkManualHost.GetState() == BST_CHECKED) - { - regInfo.port = (WORD)m_txtManualPort.GetInt(); - m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); - } else - { - regInfo.port = (WORD)m_txtPort.GetInt(); - regInfo.manualHost[0] = '\0'; - } - - if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) - EnableWindow( GetDlgItem( m_hwnd, IDC_BUTTON_REGISTER ), TRUE ); - else - EnableWindow( GetDlgItem( m_hwnd, IDC_BUTTON_REGISTER ), FALSE ); - } - - void RefreshServers( HXML node ) - { - m_gotservers = node != NULL; - - TCHAR *server = m_cbServer.GetText(); - bool bDropdown = m_cbServer.GetDroppedState(); - if (bDropdown) m_cbServer.ShowDropdown(false); - - m_cbServer.ResetContent(); - if ( node ) { - for (int i = 0; ; ++i) { - HXML n = xmlGetChild(node, i); - if ( !n ) - break; - - if ( !lstrcmp( xmlGetName( n ), _T("item"))) - if ( const TCHAR *jid = xmlGetAttrValue( n, _T("jid"))) - if ( m_cbServer.FindString(jid, -1, true) == CB_ERR) - m_cbServer.AddString(jid); - } - } - - m_cbServer.SetText(server); - - if (bDropdown) m_cbServer.ShowDropdown(); - mir_free(server); - } - - static void QueryServerListThread(void *arg) - { - CDlgOptAccount *wnd = (CDlgOptAccount *)arg; - HWND hwnd = wnd->GetHwnd(); - bool bIsError = true; - - if (!IsWindow(hwnd)) return; - - NETLIBHTTPREQUEST request = {0}; - request.cbSize = sizeof(request); - request.requestType = REQUEST_GET; - request.flags = NLHRF_REDIRECT | NLHRF_HTTP11; - request.szUrl = "http://xmpp.org/services/services.xml"; - - NETLIBHTTPREQUEST *result = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)wnd->GetProto()->m_hNetlibUser, (LPARAM)&request); - if ( result ) { - if ( result->resultCode == 200 && result->dataLength && result->pData ) { - TCHAR* buf = mir_a2t( result->pData ); - XmlNode node( buf, NULL, NULL ); - if ( node ) { - HXML queryNode = xmlGetChild( node, _T("query")); - SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); - bIsError = false; - } - mir_free( buf ); - } - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)result); - } - - if ( bIsError ) - SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)NULL); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberAdvOptDlgProc - advanced options dialog procedure - -class CDlgOptAdvanced: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - CCtrlCheck m_chkDirect; - CCtrlCheck m_chkDirectManual; - CCtrlCheck m_chkProxy; - CCtrlEdit m_txtDirect; - CCtrlEdit m_txtProxy; - CCtrlTreeOpts m_otvOptions; - -public: - CDlgOptAdvanced(CJabberProto *proto): - CJabberDlgBase(proto, IDD_OPT_JABBER2, NULL, false), - m_chkDirect(this, IDC_DIRECT), - m_chkDirectManual(this, IDC_DIRECT_MANUAL), - m_chkProxy(this, IDC_PROXY_MANUAL), - m_txtDirect(this, IDC_DIRECT_ADDR), - m_txtProxy(this, IDC_PROXY_ADDR), - m_otvOptions(this, IDC_OPTTREE) - { - CreateLink(m_chkDirect, proto->m_options.BsDirect); - CreateLink(m_chkDirectManual, proto->m_options.BsDirectManual); - CreateLink(m_chkProxy, proto->m_options.BsProxyManual); - CreateLink(m_txtDirect, "BsDirectAddr", _T("")); - CreateLink(m_txtProxy, "BsProxyServer", _T("")); - - m_chkDirect.OnChange = - m_chkDirectManual.OnChange = Callback(this, &CDlgOptAdvanced::chkDirect_OnChange); - m_chkProxy.OnChange = Callback(this, &CDlgOptAdvanced::chkProxy_OnChange); - - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Send messages slower, but with full acknowledgement"), m_proto->m_options.MsgAck); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable avatars"), m_proto->m_options.EnableAvatars); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log chat state changes"), m_proto->m_options.LogChatstates); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log presence subscription state changes"), m_proto->m_options.LogPresence); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log presence errors"), m_proto->m_options.LogPresenceErrors); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user moods receiving"), m_proto->m_options.EnableUserMood); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user tunes receiving"), m_proto->m_options.EnableUserTune); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user activity receiving"), m_proto->m_options.EnableUserActivity); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Receive notes"), m_proto->m_options.AcceptNotes); - m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Automatically save received notes"), m_proto->m_options.AutosaveNotes); - - m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Disable SASL authentication (for old servers)"), m_proto->m_options.Disable3920auth); - m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Enable stream compression (if possible)"), m_proto->m_options.EnableZlib); - - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Enable remote controlling (from another resource of same JID only)"), m_proto->m_options.EnableRemoteControl); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Show transport agents on contact list"), m_proto->m_options.ShowTransport); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Automatically add contact when accept authorization"), m_proto->m_options.AutoAdd); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Automatically accept authorization requests"), m_proto->m_options.AutoAcceptAuthorization); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Fix incorrect timestamps in incoming messages"), m_proto->m_options.FixIncorrectTimestamps); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Disable frame"), m_proto->m_options.DisableFrame); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Enable XMPP link processing (requires Association Manager)"), m_proto->m_options.ProcessXMPPLinks); - m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Keep contacts assigned to local groups (ignore roster group)"), m_proto->m_options.IgnoreRosterGroups); - - m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Allow servers to request version (XEP-0092)"), m_proto->m_options.AllowVersionRequests); - m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Show information about operating system in version replies"), m_proto->m_options.ShowOSVersion); - m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Accept only in band incoming filetransfers (don't disclose own IP)"), m_proto->m_options.BsOnlyIBB); - m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Accept HTTP Authentication requests (XEP-0070)"), m_proto->m_options.AcceptHttpAuth); - } - - void OnInitDialog() - { - CSuper::OnInitDialog(); - - chkDirect_OnChange(&m_chkDirect); - chkProxy_OnChange(&m_chkProxy); - } - - void OnApply() - { - BOOL bChecked = m_proto->m_options.ShowTransport; - LISTFOREACH(index, m_proto, LIST_ROSTER) - { - JABBER_LIST_ITEM* item = m_proto->ListGetItemPtrFromIndex( index ); - if ( item != NULL ) { - if ( _tcschr( item->jid, '@' ) == NULL ) { - HANDLE hContact = m_proto->HContactFromJID( item->jid ); - if ( hContact != NULL ) { - if ( bChecked ) { - if ( item->itemResource.status != m_proto->JGetWord( hContact, "Status", ID_STATUS_OFFLINE )) { - m_proto->JSetWord( hContact, "Status", ( WORD )item->itemResource.status ); - } } - else if ( m_proto->JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) - m_proto->JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); - } } } - } - - m_proto->SendPresence( m_proto->m_iStatus, true ); - } - - void chkDirect_OnChange(CCtrlData *) - { - if (m_chkDirect.GetState() == BST_CHECKED) - { - if (m_chkDirectManual.GetState() == BST_CHECKED) - m_txtDirect.Enable(); - else - m_txtDirect.Disable(); - - m_chkDirectManual.Enable(); - } else - { - m_txtDirect.Disable(); - m_chkDirectManual.Disable(); - } - } - - void chkProxy_OnChange(CCtrlData *) - { - if (m_chkProxy.GetState() == BST_CHECKED) - m_txtProxy.Enable(); - else - m_txtProxy.Disable(); - } - - static CDlgBase *Create(void *param) { return new CDlgOptAdvanced((CJabberProto *)param); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGcOptDlgProc - chat options dialog procedure - -class CDlgOptGc: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - CCtrlEdit m_txtAltNick; - CCtrlEdit m_txtSlap; - CCtrlEdit m_txtQuit; - CCtrlTreeOpts m_otvOptions; - -public: - CDlgOptGc(CJabberProto *proto): - CJabberDlgBase(proto, IDD_OPT_JABBER4, NULL, false), - m_txtAltNick(this, IDC_TXT_ALTNICK), - m_txtSlap(this, IDC_TXT_SLAP), - m_txtQuit(this, IDC_TXT_QUIT), - m_otvOptions(this, IDC_OPTTREE) - { - CreateLink(m_txtAltNick, "GcAltNick", _T("")); - CreateLink(m_txtSlap, "GcMsgSlap", TranslateTS(JABBER_GC_MSG_SLAP)); - CreateLink(m_txtQuit, "GcMsgQuit", TranslateTS(JABBER_GC_MSG_QUIT)); - - m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Autoaccept multiuser chat invitations"), m_proto->m_options.AutoAcceptMUC); - m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Automatically join bookmarks on login"), m_proto->m_options.AutoJoinBookmarks); - m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Automatically join conferences on login"), m_proto->m_options.AutoJoinConferences); - m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Hide conference windows at startup"), m_proto->m_options.AutoJoinHidden); - m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Do not show multiuser chat invitations"), m_proto->m_options.IgnoreMUCInvites); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Ban notifications"), m_proto->m_options.GcLogBans); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Room configuration changes"), m_proto->m_options.GcLogConfig); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Affiliation changes"), m_proto->m_options.GcLogAffiliations); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Role changes"), m_proto->m_options.GcLogRoles); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Status changes"), m_proto->m_options.GcLogStatuses); - m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Filter history messages"), m_proto->m_options.GcLogChatHistory); - } - - static CDlgBase *Create(void *param) { return new CDlgOptGc((CJabberProto *)param); } -}; - -////////////////////////////////////////////////////////////////////////// -// roster editor -// - -#include <io.h> -#define JM_STATUSCHANGED WM_USER+0x0001 -#define fopent(name, mode) _wfopen(name, mode) - -enum { - RRA_FILLLIST = 0, - RRA_SYNCROSTER, - RRA_SYNCDONE -}; - -typedef struct _tag_RosterhEditDat{ - WNDPROC OldEditProc; - HWND hList; - int index; - int subindex; -} ROSTEREDITDAT; - -static WNDPROC _RosterOldListProc=NULL; - -static int _RosterInsertListItem(HWND hList, const TCHAR * jid, const TCHAR * nick, const TCHAR * group, const TCHAR * subscr, BOOL bChecked) -{ - LVITEM item={0}; - int index; - item.mask=LVIF_TEXT|LVIF_STATE; - - item.iItem = ListView_GetItemCount(hList); - item.iSubItem = 0; - item.pszText = ( TCHAR* )jid; - - index=ListView_InsertItem(hList, &item); - - if ( index<0 ) - return index; - - ListView_SetCheckState(hList, index, bChecked); - - ListView_SetItemText(hList, index, 0, ( TCHAR* )jid); - ListView_SetItemText(hList, index, 1, ( TCHAR* )nick); - ListView_SetItemText(hList, index, 2, ( TCHAR* )group); - ListView_SetItemText(hList, index, 3, TranslateTS( subscr )); - - return index; -} - -static void _RosterListClear(HWND hwndDlg) -{ - HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); - if (!hList) return; - ListView_DeleteAllItems(hList); - while ( ListView_DeleteColumn( hList, 0)); - - LV_COLUMN column={0}; - column.mask=LVCF_TEXT; - column.cx=500; - - column.pszText=TranslateT("JID"); - ListView_InsertColumn(hList, 1, &column); - - column.pszText=TranslateT("Nick Name"); - ListView_InsertColumn(hList, 2, &column); - - column.pszText=TranslateT("Group"); - ListView_InsertColumn(hList, 3, &column); - - column.pszText=TranslateT("Subscription"); - ListView_InsertColumn(hList, 4, &column); - - RECT rc; - GetClientRect(hList, &rc); - int width=rc.right-rc.left; - - ListView_SetColumnWidth(hList,0,width*40/100); - ListView_SetColumnWidth(hList,1,width*25/100); - ListView_SetColumnWidth(hList,2,width*20/100); - ListView_SetColumnWidth(hList,3,width*10/100); -} - -void CJabberProto::_RosterHandleGetRequest( HXML node ) -{ - HWND hList=GetDlgItem(rrud.hwndDlg, IDC_ROSTER); - if (rrud.bRRAction==RRA_FILLLIST) - { - _RosterListClear(rrud.hwndDlg); - HXML query = xmlGetChild( node , "query"); - if (!query) return; - int i = 1; - while (TRUE) { - HXML item = xmlGetNthChild( query, _T("item"), i++); - if (!item) - break; - - const TCHAR *jid = xmlGetAttrValue( item, _T("jid")); - if (!jid) - continue; - - const TCHAR *name = xmlGetAttrValue( item, _T("name")); - const TCHAR *subscription = xmlGetAttrValue( item, _T("subscription")); - const TCHAR *group = NULL; - HXML groupNode = xmlGetChild( item , "group" ); - if ( groupNode ) - group = xmlGetText( groupNode ); - _RosterInsertListItem( hList, jid, name, group, subscription, TRUE ); - } - // now it is require to process whole contact list to add not in roster contacts - { - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) - { - char* str = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( str != NULL && !strcmp( str, m_szModuleName )) - { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) - { - LVFINDINFO lvfi={0}; - lvfi.flags = LVFI_STRING; - lvfi.psz = dbv.ptszVal; - TCHAR *p = _tcschr(dbv.ptszVal,_T('@')); - if ( p ) { - p = _tcschr( dbv.ptszVal, _T('/')); - if ( p ) *p = _T('\0'); - } - if ( ListView_FindItem(hList, -1, &lvfi) == -1) { - TCHAR *jid = mir_tstrdup( dbv.ptszVal ); - TCHAR *name = NULL; - TCHAR *group = NULL; - DBVARIANT dbvtemp; - if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbvtemp )) { - name = mir_tstrdup( dbvtemp.ptszVal ); - DBFreeVariant( &dbvtemp ); - } - if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbvtemp )) { - group = mir_tstrdup( dbvtemp.ptszVal ); - DBFreeVariant( &dbvtemp ); - } - _RosterInsertListItem( hList, jid, name, group, NULL, FALSE ); - if ( jid ) mir_free( jid ); - if ( name ) mir_free( name ); - if ( group ) mir_free( group ); - } - DBFreeVariant( &dbv ); - } - } - hContact = db_find_next(hContact); - } - } - rrud.bReadyToDownload = FALSE; - rrud.bReadyToUpload = TRUE; - SetDlgItemText( rrud.hwndDlg, IDC_DOWNLOAD, TranslateT( "Download" )); - SetDlgItemText( rrud.hwndDlg, IDC_UPLOAD, TranslateT( "Upload" )); - SendMessage( rrud.hwndDlg, JM_STATUSCHANGED, 0, 0 ); - return; - } - else if ( rrud.bRRAction == RRA_SYNCROSTER ) - { - SetDlgItemText(rrud.hwndDlg, IDC_UPLOAD, TranslateT("Uploading...")); - HXML queryRoster = xmlGetChild( node , "query"); - if (!queryRoster) - return; - - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::_RosterHandleGetRequest ); - - XmlNode iq( _T("iq")); - xmlAddAttr( iq, _T("type"), _T("set")); - iq << XATTRID( iqId ); - - HXML query = iq << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER)); - - int itemCount=0; - int ListItemCount=ListView_GetItemCount(hList); - for (int index=0; index<ListItemCount; index++) - { - TCHAR jid[JABBER_MAX_JID_LEN]=_T(""); - TCHAR name[260]=_T(""); - TCHAR group[260]=_T(""); - TCHAR subscr[260]=_T(""); - ListView_GetItemText(hList, index, 0, jid, SIZEOF(jid)); - ListView_GetItemText(hList, index, 1, name, SIZEOF(name)); - ListView_GetItemText(hList, index, 2, group, SIZEOF(group)); - ListView_GetItemText(hList, index, 3, subscr, SIZEOF(subscr)); - HXML itemRoster = xmlGetChildByTag( queryRoster, "item", "jid", jid); - BOOL bRemove = !ListView_GetCheckState(hList,index); - if (itemRoster && bRemove) - { - //delete item - query << XCHILD( _T("item")) << XATTR( _T("jid"), jid ) << XATTR( _T("subscription") ,_T("remove")); - itemCount++; - } - else if ( !bRemove ) - { - BOOL bPushed = itemRoster ? TRUE : FALSE; - if ( !bPushed ) { - const TCHAR *rosterName = xmlGetAttrValue( itemRoster, _T("name")); - if ( (rosterName!=NULL || name[0]!=_T('\0')) && lstrcmpi(rosterName,name)) - bPushed=TRUE; - if ( !bPushed ) { - rosterName = xmlGetAttrValue( itemRoster, _T("subscription")); - if ((rosterName!=NULL || subscr[0]!=_T('\0')) && lstrcmpi(rosterName,subscr)) - bPushed=TRUE; - } - if ( !bPushed ) { - HXML groupNode = xmlGetChild( itemRoster , "group" ); - const TCHAR* rosterGroup=NULL; - if (groupNode != NULL) - rosterGroup = xmlGetText( groupNode ); - if ((rosterGroup!=NULL || group[0]!=_T('\0')) && lstrcmpi(rosterGroup,group)) - bPushed=TRUE; - } - } - if ( bPushed ) { - HXML item = query << XCHILD( _T("item")); - if ( group && _tcslen( group )) - item << XCHILD( _T("group"), group ); - if ( name && _tcslen( name )) - item << XATTR( _T("name"), name ); - item << XATTR( _T("jid"), jid ) << XATTR( _T("subscription"), subscr[0] ? subscr : _T("none")); - itemCount++; - } - } - } - rrud.bRRAction=RRA_SYNCDONE; - if (itemCount) - m_ThreadInfo->send( iq ); - else - _RosterSendRequest(rrud.hwndDlg,RRA_FILLLIST); - } - else - { - SetDlgItemText(rrud.hwndDlg,IDC_UPLOAD,TranslateT("Upload")); - rrud.bReadyToUpload=FALSE; - rrud.bReadyToDownload=FALSE; - SendMessage(rrud.hwndDlg, JM_STATUSCHANGED,0,0); - SetDlgItemText(rrud.hwndDlg,IDC_DOWNLOAD,TranslateT("Downloading...")); - _RosterSendRequest(rrud.hwndDlg,RRA_FILLLIST); - - } -} - -void CJabberProto::_RosterSendRequest(HWND hwndDlg, BYTE rrAction) -{ - rrud.bRRAction=rrAction; - rrud.hwndDlg=hwndDlg; - - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::_RosterHandleGetRequest ); - m_ThreadInfo->send( XmlNode( _T("iq")) << XATTR( _T("type"), _T("get")) << XATTRID( iqId ) << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER ))); -} - -static void _RosterItemEditEnd( HWND hEditor, ROSTEREDITDAT * edat, BOOL bCancel ) -{ - if (!bCancel) - { - int len = GetWindowTextLength(hEditor) + 1; - TCHAR *buff=(TCHAR*)mir_alloc(len*sizeof(TCHAR)); - if ( buff ) { - GetWindowText(hEditor,buff,len); - ListView_SetItemText(edat->hList,edat->index, edat->subindex,buff); - } - mir_free(buff); - } - DestroyWindow(hEditor); -} - -static BOOL CALLBACK _RosterItemNewEditProc( HWND hEditor, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - ROSTEREDITDAT * edat = (ROSTEREDITDAT *) GetWindowLongPtr(hEditor,GWLP_USERDATA); - if (!edat) return 0; - switch(msg) - { - - case WM_KEYDOWN: - switch(wParam) - { - case VK_RETURN: - _RosterItemEditEnd(hEditor, edat, FALSE); - return 0; - case VK_ESCAPE: - _RosterItemEditEnd(hEditor, edat, TRUE); - return 0; - } - break; - case WM_GETDLGCODE: - if ( lParam ) { - MSG *msg2 = (MSG*)lParam; - if (msg2->message==WM_KEYDOWN && msg2->wParam==VK_TAB) return 0; - if (msg2->message==WM_CHAR && msg2->wParam=='\t') return 0; - } - return DLGC_WANTMESSAGE; - case WM_KILLFOCUS: - _RosterItemEditEnd(hEditor, edat, FALSE); - return 0; - } - - if (msg==WM_DESTROY) - { - SetWindowLongPtr(hEditor, GWLP_WNDPROC, (LONG_PTR) edat->OldEditProc); - SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR) 0); - free(edat); - return 0; - } - else return CallWindowProc( edat->OldEditProc, hEditor, msg, wParam, lParam); -} - - - -void CJabberProto::_RosterExportToFile(HWND hwndDlg) -{ - TCHAR filename[MAX_PATH]={0}; - - TCHAR filter[MAX_PATH]; - mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.xml)%c*.xml%c%c"), TranslateT("XML for MS Excel (UTF-8 encoded)"), 0, 0, 0); - OPENFILENAME ofn={0}; - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = hwndDlg; - ofn.hInstance = NULL; - ofn.lpstrFilter = filter; - ofn.lpstrFile = filename; - ofn.Flags = OFN_HIDEREADONLY; - ofn.nMaxFile = SIZEOF(filename); - ofn.nMaxFileTitle = MAX_PATH; - ofn.lpstrDefExt = _T("xml"); - if (!GetSaveFileName(&ofn)) return; - - FILE * fp = fopent(filename,_T("w")); - if (!fp) return; - HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); - int ListItemCount=ListView_GetItemCount(hList); - - XmlNode root(_T("Workbook")); - root << XATTR(_T("xmlns"), _T("urn:schemas-microsoft-com:office:spreadsheet")) - << XATTR(_T("xmlns:o"), _T("urn:schemas-microsoft-com:office:office")) - << XATTR(_T("xmlns:x"), _T("urn:schemas-microsoft-com:office:excel")) - << XATTR(_T("xmlns:ss"), _T("urn:schemas-microsoft-com:office:spreadsheet")) - << XATTR(_T("xmlns:html"), _T("http://www.w3.org/TR/REC-html40")); - root << XCHILD(_T("ExcelWorkbook")) - << XATTR(_T("xmlns"), _T("urn:schemas-microsoft-com:office:excel")); - HXML table = root << XCHILD(_T("Worksheet")) << XATTR(_T("ss:Name"), _T("Exported roster")) - << XCHILD(_T("Table")); - - for (int index=0; index<ListItemCount; index++) - { - TCHAR jid[JABBER_MAX_JID_LEN]=_T(""); - TCHAR name[260]=_T(""); - TCHAR group[260]=_T(""); - TCHAR subscr[260]=_T(""); - ListView_GetItemText(hList, index, 0, jid, SIZEOF(jid)); - ListView_GetItemText(hList, index, 1, name, SIZEOF(name)); - ListView_GetItemText(hList, index, 2, group, SIZEOF(group)); - ListView_GetItemText(hList, index, 3, subscr, SIZEOF(subscr)); - - HXML node = table << XCHILD(_T("Row")); - node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), _T("+")) << XATTR(_T("ss:Type"), _T("String")); - node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), jid) << XATTR(_T("ss:Type"), _T("String")); - node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), name) << XATTR(_T("ss:Type"), _T("String")); - node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), group) << XATTR(_T("ss:Type"), _T("String")); - node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), subscr) << XATTR(_T("ss:Type"), _T("String")); - - } - - char header[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n"; - fwrite(header, 1, sizeof(header) - 1 /* for zero terminator */, fp); - - TCHAR *xtmp = xi.toString(root, NULL); - char *tmp = mir_utf8encodeT(xtmp); - xi.freeMem(xtmp); - - fwrite(tmp, 1, strlen(tmp), fp); - mir_free(tmp); - fclose(fp); -} - -void CJabberProto::_RosterImportFromFile(HWND hwndDlg) -{ - char filename[MAX_PATH]={0}; - char *filter="XML for MS Excel (UTF-8 encoded)(*.xml)\0*.xml\0\0"; - OPENFILENAMEA ofn={0}; - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = hwndDlg; - ofn.hInstance = NULL; - ofn.lpstrFilter = filter; - ofn.lpstrFile = filename; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - ofn.nMaxFile = sizeof(filename); - ofn.nMaxFileTitle = MAX_PATH; - ofn.lpstrDefExt = "xml"; - if ( !GetOpenFileNameA( &ofn )) - return; - - FILE * fp=fopen(filename,"r"); - if (!fp) - return; - - DWORD bufsize = _filelength(_fileno(fp)); - if (bufsize <= 0) { - fclose(fp); - return; - } - - char* buffer=(char*)mir_calloc(bufsize+1); // zero-terminate it - fread(buffer,1,bufsize,fp); - fclose(fp); - _RosterListClear(hwndDlg); - - TCHAR* newBuf = mir_utf8decodeT( buffer ); - mir_free( buffer ); - - int nBytesProcessed = 0; - XmlNode node( newBuf, &nBytesProcessed, NULL ); - if ( node ) { - HXML Workbook = xmlGetChild( node, _T("Workbook")); - if ( Workbook ) { - HXML Worksheet = xmlGetChild( Workbook , "Worksheet"); - if ( Worksheet ) { - HXML Table = xmlGetChild( Worksheet , "Table" ); - if ( Table ) { - int index=1; - HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); - while (TRUE) - { - HXML Row = xmlGetNthChild( Table, _T("Row"), index++ ); - if (!Row) - break; - - BOOL bAdd=FALSE; - const TCHAR* jid=NULL; - const TCHAR* name=NULL; - const TCHAR* group=NULL; - const TCHAR* subscr=NULL; - HXML Cell = xmlGetNthChild( Row, _T("Cell"), 1 ); - HXML Data = (Cell) ? xmlGetChild( Cell , "Data") : XmlNode(); - if ( Data ) - { - if (!lstrcmpi(xmlGetText( Data ),_T("+"))) bAdd=TRUE; - else if (lstrcmpi(xmlGetText( Data ),_T("-"))) continue; - - Cell = xmlGetNthChild( Row, _T("Cell"),2); - if (Cell) Data=xmlGetChild( Cell , "Data"); - else Data = NULL; - if (Data) - { - jid=xmlGetText( Data ); - if (!jid || lstrlen(jid)==0) continue; - } - - Cell=xmlGetNthChild( Row,_T("Cell"),3); - if (Cell) Data=xmlGetChild( Cell , "Data"); - else Data = NULL; - if (Data) name=xmlGetText( Data ); - - Cell=xmlGetNthChild( Row,_T("Cell"),4); - if (Cell) Data=xmlGetChild( Cell , "Data"); - else Data = NULL; - if (Data) group=xmlGetText( Data ); - - Cell=xmlGetNthChild( Row,_T("Cell"),5); - if (Cell) Data=xmlGetChild( Cell , "Data"); - else Data = NULL; - if (Data) subscr=xmlGetText( Data ); - } - _RosterInsertListItem(hList,jid,name,group,subscr,bAdd); - } } } } } - - mir_free( newBuf ); - SendMessage(hwndDlg, JM_STATUSCHANGED, 0, 0); -} - -static BOOL CALLBACK _RosterNewListProc( HWND hList, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - if (msg==WM_MOUSEWHEEL || msg==WM_NCLBUTTONDOWN || msg==WM_NCRBUTTONDOWN) - { - SetFocus(hList); - } - - if (msg==WM_LBUTTONDOWN) - { - POINT pt; - GetCursorPos(&pt); - ScreenToClient(hList, &pt); - - LVHITTESTINFO lvhti={0}; - lvhti.pt=pt; - ListView_SubItemHitTest(hList,&lvhti); - if (lvhti.flags&LVHT_ONITEM && lvhti.iSubItem !=0) - { - RECT rc; - TCHAR buff[260]; - ListView_GetSubItemRect(hList, lvhti.iItem, lvhti.iSubItem, LVIR_BOUNDS,&rc); - ListView_GetItemText(hList, lvhti.iItem, lvhti.iSubItem, buff, SIZEOF(buff)); - HWND hEditor=CreateWindow(TEXT("EDIT"),buff,WS_CHILD|ES_AUTOHSCROLL,rc.left+3, rc.top+2, rc.right-rc.left-3, rc.bottom - rc.top-3,hList, NULL, hInst, NULL); - SendMessage(hEditor,WM_SETFONT,(WPARAM)SendMessage(hList,WM_GETFONT,0,0),0); - ShowWindow(hEditor,SW_SHOW); - SetWindowText(hEditor, buff); - ClientToScreen(hList, &pt); - ScreenToClient(hEditor, &pt); - mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); - mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); - - ROSTEREDITDAT * edat=(ROSTEREDITDAT *)malloc(sizeof(ROSTEREDITDAT)); - edat->OldEditProc=(WNDPROC)GetWindowLongPtr(hEditor, GWLP_WNDPROC); - SetWindowLongPtr(hEditor,GWLP_WNDPROC,(LONG_PTR)_RosterItemNewEditProc); - edat->hList=hList; - edat->index=lvhti.iItem; - edat->subindex=lvhti.iSubItem; - SetWindowLongPtr(hEditor,GWLP_USERDATA,(LONG_PTR)edat); - } - } - return CallWindowProc(_RosterOldListProc, hList, msg, wParam, lParam ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberRosterOptDlgProc - advanced options dialog procedure - -static int sttRosterEditorResizer(HWND /*hwndDlg*/, LPARAM, UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDC_HEADERBAR: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH; - case IDC_ROSTER: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT|RD_ANCHORX_WIDTH; - case IDC_DOWNLOAD: - case IDC_UPLOAD: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - case IDC_EXPORT: - case IDC_IMPORT: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; -// case IDC_STATUSBAR: -// return RD_ANCHORX_LEFT|RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; - } - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; -} - -static INT_PTR CALLBACK JabberRosterOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case JM_STATUSCHANGED: - { - int count = ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_ROSTER)); - EnableWindow( GetDlgItem( hwndDlg, IDC_DOWNLOAD ), ppro->m_bJabberOnline ); - EnableWindow( GetDlgItem( hwndDlg, IDC_UPLOAD ), count && ppro->m_bJabberOnline ); - EnableWindow( GetDlgItem( hwndDlg, IDC_EXPORT ), count > 0); - break; - } - case WM_CLOSE: - { - DestroyWindow(hwndDlg); - break; - } - case WM_DESTROY: - { - Utils_SaveWindowPosition(hwndDlg, NULL, ppro->m_szModuleName, "rosterCtrlWnd_"); - ppro->rrud.hwndDlg = NULL; - WindowFreeIcon(hwndDlg); - break; - } - case WM_INITDIALOG: - { - ppro = ( CJabberProto* )lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - TranslateDialogDefault( hwndDlg ); - WindowSetIcon( hwndDlg, ppro, "Agents" ); - - Utils_RestoreWindowPosition(hwndDlg, NULL, ppro->m_szModuleName, "rosterCtrlWnd_"); - - ListView_SetExtendedListViewStyle(GetDlgItem(hwndDlg,IDC_ROSTER), LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT /*| LVS_EX_FULLROWSELECT*/ | LVS_EX_GRIDLINES /*| LVS_EX_HEADERDRAGDROP*/ ); - _RosterOldListProc=(WNDPROC) GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_ROSTER), GWLP_WNDPROC); - SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_ROSTER), GWLP_WNDPROC, (LONG_PTR) _RosterNewListProc); - _RosterListClear(hwndDlg); - ppro->rrud.hwndDlg = hwndDlg; - ppro->rrud.bReadyToDownload = TRUE; - ppro->rrud.bReadyToUpload = FALSE; - SendMessage( hwndDlg, JM_STATUSCHANGED, 0, 0 ); - - return TRUE; - } - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 550; - lpmmi->ptMinTrackSize.y = 390; - return 0; - } - case WM_SIZE: - { - UTILRESIZEDIALOG urd = {0}; - urd.cbSize = sizeof(urd); - urd.hInstance = hInst; - urd.hwndDlg = hwndDlg; - urd.lpTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER3); - urd.pfnResizer = sttRosterEditorResizer; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); - break; - } - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDC_DOWNLOAD: - ppro->rrud.bReadyToUpload = FALSE; - ppro->rrud.bReadyToDownload = FALSE; - SendMessage( ppro->rrud.hwndDlg, JM_STATUSCHANGED,0,0); - SetDlgItemText( ppro->rrud.hwndDlg, IDC_DOWNLOAD, TranslateT("Downloading...")); - ppro->_RosterSendRequest(hwndDlg, RRA_FILLLIST); - break; - - case IDC_UPLOAD: - ppro->rrud.bReadyToUpload = FALSE; - SendMessage( ppro->rrud.hwndDlg, JM_STATUSCHANGED, 0, 0 ); - SetDlgItemText( ppro->rrud.hwndDlg, IDC_UPLOAD, TranslateT("Connecting...")); - ppro->_RosterSendRequest( hwndDlg, RRA_SYNCROSTER ); - break; - - case IDC_EXPORT: - ppro->_RosterExportToFile( hwndDlg ); - break; - - case IDC_IMPORT: - ppro->_RosterImportFromFile( hwndDlg ); - break; - } - break; - } - return FALSE; -} - -INT_PTR __cdecl CJabberProto::OnMenuHandleRosterControl( WPARAM, LPARAM ) -{ - if ( rrud.hwndDlg && IsWindow( rrud.hwndDlg )) - SetForegroundWindow( rrud.hwndDlg ); - else - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_OPT_JABBER3 ), NULL, JabberRosterOptDlgProc, ( LPARAM )this ); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberOptInit - initializes all options dialogs - -int CJabberProto::OnOptionsInit( WPARAM wParam, LPARAM ) -{ - OPTIONSDIALOGPAGE odp = { 0 }; - odp.cbSize = sizeof( odp ); - odp.hInstance = hInst; - odp.ptszGroup = LPGENT("Network"); - odp.ptszTitle = m_tszUserName; - odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; - - odp.ptszTab = LPGENT("Account"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER); - odp.pfnDlgProc = CDlgBase::DynamicDlgProc; - odp.dwInitParam = (LPARAM)&OptCreateAccount; - OptCreateAccount.create = CDlgOptAccount::Create; - OptCreateAccount.param = this; - Options_AddPage(wParam, &odp); - - odp.ptszTab = LPGENT("Conferences"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER4); - odp.pfnDlgProc = CDlgBase::DynamicDlgProc; - odp.dwInitParam = (LPARAM)&OptCreateGc; - OptCreateGc.create = CDlgOptGc::Create; - OptCreateGc.param = this; - Options_AddPage(wParam, &odp); - - odp.flags |= ODPF_EXPERTONLY; - - odp.ptszTab = LPGENT("Advanced"); - odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_JABBER2 ); - odp.pfnDlgProc = CDlgBase::DynamicDlgProc; - odp.dwInitParam = (LPARAM)&OptCreateAdvanced; - OptCreateAdvanced.create = CDlgOptAdvanced::Create; - OptCreateAdvanced.param = this; - Options_AddPage(wParam, &odp); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Account manager UI - -class CJabberDlgAccMgrUI: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - CCtrlCombo m_cbType; - CCtrlEditJid m_txtUsername; - CCtrlCombo m_cbServer; - CCtrlEdit m_txtPassword; - CCtrlCheck m_chkSavePassword; - CCtrlCheck m_chkUseDomainLogin; - CCtrlCombo m_cbResource; - CCtrlCheck m_chkManualHost; - CCtrlEdit m_txtManualHost; - CCtrlEdit m_txtPort; - CCtrlButton m_btnRegister; - -public: - CJabberDlgAccMgrUI(CJabberProto *proto, HWND hwndParent): - CJabberDlgBase(proto, IDD_ACCMGRUI, hwndParent, false), - m_cbType(this, IDC_CB_TYPE), - m_txtUsername(this, IDC_EDIT_USERNAME), - m_txtPassword(this, IDC_EDIT_PASSWORD), - m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), - m_chkSavePassword(this, IDC_SAVEPASSWORD), - m_cbResource(this, IDC_COMBO_RESOURCE), - m_cbServer(this, IDC_EDIT_LOGIN_SERVER), - m_txtPort(this, IDC_PORT), - m_chkManualHost(this, IDC_MANUAL), - m_txtManualHost(this, IDC_HOST), - m_btnRegister(this, IDC_BUTTON_REGISTER) - { - CreateLink(m_txtUsername, "LoginName", _T("")); - CreateLink(m_chkSavePassword, proto->m_options.SavePassword); - CreateLink(m_cbResource, "Resource", _T("Miranda")); - CreateLink(m_cbServer, "LoginServer", _T("jabber.org")); - CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); - CreateLink(m_chkUseDomainLogin, proto->m_options.UseDomainLogin); - - // Bind events - m_cbType.OnChange = Callback(this, &CJabberDlgAccMgrUI::cbType_OnChange); - m_cbServer.OnDropdown = Callback(this, &CJabberDlgAccMgrUI::cbServer_OnDropdown); - m_chkManualHost.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkManualHost_OnChange); - m_chkUseDomainLogin.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkUseDomainLogin_OnChange); - - m_btnRegister.OnClick = Callback(this, &CJabberDlgAccMgrUI::btnRegister_OnClick); - } - -protected: - enum { ACC_PUBLIC, ACC_TLS, ACC_SSL, ACC_GTALK, ACC_LJTALK, ACC_FBOOK, ACC_VK, ACC_SMS }; - - void OnInitDialog() - { - CSuper::OnInitDialog(); - - int i; - DBVARIANT dbv; - char server[256], manualServer[256]={0}; - - m_gotservers = false; - - TCHAR *passw = m_proto->JGetStringCrypt(NULL, "LoginPassword"); - if (passw) - { - m_txtPassword.SetText(passw); - mir_free(passw); - } - - m_cbServer.AddString(TranslateT("Loading...")); - - // fill predefined resources - TCHAR* szResources[] = { _T("Home"), _T("Work"), _T("Office"), _T("Miranda") }; - for (i = 0; i < SIZEOF(szResources); ++i) - m_cbResource.AddString(szResources[i]); - - // append computer name to the resource list - TCHAR szCompName[ MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; - if (GetComputerName(szCompName, &dwCompNameLength)) - m_cbResource.AddString(szCompName); - - if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "Resource", &dbv)) - { - if(CB_ERR == m_cbResource.FindString(dbv.ptszVal, -1, true)) - m_cbResource.AddString(dbv.ptszVal); - - m_cbResource.SetText(dbv.ptszVal); - JFreeVariant(&dbv); - } else - { - m_cbResource.SetText(_T("Miranda")); - } - - m_cbType.AddString(TranslateT("Public XMPP Network"), ACC_PUBLIC); - m_cbType.AddString(TranslateT("Secure XMPP Network"), ACC_TLS); - m_cbType.AddString(TranslateT("Secure XMPP Network (old style)"), ACC_SSL); - m_cbType.AddString(TranslateT("Google Talk!"), ACC_GTALK); - m_cbType.AddString(TranslateT("LiveJournal Talk"), ACC_LJTALK); - m_cbType.AddString(TranslateT("Facebook Chat"), ACC_FBOOK); - m_cbType.AddString(TranslateT("Vkontakte"), ACC_VK); - m_cbType.AddString(TranslateT("S.ms"), ACC_SMS); - - m_cbServer.GetTextA(server, SIZEOF(server)); - if (!DBGetContactSettingString(NULL, m_proto->m_szModuleName, "ManualHost", &dbv)) - { - lstrcpynA(manualServer, dbv.pszVal, SIZEOF(manualServer)); - JFreeVariant(&dbv); - } - - m_canregister = true; - if (!lstrcmpA(manualServer, "talk.google.com")) - { - m_cbType.SetCurSel(ACC_GTALK); - m_canregister = false; - } - else if (!lstrcmpA(server, "livejournal.com")) - { - m_cbType.SetCurSel(ACC_LJTALK); - m_canregister = false; - } - else if (!lstrcmpA(server, "chat.facebook.com")) - { - m_cbType.SetCurSel(ACC_FBOOK); - m_canregister = false; - } - else if (!lstrcmpA(server, "vk.com")) - { - m_cbType.SetCurSel(ACC_VK); - m_canregister = false; - } - else if (!lstrcmpA(server, "S.ms")) - { - m_cbType.SetCurSel(ACC_SMS); - m_canregister = false; - } - else if (m_proto->m_options.UseSSL) - m_cbType.SetCurSel(ACC_SSL); - else if (m_proto->m_options.UseTLS) { - m_cbType.SetCurSel(ACC_TLS); - m_txtPort.SetInt(5222); - } - else - m_cbType.SetCurSel(ACC_PUBLIC); - //cbType_OnChange(&m_cbType); - - if (m_chkManualHost.Enabled()) - { - if (m_proto->m_options.ManualConnect) - { - m_chkManualHost.SetState(BST_CHECKED); - m_txtManualHost.Enable(); - m_txtPort.Enable(); - - if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "ManualHost", &dbv)) - { - m_txtManualHost.SetText(dbv.ptszVal); - JFreeVariant(&dbv); - } - - m_txtPort.SetInt(m_proto->JGetWord(NULL, "ManualPort", m_txtPort.GetInt())); - } else - { - int defPort = m_txtPort.GetInt(); - int port = m_proto->JGetWord(NULL, "Port", defPort); - - if (port != defPort) - { - m_chkManualHost.SetState(BST_CHECKED); - m_txtManualHost.Enable(); - m_txtPort.Enable(); - - m_txtManualHost.SetTextA(server); - m_txtPort.SetInt(port); - } else - { - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - } - } - } - - if (m_proto->m_options.UseDomainLogin) - chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); - - CheckRegistration(); - } - - void OnApply() - { - // clear saved password - *m_proto->m_savedPassword = 0; - - BOOL bUseHostnameAsResource = FALSE; - TCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1], szResource[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; - if (GetComputerName(szCompName, &dwCompNameLength)) - { - m_cbResource.GetText(szResource, SIZEOF(szResource)); - if (!lstrcmp(szCompName, szResource)) - bUseHostnameAsResource = TRUE; - } - m_proto->m_options.HostNameAsResource = bUseHostnameAsResource; - - if (m_chkSavePassword.GetState() == BST_CHECKED) - { - TCHAR *text = m_txtPassword.GetText(); - m_proto->JSetStringCrypt(NULL, "LoginPassword", text); - mir_free(text); - } else - { - m_proto->JDeleteSetting(NULL, "LoginPassword"); - } - - switch (m_cbType.GetItemData(m_cbType.GetCurSel())) - { - case ACC_FBOOK: - m_proto->m_options.IgnoreRosterGroups = TRUE; - - case ACC_VK: - case ACC_PUBLIC: - m_proto->m_options.UseSSL = m_proto->m_options.UseTLS = FALSE; - break; - - case ACC_GTALK: - m_proto->JSetWord(NULL, "Priority", 24); - { - int port = m_txtPort.GetInt(); - if (port == 443 || port == 5223) - { - m_proto->m_options.UseSSL = TRUE; - m_proto->m_options.UseTLS = FALSE; - } - else if (port == 5222) - { - m_proto->m_options.UseSSL = FALSE; - m_proto->m_options.UseTLS = TRUE; - } - } - break; - - case ACC_TLS: - case ACC_LJTALK: - case ACC_SMS: - m_proto->m_options.UseSSL = FALSE; - m_proto->m_options.UseTLS = TRUE; - break; - - case ACC_SSL: - m_proto->m_options.UseSSL = TRUE; - m_proto->m_options.UseTLS = FALSE; - break; - } - - char server[256]; - char manualServer[256]; - - m_cbServer.GetTextA(server, SIZEOF(server)); - m_txtManualHost.GetTextA(manualServer, SIZEOF(manualServer)); - - if ((m_chkManualHost.GetState() == BST_CHECKED) && lstrcmpA(server, manualServer)) - { - m_proto->m_options.ManualConnect = TRUE; - m_proto->JSetString(NULL, "ManualHost", manualServer); - m_proto->JSetWord(NULL, "ManualPort", m_txtPort.GetInt()); - m_proto->JSetWord(NULL, "Port", m_txtPort.GetInt()); - } else - { - m_proto->m_options.ManualConnect = FALSE; - m_proto->JDeleteSetting(NULL, "ManualHost"); - m_proto->JDeleteSetting(NULL, "ManualPort"); - m_proto->JSetWord(NULL, "Port", m_txtPort.GetInt()); - } - - sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); - - if (m_proto->m_bJabberOnline) - { - if (m_cbType.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || - m_cbServer.IsChanged() || m_txtPort.IsChanged() || m_txtManualHost.IsChanged()) - { - MessageBox(m_hwnd, - TranslateT("Some changes will take effect the next time you connect to the Jabber network."), - TranslateT("Jabber Protocol Option"), MB_OK|MB_SETFOREGROUND); - } - - m_proto->SendPresence(m_proto->m_iStatus, true); - } - } - - void OnChange(CCtrlBase*) - { - if (m_initialized) - CheckRegistration(); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - switch (msg) { - case WM_JABBER_REFRESH: - RefreshServers(( HXML )lParam); - break; - } - return CSuper::DlgProc(msg, wParam, lParam); - } - -private: - bool m_gotservers; - bool m_canregister; - - void btnRegister_OnClick(CCtrlButton *) - { - TCHAR buf[512] = _T(""), pass[512]; - if (!m_proto->EnterString(buf, SIZEOF(buf), TranslateT("Confirm password"), JES_PASSWORD)) - return; - - m_txtPassword.GetText(pass, SIZEOF(pass)); - if (lstrcmp(buf, pass)) - { - MessageBox(m_hwnd, TranslateT("Passwords do not match."), _T("Miranda NG"), MB_ICONSTOP|MB_OK); - return; - } - - ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); - m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); - m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); - m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); - regInfo.port = (WORD)m_txtPort.GetInt(); - if (m_chkManualHost.GetState() == BST_CHECKED) - { - m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); - } else - { - regInfo.manualHost[0] = '\0'; - } - - if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) - { - CJabberDlgRegister dlg(m_proto, m_hwnd, ®Info); - dlg.DoModal(); -// DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_OPT_REGISTER), m_hwnd, JabberRegisterDlgProc, (LPARAM)®Info); - } - } - - void cbServer_OnDropdown(CCtrlCombo* ) - { - if ( !m_gotservers ) - mir_forkthread(QueryServerListThread, this); - } - - void cbType_OnChange(CCtrlData *sender) - { - CCtrlCombo *chk = (CCtrlCombo *)sender; - setupConnection(chk->GetItemData(chk->GetCurSel())); - CheckRegistration(); - } - - void chkUseDomainLogin_OnChange(CCtrlData *sender) - { - CCtrlCheck *chk = (CCtrlCheck *)sender; - BOOL checked = chk->GetState() == BST_CHECKED; - - m_txtPassword.Enable(!checked); - m_txtUsername.Enable(!checked); - m_chkSavePassword.Enable(!checked); - if (checked) { - m_txtPassword.SetText(_T("")); - m_txtUsername.SetText(_T("")); - m_chkSavePassword.SetState(BST_CHECKED); - } - } - - void chkManualHost_OnChange(CCtrlData *sender) - { - CCtrlCheck *chk = (CCtrlCheck *)sender; - - if (chk->GetState() == BST_CHECKED) - { - char buf[256]; - m_cbServer.GetTextA(buf, SIZEOF(buf)); - m_txtManualHost.SetTextA(buf); - m_txtPort.SetInt(5222); - - m_txtManualHost.Enable(); - m_txtPort.Enable(); - } else - { - m_txtManualHost.Disable(); - m_txtPort.Disable(); - } - } - - void CheckRegistration(); - void setupConnection(int type); - void setupPublic(); - void setupSecure(); - void setupSecureSSL(); - void setupGoogle(); - void setupLJ(); - void setupFB(); - void setupVK(); - void setupSMS(); - void RefreshServers( HXML node); - static void QueryServerListThread(void *arg); -}; - -void CJabberDlgAccMgrUI::CheckRegistration() -{ - if ( !m_canregister ) { - m_btnRegister.Disable(); - return; - } - - ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); - m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); - m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); - m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); - regInfo.port = (WORD)m_txtPort.GetInt(); - if (m_chkManualHost.GetState() == BST_CHECKED) - m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); - else - regInfo.manualHost[0] = '\0'; - - if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) - m_btnRegister.Enable(); - else - m_btnRegister.Disable(); -} - -void CJabberDlgAccMgrUI::setupConnection(int type) -{ - switch (type) { - case ACC_PUBLIC: setupPublic(); break; - case ACC_TLS: setupSecure(); break; - case ACC_SSL: setupSecureSSL(); break; - case ACC_GTALK: setupGoogle(); break; - case ACC_LJTALK: setupLJ(); break; - case ACC_FBOOK: setupFB(); break; - case ACC_VK: setupVK(); break; - case ACC_SMS: setupSMS(); break; - } -} - -void CJabberDlgAccMgrUI::setupPublic() -{ - m_canregister = true; - m_gotservers = false; - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5222); - - m_cbServer.Enable(); - m_chkManualHost.Enable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Enable(); -} - -void CJabberDlgAccMgrUI::setupSecure() -{ - m_canregister = true; - m_gotservers = false; - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5222); - - m_cbServer.Enable(); - m_chkManualHost.Enable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Enable(); -} - -void CJabberDlgAccMgrUI::setupSecureSSL() -{ - m_canregister = true; - m_gotservers = false; - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5223); - - m_cbServer.Enable(); - m_chkManualHost.Enable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Enable(); -} - -void CJabberDlgAccMgrUI::setupGoogle() -{ - m_canregister = false; - m_gotservers = true; - m_cbServer.ResetContent(); - m_cbServer.AddStringA("gmail.com"); - m_cbServer.AddStringA("googlemail.com"); - m_cbServer.SetTextA("gmail.com"); - m_chkManualHost.SetState(BST_CHECKED); - m_txtManualHost.SetTextA("talk.google.com"); - m_txtPort.SetInt(443); - - m_cbServer.Enable(); - m_chkManualHost.Disable(); - m_txtManualHost.Disable(); - //m_txtPort.Disable(); - m_btnRegister.Disable(); -} - -void CJabberDlgAccMgrUI::setupLJ() -{ - m_canregister = false; - m_gotservers = true; - m_cbServer.ResetContent(); - m_cbServer.SetTextA("livejournal.com"); - m_cbServer.AddStringA("livejournal.com"); - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5222); - - m_cbServer.Disable(); - m_chkManualHost.Disable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Disable(); -} - -void CJabberDlgAccMgrUI::setupFB() -{ - m_canregister = false; - m_gotservers = true; - m_cbServer.ResetContent(); - m_cbServer.SetTextA("chat.facebook.com"); - m_cbServer.AddStringA("chat.facebook.com"); - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(443); - - m_cbServer.Disable(); - m_chkManualHost.Disable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Disable(); -} - -void CJabberDlgAccMgrUI::setupVK() -{ - m_canregister = false; - m_gotservers = true; - m_cbServer.ResetContent(); - m_cbServer.SetTextA("VK.com"); - m_cbServer.AddStringA("VK.com"); - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5222); - - m_cbServer.Disable(); - m_chkManualHost.Disable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Disable(); -} - -void CJabberDlgAccMgrUI::setupSMS() -{ - m_canregister = false; - m_gotservers = true; - m_cbServer.ResetContent(); - m_cbServer.SetTextA("S.ms"); - m_cbServer.AddStringA("S.ms"); - m_chkManualHost.SetState(BST_UNCHECKED); - m_txtManualHost.SetTextA(""); - m_txtPort.SetInt(5222); - - m_cbServer.Disable(); - m_chkManualHost.Disable(); - m_txtManualHost.Disable(); - m_txtPort.Disable(); - m_btnRegister.Disable(); - // m_cbResource.Disable(); -} - -void CJabberDlgAccMgrUI::RefreshServers( HXML node ) -{ - m_gotservers = node != NULL; - - TCHAR *server = m_cbServer.GetText(); - bool bDropdown = m_cbServer.GetDroppedState(); - if (bDropdown) m_cbServer.ShowDropdown(false); - - m_cbServer.ResetContent(); - if ( node ) - { - for (int i = 0; ; ++i) { - HXML n = xmlGetChild(node, i); - if ( !n ) - break; - - if ( !lstrcmp( xmlGetName( n ), _T("item"))) - if ( const TCHAR *jid = xmlGetAttrValue( n, _T("jid"))) - if (m_cbServer.FindString(jid, -1, true) == CB_ERR) - m_cbServer.AddString(jid); - } - } - - m_cbServer.SetText(server); - - if (bDropdown) m_cbServer.ShowDropdown(); - mir_free(server); -} - -void CJabberDlgAccMgrUI::QueryServerListThread(void *arg) -{ - CDlgOptAccount *wnd = (CDlgOptAccount *)arg; - HWND hwnd = wnd->GetHwnd(); - bool bIsError = true; - - NETLIBHTTPREQUEST request = {0}; - request.cbSize = sizeof(request); - request.requestType = REQUEST_GET; - request.flags = NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11; - request.szUrl = "http://xmpp.org/services/services.xml"; - - NETLIBHTTPREQUEST *result = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)wnd->GetProto()->m_hNetlibUser, (LPARAM)&request); - if ( result && IsWindow( hwnd )) { - if ((result->resultCode == 200) && result->dataLength && result->pData) { - TCHAR* ptszText = mir_a2t( result->pData ); - XmlNode node( ptszText, NULL, NULL ); - if ( node ) { - HXML queryNode = xmlGetChild( node, _T("query")); - if ( queryNode && IsWindow(hwnd)) { - SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); - bIsError = false; - } } - mir_free( ptszText ); - } } - - if ( result ) - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)result); - if ( bIsError ) - SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)NULL); -} - -INT_PTR CJabberProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) -{ - CJabberDlgAccMgrUI *dlg = new CJabberDlgAccMgrUI(this, (HWND)lParam); - dlg->Show(); - return (INT_PTR)dlg->GetHwnd(); -} - -void CJabberProto::JabberUpdateDialogs( BOOL ) -{ - if ( rrud.hwndDlg ) - SendMessage(rrud.hwndDlg, JM_STATUSCHANGED, 0,0); -} - -INT_PTR __cdecl CJabberProto::OnMenuOptions( WPARAM, LPARAM ) -{ - OPENOPTIONSDIALOG ood = {0}; - ood.cbSize = sizeof(ood); - ood.pszGroup = "Network"; - ood.pszPage = mir_t2a(m_tszUserName); - ood.pszTab = "Account"; - Options_Open(&ood); - - mir_free((void *)ood.pszPage); - return 0; -} - -int CJabberProto::OnModernOptInit( WPARAM, LPARAM ) -{/* - static int iBoldControls[] = - { - IDC_TITLE1, MODERNOPT_CTRL_LAST - }; - - MODERNOPTOBJECT obj = {0}; - obj.cbSize = sizeof(obj); - obj.dwFlags = MODEROPT_FLG_TCHAR; - obj.hIcon = LoadIconEx("main"); - obj.hInstance = hInst; - obj.iSection = MODERNOPT_PAGE_ACCOUNTS; - obj.iType = MODERNOPT_TYPE_SUBSECTIONPAGE; - obj.lptzSubsection = mir_a2t(m_szModuleName); // title!!!!!!!!!!! - obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT); - obj.iBoldControls = iBoldControls; - obj.pfnDlgProc = JabberWizardDlgProc; - obj.lpszClassicGroup = "Network"; - obj.lpszClassicPage = m_szModuleName; // title!!!!!!!!!!! - obj.lpszHelpUrl = "http://forums.miranda-im.org/showthread.php?t=14294"; - CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj); - mir_free(obj.lptzSubsection); */ - return 0; -} diff --git a/protocols/JabberG/jabber_opttree.cpp b/protocols/JabberG/jabber_opttree.cpp deleted file mode 100644 index bd43b55a08..0000000000 --- a/protocols/JabberG/jabber_opttree.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2007 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_opttree.h" - -enum { IMG_GROUP, IMG_CHECK, IMG_NOCHECK, IMG_RCHECK, IMG_NORCHECK, IMG_GRPOPEN, IMG_GRPCLOSED }; - -CCtrlTreeOpts::CCtrlTreeOpts(CDlgBase* dlg, int ctrlId): - CCtrlTreeView(dlg, ctrlId), - m_options(5) -{ -} - -CCtrlTreeOpts::~CCtrlTreeOpts() -{ - for (int i = 0; i < m_options.getCount(); ++i) - delete m_options[i]; - m_options.destroy(); -} - -void CCtrlTreeOpts::AddOption(TCHAR *szOption, CMOption<BYTE> &option) -{ - m_options.insert(new COptionsItem(szOption, option), m_options.getCount()); -} - -BOOL CCtrlTreeOpts::OnNotify(int idCtrl, NMHDR *pnmh) -{ - switch (pnmh->code) - { - case TVN_KEYDOWN: - { - LPNMTVKEYDOWN lpnmtvkd = (LPNMTVKEYDOWN)pnmh; - HTREEITEM hti; - if ((lpnmtvkd->wVKey == VK_SPACE) && (hti = GetSelection())) - ProcessItemClick(hti); - break; - } - - case NM_CLICK: - { - TVHITTESTINFO hti; - hti.pt.x=(short)LOWORD(GetMessagePos()); - hti.pt.y=(short)HIWORD(GetMessagePos()); - ScreenToClient(pnmh->hwndFrom,&hti.pt); - if(HitTest(&hti)) - if(hti.flags&TVHT_ONITEMICON) - ProcessItemClick(hti.hItem); - break; - } - - case TVN_ITEMEXPANDEDW: - { - LPNMTREEVIEWW lpnmtv = (LPNMTREEVIEWW)pnmh; - TVITEM tvi; - tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; - tvi.hItem = lpnmtv->itemNew.hItem; - tvi.iImage = tvi.iSelectedImage = - (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; - SendMessageW(pnmh->hwndFrom, TVM_SETITEMW, 0, (LPARAM)&tvi); - break; - } - - case TVN_ITEMEXPANDEDA: - { - LPNMTREEVIEWA lpnmtv = (LPNMTREEVIEWA)pnmh; - TVITEM tvi; - tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; - tvi.hItem = lpnmtv->itemNew.hItem; - tvi.iImage = tvi.iSelectedImage = - (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; - SendMessageA(pnmh->hwndFrom, TVM_SETITEMA, 0, (LPARAM)&tvi); - break; - } - } - - return CCtrlTreeView::OnNotify(idCtrl, pnmh); -} - -void CCtrlTreeOpts::OnInit() -{ - CCtrlTreeView::OnInit(); - - TCHAR itemName[1024]; - HIMAGELIST hImgLst; - - SelectItem(NULL); - DeleteAllItems(); - - hImgLst = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR|ILC_COLOR32|ILC_MASK, 5, 1); - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_TICK)); // check on - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); // check off - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_TICK)); // radio on - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); // radio on - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN)); - ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT)); - SetImageList(hImgLst, TVSIL_NORMAL); - - /* build options tree. based on code from IcoLib */ - for (int i = 0; i < m_options.getCount(); i++) - { - TCHAR* sectionName; - int sectionLevel = 0; - - HTREEITEM hSection = NULL; - lstrcpy(itemName, m_options[i]->m_szOptionName); - sectionName = itemName; - - while (sectionName) - { - // allow multi-level tree - TCHAR* pItemName = sectionName; - HTREEITEM hItem; - - if (sectionName = _tcschr(sectionName, '/')) - { - // one level deeper - *sectionName = 0; - sectionName++; - } - - hItem = FindNamedItem(hSection, pItemName); - if (!sectionName || !hItem) - { - if (!hItem) - { - TVINSERTSTRUCT tvis = {0}; - - tvis.hParent = hSection; - tvis.hInsertAfter = TVI_LAST;//TVI_SORT; - tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; - tvis.item.pszText = pItemName; - tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED; - if (sectionName) - { - tvis.item.lParam = -1; - tvis.item.state |= TVIS_BOLD; - tvis.item.stateMask |= TVIS_BOLD; - tvis.item.iImage = tvis.item.iSelectedImage = IMG_GRPOPEN; - } else - { - tvis.item.lParam = i; - - BYTE val = *m_options[i]->m_option; - - if (m_options[i]->m_groupId == OPTTREE_CHECK) - { - tvis.item.iImage = tvis.item.iSelectedImage = val ? IMG_CHECK : IMG_NOCHECK; - } else - { - tvis.item.iImage = tvis.item.iSelectedImage = val ? IMG_RCHECK : IMG_NORCHECK; - } - } - hItem = InsertItem(&tvis); - if (!sectionName) - m_options[i]->m_hItem = hItem; - } - } - sectionLevel++; - hSection = hItem; - } - } - - TranslateTree(); - ShowWindow(m_hwnd, SW_SHOW); - SelectItem(FindNamedItem(0, NULL)); -} - -void CCtrlTreeOpts::OnDestroy() -{ - ImageList_Destroy(GetImageList(TVSIL_NORMAL)); -} - -void CCtrlTreeOpts::OnApply() -{ - CCtrlTreeView::OnApply(); - - for (int i = 0; i < m_options.getCount(); ++i) - { - TVITEMEX tvi; - GetItem(m_options[i]->m_hItem, &tvi); - *m_options[i]->m_option = ((tvi.iImage == IMG_CHECK) || (tvi.iImage == IMG_RCHECK)) ? 1 : 0; - } -} - -void CCtrlTreeOpts::ProcessItemClick(HTREEITEM hti) -{ - TVITEMEX tvi; - GetItem(hti, &tvi); - switch (tvi.iImage) - { - case IMG_GRPOPEN: - tvi.iImage = tvi.iSelectedImage = IMG_GRPCLOSED; - Expand(tvi.hItem, TVE_COLLAPSE); - break; - case IMG_GRPCLOSED: - tvi.iImage = tvi.iSelectedImage = IMG_GRPOPEN; - Expand(tvi.hItem, TVE_EXPAND); - break; - - case IMG_CHECK: - tvi.iImage = tvi.iSelectedImage = IMG_NOCHECK; - SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); - break; - case IMG_NOCHECK: - tvi.iImage = tvi.iSelectedImage = IMG_CHECK; - SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); - break; - case IMG_NORCHECK: - { - int i; - for (i = 0; i < m_options.getCount(); ++i) - { - if (m_options[i]->m_groupId == m_options[tvi.lParam]->m_groupId) - { - TVITEMEX tvi_tmp; - tvi_tmp.mask = TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; - tvi_tmp.hItem = m_options[i]->m_hItem; - tvi_tmp.iImage = tvi_tmp.iSelectedImage = IMG_NORCHECK; - SetItem(&tvi_tmp); - } - } - tvi.iImage = tvi.iSelectedImage = IMG_RCHECK; - SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); - break; - } - } - - SetItem(&tvi); -} - -CCtrlTreeOpts::COptionsItem::COptionsItem(TCHAR *szOption, CMOption<BYTE> &option): - m_option(&option), m_groupId(OPTTREE_CHECK), m_hItem(NULL) -{ - m_szOptionName = mir_tstrdup(szOption); -} - -CCtrlTreeOpts::COptionsItem::~COptionsItem() -{ - mir_free(m_szOptionName); -} diff --git a/protocols/JabberG/jabber_opttree.h b/protocols/JabberG/jabber_opttree.h deleted file mode 100644 index 3246ad74a3..0000000000 --- a/protocols/JabberG/jabber_opttree.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2007 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __jabber_opttree_h__ -#define __jabber_opttree_h__ - -#define OPTTREE_CHECK 0 - -class CCtrlTreeOpts : public CCtrlTreeView -{ - typedef CCtrlTreeView CSuper; - -public: - CCtrlTreeOpts( CDlgBase* dlg, int ctrlId ); - ~CCtrlTreeOpts(); - - void AddOption(TCHAR *szOption, CMOption<BYTE> &option); - - BOOL OnNotify(int idCtrl, NMHDR *pnmh); - void OnDestroy(); - void OnInit(); - void OnApply(); - -protected: - struct COptionsItem - { - TCHAR *m_szOptionName; - int m_groupId; - - CMOption<BYTE> *m_option; - - HTREEITEM m_hItem; - - COptionsItem(TCHAR *szOption, CMOption<BYTE> &option); - ~COptionsItem(); - }; - - LIST<COptionsItem> m_options; - - void ProcessItemClick(HTREEITEM hti); -}; - -#endif // __opttree_h__ diff --git a/protocols/JabberG/jabber_password.cpp b/protocols/JabberG/jabber_password.cpp deleted file mode 100644 index 2ce5128b78..0000000000 --- a/protocols/JabberG/jabber_password.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_caps.h" - -static INT_PTR CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ); - -INT_PTR __cdecl CJabberProto::OnMenuHandleChangePassword( WPARAM, LPARAM ) -{ - if ( IsWindow( m_hwndJabberChangePassword )) - SetForegroundWindow( m_hwndJabberChangePassword ); - else - m_hwndJabberChangePassword = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_CHANGEPASSWORD ), NULL, JabberChangePasswordDlgProc, ( LPARAM )this ); - - return 0; -} - -static INT_PTR CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - CJabberProto* ppro = (CJabberProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - switch ( msg ) { - case WM_INITDIALOG: - ppro = (CJabberProto*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )lParam ); - - WindowSetIcon( hwndDlg, ppro, "key" ); - TranslateDialogDefault( hwndDlg ); - if ( ppro->m_bJabberOnline && ppro->m_ThreadInfo!=NULL ) { - TCHAR text[1024]; - mir_sntprintf( text, SIZEOF( text ), _T("%s %s@") _T(TCHAR_STR_PARAM), TranslateT( "Set New Password for" ), ppro->m_ThreadInfo->username, ppro->m_ThreadInfo->server ); - SetWindowText( hwndDlg, text ); - } - return TRUE; - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDOK: - if ( ppro->m_bJabberOnline && ppro->m_ThreadInfo!=NULL ) { - TCHAR newPasswd[512], text[512]; - GetDlgItemText( hwndDlg, IDC_NEWPASSWD, newPasswd, SIZEOF( newPasswd )); - GetDlgItemText( hwndDlg, IDC_NEWPASSWD2, text, SIZEOF( text )); - if ( _tcscmp( newPasswd, text )) { - MessageBox( hwndDlg, TranslateT( "New password does not match." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); - break; - } - GetDlgItemText( hwndDlg, IDC_OLDPASSWD, text, SIZEOF( text )); - if ( _tcscmp( text, ppro->m_ThreadInfo->password )) { - MessageBox( hwndDlg, TranslateT( "Current password is incorrect." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); - break; - } - _tcsncpy( ppro->m_ThreadInfo->newPassword, newPasswd, SIZEOF( ppro->m_ThreadInfo->newPassword )); - - int iqId = ppro->SerialNext(); - ppro->IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultSetPassword ); - - XmlNodeIq iq( _T("set"), iqId, _A2T(ppro->m_ThreadInfo->server)); - HXML q = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); - q << XCHILD( _T("username"), ppro->m_ThreadInfo->username ); - q << XCHILD( _T("password"), newPasswd ); - ppro->m_ThreadInfo->send( iq ); - } - DestroyWindow( hwndDlg ); - break; - case IDCANCEL: - DestroyWindow( hwndDlg ); - break; - } - break; - case WM_CLOSE: - DestroyWindow( hwndDlg ); - break; - case WM_DESTROY: - ppro->m_hwndJabberChangePassword = NULL; - WindowFreeIcon( hwndDlg ); - break; - } - - return FALSE; -} diff --git a/protocols/JabberG/jabber_presence_manager.cpp b/protocols/JabberG/jabber_presence_manager.cpp deleted file mode 100644 index 8a8ece811d..0000000000 --- a/protocols/JabberG/jabber_presence_manager.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_presence_manager.h" - -BOOL CJabberPresenceManager::FillPermanentHandlers() -{ - return TRUE; -} - -BOOL CJabberPresenceManager::HandlePresencePermanent(HXML node, ThreadData *pThreadData) -{ - BOOL bStopHandling = FALSE; - Lock(); - CJabberPresencePermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo && !bStopHandling ) { - CJabberPresenceInfo presenceInfo; - presenceInfo.m_pUserData = pInfo->m_pUserData; - - if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &presenceInfo)) { - bStopHandling = TRUE; - break; - } - pInfo = pInfo->m_pNext; - } - Unlock(); - - return bStopHandling; -} diff --git a/protocols/JabberG/jabber_presence_manager.h b/protocols/JabberG/jabber_presence_manager.h deleted file mode 100644 index be138d3b93..0000000000 --- a/protocols/JabberG/jabber_presence_manager.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_PRESENCE_MANAGER_H_ -#define _JABBER_PRESENCE_MANAGER_H_ - -#include "jabber_xml.h" - -struct CJabberProto; -typedef void ( CJabberProto::*JABBER_PRESENCE_PFUNC )( HXML node, void *usedata ); -typedef void ( *PRESENCE_USER_DATA_FREE_FUNC )( void *pUserData ); - -class CJabberPresenceInfo; - -typedef BOOL ( CJabberProto::*JABBER_PRESENCE_HANDLER )( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ); - -class CJabberPresenceInfo -{ -protected: - friend class CJabberPresenceManager; - JABBER_PRESENCE_HANDLER m_pHandler; - CJabberPresenceInfo* m_pNext; - -public: - void *m_pUserData; - - CJabberPresenceInfo() - { - ZeroMemory(this, sizeof(*this)); - } - ~CJabberPresenceInfo() - { - } - void* GetUserData() - { - return m_pUserData; - } -}; - -class CJabberPresencePermanentInfo -{ - friend class CJabberPresenceManager; - - CJabberPresencePermanentInfo* m_pNext; - - JABBER_PRESENCE_HANDLER m_pHandler; - void *m_pUserData; - PRESENCE_USER_DATA_FREE_FUNC m_pUserDataFree; - int m_iPriority; -public: - CJabberPresencePermanentInfo() - { - ZeroMemory(this, sizeof(CJabberPresencePermanentInfo)); - } - ~CJabberPresencePermanentInfo() - { - if ( m_pUserDataFree ) - m_pUserDataFree(m_pUserData); - } -}; - -class CJabberPresenceManager -{ -protected: - CJabberProto* ppro; - CRITICAL_SECTION m_cs; - CJabberPresencePermanentInfo* m_pPermanentHandlers; - -public: - CJabberPresenceManager( CJabberProto* proto ) - { - InitializeCriticalSection(&m_cs); - m_pPermanentHandlers = NULL; - ppro = proto; - } - ~CJabberPresenceManager() - { - Lock(); - CJabberPresencePermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo ) - { - CJabberPresencePermanentInfo *pTmp = pInfo->m_pNext; - delete pInfo; - pInfo = pTmp; - } - m_pPermanentHandlers = NULL; - Unlock(); - DeleteCriticalSection(&m_cs); - } - BOOL Start() - { - return TRUE; - } - BOOL Shutdown() - { - return TRUE; - } - void Lock() - { - EnterCriticalSection(&m_cs); - } - void Unlock() - { - LeaveCriticalSection(&m_cs); - } - CJabberPresencePermanentInfo* AddPermanentHandler(JABBER_PRESENCE_HANDLER pHandler, void *pUserData = NULL, PRESENCE_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) - { - CJabberPresencePermanentInfo* pInfo = new CJabberPresencePermanentInfo(); - if (!pInfo) - return NULL; - - pInfo->m_pHandler = pHandler; - pInfo->m_pUserData = pUserData; - pInfo->m_pUserDataFree = pUserDataFree; - pInfo->m_iPriority = iPriority; - - Lock(); - if (!m_pPermanentHandlers) - m_pPermanentHandlers = pInfo; - else - { - if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { - pInfo->m_pNext = m_pPermanentHandlers; - m_pPermanentHandlers = pInfo; - } else - { - CJabberPresencePermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) - pTmp = pTmp->m_pNext; - pInfo->m_pNext = pTmp->m_pNext; - pTmp->m_pNext = pInfo; - } - } - Unlock(); - - return pInfo; - } - BOOL DeletePermanentHandler(CJabberPresencePermanentInfo *pInfo) - { // returns TRUE when pInfo found, or FALSE otherwise - Lock(); - if (!m_pPermanentHandlers) - { - Unlock(); - return FALSE; - } - if (m_pPermanentHandlers == pInfo) // check first item - { - m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } else - { - CJabberPresencePermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext) - { - if (pTmp->m_pNext == pInfo) - { - pTmp->m_pNext = pTmp->m_pNext->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } - pTmp = pTmp->m_pNext; - } - } - Unlock(); - return FALSE; - } - BOOL HandlePresencePermanent(HXML node, ThreadData *pThreadData); - BOOL FillPermanentHandlers(); -}; - -#endif diff --git a/protocols/JabberG/jabber_privacy.cpp b/protocols/JabberG/jabber_privacy.cpp deleted file mode 100644 index 636cf50bf6..0000000000 --- a/protocols/JabberG/jabber_privacy.cpp +++ /dev/null @@ -1,2328 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_privacy.h" - -#include <m_icolib.h> -#include <m_genmenu.h> -#include <m_clistint.h> - -#define JABBER_PL_BUSY_MSG "Sending request, please wait..." - -BOOL CJabberProto::OnIqRequestPrivacyLists( HXML, CJabberIqInfo* pInfo ) -{ - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_SET ) { - if ( !m_pDlgPrivacyLists ) - { - m_privacyListManager.RemoveAllLists(); - QueryPrivacyLists(); - } - else m_pDlgPrivacyLists->SetStatusText(TranslateT("Warning: privacy lists were changed on server.")); - - XmlNodeIq iq( _T("result"), pInfo ); - m_ThreadInfo->send( iq ); - } - return TRUE; -} - -void CJabberProto::OnIqResultPrivacyListModify( HXML, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->m_pUserData ) - return; - - CPrivacyListModifyUserParam *pParam = ( CPrivacyListModifyUserParam * )pInfo->m_pUserData; - - if ( pInfo->m_nIqType != JABBER_IQ_TYPE_RESULT ) - pParam->m_bAllOk = FALSE; - - InterlockedDecrement( &pParam->m_dwCount ); - if ( !pParam->m_dwCount ) { - TCHAR szText[ 512 ]; - if ( !pParam->m_bAllOk ) - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while applying changes")); - else - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy lists successfully saved")); - if (m_pDlgPrivacyLists) - m_pDlgPrivacyLists->SetStatusText( szText ); - // FIXME: enable apply button - delete pParam; - } -} - -void CJabberProto::OnIqResultPrivacyList( HXML iqNode ) -{ - if ( !iqNode ) - return; - - const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); - if ( !type ) - return; - - if ( !_tcscmp( type, _T("result"))) { - HXML query = xmlGetChild( iqNode , "query" ); - if ( !query ) - return; - HXML list = xmlGetChild( query , "list" ); - if ( !list ) - return; - TCHAR *szListName = ( TCHAR* )xmlGetAttrValue( list, _T("name")); - if ( !szListName ) - return; - m_privacyListManager.Lock(); - CPrivacyList* pList = m_privacyListManager.FindList( szListName ); - if ( !pList ) { - m_privacyListManager.AddList( szListName ); - pList = m_privacyListManager.FindList( szListName ); - if ( !pList ) { - m_privacyListManager.Unlock(); - return; - } } - - HXML item; - for ( int i = 1; ( item = xmlGetNthChild( list, _T("item"), i )) != NULL; i++ ) { - const TCHAR *itemType = xmlGetAttrValue( item, _T("type")); - PrivacyListRuleType nItemType = Else; - if ( itemType ) { - if ( !_tcsicmp( itemType, _T( "jid" ))) - nItemType = Jid; - else if ( !_tcsicmp( itemType, _T( "group" ))) - nItemType = Group; - else if ( !_tcsicmp( itemType, _T( "subscription" ))) - nItemType = Subscription; - } - - const TCHAR *itemValue = xmlGetAttrValue( item, _T("value")); - - const TCHAR *itemAction = xmlGetAttrValue( item, _T("action")); - BOOL bAllow = TRUE; - if ( itemAction && !_tcsicmp( itemAction, _T( "deny" ))) - bAllow = FALSE; - - const TCHAR *itemOrder = xmlGetAttrValue( item, _T("order")); - DWORD dwOrder = 0; - if ( itemOrder ) - dwOrder = _ttoi( itemOrder ); - - DWORD dwPackets = 0; - if ( xmlGetChild( item , "message" )) - dwPackets |= JABBER_PL_RULE_TYPE_MESSAGE; - if ( xmlGetChild( item , "presence-in" )) - dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_IN; - if ( xmlGetChild( item , "presence-out" )) - dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; - if ( xmlGetChild( item , "iq" )) - dwPackets |= JABBER_PL_RULE_TYPE_IQ; - - pList->AddRule( nItemType, itemValue, bAllow, dwOrder, dwPackets ); - } - pList->Reorder(); - pList->SetLoaded(); - pList->SetModified(FALSE); - m_privacyListManager.Unlock(); - - UI_SAFE_NOTIFY(m_pDlgPrivacyLists, WM_JABBER_REFRESH); -} } - -CPrivacyList* GetSelectedList(HWND hDlg) -{ - LRESULT nCurSel = SendDlgItemMessage( hDlg, IDC_LB_LISTS, LB_GETCURSEL, 0, 0 ); - if ( nCurSel == LB_ERR ) - return NULL; - - LRESULT nItemData = SendDlgItemMessage( hDlg, IDC_LB_LISTS, LB_GETITEMDATA, nCurSel, 0 ); - if ( nItemData == LB_ERR || nItemData == 0 ) - return NULL; - - return ( CPrivacyList* )nItemData; -} - -CPrivacyListRule* GetSelectedRule(HWND hDlg) -{ - LRESULT nCurSel = SendDlgItemMessage( hDlg, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); - if ( nCurSel == LB_ERR) - return NULL; - - LRESULT nItemData = SendDlgItemMessage( hDlg, IDC_PL_RULES_LIST, LB_GETITEMDATA, nCurSel, 0 ); - if ( nItemData == LB_ERR || nItemData == 0 ) - return NULL; - - return (CPrivacyListRule* )nItemData; -} - -void CJabberProto::OnIqResultPrivacyListActive( HXML iqNode, CJabberIqInfo* pInfo ) -{ - CPrivacyList *pList = (CPrivacyList *)pInfo->GetUserData(); - - if ( m_pDlgPrivacyLists ) - EnableWindow( GetDlgItem( m_pDlgPrivacyLists->GetHwnd(), IDC_ACTIVATE ), TRUE ); - - if ( !iqNode ) - return; - - const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); - if ( !type ) - return; - - TCHAR szText[ 512 ]; - szText[0] = _T('\0'); - m_privacyListManager.Lock(); - if ( !_tcscmp( type, _T("result"))) { - if ( pList ) { - m_privacyListManager.SetActiveListName( pList->GetListName()); - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy list %s set as active"), pList->GetListName()); - } - else { - m_privacyListManager.SetActiveListName( NULL ); - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Active privacy list successfully declined")); - } - } - else mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while setting active list")); - - m_privacyListManager.Unlock(); - - if ( m_pDlgPrivacyLists ) - { - m_pDlgPrivacyLists->SetStatusText( szText ); - RedrawWindow(GetDlgItem(m_pDlgPrivacyLists->GetHwnd(), IDC_LB_LISTS), NULL, NULL, RDW_INVALIDATE); - } - - BuildPrivacyListsMenu( true ); -} - -void CJabberProto::OnIqResultPrivacyListDefault( HXML iqNode, CJabberIqInfo* pInfo ) -{ - CPrivacyList *pList = (CPrivacyList *)pInfo->GetUserData(); - - if ( m_pDlgPrivacyLists ) - EnableWindow( GetDlgItem( m_pDlgPrivacyLists->GetHwnd(), IDC_SET_DEFAULT ), TRUE ); - - if ( !iqNode ) - return; - - const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); - if ( !type ) - return; - - TCHAR szText[ 512 ]; - szText[0] = _T('\0'); - m_privacyListManager.Lock(); - if ( !_tcscmp( type, _T("result"))) { - if ( pList ) { - m_privacyListManager.SetDefaultListName( pList->GetListName()); - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy list %s set as default"), pList->GetListName()); - } - else { - m_privacyListManager.SetDefaultListName( NULL ); - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Default privacy list successfully declined")); - } - } - else { - mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while setting default list")); - } - m_privacyListManager.Unlock(); - - if ( m_pDlgPrivacyLists ) - { - m_pDlgPrivacyLists->SetStatusText( szText ); - RedrawWindow(GetDlgItem(m_pDlgPrivacyLists->GetHwnd(), IDC_LB_LISTS), NULL, NULL, RDW_INVALIDATE); - } -} - -void CJabberProto::OnIqResultPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( pInfo->m_nIqType != JABBER_IQ_TYPE_RESULT ) - return; - - HXML query = xmlGetChild( iqNode, "query" ); - if ( !query ) - return; - - if ( m_ThreadInfo ) - m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PRIVACY_LISTS; - - m_privacyListManager.Lock(); - m_privacyListManager.RemoveAllLists(); - - for ( int i = 1; ; i++ ) { - HXML list = xmlGetNthChild( query, _T("list"), i ); - if ( !list ) - break; - - const TCHAR *listName = xmlGetAttrValue( list, _T("name")); - if ( listName ) { - m_privacyListManager.AddList(( TCHAR* )listName); - - // Query contents only if list editior is visible! - if ( m_pDlgPrivacyLists ) { - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultPrivacyList); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)) << XCHILD( _T("list")) << XATTR( _T("name"), listName )); - } } } - - const TCHAR *szName = NULL; - HXML node = xmlGetChild( query , "active" ); - if ( node ) - szName = xmlGetAttrValue( node, _T("name")); - m_privacyListManager.SetActiveListName( szName ); - - szName = NULL; - node = xmlGetChild( query , "default" ); - if ( node ) - szName = xmlGetAttrValue( node, _T("name")); - m_privacyListManager.SetDefaultListName( szName ); - - m_privacyListManager.Unlock(); - - UI_SAFE_NOTIFY(m_pDlgPrivacyLists, WM_JABBER_REFRESH); - - BuildPrivacyListsMenu( true ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Add privacy list box -class CJabberDlgPrivacyAddList: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - TCHAR szLine[512]; - - CJabberDlgPrivacyAddList(CJabberProto *proto, HWND hwndParent): - CJabberDlgBase(proto, IDD_PRIVACY_ADD_LIST, hwndParent, false), - m_txtName(this, IDC_EDIT_NAME), - m_btnOk(this, IDOK), - m_btnCancel(this, IDCANCEL) - { - m_btnOk.OnClick = Callback( this, &CJabberDlgPrivacyAddList::btnOk_OnClick ); - m_btnCancel.OnClick = Callback( this, &CJabberDlgPrivacyAddList::btnCancel_OnClick); - } - - void btnOk_OnClick(CCtrlButton*) - { - GetDlgItemText(m_hwnd, IDC_EDIT_NAME, szLine, SIZEOF(szLine)); - EndDialog(m_hwnd, 1); - } - void btnCancel_OnClick(CCtrlButton*) - { - *szLine = 0; - EndDialog(m_hwnd, 0); - } - -private: - CCtrlEdit m_txtName; - CCtrlButton m_btnOk; - CCtrlButton m_btnCancel; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Privacy rule editor -class CJabberDlgPrivacyRule: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - - CCtrlButton m_btnOk; - CCtrlButton m_btnCancel; - CCtrlCombo m_cbType; - -public: - CPrivacyListRule *m_pRule; - - CJabberDlgPrivacyRule(CJabberProto *proto, HWND hwndParent, CPrivacyListRule *pRule): - CJabberDlgBase(proto, IDD_PRIVACY_RULE, hwndParent, false), - m_btnOk(this, IDOK), - m_btnCancel(this, IDCANCEL), - m_cbType(this, IDC_COMBO_TYPE) - { - m_pRule = pRule; - m_cbType.OnChange = Callback(this, &CJabberDlgPrivacyRule::cbType_OnChange); - m_btnOk.OnClick = Callback(this, &CJabberDlgPrivacyRule::btnOk_OnClick); - m_btnCancel.OnClick = Callback(this, &CJabberDlgPrivacyRule::btnCancel_OnClick); - } - - virtual void OnInitDialog() - { - CSuper::OnInitDialog(); - - m_proto->m_hwndPrivacyRule = m_hwnd; - - SendDlgItemMessage(m_hwnd, IDC_ICO_MESSAGE, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_msg_allow"), 0); - SendDlgItemMessage(m_hwnd, IDC_ICO_QUERY, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_iq_allow"), 0); - SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEIN, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_prin_allow"), 0); - SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEOUT, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_prout_allow"), 0); - - TCHAR* szTypes[] = { _T("JID"), _T("Group"), _T("Subscription"), _T("Any") }; - int i, nTypes[] = { Jid, Group, Subscription, Else }; - for ( i = 0; i < SIZEOF(szTypes); i++ ) - { - LRESULT nItem = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateTS( szTypes[i] )); - SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_SETITEMDATA, nItem, nTypes[i] ); - if ( m_pRule->GetType() == nTypes[i] ) - SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_SETCURSEL, nItem, 0 ); - } - - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_RESETCONTENT, 0, 0 ); - TCHAR* szSubscriptions[] = { _T("none"), _T("from"), _T("to"), _T("both") }; - for ( i = 0; i < SIZEOF(szSubscriptions); i++ ) - { - LRESULT nItem = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_ADDSTRING, 0, (LPARAM)TranslateTS( szSubscriptions[i] )); - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETITEMDATA, nItem, (LPARAM)szSubscriptions[i] ); - } - - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_COMBO_TYPE, CBN_SELCHANGE ), 0 ); - - SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateTS( _T("Deny" ))); - SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateTS( _T("Allow" ))); - - SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_SETCURSEL, m_pRule->GetAction() ? 1 : 0, 0 ); - - DWORD dwPackets = m_pRule->GetPackets(); - if ( !dwPackets ) - dwPackets = JABBER_PL_RULE_TYPE_ALL; - if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) - SendDlgItemMessage( m_hwnd, IDC_CHECK_QUERIES, BM_SETCHECK, BST_CHECKED, 0 ); - if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) - SendDlgItemMessage( m_hwnd, IDC_CHECK_MESSAGES, BM_SETCHECK, BST_CHECKED, 0 ); - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) - SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_IN, BM_SETCHECK, BST_CHECKED, 0 ); - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) - SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_OUT, BM_SETCHECK, BST_CHECKED, 0 ); - - if ( m_pRule->GetValue() && ( m_pRule->GetType() == Jid || m_pRule->GetType() == Group )) - SetDlgItemText( m_hwnd, IDC_EDIT_VALUE, m_pRule->GetValue()); - } - - void cbType_OnChange(CCtrlData*) - { - if ( !m_pRule ) return; - - LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0 ); - if ( nCurSel == CB_ERR ) - return; - - LRESULT nItemData = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETITEMDATA, nCurSel, 0 ); - switch (nItemData) - { - case Jid: - { - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_SHOW ); - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); - - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_RESETCONTENT, 0, 0 ); - - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) - { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_proto->m_szModuleName )) - { - DBVARIANT dbv; - if ( !m_proto->JGetStringT( hContact, "jid", &dbv )) - { - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)dbv.ptszVal ); - JFreeVariant( &dbv ); - } - } - hContact = db_find_next(hContact); - } - - // append known chatroom jids from bookmarks - LISTFOREACH(i, m_proto, LIST_BOOKMARK) - { - JABBER_LIST_ITEM *item = 0; - if ( item = m_proto->ListGetItemPtrFromIndex( i )) - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)item->jid ); - } - - // FIXME: ugly code :) - if ( m_pRule->GetValue()) - { - SetDlgItemText( m_hwnd, IDC_COMBO_VALUES, m_pRule->GetValue()); - LRESULT nSelPos = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_FINDSTRINGEXACT , -1, (LPARAM)m_pRule->GetValue()); - if ( nSelPos != CB_ERR ) - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_SETCURSEL, nSelPos, 0 ); - } - break; - } - - case Group: - { - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_SHOW ); - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); - - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_RESETCONTENT, 0, 0 ); - - char buf[ 20 ]; - DBVARIANT dbv; - for ( int i = 0; ; i++ ) - { - mir_snprintf(buf, 20, "%d", i); - if ( DBGetContactSettingTString(NULL, "CListGroups", buf, &dbv)) - break; - - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)&dbv.ptszVal[1] ); - DBFreeVariant(&dbv); - } - - // FIXME: ugly code :) - if ( m_pRule->GetValue()) - { - SetDlgItemText( m_hwnd, IDC_COMBO_VALUES, m_pRule->GetValue()); - LRESULT nSelPos = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_FINDSTRINGEXACT , -1, (LPARAM)m_pRule->GetValue()); - if ( nSelPos != CB_ERR ) - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_SETCURSEL, nSelPos, 0 ); - } - break; - } - - case Subscription: - { - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_HIDE ); - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_SHOW ); - - if ( m_pRule->GetValue()) - { - LRESULT nSelected = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SELECTSTRING, -1, (LPARAM)TranslateTS(m_pRule->GetValue())); - if ( nSelected == CB_ERR ) - SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETCURSEL, 0, 0 ); - } - else SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETCURSEL, 0, 0 ); - break; - } - - case Else: - { - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_HIDE ); - ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); - break; - } - } - - return; - } - - void btnOk_OnClick(CCtrlButton *) - { - LRESULT nItemData = -1; - LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0 ); - if ( nCurSel != CB_ERR ) - nItemData = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETITEMDATA, nCurSel, 0 ); - - switch ( nItemData ) - { - case Jid: - case Group: - { - TCHAR szText[ 512 ]; - GetDlgItemText( m_hwnd, IDC_COMBO_VALUES, szText, SIZEOF(szText)); - m_pRule->SetValue( szText ); - break; - } - case Subscription: - { - nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_GETCURSEL, 0, 0 ); - if ( nCurSel != CB_ERR ) - m_pRule->SetValue(( TCHAR* )SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_GETITEMDATA, nCurSel, 0 )); - else - m_pRule->SetValue( _T( "none" )); - break; - } - - default: - m_pRule->SetValue( NULL ); - break; - } - - m_pRule->SetType( ( PrivacyListRuleType )nItemData ); - nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_GETCURSEL, 0, 0 ); - if ( nCurSel == CB_ERR ) - nCurSel = 1; - m_pRule->SetAction( nCurSel ? TRUE : FALSE ); - - DWORD dwPackets = 0; - if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_MESSAGES, BM_GETCHECK, 0, 0 )) - dwPackets |= JABBER_PL_RULE_TYPE_MESSAGE; - if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_IN, BM_GETCHECK, 0, 0 )) - dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_IN; - if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_OUT, BM_GETCHECK, 0, 0 )) - dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; - if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_QUERIES, BM_GETCHECK, 0, 0 )) - dwPackets |= JABBER_PL_RULE_TYPE_IQ; - if ( !dwPackets ) - dwPackets = JABBER_PL_RULE_TYPE_ALL; - - m_pRule->SetPackets( dwPackets ); - - EndDialog( m_hwnd, 1 ); - } - - void btnCancel_OnClick(CCtrlButton *) - { - EndDialog(m_hwnd, 0); - } - - void OnDestroy() - { - g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_MESSAGE, STM_SETICON, 0, 0)); - g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_QUERY, STM_SETICON, 0, 0)); - g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEIN, STM_SETICON, 0, 0)); - g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEOUT, STM_SETICON, 0, 0)); - m_proto->m_hwndPrivacyRule = NULL; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Main privacy list dialog -class CJabberDlgPrivacyLists: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgPrivacyLists(CJabberProto *proto); - -protected: - static int idSimpleControls[]; - static int idAdvancedControls[]; - - void OnInitDialog(); - void OnClose(); - void OnDestroy(); - void OnProtoRefresh(WPARAM, LPARAM); - int Resizer(UTILRESIZECONTROL *urc); - - UI_MESSAGE_MAP(CJabberDlgPrivacyLists, CSuper); - UI_MESSAGE(WM_MEASUREITEM, OnWmMeasureItem); - UI_MESSAGE(WM_DRAWITEM, OnWmDrawItem); - UI_MESSAGE(WM_GETMINMAXINFO, OnWmGetMinMaxInfo); - UI_MESSAGE_MAP_END(); - - BOOL OnWmMeasureItem(UINT msg, WPARAM wParam, LPARAM lParam); - BOOL OnWmDrawItem(UINT msg, WPARAM wParam, LPARAM lParam); - BOOL OnWmGetMinMaxInfo(UINT msg, WPARAM wParam, LPARAM lParam); - - void btnSimple_OnClick(CCtrlButton *); - void btnAdvanced_OnClick(CCtrlButton *); - void btnAddJid_OnClick(CCtrlButton *); - void btnActivate_OnClick(CCtrlButton *); - void btnSetDefault_OnClick(CCtrlButton *); - void lbLists_OnSelChange(CCtrlListBox *); - void lbLists_OnDblClick(CCtrlListBox *); - void lbRules_OnSelChange(CCtrlListBox *); - void lbRules_OnDblClick(CCtrlListBox *); - void btnEditRule_OnClick(CCtrlButton *); - void btnAddRule_OnClick(CCtrlButton *); - void btnRemoveRule_OnClick(CCtrlButton *); - void btnUpRule_OnClick(CCtrlButton *); - void btnDownRule_OnClick(CCtrlButton *); - void btnAddList_OnClick(CCtrlButton *); - void btnRemoveList_OnClick(CCtrlButton *); - void btnApply_OnClick(CCtrlButton *); - void clcClist_OnUpdate(CCtrlClc::TEventInfo *evt); - void clcClist_OnOptionsChanged(CCtrlClc::TEventInfo *evt); - void clcClist_OnClick(CCtrlClc::TEventInfo *evt); - - void OnCommand_Close(HWND hwndCtrl, WORD idCtrl, WORD idCode); - - void ShowAdvancedList(CPrivacyList *pList); - void DrawNextRulePart(HDC hdc, COLORREF color, const TCHAR *text, RECT *rc); - void DrawRuleAction(HDC hdc, COLORREF clLine1, COLORREF clLine2, CPrivacyListRule *pRule, RECT *rc); - void DrawRulesList(LPDRAWITEMSTRUCT lpdis); - void DrawLists(LPDRAWITEMSTRUCT lpdis); - - void CListResetOptions(HWND hwndList); - void CListFilter(HWND hwndList); - bool CListIsGroup(HANDLE hGroup); - HANDLE CListFindGroupByName(TCHAR *name); - void CListResetIcons(HWND hwndList, HANDLE hItem, bool hide=false); - void CListSetupIcons(HWND hwndList, HANDLE hItem, int iSlot, DWORD dwProcess, BOOL bAction); - HANDLE CListAddContact(HWND hwndList, TCHAR *jid); - void CListApplyList(HWND hwndList, CPrivacyList *pList = NULL); - DWORD CListGetPackets(HWND hwndList, HANDLE hItem, bool bAction); - void CListBuildList(HWND hwndList, CPrivacyList *pList); - - void EnableEditorControls(); - BOOL CanExit(); - - static LRESULT CALLBACK LstListsSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK LstRulesSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - - struct TCLCInfo - { - struct TJidData - { - HANDLE hItem; - TCHAR *jid; - - static int cmp(const TJidData *p1, const TJidData *p2) { return lstrcmp(p1->jid, p2->jid); } - }; - - HANDLE hItemDefault; - HANDLE hItemSubNone; - HANDLE hItemSubTo; - HANDLE hItemSubFrom; - HANDLE hItemSubBoth; - - LIST<TJidData> newJids; - - bool bChanged; - - CPrivacyList *pList; - - TCLCInfo(): newJids(1, TJidData::cmp), bChanged(false), pList(0) {} - ~TCLCInfo() - { - for (int i = 0; i < newJids.getCount(); ++i) - { - mir_free(newJids[i]->jid); - mir_free(newJids[i]); - } - newJids.destroy(); - } - - void addJid(HANDLE hItem, TCHAR *jid) - { - TJidData *data = (TJidData *)mir_alloc(sizeof(TJidData)); - data->hItem = hItem; - data->jid = mir_tstrdup(jid); - newJids.insert(data); - } - - HANDLE findJid(TCHAR *jid) - { - TJidData data = {0}; - data.jid = jid; - TJidData *found = newJids.find(&data); - return found ? found->hItem : 0; - } - }; - - TCLCInfo clc_info; - -private: - CCtrlMButton m_btnSimple; - CCtrlMButton m_btnAdvanced; - CCtrlMButton m_btnAddJid; - CCtrlMButton m_btnActivate; - CCtrlMButton m_btnSetDefault; - CCtrlMButton m_btnEditRule; - CCtrlMButton m_btnAddRule; - CCtrlMButton m_btnRemoveRule; - CCtrlMButton m_btnUpRule; - CCtrlMButton m_btnDownRule; - CCtrlMButton m_btnAddList; - CCtrlMButton m_btnRemoveList; - CCtrlButton m_btnApply; - CCtrlListBox m_lbLists; - CCtrlListBox m_lbRules; - CCtrlClc m_clcClist; -}; - -int CJabberDlgPrivacyLists::idSimpleControls[] = -{ - IDC_CLIST, IDC_CANVAS, - IDC_TXT_OTHERJID, IDC_NEWJID, IDC_ADDJID, - IDC_ICO_MESSAGE, IDC_ICO_QUERY, IDC_ICO_INPRESENCE, IDC_ICO_OUTPRESENCE, - IDC_TXT_MESSAGE, IDC_TXT_QUERY, IDC_TXT_INPRESENCE, IDC_TXT_OUTPRESENCE, - 0 -}; - -int CJabberDlgPrivacyLists::idAdvancedControls[] = -{ - IDC_PL_RULES_LIST, - IDC_ADD_RULE, IDC_EDIT_RULE, IDC_REMOVE_RULE, - IDC_UP_RULE, IDC_DOWN_RULE, - 0 -}; - -CJabberDlgPrivacyLists::CJabberDlgPrivacyLists(CJabberProto *proto): - CSuper(proto, IDD_PRIVACY_LISTS, NULL), - m_btnSimple(this, IDC_BTN_SIMPLE, proto->LoadIconEx("group"), LPGEN("Simple mode")), - m_btnAdvanced(this, IDC_BTN_ADVANCED, proto->LoadIconEx("sd_view_list"), LPGEN("Advanced mode")), - m_btnAddJid(this, IDC_ADDJID, proto->LoadIconEx("addroster"), LPGEN("Add JID")), - m_btnActivate(this, IDC_ACTIVATE, proto->LoadIconEx("pl_list_active"), LPGEN("Activate")), - m_btnSetDefault(this, IDC_SET_DEFAULT, proto->LoadIconEx("pl_list_default"), LPGEN("Set default")), - m_btnEditRule(this, IDC_EDIT_RULE, SKINICON_OTHER_RENAME, LPGEN("Edit rule")), - m_btnAddRule(this, IDC_ADD_RULE, SKINICON_OTHER_ADDCONTACT, LPGEN("Add rule")), - m_btnRemoveRule(this, IDC_REMOVE_RULE, SKINICON_OTHER_DELETE, LPGEN("Delete rule")), - m_btnUpRule(this, IDC_UP_RULE, proto->LoadIconEx("arrow_up"), LPGEN("Move rule up")), - m_btnDownRule(this, IDC_DOWN_RULE, proto->LoadIconEx("arrow_down"), LPGEN("Move rule down")), - m_btnAddList(this, IDC_ADD_LIST, SKINICON_OTHER_ADDCONTACT, LPGEN("Add list...")), - m_btnRemoveList(this, IDC_REMOVE_LIST, SKINICON_OTHER_DELETE, LPGEN("Remove list")), - m_btnApply(this, IDC_APPLY), - m_lbLists(this, IDC_LB_LISTS), - m_lbRules(this, IDC_PL_RULES_LIST), - m_clcClist(this, IDC_CLIST) -{ - m_btnSimple.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnSimple_OnClick); - m_btnAdvanced.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAdvanced_OnClick); - m_btnAddJid.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddJid_OnClick); - m_btnActivate.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnActivate_OnClick); - m_btnSetDefault.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnSetDefault_OnClick); - m_btnEditRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnEditRule_OnClick); - m_btnAddRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddRule_OnClick); - m_btnRemoveRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnRemoveRule_OnClick); - m_btnUpRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnUpRule_OnClick); - m_btnDownRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnDownRule_OnClick); - m_btnAddList.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddList_OnClick); - m_btnRemoveList.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnRemoveList_OnClick); - m_btnApply.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnApply_OnClick); - - m_lbLists.OnSelChange = Callback(this, &CJabberDlgPrivacyLists::lbLists_OnSelChange); - m_lbLists.OnDblClick = Callback(this, &CJabberDlgPrivacyLists::lbLists_OnDblClick); - m_lbRules.OnSelChange = Callback(this, &CJabberDlgPrivacyLists::lbRules_OnSelChange); - m_lbRules.OnDblClick = Callback(this, &CJabberDlgPrivacyLists::lbRules_OnDblClick); - - m_clcClist.OnNewContact = - m_clcClist.OnListRebuilt = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnUpdate); - m_clcClist.OnOptionsChanged = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnOptionsChanged); - m_clcClist.OnClick = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnClick); -} - -void CJabberDlgPrivacyLists::OnInitDialog() -{ - CSuper::OnInitDialog(); - - WindowSetIcon( m_hwnd, m_proto, "privacylists" ); - - EnableWindow( GetDlgItem( m_hwnd, IDC_ADD_RULE ), FALSE ); - EnableWindow( GetDlgItem( m_hwnd, IDC_EDIT_RULE ), FALSE ); - EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_RULE ), FALSE ); - EnableWindow( GetDlgItem( m_hwnd, IDC_UP_RULE ), FALSE ); - EnableWindow( GetDlgItem( m_hwnd, IDC_DOWN_RULE ), FALSE ); - - m_proto->QueryPrivacyLists(); - - LOGFONT lf; - GetObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_GETFONT, 0, 0), sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - HFONT hfnt = CreateFontIndirect(&lf); - SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_SETFONT, (WPARAM)hfnt, TRUE); - SendDlgItemMessage(m_hwnd, IDC_TXT_RULES, WM_SETFONT, (WPARAM)hfnt, TRUE); - - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE, - GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE)|CLS_HIDEEMPTYGROUPS|CLS_USEGROUPS|CLS_GREYALTERNATE); - m_clcClist.SetExStyle(CLS_EX_DISABLEDRAGDROP|CLS_EX_TRACKSELECT); - - HIMAGELIST hIml = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,9,9); - ImageList_AddIcon_Icolib(hIml, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT)); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_msg_allow")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_msg_deny")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prin_allow")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prin_deny")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prout_allow")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prout_deny")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_iq_allow")); - ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_iq_deny")); - m_clcClist.SetExtraImageList(hIml); - m_clcClist.SetExtraColumns(4); - - m_btnSimple.MakePush(); - m_btnAdvanced.MakePush(); - - CLCINFOITEM cii = {0}; - cii.cbSize = sizeof(cii); - - cii.flags = CLCIIF_GROUPFONT; - cii.pszText = TranslateT("** Default **"); - clc_info.hItemDefault = m_clcClist.AddInfoItem(&cii); - cii.pszText = TranslateT("** Subsription: both **"); - clc_info.hItemSubBoth = m_clcClist.AddInfoItem(&cii); - cii.pszText = TranslateT("** Subsription: to **"); - clc_info.hItemSubTo = m_clcClist.AddInfoItem(&cii); - cii.pszText = TranslateT("** Subsription: from **"); - clc_info.hItemSubFrom = m_clcClist.AddInfoItem(&cii); - cii.pszText = TranslateT("** Subsription: none **"); - clc_info.hItemSubNone = m_clcClist.AddInfoItem(&cii); - - CListResetOptions(GetDlgItem(m_hwnd, IDC_CLIST)); - CListFilter(GetDlgItem(m_hwnd, IDC_CLIST)); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST)); - - if ( DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "plistsWnd_simpleMode", 1)) - { - UIShowControls(m_hwnd, idSimpleControls, SW_SHOW); - UIShowControls(m_hwnd, idAdvancedControls, SW_HIDE); - CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, TRUE); - } else - { - UIShowControls(m_hwnd, idSimpleControls, SW_HIDE); - UIShowControls(m_hwnd, idAdvancedControls, SW_SHOW); - CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, TRUE); - } - - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LB_LISTS), GWLP_USERDATA, - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LB_LISTS), GWLP_WNDPROC, (LONG_PTR)LstListsSubclassProc)); - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PL_RULES_LIST), GWLP_USERDATA, - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PL_RULES_LIST), GWLP_WNDPROC, (LONG_PTR)LstRulesSubclassProc)); - - SetStatusText(TranslateT("Loading...")); - - Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "plistsWnd_sz"); -} - -void CJabberDlgPrivacyLists::OnClose() -{ - if (CanExit()) { - DestroyWindow(m_hwnd); - CSuper::OnClose(); - } - else - m_lresult = TRUE; -} - -void CJabberDlgPrivacyLists::OnDestroy() -{ - m_proto->m_pDlgPrivacyLists = NULL; - - // Wipe all data and query lists without contents - m_proto->m_privacyListManager.RemoveAllLists(); - m_proto->QueryPrivacyLists(); - m_proto->m_privacyListManager.SetModified( FALSE ); - - // Delete custom bold font - DeleteObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_GETFONT, 0, 0)); - - DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "plistsWnd_simpleMode", IsDlgButtonChecked(m_hwnd, IDC_BTN_SIMPLE)); - - Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "plistsWnd_sz"); - - CSuper::OnDestroy(); -} - -void CJabberDlgPrivacyLists::OnProtoRefresh(WPARAM, LPARAM) -{ - LRESULT sel = SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0); - TCHAR *szCurrentSelectedList = NULL; - if ( sel != LB_ERR ) { - LRESULT len = SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETTEXTLEN, sel, 0) + 1; - szCurrentSelectedList = (TCHAR *)mir_alloc(len * sizeof(TCHAR)); - SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETTEXT, sel, (LPARAM)szCurrentSelectedList); - } - - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_RESETCONTENT, 0, 0 ); - - LRESULT nItemId = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)TranslateT( "<none>" )); - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nItemId, (LPARAM)NULL ); - - m_proto->m_privacyListManager.Lock(); - CPrivacyList* pList = m_proto->m_privacyListManager.GetFirstList(); - while ( pList ) { - if ( !pList->IsDeleted()) { - nItemId = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)pList->GetListName()); - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nItemId, (LPARAM)pList ); - } - pList = pList->GetNext(); - } - - if ( !szCurrentSelectedList || ( SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SELECTSTRING, -1, (LPARAM)szCurrentSelectedList ) == LB_ERR )) - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETCURSEL, 0, 0 ); - if ( szCurrentSelectedList ) - mir_free( szCurrentSelectedList ); - - m_proto->m_privacyListManager.Unlock(); - - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_LB_LISTS, LBN_SELCHANGE ), 0 ); - EnableEditorControls(); -} - -BOOL CJabberDlgPrivacyLists::OnWmMeasureItem(UINT, WPARAM, LPARAM lParam) -{ - LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; - if ((lpmis->CtlID != IDC_PL_RULES_LIST) && (lpmis->CtlID != IDC_LB_LISTS)) - return FALSE; - - TEXTMETRIC tm = {0}; - HDC hdc = GetDC(GetDlgItem(m_hwnd, lpmis->CtlID)); - GetTextMetrics(hdc, &tm); - ReleaseDC(GetDlgItem(m_hwnd, lpmis->CtlID), hdc); - - if (lpmis->CtlID == IDC_PL_RULES_LIST) - lpmis->itemHeight = tm.tmHeight * 2; - else if (lpmis->CtlID == IDC_LB_LISTS) - lpmis->itemHeight = tm.tmHeight; - - if (lpmis->itemHeight < 18) lpmis->itemHeight = 18; - - return TRUE; -} - -BOOL CJabberDlgPrivacyLists::OnWmDrawItem(UINT, WPARAM, LPARAM lParam) -{ - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; - - if (lpdis->CtlID == IDC_PL_RULES_LIST) - DrawRulesList(lpdis); - else if (lpdis->CtlID == IDC_LB_LISTS) - DrawLists(lpdis); - else if (lpdis->CtlID == IDC_CANVAS) - { - static struct - { - TCHAR *textEng; - char *icon; - TCHAR *text; - } items[] = - { - { _T("Message"), "pl_msg_allow" }, - { _T("Presence (in)"), "pl_prin_allow" }, - { _T("Presence (out)"), "pl_prout_allow" }, - { _T("Query"), "pl_iq_allow" }, - }; - - int i, totalWidth = -5; // spacing for last item - for (i = 0; i < SIZEOF(items); ++i) - { - SIZE sz = {0}; - if (!items[i].text) items[i].text = TranslateTS(items[i].textEng); - GetTextExtentPoint32(lpdis->hDC, items[i].text, lstrlen(items[i].text), &sz); - totalWidth += sz.cx + 18 + 5; // 18 pixels for icon, 5 pixel spacing - } - - COLORREF clText = GetSysColor(COLOR_BTNTEXT); - RECT rc = lpdis->rcItem; - rc.left = (rc.left + rc.right - totalWidth)/2; - - for (i = 0; i < SIZEOF(items); ++i) - { - DrawIconEx(lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, m_proto->LoadIconEx(items[i].icon), - 16, 16, 0, NULL, DI_NORMAL); - rc.left += 18; - DrawNextRulePart(lpdis->hDC, clText, items[i].text, &rc); - rc.left += 5; - } - } - else return FALSE; - - return TRUE; -} - -BOOL CJabberDlgPrivacyLists::OnWmGetMinMaxInfo(UINT, WPARAM, LPARAM lParam) -{ - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 550; - lpmmi->ptMinTrackSize.y = 390; - return 0; -} - -void CJabberDlgPrivacyLists::ShowAdvancedList(CPrivacyList *pList) -{ - int nLbSel = SendDlgItemMessage(m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_RESETCONTENT, 0, 0 ); - - BOOL bListEmpty = TRUE; - - CPrivacyListRule* pRule = pList->GetFirstRule(); - - while ( pRule ) { - bListEmpty = FALSE; - TCHAR szTypeValue[ 512 ]; - switch ( pRule->GetType()) { - case Jid: - mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If jabber id is '%s' then" ), pRule->GetValue()); - break; - case Group: - mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If group is '%s' then" ), pRule->GetValue()); - break; - case Subscription: - mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If subscription is '%s' then" ), pRule->GetValue()); - break; - case Else: - mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "Else")); - break; - } - - TCHAR szPackets[ 512 ]; - szPackets[ 0 ] = '\0'; - - DWORD dwPackets = pRule->GetPackets(); - if ( !dwPackets ) - dwPackets = JABBER_PL_RULE_TYPE_ALL; - if ( dwPackets == JABBER_PL_RULE_TYPE_ALL ) - _tcscpy( szPackets, _T("all")); - else { - if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) - _tcscat( szPackets, _T("messages")); - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) { - if ( _tcslen( szPackets )) - _tcscat( szPackets, _T(", ")); - _tcscat( szPackets, _T("presence-in")); - } - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) { - if ( _tcslen( szPackets )) - _tcscat( szPackets, _T(", ")); - _tcscat( szPackets, _T("presence-out")); - } - if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) { - if ( _tcslen( szPackets )) - _tcscat( szPackets, _T(", ")); - _tcscat( szPackets, _T("queries")); - } } - - TCHAR szListItem[ 512 ]; - mir_sntprintf( szListItem, SIZEOF( szListItem ), _T("%s %s %s"), szTypeValue, pRule->GetAction() ? _T("allow") : _T("deny"), szPackets ); - - LRESULT nItemId = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)szListItem ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETITEMDATA, nItemId, (LPARAM)pRule ); - - pRule = pRule->GetNext(); - } - - EnableWindow( GetDlgItem( m_hwnd, IDC_PL_RULES_LIST ), !bListEmpty ); - if ( bListEmpty ) - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)TranslateTS(_T("List has no rules, empty lists will be deleted then changes applied"))); - else - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nLbSel, 0 ); - - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_PL_RULES_LIST, LBN_SELCHANGE ), 0 ); -} - -void CJabberDlgPrivacyLists::DrawNextRulePart(HDC hdc, COLORREF color, const TCHAR *text, RECT *rc) -{ - SetTextColor(hdc, color); - DrawText(hdc, text, lstrlen(text), rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); - - SIZE sz; - GetTextExtentPoint32(hdc, text, lstrlen(text), &sz); - rc->left += sz.cx; -} - -void CJabberDlgPrivacyLists::DrawRuleAction(HDC hdc, COLORREF clLine1, COLORREF, CPrivacyListRule *pRule, RECT *rc) -{ - DrawNextRulePart(hdc, clLine1, pRule->GetAction() ? TranslateT("allow ") : TranslateT("deny "), rc); - if (!pRule->GetPackets() || (pRule->GetPackets() == JABBER_PL_RULE_TYPE_ALL)) - { - DrawNextRulePart(hdc, clLine1, TranslateT("all."), rc); - } else - { - bool needComma = false; - int itemCount = - ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_MESSAGE) ? 1 : 0) + - ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_IN) ? 1 : 0) + - ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_OUT) ? 1 : 0) + - ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_IQ) ? 1 : 0); - - if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_MESSAGE) - { - --itemCount; - needComma = true; - DrawNextRulePart(hdc, clLine1, TranslateT("messages"), rc); - } - if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_IN) - { - --itemCount; - if (needComma) - DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); - needComma = true; - DrawNextRulePart(hdc, clLine1, TranslateT("incoming presences"), rc); - } - if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_OUT) - { - --itemCount; - if (needComma) - DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); - needComma = true; - DrawNextRulePart(hdc, clLine1, TranslateT("outgoing presences"), rc); - } - if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_IQ) - { - --itemCount; - if (needComma) - DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); - needComma = true; - DrawNextRulePart(hdc, clLine1, TranslateT("queries"), rc); - } - DrawNextRulePart(hdc, clLine1, _T("."), rc); - } -} - -void CJabberDlgPrivacyLists::DrawRulesList(LPDRAWITEMSTRUCT lpdis) -{ - if (lpdis->itemID == -1) - return; - - CPrivacyListRule *pRule = (CPrivacyListRule *)lpdis->itemData; - - COLORREF clLine1, clLine2, clBack; - if (lpdis->itemState & ODS_SELECTED) - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - clBack = GetSysColor(COLOR_HIGHLIGHT); - clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); - } else - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); - clBack = GetSysColor(COLOR_WINDOW); - clLine1 = GetSysColor(COLOR_WINDOWTEXT); - } - clLine2 = RGB( - GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, - GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, - GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 - ); - - SetBkMode(lpdis->hDC, TRANSPARENT); - - RECT rc; - - if ( !pRule ) { - rc = lpdis->rcItem; - rc.left += 25; - - int len = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETTEXTLEN, lpdis->itemID, 0) + 1; - TCHAR *str = (TCHAR *)_alloca(len * sizeof(TCHAR)); - SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETTEXT, lpdis->itemID, (LPARAM)str); - DrawNextRulePart(lpdis->hDC, clLine1, str, &rc); - } - else if (pRule->GetType() == Else) { - rc = lpdis->rcItem; - rc.left += 25; - - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("Else "), &rc); - DrawRuleAction(lpdis->hDC, clLine1, clLine2, pRule, &rc); - } - else { - rc = lpdis->rcItem; - rc.bottom -= (rc.bottom - rc.top) / 2; - rc.left += 25; - - switch ( pRule->GetType()) - { - case Jid: - { - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If jabber id is '"), &rc); - DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); - - if (HANDLE hContact = m_proto->HContactFromJID(pRule->GetValue())) { - TCHAR *szName = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); - if ( szName ) { - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (nickname: "), &rc); - DrawNextRulePart(lpdis->hDC, clLine1, szName, &rc); - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(")"), &rc); - } } - break; - } - - case Group: - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If group is '"), &rc); - DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); - break; - case Subscription: - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If subscription is '"), &rc); - DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); - break; - } - - rc = lpdis->rcItem; - rc.top += (rc.bottom - rc.top) / 2; - rc.left += 25; - - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("then "), &rc); - DrawRuleAction(lpdis->hDC, clLine1, clLine2, pRule, &rc); - } - - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, - m_proto->LoadIconEx("main"), 16, 16, 0, NULL, DI_NORMAL); - - if (pRule) - { - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, - m_proto->LoadIconEx(pRule->GetAction() ? "disco_ok" : "disco_fail"), - 16, 16, 0, NULL, DI_NORMAL); - } - - if (lpdis->itemState & ODS_FOCUS) - { - LRESULT sel = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETCURSEL, 0, 0); - if ((sel == LB_ERR) || (sel == (LRESULT)lpdis->itemID)) - DrawFocusRect(lpdis->hDC, &lpdis->rcItem); - } -} - -void CJabberDlgPrivacyLists::DrawLists(LPDRAWITEMSTRUCT lpdis) -{ - if (lpdis->itemID == -1) - return; - - CPrivacyList *pList = (CPrivacyList *)lpdis->itemData; - - COLORREF clLine1, clLine2, clBack; - if (lpdis->itemState & ODS_SELECTED) - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - clBack = GetSysColor(COLOR_HIGHLIGHT); - clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); - } else - { - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); - clBack = GetSysColor(COLOR_WINDOW); - clLine1 = GetSysColor(COLOR_WINDOWTEXT); - } - clLine2 = RGB( - GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, - GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, - GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 - ); - - SetBkMode(lpdis->hDC, TRANSPARENT); - - RECT rc; - m_proto->m_privacyListManager.Lock(); - TCHAR *szDefault = NEWTSTR_ALLOCA(m_proto->m_privacyListManager.GetDefaultListName()); - TCHAR *szActive = NEWTSTR_ALLOCA(m_proto->m_privacyListManager.GetActiveListName()); - m_proto->m_privacyListManager.Unlock(); - - rc = lpdis->rcItem; - rc.left +=3; - - bool bActive = false; - bool bDefault = false; - TCHAR *szName; - - if (!pList) - { - if (!szActive) bActive = true; - if (!szDefault) bDefault = true; - szName = TranslateT("<none>"); - } else - { - if (!lstrcmp(pList->GetListName(), szActive)) bActive = true; - if (!lstrcmp(pList->GetListName(), szDefault)) bDefault = true; - szName = pList->GetListName(); - } - - HFONT hfnt = NULL; - if (bActive) - { - LOGFONT lf; - GetObject(GetCurrentObject(lpdis->hDC, OBJ_FONT), sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - hfnt = (HFONT)SelectObject(lpdis->hDC, CreateFontIndirect(&lf)); - } - - DrawNextRulePart(lpdis->hDC, clLine1, szName, &rc); - - if (bActive && bDefault) - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (act., def.)"), &rc); - else if (bActive) - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (active)"), &rc); - else if (bDefault) - DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (default)"), &rc); - - DrawIconEx(lpdis->hDC, lpdis->rcItem.right-16-4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, - m_proto->LoadIconEx(bActive ? "pl_list_active" : "pl_list_any"), - 16, 16, 0, NULL, DI_NORMAL); - - if (bDefault) - DrawIconEx(lpdis->hDC, lpdis->rcItem.right-16-4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, - m_proto->LoadIconEx("disco_ok"), - 16, 16, 0, NULL, DI_NORMAL); - - if (hfnt) - DeleteObject(SelectObject(lpdis->hDC, hfnt)); - - if (lpdis->itemState & ODS_FOCUS) - { - int sel = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETCURSEL, 0, 0); - if ((sel == LB_ERR) || (sel == (int)lpdis->itemID)) - DrawFocusRect(lpdis->hDC, &lpdis->rcItem); - } -} - -void CJabberDlgPrivacyLists::CListResetOptions(HWND) -{ - m_clcClist.SetBkBitmap(0, NULL); - m_clcClist.SetBkColor(GetSysColor(COLOR_WINDOW)); - m_clcClist.SetGreyoutFlags(0); - m_clcClist.SetLeftMargin(4); - m_clcClist.SetIndent(10); - m_clcClist.SetHideEmptyGroups(false); - m_clcClist.SetHideOfflineRoot(false); - for (int i = 0; i <= FONTID_MAX; i++) - m_clcClist.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT)); -} - -void CJabberDlgPrivacyLists::CListFilter(HWND) -{ - for (HANDLE hContact = db_find_first(); - hContact; - hContact = db_find_next(hContact)) - { - char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - if (!proto || lstrcmpA(proto, m_proto->m_szModuleName)) - if (HANDLE hItem = m_clcClist.FindContact(hContact)) - m_clcClist.DeleteItem(hItem); - } -} - -bool CJabberDlgPrivacyLists::CListIsGroup(HANDLE hGroup) -{ - char idstr[33]; - _i64toa((INT_PTR)hGroup-1, idstr, 10); - - DBVARIANT dbv; - bool result = DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv) == 0; - if ( result ) - DBFreeVariant(&dbv); - - return result; -} - -HANDLE CJabberDlgPrivacyLists::CListFindGroupByName(TCHAR *name) -{ - char idstr[33]; - DBVARIANT dbv; - - HANDLE hGroup = 0; - - for (int i= 0; !hGroup; ++i) - { - _itoa(i, idstr, 10); - - if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv)) - break; - - if (!_tcscmp(dbv.ptszVal + 1, name)) - hGroup = (HANDLE)(i+1); - - DBFreeVariant(&dbv); - } - - return hGroup; -} - -void CJabberDlgPrivacyLists::CListResetIcons(HWND, HANDLE hItem, bool hide) -{ - for (int i = 0; i < 4; ++i) - m_clcClist.SetExtraImage(hItem, i, hide ? 0xFF : 0); -} - -void CJabberDlgPrivacyLists::CListSetupIcons(HWND, HANDLE hItem, int iSlot, DWORD dwProcess, BOOL bAction) -{ - if (dwProcess && !m_clcClist.GetExtraImage(hItem, iSlot)) - m_clcClist.SetExtraImage(hItem, iSlot, iSlot*2 + (bAction?1:2)); -} - -HANDLE CJabberDlgPrivacyLists::CListAddContact(HWND hwndList, TCHAR *jid) -{ - HANDLE hItem = 0; - - HANDLE hContact = m_proto->HContactFromJID(jid); - if ( !hContact ) { - hItem = clc_info.findJid(jid); - if (!hItem) - { - CLCINFOITEM cii = {0}; - cii.cbSize = sizeof(cii); - cii.pszText = jid; - hItem = m_clcClist.AddInfoItem(&cii); - CListResetIcons(hwndList, hItem); - clc_info.addJid(hItem, jid); - } - } else - { - hItem = m_clcClist.FindContact(hContact); - } - - return hItem; -} - -void CJabberDlgPrivacyLists::CListApplyList(HWND hwndList, CPrivacyList *pList) -{ - clc_info.pList = pList; - - bool bHideIcons = pList ? false : true; - - CListResetIcons(hwndList, clc_info.hItemDefault, bHideIcons); - CListResetIcons(hwndList, clc_info.hItemSubBoth, bHideIcons); - CListResetIcons(hwndList, clc_info.hItemSubFrom, bHideIcons); - CListResetIcons(hwndList, clc_info.hItemSubNone, bHideIcons); - CListResetIcons(hwndList, clc_info.hItemSubTo, bHideIcons); - - // group handles start with 1 (0 is "root") - for (int iGroup = 1; CListIsGroup((HANDLE)iGroup); ++iGroup) - { - HANDLE hItem = m_clcClist.FindGroup((HANDLE)iGroup); - if (!hItem) continue; - CListResetIcons(hwndList, hItem, bHideIcons); - } - - for (HANDLE hContact=db_find_first(); hContact; - hContact=db_find_next(hContact)) - { - HANDLE hItem = m_clcClist.FindContact(hContact); - if (!hItem) continue; - CListResetIcons(hwndList, hItem, bHideIcons); - } - - for (int iJid = 0; iJid < clc_info.newJids.getCount(); ++iJid) - CListResetIcons(hwndList, clc_info.newJids[iJid]->hItem, bHideIcons); - - if (!pList) - goto lbl_return; - - CPrivacyListRule *pRule; - for (pRule = pList->GetFirstRule(); pRule; pRule = pRule->GetNext()) - { - HANDLE hItem = 0; - switch (pRule->GetType()) - { - case Jid: - { - hItem = CListAddContact(hwndList, pRule->GetValue()); - break; - } - case Group: - { - HANDLE hGroup = CListFindGroupByName(pRule->GetValue()); - hItem = m_clcClist.FindGroup(hGroup); - break; - } - case Subscription: - { - if (!lstrcmp(pRule->GetValue(), _T("none"))) hItem = clc_info.hItemSubNone; - else if (!lstrcmp(pRule->GetValue(), _T("from"))) hItem = clc_info.hItemSubFrom; - else if (!lstrcmp(pRule->GetValue(), _T("to"))) hItem = clc_info.hItemSubTo; - else if (!lstrcmp(pRule->GetValue(), _T("both"))) hItem = clc_info.hItemSubBoth; - break; - } - case Else: - { - hItem = clc_info.hItemDefault; - break; - } - } - - if (!hItem) continue; - - DWORD dwPackets = pRule->GetPackets(); - if (!dwPackets) dwPackets = JABBER_PL_RULE_TYPE_ALL; - CListSetupIcons(hwndList, hItem, 0, dwPackets & JABBER_PL_RULE_TYPE_MESSAGE, pRule->GetAction()); - CListSetupIcons(hwndList, hItem, 1, dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN, pRule->GetAction()); - CListSetupIcons(hwndList, hItem, 2, dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT, pRule->GetAction()); - CListSetupIcons(hwndList, hItem, 3, dwPackets & JABBER_PL_RULE_TYPE_IQ, pRule->GetAction()); - } - -lbl_return: - clc_info.bChanged = false; -} - -DWORD CJabberDlgPrivacyLists::CListGetPackets(HWND, HANDLE hItem, bool bAction) -{ - DWORD result = 0; - - int iIcon = 0; - - iIcon = m_clcClist.GetExtraImage(hItem, 0); - if ( bAction && (iIcon == 1)) result |= JABBER_PL_RULE_TYPE_MESSAGE; - else if (!bAction && (iIcon == 2)) result |= JABBER_PL_RULE_TYPE_MESSAGE; - - iIcon = m_clcClist.GetExtraImage(hItem, 1); - if ( bAction && (iIcon == 3)) result |= JABBER_PL_RULE_TYPE_PRESENCE_IN; - else if (!bAction && (iIcon == 4)) result |= JABBER_PL_RULE_TYPE_PRESENCE_IN; - - iIcon = m_clcClist.GetExtraImage(hItem, 2); - if ( bAction && (iIcon == 5)) result |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; - else if (!bAction && (iIcon == 6)) result |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; - - iIcon = m_clcClist.GetExtraImage(hItem, 3); - if ( bAction && (iIcon == 7)) result |= JABBER_PL_RULE_TYPE_IQ; - else if (!bAction && (iIcon == 8)) result |= JABBER_PL_RULE_TYPE_IQ; - - return result; -} - -void CJabberDlgPrivacyLists::CListBuildList(HWND hwndList, CPrivacyList *pList) -{ - if (!pList) return; - - if (!clc_info.bChanged) return; - - clc_info.bChanged = false; - - DWORD dwOrder = 0; - DWORD dwPackets = 0; - - HANDLE hItem; - TCHAR *szJid; - - pList->RemoveAllRules(); - - for (int iJid = 0; iJid < clc_info.newJids.getCount(); ++iJid) - { - hItem = clc_info.newJids[iJid]->hItem; - szJid = clc_info.newJids[iJid]->jid; - - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Jid, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Jid, szJid, FALSE, dwOrder++, dwPackets); - } - - for (HANDLE hContact=db_find_first(); hContact; - hContact=db_find_next(hContact)) - { - hItem = m_clcClist.FindContact(hContact); - - DBVARIANT dbv = {0}; - if ( m_proto->JGetStringT(hContact, "jid", &dbv)) { - if ( m_proto->JGetStringT(hContact, "ChatRoomID", &dbv)) - continue; - } - - szJid = dbv.ptszVal; - - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Jid, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Jid, szJid, FALSE, dwOrder++, dwPackets); - - JFreeVariant(&dbv); - } - - // group handles start with 1 (0 is "root") - for (int iGroup = 1; ; ++iGroup) - { - char idstr[33]; - _itoa(iGroup-1, idstr, 10); - DBVARIANT dbv = {0}; - if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv)) - break; - - hItem = m_clcClist.FindGroup((HANDLE)iGroup); - szJid = dbv.ptszVal+1; - - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Group, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Group, szJid, FALSE, dwOrder++, dwPackets); - - DBFreeVariant(&dbv); - } - - hItem = clc_info.hItemSubBoth; - szJid = _T("both"); - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); - - hItem = clc_info.hItemSubFrom; - szJid = _T("from"); - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); - - hItem = clc_info.hItemSubNone; - szJid = _T("none"); - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); - - hItem = clc_info.hItemSubTo; - szJid = _T("to"); - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); - - hItem = clc_info.hItemDefault; - szJid = NULL; - if (dwPackets = CListGetPackets(hwndList, hItem, true)) - pList->AddRule(Else, szJid, TRUE, dwOrder++, dwPackets); - if (dwPackets = CListGetPackets(hwndList, hItem, false)) - pList->AddRule(Else, szJid, FALSE, dwOrder++, dwPackets); - - pList->Reorder(); - pList->SetModified(); -} - -void CJabberDlgPrivacyLists::EnableEditorControls() -{ - m_proto->m_privacyListManager.Lock(); - BOOL bListsLoaded = m_proto->m_privacyListManager.IsAllListsLoaded(); - BOOL bListsModified = m_proto->m_privacyListManager.IsModified() || clc_info.bChanged; - m_proto->m_privacyListManager.Unlock(); - - int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); - int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); - BOOL bSelected = nCurSel != CB_ERR; - BOOL bListSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCOUNT, 0, 0); - bListSelected = bListSelected && (SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0) != LB_ERR); - bListSelected = bListSelected && SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETITEMDATA, SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0), 0); - - EnableWindow( GetDlgItem( m_hwnd, IDC_TXT_OTHERJID ), bListsLoaded && bListSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_NEWJID ), bListsLoaded && bListSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_ADDJID ), bListsLoaded && bListSelected ); - - EnableWindow( GetDlgItem( m_hwnd, IDC_ADD_RULE ), bListsLoaded && bListSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_EDIT_RULE ), bListsLoaded && bSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_RULE ), bListsLoaded && bSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_UP_RULE ), bListsLoaded && bSelected && nCurSel != 0 ); - EnableWindow( GetDlgItem( m_hwnd, IDC_DOWN_RULE ), bListsLoaded && bSelected && nCurSel != ( nItemCount - 1 )); - EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_LIST ), bListsLoaded && bListSelected ); - EnableWindow( GetDlgItem( m_hwnd, IDC_APPLY ), bListsLoaded && bListsModified ); - - if (bListsLoaded) - SetStatusText( TranslateT("Ready.")); -} - -LRESULT CALLBACK CJabberDlgPrivacyLists::LstListsSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC sttOldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); - switch (msg) - { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - { - if (wParam == VK_INSERT) - return UIEmulateBtnClick(GetParent(hwnd), IDC_ADD_LIST); - if (wParam == VK_DELETE) - return UIEmulateBtnClick(GetParent(hwnd), IDC_REMOVE_LIST); - if (wParam == VK_SPACE) - { - if (GetAsyncKeyState(VK_CONTROL)) - return UIEmulateBtnClick(GetParent(hwnd), IDC_SET_DEFAULT); - return UIEmulateBtnClick(GetParent(hwnd), IDC_ACTIVATE); - } - - break; - } - } - return CallWindowProc(sttOldWndProc, hwnd, msg, wParam, lParam); -} - -LRESULT CALLBACK CJabberDlgPrivacyLists::LstRulesSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC sttOldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); - switch (msg) - { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - { - if (wParam == VK_INSERT) - return UIEmulateBtnClick(GetParent(hwnd), IDC_ADD_RULE); - if (wParam == VK_DELETE) - return UIEmulateBtnClick(GetParent(hwnd), IDC_REMOVE_RULE); - if ((wParam == VK_UP) && (lParam & (1UL << 29))) - return UIEmulateBtnClick(GetParent(hwnd), IDC_UP_RULE); - if ((wParam == VK_DOWN) && (lParam & (1UL << 29))) - return UIEmulateBtnClick(GetParent(hwnd), IDC_DOWN_RULE); - if (wParam == VK_F2) - return UIEmulateBtnClick(GetParent(hwnd), IDC_EDIT_RULE); - - break; - } - } - return CallWindowProc(sttOldWndProc, hwnd, msg, wParam, lParam); -} - -BOOL CJabberDlgPrivacyLists::CanExit() -{ - m_proto->m_privacyListManager.Lock(); - BOOL bModified = m_proto->m_privacyListManager.IsModified(); - m_proto->m_privacyListManager.Unlock(); - - if (clc_info.bChanged) - bModified = TRUE; - - if ( !bModified ) - return TRUE; - - if ( IDYES == MessageBox( m_hwnd, TranslateT("Privacy lists are not saved, discard any changes and exit?"), TranslateT("Are you sure?"), MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 )) - return TRUE; - - return FALSE; -} - -void CJabberDlgPrivacyLists::btnSimple_OnClick(CCtrlButton *) -{ - CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, TRUE); - CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, FALSE); - UIShowControls(m_hwnd, idSimpleControls, SW_SHOW); - UIShowControls(m_hwnd, idAdvancedControls, SW_HIDE); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); -} - -void CJabberDlgPrivacyLists::btnAdvanced_OnClick(CCtrlButton *) -{ - CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, FALSE); - CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, TRUE); - UIShowControls(m_hwnd, idSimpleControls, SW_HIDE); - UIShowControls(m_hwnd, idAdvancedControls, SW_SHOW); - CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); - PostMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_LISTS, LBN_SELCHANGE), 0); -} - -void CJabberDlgPrivacyLists::btnAddJid_OnClick(CCtrlButton *) -{ - int len = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_NEWJID))+1; - TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); - GetWindowText(GetDlgItem(m_hwnd, IDC_NEWJID), buf, len); - SetWindowText(GetDlgItem(m_hwnd, IDC_NEWJID), _T("")); - CListAddContact(GetDlgItem(m_hwnd, IDC_CLIST), buf); -} - -void CJabberDlgPrivacyLists::btnActivate_OnClick(CCtrlButton *) -{ - if ( m_proto->m_bJabberOnline ) - { - m_proto->m_privacyListManager.Lock(); - CPrivacyList* pList = GetSelectedList(m_hwnd); - if ( pList && pList->IsModified()) { - m_proto->m_privacyListManager.Unlock(); - MessageBox( m_hwnd, TranslateT("Please save list before activating"), TranslateT("First, save the list"), MB_OK | MB_ICONSTOP ); - return; - } - EnableWindow( GetDlgItem( m_hwnd, IDC_ACTIVATE ), FALSE ); - SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_ACTIVATE ), GWLP_USERDATA, (LONG_PTR)pList ); - XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListActive, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); - HXML active = query << XCHILD( _T("active")); - if ( pList ) - active << XATTR( _T("name"), pList->GetListName()); - m_proto->m_privacyListManager.Unlock(); - - SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); - - m_proto->m_ThreadInfo->send( iq ); - } -} - -void CJabberDlgPrivacyLists::btnSetDefault_OnClick(CCtrlButton *) -{ - if ( m_proto->m_bJabberOnline ) - { - m_proto->m_privacyListManager.Lock(); - CPrivacyList* pList = GetSelectedList(m_hwnd); - if ( pList && pList->IsModified()) { - m_proto->m_privacyListManager.Unlock(); - MessageBox( m_hwnd, TranslateT("Please save list before you make it the default list"), TranslateT("First, save the list"), MB_OK | MB_ICONSTOP ); - return; - } - EnableWindow( GetDlgItem( m_hwnd, IDC_SET_DEFAULT ), FALSE ); - SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_SET_DEFAULT ), GWLP_USERDATA, (LONG_PTR)pList ); - - XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListDefault, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS )); - HXML defaultTag = query << XCHILD( _T("default")); - if ( pList ) - xmlAddAttr( defaultTag, _T("name"), pList->GetListName()); - m_proto->m_privacyListManager.Unlock(); - - SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); - - m_proto->m_ThreadInfo->send( iq ); - } -} - -void CJabberDlgPrivacyLists::lbLists_OnSelChange(CCtrlListBox *) -{ - LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0 ); - if ( nCurSel == LB_ERR ) - return; - - LRESULT nErr = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETITEMDATA, nCurSel, 0 ); - if ( nErr == LB_ERR ) - return; - if ( nErr == 0 ) - { - if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) - { - CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), NULL); - } else - { - EnableWindow( GetDlgItem( m_hwnd, IDC_PL_RULES_LIST ), FALSE ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_RESETCONTENT, 0, 0 ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)TranslateTS(_T("No list selected"))); - } - EnableEditorControls(); - return; - } - - m_proto->m_privacyListManager.Lock(); - if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) - { - CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), (CPrivacyList* )nErr); - } - else ShowAdvancedList((CPrivacyList* )nErr); - - m_proto->m_privacyListManager.Unlock(); - - EnableEditorControls(); -} - -void CJabberDlgPrivacyLists::lbLists_OnDblClick(CCtrlListBox *) -{ - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_ACTIVATE, 0 ), 0 ); -} - -void CJabberDlgPrivacyLists::lbRules_OnSelChange(CCtrlListBox *) -{ - EnableEditorControls(); -} - -void CJabberDlgPrivacyLists::lbRules_OnDblClick(CCtrlListBox *) -{ - PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_EDIT_RULE, 0 ), 0 ); -} - -void CJabberDlgPrivacyLists::btnEditRule_OnClick(CCtrlButton *) -{ - // FIXME: potential deadlock due to PLM lock while editing rule - m_proto->m_privacyListManager.Lock(); - { - CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); - CPrivacyList* pList = GetSelectedList(m_hwnd); - if ( pList && pRule ) { - CJabberDlgPrivacyRule dlgPrivacyRule(m_proto, m_hwnd, pRule); - int nResult = dlgPrivacyRule.DoModal(); - if ( nResult ) { - pList->SetModified(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } } } - m_proto->m_privacyListManager.Unlock(); -} - -void CJabberDlgPrivacyLists::btnAddRule_OnClick(CCtrlButton *) -{ - // FIXME: potential deadlock due to PLM lock while editing rule - m_proto->m_privacyListManager.Lock(); - { - CPrivacyList* pList = GetSelectedList(m_hwnd); - if ( pList ) { - CPrivacyListRule* pRule = new CPrivacyListRule( m_proto, Jid, _T(""), FALSE ); - CJabberDlgPrivacyRule dlgPrivacyRule(m_proto, m_hwnd, pRule); - int nResult = dlgPrivacyRule.DoModal(); - if ( nResult ) { - pList->AddRule(pRule); - pList->Reorder(); - pList->SetModified(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } - else delete pRule; - } } - m_proto->m_privacyListManager.Unlock(); -} - -void CJabberDlgPrivacyLists::btnRemoveRule_OnClick(CCtrlButton *) -{ - m_proto->m_privacyListManager.Lock(); - { - CPrivacyList* pList = GetSelectedList(m_hwnd); - CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); - - if ( pList && pRule ) { - pList->RemoveRule( pRule ); - int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); - int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel != nItemCount - 1 ? nCurSel : nCurSel - 1, 0 ); - pList->Reorder(); - pList->SetModified(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } } - - m_proto->m_privacyListManager.Unlock(); -} - -void CJabberDlgPrivacyLists::btnUpRule_OnClick(CCtrlButton *) -{ - m_proto->m_privacyListManager.Lock(); - { - CPrivacyList* pList = GetSelectedList(m_hwnd); - CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); - int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); - - if ( pList && pRule && nCurSel ) { - pRule->SetOrder( pRule->GetOrder() - 11 ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel - 1, 0 ); - pList->Reorder(); - pList->SetModified(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } } - - m_proto->m_privacyListManager.Unlock(); -} - -void CJabberDlgPrivacyLists::btnDownRule_OnClick(CCtrlButton *) -{ - m_proto->m_privacyListManager.Lock(); - { - CPrivacyList* pList = GetSelectedList(m_hwnd); - CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); - int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); - int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); - - if ( pList && pRule && ( nCurSel != ( nItemCount - 1 ))) { - pRule->SetOrder( pRule->GetOrder() + 11 ); - SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel + 1, 0 ); - pList->Reorder(); - pList->SetModified(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } } - - m_proto->m_privacyListManager.Unlock(); -} - -void CJabberDlgPrivacyLists::btnAddList_OnClick(CCtrlButton *) -{ - // FIXME: line length is hard coded in dialog procedure - CJabberDlgPrivacyAddList dlgPrivacyAddList(m_proto, m_hwnd); - int nRetVal = dlgPrivacyAddList.DoModal(); - if ( nRetVal && _tcslen( dlgPrivacyAddList.szLine )) { - m_proto->m_privacyListManager.Lock(); - CPrivacyList* pList = m_proto->m_privacyListManager.FindList( dlgPrivacyAddList.szLine ); - if ( !pList ) { - m_proto->m_privacyListManager.AddList( dlgPrivacyAddList.szLine ); - pList = m_proto->m_privacyListManager.FindList( dlgPrivacyAddList.szLine ); - if ( pList ) { - pList->SetModified( TRUE ); - pList->SetLoaded( TRUE ); - } - } - if ( pList ) - pList->SetDeleted( FALSE ); - int nSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SELECTSTRING, -1, (LPARAM)dlgPrivacyAddList.szLine ); - if ( nSelected == CB_ERR ) { - nSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)dlgPrivacyAddList.szLine ); - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nSelected, (LPARAM)pList ); - SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETCURSEL, nSelected, 0 ); - } - m_proto->m_privacyListManager.Unlock(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); - } -} - -void CJabberDlgPrivacyLists::btnRemoveList_OnClick(CCtrlButton *) -{ - m_proto->m_privacyListManager.Lock(); - { - CPrivacyList* pList = GetSelectedList(m_hwnd); - if ( pList ) { - TCHAR *szListName = pList->GetListName(); - if ( ( m_proto->m_privacyListManager.GetActiveListName() && !_tcscmp( szListName, m_proto->m_privacyListManager.GetActiveListName())) - || ( m_proto->m_privacyListManager.GetDefaultListName() && !_tcscmp( szListName, m_proto->m_privacyListManager.GetDefaultListName()))) { - m_proto->m_privacyListManager.Unlock(); - MessageBox( m_hwnd, TranslateTS(_T("Can't remove active or default list")), TranslateTS(_T("Sorry")), MB_OK | MB_ICONSTOP ); - return; - } - pList->SetDeleted(); - pList->SetModified(); - } } - - m_proto->m_privacyListManager.Unlock(); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); -} - -void CJabberDlgPrivacyLists::btnApply_OnClick(CCtrlButton *) -{ - if ( !m_proto->m_bJabberOnline ) { - SetStatusText(TranslateT("Unable to save list because you are currently offline.")); - return; - } - - m_proto->m_privacyListManager.Lock(); - { - if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) - CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); - - CPrivacyListModifyUserParam *pUserData = NULL; - CPrivacyList* pList = m_proto->m_privacyListManager.GetFirstList(); - while ( pList ) { - if ( pList->IsModified()) { - CPrivacyListRule* pRule = pList->GetFirstRule(); - if ( !pRule ) - pList->SetDeleted(); - if ( pList->IsDeleted()) { - pList->RemoveAllRules(); - pRule = NULL; - } - pList->SetModified( FALSE ); - - if ( !pUserData ) - pUserData = new CPrivacyListModifyUserParam(); - - pUserData->m_dwCount++; - - XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListModify, JABBER_IQ_TYPE_SET, NULL, 0, -1, pUserData )); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS )); - HXML listTag = query << XCHILD( _T("list")) << XATTR( _T("name"), pList->GetListName()); - - while ( pRule ) { - HXML itemTag = listTag << XCHILD( _T("item")); - switch ( pRule->GetType()) { - case Jid: - itemTag << XATTR( _T("type"), _T("jid")); - break; - case Group: - itemTag << XATTR( _T("type"), _T("group")); - break; - case Subscription: - itemTag << XATTR( _T("type"), _T("subscription")); - break; - } - if ( pRule->GetType() != Else ) - itemTag << XATTR( _T("value"), pRule->GetValue()); - if ( pRule->GetAction()) - itemTag << XATTR( _T("action"), _T("allow")); - else - itemTag << XATTR( _T("action"), _T("deny")); - itemTag << XATTRI( _T("order"), pRule->GetOrder()); - DWORD dwPackets = pRule->GetPackets(); - if ( dwPackets != JABBER_PL_RULE_TYPE_ALL ) { - if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) - itemTag << XCHILD( _T("iq")); - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) - itemTag << XCHILD( _T("presence-in")); - if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) - itemTag << XCHILD( _T("presence-out")); - if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) - itemTag << XCHILD( _T("message")); - } - pRule = pRule->GetNext(); - } - - m_proto->m_ThreadInfo->send( iq ); - } - pList = pList->GetNext(); - } } - m_proto->m_privacyListManager.Unlock(); - SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); - PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); -} - -void CJabberDlgPrivacyLists::OnCommand_Close(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) -{ - if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) - CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); - - if (CanExit()) - DestroyWindow(m_hwnd); -} - -void CJabberDlgPrivacyLists::clcClist_OnUpdate(CCtrlClc::TEventInfo*) -{ - CListFilter(GetDlgItem(m_hwnd, IDC_CLIST)); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); -} - -void CJabberDlgPrivacyLists::clcClist_OnOptionsChanged(CCtrlClc::TEventInfo*) -{ - CListResetOptions(GetDlgItem(m_hwnd, IDC_CLIST)); - CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); -} - -void CJabberDlgPrivacyLists::clcClist_OnClick(CCtrlClc::TEventInfo *evt) -{ - HANDLE hItem; - DWORD hitFlags; - int iImage; - - if(evt->info->iColumn==-1) return; - hItem = m_clcClist.HitTest(evt->info->pt.x, evt->info->pt.y, &hitFlags); - if(hItem==NULL) return; - if (!(hitFlags&CLCHT_ONITEMEXTRA)) return; - - iImage = m_clcClist.GetExtraImage(hItem, evt->info->iColumn); - if (iImage != 0xFF) - { - if (iImage == 0) - iImage = evt->info->iColumn * 2 + 2; - else if (iImage == evt->info->iColumn * 2 + 2) - iImage = evt->info->iColumn * 2 + 1; - else - iImage = 0; - - m_clcClist.SetExtraImage(hItem, evt->info->iColumn, iImage); - - clc_info.bChanged = true; - - EnableEditorControls(); - } -} - -int CJabberDlgPrivacyLists::Resizer(UTILRESIZECONTROL *urc) -{ - switch (urc->wId) { - case IDC_HEADERBAR: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH; - case IDC_BTN_SIMPLE: - case IDC_BTN_ADVANCED: - return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP; - case IDC_LB_LISTS: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT; - case IDC_PL_RULES_LIST: - case IDC_CLIST: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT|RD_ANCHORX_WIDTH; - case IDC_NEWJID: - case IDC_CANVAS: - return RD_ANCHORX_LEFT|RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; - case IDC_ADD_LIST: - case IDC_ACTIVATE: - case IDC_REMOVE_LIST: - case IDC_SET_DEFAULT: - case IDC_TXT_OTHERJID: - case IDC_ADD_RULE: - case IDC_UP_RULE: - case IDC_EDIT_RULE: - case IDC_DOWN_RULE: - case IDC_REMOVE_RULE: - return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; - case IDC_ADDJID: - case IDC_APPLY: - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - return CSuper::Resizer(urc); -} - -INT_PTR __cdecl CJabberProto::OnMenuHandlePrivacyLists( WPARAM, LPARAM ) -{ - UI_SAFE_OPEN(CJabberDlgPrivacyLists, m_pDlgPrivacyLists); - return 0; -} - -void CJabberProto::QueryPrivacyLists( ThreadData *pThreadInfo ) -{ - XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyLists )); - iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); - if ( pThreadInfo ) - pThreadInfo->send( iq ); - else if ( m_ThreadInfo ) - m_ThreadInfo->send( iq ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// builds privacy menu - -INT_PTR __cdecl CJabberProto::menuSetPrivacyList( WPARAM, LPARAM, LPARAM iList ) -{ - m_privacyListManager.Lock(); - CPrivacyList *pList = NULL; - - if (iList) - { - pList = m_privacyListManager.GetFirstList(); - for (int i = 1; pList && (i < iList); ++i) - pList = pList->GetNext(); - } - - XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListActive, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); - HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); - HXML active = query << XCHILD( _T("active")); - if ( pList ) - active << XATTR( _T("name"), pList->GetListName()); - m_privacyListManager.Unlock(); - - m_ThreadInfo->send( iq ); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// init privacy menu - -void CJabberProto::BuildPrivacyMenu() -{ - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(mi); - mi.position = 200005; - mi.pszContactOwner = m_szModuleName; - mi.icolibItem = GetIconHandle(IDI_AGENTS); - mi.flags = CMIF_ROOTPOPUP | CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB | CMIF_HIDDEN; - mi.pszName = LPGEN("Privacy Lists"); - mi.hParentMenu = MO_GetProtoRootMenu( m_szModuleName ); - m_hPrivacyMenuRoot = Menu_AddProtoMenuItem(&mi); - - JCreateService( "/PrivacyLists", &CJabberProto::OnMenuHandlePrivacyLists ); - char srvFce[MAX_PATH + 64]; - mir_snprintf( srvFce, SIZEOF(srvFce), "%s/PrivacyLists", m_szModuleName ); - mi.pszService = srvFce; - mi.position = 3000040000; - mi.flags = CMIF_CHILDPOPUP | CMIF_TCHAR | CMIF_ICONFROMICOLIB; - mi.icolibItem = GetIconHandle(IDI_PRIVACY_LISTS); - mi.ptszName = LPGENT("List Editor..."); - mi.hParentMenu = m_hPrivacyMenuRoot; - Menu_AddProtoMenuItem(&mi); -} - -void CJabberProto::BuildPrivacyListsMenu( bool bDeleteOld ) -{ - int i; - if ( bDeleteOld ) - for ( i=0; i < m_hPrivacyMenuItems.getCount(); i++ ) - CallService( MO_REMOVEMENUITEM, (WPARAM)m_hPrivacyMenuItems[i], 0 ); - m_hPrivacyMenuItems.destroy(); - - m_privacyListManager.Lock(); - - i = 0; - char srvFce[MAX_PATH + 64], *svcName = srvFce+strlen( m_szModuleName ); - - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(mi); - mi.position = 2000040000; - mi.flags = CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB | CMIF_TCHAR; - mi.hParentMenu = m_hPrivacyMenuRoot; - mi.pszService = srvFce; - - mir_snprintf( srvFce, SIZEOF(srvFce), "%s/menuPrivacy%d", m_szModuleName, i ); - if ( i > m_privacyMenuServiceAllocated ) { - JCreateServiceParam( svcName, &CJabberProto::menuSetPrivacyList, i ); - m_privacyMenuServiceAllocated = i; - } - mi.position++; - mi.icolibItem = LoadSkinnedIconHandle( - m_privacyListManager.GetActiveListName() ? - SKINICON_OTHER_SMALLDOT : - SKINICON_OTHER_EMPTYBLOB); - mi.ptszName = LPGENT("<none>"); - m_hPrivacyMenuItems.insert( Menu_AddProtoMenuItem(&mi)); - - for ( CPrivacyList *pList = m_privacyListManager.GetFirstList(); pList; pList = pList->GetNext()) { - ++i; - mir_snprintf( srvFce, SIZEOF(srvFce), "%s/menuPrivacy%d", m_szModuleName, i ); - - if ( i > m_privacyMenuServiceAllocated ) { - JCreateServiceParam( svcName, &CJabberProto::menuSetPrivacyList, i ); - m_privacyMenuServiceAllocated = i; - } - - mi.position++; - mi.icolibItem = LoadSkinnedIconHandle( - lstrcmp( m_privacyListManager.GetActiveListName(), pList->GetListName()) ? - SKINICON_OTHER_SMALLDOT : - SKINICON_OTHER_EMPTYBLOB); - mi.ptszName = pList->GetListName(); - m_hPrivacyMenuItems.insert( Menu_AddProtoMenuItem(&mi)); - } - - m_privacyListManager.Unlock(); -} diff --git a/protocols/JabberG/jabber_privacy.h b/protocols/JabberG/jabber_privacy.h deleted file mode 100644 index 4a2cfd8f2f..0000000000 --- a/protocols/JabberG/jabber_privacy.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_PRIVACY_H_ -#define _JABBER_PRIVACY_H_ - -#define JABBER_PL_RULE_TYPE_MESSAGE 1 -#define JABBER_PL_RULE_TYPE_PRESENCE_IN 2 -#define JABBER_PL_RULE_TYPE_PRESENCE_OUT 4 -#define JABBER_PL_RULE_TYPE_IQ 8 -#define JABBER_PL_RULE_TYPE_ALL 0x0F - -enum PrivacyListRuleType -{ - Jid, - Group, - Subscription, - Else -}; - -struct CPrivacyListModifyUserParam -{ - BOOL m_bAllOk; - volatile LONG m_dwCount; - CPrivacyListModifyUserParam() : - m_bAllOk( TRUE ), - m_dwCount( 0 ) - { - } -}; - -class CPrivacyList; - -class CPrivacyListRule -{ -protected: - friend class CPrivacyList; -public: - CPrivacyListRule( CJabberProto* ppro, PrivacyListRuleType type = Else, const TCHAR *szValue = _T(""), BOOL bAction = TRUE, DWORD dwOrder = 90, DWORD dwPackets = 0) - { - m_proto = ppro; - m_szValue = mir_tstrdup(szValue); - m_nType = type; - m_bAction = bAction; - m_dwOrder = dwOrder; - m_dwPackets = dwPackets; - m_pNext = NULL; - }; - ~CPrivacyListRule() - { - if (m_szValue) - mir_free(m_szValue); - - if (m_pNext) - delete m_pNext; - }; - __inline CPrivacyListRule* GetNext() - { - return m_pNext; - } - CPrivacyListRule* SetNext(CPrivacyListRule *pNext) - { - CPrivacyListRule *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } - __inline DWORD GetOrder() - { - return m_dwOrder; - } - DWORD SetOrder(DWORD dwOrder) - { - DWORD dwRetVal = m_dwOrder; - m_dwOrder = dwOrder; - return dwRetVal; - } - __inline PrivacyListRuleType GetType() - { - return m_nType; - } - __inline BOOL SetType( PrivacyListRuleType type ) - { - m_nType = type; - return TRUE; - } - __inline TCHAR* GetValue() - { - return m_szValue; - } - __inline BOOL SetValue( TCHAR *szValue ) - { - replaceStrT( m_szValue, szValue ); - return TRUE; - } - __inline DWORD GetPackets() - { - return m_dwPackets; - } - __inline BOOL SetPackets( DWORD dwPackets ) - { - m_dwPackets = dwPackets; - return TRUE; - } - __inline BOOL GetAction() - { - return m_bAction; - } - __inline BOOL SetAction( BOOL bAction ) - { - m_bAction = bAction; - return TRUE; - } - CJabberProto* m_proto; -protected: - PrivacyListRuleType m_nType; - TCHAR *m_szValue; - BOOL m_bAction; - DWORD m_dwOrder; - DWORD m_dwPackets; - CPrivacyListRule *m_pNext; -}; - -class CPrivacyList; -class CPrivacyList -{ -protected: - CPrivacyListRule *m_pRules; - TCHAR *m_szListName; - CPrivacyList *m_pNext; - BOOL m_bLoaded; - BOOL m_bModified; - BOOL m_bDeleted; -public: - CJabberProto* m_proto; - - CPrivacyList(CJabberProto* ppro, TCHAR *szListName) - { - m_proto = ppro; - m_szListName = mir_tstrdup(szListName); - m_pRules = NULL; - m_pNext = NULL; - m_bLoaded = FALSE; - m_bModified = FALSE; - m_bDeleted = FALSE; - }; - ~CPrivacyList() - { - if (m_szListName) - mir_free(m_szListName); - RemoveAllRules(); - if (m_pNext) - delete m_pNext; - }; - BOOL RemoveAllRules() - { - if (m_pRules) - delete m_pRules; - m_pRules = NULL; - return TRUE; - } - __inline TCHAR* GetListName() - { - return m_szListName; - } - __inline CPrivacyListRule* GetFirstRule() - { - return m_pRules; - } - __inline CPrivacyList* GetNext() - { - return m_pNext; - } - CPrivacyList* SetNext(CPrivacyList *pNext) - { - CPrivacyList *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } - BOOL AddRule(PrivacyListRuleType type, const TCHAR *szValue, BOOL bAction, DWORD dwOrder, DWORD dwPackets) - { - CPrivacyListRule *pRule = new CPrivacyListRule( m_proto, type, szValue, bAction, dwOrder, dwPackets ); - if ( !pRule ) - return FALSE; - pRule->SetNext( m_pRules ); - m_pRules = pRule; - return TRUE; - } - BOOL AddRule(CPrivacyListRule *pRule) - { - pRule->SetNext( m_pRules ); - m_pRules = pRule; - return TRUE; - } - BOOL RemoveRule(CPrivacyListRule *pRuleToRemove) - { - if ( !m_pRules ) - return FALSE; - - if ( m_pRules == pRuleToRemove ) { - m_pRules = m_pRules->GetNext(); - pRuleToRemove->SetNext( NULL ); - delete pRuleToRemove; - return TRUE; - } - - CPrivacyListRule *pRule = m_pRules; - while ( pRule->GetNext()) { - if ( pRule->GetNext() == pRuleToRemove ) { - pRule->SetNext( pRule->GetNext()->GetNext()); - pRuleToRemove->SetNext( NULL ); - delete pRuleToRemove; - return TRUE; - } - pRule = pRule->GetNext(); - } - return FALSE; - } - BOOL Reorder() - { - // 0 or 1 rules? - if ( !m_pRules ) - return TRUE; - if ( !m_pRules->GetNext()) { - m_pRules->SetOrder( 100 ); - return TRUE; - } - - // get rules count - DWORD dwCount = 0; - CPrivacyListRule *pRule = m_pRules; - while ( pRule ) { - dwCount++; - pRule = pRule->GetNext(); - } - - // create pointer array for sort procedure - CPrivacyListRule **pRules = ( CPrivacyListRule ** )mir_alloc( dwCount * sizeof( CPrivacyListRule * )); - if ( !pRules ) - return FALSE; - DWORD dwPos = 0; - pRule = m_pRules; - while ( pRule ) { - pRules[dwPos++] = pRule; - pRule = pRule->GetNext(); - } - - // sort array of pointers, slow, but working :) - DWORD i, j; - CPrivacyListRule *pTmp; - for ( i = 0; i < dwCount; i++ ) { - for ( j = dwCount - 1; j > i; j-- ) { - if ( pRules[j - 1]->GetOrder() > pRules[j]->GetOrder()) { - pTmp = pRules[j - 1]; - pRules[j - 1] = pRules[j]; - pRules[j] = pTmp; - } - } - } - - // reorder linked list - DWORD dwOrder = 100; - CPrivacyListRule **ppPtr = &m_pRules; - for ( i = 0; i < dwCount; i++ ) { - *ppPtr = pRules[ i ]; - ppPtr = &pRules[ i ]->m_pNext; - pRules[ i ]->SetOrder( dwOrder ); - dwOrder += 10; - } - *ppPtr = NULL; - mir_free( pRules ); - - return TRUE; - } - __inline void SetLoaded(BOOL bLoaded = TRUE) - { - m_bLoaded = bLoaded; - } - __inline BOOL IsLoaded() - { - return m_bLoaded; - } - __inline void SetModified(BOOL bModified = TRUE) - { - m_bModified = bModified; - } - __inline BOOL IsModified() - { - return m_bModified; - } - __inline void SetDeleted(BOOL bDeleted = TRUE) - { - m_bDeleted = bDeleted; - } - __inline BOOL IsDeleted() - { - return m_bDeleted; - } -}; - -class CPrivacyListManager -{ -protected: - TCHAR *m_szActiveListName; - TCHAR *m_szDefaultListName; - CPrivacyList *m_pLists; - CRITICAL_SECTION m_cs; - BOOL m_bModified; - -public: - CJabberProto* m_proto; - - CPrivacyListManager( CJabberProto* ppro ) - { - m_proto = ppro; - m_szActiveListName = NULL; - m_szDefaultListName = NULL; - m_pLists = NULL; - InitializeCriticalSection(&m_cs); - m_bModified = FALSE; - }; - ~CPrivacyListManager() - { - if (m_szActiveListName) - mir_free(m_szActiveListName); - if (m_szDefaultListName) - mir_free(m_szDefaultListName); - RemoveAllLists(); - DeleteCriticalSection(&m_cs); - }; - BOOL Lock() - { - EnterCriticalSection(&m_cs); - return TRUE; - } - BOOL Unlock() - { - LeaveCriticalSection(&m_cs); - return TRUE; - } - void SetActiveListName(const TCHAR *szListName) - { - replaceStrT(m_szActiveListName, szListName); - } - void SetDefaultListName(const TCHAR *szListName) - { - replaceStrT(m_szDefaultListName, szListName); - } - TCHAR* GetDefaultListName() - { - return m_szDefaultListName; - } - TCHAR* GetActiveListName() - { - return m_szActiveListName; - } - BOOL RemoveAllLists() - { - if (m_pLists) - delete m_pLists; - m_pLists = NULL; - return TRUE; - } - CPrivacyList* FindList( const TCHAR *szListName ) - { - CPrivacyList *pList = m_pLists; - while ( pList ) { - if ( !_tcscmp(pList->GetListName(), szListName )) - return pList; - pList = pList->GetNext(); - } - return NULL; - } - CPrivacyList* GetFirstList() - { - return m_pLists; - } - BOOL AddList( TCHAR *szListName ) - { - if (FindList(szListName)) - return FALSE; - CPrivacyList *pList = new CPrivacyList( m_proto, szListName ); - pList->SetNext( m_pLists ); - m_pLists = pList; - return TRUE; - } - BOOL SetModified(BOOL bModified = TRUE) - { - m_bModified = bModified; - return TRUE; - } - BOOL IsModified() - { - if ( m_bModified ) - return TRUE; - CPrivacyList *pList = m_pLists; - while ( pList ) { - if ( pList->IsModified()) - return TRUE; - pList = pList->GetNext(); - } - return FALSE; - } - BOOL IsAllListsLoaded() - { - CPrivacyList *pList = m_pLists; - while ( pList ) { - if ( !pList->IsLoaded()) - return FALSE; - pList = pList->GetNext(); - } - return TRUE; - } -}; - -#endif //_JABBER_PRIVACY_H_ diff --git a/protocols/JabberG/jabber_proto.cpp b/protocols/JabberG/jabber_proto.cpp deleted file mode 100644 index 6444482ee6..0000000000 --- a/protocols/JabberG/jabber_proto.cpp +++ /dev/null @@ -1,1659 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#include <fcntl.h> -#include <io.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <m_addcontact.h> -#include <m_file.h> -#include <m_genmenu.h> -#include <m_icolib.h> - -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "jabber_disco.h" - -#include "m_proto_listeningto.h" -#include "m_modernopt.h" - -#pragma warning(disable:4355) - -static int compareTransports( const TCHAR* p1, const TCHAR* p2 ) -{ return _tcsicmp( p1, p2 ); -} - -static int compareListItems( const JABBER_LIST_ITEM* p1, const JABBER_LIST_ITEM* p2 ) -{ - if ( p1->list != p2->list ) - return p1->list - p2->list; - - // for bookmarks, temporary contacts & groupchat members - // resource must be used in the comparison - if (( p1->list == LIST_ROSTER && ( p1->bUseResource == TRUE || p2->bUseResource == TRUE )) - || ( p1->list == LIST_BOOKMARK ) || ( p1->list == LIST_VCARD_TEMP )) - return lstrcmpi( p1->jid, p2->jid ); - - TCHAR szp1[ JABBER_MAX_JID_LEN ], szp2[ JABBER_MAX_JID_LEN ]; - JabberStripJid( p1->jid, szp1, SIZEOF( szp1 )); - JabberStripJid( p2->jid, szp2, SIZEOF( szp2 )); - return lstrcmpi( szp1, szp2 ); -} - -CJabberProto::CJabberProto( const char* aProtoName, const TCHAR* aUserName ) : - m_options( this ), - m_lstTransports( 50, compareTransports ), - m_lstRoster( 50, compareListItems ), - m_iqManager( this ), - m_messageManager( this ), - m_presenceManager( this ), - m_sendManager( this ), - m_adhocManager( this ), - m_clientCapsManager( this ), - m_privacyListManager( this ), - m_privacyMenuServiceAllocated( -1 ), - m_priorityMenuVal( 0 ), - m_priorityMenuValSet( false ), - m_hPrivacyMenuRoot( 0 ), - m_hPrivacyMenuItems( 10 ), - m_pLastResourceList( NULL ), - m_lstJabberFeatCapPairsDynamic( 2 ), - m_uEnabledFeatCapsDynamic( 0 ) -{ - InitializeCriticalSection( &m_csModeMsgMutex ); - InitializeCriticalSection( &m_csLists ); - InitializeCriticalSection( &m_csLastResourceMap ); - - m_szXmlStreamToBeInitialized = NULL; - - m_iVersion = 2; - m_tszUserName = mir_tstrdup( aUserName ); - m_szModuleName = mir_strdup( aProtoName ); - m_szProtoName = mir_strdup( aProtoName ); - _strlwr( m_szProtoName ); - m_szProtoName[0] = toupper( m_szProtoName[0] ); - Log( "Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName ); - - // Initialize Jabber API - m_JabberApi.m_psProto = this; - m_JabberSysApi.m_psProto = this; - m_JabberNetApi.m_psProto = this; - - // Jabber dialog list - m_windowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); - - // Protocol services and events... - m_hEventNudge = JCreateHookableEvent( JE_NUDGE ); - m_hEventXStatusIconChanged = JCreateHookableEvent( JE_CUSTOMSTATUS_EXTRAICON_CHANGED ); - m_hEventXStatusChanged = JCreateHookableEvent( JE_CUSTOMSTATUS_CHANGED ); - - JCreateService( PS_CREATEACCMGRUI, &CJabberProto::SvcCreateAccMgrUI ); - - JCreateService( PS_GETAVATARINFOT, &CJabberProto::JabberGetAvatarInfo ); - JCreateService( PS_GETMYAWAYMSG, &CJabberProto::GetMyAwayMsg ); - JCreateService( PS_SET_LISTENINGTO, &CJabberProto::OnSetListeningTo ); - - JCreateService( PS_JOINCHAT, &CJabberProto::OnJoinChat ); - JCreateService( PS_LEAVECHAT, &CJabberProto::OnLeaveChat ); - - JCreateService( JS_GETCUSTOMSTATUSICON, &CJabberProto::OnGetXStatusIcon ); - JCreateService( JS_GETXSTATUS, &CJabberProto::OnGetXStatus ); - JCreateService( JS_SETXSTATUS, &CJabberProto::OnSetXStatus ); - JCreateService( JS_SETXSTATUSEX, &CJabberProto::OnSetXStatusEx ); - - // not needed anymore and therefore commented out - // JCreateService( JS_GETXSTATUSEX, &CJabberProto::OnGetXStatusEx ); - - JCreateService( JS_HTTP_AUTH, &CJabberProto::OnHttpAuthRequest ); - JCreateService( JS_INCOMING_NOTE_EVENT, &CJabberProto::OnIncomingNoteEvent ); - - JCreateService( JS_SENDXML, &CJabberProto::ServiceSendXML ); - JCreateService( PS_GETMYAVATART, &CJabberProto::JabberGetAvatar ); - JCreateService( PS_GETAVATARCAPS, &CJabberProto::JabberGetAvatarCaps ); - JCreateService( PS_SETMYAVATART, &CJabberProto::JabberSetAvatar ); - JCreateService( PS_SETMYNICKNAME, &CJabberProto::JabberSetNickname ); - - JCreateService( JS_GETADVANCEDSTATUSICON, &CJabberProto::JGetAdvancedStatusIcon ); - JCreateService( JS_DB_GETEVENTTEXT_CHATSTATES, &CJabberProto::OnGetEventTextChatStates ); - JCreateService( JS_DB_GETEVENTTEXT_PRESENCE, &CJabberProto::OnGetEventTextPresence ); - - JCreateService( JS_GETJABBERAPI, &CJabberProto::JabberGetApi ); - - // XEP-0224 support (Attention/Nudge) - JCreateService( JS_SEND_NUDGE, &CJabberProto::JabberSendNudge ); - - // service to get from protocol chat buddy info - JCreateService( MS_GC_PROTO_GETTOOLTIPTEXT, &CJabberProto::JabberGCGetToolTipText ); - - // XMPP URI parser service for "File Association Manager" plugin - JCreateService( JS_PARSE_XMPP_URI, &CJabberProto::JabberServiceParseXmppURI ); - - JHookEvent( ME_MODERNOPT_INITIALIZE, &CJabberProto::OnModernOptInit ); - JHookEvent( ME_OPT_INITIALISE, &CJabberProto::OnOptionsInit ); - JHookEvent( ME_SKIN2_ICONSCHANGED, &CJabberProto::OnReloadIcons ); - - m_iqManager.FillPermanentHandlers(); - m_iqManager.Start(); - m_messageManager.FillPermanentHandlers(); - m_messageManager.Start(); - m_presenceManager.FillPermanentHandlers(); - m_presenceManager.Start(); - m_sendManager.Start(); - m_adhocManager.FillDefaultNodes(); - m_clientCapsManager.AddDefaultCaps(); - - IconsInit(); - InitPopups(); - GlobalMenuInit(); - WsInit(); - IqInit(); - SerialInit(); - ConsoleInit(); - InitCustomFolders(); - - m_pepServices.insert(new CPepMood(this)); - m_pepServices.insert(new CPepActivity(this)); - - *m_savedPassword = 0; - - char text[ MAX_PATH ]; - mir_snprintf( text, sizeof( text ), "%s/Status", m_szModuleName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - mir_snprintf( text, sizeof( text ), "%s/%s", m_szModuleName, DBSETTING_DISPLAY_UID ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - - mir_snprintf( text, sizeof( text ), "%s/SubscriptionText", m_szModuleName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - mir_snprintf( text, sizeof( text ), "%s/Subscription", m_szModuleName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - mir_snprintf( text, sizeof( text ), "%s/Auth", m_szModuleName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - mir_snprintf( text, sizeof( text ), "%s/Grant", m_szModuleName ); - CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); - - DBVARIANT dbv; - if ( !JGetStringT( NULL, "XmlLang", &dbv )) { - m_tszSelectedLang = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else m_tszSelectedLang = mir_tstrdup( _T( "en" )); - - if (!DBGetContactSettingString(NULL, m_szModuleName, "Password", &dbv)) { - CallService(MS_DB_CRYPT_DECODESTRING, lstrlenA(dbv.pszVal) + 1, (LPARAM)dbv.pszVal); - TCHAR *pssw = mir_a2t(dbv.pszVal); - JSetStringCrypt(NULL, "LoginPassword", pssw); - mir_free(pssw); - JFreeVariant(&dbv); - JDeleteSetting(NULL, "Password"); - } - - CleanLastResourceMap(); -} - -CJabberProto::~CJabberProto() -{ - WsUninit(); - IqUninit(); - XStatusUninit(); - SerialUninit(); - ConsoleUninit(); - GlobalMenuUninit(); - - delete m_pInfoFrame; - - DestroyHookableEvent( m_hEventNudge ); - DestroyHookableEvent( m_hEventXStatusIconChanged ); - DestroyHookableEvent( m_hEventXStatusChanged ); - if ( m_hInitChat ) - DestroyHookableEvent( m_hInitChat ); - - CleanLastResourceMap(); - - ListWipe(); - DeleteCriticalSection( &m_csLists ); - - mir_free( m_tszSelectedLang ); - mir_free( m_phIconLibItems ); - mir_free( m_AuthMechs.m_gssapiHostName ); - - DeleteCriticalSection( &m_filterInfo.csPatternLock ); - DeleteCriticalSection( &m_csModeMsgMutex ); - DeleteCriticalSection( &m_csLastResourceMap ); - - mir_free( m_modeMsgs.szOnline ); - mir_free( m_modeMsgs.szAway ); - mir_free( m_modeMsgs.szNa ); - mir_free( m_modeMsgs.szDnd ); - mir_free( m_modeMsgs.szFreechat ); - - mir_free( m_transportProtoTableStartIndex ); - - mir_free( m_szStreamId ); - mir_free( m_szProtoName ); - mir_free( m_szModuleName ); - mir_free( m_tszUserName ); - - int i; - for ( i=0; i < m_lstTransports.getCount(); i++ ) - mir_free( m_lstTransports[i] ); - m_lstTransports.destroy(); - - for ( i=0; i < m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { - mir_free( m_lstJabberFeatCapPairsDynamic[i]->szExt ); - mir_free( m_lstJabberFeatCapPairsDynamic[i]->szFeature ); - if ( m_lstJabberFeatCapPairsDynamic[i]->szDescription ) - mir_free( m_lstJabberFeatCapPairsDynamic[i]->szDescription ); - delete m_lstJabberFeatCapPairsDynamic[i]; - } - m_lstJabberFeatCapPairsDynamic.destroy(); - m_hPrivacyMenuItems.destroy(); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// OnModulesLoadedEx - performs hook registration - -static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - -int CJabberProto::OnModulesLoadedEx( WPARAM, LPARAM ) -{ - JHookEvent( ME_USERINFO_INITIALISE, &CJabberProto::OnUserInfoInit ); - XStatusInit(); - m_pepServices.InitGui(); - - m_pInfoFrame = new CJabberInfoFrame(this); - - if ( ServiceExists( MS_GC_REGISTER )) { - jabberChatDllPresent = true; - - GCREGISTER gcr = {0}; - gcr.cbSize = sizeof( GCREGISTER ); - gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR | GC_TCHAR; - gcr.iMaxText = 0; - gcr.nColors = 16; - gcr.pColors = &crCols[0]; - gcr.ptszModuleDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - CallServiceSync( MS_GC_REGISTER, NULL, ( LPARAM )&gcr ); - - JHookEvent( ME_GC_EVENT, &CJabberProto::JabberGcEventHook ); - JHookEvent( ME_GC_BUILDMENU, &CJabberProto::JabberGcMenuHook ); - - char szEvent[ 200 ]; - mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", m_szModuleName ); - m_hInitChat = CreateHookableEvent( szEvent ); - JHookEvent( szEvent, &CJabberProto::JabberGcInit ); - } - - if ( ServiceExists( MS_MSG_ADDICON )) { - StatusIconData sid = {0}; - sid.cbSize = sizeof(sid); - sid.szModule = m_szModuleName; - sid.hIcon = LoadIconEx("main"); - sid.hIconDisabled = LoadIconEx("main"); - sid.flags = MBF_HIDDEN; - sid.szTooltip = Translate("Jabber Resource"); - CallService(MS_MSG_ADDICON, 0, (LPARAM) &sid); - JHookEvent( ME_MSG_ICONPRESSED, &CJabberProto::OnProcessSrmmIconClick ); - JHookEvent( ME_MSG_WINDOWEVENT, &CJabberProto::OnProcessSrmmEvent ); - - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) - MenuHideSrmmIcon(hContact); - hContact = db_find_next(hContact); - } } - - DBEVENTTYPEDESCR dbEventType = {0}; - dbEventType.cbSize = sizeof(DBEVENTTYPEDESCR); - dbEventType.eventType = JABBER_DB_EVENT_TYPE_CHATSTATES; - dbEventType.module = m_szModuleName; - dbEventType.descr = "Chat state notifications"; - CallService( MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&dbEventType ); - - dbEventType.eventType = JABBER_DB_EVENT_TYPE_PRESENCE; - dbEventType.module = m_szModuleName; - dbEventType.descr = "Presence notifications"; - CallService( MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&dbEventType ); - - JHookEvent( ME_IDLE_CHANGED, &CJabberProto::OnIdleChanged ); - - CheckAllContactsAreTransported(); - - // Set all contacts to offline - HANDLE hContact = db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { - SetContactOfflineStatus( hContact ); - - if ( JGetByte( hContact, "IsTransport", 0 )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - TCHAR* domain = NEWTSTR_ALLOCA(dbv.ptszVal); - TCHAR* resourcepos = _tcschr( domain, '/' ); - if ( resourcepos != NULL ) - *resourcepos = '\0'; - m_lstTransports.insert( mir_tstrdup( domain )); - JFreeVariant( &dbv ); - } } } - - hContact = db_find_next(hContact); - } - - CleanLastResourceMap(); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberAddToList - adds a contact to the contact list - -HANDLE CJabberProto::AddToListByJID( const TCHAR* newJid, DWORD flags ) -{ - HANDLE hContact; - TCHAR* jid, *nick; - - Log( "AddToListByJID jid = " TCHAR_STR_PARAM, newJid ); - - if (( hContact=HContactFromJID( newJid )) == NULL ) { - // not already there: add - jid = mir_tstrdup( newJid ); - Log( "Add new jid to contact jid = " TCHAR_STR_PARAM, jid ); - hContact = ( HANDLE ) CallService( MS_DB_CONTACT_ADD, 0, 0 ); - CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )m_szModuleName ); - JSetStringT( hContact, "jid", jid ); - if (( nick=JabberNickFromJID( newJid )) == NULL ) - nick = mir_tstrdup( newJid ); -// JSetStringT( hContact, "Nick", nick ); - mir_free( nick ); - mir_free( jid ); - - // Note that by removing or disable the "NotOnList" will trigger - // the plugin to add a particular contact to the roster list. - // See DBSettingChanged hook at the bottom part of this source file. - // But the add module will delete "NotOnList". So we will not do it here. - // Also because we need "MyHandle" and "Group" info, which are set after - // PS_ADDTOLIST is called but before the add dialog issue deletion of - // "NotOnList". - // If temporary add, "NotOnList" won't be deleted, and that's expected. - DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); - if ( flags & PALF_TEMPORARY ) - DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 ); - } - else { - // already exist - // Set up a dummy "NotOnList" when adding permanently only - if ( !( flags & PALF_TEMPORARY )) - DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); - } - - if (hContact && newJid) - DBCheckIsTransportedContact( newJid, hContact ); - return hContact; -} - -HANDLE CJabberProto::AddToList( int flags, PROTOSEARCHRESULT* psr ) -{ - if ( psr->cbSize != sizeof( JABBER_SEARCH_RESULT ) && psr->id == NULL ) - return NULL; - - JABBER_SEARCH_RESULT* jsr = ( JABBER_SEARCH_RESULT* )psr; - TCHAR *jid = psr->id ? psr->id : jsr->jid; - return AddToListByJID( jid, flags ); -} - -HANDLE __cdecl CJabberProto::AddToListByEvent( int flags, int /*iContact*/, HANDLE hDbEvent ) -{ - DBEVENTINFO dbei; - HANDLE hContact; - char* nick, *firstName, *lastName, *jid; - - Log( "AddToListByEvent" ); - ZeroMemory( &dbei, sizeof( dbei )); - dbei.cbSize = sizeof( dbei ); - if (( dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) - return NULL; - if (( dbei.pBlob=( PBYTE ) alloca( dbei.cbBlob )) == NULL ) - return NULL; - if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) - return NULL; - if ( strcmp( dbei.szModule, m_szModuleName )) - return NULL; - -/* - // EVENTTYPE_CONTACTS is when adding from when we receive contact list ( not used in Jabber ) - // EVENTTYPE_ADDED is when adding from when we receive "You are added" ( also not used in Jabber ) - // Jabber will only handle the case of EVENTTYPE_AUTHREQUEST - // EVENTTYPE_AUTHREQUEST is when adding from the authorization request dialog -*/ - - if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) - return NULL; - - nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2); - firstName = nick + strlen( nick ) + 1; - lastName = firstName + strlen( firstName ) + 1; - jid = lastName + strlen( lastName ) + 1; - - TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); - hContact = ( HANDLE ) AddToListByJID( newJid, flags ); - mir_free( newJid ); - return hContact; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberAuthAllow - processes the successful authorization - -int CJabberProto::Authorize( HANDLE hDbEvent ) -{ - DBEVENTINFO dbei; - char* nick, *firstName, *lastName, *jid; - - if ( !m_bJabberOnline ) - return 1; - - memset( &dbei, 0, sizeof( dbei )); - dbei.cbSize = sizeof( dbei ); - if (( dbei.cbBlob=CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) - return 1; - if (( dbei.pBlob=( PBYTE )alloca( dbei.cbBlob )) == NULL ) - return 1; - if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) - return 1; - if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) - return 1; - if ( strcmp( dbei.szModule, m_szModuleName )) - return 1; - - nick = ( char* )(dbei.pBlob + sizeof(DWORD)*2); - firstName = nick + strlen( nick ) + 1; - lastName = firstName + strlen( firstName ) + 1; - jid = lastName + strlen( lastName ) + 1; - - Log( "Send 'authorization allowed' to " TCHAR_STR_PARAM, jid ); - - TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); - - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), newJid) << XATTR( _T("type"), _T("subscribed"))); - - // Automatically add this user to my roster if option is enabled - if ( m_options.AutoAdd == TRUE ) { - HANDLE hContact; - JABBER_LIST_ITEM *item; - - if (( item = ListGetItemPtr( LIST_ROSTER, newJid )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) { - Log( "Try adding contact automatically jid = " TCHAR_STR_PARAM, jid ); - if (( hContact=AddToListByJID( newJid, 0 )) != NULL ) { - // Trigger actual add by removing the "NotOnList" added by AddToListByJID() - // See AddToListByJID() and JabberDbSettingChanged(). - DBDeleteContactSetting( hContact, "CList", "NotOnList" ); - } } } - - mir_free( newJid ); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberAuthDeny - handles the unsuccessful authorization - -int CJabberProto::AuthDeny( HANDLE hDbEvent, const TCHAR* /*szReason*/ ) -{ - DBEVENTINFO dbei; - char* nick, *firstName, *lastName, *jid; - - if ( !m_bJabberOnline ) - return 1; - - Log( "Entering AuthDeny" ); - memset( &dbei, 0, sizeof( dbei )); - dbei.cbSize = sizeof( dbei ); - if (( dbei.cbBlob=CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) - return 1; - if (( dbei.pBlob=( PBYTE ) mir_alloc( dbei.cbBlob )) == NULL ) - return 1; - if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) { - mir_free( dbei.pBlob ); - return 1; - } - if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) { - mir_free( dbei.pBlob ); - return 1; - } - if ( strcmp( dbei.szModule, m_szModuleName )) { - mir_free( dbei.pBlob ); - return 1; - } - - nick = ( char* )( dbei.pBlob + sizeof(DWORD)*2); - firstName = nick + strlen( nick ) + 1; - lastName = firstName + strlen( firstName ) + 1; - jid = lastName + strlen( lastName ) + 1; - - Log( "Send 'authorization denied' to %s" , jid ); - - TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); - - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), newJid) << XATTR( _T("type"), _T("unsubscribed"))); - - mir_free( newJid ); - mir_free( dbei.pBlob ); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AUTH - -int __cdecl CJabberProto::AuthRecv( HANDLE, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AUTHREQUEST - -int __cdecl CJabberProto::AuthRequest( HANDLE, const TCHAR* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// ChangeInfo - -HANDLE __cdecl CJabberProto::ChangeInfo( int /*iInfoType*/, void* ) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberFileAllow - starts a file transfer - -HANDLE __cdecl CJabberProto::FileAllow( HANDLE /*hContact*/, HANDLE hTransfer, const TCHAR* szPath ) -{ - if ( !m_bJabberOnline ) - return 0; - - filetransfer* ft = ( filetransfer* )hTransfer; - ft->std.tszWorkingDir = mir_tstrdup( szPath ); - size_t len = _tcslen( ft->std.tszWorkingDir )-1; - if ( ft->std.tszWorkingDir[len] == '/' || ft->std.tszWorkingDir[len] == '\\' ) - ft->std.tszWorkingDir[len] = 0; - - switch ( ft->type ) { - case FT_OOB: - JForkThread(( JThreadFunc )&CJabberProto::FileReceiveThread, ft ); - break; - case FT_BYTESTREAM: - FtAcceptSiRequest( ft ); - break; - case FT_IBB: - FtAcceptIbbRequest( ft ); - break; - } - return hTransfer; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberFileCancel - cancels a file transfer - -int __cdecl CJabberProto::FileCancel( HANDLE /*hContact*/, HANDLE hTransfer ) -{ - filetransfer* ft = ( filetransfer* )hTransfer; - HANDLE hEvent; - - Log( "Invoking FileCancel()" ); - if ( ft->type == FT_OOB ) { - if ( ft->s ) { - Log( "FT canceled" ); - Log( "Closing ft->s = %d", ft->s ); - ft->state = FT_ERROR; - Netlib_CloseHandle( ft->s ); - ft->s = NULL; - if ( ft->hFileEvent != NULL ) { - hEvent = ft->hFileEvent; - ft->hFileEvent = NULL; - SetEvent( hEvent ); - } - Log( "ft->s is now NULL, ft->state is now FT_ERROR" ); - } - } - else FtCancel( ft ); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberFileDeny - denies a file transfer - -int __cdecl CJabberProto::FileDeny( HANDLE /*hContact*/, HANDLE hTransfer, const TCHAR* /*reason*/ ) -{ - if ( !m_bJabberOnline ) - return 1; - - filetransfer* ft = ( filetransfer* )hTransfer; - - switch ( ft->type ) { - case FT_OOB: - m_ThreadInfo->send( XmlNodeIq( _T("error"), ft->iqId, ft->jid ) << XCHILD( _T("error"), _T("File transfer refused")) << XATTRI( _T("code"), 406 )); - break; - - case FT_BYTESTREAM: - case FT_IBB: - m_ThreadInfo->send( - XmlNodeIq( _T("error"), ft->iqId, ft->jid ) - << XCHILD( _T("error"), _T("File transfer refused")) << XATTRI( _T("code"), 403 ) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("forbidden"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")) - << XCHILD( _T("text"), _T("File transfer refused")) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - break; - } - delete ft; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberFileResume - processes file renaming etc - -int __cdecl CJabberProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) -{ - filetransfer* ft = ( filetransfer* )hTransfer; - if ( !m_bJabberOnline || ft == NULL ) - return 1; - - if ( *action == FILERESUME_RENAME ) - replaceStrT( ft->std.tszCurrentFile, *szFilename ); - - SetEvent( ft->hWaitEvent ); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetCaps - return protocol capabilities bits - -DWORD_PTR __cdecl CJabberProto::GetCaps( int type, HANDLE hContact ) -{ - switch( type ) { - case PFLAGNUM_1: - return PF1_IM | PF1_AUTHREQ | PF1_CHAT | PF1_SERVERCLIST | PF1_MODEMSG | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_FILE | PF1_CONTACT; - case PFLAGNUM_2: - return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT; - case PFLAGNUM_3: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT; - case PFLAGNUM_4: - return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_IMSENDUTF | PF4_FORCEADDED; - case PFLAG_UNIQUEIDTEXT: - return ( DWORD_PTR ) JTranslate( "JID" ); - case PFLAG_UNIQUEIDSETTING: - return ( DWORD_PTR ) "jid"; - case PFLAG_MAXCONTACTSPERPACKET: - { - DBVARIANT dbv; - if(JGetStringT( hContact, "jid", &dbv )) - return 0; - TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); - JFreeVariant( &dbv ); - JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); - return (( ~jcb & JABBER_CAPS_ROSTER_EXCHANGE ) ? 0 : 50); - } - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetIcon - loads an icon for the contact list - -HICON __cdecl CJabberProto::GetIcon( int iconIndex ) -{ - if (LOWORD(iconIndex) == PLI_PROTOCOL) - { - if (iconIndex & PLIF_ICOLIBHANDLE) - return (HICON)GetIconHandle(IDI_JABBER); - - bool big = (iconIndex & PLIF_SMALL) == 0; - HICON hIcon = LoadIconEx("main", big); - - if (iconIndex & PLIF_ICOLIB) - return hIcon; - - HICON hIcon2 = CopyIcon(hIcon); - g_ReleaseIcon(hIcon); - return hIcon2; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetInfo - retrieves a contact info - -int __cdecl CJabberProto::GetInfo( HANDLE hContact, int /*infoType*/ ) -{ - if ( !m_bJabberOnline ) - return 1; - - int result = 1; - DBVARIANT dbv; - if ( JGetByte( hContact, "ChatRoom" , 0)) - return 1; - - if ( !JGetStringT( hContact, "jid", &dbv )) { - if ( m_ThreadInfo ) { - TCHAR jid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, jid, SIZEOF( jid )); - - m_ThreadInfo->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultEntityTime, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_HCONTACT )) - << XCHILDNS( _T("time"), _T(JABBER_FEAT_ENTITY_TIME))); - - // XEP-0012, last logoff time - XmlNodeIq iq2( m_iqManager.AddHandler( &CJabberProto::OnIqResultLastActivity, JABBER_IQ_TYPE_GET, dbv.ptszVal, JABBER_IQ_PARSE_FROM )); - iq2 << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)); - m_ThreadInfo->send( iq2 ); - - JABBER_LIST_ITEM *item = NULL; - - if (( item = ListGetItemPtr( LIST_VCARD_TEMP, dbv.ptszVal )) == NULL) - item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); - - if ( !item ) { - TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; - _tcsncpy( szBareJid, dbv.ptszVal, SIZEOF( szBareJid )); - TCHAR* pDelimiter = _tcschr( szBareJid, _T('/')); - if ( pDelimiter ) { - *pDelimiter = 0; - pDelimiter++; - if ( !*pDelimiter ) - pDelimiter = NULL; - } - JABBER_LIST_ITEM *tmpItem = NULL; - if ( pDelimiter && ( tmpItem = ListGetItemPtr( LIST_CHATROOM, szBareJid ))) { - JABBER_RESOURCE_STATUS *him = NULL; - for ( int i=0; i < tmpItem->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& p = tmpItem->resource[i]; - if ( !lstrcmp( p.resourceName, pDelimiter )) him = &p; - } - if ( him ) { - item = ListAdd( LIST_VCARD_TEMP, dbv.ptszVal ); - ListAddResource( LIST_VCARD_TEMP, dbv.ptszVal, him->status, him->statusMessage, him->priority ); - } - } - else - item = ListAdd( LIST_VCARD_TEMP, dbv.ptszVal ); - } - - if ( item ) { - if ( item->resource ) { - for ( int i = 0; i < item->resourceCount; i++ ) { - TCHAR szp1[ JABBER_MAX_JID_LEN ]; - JabberStripJid( dbv.ptszVal, szp1, SIZEOF( szp1 )); - mir_sntprintf( jid, 256, _T("%s/%s"), szp1, item->resource[i].resourceName ); - - XmlNodeIq iq3( m_iqManager.AddHandler( &CJabberProto::OnIqResultLastActivity, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM )); - iq3 << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)); - m_ThreadInfo->send( iq3 ); - - if ( !item->resource[i].dwVersionRequestTime ) { - XmlNodeIq iq4( m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE )); - iq4 << XQUERY( _T(JABBER_FEAT_VERSION)); - m_ThreadInfo->send( iq4 ); - } - - if ( !item->resource[i].pSoftwareInfo ) { - XmlNodeIq iq5( m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfoSI, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE | JABBER_IQ_PARSE_HCONTACT )); - iq5 << XQUERY( _T(JABBER_FEAT_DISCO_INFO )); - m_ThreadInfo->send( iq5 ); - } - } - } - else if ( !item->itemResource.dwVersionRequestTime ) { - XmlNodeIq iq4( m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, item->jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE )); - iq4 << XQUERY( _T(JABBER_FEAT_VERSION)); - m_ThreadInfo->send( iq4 ); - } } } - - SendGetVcard( dbv.ptszVal ); - JFreeVariant( &dbv ); - result = 0; - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchBasic - searches the contact by JID - -struct JABBER_SEARCH_BASIC -{ int hSearch; - TCHAR jid[128]; -}; - -void __cdecl CJabberProto::BasicSearchThread( JABBER_SEARCH_BASIC *jsb ) -{ - Sleep( 100 ); - - JABBER_SEARCH_RESULT jsr = { 0 }; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - jsr.hdr.flags = PSR_TCHAR; - jsr.hdr.nick = jsb->jid; - jsr.hdr.firstName = _T(""); - jsr.hdr.lastName = _T(""); - jsr.hdr.id = jsb->jid; - - _tcsncpy( jsr.jid, jsb->jid, SIZEOF( jsr.jid )); - - jsr.jid[SIZEOF( jsr.jid )-1] = '\0'; - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) jsb->hSearch, ( LPARAM )&jsr ); - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) jsb->hSearch, 0 ); - mir_free( jsb ); -} - -HANDLE __cdecl CJabberProto::SearchBasic( const TCHAR* szJid ) -{ - Log( "JabberBasicSearch called with lParam = '%s'", szJid ); - - JABBER_SEARCH_BASIC *jsb; - if ( !m_bJabberOnline || ( jsb=( JABBER_SEARCH_BASIC * ) mir_alloc( sizeof( JABBER_SEARCH_BASIC )))==NULL ) - return 0; - - if ( _tcschr( szJid, '@' ) == NULL ) { - TCHAR *szServer = mir_a2t( m_ThreadInfo->server ); - const TCHAR* p = _tcsstr( szJid, szServer ); - if ( !p ) - { - bool numericjid = true; - for (const TCHAR * i = szJid; *i && numericjid; ++i) - numericjid = (*i >= '0') && (*i <= '9'); - - mir_free( szServer ); - szServer = JGetStringT( NULL, "LoginServer" ); - if ( !szServer ) - { - szServer = mir_tstrdup( _T( "jabber.org" )); - } else if (numericjid && !_tcsicmp(szServer, _T("S.ms"))) - { - mir_free(szServer); - szServer = mir_tstrdup(_T("sms")); - } - mir_sntprintf( jsb->jid, SIZEOF(jsb->jid), _T("%s@%s"), szJid, szServer ); - } - else _tcsncpy( jsb->jid, szJid, SIZEOF(jsb->jid)); - mir_free( szServer ); - } - else _tcsncpy( jsb->jid, szJid, SIZEOF(jsb->jid)); - - Log( "Adding '%s' without validation", jsb->jid ); - jsb->hSearch = SerialNext(); - JForkThread(( JThreadFunc )&CJabberProto::BasicSearchThread, jsb ); - return ( HANDLE )jsb->hSearch; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchByEmail - searches the contact by its e-mail - -HANDLE __cdecl CJabberProto::SearchByEmail( const TCHAR* email ) -{ - if ( !m_bJabberOnline ) return 0; - if ( email == NULL ) return 0; - - char szServerName[100]; - if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) - strcpy( szServerName, "users.jabber.org" ); - - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultSetSearch ); - m_ThreadInfo->send( XmlNodeIq( _T("set"), iqId, _A2T(szServerName)) << XQUERY( _T("jabber:iq:search")) - << XCHILD( _T("email"), email)); - return ( HANDLE )iqId; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSearchByName - searches the contact by its first or last name, or by a nickname - -HANDLE __cdecl CJabberProto::SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName ) -{ - if ( !m_bJabberOnline ) - return NULL; - - BOOL bIsExtFormat = m_options.ExtendedSearch; - - char szServerName[100]; - if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) - strcpy( szServerName, "users.jabber.org" ); - - int iqId = SerialNext(); - XmlNodeIq iq( _T("set"), iqId, _A2T(szServerName)); - HXML query = iq << XQUERY( _T("jabber:iq:search")); - - if ( bIsExtFormat ) { - IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultExtSearch ); - - if ( m_tszSelectedLang ) - iq << XATTR( _T("xml:lang"), m_tszSelectedLang ); - - HXML x = query << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")); - if ( nick[0] != '\0' ) - x << XCHILD( _T("field")) << XATTR( _T("var"), _T("user")) << XATTR( _T("value"), nick); - - if ( firstName[0] != '\0' ) - x << XCHILD( _T("field")) << XATTR( _T("var"), _T("fn")) << XATTR( _T("value"), firstName); - - if ( lastName[0] != '\0' ) - x << XCHILD( _T("field")) << XATTR( _T("var"), _T("given")) << XATTR( _T("value"), lastName); - } - else { - IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultSetSearch ); - if ( nick[0] != '\0' ) - query << XCHILD( _T("nick"), nick); - - if ( firstName[0] != '\0' ) - query << XCHILD( _T("first"), firstName); - - if ( lastName[0] != '\0' ) - query << XCHILD( _T("last"), lastName); - } - - m_ThreadInfo->send( iq ); - return ( HANDLE )iqId; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvContacts - -int __cdecl CJabberProto::RecvContacts( HANDLE /*hContact*/, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvFile - -int __cdecl CJabberProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) -{ - return Proto_RecvFile(hContact, evt); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvMsg - -int __cdecl CJabberProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* evt ) -{ - INT_PTR nDbEvent = Proto_RecvMessage(hContact, evt); - - EnterCriticalSection( &m_csLastResourceMap ); - if (IsLastResourceExists( (void *)evt->lParam)) { - m_ulpResourceToDbEventMap[ m_dwResourceMapPointer++ ] = nDbEvent; - m_ulpResourceToDbEventMap[ m_dwResourceMapPointer++ ] = evt->lParam; - if ( m_dwResourceMapPointer >= SIZEOF( m_ulpResourceToDbEventMap )) - m_dwResourceMapPointer = 0; - } - LeaveCriticalSection( &m_csLastResourceMap ); - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvUrl - -int __cdecl CJabberProto::RecvUrl( HANDLE /*hContact*/, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendContacts - -int __cdecl CJabberProto::SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ) -{ - DBVARIANT dbv; - if ( !m_bJabberOnline || JGetStringT( hContact, "jid", &dbv )) { -// JSendBroadcast( hContact, ACKTYPE_CONTACTS, ACKRESULT_FAILED, ( HANDLE ) 1, 0 ); - return 0; - } - - TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); - JFreeVariant( &dbv ); - - JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); - if ( ~jcb & JABBER_CAPS_ROSTER_EXCHANGE ) - return 0; - - XmlNode m( _T("message")); -// m << XCHILD( _T("body"), msg ); - HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_ROSTER_EXCHANGE)); - - for ( int i = 0; i < nContacts; ++i ) { - if (!JGetStringT( hContactsList[i], "jid", &dbv )) { - x << XCHILD( _T("item")) << XATTR( _T("action"), _T("add")) << - XATTR( _T("jid"), dbv.ptszVal); - JFreeVariant( &dbv ); - } - } - - int id = SerialNext(); - m << XATTR( _T("to"), szClientJid ) << XATTRID( id ); - - m_ThreadInfo->send( m ); -// mir_free( msg ); - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendFile - sends a file - -HANDLE __cdecl CJabberProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) -{ - if ( !m_bJabberOnline ) return 0; - - if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE ) - return 0; - - DBVARIANT dbv; - if ( JGetStringT( hContact, "jid", &dbv )) - return 0; - - int i, j; - struct _stati64 statbuf; - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); - if ( item == NULL ) { - JFreeVariant( &dbv ); - return 0; - } - - // Check if another file transfer session request is pending ( waiting for disco result ) - if ( item->ft != NULL ) { - JFreeVariant( &dbv ); - return 0; - } - - JabberCapsBits jcb = GetResourceCapabilites( item->jid, TRUE ); - if ( jcb == JABBER_RESOURCE_CAPS_IN_PROGRESS ) { - Sleep(600); - jcb = GetResourceCapabilites( item->jid, TRUE ); - } - - // fix for very smart clients, like gajim - if ( !m_options.BsDirect && !m_options.BsProxyManual ) { - // disable bytestreams - jcb &= ~JABBER_CAPS_BYTESTREAMS; - } - - // if only JABBER_CAPS_SI_FT feature set (without BS or IBB), disable JABBER_CAPS_SI_FT - if (( jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_BYTESTREAMS)) == JABBER_CAPS_SI_FT) - jcb &= ~JABBER_CAPS_SI_FT; - - if ( - // can't get caps - ( jcb & JABBER_RESOURCE_CAPS_ERROR ) - // caps not already received - || ( jcb == JABBER_RESOURCE_CAPS_NONE ) - // XEP-0096 and OOB not supported? - || !(jcb & ( JABBER_CAPS_SI_FT | JABBER_CAPS_OOB )) - ) { - JFreeVariant( &dbv ); - MsgPopup( hContact, TranslateT("No compatible file transfer machanism exist"), item->jid ); - return 0; - } - - filetransfer* ft = new filetransfer(this); - ft->std.hContact = hContact; - while( ppszFiles[ ft->std.totalFiles ] != NULL ) - ft->std.totalFiles++; - - ft->std.ptszFiles = ( TCHAR** ) mir_calloc( sizeof( TCHAR* )* ft->std.totalFiles ); - ft->fileSize = ( unsigned __int64* ) mir_calloc( sizeof( unsigned __int64 ) * ft->std.totalFiles ); - for ( i=j=0; i < ft->std.totalFiles; i++ ) { - if ( _tstati64( ppszFiles[i], &statbuf )) - Log( "'%s' is an invalid filename", ppszFiles[i] ); - else { - ft->std.ptszFiles[j] = mir_tstrdup( ppszFiles[i] ); - ft->fileSize[j] = statbuf.st_size; - j++; - ft->std.totalBytes += statbuf.st_size; - } } - if ( j == 0 ) { - delete ft; - JFreeVariant( &dbv ); - return NULL; - } - - ft->std.tszCurrentFile = mir_tstrdup( ppszFiles[0] ); - ft->szDescription = mir_tstrdup( szDescription ); - ft->jid = mir_tstrdup( dbv.ptszVal ); - JFreeVariant( &dbv ); - - if ( jcb & JABBER_CAPS_SI_FT ) - FtInitiate( item->jid, ft ); - else if ( jcb & JABBER_CAPS_OOB ) - JForkThread(( JThreadFunc )&CJabberProto::FileServerThread, ft ); - - return ft; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSendMessage - sends a message - -struct TFakeAckParams -{ - inline TFakeAckParams( HANDLE p1, const char* p2 ) - : hContact( p1 ), msg( p2 ) {} - - HANDLE hContact; - const char* msg; -}; - -void __cdecl CJabberProto::SendMessageAckThread( void* param ) -{ - TFakeAckParams *par = ( TFakeAckParams* )param; - Sleep( 100 ); - Log( "Broadcast ACK" ); - JSendBroadcast( par->hContact, ACKTYPE_MESSAGE, - par->msg ? ACKRESULT_FAILED : ACKRESULT_SUCCESS, - ( HANDLE ) 1, ( LPARAM ) par->msg ); - Log( "Returning from thread" ); - delete par; -} - -static char PGP_PROLOG[] = "-----BEGIN PGP MESSAGE-----\r\n\r\n"; -static char PGP_EPILOG[] = "\r\n-----END PGP MESSAGE-----\r\n"; - -int __cdecl CJabberProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) -{ - int id; - - DBVARIANT dbv; - if ( !m_bJabberOnline || JGetStringT( hContact, "jid", &dbv )) { - TFakeAckParams *param = new TFakeAckParams( hContact, Translate( "Protocol is offline or no jid" )); - JForkThread( &CJabberProto::SendMessageAckThread, param ); - return 1; - } - - TCHAR *msg; - int isEncrypted; - - if ( !strncmp( pszSrc, PGP_PROLOG, strlen( PGP_PROLOG ))) { - const char* szEnd = strstr( pszSrc, PGP_EPILOG ); - char* tempstring = ( char* )alloca( strlen( pszSrc ) + 1 ); - size_t nStrippedLength = strlen(pszSrc) - strlen(PGP_PROLOG) - (szEnd ? strlen(szEnd) : 0); - strncpy( tempstring, pszSrc + strlen(PGP_PROLOG), nStrippedLength ); - tempstring[ nStrippedLength ] = 0; - pszSrc = tempstring; - isEncrypted = 1; - flags &= ~PREF_UNICODE; - } - else isEncrypted = 0; - - if ( flags & PREF_UTF ) { - - mir_utf8decode( NEWSTR_ALLOCA( pszSrc ), &msg ); - - } - else if ( flags & PREF_UNICODE ) - msg = mir_u2t(( wchar_t* )&pszSrc[ strlen( pszSrc )+1 ] ); - else - msg = mir_a2t( pszSrc ); - - int nSentMsgId = 0; - - if ( msg != NULL ) { - TCHAR* msgType; - if ( ListExist( LIST_CHATROOM, dbv.ptszVal ) && _tcschr( dbv.ptszVal, '/' )==NULL ) - msgType = _T("groupchat"); - else - msgType = _T("chat"); - - XmlNode m( _T("message" )); xmlAddAttr( m, _T("type"), msgType ); - if ( !isEncrypted ) - m << XCHILD( _T("body"), msg ); - else { - m << XCHILD( _T("body"), _T("[This message is encrypted.]" )); - m << XCHILD( _T("x"), msg) << XATTR(_T("xmlns"), _T("jabber:x:encrypted")); - } - mir_free( msg ); - - TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); - - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( szClientJid ); - if ( r ) - r->bMessageSessionActive = TRUE; - - JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); - - if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) - jcb = JABBER_RESOURCE_CAPS_NONE; - - if ( jcb & JABBER_CAPS_CHATSTATES ) - m << XCHILDNS( _T("active"), _T(JABBER_FEAT_CHATSTATES)); - - if ( - // if message delivery check disabled by entity caps manager - ( jcb & JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY ) || - // if client knows nothing about delivery - !( jcb & ( JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_RECEIPTS )) || - // if message sent to groupchat - !lstrcmp( msgType, _T("groupchat")) || - // if message delivery check disabled in settings - !m_options.MsgAck || !JGetByte( hContact, "MsgAck", TRUE )) { - if ( !lstrcmp( msgType, _T("groupchat"))) - xmlAddAttr( m, _T("to"), dbv.ptszVal ); - else { - id = SerialNext(); - xmlAddAttr( m, _T("to"), szClientJid ); xmlAddAttrID( m, id ); - } - m_ThreadInfo->send( m ); - - JForkThread( &CJabberProto::SendMessageAckThread, new TFakeAckParams( hContact, 0 )); - - nSentMsgId = 1; - } - else { - id = SerialNext(); - xmlAddAttr( m, _T("to"), szClientJid ); xmlAddAttrID( m, id ); - - // message receipts XEP priority - if ( jcb & JABBER_CAPS_MESSAGE_RECEIPTS ) - m << XCHILDNS( _T("request"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)); - else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { - HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); - x << XCHILD( _T("delivered")); x << XCHILD( _T("offline")); - } - else - id = 1; - - m_ThreadInfo->send( m ); - nSentMsgId = id; - } } - - JFreeVariant( &dbv ); - return nSentMsgId; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendUrl - -int __cdecl CJabberProto::SendUrl( HANDLE /*hContact*/, int /*flags*/, const char* /*url*/ ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSetApparentMode - sets the visibility status - -int __cdecl CJabberProto::SetApparentMode( HANDLE hContact, int mode ) -{ - if ( mode != 0 && mode != ID_STATUS_ONLINE && mode != ID_STATUS_OFFLINE ) - return 1; - - int oldMode = JGetWord( hContact, "ApparentMode", 0 ); - if ( mode == oldMode ) - return 1; - - JSetWord( hContact, "ApparentMode", ( WORD )mode ); - if ( !m_bJabberOnline ) - return 0; - - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - TCHAR* jid = dbv.ptszVal; - switch ( mode ) { - case ID_STATUS_ONLINE: - if ( m_iStatus == ID_STATUS_INVISIBLE || oldMode == ID_STATUS_OFFLINE ) - m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), jid )); - break; - case ID_STATUS_OFFLINE: - if ( m_iStatus != ID_STATUS_INVISIBLE || oldMode == ID_STATUS_ONLINE ) - SendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL ); - break; - case 0: - if ( oldMode == ID_STATUS_ONLINE && m_iStatus == ID_STATUS_INVISIBLE ) - SendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL ); - else if ( oldMode == ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_INVISIBLE ) - SendPresenceTo( m_iStatus, jid, NULL ); - break; - } - JFreeVariant( &dbv ); - } - - // TODO: update the zebra list ( jabber:iq:privacy ) - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSetStatus - sets the protocol status - -int __cdecl CJabberProto::SetStatus( int iNewStatus ) -{ - if (m_iDesiredStatus == iNewStatus) - return 0; - - int oldStatus = m_iStatus; - - Log( "PS_SETSTATUS( %d )", iNewStatus ); - m_iDesiredStatus = iNewStatus; - - if ( iNewStatus == ID_STATUS_OFFLINE ) { - if ( m_ThreadInfo ) { - if ( m_bJabberOnline ) { - // Quit all chatrooms (will send quit message) - LISTFOREACH(i, this, LIST_CHATROOM) - if (JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex(i)) - GcQuit(item, 0, NULL); - } - - m_ThreadInfo->send( "</stream:stream>" ); - m_ThreadInfo->shutdown(); - - if ( m_bJabberConnected ) { - m_bJabberConnected = m_bJabberOnline = FALSE; - RebuildInfoFrame(); - } - } - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - } - else if ( !m_bJabberConnected && !m_ThreadInfo && !( m_iStatus >= ID_STATUS_CONNECTING && m_iStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES )) { - m_iStatus = ID_STATUS_CONNECTING; - ThreadData* thread = new ThreadData( this, JABBER_SESSION_NORMAL ); - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - thread->hThread = JForkThreadEx(( JThreadFunc )&CJabberProto::ServerThread, thread ); - - RebuildInfoFrame(); - } - else if ( m_bJabberOnline ) - SetServerStatus( iNewStatus ); - else - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberGetAwayMsg - returns a contact's away message - -void __cdecl CJabberProto::GetAwayMsgThread( void* hContact ) -{ - DBVARIANT dbv; - JABBER_LIST_ITEM *item; - JABBER_RESOURCE_STATUS *r; - int i, msgCount; - size_t len; - - if ( !JGetStringT( hContact, "jid", &dbv )) { - if (( item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) { - JFreeVariant( &dbv ); - if ( item->resourceCount > 0 ) { - Log( "resourceCount > 0" ); - r = item->resource; - len = msgCount = 0; - for ( i=0; i<item->resourceCount; i++ ) - if ( r[i].statusMessage ) { - msgCount++; - len += ( _tcslen( r[i].resourceName ) + _tcslen( r[i].statusMessage ) + 8 ); - } - - TCHAR* str = ( TCHAR* )alloca( sizeof( TCHAR )*( len+1 )); - str[0] = str[len] = '\0'; - for ( i=0; i < item->resourceCount; i++ ) - if ( r[i].statusMessage ) { - if ( str[0] != '\0' ) _tcscat( str, _T("\r\n" )); - if ( msgCount > 1 ) { - _tcscat( str, _T("( ")); - _tcscat( str, r[i].resourceName ); - _tcscat( str, _T(" ): ")); - } - _tcscat( str, r[i].statusMessage ); - } - - JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)str); - return; - } - - if ( item->itemResource.statusMessage != NULL ) { - JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)item->itemResource.statusMessage); - return; - } - } - else JFreeVariant( &dbv ); - } - - JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )0 ); -} - -HANDLE __cdecl CJabberProto::GetAwayMsg( HANDLE hContact ) -{ - Log( "GetAwayMsg called, hContact=%08X", hContact ); - - JForkThread( &CJabberProto::GetAwayMsgThread, hContact ); - return (HANDLE)1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AWAYMSG - -int __cdecl CJabberProto::RecvAwayMsg( HANDLE /*hContact*/, int /*statusMode*/, PROTORECVEVENT* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AWAYMSG - -int __cdecl CJabberProto::SendAwayMsg( HANDLE /*hContact*/, HANDLE /*hProcess*/, const char* ) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSetAwayMsg - sets the away status message - -int __cdecl CJabberProto::SetAwayMsg( int status, const TCHAR* msg ) -{ - Log( "SetAwayMsg called, wParam=%d lParam=" TCHAR_STR_PARAM, status, msg ); - - EnterCriticalSection( &m_csModeMsgMutex ); - - TCHAR **szMsg; - - switch ( status ) { - case ID_STATUS_ONLINE: - szMsg = &m_modeMsgs.szOnline; - break; - case ID_STATUS_AWAY: - case ID_STATUS_ONTHEPHONE: - case ID_STATUS_OUTTOLUNCH: - szMsg = &m_modeMsgs.szAway; - status = ID_STATUS_AWAY; - break; - case ID_STATUS_NA: - szMsg = &m_modeMsgs.szNa; - break; - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - szMsg = &m_modeMsgs.szDnd; - status = ID_STATUS_DND; - break; - case ID_STATUS_FREECHAT: - szMsg = &m_modeMsgs.szFreechat; - break; - default: - LeaveCriticalSection( &m_csModeMsgMutex ); - return 1; - } - - TCHAR* newModeMsg = mir_tstrdup( msg ); - - if (( *szMsg == NULL && newModeMsg == NULL ) || - ( *szMsg != NULL && newModeMsg != NULL && !lstrcmp( *szMsg, newModeMsg ))) { - // Message is the same, no update needed - mir_free( newModeMsg ); - LeaveCriticalSection( &m_csModeMsgMutex ); - } - else { - // Update with the new mode message - if ( *szMsg != NULL ) - mir_free( *szMsg ); - *szMsg = newModeMsg; - // Send a presence update if needed - LeaveCriticalSection( &m_csModeMsgMutex ); - if ( status == m_iStatus ) { - SendPresence( m_iStatus, true ); - } } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberUserIsTyping - sends a UTN notification - -int __cdecl CJabberProto::UserIsTyping( HANDLE hContact, int type ) -{ - if ( !m_bJabberOnline ) return 0; - - DBVARIANT dbv; - if ( JGetStringT( hContact, "jid", &dbv )) return 0; - - JABBER_LIST_ITEM *item; - if (( item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) { - TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; - GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); - - JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); - - if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) - jcb = JABBER_RESOURCE_CAPS_NONE; - - XmlNode m( _T("message")); xmlAddAttr( m, _T("to"), szClientJid ); - - if ( jcb & JABBER_CAPS_CHATSTATES ) { - m << XATTR( _T("type"), _T("chat")) << XATTRID( SerialNext()); - switch ( type ) { - case PROTOTYPE_SELFTYPING_OFF: - m << XCHILDNS( _T("paused"), _T(JABBER_FEAT_CHATSTATES)); - m_ThreadInfo->send( m ); - break; - case PROTOTYPE_SELFTYPING_ON: - m << XCHILDNS( _T("composing"), _T(JABBER_FEAT_CHATSTATES)); - m_ThreadInfo->send( m ); - break; - } - } - else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { - HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); - if ( item->messageEventIdStr != NULL ) - x << XCHILD( _T("id"), item->messageEventIdStr ); - - switch ( type ) { - case PROTOTYPE_SELFTYPING_OFF: - m_ThreadInfo->send( m ); - break; - case PROTOTYPE_SELFTYPING_ON: - x << XCHILD( _T("composing")); - m_ThreadInfo->send( m ); - break; - } } } - - JFreeVariant( &dbv ); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Notify dialogs - -void CJabberProto::WindowSubscribe(HWND hwnd) -{ - WindowList_Add(m_windowList, hwnd, NULL); -} - -void CJabberProto::WindowUnsubscribe(HWND hwnd) -{ - WindowList_Remove(m_windowList, hwnd); -} - -void CJabberProto::WindowNotify(UINT msg, bool async) -{ - if (async) - WindowList_BroadcastAsync(m_windowList, msg, 0, 0); - else - WindowList_Broadcast(m_windowList, msg, 0, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// InfoFrame events - -void CJabberProto::InfoFrame_OnSetup(CJabberInfoFrame_Event*) -{ - OnMenuOptions(0,0); -} - -void CJabberProto::InfoFrame_OnTransport(CJabberInfoFrame_Event *evt) -{ - if (evt->m_event == CJabberInfoFrame_Event::CLICK) - { - HANDLE hContact = (HANDLE)evt->m_pUserData; - POINT pt; - - HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); - GetCursorPos(&pt); - int res = TrackPopupMenu(hContactMenu, TPM_RETURNCMD, pt.x, pt.y, 0, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL); - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnEvent - maintain protocol events - -int __cdecl CJabberProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ) -{ - switch( eventType ) { - case EV_PROTO_ONLOAD: return OnModulesLoadedEx( 0, 0 ); - case EV_PROTO_ONEXIT: return OnPreShutdown( 0, 0 ); - case EV_PROTO_ONOPTIONS: return OnOptionsInit( wParam, lParam ); - - case EV_PROTO_ONMENU: - MenuInit(); - break; - - case EV_PROTO_ONRENAME: - if ( m_hMenuRoot ) - { - CLISTMENUITEM clmi = { 0 }; - clmi.cbSize = sizeof(CLISTMENUITEM); - clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - clmi.ptszName = m_tszUserName; - CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuRoot, ( LPARAM )&clmi ); - } - break; - - case EV_PROTO_ONCONTACTDELETED: - return OnContactDeleted(wParam, lParam); - - case EV_PROTO_DBSETTINGSCHANGED: - return OnDbSettingChanged(wParam, lParam); - } - return 1; -} diff --git a/protocols/JabberG/jabber_proto.h b/protocols/JabberG/jabber_proto.h deleted file mode 100644 index eff59bb002..0000000000 --- a/protocols/JabberG/jabber_proto.h +++ /dev/null @@ -1,1008 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_PROTO_H_ -#define _JABBER_PROTO_H_ - -#include "jabber_disco.h" -#include "jabber_rc.h" -#include "jabber_privacy.h" -#include "jabber_search.h" -#include "jabber_iq.h" -#include "jabber_icolib.h" -#include "jabber_xstatus.h" -#include "jabber_notes.h" -#include "jabber_message_manager.h" -#include "jabber_presence_manager.h" -#include "jabber_send_manager.h" - -struct CJabberProto; -typedef void ( __cdecl CJabberProto::*JThreadFunc )( void* ); -typedef int ( __cdecl CJabberProto::*JEventFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CJabberProto::*JServiceFunc )( WPARAM, LPARAM ); -typedef INT_PTR ( __cdecl CJabberProto::*JServiceFuncParam )( WPARAM, LPARAM, LPARAM ); - -enum TJabberGcLogInfoType { INFO_BAN, INFO_STATUS, INFO_CONFIG, INFO_AFFILIATION, INFO_ROLE }; - -// for JabberEnterString -enum { JES_MULTINE, JES_COMBO, JES_RICHEDIT, JES_PASSWORD }; - -typedef UNIQUE_MAP<TCHAR,TCharKeyCmp> U_TCHAR_MAP; - -#define JABBER_DEFAULT_RECENT_COUNT 10 - -struct JABBER_IQ_FUNC -{ - int iqId; // id to match IQ get/set with IQ result - JABBER_IQ_PROCID procId; // must be unique in the list, except for IQ_PROC_NONE which can have multiple entries - JABBER_IQ_PFUNC func; // callback function - time_t requestTime; // time the request was sent, used to remove relinquent entries -}; - -struct JABBER_GROUPCHAT_INVITE_INFO -{ - TCHAR* roomJid; - TCHAR* from; - TCHAR* reason; - TCHAR* password; -}; - -struct ROSTERREQUSERDATA -{ - HWND hwndDlg; - BYTE bRRAction; - BOOL bReadyToDownload; - BOOL bReadyToUpload; -}; - -struct TFilterInfo -{ - enum Type { T_JID, T_XMLNS, T_ANY, T_OFF }; - - volatile BOOL msg, presence, iq; - volatile Type type; - - CRITICAL_SECTION csPatternLock; - TCHAR pattern[256]; -}; - -struct CJabberSysInterface: public IJabberSysInterface -{ - int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberSysInterface. - int STDMETHODCALLTYPE CompareJIDs(LPCTSTR jid1, LPCTSTR jid2); // Strips resource names from given JIDs and returns result of comparison for these JIDs. - HANDLE STDMETHODCALLTYPE ContactFromJID(LPCTSTR jid); // Returns contact handle for given JID. - LPTSTR STDMETHODCALLTYPE ContactToJID(HANDLE hContact); // Returns JID of hContact. You must free the result using mir_free(). - LPTSTR STDMETHODCALLTYPE GetBestResourceName(LPCTSTR jid); // Returns best resource name for given JID. You must free the result using mir_free(). - LPTSTR STDMETHODCALLTYPE GetResourceList(LPCTSTR jid); // Returns all resource names for a given JID in format "resource1\0resource2\0resource3\0\0" (all resources are separated by \0 character and the whole string is terminated with two \0 characters). You must free the string using mir_free(). - char* STDMETHODCALLTYPE GetModuleName() const; // Returns Jabber module name. - - CJabberProto *m_psProto; -}; - -struct CJabberNetInterface: public IJabberNetInterface -{ - int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberNetInterface. - unsigned int STDMETHODCALLTYPE SerialNext(); // Returns id that can be used for next message sent through SendXmlNode(). - int STDMETHODCALLTYPE SendXmlNode(HXML node); // Sends XML node. - - // In all incoming stanza handlers, return TRUE to continue processing of the stanza (Jabber plugin will then call other handlers). Return FALSE only when you're sure noone else will need to process this stanza. - // Registers incoming <presence/> handler. Returns handler handle on success or NULL on error. - HJHANDLER STDMETHODCALLTYPE AddPresenceHandler(JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority); - // Registers incoming <message/> handler for messages of types specified by iMsgTypes. iMsgTypes is a combination of JABBER_MESSAGE_TYPE_* flags. Returns handler handle on success or NULL on error. - HJHANDLER STDMETHODCALLTYPE AddMessageHandler(JABBER_HANDLER_FUNC Func, int iMsgTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority); - // Registers incoming <iq/> handler. iIqTypes is a combination of JABBER_IQ_TYPE_* flags. Returns handler handle on success or NULL on error. - HJHANDLER STDMETHODCALLTYPE AddIqHandler(JABBER_HANDLER_FUNC Func, int iIqTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority); - // Registers temporary handler for incoming <iq/> stanza of type iIqType with id iIqId. iIqTypes is a combination of JABBER_IQ_TYPE_* flags. Returns handler handle on success or NULL on error. You must free pUserData in the handler by yourself. - HJHANDLER STDMETHODCALLTYPE AddTemporaryIqHandler(JABBER_HANDLER_FUNC Func, int iIqTypes, int iIqId, void *pUserData, DWORD dwTimeout, int iPriority); - - // Registers handler for outgoing nodes. The handler may modify the node if it's necessary. Return TRUE in the handler to continue, or FALSE to abort sending. - HJHANDLER STDMETHODCALLTYPE AddSendHandler(JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority); - - // Unregisters handler by its handle. - int STDMETHODCALLTYPE RemoveHandler(HJHANDLER hHandler); - - int STDMETHODCALLTYPE RegisterFeature(LPCTSTR szFeature, LPCTSTR szDescription); // Registers feature so that it's displayed with proper description in other users' details. Call this function in your ME_SYSTEM_MODULESLOADED handler. Returns TRUE on success or FALSE on error. - int STDMETHODCALLTYPE AddFeatures(LPCTSTR szFeatures); // Adds features to the list of features returned by the client. - int STDMETHODCALLTYPE RemoveFeatures(LPCTSTR szFeatures); // Removes features from the list of features returned by the client. - LPTSTR STDMETHODCALLTYPE GetResourceFeatures(LPCTSTR jid); // Returns all features supported by JID in format "feature1\0feature2\0...\0featureN\0\0". You must free returned string using mir_free(). - - CJabberProto *m_psProto; - -private: - JabberFeatCapPairDynamic *FindFeature(LPCTSTR szFeature); -}; - -struct CJabberInterface: public IJabberInterface -{ - DWORD STDMETHODCALLTYPE GetFlags() const; // Set of JIF_* flags. - int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberInterface. - DWORD STDMETHODCALLTYPE GetJabberVersion() const; // Returns Jabber plugin version. - - IJabberSysInterface* STDMETHODCALLTYPE Sys() const; // Jabber system utilities. - IJabberNetInterface* STDMETHODCALLTYPE Net() const; // Jabber network interface. - - CJabberProto *m_psProto; -}; - -struct CJabberProto : public PROTO_INTERFACE, public MZeroedObject -{ - typedef PROTO_INTERFACE CSuper; - - CJabberProto( const char*, const TCHAR* ); - ~CJabberProto(); - - //==================================================================================== - // PROTO_INTERFACE - //==================================================================================== - - virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); - virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); - - virtual int __cdecl Authorize( HANDLE hDbEvent ); - virtual int __cdecl AuthDeny( HANDLE hDbEvent, const TCHAR* szReason ); - virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); - - virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); - - virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); - virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); - virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); - virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); - - virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); - virtual HICON __cdecl GetIcon( int iconIndex ); - virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); - - virtual HANDLE __cdecl SearchBasic( const TCHAR* id ); - virtual HANDLE __cdecl SearchByEmail( const TCHAR* email ); - virtual HANDLE __cdecl SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName ); - virtual HWND __cdecl SearchAdvanced( HWND owner ); - virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); - - virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); - virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); - virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); - - virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); - virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); - virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); - virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); - - virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); - virtual int __cdecl SetStatus( int iNewStatus ); - - virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); - virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); - virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); - virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); - - virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); - - virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); - - //====| Services |==================================================================== - INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl GetMyAwayMsg(WPARAM wParam, LPARAM lParam); - - //====| Events |====================================================================== - void __cdecl OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - int __cdecl OnContactDeleted( WPARAM, LPARAM ); - int __cdecl OnDbSettingChanged( WPARAM, LPARAM ); - int __cdecl OnIdleChanged( WPARAM, LPARAM ); - int __cdecl OnModernOptInit( WPARAM, LPARAM ); - int __cdecl OnModulesLoadedEx( WPARAM, LPARAM ); - int __cdecl OnOptionsInit( WPARAM, LPARAM ); - int __cdecl OnPreShutdown( WPARAM, LPARAM ); - int __cdecl OnPrebuildContactMenu( WPARAM, LPARAM ); - int __cdecl OnMsgUserTyping( WPARAM, LPARAM ); - int __cdecl OnProcessSrmmIconClick( WPARAM, LPARAM ); - int __cdecl OnProcessSrmmEvent( WPARAM, LPARAM ); - int __cdecl OnReloadIcons( WPARAM, LPARAM ); - void __cdecl OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - void __cdecl OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ); - int __cdecl OnUserInfoInit( WPARAM, LPARAM ); - - int __cdecl JabberGcEventHook( WPARAM, LPARAM ); - int __cdecl JabberGcMenuHook( WPARAM, LPARAM ); - int __cdecl JabberGcInit( WPARAM, LPARAM ); - - int __cdecl CListMW_ExtraIconsApply( WPARAM, LPARAM ); - - // Google Shared Status - BOOL m_bGoogleSharedStatus; - BOOL m_bGoogleSharedStatusLock; - void OnIqResultGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo); - BOOL OnIqSetGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo); - void SendIqGoogleSharedStatus(int status, const TCHAR *msg); - - //====| Data |======================================================================== - - ThreadData* m_ThreadInfo; - CJabberOptions m_options; - - HANDLE m_hNetlibUser; - PVOID m_sslCtx; - - HANDLE m_hThreadHandle; - - TCHAR* m_szJabberJID; - char* m_szStreamId; - BOOL m_bJabberConnected; // TCP connection to jabber server established - BOOL m_bJabberOnline; // XMPP connection initialized and we can send XMPP packets - int m_nJabberSearchID; - time_t m_tmJabberLoggedInTime; - time_t m_tmJabberIdleStartTime; - UINT m_nJabberCodePage; - TCHAR* m_tszSelectedLang; - - CMString m_szCurrentEntityCapsHash; - - CRITICAL_SECTION m_csModeMsgMutex; - JABBER_MODEMSGS m_modeMsgs; - BOOL m_bModeMsgStatusChangePending; - - HANDLE m_hHookExtraIconsRebuild; - HANDLE m_hHookExtraIconsApply; - - BOOL m_bChangeStatusMessageOnly; - BOOL m_bSendKeepAlive; - BOOL m_bPepSupported; - BOOL m_bGoogleTalk; - - HWND m_hwndAgentRegInput; - HWND m_hwndRegProgress; - HWND m_hwndJabberChangePassword; - HWND m_hwndMucVoiceList; - HWND m_hwndMucMemberList; - HWND m_hwndMucModeratorList; - HWND m_hwndMucBanList; - HWND m_hwndMucAdminList; - HWND m_hwndMucOwnerList; - HWND m_hwndJabberAddBookmark; - HWND m_hwndPrivacyRule; - - CJabberDlgBase *m_pDlgPrivacyLists; - CJabberDlgBase *m_pDlgBookmarks; - CJabberDlgBase *m_pDlgServiceDiscovery; - CJabberDlgBase *m_pDlgJabberJoinGroupchat; - CJabberDlgBase *m_pDlgNotes; - - HANDLE m_windowList; - - // Service and event handles - HANDLE m_hEventNudge; - HANDLE m_hEventXStatusIconChanged; - HANDLE m_hEventXStatusChanged; - - // Transports list - LIST<TCHAR> m_lstTransports; - - CJabberIqManager m_iqManager; - CJabberMessageManager m_messageManager; - CJabberPresenceManager m_presenceManager; // manager of <presence> stanzas and their handlers - CJabberSendManager m_sendManager; // manager of outgoing stanza handlers - CJabberAdhocManager m_adhocManager; - CJabberClientCapsManager m_clientCapsManager; - CPrivacyListManager m_privacyListManager; - CJabberSDManager m_SDManager; - - //HWND m_hwndConsole; - CJabberDlgBase *m_pDlgConsole; - HANDLE m_hThreadConsole; - UINT m_dwConsoleThreadId; - - // proto frame - CJabberInfoFrame *m_pInfoFrame; - - LIST<JABBER_LIST_ITEM> m_lstRoster; - CRITICAL_SECTION m_csLists; - BOOL m_bListInitialised; - - LIST<JabberFeatCapPairDynamic> m_lstJabberFeatCapPairsDynamic; // list of features registered through IJabberNetInterface::RegisterFeature() - JabberCapsBits m_uEnabledFeatCapsDynamic; - - CRITICAL_SECTION m_csIqList; - JABBER_IQ_FUNC *m_ppIqList; - int m_nIqCount; - int m_nIqAlloced; - - HGENMENU m_hMenuRoot; - HGENMENU m_hMenuChangePassword; - HGENMENU m_hMenuGroupchat; - HGENMENU m_hMenuBookmarks; - HGENMENU m_hMenuNotes; - - HGENMENU m_hMenuPrivacyLists; - HGENMENU m_hMenuRosterControl; - HGENMENU m_hMenuServiceDiscovery; - HGENMENU m_hMenuSDMyTransports; - HGENMENU m_hMenuSDTransports; - HGENMENU m_hMenuSDConferences; - - HWND m_hwndCommandWindow; - - int m_nIqIdRegGetReg; - int m_nIqIdRegSetReg; - - int m_nSDBrowseMode; - DWORD m_dwSDLastRefresh; - DWORD m_dwSDLastAutoDisco; - - HANDLE m_hChooseMenuItem; - int m_privacyMenuServiceAllocated; - - TFilterInfo m_filterInfo; - - CNoteList m_notes; - - CRITICAL_SECTION m_csLastResourceMap; - void *m_pLastResourceList; - ULONG_PTR m_ulpResourceToDbEventMap[256]; // last 128 messages (128+128) - DWORD m_dwResourceMapPointer; - - CJabberInterface m_JabberApi; - CJabberSysInterface m_JabberSysApi; - CJabberNetInterface m_JabberNetApi; - - /******************************************************************* - * Function declarations - *******************************************************************/ - - void JabberUpdateDialogs( BOOL bEnable ); - - void CleanLastResourceMap(); - BOOL IsLastResourceExists(void *pResource); - void* AddToLastResourceMap( LPCTSTR szFullJid ); - TCHAR* FindLastResourceByDbEvent( HANDLE hDbEvent ); - - //---- jabber_adhoc.cpp -------------------------------------------------------------- - - int __cdecl ContactMenuRunCommands(WPARAM wParam, LPARAM lParam); - - HWND GetWindowFromIq( HXML iqNode ); - BOOL HandleAdhocCommandRequest( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL IsRcRequestAllowedByACL( CJabberIqInfo* pInfo ); - - int AdhocSetStatusHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - int AdhocOptionsHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - int AdhocForwardHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - int AdhocLockWSHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - int AdhocQuitMirandaHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - int AdhocLeaveGroupchatsHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - - void OnIqResult_ListOfCommands( HXML iqNode ); - void OnIqResult_CommandExecution( HXML iqNode ); - int AdHoc_RequestListOfCommands( TCHAR * szResponder, HWND hwndDlg ); - int AdHoc_ExecuteCommand( HWND hwndDlg, TCHAR * jid, struct JabberAdHocData* dat ); - int AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData * dat, TCHAR* action); - int AdHoc_AddCommandRadio(HWND hFrame, TCHAR * labelStr, int id, int ypos, int value); - int AdHoc_OnJAHMCommandListResult( HWND hwndDlg, HXML iqNode, JabberAdHocData* dat ); - int AdHoc_OnJAHMProcessResult( HWND hwndDlg, HXML workNode, JabberAdHocData* dat ); - - void ContactMenuAdhocCommands( struct CJabberAdhocStartupParams* param ); - - //---- jabber_bookmarks.c ------------------------------------------------------------ - - INT_PTR __cdecl OnMenuHandleBookmarks( WPARAM wParam, LPARAM lParam ); - - int AddEditBookmark( JABBER_LIST_ITEM* item ); - - //---- jabber_notes.c ----------------------------------------------------------------- - - void CJabberProto::ProcessIncomingNote(CNoteItem *pNote, bool ok); - void CJabberProto::ProcessOutgoingNote(CNoteItem *pNote, bool ok); - - bool CJabberProto::OnIncomingNote(const TCHAR *szFrom, HXML hXml); - - INT_PTR __cdecl CJabberProto::OnMenuSendNote(WPARAM, LPARAM); - INT_PTR __cdecl CJabberProto::OnMenuHandleNotes(WPARAM, LPARAM); - INT_PTR __cdecl CJabberProto::OnIncomingNoteEvent(WPARAM, LPARAM); - - //---- jabber_byte.c ----------------------------------------------------------------- - - void __cdecl ByteSendThread( JABBER_BYTE_TRANSFER *jbt ); - void __cdecl ByteReceiveThread( JABBER_BYTE_TRANSFER *jbt ); - - void IqResultProxyDiscovery( HXML iqNode, CJabberIqInfo* pInfo ); - void ByteInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ); - void ByteSendViaProxy( JABBER_BYTE_TRANSFER *jbt ); - int ByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); - void IqResultStreamActivate( HXML iqNode ); - int ByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); - int ByteSendProxyParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); - - //---- jabber_caps.cpp --------------------------------------------------------------- - - JabberCapsBits GetTotalJidCapabilites( const TCHAR *jid ); - JabberCapsBits GetResourceCapabilites( const TCHAR *jid, BOOL appendBestResource ); - - //---- jabber_captcha.cpp ------------------------------------------------------------ - - void GetCaptchaImage ( HXML node, char *ImageBuf, const TCHAR *PicType, TCHAR*& CaptchaPath); - void sendCaptchaResult(TCHAR* buf, ThreadData* info, LPCTSTR from, LPCTSTR challenge, LPCTSTR fromjid, LPCTSTR sid); - void sendCaptchaError(ThreadData* info, LPCTSTR from, LPCTSTR to, LPCTSTR challenge); - - //---- jabber_chat.cpp --------------------------------------------------------------- - - void GcLogCreate( JABBER_LIST_ITEM* item ); - void GcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, const TCHAR* resource, const TCHAR* nick, const TCHAR* jid, int action, HXML reason, int nStatusCode = -1 ); - void GcLogShowInformation( JABBER_LIST_ITEM *item, JABBER_RESOURCE_STATUS *user, TJabberGcLogInfoType type ); - void GcQuit( JABBER_LIST_ITEM* jid, int code, HXML reason ); - - void FilterList(HWND hwndList); - void ResetListOptions(HWND hwndList); - void InviteUser(TCHAR *room, TCHAR *pUser, TCHAR *text); - - void AdminSet( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal ); - void AdminGet( const TCHAR* to, const TCHAR* ns, const TCHAR* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo ); - void AdminSetReason( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal, const TCHAR* rsn ); - void AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str ); - void AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str , TCHAR* rsn); - void DeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid ); - - //---- jabber_console.cpp ------------------------------------------------------------ - - INT_PTR __cdecl OnMenuHandleConsole( WPARAM wParam, LPARAM lParam ); - void __cdecl ConsoleThread( void* ); - - void ConsoleInit( void ); - void ConsoleUninit( void ); - - bool FilterXml(HXML node, DWORD flags); - bool RecursiveCheckFilter(HXML node, DWORD flags); - - //---- jabber_disco.cpp -------------------------------------------------------------- - - void LaunchServiceDiscovery(TCHAR *jid); - INT_PTR __cdecl OnMenuHandleServiceDiscovery( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleServiceDiscoveryMyTransports( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleServiceDiscoveryTransports( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleServiceDiscoveryConferences( WPARAM wParam, LPARAM lParam ); - - void OnIqResultServiceDiscoveryInfo( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultServiceDiscoveryItems( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultServiceDiscoveryRootInfo( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultServiceDiscoveryRoot( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultServiceDiscoveryRootItems( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL SendInfoRequest(CJabberSDNode* pNode, HXML parent); - BOOL SendBothRequests(CJabberSDNode* pNode, HXML parent); - void PerformBrowse(HWND hwndDlg); - BOOL IsNodeRegistered(CJabberSDNode *pNode); - void ApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode); - BOOL SyncTree(HTREELISTITEM hIndex, CJabberSDNode* pNode); - void ServiceDiscoveryShowMenu(CJabberSDNode *node, HTREELISTITEM hItem, POINT pt); - - int SetupServiceDiscoveryDlg( TCHAR* jid ); - - void OnIqResultCapsDiscoInfo( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultCapsDiscoInfoSI( HXML iqNode, CJabberIqInfo* pInfo ); - - void RegisterAgent( HWND hwndDlg, TCHAR* jid ); - - //---- jabber_file.cpp --------------------------------------------------------------- - - int FileReceiveParse( filetransfer* ft, char* buffer, int datalen ); - int FileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen ); - - void UpdateChatUserStatus( wchar_t* chat_jid, wchar_t* jid, wchar_t* nick, int role, int affil, int status, BOOL update_nick ); - - void GroupchatJoinRoomByJid(HWND hwndParent, TCHAR *jid); - - void RenameParticipantNick( JABBER_LIST_ITEM* item, const TCHAR* oldNick, HXML itemNode ); - void AcceptGroupchatInvite( const TCHAR* roomJid, const TCHAR* reason, const TCHAR* password ); - - //---- jabber_form.c ----------------------------------------------------------------- - - void FormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ); - - //---- jabber_ft.c ------------------------------------------------------------------- - - void __cdecl FileReceiveThread( filetransfer* ft ); - void __cdecl FileServerThread( filetransfer* ft ); - - void FtCancel( filetransfer* ft ); - void FtInitiate( TCHAR* jid, filetransfer* ft ); - void FtHandleSiRequest( HXML iqNode ); - void FtAcceptSiRequest( filetransfer* ft ); - void FtAcceptIbbRequest( filetransfer* ft ); - BOOL FtHandleBytestreamRequest( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL FtHandleIbbRequest( HXML iqNode, BOOL bOpen ); - - //---- jabber_groupchat.c ------------------------------------------------------------ - - INT_PTR __cdecl OnMenuHandleJoinGroupchat( WPARAM wParam, LPARAM lParam ); - void __cdecl GroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo ); - - INT_PTR __cdecl OnJoinChat( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnLeaveChat( WPARAM wParam, LPARAM lParam ); - - JABBER_RESOURCE_STATUS* GcFindResource(JABBER_LIST_ITEM *item, const TCHAR *resource); - void GroupchatJoinRoom( LPCTSTR server, LPCTSTR room, LPCTSTR nick, LPCTSTR password, bool autojoin = false ); - void GroupchatProcessPresence( HXML node ); - void GroupchatProcessMessage( HXML node ); - void GroupchatProcessInvite( LPCTSTR roomJid, LPCTSTR from, LPCTSTR reason, LPCTSTR password ); - void GroupchatJoinDlg( TCHAR* roomJid ); - void OnIqResultDiscovery(HXML iqNode, CJabberIqInfo *pInfo); - - //---- jabber_icolib.cpp ------------------------------------------------------------- - - int* m_transportProtoTableStartIndex; - - void IconsInit( void ); - HANDLE GetIconHandle( int iconId ); - HICON LoadIconEx( const char* name, bool big = false ); - int LoadAdvancedIcons(int iID); - int GetTransportProtoID( TCHAR* TransportDomain ); - int GetTransportStatusIconIndex(int iID, int Status); - BOOL DBCheckIsTransportedContact(const TCHAR* jid, HANDLE hContact); - void CheckAllContactsAreTransported( void ); - INT_PTR __cdecl JGetAdvancedStatusIcon(WPARAM wParam, LPARAM lParam ); - - //---- jabber_iq.c ------------------------------------------------------------------- - - JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId ); - - void __cdecl ExpirerThread( void* ); - - void IqInit(); - void IqUninit(); - void IqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func ); - void IqRemove( int index ); - void IqExpire(); - - void OnIqResultBind( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultDiscoBookmarks( HXML iqNode ); - void OnIqResultEntityTime( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultExtSearch( HXML iqNode ); - void OnIqResultGetAuth( HXML iqNode ); - void OnIqResultGetVCardAvatar( HXML iqNode ); - void OnIqResultGetClientAvatar( HXML iqNode ); - void OnIqResultGetServerAvatar( HXML iqNode ); - void OnIqResultGotAvatar( HANDLE hContact, HXML n, const TCHAR* mimeType ); - void OnIqResultGetMuc( HXML iqNode ); - void OnIqResultGetRegister( HXML iqNode ); - void OnIqResultGetRoster( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultGetVcard( HXML iqNode ); - void OnIqResultLastActivity( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultMucGetAdminList( HXML iqNode ); - void OnIqResultMucGetBanList( HXML iqNode ); - void OnIqResultMucGetMemberList( HXML iqNode ); - void OnIqResultMucGetModeratorList( HXML iqNode ); - void OnIqResultMucGetOwnerList( HXML iqNode ); - void OnIqResultMucGetVoiceList( HXML iqNode ); - void OnIqResultNestedRosterGroups( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultNotes( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultSession( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultSetAuth( HXML iqNode ); - void OnIqResultSetBookmarks( HXML iqNode ); - void OnIqResultSetPassword( HXML iqNode ); - void OnIqResultSetRegister( HXML iqNode ); - void OnIqResultSetSearch( HXML iqNode ); - void OnIqResultSetVcard( HXML iqNode ); - void OnIqResultVersion( HXML node, CJabberIqInfo *pInfo ); - void OnProcessLoginRq( ThreadData* info, DWORD rq ); - void OnLoggedIn( void ); - - //---- jabber_iq_handlers.cpp -------------------------------------------------------- - - BOOL OnIqRequestVersion( HXML node, CJabberIqInfo* pInfo ); - BOOL OnIqRequestLastActivity( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqRequestPing( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqRequestTime( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqProcessIqOldTime( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqRequestAvatar( HXML node, CJabberIqInfo *pInfo ); - BOOL OnSiRequest( HXML node, CJabberIqInfo *pInfo ); - BOOL OnRosterPushRequest( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqRequestOOB( HXML node, CJabberIqInfo *pInfo ); - BOOL OnIqHttpAuth( HXML node, CJabberIqInfo* pInfo ); - BOOL AddClistHttpAuthEvent( CJabberHttpAuthParams *pParams ); - - void __cdecl IbbSendThread( JABBER_IBB_TRANSFER *jibb ); - void __cdecl IbbReceiveThread( JABBER_IBB_TRANSFER *jibb ); - - void OnIbbInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIbbCloseResult( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL OnFtHandleIbbIq( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL OnIbbRecvdData( const TCHAR *data, const TCHAR *sid, const TCHAR *seq ); - - void OnFtSiResult( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL FtIbbSend( int blocksize, filetransfer* ft ); - BOOL FtSend( HANDLE hConn, filetransfer* ft ); - void FtSendFinal( BOOL success, filetransfer* ft ); - int FtReceive( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); - void FtReceiveFinal( BOOL success, filetransfer* ft ); - - //---- jabber_message_handlers.cpp -------------------------------------------------------- - - BOOL OnMessageError( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - BOOL OnMessageIbb( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - BOOL OnMessagePubsubEvent( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - BOOL OnMessageGroupchat( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - - //---- jabber_list.cpp --------------------------------------------------------------- - - JABBER_LIST_ITEM *ListAdd( JABBER_LIST list, const TCHAR* jid ); - JABBER_LIST_ITEM *ListGetItemPtr( JABBER_LIST list, const TCHAR* jid ); - JABBER_LIST_ITEM *ListGetItemPtrFromIndex( int index ); - - void ListWipe( void ); - int ListExist( JABBER_LIST list, const TCHAR* jid ); - - BOOL ListLock(); - BOOL ListUnlock(); - - void ListRemove( JABBER_LIST list, const TCHAR* jid ); - void ListRemoveList( JABBER_LIST list ); - void ListRemoveByIndex( int index ); - int ListFindNext( JABBER_LIST list, int fromOffset ); - - JABBER_RESOURCE_STATUS *CJabberProto::ListFindResource( JABBER_LIST list, const TCHAR* jid ); - int ListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage, char priority = 0, const TCHAR* nick = NULL ); - void ListRemoveResource( JABBER_LIST list, const TCHAR* jid ); - TCHAR* ListGetBestResourceNamePtr( const TCHAR* jid ); - TCHAR* ListGetBestClientResourceNamePtr( const TCHAR* jid ); - - void SetMucConfig( HXML node, void *from ); - void OnIqResultMucGetJidList( HXML iqNode, JABBER_MUC_JIDLIST_TYPE listType ); - - void OnIqResultServerDiscoInfo( HXML iqNode ); - void OnIqResultGetVcardPhoto( const TCHAR* jid, HXML n, HANDLE hContact, BOOL& hasPhoto ); - void SetBookmarkRequest (XmlNodeIq& iqId); - - //---- jabber_menu.cpp --------------------------------------------------------------- - - INT_PTR __cdecl OnMenuConvertChatContact( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuRosterAdd( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuOptions( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuTransportLogin( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuTransportResolve( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuBookmarkAdd( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuRevokeAuth( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnMenuHandleResource(WPARAM wParam, LPARAM lParam, LPARAM res); - INT_PTR __cdecl OnMenuHandleDirectPresence(WPARAM wParam, LPARAM lParam, LPARAM res); - INT_PTR __cdecl OnMenuSetPriority(WPARAM wParam, LPARAM lParam, LPARAM dwDelta); - - void GlobalMenuInit( void ); - void GlobalMenuUninit( void ); - - void MenuInit( void ); - - void MenuHideSrmmIcon(HANDLE hContact); - void MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item); - - void AuthWorker( HANDLE hContact, char* authReqType ); - - void UpdatePriorityMenu(short priority); - - HGENMENU m_hMenuPriorityRoot; - short m_priorityMenuVal; - bool m_priorityMenuValSet; - - //---- jabber_misc.c ----------------------------------------------------------------- - - INT_PTR __cdecl OnGetEventTextChatStates( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnGetEventTextPresence( WPARAM wParam, LPARAM lParam ); - - void AddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName ); - void DBAddAuthRequest( const TCHAR* jid, const TCHAR* nick ); - BOOL AddDbPresenceEvent(HANDLE hContact, BYTE btEventType); - HANDLE DBCreateContact( const TCHAR* jid, const TCHAR* nick, BOOL temporary, BOOL stripResource ); - void GetAvatarFileName( HANDLE hContact, TCHAR* pszDest, size_t cbLen ); - void ResolveTransportNicks( const TCHAR* jid ); - void SetServerStatus( int iNewStatus ); - void FormatMirVer(JABBER_RESOURCE_STATUS *resource, TCHAR *buf, int bufSize); - void UpdateMirVer(JABBER_LIST_ITEM *item); - void UpdateMirVer(HANDLE hContact, JABBER_RESOURCE_STATUS *resource); - void UpdateSubscriptionInfo(HANDLE hContact, JABBER_LIST_ITEM *item); - void SetContactOfflineStatus( HANDLE hContact ); - void InitCustomFolders( void ); - void InitPopups( void ); - void MsgPopup( HANDLE hContact, const TCHAR *szMsg, const TCHAR *szTitle ); - - //---- jabber_opt.cpp ---------------------------------------------------------------- - - CJabberDlgBase::CreateParam OptCreateAccount; - CJabberDlgBase::CreateParam OptCreateGc; - CJabberDlgBase::CreateParam OptCreateAdvanced; - - INT_PTR __cdecl OnMenuHandleRosterControl( WPARAM wParam, LPARAM lParam ); - - void _RosterExportToFile(HWND hwndDlg); - void _RosterImportFromFile(HWND hwndDlg); - void _RosterSendRequest(HWND hwndDlg, BYTE rrAction); - void _RosterHandleGetRequest( HXML node ); - - //---- jabber_password.cpp -------------------------------------------------------------- - - INT_PTR __cdecl OnMenuHandleChangePassword( WPARAM wParam, LPARAM lParam ); - - //---- jabber_privacy.cpp ------------------------------------------------------------ - ROSTERREQUSERDATA rrud; - - INT_PTR __cdecl menuSetPrivacyList( WPARAM wParam, LPARAM lParam, LPARAM iList ); - INT_PTR __cdecl OnMenuHandlePrivacyLists( WPARAM wParam, LPARAM lParam ); - - void BuildPrivacyMenu( void ); - void BuildPrivacyListsMenu( bool bDeleteOld ); - - void QueryPrivacyLists( ThreadData *pThreadInfo = NULL ); - - BOOL OnIqRequestPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultPrivacyList( HXML iqNode ); - void OnIqResultPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultPrivacyListActive( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultPrivacyListDefault( HXML iqNode, CJabberIqInfo* pInfo ); - void OnIqResultPrivacyListModify( HXML iqNode, CJabberIqInfo* pInfo ); - - //---- jabber_proto.cpp -------------------------------------------------------------- - - void __cdecl BasicSearchThread( struct JABBER_SEARCH_BASIC *jsb ); - void __cdecl GetAwayMsgThread( void* hContact ); - void __cdecl SendMessageAckThread( void* hContact ); - - HANDLE AddToListByJID( const TCHAR* newJid, DWORD flags ); - void WindowSubscribe(HWND hwnd); - void WindowUnsubscribe(HWND hwnd); - void WindowNotify(UINT msg, bool async = false); - - void InfoFrame_OnSetup(CJabberInfoFrame_Event *evt); - void InfoFrame_OnTransport(CJabberInfoFrame_Event *evt); - - //---- jabber_rc.cpp ----------------------------------------------------------------- - - int RcGetUnreadEventsCount( void ); - - //---- jabber_search.cpp ------------------------------------------------------------- - - void SearchReturnResults( HANDLE id, void* pvUsersInfo, U_TCHAR_MAP* pmAllFields ); - void OnIqResultAdvancedSearch( HXML iqNode ); - void OnIqResultGetSearchFields( HXML iqNode ); - int SearchRenewFields( HWND hwndDlg, JabberSearchData * dat); - void SearchDeleteFromRecent( const TCHAR* szAddr, BOOL deleteLastFromDB = TRUE ); - void SearchAddToRecent( const TCHAR* szAddr, HWND hwndDialog = NULL ); - - //---- jabber_std.cpp ---------------------------------------------- - - void JCreateService( const char* szService, JServiceFunc serviceProc ); - void JCreateServiceParam( const char* szService, JServiceFuncParam serviceProc, LPARAM lParam ); - HANDLE JCreateHookableEvent( const char* szService ); - void JForkThread( JThreadFunc, void* ); - HANDLE JForkThreadEx( JThreadFunc, void*, UINT* threadID = NULL ); - - void JDeleteSetting( HANDLE hContact, const char* valueName ); -// DWORD JGetByte( const char* valueName, int parDefltValue ); - DWORD JGetByte( HANDLE hContact, const char* valueName, int parDefltValue ); - char* JGetContactName( HANDLE hContact ); - DWORD JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue ); - int JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len ); - int JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv ); - int JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv ); - TCHAR *JGetStringT( HANDLE hContact, char* valueName ); - TCHAR *JGetStringT( HANDLE hContact, char* valueName, TCHAR *&out ); - TCHAR *JGetStringT( HANDLE hContact, char* valueName, TCHAR *buf, int size ); - WORD JGetWord( HANDLE hContact, const char* valueName, int parDefltValue ); - void JHookEvent( const char*, JEventFunc ); - int JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam ); -// DWORD JSetByte( const char* valueName, int parValue ); - DWORD JSetByte( HANDLE hContact, const char* valueName, int parValue ); - DWORD JSetDword( HANDLE hContact, const char* valueName, DWORD parValue ); - DWORD JSetString( HANDLE hContact, const char* valueName, const char* parValue ); - DWORD JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue ); - DWORD JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue ); - DWORD JSetWord( HANDLE hContact, const char* valueName, int parValue ); - - TCHAR* JGetStringCrypt( HANDLE hContact, char* valueName ); - DWORD JSetStringCrypt( HANDLE hContact, char* valueName, const TCHAR* parValue ); - - //---- jabber_svc.c ------------------------------------------------------------------ - - void CheckMenuItems(); - void EnableMenuItems( BOOL bEnable ); - - INT_PTR __cdecl JabberGetAvatar( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberGetAvatarCaps( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberGetAvatarInfo( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl ServiceSendXML( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberSetAvatar( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberSetNickname( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberSendNudge( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberGCGetToolTipText( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberServiceParseXmppURI( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl OnHttpAuthRequest( WPARAM wParam, LPARAM lParam ); - INT_PTR __cdecl JabberGetApi( WPARAM wParam, LPARAM lParam ); - - void ExternalTempIqHandler( HXML node, CJabberIqInfo *pInfo ); - BOOL ExternalIqHandler( HXML node, CJabberIqInfo *pInfo ); - BOOL ExternalMessageHandler( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); - BOOL ExternalPresenceHandler( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ); - BOOL ExternalSendHandler( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ); - - BOOL SendHttpAuthReply( CJabberHttpAuthParams *pParams, BOOL bAuthorized ); - - //---- jabber_thread.c ---------------------------------------------- - - TCHAR m_savedPassword[512]; - - typedef struct { - bool isPlainAvailable; - bool isPlainOldAvailable; - bool isMd5Available; - bool isScramAvailable; - bool isNtlmAvailable; - bool isSpnegoAvailable; - bool isKerberosAvailable; - bool isAuthAvailable; - bool isSessionAvailable; - TCHAR *m_gssapiHostName; - } AUTHMECHS; - - AUTHMECHS m_AuthMechs; - - void __cdecl ServerThread( ThreadData* info ); - - void OnProcessFailure( HXML node, ThreadData *info ); - void OnProcessError( HXML node, ThreadData *info ); - void OnProcessSuccess( HXML node, ThreadData *info ); - void OnProcessChallenge( HXML node, ThreadData *info ); - void OnProcessProceed( HXML node, ThreadData *info ); - void OnProcessCompressed( HXML node, ThreadData *info ); - void OnProcessMessage( HXML node, ThreadData *info ); - void OnProcessPresence( HXML node, ThreadData *info ); - void OnProcessPresenceCapabilites( HXML node ); - void OnProcessPubsubEvent( HXML node ); - - void OnProcessStreamOpening( HXML node, ThreadData *info ); - void OnProcessProtocol( HXML node, ThreadData *info ); - - void UpdateJidDbSettings( const TCHAR *jid ); - HANDLE CreateTemporaryContact( const TCHAR *szJid, JABBER_LIST_ITEM* chatItem ); - - void PerformRegistration( ThreadData* info ); - void PerformIqAuth( ThreadData* info ); - void PerformAuthentication( ThreadData* info ); - void OnProcessFeatures( HXML node, ThreadData* info ); - - void xmlStreamInitialize( char *which ); - void xmlStreamInitializeNow(ThreadData* info); - - BOOL OnProcessJingle( HXML node ); - void OnProcessIq( HXML node ); - void OnProcessRegIq( HXML node, ThreadData* info ); - void OnPingReply( HXML node, CJabberIqInfo* pInfo ); - - bool ProcessCaptcha( HXML node, HXML parentNode, ThreadData *info ); - - //---- jabber_util.c ----------------------------------------------------------------- - - JABBER_RESOURCE_STATUS* ResourceInfoFromJID( const TCHAR* jid ); - - void SerialInit( void ); - void SerialUninit( void ); - int SerialNext( void ); - - HANDLE HContactFromJID( const TCHAR* jid , BOOL bStripResource = 3); - HANDLE ChatRoomHContactFromJID( const TCHAR* jid ); - void Log( const char* fmt, ... ); - void SendVisibleInvisiblePresence( BOOL invisible ); - void SendPresenceTo( int status, TCHAR* to, HXML extra, const TCHAR *msg = NULL ); - void SendPresence( int m_iStatus, bool bSendToAll ); - void StringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ); - TCHAR* GetClientJID( const TCHAR* jid, TCHAR*, size_t ); - void RebuildInfoFrame( void ); - - void ComboLoadRecentStrings(HWND hwndDlg, UINT idcCombo, char *param, int recentCount=JABBER_DEFAULT_RECENT_COUNT); - void ComboAddRecentString(HWND hwndDlg, UINT idcCombo, char *param, TCHAR *string, int recentCount=JABBER_DEFAULT_RECENT_COUNT); - BOOL EnterString(TCHAR *result, size_t resultLen, TCHAR *caption=NULL, int type=0, char *windowName=NULL, int recentCount=JABBER_DEFAULT_RECENT_COUNT, int timeout=0); - BOOL IsMyOwnJID( LPCTSTR szJID ); - - void __cdecl LoadHttpAvatars(void* param); - - //---- jabber_vcard.c ----------------------------------------------- - - int m_vCardUpdates; - HWND m_hwndPhoto; - bool m_bPhotoChanged; - TCHAR m_szPhotoFileName[MAX_PATH]; - void OnUserInfoInit_VCard( WPARAM, LPARAM ); - - void GroupchatJoinByHContact( HANDLE hContact, bool autojoin=false ); - int SendGetVcard( const TCHAR* jid ); - void AppendVcardFromDB( HXML n, char* tag, char* key ); - void SetServerVcard( BOOL bPhotoChanged, TCHAR* szPhotoFileName ); - void SaveVcardToDB( HWND hwndPage, int iPage ); - - //---- jabber_ws.c ------------------------------------------------- - - JABBER_SOCKET WsConnect( char* host, WORD port ); - - BOOL WsInit(void); - void WsUninit(void); - int WsSend( JABBER_SOCKET s, char* data, int datalen, int flags ); - int WsRecv( JABBER_SOCKET s, char* data, long datalen, int flags ); - - //---- jabber_xml.c ------------------------------------------------------------------ - - int OnXmlParse( char* buffer ); - void OnConsoleProcessXml(HXML node, DWORD flags); - - //---- jabber_xmlns.c ---------------------------------------------------------------- - - BOOL OnHandleDiscoInfoRequest( HXML iqNode, CJabberIqInfo* pInfo ); - BOOL OnHandleDiscoItemsRequest( HXML iqNode, CJabberIqInfo* pInfo ); - - //---- jabber_xstatus.c -------------------------------------------------------------- - - INT_PTR __cdecl OnSetListeningTo( WPARAM wParam, LPARAM lParams ); - INT_PTR __cdecl OnGetXStatusIcon( WPARAM wParam, LPARAM lParams ); - INT_PTR __cdecl OnGetXStatus( WPARAM wParam, LPARAM lParams ); - INT_PTR __cdecl OnSetXStatus( WPARAM wParam, LPARAM lParams ); - INT_PTR __cdecl OnSetXStatusEx( WPARAM wParam, LPARAM lParams ); - - HICON GetXStatusIcon(int bStatus, UINT flags); - - void RegisterAdvStatusSlot(const char *pszSlot); - void ResetAdvStatus(HANDLE hContact, const char *pszSlot); - void WriteAdvStatus(HANDLE hContact, const char *pszSlot, const TCHAR *pszMode, const char *pszIcon, const TCHAR *pszTitle, const TCHAR *pszText); - char* ReadAdvStatusA(HANDLE hContact, const char *pszSlot, const char *pszValue); - TCHAR* ReadAdvStatusT(HANDLE hContact, const char *pszSlot, const char *pszValue); - - BOOL SendPepTune( TCHAR* szArtist, TCHAR* szLength, TCHAR* szSource, TCHAR* szTitle, TCHAR* szTrack, TCHAR* szUri ); - - void XStatusInit( void ); - void XStatusUninit( void ); - - void SetContactTune( HANDLE hContact, LPCTSTR szArtist, LPCTSTR szLength, LPCTSTR szSource, LPCTSTR szTitle, LPCTSTR szTrack ); - - void InfoFrame_OnUserMood(CJabberInfoFrame_Event *evt); - void InfoFrame_OnUserActivity(CJabberInfoFrame_Event *evt); - - int m_xsActivity; - - CPepServiceList m_pepServices; - -private: - char* m_szXmlStreamToBeInitialized; - - DWORD m_lastTicks; - - CRITICAL_SECTION m_csSerial; - unsigned int m_nSerial; - - HANDLE m_hInitChat; - HGENMENU m_hPrivacyMenuRoot; - BOOL m_menuItemsStatus; - LIST<void> m_hPrivacyMenuItems; - - int m_nMenuResourceItems; - HANDLE* m_phMenuResourceItems; - - HANDLE* m_phIconLibItems; -}; - -extern LIST<CJabberProto> g_Instances; - -#endif diff --git a/protocols/JabberG/jabber_proxy.cpp b/protocols/JabberG/jabber_proxy.cpp deleted file mode 100644 index 1702eb52de..0000000000 --- a/protocols/JabberG/jabber_proxy.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -int JabberHttpGatewayInit( HANDLE /*hConn*/, NETLIBOPENCONNECTION* /*nloc*/, NETLIBHTTPREQUEST* /*nlhr*/ ) -{ -#ifdef NNNN - WORD wLen, wVersion, wType; - WORD wIpLen; - DWORD dwSid1, dwSid2, dwSid3, dwSid4; - BYTE response[300], *buf; - int responseBytes, recvResult; - char szSid[33], szHttpServer[256], szHttpGetUrl[300], szHttpPostUrl[300]; - NETLIBHTTPPROXYINFO nlhpi = {0}; - - for ( responseBytes = 0; ; ) { - recvResult = Netlib_Recv( hConn, response + responseBytes, sizeof( response ) - responseBytes, MSG_DUMPPROXY ); - if ( recvResult<=0 ) break; - responseBytes += recvResult; - if ( responseBytes == sizeof( response )) - break; - } - if ( responseBytes < 31 ) - { - SetLastError( ERROR_INVALID_DATA ); - return 0; - } - buf = response; - unpackWord( &buf, &wLen ); - unpackWord( &buf, &wVersion ); /* always 0x0443 */ - unpackWord( &buf, &wType ); - buf += 6; /* dunno */ - unpackDWord( &buf, &dwSid1 ); - unpackDWord( &buf, &dwSid2 ); - unpackDWord( &buf, &dwSid3 ); - unpackDWord( &buf, &dwSid4 ); - sprintf( szSid, "%08x%08x%08x%08x", dwSid1, dwSid2, dwSid3, dwSid4 ); - unpackWord( &buf, &wIpLen ); - if ( responseBytes < 30 + wIpLen || wIpLen == 0 || wIpLen > sizeof( szHttpServer ) - 1 ) - { - SetLastError( ERROR_INVALID_DATA ); - return 0; - } - memcpy( szHttpServer, buf, wIpLen ); - szHttpServer[wIpLen] = '\0'; - - nlhpi.cbSize = sizeof( nlhpi ); - nlhpi.flags = NLHPIF_USEPOSTSEQUENCE; - nlhpi.szHttpGetUrl = szHttpGetUrl; - nlhpi.szHttpPostUrl = szHttpPostUrl; - nlhpi.firstPostSequence = 1; - sprintf( szHttpGetUrl, "http://%s/monitor?sid=%s", szHttpServer, szSid ); - sprintf( szHttpPostUrl, "http://%s/data?sid=%s&seq=", szHttpServer, szSid ); - return CallService( MS_NETLIB_SETHTTPPROXYINFO, ( WPARAM )hConn, ( LPARAM )&nlhpi ); -#endif - return 1; -} - -int JabberHttpGatewayBegin( HANDLE /*hConn*/, NETLIBOPENCONNECTION* /*nloc*/ ) -{ - /* - icq_packet packet; - int serverNameLen; - - serverNameLen = strlen( nloc->szHost ); - - packet.wLen = ( WORD )( serverNameLen + 4 ); - write_httphdr( &packet, HTTP_PACKETTYPE_LOGIN ); - packWord( &packet, ( WORD )serverNameLen ); - packString( &packet, nloc->szHost, ( WORD )serverNameLen ); - packWord( &packet, nloc->wPort ); - Netlib_Send( hConn, packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP ); - mir_free( packet.pData ); - return 1; - */ - return 1; -} - -int JabberHttpGatewayWrapSend( HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend ) -{ - TCHAR* strb = mir_utf8decodeW(( char* )buf ); - - TCHAR sid[25] = _T(""); - unsigned __int64 rid = 0; - - XmlNode hPayLoad( strb ); - XmlNode body( _T("body")); - HXML hBody = body << XATTRI64( _T("rid"), rid++ ) << XATTR( _T("sid"), sid ) << - XATTR( _T("xmlns"), _T( "http://jabber.org/protocol/httpbind" )); - xmlAddChild( hBody, hPayLoad ); - - TCHAR* str = xi.toString( hBody, NULL ); - - mir_free( strb ); - char* utfStr = mir_utf8encodeT( str ); - NETLIBBUFFER nlb = { utfStr, (int)strlen( utfStr ), flags }; - int result = pfnNetlibSend(( WPARAM )hConn, ( LPARAM )&nlb); - mir_free( utfStr ); - xi.freeMem( str ); - - return result; -} - -#if 0 -PBYTE JabberHttpGatewayUnwrapRecv( NETLIBHTTPREQUEST *nlhr, PBYTE buf, int len, int *outBufLen, void *( *NetlibRealloc )( void *, size_t )) -{ - WORD wLen, wType; - PBYTE tbuf; - int i, copyBytes; - - tbuf = buf; - for ( i = 0;; ) - { - if ( tbuf - buf + 2 > len ) break; - unpackWord( &tbuf, &wLen ); - if ( wLen < 12 ) break; - if ( tbuf - buf + wLen > len ) break; - tbuf += 2; /* version */ - unpackWord( &tbuf, &wType ); - tbuf += 8; /* flags & subtype */ - if ( wType == HTTP_PACKETTYPE_FLAP ) - { - copyBytes = wLen - 12; - if ( copyBytes > len - i ) - { - /* invalid data - do our best to get something out of it */ - copyBytes = len - i; - } - memcpy( buf + i, tbuf, copyBytes ); - i += copyBytes; - } - tbuf += wLen - 12; - } - *outBufLen = i; - return buf; -} -#endif diff --git a/protocols/JabberG/jabber_proxy.h b/protocols/JabberG/jabber_proxy.h deleted file mode 100644 index a42591f81e..0000000000 --- a/protocols/JabberG/jabber_proxy.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_PROXY_H_ -#define _JABBER_PROXY_H_ - -int JabberHttpGatewayInit( HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr ); -int JabberHttpGatewayBegin( HANDLE hConn, NETLIBOPENCONNECTION *nloc ); - -#endif diff --git a/protocols/JabberG/jabber_rc.cpp b/protocols/JabberG/jabber_rc.cpp deleted file mode 100644 index 0021733356..0000000000 --- a/protocols/JabberG/jabber_rc.cpp +++ /dev/null @@ -1,814 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -XEP-0146 support for Miranda IM - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_iq.h" -#include "jabber_rc.h" -#include "m_awaymsg.h" - -CJabberAdhocSession::CJabberAdhocSession( CJabberProto* global ) -{ - m_pNext = NULL; - m_pUserData = NULL; - m_bAutofreeUserData = FALSE; - m_dwStage = 0; - ppro = global; - m_szSessionId.Format(_T("%u%u"), ppro->SerialNext(), GetTickCount()); - m_dwStartTime = GetTickCount(); -} - -BOOL CJabberProto::IsRcRequestAllowedByACL( CJabberIqInfo* pInfo ) -{ - if ( !pInfo || !pInfo->GetFrom()) - return FALSE; - - return IsMyOwnJID( pInfo->GetFrom()); -} - -BOOL CJabberProto::HandleAdhocCommandRequest( HXML iqNode, CJabberIqInfo* pInfo ) -{ - if ( !pInfo->GetChildNode()) - return TRUE; - - if ( !m_options.EnableRemoteControl || !IsRcRequestAllowedByACL( pInfo )) { - // FIXME: send error and return - return TRUE; - } - - const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); - if ( !szNode ) - return TRUE; - - m_adhocManager.HandleCommandRequest( iqNode, pInfo, ( TCHAR* )szNode ); - return TRUE; -} - -BOOL CJabberAdhocManager::HandleItemsRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) -{ - if ( !szNode || !m_pProto->m_options.EnableRemoteControl || !m_pProto->IsRcRequestAllowedByACL( pInfo )) - return FALSE; - - if ( !_tcscmp( szNode, _T(JABBER_FEAT_COMMANDS))) - { - XmlNodeIq iq( _T("result"), pInfo ); - HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)) << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)); - - Lock(); - CJabberAdhocNode* pNode = GetFirstNode(); - while ( pNode ) { - TCHAR* szJid = pNode->GetJid(); - if ( !szJid ) - szJid = m_pProto->m_ThreadInfo->fullJID; - - resultQuery << XCHILD( _T("item")) << XATTR( _T("jid"), szJid ) - << XATTR( _T("node"), pNode->GetNode()) << XATTR( _T("name"), pNode->GetName()); - - pNode = pNode->GetNext(); - } - Unlock(); - - m_pProto->m_ThreadInfo->send( iq ); - return TRUE; - } - return FALSE; -} - -BOOL CJabberAdhocManager::HandleInfoRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) -{ - if ( !szNode || !m_pProto->m_options.EnableRemoteControl || !m_pProto->IsRcRequestAllowedByACL( pInfo )) - return FALSE; - - // FIXME: same code twice - if ( !_tcscmp( szNode, _T(JABBER_FEAT_COMMANDS))) { - XmlNodeIq iq( _T("result"), pInfo ); - HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)); - resultQuery << XCHILD( _T("identity")) << XATTR( _T("name"), _T("Ad-hoc commands")) - << XATTR( _T("category"), _T("automation")) << XATTR( _T("type"), _T("command-node")); - - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_COMMANDS)); - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DATA_FORMS)); - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_INFO)); - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_ITEMS)); - - m_pProto->m_ThreadInfo->send( iq ); - return TRUE; - } - - Lock(); - CJabberAdhocNode *pNode = FindNode( szNode ); - if ( pNode ) { - XmlNodeIq iq( _T("result"), pInfo ); - HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), _T(JABBER_FEAT_DISCO_INFO)); - resultQuery << XCHILD( _T("identity")) << XATTR( _T("name"), pNode->GetName()) - << XATTR( _T("category"), _T("automation")) << XATTR( _T("type"), _T("command-node")); - - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_COMMANDS)); - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DATA_FORMS)); - resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_INFO)); - - Unlock(); - m_pProto->m_ThreadInfo->send( iq ); - return TRUE; - } - Unlock(); - return FALSE; -} - -BOOL CJabberAdhocManager::HandleCommandRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ) -{ - // ATTN: ACL and db settings checked in calling function - - HXML commandNode = pInfo->GetChildNode(); - - Lock(); - CJabberAdhocNode* pNode = FindNode( szNode ); - if ( !pNode ) { - Unlock(); - - m_pProto->m_ThreadInfo->send( - XmlNodeIq( _T("error"), pInfo ) - << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - - return FALSE; - } - - const TCHAR* szSessionId = xmlGetAttrValue( commandNode, _T("sessionid")); - - CJabberAdhocSession* pSession = NULL; - if ( szSessionId ) { - pSession = FindSession( szSessionId ); - if ( !pSession ) { - Unlock(); - - XmlNodeIq iq( _T("error"), pInfo ); - HXML errorNode = iq << XCHILD( _T("error")) << XATTR( _T("type"), _T("modify")); - errorNode << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - errorNode << XCHILDNS( _T("bad-sessionid"), _T(JABBER_FEAT_COMMANDS)); - m_pProto->m_ThreadInfo->send( iq ); - return FALSE; - } - } - else - pSession = AddNewSession(); - - if ( !pSession ) { - Unlock(); - - m_pProto->m_ThreadInfo->send( - XmlNodeIq( _T("error"), pInfo ) - << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("forbidden"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); - - return FALSE; - } - - // session id and node exits here, call handler - - int nResultCode = pNode->CallHandler( iqNode, pInfo, pSession ); - - if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_COMPLETED ) { - m_pProto->m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), szNode ) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) - << XCHILD( _T("note"), TranslateT("Command completed successfully")) << XATTR( _T("type"), _T("info"))); - - RemoveSession( pSession ); - pSession = NULL; - } - else if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_CANCEL ) { - m_pProto->m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), szNode ) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("canceled")) - << XCHILD( _T("note"), TranslateT("Error occured during processing command")) << XATTR( _T("type"), _T("error"))); - - RemoveSession( pSession ); - pSession = NULL; - } - else if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION ) { - RemoveSession( pSession ); - pSession = NULL; - } - Unlock(); - return TRUE; -} - -BOOL CJabberAdhocManager::FillDefaultNodes() -{ - AddNode( NULL, _T(JABBER_FEAT_RC_SET_STATUS), TranslateT("Set status"), &CJabberProto::AdhocSetStatusHandler ); - AddNode( NULL, _T(JABBER_FEAT_RC_SET_OPTIONS), TranslateT("Set options"), &CJabberProto::AdhocOptionsHandler ); - AddNode( NULL, _T(JABBER_FEAT_RC_FORWARD), TranslateT("Forward unread messages"), &CJabberProto::AdhocForwardHandler ); - AddNode( NULL, _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS), TranslateT("Leave groupchats"), &CJabberProto::AdhocLeaveGroupchatsHandler ); - AddNode( NULL, _T(JABBER_FEAT_RC_WS_LOCK), TranslateT("Lock workstation"), &CJabberProto::AdhocLockWSHandler ); - AddNode( NULL, _T(JABBER_FEAT_RC_QUIT_MIRANDA), TranslateT("Quit Miranda NG"), &CJabberProto::AdhocQuitMirandaHandler ); - return TRUE; -} - - -static char *StatusModeToDbSetting(int status,const char *suffix) -{ - char *prefix; - static char str[64]; - - switch(status) { - case ID_STATUS_AWAY: prefix="Away"; break; - case ID_STATUS_NA: prefix="Na"; break; - case ID_STATUS_DND: prefix="Dnd"; break; - case ID_STATUS_OCCUPIED: prefix="Occupied"; break; - case ID_STATUS_FREECHAT: prefix="FreeChat"; break; - case ID_STATUS_ONLINE: prefix="On"; break; - case ID_STATUS_OFFLINE: prefix="Off"; break; - case ID_STATUS_INVISIBLE: prefix="Inv"; break; - case ID_STATUS_ONTHEPHONE: prefix="Otp"; break; - case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break; - case ID_STATUS_IDLE: prefix="Idl"; break; - default: return NULL; - } - lstrcpyA(str,prefix); lstrcatA(str,suffix); - return str; -} - -int CJabberProto::AdhocSetStatusHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - if ( pSession->GetStage() == 0 ) { - // first form - pSession->SetStage( 1 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML xNode = iq - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_SET_STATUS)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); - - xNode << XCHILD( _T("title"), TranslateT("Change Status")); - xNode << XCHILD( _T("instructions"), TranslateT("Choose the status and status message")); - - xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) - << XATTR( _T("value"), _T(JABBER_FEAT_RC)); - - HXML fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Status")) - << XATTR( _T("type"), _T("list-single")) << XATTR( _T("var"), _T("status")); - - fieldNode << XCHILD( _T("required")); - - int status = CallService( MS_CLIST_GETSTATUSMODE, 0, 0 ); - switch ( status ) { - case ID_STATUS_INVISIBLE: - fieldNode << XCHILD( _T("value"), _T("invisible")); - break; - case ID_STATUS_AWAY: - case ID_STATUS_ONTHEPHONE: - case ID_STATUS_OUTTOLUNCH: - fieldNode << XCHILD( _T("value"), _T("away")); - break; - case ID_STATUS_NA: - fieldNode << XCHILD( _T("value"), _T("xa")); - break; - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - fieldNode << XCHILD( _T("value"), _T("dnd")); - break; - case ID_STATUS_FREECHAT: - fieldNode << XCHILD( _T("value"), _T("chat")); - break; - case ID_STATUS_ONLINE: - default: - fieldNode << XCHILD( _T("value"), _T("online")); - break; - } - - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Free for chat")) << XCHILD( _T("value"), _T("chat")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Online")) << XCHILD( _T("value"), _T("online")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Away")) << XCHILD( _T("value"), _T("away")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Extended Away (N/A)")) << XCHILD( _T("value"), _T("xa")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Do Not Disturb")) << XCHILD( _T("value"), _T("dnd")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Invisible")) << XCHILD( _T("value"), _T("invisible")); - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Offline")) << XCHILD( _T("value"), _T("offline")); - - // priority - TCHAR szPriority[ 256 ]; - mir_sntprintf( szPriority, SIZEOF(szPriority), _T("%d"), (short)JGetWord( NULL, "Priority", 5 )); - xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Priority")) << XATTR( _T("type"), _T("text-single")) - << XATTR( _T("var"), _T("status-priority")) << XCHILD( _T("value"), szPriority ); - - // status message text - xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Status message")) - << XATTR( _T("type"), _T("text-multi")) << XATTR( _T("var"), _T("status-message")); - - // global status - fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Change global status")) - << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("status-global")); - - char* szStatusMsg = (char *)CallService( MS_AWAYMSG_GETSTATUSMSG, status, 0 ); - if ( szStatusMsg ) { - fieldNode << XCHILD( _T("value"), _A2T(szStatusMsg)); - mir_free( szStatusMsg ); - } - - m_ThreadInfo->send( iq ); - return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; - } - else if ( pSession->GetStage() == 1 ) { - // result form here - HXML commandNode = pInfo->GetChildNode(); - HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - HXML fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status")); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - HXML valueNode = xmlGetChild( fieldNode , "value" ); - if ( !valueNode || !xmlGetText( valueNode )) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - int status = 0; - - if ( !_tcscmp( xmlGetText( valueNode ), _T("away"))) status = ID_STATUS_AWAY; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("xa"))) status = ID_STATUS_NA; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("dnd"))) status = ID_STATUS_DND; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("chat"))) status = ID_STATUS_FREECHAT; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("online"))) status = ID_STATUS_ONLINE; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("invisible"))) status = ID_STATUS_INVISIBLE; - else if ( !_tcscmp( xmlGetText( valueNode ), _T("offline"))) status = ID_STATUS_OFFLINE; - - if ( !status ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - int priority = -9999; - - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-priority")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode )) - priority = _ttoi( xmlGetText( valueNode )); - } - - if ( priority >= -128 && priority <= 127 ) - JSetWord( NULL, "Priority", (WORD)priority ); - - const TCHAR* szStatusMessage = NULL; - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-message")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode )) - szStatusMessage = xmlGetText( valueNode ); - } - - // skip f...ng away dialog - int nNoDlg = DBGetContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), 0 ); - DBWriteContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), 1 ); - - DBWriteContactSettingTString( NULL, "SRAway", StatusModeToDbSetting( status, "Msg" ), szStatusMessage ? szStatusMessage : _T( "" )); - - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-global")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) - CallService( MS_CLIST_SETSTATUSMODE, status, NULL ); - else - CallProtoService( m_szModuleName, PS_SETSTATUS, status, NULL ); - } - SetAwayMsg( status, szStatusMessage ); - - // return NoDlg setting - DBWriteContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), (BYTE)nNoDlg ); - - return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; - } - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; -} - -int CJabberProto::AdhocOptionsHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - if ( pSession->GetStage() == 0 ) { - // first form - pSession->SetStage( 1 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML xNode = iq - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_SET_OPTIONS)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); - - xNode << XCHILD( _T("title"), TranslateT("Set Options")); - xNode << XCHILD( _T("instructions"), TranslateT("Set the desired options")); - - xNode << XCHILD( _T("field" )) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) - << XATTR( _T("value"), _T(JABBER_FEAT_RC)); - - // Automatically Accept File Transfers - TCHAR szTmpBuff[ 1024 ]; - mir_sntprintf( szTmpBuff, SIZEOF(szTmpBuff), _T("%d"), DBGetContactSettingByte( NULL, "SRFile", "AutoAccept", 0 )); - xNode << XCHILD( _T("field" )) << XATTR( _T("label"), TranslateT("Automatically Accept File Transfers" )) - << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("auto-files")) << XCHILD( _T("value"), szTmpBuff ); - - // Use sounds - mir_sntprintf( szTmpBuff, SIZEOF(szTmpBuff), _T("%d"), DBGetContactSettingByte( NULL, "Skin", "UseSound", 0 )); - xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Play sounds")) - << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("sounds")) << XCHILD( _T("value"), szTmpBuff ); - - // Disable remote controlling - xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Disable remote controlling (check twice what you are doing)")) - << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("enable-rc")) << XCHILD( _T("value"), _T("0")); - - m_ThreadInfo->send( iq ); - return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; - } - - if ( pSession->GetStage() == 1 ) { - // result form here - HXML commandNode = pInfo->GetChildNode(); - HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - HXML fieldNode, valueNode; - - // Automatically Accept File Transfers - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("auto-files")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode )) - DBWriteContactSettingByte( NULL, "SRFile", "AutoAccept", (BYTE)_ttoi( xmlGetText( valueNode )) ); - } - - // Use sounds - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("sounds")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode )) - DBWriteContactSettingByte( NULL, "Skin", "UseSound", (BYTE)_ttoi( xmlGetText( valueNode )) ); - } - - // Disable remote controlling - fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("enable-rc")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) - m_options.EnableRemoteControl = 0; - } - - return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; - } - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; -} - -int CJabberProto::RcGetUnreadEventsCount() -{ - int nEventsSent = 0; - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM)hContact, 0 ); - while ( hDbEvent ) { - DBEVENTINFO dbei = { 0 }; - dbei.cbSize = sizeof(dbei); - dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); - if ( dbei.cbBlob != -1 ) { - dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); - int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); - if ( !nGetTextResult && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT)) { - TCHAR* szEventText = DbGetEventTextT( &dbei, CP_ACP ); - if ( szEventText ) { - nEventsSent++; - mir_free( szEventText ); - } - } - mir_free( dbei.pBlob ); - } - hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0 ); - } - JFreeVariant( &dbv ); - } - } - hContact = db_find_next(hContact); - } - return nEventsSent; -} - -int CJabberProto::AdhocForwardHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - TCHAR szMsg[ 1024 ]; - if ( pSession->GetStage() == 0 ) { - int nUnreadEvents = RcGetUnreadEventsCount(); - if ( !nUnreadEvents ) { - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("There is no messages to forward")); - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) - << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); - - return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; - } - - // first form - pSession->SetStage( 1 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML xNode = iq - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); - - xNode << XCHILD( _T("title"), TranslateT("Forward options")); - - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("%d message(s) to be forwarded"), nUnreadEvents ); - xNode << XCHILD( _T("instructions"), szMsg ); - - xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) - << XCHILD( _T("value"), _T(JABBER_FEAT_RC)); - - // remove clist events - xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Mark messages as read")) << XATTR( _T("type"), _T("boolean")) - << XATTR( _T("var"), _T("remove-clist-events")) << XCHILD( _T("value"), - m_options.RcMarkMessagesAsRead == 1 ? _T("1") : _T("0")); - - m_ThreadInfo->send( iq ); - return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; - } - - if ( pSession->GetStage() == 1 ) { - // result form here - HXML commandNode = pInfo->GetChildNode(); - HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - HXML fieldNode, valueNode; - - BOOL bRemoveCListEvents = TRUE; - - // remove clist events - fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("remove-clist-events")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { - if ( xmlGetText( valueNode ) && !_ttoi( xmlGetText( valueNode )) ) { - bRemoveCListEvents = FALSE; - } - } - m_options.RcMarkMessagesAsRead = bRemoveCListEvents ? 1 : 0; - - int nEventsSent = 0; - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - - HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM)hContact, 0 ); - while ( hDbEvent ) { - DBEVENTINFO dbei = { 0 }; - dbei.cbSize = sizeof(dbei); - dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); - if ( dbei.cbBlob != -1 ) { - dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); - int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); - if ( !nGetTextResult && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT)) { - TCHAR* szEventText = DbGetEventTextT( &dbei, CP_ACP ); - if ( szEventText ) { - XmlNode msg( _T("message")); - msg << XATTR( _T("to"), pInfo->GetFrom()) << XATTRID( SerialNext()) - << XCHILD( _T("body"), szEventText ); - - HXML addressesNode = msg << XCHILDNS( _T("addresses"), _T(JABBER_FEAT_EXT_ADDRESSING)); - TCHAR szOFrom[ JABBER_MAX_JID_LEN ]; - EnterCriticalSection( &m_csLastResourceMap ); - TCHAR *szOResource = FindLastResourceByDbEvent( hDbEvent ); - if ( szOResource ) - mir_sntprintf( szOFrom, SIZEOF( szOFrom ), _T("%s/%s"), dbv.ptszVal, szOResource ); - else - mir_sntprintf( szOFrom, SIZEOF( szOFrom ), _T("%s"), dbv.ptszVal ); - LeaveCriticalSection( &m_csLastResourceMap ); - addressesNode << XCHILD( _T("address")) << XATTR( _T("type"), _T("ofrom")) << XATTR( _T("jid"), szOFrom ); - addressesNode << XCHILD( _T("address")) << XATTR( _T("type"), _T("oto")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ); - - time_t ltime = ( time_t )dbei.timestamp; - struct tm *gmt = gmtime( <ime ); - TCHAR stime[ 512 ]; - wsprintf(stime, _T("%.4i-%.2i-%.2iT%.2i:%.2i:%.2iZ"), gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, - gmt->tm_hour, gmt->tm_min, gmt->tm_sec); - msg << XCHILDNS( _T("delay"), _T("urn:xmpp:delay")) << XATTR( _T("stamp"), stime ); - - m_ThreadInfo->send( msg ); - - nEventsSent++; - - CallService( MS_DB_EVENT_MARKREAD, (WPARAM)hContact, (LPARAM)hDbEvent ); - if ( bRemoveCListEvents ) - CallService( MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)hDbEvent ); - - mir_free( szEventText ); - } - } - mir_free( dbei.pBlob ); - } - hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0 ); - } - JFreeVariant( &dbv ); - } - } - hContact = db_find_next(hContact); - } - - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("%d message(s) forwarded"), nEventsSent ); - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) - << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); - - return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; - } - - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; -} - -typedef BOOL (WINAPI *LWS )( VOID ); - -int CJabberProto::AdhocLockWSHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - BOOL bOk = FALSE; - HMODULE hLibrary = LoadLibrary( _T("user32.dll")); - if ( hLibrary ) { - LWS pLws = (LWS)GetProcAddress( hLibrary, "LockWorkStation" ); - if ( pLws ) - bOk = pLws(); - FreeLibrary( hLibrary ); - } - - TCHAR szMsg[ 1024 ]; - if ( bOk ) - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("Workstation successfully locked")); - else - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("Error %d occured during workstation lock"), GetLastError()); - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_WS_LOCK)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) - << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), bOk ? _T("info") : _T("error"))); - - return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; -} - -static void __stdcall JabberQuitMirandaIMThread( void* ) -{ - CallService( "CloseAction", 0, 0 ); -} - -int CJabberProto::AdhocQuitMirandaHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - if ( pSession->GetStage() == 0 ) { - // first form - pSession->SetStage( 1 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML xNode = iq - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_QUIT_MIRANDA)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); - - xNode << XCHILD( _T("title"), TranslateT("Confirmation needed")); - xNode << XCHILD( _T("instructions"), TranslateT("Please confirm Miranda NG shutdown")); - - xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) - << XCHILD( _T("value"), _T(JABBER_FEAT_RC)); - - // I Agree checkbox - xNode << XCHILD( _T("field")) << XATTR( _T("label"), _T("I agree")) << XATTR( _T("type"), _T("boolean")) - << XATTR( _T("var"), _T("allow-shutdown")) << XCHILD( _T("value"), _T("0")); - - m_ThreadInfo->send( iq ); - return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; - } - - if ( pSession->GetStage() == 1 ) { - // result form here - HXML commandNode = pInfo->GetChildNode(); - HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - HXML fieldNode, valueNode; - - // I Agree checkbox - fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("allow-shutdown")); - if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) - if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) - CallFunctionAsync(JabberQuitMirandaIMThread, 0); - - return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; - } - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; -} - -int CJabberProto::AdhocLeaveGroupchatsHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) -{ - int i = 0; - if ( pSession->GetStage() == 0 ) { - // first form - TCHAR szMsg[ 1024 ]; - - ListLock(); - int nChatsCount = 0; - LISTFOREACH_NODEF(i, this, LIST_CHATROOM) - { - JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); - if ( item != NULL ) - nChatsCount++; - } - ListUnlock(); - - if ( !nChatsCount ) { - mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("There is no groupchats to leave")); - - m_ThreadInfo->send( - XmlNodeIq( _T("result"), pInfo ) - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) - << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); - - return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; - } - - pSession->SetStage( 1 ); - - XmlNodeIq iq( _T("result"), pInfo ); - HXML xNode = iq - << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS)) - << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) - << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); - - xNode << XCHILD( _T("title"), TranslateT("Leave groupchats")); - xNode << XCHILD( _T("instructions"), TranslateT("Choose the groupchats you want to leave")); - - xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) - << XATTR( _T("value"), _T(JABBER_FEAT_RC)); - - // Groupchats - HXML fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), NULL ) << XATTR( _T("type"), _T("list-multi")) << XATTR( _T("var"), _T("groupchats")); - fieldNode << XCHILD( _T("required")); - - ListLock(); - LISTFOREACH_NODEF(i, this, LIST_CHATROOM) - { - JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); - if ( item != NULL ) - fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), item->jid ) << XCHILD( _T("value"), item->jid ); - } - ListUnlock(); - - m_ThreadInfo->send( iq ); - return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; - } - - if ( pSession->GetStage() == 1 ) { - // result form here - HXML commandNode = pInfo->GetChildNode(); - HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if ( !xNode ) - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; - - // Groupchat list here: - HXML fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("groupchats")); - if ( fieldNode ) { - for ( i = 0; i < xmlGetChildCount( fieldNode ); i++ ) { - HXML valueNode = xmlGetChild( fieldNode, i ); - if ( valueNode && xmlGetName( valueNode ) && xmlGetText( valueNode ) && !_tcscmp( xmlGetName( valueNode ), _T("value"))) { - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, xmlGetText( valueNode )); - if ( item ) - GcQuit( item, 0, NULL ); - } - } - } - - return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; - } - return JABBER_ADHOC_HANDLER_STATUS_CANCEL; -} \ No newline at end of file diff --git a/protocols/JabberG/jabber_rc.h b/protocols/JabberG/jabber_rc.h deleted file mode 100644 index cb3bf1b9cc..0000000000 --- a/protocols/JabberG/jabber_rc.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -XEP-0146 support for Miranda IM - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_RC_H_ -#define _JABBER_RC_H_ - -class CJabberAdhocSession; - -#define JABBER_ADHOC_HANDLER_STATUS_EXECUTING 1 -#define JABBER_ADHOC_HANDLER_STATUS_COMPLETED 2 -#define JABBER_ADHOC_HANDLER_STATUS_CANCEL 3 -#define JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION 4 -typedef int ( CJabberProto::*JABBER_ADHOC_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); - -// 5 minutes to fill out form :) -#define JABBER_ADHOC_SESSION_EXPIRE_TIME 300000 - -class CJabberAdhocSession -{ -protected: - CMString m_szSessionId; - CJabberAdhocSession* m_pNext; - DWORD m_dwStartTime; - - void* m_pUserData; - BOOL m_bAutofreeUserData; - - DWORD m_dwStage; -public: - CJabberProto* ppro; - CJabberAdhocSession( CJabberProto* global ); - ~CJabberAdhocSession() - { - if ( m_bAutofreeUserData && m_pUserData ) - mir_free( m_pUserData ); - if ( m_pNext ) - delete m_pNext; - } - CJabberAdhocSession* GetNext() - { - return m_pNext; - } - CJabberAdhocSession* SetNext( CJabberAdhocSession *pNext ) - { - CJabberAdhocSession *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } - DWORD GetSessionStartTime() - { - return m_dwStartTime; - } - LPCTSTR GetSessionId() - { - return m_szSessionId; - } - BOOL SetUserData( void* pUserData, BOOL bAutofree = FALSE ) - { - if ( m_bAutofreeUserData && m_pUserData ) - mir_free( m_pUserData ); - m_pUserData = pUserData; - m_bAutofreeUserData = bAutofree; - return TRUE; - } - DWORD SetStage( DWORD dwStage ) - { - DWORD dwRetVal = m_dwStage; - m_dwStage = dwStage; - return dwRetVal; - } - DWORD GetStage() - { - return m_dwStage; - } -}; - -class CJabberAdhocNode; -class CJabberAdhocNode -{ -protected: - TCHAR* m_szJid; - TCHAR* m_szNode; - TCHAR* m_szName; - CJabberAdhocNode* m_pNext; - JABBER_ADHOC_HANDLER m_pHandler; - CJabberProto* m_pProto; -public: - CJabberAdhocNode( CJabberProto* pProto, TCHAR* szJid, TCHAR* szNode, TCHAR* szName, JABBER_ADHOC_HANDLER pHandler ) - { - ZeroMemory( this, sizeof( CJabberAdhocNode )); - replaceStrT( m_szJid, szJid ); - replaceStrT( m_szNode, szNode ); - replaceStrT( m_szName, szName ); - m_pHandler = pHandler; - m_pProto = pProto; - } - ~CJabberAdhocNode() - { - if ( m_szJid) - mir_free( m_szJid ); - if ( m_szNode ) - mir_free( m_szNode ); - if ( m_szName ) - mir_free( m_szName ); - if ( m_pNext ) - delete m_pNext; - } - CJabberAdhocNode* GetNext() - { - return m_pNext; - } - CJabberAdhocNode* SetNext( CJabberAdhocNode *pNext ) - { - CJabberAdhocNode *pRetVal = m_pNext; - m_pNext = pNext; - return pRetVal; - } - TCHAR* GetJid() - { - return m_szJid; - } - TCHAR* GetNode() - { - return m_szNode; - } - TCHAR* GetName() - { - return m_szName; - } - BOOL CallHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) - { - if ( m_pHandler == NULL ) - return FALSE; - return (m_pProto->*m_pHandler)( iqNode, pInfo, pSession ); - } -}; - -class CJabberAdhocManager -{ -protected: - CJabberProto* m_pProto; - CJabberAdhocNode* m_pNodes; - CJabberAdhocSession* m_pSessions; - CRITICAL_SECTION m_cs; - - CJabberAdhocSession* FindSession( const TCHAR* szSession ) - { - CJabberAdhocSession* pSession = m_pSessions; - while ( pSession ) { - if ( !_tcscmp( pSession->GetSessionId(), szSession )) - return pSession; - pSession = pSession->GetNext(); - } - return NULL; - } - - CJabberAdhocSession* AddNewSession() - { - CJabberAdhocSession* pSession = new CJabberAdhocSession( m_pProto ); - if ( !pSession ) - return NULL; - - pSession->SetNext( m_pSessions ); - m_pSessions = pSession; - - return pSession; - } - - CJabberAdhocNode* FindNode( const TCHAR* szNode ) - { - CJabberAdhocNode* pNode = m_pNodes; - while ( pNode ) { - if ( !_tcscmp( pNode->GetNode(), szNode )) - return pNode; - pNode = pNode->GetNext(); - } - return NULL; - } - - BOOL RemoveSession( CJabberAdhocSession* pSession ) - { - if ( !m_pSessions ) - return FALSE; - - if ( pSession == m_pSessions ) { - m_pSessions = m_pSessions->GetNext(); - pSession->SetNext( NULL ); - delete pSession; - return TRUE; - } - - CJabberAdhocSession* pTmp = m_pSessions; - while ( pTmp->GetNext()) { - if ( pTmp->GetNext() == pSession ) { - pTmp->SetNext( pSession->GetNext()); - pSession->SetNext( NULL ); - delete pSession; - return TRUE; - } - pTmp = pTmp->GetNext(); - } - return FALSE; - } - - BOOL _ExpireSession( DWORD dwExpireTime ) - { - if ( !m_pSessions ) - return FALSE; - - CJabberAdhocSession* pSession = m_pSessions; - if ( pSession->GetSessionStartTime() < dwExpireTime ) { - m_pSessions = pSession->GetNext(); - pSession->SetNext( NULL ); - delete pSession; - return TRUE; - } - - while ( pSession->GetNext()) { - if ( pSession->GetNext()->GetSessionStartTime() < dwExpireTime ) { - CJabberAdhocSession* pRetVal = pSession->GetNext(); - pSession->SetNext( pSession->GetNext()->GetNext()); - pRetVal->SetNext( NULL ); - delete pRetVal; - return TRUE; - } - pSession = pSession->GetNext(); - } - return FALSE; - } - -public: - CJabberAdhocManager( CJabberProto* pProto ) - { - ZeroMemory( this, sizeof( CJabberAdhocManager )); - m_pProto = pProto; - InitializeCriticalSection( &m_cs ); - } - ~CJabberAdhocManager() - { - if ( m_pNodes ) - delete m_pNodes; - if ( m_pSessions ) - delete m_pSessions; - DeleteCriticalSection( &m_cs ); - } - void Lock() - { - EnterCriticalSection( &m_cs ); - } - void Unlock() - { - LeaveCriticalSection( &m_cs ); - } - BOOL FillDefaultNodes(); - BOOL AddNode( TCHAR* szJid, TCHAR* szNode, TCHAR* szName, JABBER_ADHOC_HANDLER pHandler ) - { - CJabberAdhocNode* pNode = new CJabberAdhocNode( m_pProto, szJid, szNode, szName, pHandler ); - if ( !pNode ) - return FALSE; - - Lock(); - if ( !m_pNodes ) - m_pNodes = pNode; - else { - CJabberAdhocNode* pTmp = m_pNodes; - while ( pTmp->GetNext()) - pTmp = pTmp->GetNext(); - pTmp->SetNext( pNode ); - } - Unlock(); - - return TRUE; - } - CJabberAdhocNode* GetFirstNode() - { - return m_pNodes; - } - BOOL HandleItemsRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); - BOOL HandleInfoRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); - BOOL HandleCommandRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); - - BOOL ExpireSessions() - { - Lock(); - DWORD dwExpireTime = GetTickCount() - JABBER_ADHOC_SESSION_EXPIRE_TIME; - while ( _ExpireSession( dwExpireTime )); - Unlock(); - return TRUE; - } -}; - -#endif //_JABBER_RC_H_ diff --git a/protocols/JabberG/jabber_search.cpp b/protocols/JabberG/jabber_search.cpp deleted file mode 100644 index e242294a16..0000000000 --- a/protocols/JabberG/jabber_search.cpp +++ /dev/null @@ -1,762 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Artem Shpynov - -Module implements a search according to XEP-0055: Jabber Search -http://www.xmpp.org/extensions/xep-0055.html - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include <CommCtrl.h> -#include "jabber_iq.h" -#include "jabber_caps.h" - -/////////////////////////////////////////////////////////////////////////////// -// Subclassing of IDC_FRAME to implement more user-friendly fields scrolling -// -static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam) -{ - if ( msg == WM_COMMAND && lParam != 0 ) { - HWND hwndDlg=GetParent(hwnd); - JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); - if ( dat && lParam ) { - int pos=dat->curPos; - RECT MineRect; - RECT FrameRect; - GetWindowRect(GetDlgItem( hwndDlg, IDC_FRAME ),&FrameRect); - GetWindowRect((HWND)lParam, &MineRect); - if ( MineRect.top-10 < FrameRect.top ) { - pos=dat->curPos+(MineRect.top-14-FrameRect.top); - if (pos<0) pos=0; - } - else if ( MineRect.bottom > FrameRect.bottom ) { - pos=dat->curPos+(MineRect.bottom-FrameRect.bottom); - if (dat->frameHeight+pos>dat->CurrentHeight) - pos=dat->CurrentHeight-dat->frameHeight; - } - if ( pos != dat->curPos ) { - ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL, &( dat->frameRect )); - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); - RECT Invalid=dat->frameRect; - if (dat->curPos - pos >0) - Invalid.bottom=Invalid.top+(dat->curPos - pos); - else - Invalid.top=Invalid.bottom+(dat->curPos - pos); - - RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW |RDW_ALLCHILDREN); - dat->curPos = pos; - } } - if (HIWORD(wParam)==EN_SETFOCUS) { //Transmit focus set notification to parent window - PostMessage(GetParent(hwndDlg),WM_COMMAND, MAKEWPARAM(0,EN_SETFOCUS), (LPARAM)hwndDlg); - } - } - - if ( msg == WM_PAINT ) { - PAINTSTRUCT ps; - HDC hdc=BeginPaint(hwnd, &ps); - FillRect(hdc,&(ps.rcPaint),GetSysColorBrush(COLOR_BTNFACE)); - EndPaint(hwnd, &ps); - } - - return DefWindowProc(hwnd,msg,wParam,lParam); -} - -/////////////////////////////////////////////////////////////////////////////// -// Add Search field to form -// -static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat ) -{ - if (!FieldDat || !FieldDat->Label || !FieldDat->Var) return FALSE; - HFONT hFont = ( HFONT ) SendMessage( hwndDlg, WM_GETFONT, 0, 0 ); - HWND hwndParent=GetDlgItem(hwndDlg,IDC_FRAME); - LONG frameExStyle = GetWindowLongPtr( hwndParent, GWL_EXSTYLE ); - frameExStyle |= WS_EX_CONTROLPARENT; - SetWindowLongPtr( hwndParent, GWL_EXSTYLE, frameExStyle ); - SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_FRAME),GWLP_WNDPROC,(LONG_PTR)JabberSearchFrameProc); - - int CornerX=1; - int CornerY=1; - RECT rect; - GetClientRect(hwndParent,&rect); - int width=rect.right-5-CornerX; - - int Order=(FieldDat->bHidden) ? -1 : FieldDat->Order; - - HWND hwndLabel=CreateWindowEx(0,_T("STATIC"),(LPCTSTR)TranslateTS(FieldDat->Label),WS_CHILD, CornerX, CornerY + Order*40, width, 13,hwndParent,NULL,hInst,0); - HWND hwndVar=CreateWindowEx(0|WS_EX_CLIENTEDGE,_T("EDIT"),(LPCTSTR)FieldDat->defValue,WS_CHILD|WS_TABSTOP, CornerX+5, CornerY + Order*40+14, width ,20,hwndParent,NULL,hInst,0); - SendMessage(hwndLabel, WM_SETFONT, (WPARAM)hFont,0); - SendMessage(hwndVar, WM_SETFONT, (WPARAM)hFont,0); - if (!FieldDat->bHidden) - { - ShowWindow(hwndLabel,SW_SHOW); - ShowWindow(hwndVar,SW_SHOW); - EnableWindow(hwndLabel,!FieldDat->bReadOnly); - SendMessage(hwndVar, EM_SETREADONLY, (WPARAM)FieldDat->bReadOnly,0); - } - //remade list - //reallocation - JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); - if ( dat ) { - dat->pJSInf=(JabberSearchFieldsInfo*) realloc(dat->pJSInf, sizeof(JabberSearchFieldsInfo)*(dat->nJSInfCount+1)); - dat->pJSInf[dat->nJSInfCount].hwndCaptionItem=hwndLabel; - dat->pJSInf[dat->nJSInfCount].hwndValueItem=hwndVar; - dat->pJSInf[dat->nJSInfCount].szFieldCaption=_tcsdup(FieldDat->Label); - dat->pJSInf[dat->nJSInfCount].szFieldName=_tcsdup(FieldDat->Var); - dat->nJSInfCount++; - } - return CornerY + Order*40+14 +20; -} - -//////////////////////////////////////////////////////////////////////////////// -// Available search field request result handler (XEP-0055. Examples 2, 7) - -void CJabberProto::OnIqResultGetSearchFields( HXML iqNode ) -{ - if ( !searchHandleDlg ) - return; - - LPCTSTR type = xmlGetAttrValue( iqNode, _T("type")); - if ( !type ) - return; - - if ( !lstrcmp( type, _T("result"))) { - HXML queryNode = xmlGetNthChild( iqNode, _T("query"), 1 ); - HXML xNode = xmlGetChildByTag( queryNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - - ShowWindow(searchHandleDlg,SW_HIDE); - if ( xNode ) { - //1. Form - PostMessage( searchHandleDlg, WM_USER+11, ( WPARAM )xi.copyNode( xNode ), ( LPARAM )0 ); - HXML xcNode = xmlGetNthChild( xNode, _T("instructions"), 1 ); - if ( xcNode ) - SetDlgItemText( searchHandleDlg, IDC_INSTRUCTIONS, xmlGetText( xcNode )); - } - else { - int Order=0; - for ( int i = 0; ; i++ ) { - HXML chNode = xmlGetChild( queryNode, i ); - if ( !chNode ) - break; - - if ( !_tcsicmp( xmlGetName( chNode ), _T("instructions")) && xmlGetText( chNode )) - SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,TranslateTS(xmlGetText( chNode ))); - else if ( xmlGetName( chNode )) { - Data *MyData=(Data*)malloc(sizeof(Data)); - memset(MyData,0,sizeof(Data)); - - MyData->Label = mir_tstrdup( xmlGetName( chNode )); - MyData->Var = mir_tstrdup( xmlGetName( chNode )); - MyData->defValue = mir_tstrdup(xmlGetText( chNode )); - MyData->Order = Order; - if (MyData->defValue) MyData->bReadOnly = TRUE; - PostMessage(searchHandleDlg,WM_USER+10,(WPARAM)FALSE,(LPARAM)MyData); - Order++; - } } } - const TCHAR* szFrom = xmlGetAttrValue( iqNode, _T("from")); - if (szFrom) - SearchAddToRecent(szFrom,searchHandleDlg); - PostMessage(searchHandleDlg,WM_USER+10,(WPARAM)0,(LPARAM)0); - ShowWindow(searchHandleDlg,SW_SHOW); - } - else if ( !lstrcmp( type, _T("error"))) { - const TCHAR* code=NULL; - const TCHAR* description=NULL; - TCHAR buff[255]; - HXML errorNode = xmlGetChild( iqNode, "error"); - if ( errorNode ) { - code = xmlGetAttrValue( errorNode, _T("code")); - description=xmlGetText( errorNode ); - } - _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s\r\nPlease select other server"),code ? code : _T(""),description?description:_T("")); - SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,buff); - } - else SetDlgItemText( searchHandleDlg, IDC_INSTRUCTIONS, TranslateT( "Error Unknown reply recieved\r\nPlease select other server" )); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Return results to search dialog -// The pmFields is the pointer to map of <field Name, field Label> Not unical but ordered -// This can help to made result parser routines more simple - -void CJabberProto::SearchReturnResults( HANDLE id, void * pvUsersInfo, U_TCHAR_MAP * pmAllFields ) -{ - LIST<TCHAR> ListOfNonEmptyFields(20,(LIST<TCHAR>::FTSortFunc)TCharKeyCmp); - LIST<TCHAR> ListOfFields(20); - LIST<void>* plUsersInfo = ( LIST<void>* )pvUsersInfo; - int i, nUsersFound = plUsersInfo->getCount(); - - // lets fill the ListOfNonEmptyFields but in users order - for ( i=0; i < nUsersFound; i++ ) { - U_TCHAR_MAP* pmUserData = ( U_TCHAR_MAP* )plUsersInfo->operator [](i); - int nUserFields = pmUserData->getCount(); - for (int j=0; j < nUserFields; j++) { - TCHAR* var = pmUserData->getKeyName(j); - if (var && ListOfNonEmptyFields.getIndex(var) < 0) - ListOfNonEmptyFields.insert(var); - } } - - // now fill the ListOfFields but order is from pmAllFields - int nAllCount = pmAllFields->getCount(); - for ( i=0; i < nAllCount; i++ ) { - TCHAR * var=pmAllFields->getUnOrderedKeyName(i); - if ( var && ListOfNonEmptyFields.getIndex(var) < 0 ) - continue; - ListOfFields.insert(var); - } - - // now lets transfer field names - int nFieldCount = ListOfFields.getCount(); - - JABBER_CUSTOMSEARCHRESULTS Results={0}; - Results.nSize=sizeof(Results); - Results.pszFields=(TCHAR**)mir_alloc(sizeof(TCHAR*)*nFieldCount); - Results.nFieldCount=nFieldCount; - - /* Sending Columns Titles */ - for ( i=0; i < nFieldCount; i++ ) { - TCHAR* var = ListOfFields[i]; - if ( var ) - Results.pszFields[i] = pmAllFields->operator [](var); - } - - Results.jsr.hdr.cbSize = 0; // sending column names - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM) &Results ); - - /* Sending Users Data */ - Results.jsr.hdr.cbSize = sizeof(Results.jsr); // sending user data - - for ( i=0; i < nUsersFound; i++ ) { - TCHAR buff[200]=_T(""); - Results.jsr.jid[0]=_T('\0'); - U_TCHAR_MAP * pmUserData = (U_TCHAR_MAP *) plUsersInfo->operator [](i); - for ( int j=0; j < nFieldCount; j++ ) { - TCHAR* var = ListOfFields[j]; - TCHAR* value = pmUserData->operator [](var); - Results.pszFields[j] = value ? value : (TCHAR *)_T(" "); - if (!_tcsicmp(var,_T("jid")) && value ) - _tcsncpy(Results.jsr.jid, value, SIZEOF(Results.jsr.jid)); - } - { - TCHAR * nickfields[]={ _T("nick"), _T("nickname"), - _T("fullname"), _T("name"), - _T("given"), _T("first"), - _T("jid"), NULL }; - TCHAR * nick=NULL; - int k=0; - while (nickfields[k] && !nick) nick=pmUserData->operator [](nickfields[k++]); - if (_tcsicmp(nick, Results.jsr.jid)) - _sntprintf(buff,SIZEOF(buff),_T("%s ( %s )"),nick, Results.jsr.jid); - else - _tcsncpy(buff, nick, SIZEOF(buff)); - Results.jsr.hdr.nick = nick ? buff : NULL; - Results.jsr.hdr.flags = PSR_TCHAR; - } - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM) &Results ); - Results.jsr.hdr.nick=NULL; - - } - mir_free( Results.pszFields ); -} - -void DestroyKey( TCHAR* key ) -{ - mir_free( key ); -} - -TCHAR* CopyKey( TCHAR* key ) -{ - return mir_tstrdup( key ); -} - -//////////////////////////////////////////////////////////////////////////////// -// Search field request result handler (XEP-0055. Examples 3, 8) - -void CJabberProto::OnIqResultAdvancedSearch( HXML iqNode ) -{ - const TCHAR* type; - int id; - - U_TCHAR_MAP mColumnsNames(10); - LIST<void> SearchResults(2); - - if ((( id = JabberGetPacketID( iqNode )) == -1 ) || (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL )) { - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); - return; - } - - if ( !lstrcmp( type, _T("result"))) { - HXML queryNode = xmlGetNthChild( iqNode, _T("query"), 1 ); - HXML xNode = xmlGetChildByTag( queryNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); - if (xNode) { - //1. Form search results info - HXML reportNode = xmlGetNthChild( xNode, _T("reported"), 1 ); - if (reportNode) { - int i = 1; - while ( HXML fieldNode = xmlGetNthChild( reportNode, _T("field"), i++ )) { - TCHAR* var = ( TCHAR* )xmlGetAttrValue( fieldNode, _T( "var" )); - if ( var ) { - TCHAR* Label = ( TCHAR* )xmlGetAttrValue( fieldNode, _T( "label" )); - mColumnsNames.insert(var, (Label!=NULL) ? Label : var); - } } } - - int i=1; - HXML itemNode; - while ( itemNode = xmlGetNthChild( xNode, _T("item"), i++ )) { - U_TCHAR_MAP *pUserColumn = new U_TCHAR_MAP(10); - int j = 1; - while ( HXML fieldNode = xmlGetNthChild( itemNode, _T("field"), j++ )) { - if ( TCHAR* var = (TCHAR*)xmlGetAttrValue( fieldNode, _T("var"))) { - if ( TCHAR* Text = (TCHAR*)xmlGetText( xmlGetChild( fieldNode, _T("value")))) { - if ( !mColumnsNames[var] ) - mColumnsNames.insert(var,var); - pUserColumn->insert(var,Text); - } } } - - SearchResults.insert((void*)pUserColumn); - } - } - else { - //2. Field list search results info - int i=1; - while ( HXML itemNode = xmlGetNthChild( queryNode, _T("item"), i++ )) { - U_TCHAR_MAP *pUserColumn=new U_TCHAR_MAP(10); - - TCHAR* jid = (TCHAR*)xmlGetAttrValue( itemNode, _T("jid")); - TCHAR* keyReturned; - mColumnsNames.insertCopyKey( _T("jid"),_T("jid"),&keyReturned, CopyKey, DestroyKey ); - mColumnsNames.insert( _T("jid"), keyReturned ); - pUserColumn->insertCopyKey( _T("jid"), jid, NULL, CopyKey, DestroyKey ); - - for ( int j=0; ; j++ ) { - HXML child = xmlGetChild( itemNode, j ); - if ( !child ) - break; - - const TCHAR* szColumnName = xmlGetName( child ); - if ( szColumnName ) { - if ( xmlGetText( child ) && xmlGetText( child )[0] != _T('\0')) { - mColumnsNames.insertCopyKey(( TCHAR* )szColumnName,_T(""),&keyReturned, CopyKey, DestroyKey); - mColumnsNames.insert(( TCHAR* )szColumnName,keyReturned); - pUserColumn->insertCopyKey(( TCHAR* )szColumnName, ( TCHAR* )xmlGetText( child ),NULL, CopyKey, DestroyKey); - } } } - - SearchResults.insert((void*)pUserColumn); - } } - } - else if (!lstrcmp( type, _T("error"))) { - const TCHAR* code=NULL; - const TCHAR* description=NULL; - TCHAR buff[255]; - HXML errorNode = xmlGetChild( iqNode , "error" ); - if (errorNode) { - code = xmlGetAttrValue( errorNode, _T("code")); - description = xmlGetText( errorNode ); - } - - _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s\r\nTry to specify more detailed"),code ? code : _T(""),description?description:_T("")); - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); - if (searchHandleDlg ) - SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,buff); - else - MessageBox(NULL, buff, TranslateT("Search error"), MB_OK|MB_ICONSTOP); - return; - } - - SearchReturnResults((HANDLE)id, (void*)&SearchResults, (U_TCHAR_MAP *)&mColumnsNames); - - for (int i=0; i < SearchResults.getCount(); i++ ) - delete ((U_TCHAR_MAP *)SearchResults[i]); - - //send success to finish searching - JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); -} - -static BOOL CALLBACK DeleteChildWindowsProc( HWND hwnd, LPARAM ) -{ - DestroyWindow(hwnd); - return TRUE; -} - -static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat) -{ - //lock - if ( !dat->fSearchRequestIsXForm && dat->nJSInfCount && dat->pJSInf ) { - for ( int i=0; i < dat->nJSInfCount; i++ ) { - if (dat->pJSInf[i].hwndValueItem) - DestroyWindow(dat->pJSInf[i].hwndValueItem); - if (dat->pJSInf[i].hwndCaptionItem) - DestroyWindow(dat->pJSInf[i].hwndCaptionItem); - if (dat->pJSInf[i].szFieldCaption) - free(dat->pJSInf[i].szFieldCaption); - if (dat->pJSInf[i].szFieldName) - free(dat->pJSInf[i].szFieldName); - } - free(dat->pJSInf); - dat->pJSInf=NULL; - } - else EnumChildWindows(GetDlgItem(hwndDlg,IDC_FRAME),DeleteChildWindowsProc,0); - - if ( dat->xNode ) - xi.destroyNode( dat->xNode ); - - SendMessage(GetDlgItem(hwndDlg,IDC_FRAME), WM_SETFONT, (WPARAM) SendMessage( hwndDlg, WM_GETFONT, 0, 0 ),0 ); - dat->nJSInfCount=0; - ShowWindow(GetDlgItem(hwndDlg,IDC_VSCROLL),SW_HIDE); - SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,TranslateT("Select/type search service URL above and press <Go>")); - //unlock -} - -static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData * dat) -{ - HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); - HWND hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); - RECT rc; - GetClientRect( hFrame, &rc ); - GetClientRect( hFrame, &dat->frameRect ); - dat->frameHeight = rc.bottom-rc.top; - if ( dat->frameHeight < dat->CurrentHeight) { - ShowWindow( hwndScroll, SW_SHOW ); - EnableWindow( hwndScroll, TRUE ); - } - else ShowWindow( hwndScroll, SW_HIDE ); - - SetScrollRange( hwndScroll, SB_CTL, 0, dat->CurrentHeight-dat->frameHeight, FALSE ); -} - -int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat) -{ - TCHAR szServerName[100]; - EnableWindow(GetDlgItem(hwndDlg, IDC_GO),FALSE); - GetDlgItemText(hwndDlg,IDC_SERVER,szServerName,SIZEOF(szServerName)); - dat->CurrentHeight = 0; - dat->curPos = 0; - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); - - JabberSearchFreeData( hwndDlg, dat ); - JabberSearchRefreshFrameScroll( hwndDlg, dat ); - - SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server")); - - if ( !m_bJabberOnline ) - return 0; - - searchHandleDlg = hwndDlg; - - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_GETSEARCHFIELDS, &CJabberProto::OnIqResultGetSearchFields ); - m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szServerName ) << XQUERY( _T("jabber:iq:search"))); - return iqId; -} - -static void JabberSearchAddUrlToRecentCombo(HWND hwndDlg, const TCHAR* szAddr) -{ - int lResult = SendMessage( GetDlgItem(hwndDlg,IDC_SERVER), (UINT) CB_FINDSTRING, 0, (LPARAM)szAddr ); - if ( lResult == -1 ) - SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )szAddr ); -} - -void CJabberProto::SearchDeleteFromRecent( const TCHAR* szAddr, BOOL deleteLastFromDB ) -{ - DBVARIANT dbv; - char key[30]; - //search in recent - for ( int i=0; i<10; i++ ) { - sprintf(key,"RecentlySearched_%d",i); - if ( !JGetStringT( NULL, key, &dbv )) { - if ( !_tcsicmp( szAddr, dbv.ptszVal )) { - JFreeVariant( &dbv ); - for ( int j=i; j<10; j++ ) { - sprintf( key, "RecentlySearched_%d", j+1 ); - if ( !JGetStringT( NULL, key, &dbv )) { - sprintf(key,"RecentlySearched_%d",j); - JSetStringT(NULL,key,dbv.ptszVal); - JFreeVariant( &dbv ); - } - else { - if ( deleteLastFromDB ) { - sprintf(key,"RecentlySearched_%d",j); - JDeleteSetting(NULL,key); - } - break; - } } - break; - } - else JFreeVariant( &dbv ); -} } } - -void CJabberProto::SearchAddToRecent( const TCHAR* szAddr, HWND hwndDialog ) -{ - DBVARIANT dbv; - char key[30]; - SearchDeleteFromRecent( szAddr ); - for ( int j=9; j > 0; j-- ) { - sprintf( key, "RecentlySearched_%d", j-1 ); - if ( !JGetStringT( NULL, key, &dbv )) { - sprintf(key,"RecentlySearched_%d",j); - JSetStringT(NULL,key,dbv.ptszVal); - JFreeVariant(&dbv); - } } - - sprintf( key, "RecentlySearched_%d", 0 ); - JSetStringT( NULL, key, szAddr ); - if ( hwndDialog ) - JabberSearchAddUrlToRecentCombo( hwndDialog, szAddr ); -} - -static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - JabberSearchData* dat = ( JabberSearchData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - switch ( msg ) { - case WM_INITDIALOG: - { - TranslateDialogDefault(hwndDlg); - dat = ( JabberSearchData * )mir_alloc( sizeof( JabberSearchData )); - memset( dat, 0, sizeof( JabberSearchData )); - dat->ppro = ( CJabberProto* )lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)dat ); - - /* Server Combo box */ - char szServerName[100]; - if ( dat->ppro->JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) - strcpy( szServerName, "users.jabber.org" ); - SetDlgItemTextA(hwndDlg,IDC_SERVER,szServerName); - SendDlgItemMessageA(hwndDlg,IDC_SERVER,CB_ADDSTRING,0,(LPARAM)szServerName); - //TO DO: Add Transports here - int i, transpCount = dat->ppro->m_lstTransports.getCount(); - for ( i=0; i < transpCount; i++ ) { - TCHAR* szTransp = dat->ppro->m_lstTransports[i]; - if ( szTransp ) - JabberSearchAddUrlToRecentCombo(hwndDlg, szTransp ); - } - - DBVARIANT dbv; - char key[30]; - for ( i=0; i < 10; i++ ) { - sprintf(key,"RecentlySearched_%d",i); - if ( !dat->ppro->JGetStringT( NULL, key, &dbv )) { - JabberSearchAddUrlToRecentCombo(hwndDlg, dbv.ptszVal ); - JFreeVariant( &dbv ); - } } - - //TO DO: Add 4 recently used - dat->lastRequestIq = dat->ppro->SearchRenewFields(hwndDlg,dat); - } - return TRUE; - - case WM_COMMAND: - if ( LOWORD(wParam) == IDC_SERVER ) { - switch ( HIWORD( wParam )) { - case CBN_SETFOCUS: - PostMessage(GetParent(hwndDlg),WM_COMMAND, MAKEWPARAM(0,EN_SETFOCUS), (LPARAM)hwndDlg); - return TRUE; - - case CBN_EDITCHANGE: - EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); - return TRUE; - - case CBN_EDITUPDATE: - JabberSearchFreeData(hwndDlg, dat); - EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); - return TRUE; - - case CBN_SELENDOK: - EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); - PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_GO,BN_CLICKED),0); - return TRUE; - } - } - else if ( LOWORD(wParam) == IDC_GO && HIWORD(wParam) == BN_CLICKED ) { - dat->ppro->SearchRenewFields( hwndDlg, dat ); - return TRUE; - } - break; - - case WM_SIZE: - { - //Resize IDC_FRAME to take full size - RECT rcForm; - GetWindowRect(hwndDlg, &rcForm); - RECT rcFrame; - GetWindowRect( GetDlgItem(hwndDlg, IDC_FRAME), &rcFrame ); - rcFrame.bottom = rcForm.bottom; - SetWindowPos(GetDlgItem(hwndDlg,IDC_FRAME),NULL,0,0,rcFrame.right-rcFrame.left,rcFrame.bottom-rcFrame.top,SWP_NOZORDER|SWP_NOMOVE); - GetWindowRect(GetDlgItem(hwndDlg,IDC_VSCROLL), &rcForm); - SetWindowPos(GetDlgItem(hwndDlg,IDC_VSCROLL),NULL,0,0,rcForm.right-rcForm.left,rcFrame.bottom-rcFrame.top,SWP_NOZORDER|SWP_NOMOVE); - JabberSearchRefreshFrameScroll(hwndDlg, dat); - } - return TRUE; - - case WM_USER+11: - { - dat->fSearchRequestIsXForm=TRUE; - dat->xNode = ( HXML )wParam; - JabberFormCreateUI( GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode, &dat->CurrentHeight,TRUE); - ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME), SW_SHOW); - dat->nJSInfCount=1; - return TRUE; - } - case WM_USER+10: - { - Data* MyDat = ( Data* )lParam; - if ( MyDat ) { - dat->fSearchRequestIsXForm = ( BOOL )wParam; - dat->CurrentHeight = JabberSearchAddField(hwndDlg,MyDat); - mir_free( MyDat->Label ); - mir_free( MyDat->Var ); - mir_free( MyDat->defValue ); - free( MyDat ); - } - else - { - JabberSearchRefreshFrameScroll(hwndDlg,dat); - ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - 0, NULL, &( dat->frameRect )); - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); - dat->curPos=0; - } - return TRUE; - } - case WM_MOUSEWHEEL: - { - int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); - if ( zDelta ) { - int nScrollLines=0; - SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,(void*)&nScrollLines,0); - for (int i=0; i<(nScrollLines+1)/2; i++) - SendMessage(hwndDlg,WM_VSCROLL, (zDelta<0)?SB_LINEDOWN:SB_LINEUP,0); - } } - return TRUE; - - case WM_VSCROLL: - { - int pos; - if ( dat != NULL ) { - pos = dat->curPos; - switch ( LOWORD( wParam )) { - case SB_LINEDOWN: - pos += 10; - break; - case SB_LINEUP: - pos -= 10; - break; - case SB_PAGEDOWN: - pos += ( dat->CurrentHeight - 10 ); - break; - case SB_PAGEUP: - pos -= ( dat->CurrentHeight - 10 ); - break; - case SB_THUMBTRACK: - pos = HIWORD( wParam ); - break; - } - if ( pos > ( dat->CurrentHeight - dat->frameHeight )) - pos = dat->CurrentHeight - dat->frameHeight; - if ( pos < 0 ) - pos = 0; - if ( dat->curPos != pos ) { - ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL , &( dat->frameRect )); - SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); - RECT Invalid=dat->frameRect; - if (dat->curPos - pos >0) - Invalid.bottom=Invalid.top+(dat->curPos - pos); - else - Invalid.top=Invalid.bottom+(dat->curPos - pos); - - RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_UPDATENOW |RDW_ALLCHILDREN); - dat->curPos = pos; - } } } - return TRUE; - - case WM_DESTROY: - JabberSearchFreeData( hwndDlg, dat ); - JabberFormDestroyUI( GetDlgItem( hwndDlg, IDC_FRAME )); - mir_free( dat ); - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0 ); - return TRUE; - } - return FALSE; -} - -HWND __cdecl CJabberProto::CreateExtendedSearchUI( HWND parent ) -{ - TCHAR szServer[128]; - if (parent && hInst && (!JGetStringT(NULL, "LoginServer", szServer, SIZEOF(szServer)) || _tcsicmp(szServer, _T("S.ms")))) - return CreateDialogParam( hInst, MAKEINTRESOURCE(IDD_SEARCHUSER), parent, JabberSearchAdvancedDlgProc, ( LPARAM )this ); - - return 0; // Failure -} - -////////////////////////////////////////////////////////////////////////// -// The function formats request to server - -HWND __cdecl CJabberProto::SearchAdvanced( HWND hwndDlg ) -{ - if ( !m_bJabberOnline || !hwndDlg ) - return 0; //error - - JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); - if ( !dat ) - return 0; //error - - // check if server connected (at least one field exists) - if ( dat->nJSInfCount == 0 ) - return 0; - - // formating request - BOOL fRequestNotEmpty=FALSE; - - // get server name - TCHAR szServerName[100]; - GetDlgItemText( hwndDlg, IDC_SERVER, szServerName, SIZEOF( szServerName )); - - // formating query - int iqId = SerialNext(); - XmlNodeIq iq( _T("set"), iqId, szServerName ); - HXML query = iq << XQUERY( _T("jabber:iq:search")); - - if ( m_tszSelectedLang ) - iq << XATTR( _T("xml:lang"), m_tszSelectedLang ); // i'm sure :) - - // next can be 2 cases: - // Forms: XEP-0055 Example 7 - if ( dat->fSearchRequestIsXForm ) { - fRequestNotEmpty=TRUE; - HXML n = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode); - xmlAddChild( query, n ); - xi.destroyNode( n ); - } - else { //and Simple fields: XEP-0055 Example 3 - for ( int i=0; i<dat->nJSInfCount; i++ ) { - TCHAR szFieldValue[100]; - GetWindowText(dat->pJSInf[i].hwndValueItem, szFieldValue, SIZEOF(szFieldValue)); - if ( szFieldValue[0] != _T('\0')) { - xmlAddChild( query, dat->pJSInf[i].szFieldName, szFieldValue ); - fRequestNotEmpty=TRUE; - } } } - - if ( fRequestNotEmpty ) { - // register search request result handler - IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultAdvancedSearch ); - // send request - m_ThreadInfo->send( iq ); - return ( HWND )iqId; - } - return 0; -} diff --git a/protocols/JabberG/jabber_search.h b/protocols/JabberG/jabber_search.h deleted file mode 100644 index 7450b652d1..0000000000 --- a/protocols/JabberG/jabber_search.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Artem Shpynov - -Module implements a search according to XEP-0055: Jabber Search -http://www.xmpp.org/extensions/xep-0055.html - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -typedef struct _tagJabberSearchFieldsInfo -{ - TCHAR * szFieldName; - TCHAR * szFieldCaption; - HWND hwndCaptionItem; - HWND hwndValueItem; -} JabberSearchFieldsInfo; - -typedef struct _tagJabberSearchData -{ - struct CJabberProto* ppro; - JabberSearchFieldsInfo * pJSInf; - HXML xNode; - int nJSInfCount; - int lastRequestIq; - int CurrentHeight; - int curPos; - int frameHeight; - RECT frameRect; - BOOL fSearchRequestIsXForm; - -}JabberSearchData; - -typedef struct tag_Data -{ - TCHAR *Label; - TCHAR * Var; - TCHAR * defValue; - BOOL bHidden; - BOOL bReadOnly; - int Order; - -} Data; - - -typedef struct tagJABBER_CUSTOMSEARCHRESULTS -{ - size_t nSize; - int nFieldCount; - TCHAR ** pszFields; - JABBER_SEARCH_RESULT jsr; -}JABBER_CUSTOMSEARCHRESULTS; - -static HWND searchHandleDlg=NULL; - -//local functions declarations -static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam); -static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat ); -static void JabberIqResultGetSearchFields( HXML iqNode, void *userdata ); -static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat); -static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData * dat); -static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); -static void JabberSearchDeleteFromRecent(TCHAR * szAddr,BOOL deleteLastFromDB); -void SearchAddToRecent(TCHAR * szAddr, HWND hwnd); - -// Implementation of MAP class (the list -template <typename _KEYTYPE , int (*COMPARATOR)(_KEYTYPE*, _KEYTYPE*) > -class UNIQUE_MAP -{ - -public: - typedef _KEYTYPE* (*COPYKEYPROC)(_KEYTYPE*); - typedef void (*DESTROYKEYPROC)(_KEYTYPE*); - -private: - typedef struct _tagRECORD - { - _tagRECORD(_KEYTYPE * key, TCHAR * value=NULL) { _key=key; _value=value; _order=0; _destroyKeyProc=NULL; } - ~_tagRECORD() - { - if (_key && _destroyKeyProc) - _destroyKeyProc(_key); - _key=NULL; - _destroyKeyProc=NULL; - } - _KEYTYPE *_key; - TCHAR * _value; - int _order; - DESTROYKEYPROC _destroyKeyProc; - } _RECORD; - - int _nextOrder; - LIST<_RECORD> _Records; - - static int _KeysEqual( const _RECORD* p1, const _RECORD* p2 ) - { - if (COMPARATOR) - return (int)(COMPARATOR((p1->_key),(p2->_key))); - else - return (int) (p1->_key < p2->_key); - } - - inline int _remove(_RECORD* p) - { - int _itemOrder=p->_order; - if (_Records.remove(p)) - { - delete(p); - _nextOrder--; - for (int i=0; i<_Records.getCount(); i++) - { - _RECORD * temp=_Records[i]; - if (temp && temp->_order>_itemOrder) - temp->_order--; - } - return 1; - } - return 0; - } - inline _RECORD * _getUnorderedRec (int index) - { - for (int i=0; i<_Records.getCount(); i++) - { - _RECORD * rec=_Records[i]; - if (rec->_order==index) return rec; - } - return NULL; - } - -public: - UNIQUE_MAP(int incr):_Records(incr,_KeysEqual) - { - _nextOrder=0; - }; - ~UNIQUE_MAP() - { - _RECORD * record; - int i=0; - while (record=_Records[i++]) delete record; - } - - int insert(_KEYTYPE* Key, TCHAR *Value) - { - _RECORD * rec= new _RECORD(Key,Value); - int index=_Records.getIndex(rec); - if (index<0) - { - if (!_Records.insert(rec)) delete rec; - else - { - index=_Records.getIndex(rec); - rec->_order=_nextOrder++; - } - } - else - { - _Records[index]->_value=Value; - delete rec; - } - return index; - } - int insertCopyKey(_KEYTYPE* Key, TCHAR *Value, _KEYTYPE** _KeyReturn, COPYKEYPROC CopyProc, DESTROYKEYPROC DestroyProc ) - { - _RECORD * rec= new _RECORD(Key,Value); - int index=_Records.getIndex(rec); - if (index<0) - { - _KEYTYPE* newKey=CopyProc(Key); - if (!_Records.insert(rec)) - { - delete rec; - DestroyProc(newKey); - if (_KeyReturn) *_KeyReturn=NULL; - } - else - { - rec->_key=newKey; - rec->_destroyKeyProc=DestroyProc; - index=_Records.getIndex(rec); - rec->_order=_nextOrder++; - if (_KeyReturn) *_KeyReturn=newKey; - } - } - else - { - _Records[index]->_value=Value; - if (_KeyReturn) *_KeyReturn=_Records[index]->_key; - delete rec; - } - return index; - } - inline TCHAR* operator[]( _KEYTYPE* _KEY ) const - { - _RECORD rec(_KEY); - int index=_Records.getIndex(&rec); - _RECORD * rv=_Records[index]; - if (rv) - { - if (rv->_value) - return rv->_value; - else - return _T(""); - } - else - return NULL; - } - inline TCHAR* operator[]( int index ) const - { - _RECORD * rv=_Records[index]; - if (rv) return rv->_value; - else return NULL; - } - inline _KEYTYPE* getKeyName(int index) - { - _RECORD * rv=_Records[index]; - if (rv) return rv->_key; - else return NULL; - } - inline TCHAR * getUnOrdered(int index) - { - _RECORD * rec=_getUnorderedRec(index); - if (rec) return rec->_value; - else return NULL; - } - inline _KEYTYPE * getUnOrderedKeyName(int index) - { - _RECORD * rec=_getUnorderedRec(index); - if (rec) return rec->_key; - else return NULL; - } - inline int getCount() - { - return _Records.getCount(); - } - inline int removeUnOrdered(int index) - { - _RECORD * p=_getUnorderedRec(index); - if (p) return _remove(p); - else return 0; - } - inline int remove(int index) - { - _RECORD * p=_Records[index]; - if (p) return _remove(p); - else return 0; - } - inline int getIndex(_KEYTYPE * key) - { - _RECORD temp(key); - return _Records.getIndex(&temp); - } -}; - -inline int TCharKeyCmp(TCHAR* a, TCHAR* b) -{ - return (int)(_tcsicmp(a,b)); -} diff --git a/protocols/JabberG/jabber_secur.cpp b/protocols/JabberG/jabber_secur.cpp deleted file mode 100644 index c48ded22d6..0000000000 --- a/protocols/JabberG/jabber_secur.cpp +++ /dev/null @@ -1,469 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_secur.h" - -typedef BYTE (WINAPI *GetUserNameExType )( int NameFormat, LPTSTR lpNameBuffer, PULONG nSize ); - - -///////////////////////////////////////////////////////////////////////////////////////// -// ntlm auth - LanServer based authorization - -TNtlmAuth::TNtlmAuth( ThreadData* info, const char* mechanism, const TCHAR* hostname ) : - TJabberAuth( info ) -{ - szName = mechanism; - szHostName = hostname; - - const TCHAR *szProvider; - if ( !strcmp( mechanism, "GSS-SPNEGO" )) - szProvider = _T("Negotiate"); - else if ( !strcmp( mechanism, "GSSAPI" )) - szProvider = _T("GSSAPI"); - else if ( !strcmp( mechanism, "NTLM" )) - szProvider = _T("NTLM"); - else { - bIsValid = false; - return; - } - - TCHAR szSpn[ 1024 ] = _T( "" ); - if ( strcmp( mechanism, "NTLM" )) { - if ( !getSpn( szSpn, SIZEOF( szSpn )) && !strcmp( mechanism, "GSSAPI" )) { - bIsValid = false; - return; - } } - - if (( hProvider = Netlib_InitSecurityProvider2( szProvider, szSpn )) == NULL ) - bIsValid = false; -} - -TNtlmAuth::~TNtlmAuth() -{ - if ( hProvider != NULL ) - Netlib_DestroySecurityProvider( NULL, hProvider ); -} - -bool TNtlmAuth::getSpn( TCHAR* szSpn, size_t dwSpnLen ) -{ - GetUserNameExType myGetUserNameEx = - ( GetUserNameExType )GetProcAddress( GetModuleHandleA( "secur32.dll" ), "GetUserNameExW" ); - - if ( !myGetUserNameEx ) return false; - - TCHAR szFullUserName[128] = _T( "" ); - ULONG szFullUserNameLen = SIZEOF( szFullUserName ); - if (!myGetUserNameEx( 12, szFullUserName, &szFullUserNameLen )) { - szFullUserName[ 0 ] = 0; - szFullUserNameLen = SIZEOF( szFullUserName ); - myGetUserNameEx( 2, szFullUserName, &szFullUserNameLen ); - } - - TCHAR* name = _tcsrchr( szFullUserName, '\\' ); - if ( name ) *name = 0; - else return false; - - if ( szHostName && szHostName[0] ) { - TCHAR *szFullUserNameU = _tcsupr( mir_tstrdup( szFullUserName )); - mir_sntprintf( szSpn, dwSpnLen, _T( "xmpp/%s/%s@%s" ), szHostName, szFullUserName, szFullUserNameU ); - mir_free( szFullUserNameU ); - } else { - const char* connectHost = info->manualHost[0] ? info->manualHost : info->server; - - unsigned long ip = inet_addr( connectHost ); - // Convert host name to FQDN -// PHOSTENT host = (ip == INADDR_NONE) ? gethostbyname( szHost ) : gethostbyaddr(( char* )&ip, 4, AF_INET ); - PHOSTENT host = (ip == INADDR_NONE) ? NULL : gethostbyaddr(( char* )&ip, 4, AF_INET ); - if ( host && host->h_name ) - connectHost = host->h_name; - - TCHAR *connectHostT = mir_a2t( connectHost ); - mir_sntprintf( szSpn, dwSpnLen, _T( "xmpp/%s@%s" ), connectHostT, _tcsupr( szFullUserName )); - mir_free( connectHostT ); - } - - Netlib_Logf( NULL, "SPN: " TCHAR_STR_PARAM, szSpn ); - - - return true; -} - -char* TNtlmAuth::getInitialRequest() -{ - if ( !hProvider ) - return NULL; - - // This generates login method advertisement packet - char* result; - if ( info->password[0] != 0 ) - result = Netlib_NtlmCreateResponse2( hProvider, "", info->username, info->password, &complete ); - else - result = Netlib_NtlmCreateResponse2( hProvider, "", NULL, NULL, &complete ); - - return result; -} - -char* TNtlmAuth::getChallenge( const TCHAR* challenge ) -{ - if ( !hProvider ) - return NULL; - - char *text = ( !lstrcmp( challenge, _T("="))) ? mir_strdup( "" ) : mir_t2a( challenge ), *result; - if ( info->password[0] != 0 ) - result = Netlib_NtlmCreateResponse2( hProvider, text, info->username, info->password, &complete ); - else - result = Netlib_NtlmCreateResponse2( hProvider, text, NULL, NULL, &complete ); - - mir_free( text ); - return result; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// md5 auth - digest-based authorization - -TMD5Auth::TMD5Auth( ThreadData* info ) : - TJabberAuth( info ), - iCallCount( 0 ) -{ - szName = "DIGEST-MD5"; -} - -TMD5Auth::~TMD5Auth() -{ -} - -char* TMD5Auth::getChallenge( const TCHAR* challenge ) -{ - if ( iCallCount > 0 ) - return NULL; - - iCallCount++; - - int resultLen; - char* text = JabberBase64DecodeT( challenge, &resultLen ); - - TStringPairs pairs( text ); - const char *realm = pairs["realm"], *nonce = pairs["nonce"]; - - char cnonce[40], tmpBuf[40]; - DWORD digest[4], hash1[4], hash2[4]; - mir_md5_state_t ctx; - - CallService( MS_UTILS_GETRANDOM, sizeof( digest ), ( LPARAM )digest ); - sprintf( cnonce, "%08x%08x%08x%08x", htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); - - char *uname = mir_utf8encodeT( info->username ), - *passw = mir_utf8encodeT( info->password ), - *serv = mir_utf8encode( info->server ); - - mir_md5_init( &ctx ); - mir_md5_append( &ctx, ( BYTE* )uname, (int)strlen( uname )); - mir_md5_append( &ctx, ( BYTE* )":", 1 ); - mir_md5_append( &ctx, ( BYTE* )realm, (int)strlen( realm )); - mir_md5_append( &ctx, ( BYTE* )":", 1 ); - mir_md5_append( &ctx, ( BYTE* )passw, (int)strlen( passw )); - mir_md5_finish( &ctx, ( BYTE* )hash1 ); - - mir_md5_init( &ctx ); - mir_md5_append( &ctx, ( BYTE* )hash1, 16 ); - mir_md5_append( &ctx, ( BYTE* )":", 1 ); - mir_md5_append( &ctx, ( BYTE* )nonce, (int)strlen( nonce )); - mir_md5_append( &ctx, ( BYTE* )":", 1 ); - mir_md5_append( &ctx, ( BYTE* )cnonce, (int)strlen( cnonce )); - mir_md5_finish( &ctx, ( BYTE* )hash1 ); - - mir_md5_init( &ctx ); - mir_md5_append( &ctx, ( BYTE* )"AUTHENTICATE:xmpp/", 18 ); - mir_md5_append( &ctx, ( BYTE* )serv, (int)strlen( serv )); - mir_md5_finish( &ctx, ( BYTE* )hash2 ); - - mir_md5_init( &ctx ); - sprintf( tmpBuf, "%08x%08x%08x%08x", htonl(hash1[0]), htonl(hash1[1]), htonl(hash1[2]), htonl(hash1[3])); - mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); - mir_md5_append( &ctx, ( BYTE* )":", 1 ); - mir_md5_append( &ctx, ( BYTE* )nonce, (int)strlen( nonce )); - sprintf( tmpBuf, ":%08d:", iCallCount ); - mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); - mir_md5_append( &ctx, ( BYTE* )cnonce, (int)strlen( cnonce )); - mir_md5_append( &ctx, ( BYTE* )":auth:", 6 ); - sprintf( tmpBuf, "%08x%08x%08x%08x", htonl(hash2[0]), htonl(hash2[1]), htonl(hash2[2]), htonl(hash2[3])); - mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); - mir_md5_finish( &ctx, ( BYTE* )digest ); - - char* buf = (char*)alloca(8000); - int cbLen = mir_snprintf( buf, 8000, - "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\",nc=%08d," - "qop=auth,digest-uri=\"xmpp/%s\",charset=utf-8,response=%08x%08x%08x%08x", - uname, realm, nonce, cnonce, iCallCount, serv, - htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); - - mir_free( uname ); - mir_free( passw ); - mir_free( serv ); - mir_free( text ); - - return JabberBase64Encode( buf, cbLen ); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// SCRAM-SHA-1 authorization - -void hmac_sha1(mir_sha1_byte_t *md, mir_sha1_byte_t *key, size_t keylen, mir_sha1_byte_t *text, size_t textlen) -{ - const unsigned SHA_BLOCKSIZE = 64; - - unsigned char mdkey[MIR_SHA1_HASH_SIZE]; - unsigned char k_ipad[SHA_BLOCKSIZE], k_opad[SHA_BLOCKSIZE]; - mir_sha1_ctx ctx; - - if (keylen > SHA_BLOCKSIZE) - { - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, key, (int)keylen); - mir_sha1_finish(&ctx, mdkey); - keylen = 20; - key = mdkey; - } - - memcpy(k_ipad, key, keylen); - memcpy(k_opad, key, keylen); - memset(k_ipad+keylen, 0x36, SHA_BLOCKSIZE - keylen); - memset(k_opad+keylen, 0x5c, SHA_BLOCKSIZE - keylen); - - for (unsigned i = 0; i < keylen; i++) - { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, k_ipad, SHA_BLOCKSIZE); - mir_sha1_append(&ctx, text, (int)textlen); - mir_sha1_finish(&ctx, md); - - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, k_opad, SHA_BLOCKSIZE); - mir_sha1_append(&ctx, md, MIR_SHA1_HASH_SIZE); - mir_sha1_finish(&ctx, md); -} - -TScramAuth::TScramAuth( ThreadData* info ) : - TJabberAuth( info ) -{ - szName = "SCRAM-SHA-1"; - cnonce = msg1 = serverSignature = NULL; -} - -TScramAuth::~TScramAuth() -{ - mir_free( cnonce ); - mir_free( msg1 ); - mir_free( serverSignature ); -} - -void TScramAuth::Hi( mir_sha1_byte_t* res , char* passw, size_t passwLen, char* salt, size_t saltLen, int ind ) -{ - mir_sha1_byte_t u[ MIR_SHA1_HASH_SIZE ]; - memcpy( u, salt, saltLen ); *( unsigned* )( u + saltLen ) = htonl( 1 ); saltLen += 4; - memset( res, 0, MIR_SHA1_HASH_SIZE ); - - for (int i = 0; i < ind; i++) - { - hmac_sha1( u, (mir_sha1_byte_t*)passw, passwLen, u, saltLen); - saltLen = sizeof( u ); - - for (unsigned j = 0; j < sizeof( u ); j++) - res[j] ^= u[j]; - } -} - -char* TScramAuth::getChallenge( const TCHAR* challenge ) -{ - int chlLen; - char *chl = JabberBase64DecodeT( challenge, &chlLen ); - - char *r = strstr( chl, "r=" ); if ( !r ) { mir_free( chl ); return NULL; } - char *e = strchr( r, ',' ); if ( e ) *e = 0; - char *snonce = mir_strdup(r + 2); - if ( e ) *e = ','; - - size_t cnlen = strlen( cnonce ); - if (strncmp(cnonce, snonce, cnlen )) { mir_free( chl ); mir_free( snonce ); return NULL; } - - char *s = strstr( chl, "s=" ); if ( !s ) { mir_free( chl ); mir_free( snonce ); return NULL; } - e = strchr( s, ',' ); if ( e ) *e = 0; - int saltLen; - char *salt = JabberBase64Decode( s + 2, &saltLen ); - if ( e ) *e = ','; - - if ( saltLen > 16 ) { - mir_free( salt ); - mir_free( snonce ); - mir_free( chl ); - return NULL; - } - - char *in = strstr( chl, "i=" ); if ( !in ) return NULL; - e = strchr( in, ',' ); if ( e ) *e = 0; - int ind = atoi( in + 2 ); - if ( e ) *e = ','; - - char *passw = mir_utf8encodeT( info->password ); - size_t passwLen = strlen( passw ); - - mir_sha1_byte_t saltedPassw[ MIR_SHA1_HASH_SIZE ]; - Hi( saltedPassw, passw, passwLen, salt, saltLen, ind ); - - mir_free( salt ); - mir_free( passw ); - - mir_sha1_byte_t clientKey[ MIR_SHA1_HASH_SIZE ]; - hmac_sha1( clientKey, saltedPassw, sizeof( saltedPassw ), (mir_sha1_byte_t*)"Client Key", 10 ); - - mir_sha1_byte_t storedKey[ MIR_SHA1_HASH_SIZE ]; - - mir_sha1_ctx ctx; - mir_sha1_init( &ctx ); - mir_sha1_append( &ctx, clientKey, MIR_SHA1_HASH_SIZE ); - mir_sha1_finish( &ctx, storedKey ); - - char authmsg[4096]; - int authmsgLen = mir_snprintf( authmsg, sizeof( authmsg ), "%s,%s,c=biws,r=%s", msg1, chl, snonce); - - mir_sha1_byte_t clientSig[ MIR_SHA1_HASH_SIZE ]; - hmac_sha1( clientSig, storedKey, sizeof( storedKey ), (mir_sha1_byte_t*)authmsg, authmsgLen); - - mir_sha1_byte_t clientProof[ MIR_SHA1_HASH_SIZE ]; - for (unsigned j = 0; j < sizeof( clientKey ); j++) - clientProof[j] = clientKey[j] ^ clientSig[j]; - - /* Calculate the server signature */ - mir_sha1_byte_t serverKey[ MIR_SHA1_HASH_SIZE ]; - hmac_sha1( serverKey, saltedPassw, sizeof( saltedPassw ), (mir_sha1_byte_t*)"Server Key", 10 ); - - mir_sha1_byte_t srvSig[ MIR_SHA1_HASH_SIZE ]; - hmac_sha1( srvSig, serverKey, sizeof( serverKey ), (mir_sha1_byte_t*)authmsg, authmsgLen); - serverSignature = JabberBase64Encode(( char* )srvSig, sizeof( srvSig )); - - char buf[4096]; - char *encproof = JabberBase64Encode(( char* )clientProof, sizeof( clientProof )); - int cbLen = mir_snprintf( buf, sizeof( buf ), "c=biws,r=%s,p=%s", snonce, encproof ); - - mir_free( encproof ); - mir_free( snonce ); - mir_free( chl ); - - return JabberBase64Encode( buf, cbLen ); -} - -char* TScramAuth::getInitialRequest() -{ - char *uname = mir_utf8encodeT( info->username ), - *serv = mir_utf8encode( info->server ); - - unsigned char nonce[24]; - CallService( MS_UTILS_GETRANDOM, sizeof(nonce), ( LPARAM )nonce ); - cnonce = JabberBase64Encode(( char* )nonce, sizeof( nonce )); - - char buf[4096]; - int cbLen = mir_snprintf( buf, sizeof( buf ), "n,,n=%s@%s,r=%s", uname, serv, cnonce ); - msg1 = mir_strdup( buf + 3 ); - - mir_free( serv ); - mir_free( uname ); - - return JabberBase64Encode( buf, cbLen ); -} - -bool TScramAuth::validateLogin( const TCHAR* challenge ) -{ - int chlLen; - char* chl = JabberBase64DecodeT( challenge, &chlLen ); - bool res = chl && strncmp( chl + 2, serverSignature, chlLen - 2 ) == 0; - mir_free( chl ); - - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// plain auth - the most simple one - -TPlainAuth::TPlainAuth( ThreadData* info, bool old ) : - TJabberAuth( info ) -{ - szName = "PLAIN"; - bOld = old; -} - -TPlainAuth::~TPlainAuth() -{ -} - -char* TPlainAuth::getInitialRequest() -{ - char *uname = mir_utf8encodeT( info->username ), - *passw = mir_utf8encodeT( info->password ); - - size_t size = 2 * strlen( uname ) + strlen( passw ) + strlen( info->server ) + 4; - char *toEncode = ( char* )alloca( size ); - if ( bOld ) - size = mir_snprintf( toEncode, size, "%s@%s%c%s%c%s", uname, info->server, 0, uname, 0, passw ); - else - size = mir_snprintf( toEncode, size, "%c%s%c%s", 0, uname, 0, passw ); - - mir_free( uname ); - mir_free( passw ); - - return JabberBase64Encode( toEncode, (int)size ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// basic type - -TJabberAuth::TJabberAuth( ThreadData* pInfo ) : - bIsValid( true ), - szName( NULL ), - info( pInfo ) -{ -} - -TJabberAuth::~TJabberAuth() -{ -} - -char* TJabberAuth::getInitialRequest() -{ - return NULL; -} - -char* TJabberAuth::getChallenge( const TCHAR* ) -{ - return NULL; -} - -bool TJabberAuth::validateLogin( const TCHAR* ) -{ - return true; -} - diff --git a/protocols/JabberG/jabber_secur.h b/protocols/JabberG/jabber_secur.h deleted file mode 100644 index 0c3287b88d..0000000000 --- a/protocols/JabberG/jabber_secur.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -// basic class - provides interface for various Jabber auth - -class TJabberAuth -{ - -protected: bool bIsValid; - const char* szName; - unsigned complete; - ThreadData* info; - -public: - TJabberAuth( ThreadData* ); - virtual ~TJabberAuth(); - - virtual char* getInitialRequest(); - virtual char* getChallenge( const TCHAR* challenge ); - virtual bool validateLogin( const TCHAR* challenge ); - - inline const char* getName() const - { return szName; - } - - inline bool isValid() const - { return bIsValid; - } -}; - -// plain auth - the most simple one - -class TPlainAuth : public TJabberAuth -{ - typedef TJabberAuth CSuper; - - bool bOld; - - -public: TPlainAuth( ThreadData*, bool ); - virtual ~TPlainAuth(); - - virtual char* getInitialRequest(); -}; - -// md5 auth - digest-based authorization - -class TMD5Auth : public TJabberAuth -{ - typedef TJabberAuth CSuper; - - int iCallCount; -public: - TMD5Auth( ThreadData* ); - virtual ~TMD5Auth(); - - virtual char* getChallenge( const TCHAR* challenge ); -}; - -class TScramAuth : public TJabberAuth -{ - typedef TJabberAuth CSuper; - - char *cnonce, *msg1, *serverSignature; -public: - TScramAuth( ThreadData* ); - virtual ~TScramAuth(); - - virtual char* getInitialRequest(); - virtual char* getChallenge( const TCHAR* challenge ); - virtual bool validateLogin( const TCHAR* challenge ); - - void Hi( mir_sha1_byte_t* res , char* passw, size_t passwLen, char* salt, size_t saltLen, int ind ); -}; - -// ntlm auth - LanServer based authorization - -class TNtlmAuth : public TJabberAuth -{ - typedef TJabberAuth CSuper; - - HANDLE hProvider; - const TCHAR *szHostName; -public: - TNtlmAuth( ThreadData*, const char* mechanism, const TCHAR* hostname = NULL ); - virtual ~TNtlmAuth(); - - virtual char* getInitialRequest(); - virtual char* getChallenge( const TCHAR* challenge ); - - bool getSpn( TCHAR* szSpn, size_t dwSpnLen ); -}; diff --git a/protocols/JabberG/jabber_send_manager.cpp b/protocols/JabberG/jabber_send_manager.cpp deleted file mode 100644 index b37b1d2f09..0000000000 --- a/protocols/JabberG/jabber_send_manager.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_send_manager.h" - -BOOL CJabberSendManager::FillPermanentHandlers() -{ - return TRUE; -} - -BOOL CJabberSendManager::HandleSendPermanent(HXML node, ThreadData *pThreadData) -{ - BOOL bStopHandling = FALSE; - Lock(); - CJabberSendPermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo && !bStopHandling ) { - CJabberSendInfo sendInfo; - sendInfo.m_pUserData = pInfo->m_pUserData; - - if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &sendInfo)) { - bStopHandling = TRUE; - break; - } - pInfo = pInfo->m_pNext; - } - Unlock(); - - return bStopHandling; -} diff --git a/protocols/JabberG/jabber_send_manager.h b/protocols/JabberG/jabber_send_manager.h deleted file mode 100644 index fe4916686f..0000000000 --- a/protocols/JabberG/jabber_send_manager.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-08 George Hazan -Copyright ( C ) 2007 Maxim Mluhov -Copyright ( C ) 2008-09 Dmitriy Chervov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_SEND_MANAGER_H_ -#define _JABBER_SEND_MANAGER_H_ - -#include "jabber_xml.h" - -struct CJabberProto; -typedef void ( CJabberProto::*JABBER_SEND_PFUNC )( HXML node, void *usedata ); -typedef void ( *SEND_USER_DATA_FREE_FUNC )( void *pUserData ); - -class CJabberSendInfo; - -typedef BOOL ( CJabberProto::*JABBER_SEND_HANDLER )( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ); - -class CJabberSendInfo -{ -protected: - friend class CJabberSendManager; - JABBER_SEND_HANDLER m_pHandler; - CJabberSendInfo* m_pNext; - -public: - void *m_pUserData; - - CJabberSendInfo() - { - ZeroMemory(this, sizeof(*this)); - } - ~CJabberSendInfo() - { - } - void* GetUserData() - { - return m_pUserData; - } -}; - -class CJabberSendPermanentInfo -{ - friend class CJabberSendManager; - - CJabberSendPermanentInfo* m_pNext; - - JABBER_SEND_HANDLER m_pHandler; - void *m_pUserData; - SEND_USER_DATA_FREE_FUNC m_pUserDataFree; - int m_iPriority; -public: - CJabberSendPermanentInfo() - { - ZeroMemory(this, sizeof(CJabberSendPermanentInfo)); - } - ~CJabberSendPermanentInfo() - { - if ( m_pUserDataFree ) - m_pUserDataFree(m_pUserData); - } -}; - -class CJabberSendManager -{ -protected: - CJabberProto* ppro; - CRITICAL_SECTION m_cs; - CJabberSendPermanentInfo* m_pPermanentHandlers; - -public: - CJabberSendManager( CJabberProto* proto ) - { - InitializeCriticalSection(&m_cs); - m_pPermanentHandlers = NULL; - ppro = proto; - } - ~CJabberSendManager() - { - Lock(); - CJabberSendPermanentInfo *pInfo = m_pPermanentHandlers; - while ( pInfo ) - { - CJabberSendPermanentInfo *pTmp = pInfo->m_pNext; - delete pInfo; - pInfo = pTmp; - } - m_pPermanentHandlers = NULL; - Unlock(); - DeleteCriticalSection(&m_cs); - } - BOOL Start() - { - return TRUE; - } - BOOL Shutdown() - { - return TRUE; - } - void Lock() - { - EnterCriticalSection(&m_cs); - } - void Unlock() - { - LeaveCriticalSection(&m_cs); - } - CJabberSendPermanentInfo* AddPermanentHandler(JABBER_SEND_HANDLER pHandler, void *pUserData = NULL, SEND_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) - { - CJabberSendPermanentInfo* pInfo = new CJabberSendPermanentInfo(); - if (!pInfo) - return NULL; - - pInfo->m_pHandler = pHandler; - pInfo->m_pUserData = pUserData; - pInfo->m_pUserDataFree = pUserDataFree; - pInfo->m_iPriority = iPriority; - - Lock(); - if (!m_pPermanentHandlers) - m_pPermanentHandlers = pInfo; - else - { - if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { - pInfo->m_pNext = m_pPermanentHandlers; - m_pPermanentHandlers = pInfo; - } else - { - CJabberSendPermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) - pTmp = pTmp->m_pNext; - pInfo->m_pNext = pTmp->m_pNext; - pTmp->m_pNext = pInfo; - } - } - Unlock(); - - return pInfo; - } - BOOL DeletePermanentHandler(CJabberSendPermanentInfo *pInfo) - { // returns TRUE when pInfo found, or FALSE otherwise - Lock(); - if (!m_pPermanentHandlers) - { - Unlock(); - return FALSE; - } - if (m_pPermanentHandlers == pInfo) // check first item - { - m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } else - { - CJabberSendPermanentInfo* pTmp = m_pPermanentHandlers; - while (pTmp->m_pNext) - { - if (pTmp->m_pNext == pInfo) - { - pTmp->m_pNext = pTmp->m_pNext->m_pNext; - delete pInfo; - Unlock(); - return TRUE; - } - pTmp = pTmp->m_pNext; - } - } - Unlock(); - return FALSE; - } - BOOL HandleSendPermanent(HXML node, ThreadData *pThreadData); - BOOL FillPermanentHandlers(); -}; - -#endif diff --git a/protocols/JabberG/jabber_std.cpp b/protocols/JabberG/jabber_std.cpp deleted file mode 100644 index 099c28b993..0000000000 --- a/protocols/JabberG/jabber_std.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -void CJabberProto::JCreateService( const char* szService, JServiceFunc serviceProc ) -{ - char str[ MAXMODULELABELLENGTH ]; - strcpy( str, m_szModuleName ); - strcat( str, szService ); - ::CreateServiceFunctionObj( str, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this ); -} - -void CJabberProto::JCreateServiceParam( const char* szService, JServiceFuncParam serviceProc, LPARAM lParam ) -{ - char str[ MAXMODULELABELLENGTH ]; - strcpy( str, m_szModuleName ); - strcat( str, szService ); - ::CreateServiceFunctionObjParam( str, ( MIRANDASERVICEOBJPARAM )*( void** )&serviceProc, this, lParam ); -} - -void CJabberProto::JHookEvent( const char* szEvent, JEventFunc handler ) -{ - ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&handler, this ); -} - -HANDLE CJabberProto::JCreateHookableEvent( const char* szService ) -{ - char str[ MAXMODULELABELLENGTH ]; - strcpy( str, m_szModuleName ); - strcat( str, szService ); - return CreateHookableEvent( str ); -} - -void CJabberProto::JForkThread( JThreadFunc pFunc, void *param ) -{ - UINT threadID; - CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, &threadID )); -} - -HANDLE CJabberProto::JForkThreadEx( JThreadFunc pFunc, void *param, UINT* threadID ) -{ - UINT lthreadID; - return ( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, threadID ? threadID : <hreadID); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CJabberProto::JDeleteSetting( HANDLE hContact, const char* valueName ) -{ - DBDeleteContactSetting( hContact, m_szModuleName, valueName ); -} -/* -DWORD CJabberProto::JGetByte( const char* valueName, int parDefltValue ) -{ - return DBGetContactSettingByte( NULL, m_szModuleName, valueName, parDefltValue ); -} -*/ -DWORD CJabberProto::JGetByte( HANDLE hContact, const char* valueName, int parDefltValue ) -{ - return DBGetContactSettingByte( hContact, m_szModuleName, valueName, parDefltValue ); -} - -char* __stdcall JGetContactName( HANDLE hContact ) -{ - return ( char* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact ), 0 ); -} - -DWORD CJabberProto::JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue ) -{ - return DBGetContactSettingDword( hContact, m_szModuleName, valueName, parDefltValue ); -} - -int CJabberProto::JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len ) -{ - DBVARIANT dbv; - dbv.pszVal = dest; - dbv.cchVal = dest_len; - dbv.type = DBVT_ASCIIZ; - - DBCONTACTGETSETTING sVal; - sVal.pValue = &dbv; - sVal.szModule = m_szModuleName; - sVal.szSetting = valueName; - if ( CallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 ) - return 1; - - return ( dbv.type != DBVT_ASCIIZ ); -} - -int CJabberProto::JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv ) -{ - return DBGetContactSettingStringUtf( hContact, m_szModuleName, valueName, dbv ); -} - -int CJabberProto::JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv ) -{ - return DBGetContactSettingTString( hContact, m_szModuleName, valueName, dbv ); -} - -TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName ) -{ - DBVARIANT dbv = {0}; - if (JGetStringT(hContact, valueName, &dbv)) - return NULL; - - TCHAR *res = mir_tstrdup(dbv.ptszVal); - JFreeVariant(&dbv); - return res; -} - -TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName, TCHAR *&out ) -{ - return out = JGetStringT( hContact, valueName ); -} - -TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName, TCHAR *buf, int size ) -{ - DBVARIANT dbv = {0}; - if (JGetStringT(hContact, valueName, &dbv)) - return NULL; - - lstrcpyn(buf, dbv.ptszVal, size); - JFreeVariant(&dbv); - return buf; -} - -WORD CJabberProto::JGetWord( HANDLE hContact, const char* valueName, int parDefltValue ) -{ - return DBGetContactSettingWord( hContact, m_szModuleName, valueName, parDefltValue ); -} - -void __fastcall JFreeVariant( DBVARIANT* dbv ) -{ - DBFreeVariant( dbv ); -} - -int CJabberProto::JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam ) -{ - // clear saved passowrd on login error. ugly hack, but at least this is centralized - if (type == ACKTYPE_LOGIN && (lParam == LOGINERR_WRONGPASSWORD || lParam == LOGINERR_BADUSERID)) - *m_savedPassword = 0; - - ACKDATA ack = {0}; - ack.cbSize = sizeof( ACKDATA ); - ack.szModule = m_szModuleName; - ack.hContact = hContact; - ack.type = type; - ack.result = result; - ack.hProcess = hProcess; - ack.lParam = lParam; - return CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack ); -} -/* -DWORD CJabberProto::JSetByte( const char* valueName, int parValue ) -{ - return DBWriteContactSettingByte( NULL, m_szModuleName, valueName, parValue ); -} -*/ -DWORD CJabberProto::JSetByte( HANDLE hContact, const char* valueName, int parValue ) -{ - return DBWriteContactSettingByte( hContact, m_szModuleName, valueName, parValue ); -} - -DWORD CJabberProto::JSetDword( HANDLE hContact, const char* valueName, DWORD parValue ) -{ - return DBWriteContactSettingDword( hContact, m_szModuleName, valueName, parValue ); -} - -DWORD CJabberProto::JSetString( HANDLE hContact, const char* valueName, const char* parValue ) -{ - return DBWriteContactSettingString( hContact, m_szModuleName, valueName, parValue ); -} - -DWORD CJabberProto::JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue ) -{ - return DBWriteContactSettingTString( hContact, m_szModuleName, valueName, parValue ); -} - -DWORD CJabberProto::JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue ) -{ - return DBWriteContactSettingStringUtf( hContact, m_szModuleName, valueName, parValue ); -} - -DWORD CJabberProto::JSetWord( HANDLE hContact, const char* valueName, int parValue ) -{ - return DBWriteContactSettingWord( hContact, m_szModuleName, valueName, parValue ); -} - -char* __fastcall JTranslate( const char* str ) -{ - return Translate( str ); -} - -// save/load crypted strings -void __forceinline sttCryptString(char *str) -{ - for (;*str; ++str) - { - const char c = *str ^ 0xc3; - if (c) *str = c; - } -} - -TCHAR* CJabberProto::JGetStringCrypt( HANDLE hContact, char* valueName ) -{ - DBVARIANT dbv; - - if (DBGetContactSettingString( hContact, m_szModuleName, valueName, &dbv )) - return NULL; - - sttCryptString(dbv.pszVal); - WCHAR *res = mir_utf8decodeW(dbv.pszVal); - - - DBFreeVariant(&dbv); - return res; -} - -DWORD CJabberProto::JSetStringCrypt( HANDLE hContact, char* valueName, const TCHAR* parValue ) -{ - char *tmp = mir_utf8encodeT(parValue); - sttCryptString(tmp); - DWORD res = JSetString( hContact, valueName, tmp ); - mir_free(tmp); - return res; -} diff --git a/protocols/JabberG/jabber_svc.cpp b/protocols/JabberG/jabber_svc.cpp deleted file mode 100644 index 6344751ead..0000000000 --- a/protocols/JabberG/jabber_svc.cpp +++ /dev/null @@ -1,1138 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#include <fcntl.h> -#include <io.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_caps.h" -#include "m_file.h" -#include "m_addcontact.h" -#include "jabber_disco.h" -#include "m_proto_listeningto.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// GetMyAwayMsg - obtain the current away message - -INT_PTR __cdecl CJabberProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam) -{ - TCHAR *szStatus = NULL; - INT_PTR nRetVal = 0; - - EnterCriticalSection( &m_csModeMsgMutex ); - switch ( wParam ? (int)wParam : m_iStatus ) { - case ID_STATUS_ONLINE: - szStatus = m_modeMsgs.szOnline; - break; - case ID_STATUS_AWAY: - case ID_STATUS_ONTHEPHONE: - case ID_STATUS_OUTTOLUNCH: - szStatus = m_modeMsgs.szAway; - break; - case ID_STATUS_NA: - szStatus = m_modeMsgs.szNa; - break; - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - szStatus = m_modeMsgs.szDnd; - break; - case ID_STATUS_FREECHAT: - szStatus = m_modeMsgs.szFreechat; - break; - default: - // Should not reach here - break; - } - if ( szStatus ) - nRetVal = ( lParam & SGMA_UNICODE ) ? ( INT_PTR )mir_t2u( szStatus ) : ( INT_PTR )mir_t2a( szStatus ); - LeaveCriticalSection( &m_csModeMsgMutex ); - - return nRetVal; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetAvatar - retrieves the file name of my own avatar - -INT_PTR __cdecl CJabberProto::JabberGetAvatar( WPARAM wParam, LPARAM lParam ) -{ - TCHAR* buf = ( TCHAR* )wParam; - int size = ( int )lParam; - - if ( buf == NULL || size <= 0 ) - return -1; - - if ( !m_options.EnableAvatars ) - return -2; - - GetAvatarFileName( NULL, buf, size ); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetAvatarCaps - returns directives how to process avatars - -INT_PTR __cdecl CJabberProto::JabberGetAvatarCaps( WPARAM wParam, LPARAM lParam ) -{ - switch( wParam ) { - case AF_MAXSIZE: - { - POINT* size = (POINT*)lParam; - if ( size ) - size->x = size->y = 96; - } - return 0; - - case AF_PROPORTION: - return PIP_NONE; - - case AF_FORMATSUPPORTED: // Jabber supports avatars of virtually all formats - return 1; - - case AF_ENABLED: - return m_options.EnableAvatars; - } - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetAvatarInfo - retrieves the avatar info - -INT_PTR __cdecl CJabberProto::JabberGetAvatarInfo( WPARAM wParam, LPARAM lParam ) -{ - if ( !m_options.EnableAvatars ) - return GAIR_NOAVATAR; - - PROTO_AVATAR_INFORMATIONT* AI = ( PROTO_AVATAR_INFORMATIONT* )lParam; - - char szHashValue[ MAX_PATH ]; - if ( JGetStaticString( "AvatarHash", AI->hContact, szHashValue, sizeof szHashValue )) { - Log( "No avatar" ); - return GAIR_NOAVATAR; - } - - TCHAR tszFileName[ MAX_PATH ]; - GetAvatarFileName( AI->hContact, tszFileName, SIZEOF(tszFileName)); - _tcsncpy( AI->filename, tszFileName, SIZEOF(AI->filename)); - - AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : JGetByte( AI->hContact, "AvatarType", 0 ); - - if ( ::_taccess( AI->filename, 0 ) == 0 ) { - char szSavedHash[ 256 ]; - if ( !JGetStaticString( "AvatarSaved", AI->hContact, szSavedHash, sizeof szSavedHash )) { - if ( !strcmp( szSavedHash, szHashValue )) { - Log( "Avatar is Ok: %s == %s", szSavedHash, szHashValue ); - return GAIR_SUCCESS; - } } } - - if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL && m_bJabberOnline ) { - DBVARIANT dbv; - if ( !JGetStringT( AI->hContact, "jid", &dbv )) { - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); - if ( item != NULL ) { - BOOL isXVcard = JGetByte( AI->hContact, "AvatarXVcard", 0 ); - - TCHAR szJid[ JABBER_MAX_JID_LEN ]; - if ( item->resourceCount != NULL && !isXVcard ) { - TCHAR *bestResName = ListGetBestClientResourceNamePtr(dbv.ptszVal); - mir_sntprintf( szJid, SIZEOF( szJid ), bestResName?_T("%s/%s"):_T("%s"), dbv.ptszVal, bestResName ); - } - else lstrcpyn( szJid, dbv.ptszVal, SIZEOF( szJid )); - - Log( "Rereading %s for " TCHAR_STR_PARAM, isXVcard ? JABBER_FEAT_VCARD_TEMP : JABBER_FEAT_AVATAR, szJid ); - - int iqId = SerialNext(); - if ( isXVcard ) - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetVCardAvatar ); - else - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetClientAvatar ); - - XmlNodeIq iq( _T("get"), iqId, szJid ); - if ( isXVcard ) - iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); - else - iq << XQUERY( isXVcard ? _T("") : _T(JABBER_FEAT_AVATAR)); - m_ThreadInfo->send( iq ); - - JFreeVariant( &dbv ); - return GAIR_WAITFOR; - } - JFreeVariant( &dbv ); - } - } - - Log( "No avatar" ); - return GAIR_NOAVATAR; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberGetEventTextChatStates - retrieves a chat state description from an event - -INT_PTR __cdecl CJabberProto::OnGetEventTextChatStates( WPARAM, LPARAM lParam ) -{ - DBEVENTGETTEXT *pdbEvent = ( DBEVENTGETTEXT * )lParam; - - INT_PTR nRetVal = 0; - - if ( pdbEvent->dbei->cbBlob > 0 ) { - if ( pdbEvent->dbei->pBlob[0] == JABBER_DB_EVENT_CHATSTATES_GONE ) { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("closed chat session"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("closed chat session")); - } - } - - return nRetVal; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// OnGetEventTextPresence - retrieves presence state description from an event - -INT_PTR __cdecl CJabberProto::OnGetEventTextPresence( WPARAM, LPARAM lParam ) -{ - DBEVENTGETTEXT *pdbEvent = ( DBEVENTGETTEXT * )lParam; - - INT_PTR nRetVal = 0; - - if ( pdbEvent->dbei->cbBlob > 0 ) { - switch ( pdbEvent->dbei->pBlob[0] ) - { - case JABBER_DB_EVENT_PRESENCE_SUBSCRIBE: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent subscription request"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("sent subscription request")); - break; - } - case JABBER_DB_EVENT_PRESENCE_SUBSCRIBED: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("approved subscription request"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("approved subscription request")); - break; - } - case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("declined subscription"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("declined subscription")); - break; - } - case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("declined subscription"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("declined subscription")); - break; - } - case JABBER_DB_EVENT_PRESENCE_ERROR: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent error presence"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("sent error presence")); - break; - } - default: - { - if ( pdbEvent->datatype == DBVT_WCHAR ) - nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent unknown presence type"))); - else if ( pdbEvent->datatype == DBVT_ASCIIZ ) - nRetVal = (INT_PTR)mir_strdup(Translate("sent unknown presence type")); - break; - } - } - } - - return nRetVal; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSetAvatar - sets an avatar without UI - -INT_PTR __cdecl CJabberProto::JabberSetAvatar( WPARAM, LPARAM lParam ) -{ - TCHAR* tszFileName = ( TCHAR* )lParam; - - if ( m_bJabberOnline ) { - SetServerVcard( TRUE, tszFileName ); - SendPresence( m_iDesiredStatus, false ); - } - else if ( tszFileName == NULL || tszFileName[0] == 0 ) { - // Remove avatar - TCHAR tFileName[ MAX_PATH ]; - GetAvatarFileName( NULL, tFileName, MAX_PATH ); - DeleteFile( tFileName ); - - JDeleteSetting( NULL, "AvatarSaved" ); - JDeleteSetting( NULL, "AvatarHash" ); - } - else { - int fileIn = _topen( tszFileName, O_RDWR | O_BINARY, S_IREAD | S_IWRITE ); - if ( fileIn == -1 ) { - mir_free(tszFileName); - return 1; - } - - long dwPngSize = _filelength( fileIn ); - char* pResult = new char[ dwPngSize ]; - if ( pResult == NULL ) { - _close( fileIn ); - mir_free(tszFileName); - return 2; - } - - _read( fileIn, pResult, dwPngSize ); - _close( fileIn ); - - mir_sha1_byte_t digest[MIR_SHA1_HASH_SIZE]; - mir_sha1_ctx sha1ctx; - mir_sha1_init( &sha1ctx ); - mir_sha1_append( &sha1ctx, (mir_sha1_byte_t*)pResult, dwPngSize ); - mir_sha1_finish( &sha1ctx, digest ); - - TCHAR tFileName[ MAX_PATH ]; - GetAvatarFileName( NULL, tFileName, MAX_PATH ); - DeleteFile( tFileName ); - - char buf[MIR_SHA1_HASH_SIZE*2+1]; - for ( int i=0; i<MIR_SHA1_HASH_SIZE; i++ ) - sprintf( buf+( i<<1 ), "%02x", digest[i] ); - - m_options.AvatarType = JabberGetPictureType( pResult ); - - GetAvatarFileName( NULL, tFileName, MAX_PATH ); - FILE* out = _tfopen( tFileName, _T("wb")); - if ( out != NULL ) { - fwrite( pResult, dwPngSize, 1, out ); - fclose( out ); - } - delete[] pResult; - - JSetString( NULL, "AvatarSaved", buf ); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// JabberSetNickname - sets the user nickname without UI - -INT_PTR __cdecl CJabberProto::JabberSetNickname( WPARAM wParam, LPARAM lParam ) -{ - TCHAR *nickname = ( wParam & SMNN_UNICODE ) ? mir_u2t( (WCHAR *) lParam ) : mir_a2t( (char *) lParam ); - - JSetStringT( NULL, "Nick", nickname ); - SetServerVcard( FALSE, _T("")); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// "/SendXML" - Allows external plugins to send XML to the server - -INT_PTR __cdecl CJabberProto::ServiceSendXML( WPARAM, LPARAM lParam ) -{ - return m_ThreadInfo->send( (char*)lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// "/GCGetToolTipText" - gets tooltip text - -static const TCHAR * JabberEnum2AffilationStr[]={ _T("None"), _T("Outcast"), _T("Member"), _T("Admin"), _T("Owner") }; -static const TCHAR * JabberEnum2RoleStr[]={ _T("None"), _T("Visitor"), _T("Participant"), _T("Moderator") }; - -//FIXME Table conversion fast but is not safe -static const TCHAR * JabberEnum2StatusStr[]= { _T("Offline"), _T("Online"), _T("Away"), _T("DND"), - _T("NA"), _T("Occupied"), _T("Free for chat"), - _T("Invisible"), _T("On the phone"), _T("Out to lunch"), - _T("Idle") }; - -static void appendString( bool bIsTipper, const TCHAR* tszTitle, const TCHAR* tszValue, TCHAR* buf, size_t bufSize ) -{ - if ( *buf ) { - const TCHAR* szSeparator = (bIsTipper) ? _T("\n") : ((IsWinVerMEPlus()) ? _T("\r\n") : _T(" | ")); - _tcsncat( buf, szSeparator, bufSize ); - } - - size_t len = _tcslen(buf); - buf += len; - bufSize -= len; - - if ( bIsTipper ) - mir_sntprintf(buf, bufSize, _T("%s%s%s%s"), _T("<b>"), TranslateTS(tszTitle), _T("</b>\t"), tszValue); - else { - TCHAR* p = TranslateTS(tszTitle); - mir_sntprintf(buf, bufSize, _T("%s%s\t%s"), p, _tcslen(p)<=7 ? _T("\t") : _T(""), tszValue); - } -} - -INT_PTR __cdecl CJabberProto::JabberGCGetToolTipText( WPARAM wParam, LPARAM lParam ) -{ - if ( !wParam || !lParam ) - return 0; //room global tooltip not supported yet - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, (TCHAR*)wParam); - if ( item == NULL ) - return 0; //no room found - - JABBER_RESOURCE_STATUS * info = NULL; - for ( int i=0; i < item->resourceCount; i++ ) { - JABBER_RESOURCE_STATUS& p = item->resource[i]; - if ( !lstrcmp( p.resourceName, (TCHAR*)lParam )) { - info = &p; - break; - } } - - if ( info == NULL ) - return 0; //no info found - - // ok process info output will be: - // JID: real@jid/resource or - // Nick: Nickname - // Status: StatusText - // Role: Moderator - // Affiliation: Affiliation - - TCHAR outBuf[2048]; - outBuf[0]=_T('\0'); - - bool bIsTipper = DBGetContactSettingByte(NULL, "Tab_SRMsg", "adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip"); - - //JID: - if ( _tcschr(info->resourceName, _T('@')) != NULL ) - appendString(bIsTipper, _T("JID:"), info->resourceName, outBuf, SIZEOF(outBuf)); - else if (lParam) { //or simple nick - appendString(bIsTipper, _T("Nick:"), (TCHAR*) lParam, outBuf, SIZEOF(outBuf)); - } - - // status - if ( info->status >= ID_STATUS_OFFLINE && info->status <= ID_STATUS_IDLE ) - appendString(bIsTipper, _T("Status:"), TranslateTS(JabberEnum2StatusStr[info->status-ID_STATUS_OFFLINE]), outBuf, SIZEOF(outBuf)); - - // status text - if ( info->statusMessage ) - appendString(bIsTipper, _T("Status text:"), info->statusMessage, outBuf, SIZEOF(outBuf)); - - // Role - appendString(bIsTipper, _T("Role:"), TranslateTS(JabberEnum2RoleStr[info->role]), outBuf, SIZEOF(outBuf)); - - // Affiliation - appendString(bIsTipper, _T("Affiliation:"), TranslateTS(JabberEnum2AffilationStr[info->affiliation]), outBuf, SIZEOF(outBuf)); - - // real jid - if ( info->szRealJid ) - appendString(bIsTipper, _T("Real JID:"), info->szRealJid, outBuf, SIZEOF(outBuf)); - - return (INT_PTR)( outBuf[0] == 0 ? NULL : mir_tstrdup( outBuf )); -} - -// File Association Manager plugin support - -INT_PTR __cdecl CJabberProto::JabberServiceParseXmppURI( WPARAM wParam, LPARAM lParam ) -{ - UNREFERENCED_PARAMETER( wParam ); - - TCHAR *arg = ( TCHAR * )lParam; - if ( arg == NULL ) - return 1; - - TCHAR szUri[ 1024 ]; - mir_sntprintf( szUri, SIZEOF(szUri), _T("%s"), arg ); - - TCHAR *szJid = szUri; - - // skip leading prefix - szJid = _tcschr( szJid, _T( ':' )); - if ( szJid == NULL ) - return 1; - - // skip // - for ( ++szJid; *szJid == _T( '/' ); ++szJid ); - - // empty jid? - if ( !*szJid ) - return 1; - - // command code - TCHAR *szCommand = szJid; - szCommand = _tcschr( szCommand, _T( '?' )); - if ( szCommand ) - *( szCommand++ ) = 0; - - // parameters - TCHAR *szSecondParam = szCommand ? _tcschr( szCommand, _T( ';' )) : NULL; - if ( szSecondParam ) - *( szSecondParam++ ) = 0; - -// TCHAR *szThirdParam = szSecondParam ? _tcschr( szSecondParam, _T( ';' )) : NULL; -// if ( szThirdParam ) -// *( szThirdParam++ ) = 0; - - // no command or message command - if ( !szCommand || ( szCommand && !_tcsicmp( szCommand, _T( "message" )))) { - // message - if ( ServiceExists( MS_MSG_SENDMESSAGE )) { - HANDLE hContact = HContactFromJID( szJid, TRUE ); - TCHAR *szMsgBody = NULL; - if ( !hContact ) - hContact = DBCreateContact( szJid, szJid, TRUE, TRUE ); - if ( !hContact ) - return 1; - - if ( szSecondParam ) { //there are parameters to message - szMsgBody = _tcsstr(szSecondParam, _T( "body=" )); - if ( szMsgBody ) { - szMsgBody += 5; - TCHAR* szDelim = _tcschr( szMsgBody, _T( ';' )); - if ( szDelim ) - szDelim = 0; - JabberHttpUrlDecode( szMsgBody ); - } } - - CallService(MS_MSG_SENDMESSAGE "W",(WPARAM)hContact, (LPARAM)szMsgBody); - - return 0; - } - return 1; - } - else if ( !_tcsicmp( szCommand, _T( "roster" ))) - { - if ( !HContactFromJID( szJid )) { - JABBER_SEARCH_RESULT jsr = { 0 }; - jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); - jsr.hdr.flags = PSR_TCHAR; - jsr.hdr.nick = szJid; - jsr.hdr.id = szJid; - _tcsncpy( jsr.jid, szJid, SIZEOF(jsr.jid) - 1 ); - - ADDCONTACTSTRUCT acs; - acs.handleType = HANDLE_SEARCHRESULT; - acs.szProto = m_szModuleName; - acs.psr = &jsr.hdr; - CallService( MS_ADDCONTACT_SHOW, (WPARAM)NULL, (LPARAM)&acs ); - } - return 0; - } - else if ( !_tcsicmp( szCommand, _T( "join" ))) - { - // chat join invitation - GroupchatJoinRoomByJid( NULL, szJid ); - return 0; - } - else if ( !_tcsicmp( szCommand, _T( "disco" ))) - { - // service discovery request - OnMenuHandleServiceDiscovery( 0, ( LPARAM )szJid ); - return 0; - } - else if ( !_tcsicmp( szCommand, _T( "command" ))) - { - // ad-hoc commands - if ( szSecondParam ) { - if ( !_tcsnicmp( szSecondParam, _T( "node=" ), 5 )) { - szSecondParam += 5; - if (!*szSecondParam) - szSecondParam = NULL; - } - else - szSecondParam = NULL; - } - CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams( this, szJid, szSecondParam ); - ContactMenuRunCommands( 0, ( LPARAM )pStartupParams ); - return 0; - } - else if ( !_tcsicmp( szCommand, _T( "sendfile" ))) - { - // send file - if ( ServiceExists( MS_FILE_SENDFILE )) { - HANDLE hContact = HContactFromJID( szJid, TRUE ); - if ( !hContact ) - hContact = DBCreateContact( szJid, szJid, TRUE, TRUE ); - if ( !hContact ) - return 1; - CallService( MS_FILE_SENDFILE, ( WPARAM )hContact, ( LPARAM )NULL ); - return 0; - } - return 1; - } - - return 1; /* parse failed */ -} - -// XEP-0224 support (Attention/Nudge) -INT_PTR __cdecl CJabberProto::JabberSendNudge( WPARAM wParam, LPARAM ) -{ - if ( !m_bJabberOnline ) - return 0; - - HANDLE hContact = ( HANDLE )wParam; - DBVARIANT dbv; - if ( !JGetStringT( hContact, "jid", &dbv )) { - TCHAR tszJid[ JABBER_MAX_JID_LEN ]; - TCHAR *szResource = ListGetBestClientResourceNamePtr( dbv.ptszVal ); - if ( szResource ) - mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), dbv.ptszVal, szResource ); - else - mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s"), dbv.ptszVal ); - JFreeVariant( &dbv ); - - JabberCapsBits jcb = GetResourceCapabilites( tszJid, FALSE ); - - m_ThreadInfo->send( - XmlNode( _T("message")) << XATTR( _T("type"), _T("headline")) << XATTR( _T("to"), tszJid ) - << XCHILDNS( _T("attention"), - jcb & JABBER_CAPS_ATTENTION ? _T(JABBER_FEAT_ATTENTION) : _T(JABBER_FEAT_ATTENTION_0 ))); - } - return 0; -} - -BOOL CJabberProto::SendHttpAuthReply( CJabberHttpAuthParams *pParams, BOOL bAuthorized ) -{ - if ( !m_bJabberOnline || !pParams || !m_ThreadInfo ) - return FALSE; - - if ( pParams->m_nType == CJabberHttpAuthParams::IQ ) { - XmlNodeIq iq( bAuthorized ? _T("result") : _T("error"), pParams->m_szIqId, pParams->m_szFrom ); - if ( !bAuthorized ) { - iq << XCHILDNS( _T("confirm"), _T(JABBER_FEAT_HTTP_AUTH)) << XATTR( _T("id"), pParams->m_szId ) - << XATTR( _T("method"), pParams->m_szMethod ) << XATTR( _T("url"), pParams->m_szUrl ); - iq << XCHILD( _T("error")) << XATTRI( _T("code"), 401 ) << XATTR( _T("type"), _T("auth")) - << XCHILDNS( _T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); - } - m_ThreadInfo->send( iq ); - } - else if ( pParams->m_nType == CJabberHttpAuthParams::MSG ) { - XmlNode msg( _T("message")); - msg << XATTR( _T("to"), pParams->m_szFrom ); - if ( !bAuthorized ) - msg << XATTR( _T("type"), _T("error")); - if ( pParams->m_szThreadId ) - msg << XCHILD( _T("thread"), pParams->m_szThreadId ); - - msg << XCHILDNS( _T("confirm"), _T(JABBER_FEAT_HTTP_AUTH)) << XATTR( _T("id"), pParams->m_szId ) - << XATTR( _T("method"), pParams->m_szMethod ) << XATTR( _T("url"), pParams->m_szUrl ); - - if ( !bAuthorized ) - msg << XCHILD( _T("error")) << XATTRI( _T("code"), 401 ) << XATTR( _T("type"), _T("auth")) - << XCHILDNS( _T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); - - m_ThreadInfo->send( msg ); - } - else - return FALSE; - - - return TRUE; -} - -class CJabberDlgHttpAuth: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; - -public: - CJabberDlgHttpAuth(CJabberProto *proto, HWND hwndParent, CJabberHttpAuthParams *pParams): - CSuper(proto, IDD_HTTP_AUTH, hwndParent, true), - m_txtInfo(this, IDC_EDIT_HTTP_AUTH_INFO), - m_btnAuth(this, IDOK), - m_btnDeny(this, IDCANCEL), - m_pParams(pParams) - { - m_btnAuth.OnClick = Callback( this, &CJabberDlgHttpAuth::btnAuth_OnClick ); - m_btnDeny.OnClick = Callback( this, &CJabberDlgHttpAuth::btnDeny_OnClick ); - } - - void OnInitDialog() - { - CSuper::OnInitDialog(); - - WindowSetIcon( m_hwnd, m_proto, "openid" ); - - SetDlgItemText(m_hwnd, IDC_TXT_URL, m_pParams->m_szUrl); - SetDlgItemText(m_hwnd, IDC_TXT_FROM, m_pParams->m_szFrom); - SetDlgItemText(m_hwnd, IDC_TXT_ID, m_pParams->m_szId); - SetDlgItemText(m_hwnd, IDC_TXT_METHOD, m_pParams->m_szMethod); - } - - BOOL SendReply( BOOL bAuthorized ) - { - BOOL bRetVal = m_proto->SendHttpAuthReply( m_pParams, bAuthorized ); - m_pParams->Free(); - mir_free( m_pParams ); - m_pParams = NULL; - return bRetVal; - } - - void btnAuth_OnClick(CCtrlButton*) - { - SendReply( TRUE ); - Close(); - } - void btnDeny_OnClick(CCtrlButton*) - { - SendReply( FALSE ); - Close(); - } - - UI_MESSAGE_MAP(CJabberDlgHttpAuth, CSuper); - UI_MESSAGE(WM_CTLCOLORSTATIC, OnCtlColorStatic); - UI_MESSAGE_MAP_END(); - - INT_PTR OnCtlColorStatic(UINT, WPARAM, LPARAM) - { - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - } - -private: - CCtrlEdit m_txtInfo; - CCtrlButton m_btnAuth; - CCtrlButton m_btnDeny; - - CJabberHttpAuthParams *m_pParams; -}; - -// XEP-0070 support (http auth) -INT_PTR __cdecl CJabberProto::OnHttpAuthRequest( WPARAM wParam, LPARAM lParam ) -{ - CLISTEVENT *pCle = (CLISTEVENT *)lParam; - CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)pCle->lParam; - if ( !pParams ) - return 0; - - CJabberDlgHttpAuth *pDlg = new CJabberDlgHttpAuth( this, (HWND)wParam, pParams ); - if ( !pDlg ) { - pParams->Free(); - mir_free( pParams ); - return 0; - } - - pDlg->Show(); - - return 0; -} - - -// Jabber API functions -INT_PTR __cdecl CJabberProto::JabberGetApi( WPARAM wParam, LPARAM lParam ) -{ - IJabberInterface **ji = (IJabberInterface**)lParam; - if ( !ji ) - return -1; - *ji = &m_JabberApi; - return 0; -} - -DWORD CJabberInterface::GetFlags() const -{ - return JIF_UNICODE; -} - -int CJabberInterface::GetVersion() const -{ - return 1; -} - -DWORD CJabberInterface::GetJabberVersion() const -{ - return __VERSION_DWORD; -} - -IJabberSysInterface *CJabberInterface::Sys() const -{ - return &m_psProto->m_JabberSysApi; -} - -IJabberNetInterface *CJabberInterface::Net() const -{ - return &m_psProto->m_JabberNetApi; -} - -int CJabberSysInterface::GetVersion() const -{ - return 1; -} - -int CJabberSysInterface::CompareJIDs( LPCTSTR jid1, LPCTSTR jid2 ) -{ - if ( !jid1 || !jid2 ) return 0; - return JabberCompareJids( jid1, jid2 ); -} - -HANDLE CJabberSysInterface::ContactFromJID( LPCTSTR jid ) -{ - if ( !jid ) return NULL; - return m_psProto->HContactFromJID( jid ); -} - -LPTSTR CJabberSysInterface::ContactToJID( HANDLE hContact ) -{ - return m_psProto->JGetStringT( hContact, m_psProto->JGetByte( hContact, "ChatRoom", 0 ) ? "ChatRoomID" : "jid" ); -} - -LPTSTR CJabberSysInterface::GetBestResourceName( LPCTSTR jid ) -{ - if ( jid == NULL ) - return NULL; - LPCTSTR p = _tcschr( jid, '/' ); - if ( p == NULL ) { - m_psProto->ListLock(); // make sure we allow access to the list only after making mir_tstrdup() of resource name - LPTSTR res = mir_tstrdup( m_psProto->ListGetBestClientResourceNamePtr( jid )); - m_psProto->ListUnlock(); - return res; - } - return mir_tstrdup( jid ); -} - -LPTSTR CJabberSysInterface::GetResourceList( LPCTSTR jid ) -{ - if ( !jid ) - return NULL; - - m_psProto->ListLock(); - JABBER_LIST_ITEM *item = NULL; - if (( item = m_psProto->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) - item = m_psProto->ListGetItemPtr( LIST_ROSTER, jid ); - if ( item == NULL ) { - m_psProto->ListUnlock(); - return NULL; - } - - if ( item->resource == NULL ) { - m_psProto->ListUnlock(); - return NULL; - } - - int i; - int iLen = 1; // 1 for extra zero terminator at the end of the string - // calculate total necessary string length - for ( i=0; i<item->resourceCount; i++ ) { - iLen += lstrlen(item->resource[i].resourceName) + 1; - } - - // allocate memory and fill it - LPTSTR str = (LPTSTR)mir_alloc(iLen * sizeof(TCHAR)); - LPTSTR p = str; - for ( i=0; i<item->resourceCount; i++ ) { - lstrcpy(p, item->resource[i].resourceName); - p += lstrlen(item->resource[i].resourceName) + 1; - } - *p = 0; // extra zero terminator - - m_psProto->ListUnlock(); - return str; -} - -char *CJabberSysInterface::GetModuleName() const -{ - return m_psProto->m_szModuleName; -} - -int CJabberNetInterface::GetVersion() const -{ - return 1; -} - -unsigned int CJabberNetInterface::SerialNext() -{ - return m_psProto->SerialNext(); -} - -int CJabberNetInterface::SendXmlNode( HXML node ) -{ - return m_psProto->m_ThreadInfo->send(node); -} - - -typedef struct -{ - JABBER_HANDLER_FUNC Func; - void *pUserData; -} sHandlerData; - -void CJabberProto::ExternalTempIqHandler( HXML node, CJabberIqInfo *pInfo ) -{ - sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); - d->Func(&m_JabberApi, node, d->pUserData); - free(d); // free IqHandlerData allocated in CJabberNetInterface::AddIqHandler below -} - -BOOL CJabberProto::ExternalIqHandler( HXML node, CJabberIqInfo *pInfo ) -{ - sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); - return d->Func(&m_JabberApi, node, d->pUserData); -} - -BOOL CJabberProto::ExternalMessageHandler( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) -{ - sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); - return d->Func(&m_JabberApi, node, d->pUserData); -} - -BOOL CJabberProto::ExternalPresenceHandler( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ) -{ - sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); - return d->Func(&m_JabberApi, node, d->pUserData); -} - -BOOL CJabberProto::ExternalSendHandler( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ) -{ - sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); - return d->Func(&m_JabberApi, node, d->pUserData); -} - -HJHANDLER CJabberNetInterface::AddPresenceHandler( JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority ) -{ - sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); - d->Func = Func; - d->pUserData = pUserData; - return (HJHANDLER)m_psProto->m_presenceManager.AddPermanentHandler( &CJabberProto::ExternalPresenceHandler, d, free, iPriority ); -} - -HJHANDLER CJabberNetInterface::AddMessageHandler( JABBER_HANDLER_FUNC Func, int iMsgTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority ) -{ - sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); - d->Func = Func; - d->pUserData = pUserData; - return (HJHANDLER)m_psProto->m_messageManager.AddPermanentHandler( &CJabberProto::ExternalMessageHandler, iMsgTypes, 0, szXmlns, FALSE, szTag, d, free, iPriority ); -} - -HJHANDLER CJabberNetInterface::AddIqHandler( JABBER_HANDLER_FUNC Func, int iIqTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority ) -{ - sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); - d->Func = Func; - d->pUserData = pUserData; - return (HJHANDLER)m_psProto->m_iqManager.AddPermanentHandler( &CJabberProto::ExternalIqHandler, iIqTypes, 0, szXmlns, FALSE, szTag, d, free, iPriority ); -} - -HJHANDLER CJabberNetInterface::AddTemporaryIqHandler( JABBER_HANDLER_FUNC Func, int iIqTypes, int iIqId, void *pUserData, DWORD dwTimeout, int iPriority ) -{ - sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); - d->Func = Func; - d->pUserData = pUserData; - CJabberIqInfo* pInfo = m_psProto->m_iqManager.AddHandler( &CJabberProto::ExternalTempIqHandler, iIqTypes, NULL, 0, iIqId, d, iPriority ); - if ( pInfo && dwTimeout > 0 ) - pInfo->SetTimeout( dwTimeout ); - return (HJHANDLER)pInfo; -} - -HJHANDLER CJabberNetInterface::AddSendHandler( JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority ) -{ - sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); - d->Func = Func; - d->pUserData = pUserData; - return (HJHANDLER)m_psProto->m_sendManager.AddPermanentHandler( &CJabberProto::ExternalSendHandler, d, free, iPriority ); -} - -int CJabberNetInterface::RemoveHandler( HJHANDLER hHandler ) -{ - return m_psProto->m_sendManager.DeletePermanentHandler( (CJabberSendPermanentInfo*)hHandler ) || - m_psProto->m_presenceManager.DeletePermanentHandler( (CJabberPresencePermanentInfo*)hHandler ) || - m_psProto->m_messageManager.DeletePermanentHandler( (CJabberMessagePermanentInfo*)hHandler ) || - m_psProto->m_iqManager.DeletePermanentHandler( (CJabberIqPermanentInfo*)hHandler ) || - m_psProto->m_iqManager.DeleteHandler( (CJabberIqInfo*)hHandler ); -} - -JabberFeatCapPairDynamic *CJabberNetInterface::FindFeature(LPCTSTR szFeature) -{ - int i; - for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) - if ( !lstrcmp( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature, szFeature )) - return m_psProto->m_lstJabberFeatCapPairsDynamic[i]; - return NULL; -} - -int CJabberNetInterface::RegisterFeature( LPCTSTR szFeature, LPCTSTR szDescription ) -{ - if ( !szFeature ) { - return false; - } - - // check for this feature in core features, and return false if it's present, to prevent re-registering a core feature - int i; - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) - { - if ( !lstrcmp( g_JabberFeatCapPairs[i].szFeature, szFeature )) - { - return false; - } - } - - m_psProto->ListLock(); - JabberFeatCapPairDynamic *fcp = FindFeature( szFeature ); - if ( !fcp ) { - // if the feature is not registered yet, allocate new bit for it - JabberCapsBits jcb = JABBER_CAPS_OTHER_SPECIAL; // set all bits not included in g_JabberFeatCapPairs - - // set all bits occupied by g_JabberFeatCapPairs - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) - jcb |= g_JabberFeatCapPairs[i].jcbCap; - - // set all bits already occupied by external plugins - for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) - jcb |= m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; - - // Now get first zero bit. The line below is a fast way to do it. If there are no zero bits, it returns 0. - jcb = (~jcb) & (JabberCapsBits)(-(__int64)(~jcb)); - - if ( !jcb ) { - // no more free bits - m_psProto->ListUnlock(); - return false; - } - - LPTSTR szExt = mir_tstrdup( szFeature ); - LPTSTR pSrc, pDst; - for ( pSrc = szExt, pDst = szExt; *pSrc; pSrc++ ) { - // remove unnecessary symbols from szFeature to make the string shorter, and use it as szExt - if ( _tcschr( _T("bcdfghjklmnpqrstvwxz0123456789"), *pSrc )) { - *pDst++ = *pSrc; - } - } - *pDst = 0; - m_psProto->m_clientCapsManager.SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), szExt, jcb ); - - fcp = new JabberFeatCapPairDynamic(); - fcp->szExt = szExt; // will be deallocated along with other values of JabberFeatCapPairDynamic in CJabberProto destructor - fcp->szFeature = mir_tstrdup( szFeature ); - fcp->szDescription = szDescription ? mir_tstrdup( szDescription ) : NULL; - fcp->jcbCap = jcb; - m_psProto->m_lstJabberFeatCapPairsDynamic.insert( fcp ); - } else if ( szDescription ) { - // update description - if ( fcp->szDescription ) - mir_free( fcp->szDescription ); - fcp->szDescription = mir_tstrdup( szDescription ); - } - m_psProto->ListUnlock(); - return true; -} - -int CJabberNetInterface::AddFeatures( LPCTSTR szFeatures ) -{ - if ( !szFeatures ) { - return false; - } - - m_psProto->ListLock(); - BOOL ret = true; - LPCTSTR szFeat = szFeatures; - while ( szFeat[0] ) { - JabberFeatCapPairDynamic *fcp = FindFeature( szFeat ); - // if someone is trying to add one of core features, RegisterFeature() will return false, so we don't have to perform this check here - if ( !fcp ) { - // if the feature is not registered yet - if ( !RegisterFeature( szFeat, NULL )) { - ret = false; - } else { - fcp = FindFeature( szFeat ); // update fcp after RegisterFeature() - } - } - if ( fcp ) { - m_psProto->m_uEnabledFeatCapsDynamic |= fcp->jcbCap; - } else { - ret = false; - } - szFeat += lstrlen( szFeat ) + 1; - } - m_psProto->ListUnlock(); - - if ( m_psProto->m_bJabberOnline ) { - m_psProto->SendPresence( m_psProto->m_iStatus, true ); - } - return ret; -} - -int CJabberNetInterface::RemoveFeatures( LPCTSTR szFeatures ) -{ - if ( !szFeatures ) { - return false; - } - - m_psProto->ListLock(); - BOOL ret = true; - LPCTSTR szFeat = szFeatures; - while ( szFeat[0] ) { - JabberFeatCapPairDynamic *fcp = FindFeature( szFeat ); - if ( fcp ) { - m_psProto->m_uEnabledFeatCapsDynamic &= ~fcp->jcbCap; - } else { - ret = false; // indicate that there was an error removing at least one of the specified features - } - szFeat += lstrlen( szFeat ) + 1; - } - m_psProto->ListUnlock(); - - if ( m_psProto->m_bJabberOnline ) { - m_psProto->SendPresence( m_psProto->m_iStatus, true ); - } - return ret; -} - -LPTSTR CJabberNetInterface::GetResourceFeatures( LPCTSTR jid ) -{ - JabberCapsBits jcb = m_psProto->GetResourceCapabilites( jid, true ); - if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) { - m_psProto->ListLock(); // contents of m_lstJabberFeatCapPairsDynamic must not change from the moment we calculate total length and to the moment when we fill the string - int i; - int iLen = 1; // 1 for extra zero terminator at the end of the string - // calculate total necessary string length - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) { - if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { - iLen += lstrlen( g_JabberFeatCapPairs[i].szFeature ) + 1; - } - } - for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { - if ( jcb & m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { - iLen += lstrlen( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ) + 1; - } - } - - // allocate memory and fill it - LPTSTR str = (LPTSTR)mir_alloc( iLen * sizeof(TCHAR)); - LPTSTR p = str; - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) { - if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { - lstrcpy( p, g_JabberFeatCapPairs[i].szFeature ); - p += lstrlen( g_JabberFeatCapPairs[i].szFeature ) + 1; - } - } - for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { - if ( jcb & m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { - lstrcpy( p, m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ); - p += lstrlen( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ) + 1; - } - } - *p = 0; // extra zero terminator - m_psProto->ListUnlock(); - return str; - } - return NULL; -} diff --git a/protocols/JabberG/jabber_thread.cpp b/protocols/JabberG/jabber_thread.cpp deleted file mode 100644 index d71fd2ab60..0000000000 --- a/protocols/JabberG/jabber_thread.cpp +++ /dev/null @@ -1,2160 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#include <windns.h> // requires Windows Platform SDK - -#include "jabber_list.h" -#include "jabber_iq.h" -#include "jabber_secur.h" -#include "jabber_caps.h" -#include "jabber_privacy.h" -#include "jabber_rc.h" -#include "jabber_proto.h" - -#ifndef DNS_TYPE_SRV -#define DNS_TYPE_SRV 0x0021 -#endif - -// <iq/> identification number for various actions -// for JABBER_REGISTER thread -int iqIdRegGetReg; -int iqIdRegSetReg; - -// XML Console -#define JCPF_IN 0x01UL -#define JCPF_OUT 0x02UL -#define JCPF_ERROR 0x04UL - -//extern int bSecureIM; -static VOID CALLBACK JabberDummyApcFunc( DWORD_PTR ) -{ - return; -} - -struct JabberPasswordDlgParam -{ - CJabberProto* pro; - - BOOL saveOnlinePassword; - WORD dlgResult; - TCHAR onlinePassword[128]; - HANDLE hEventPasswdDlg; - TCHAR* ptszJid; -}; - -static INT_PTR CALLBACK JabberPasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JabberPasswordDlgParam* param = (JabberPasswordDlgParam*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - TranslateDialogDefault( hwndDlg ); - { - param = (JabberPasswordDlgParam*)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - TCHAR text[512]; - mir_sntprintf( text, SIZEOF(text), _T("%s %s"), TranslateT( "Enter password for" ), ( TCHAR* )param->ptszJid ); - SetDlgItemText( hwndDlg, IDC_JID, text ); - - int bSavePassword = param->pro->JGetByte( NULL, "SaveSessionPassword", 0 ); - CheckDlgButton( hwndDlg, IDC_SAVEPASSWORD, ( bSavePassword ) ? BST_CHECKED : BST_UNCHECKED ); - } - return TRUE; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDOK: - param->saveOnlinePassword = IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD ); - param->pro->JSetByte( NULL, "SaveSessionPassword", param->saveOnlinePassword ); - - GetDlgItemText( hwndDlg, IDC_PASSWORD, param->onlinePassword, SIZEOF( param->onlinePassword )); - // Fall through - case IDCANCEL: - param->dlgResult = LOWORD( wParam ); - SetEvent( param->hEventPasswdDlg ); - DestroyWindow( hwndDlg ); - return TRUE; - } - break; - } - - return FALSE; -} - -static VOID CALLBACK JabberPasswordCreateDialogApcProc( void* param ) -{ - CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_PASSWORD ), NULL, JabberPasswordDlgProc, ( LPARAM )param ); -} - -static VOID CALLBACK JabberOfflineChatWindows( void* param ) -{ - CJabberProto* ppro = ( CJabberProto* )param; - GCDEST gcd = { ppro->m_szModuleName, NULL, GC_EVENT_CONTROL }; - GCEVENT gce = { 0 }; - gce.cbSize = sizeof(GCEVENT); - gce.pDest = &gcd; - CallService( MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Jabber keep-alive thread - -void CJabberProto::OnPingReply( HXML, CJabberIqInfo* pInfo ) -{ - if ( !pInfo ) - return; - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_FAIL ) { - // disconnect because of timeout - m_ThreadInfo->send( "</stream:stream>" ); - m_ThreadInfo->shutdown(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -typedef DNS_STATUS (WINAPI *DNSQUERYA)(IN PCSTR pszName, IN WORD wType, IN DWORD Options, IN PIP4_ARRAY aipServers OPTIONAL, IN OUT PDNS_RECORDA *ppQueryResults OPTIONAL, IN OUT PVOID *pReserved OPTIONAL); -typedef void (WINAPI *DNSFREELIST)(IN OUT PDNS_RECORDA pRecordList, IN DNS_FREE_TYPE FreeType); - -static int CompareDNS(const DNS_SRV_DATAA* dns1, const DNS_SRV_DATAA* dns2) -{ - return (int)dns1->wPriority - (int)dns2->wPriority; -} - -void ThreadData::xmpp_client_query( void ) -{ - if (inet_addr(server) != INADDR_NONE) - return; - - HMODULE hDnsapi = LoadLibraryA( "dnsapi.dll" ); - if ( hDnsapi == NULL ) - return; - - DNSQUERYA pDnsQuery = (DNSQUERYA)GetProcAddress(hDnsapi, "DnsQuery_A"); - DNSFREELIST pDnsRecordListFree = (DNSFREELIST)GetProcAddress(hDnsapi, "DnsRecordListFree"); - if ( pDnsQuery == NULL ) { - //dnsapi.dll is not the needed dnsapi ;) - FreeLibrary( hDnsapi ); - return; - } - - char temp[256]; - mir_snprintf( temp, SIZEOF(temp), "_xmpp-client._tcp.%s", server ); - - DNS_RECORDA *results = NULL; - DNS_STATUS status = pDnsQuery(temp, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &results, NULL); - if (SUCCEEDED(status) && results) { - LIST<DNS_SRV_DATAA> dnsList(5, CompareDNS); - - for (DNS_RECORDA *rec = results; rec; rec = rec->pNext) { - if (rec->Data.Srv.pNameTarget && rec->wType == DNS_TYPE_SRV) - dnsList.insert(&rec->Data.Srv); - } - - for (int i = 0; i < dnsList.getCount(); ++i) { - WORD dnsPort = port == 0 || port == 5222 ? dnsList[i]->wPort : port; - char* dnsHost = dnsList[i]->pNameTarget; - - proto->Log("%s%s resolved to %s:%d", "_xmpp-client._tcp.", server, dnsHost, dnsPort); - s = proto->WsConnect(dnsHost, dnsPort); - if (s) { - mir_snprintf( manualHost, SIZEOF( manualHost ), "%s", dnsHost ); - port = dnsPort; - break; - } } - dnsList.destroy(); - pDnsRecordListFree(results, DnsFreeRecordList); - } - else - proto->Log("%s not resolved", temp); - - FreeLibrary(hDnsapi); -} - -void CJabberProto::xmlStreamInitialize(char *szWhich) -{ - Log("Stream will be initialized %s", szWhich); - if ( m_szXmlStreamToBeInitialized ) - free( m_szXmlStreamToBeInitialized ); - m_szXmlStreamToBeInitialized = _strdup( szWhich ); -} - -void CJabberProto::xmlStreamInitializeNow(ThreadData* info) -{ - Log( "Stream is initializing %s", - m_szXmlStreamToBeInitialized ? m_szXmlStreamToBeInitialized : "after connect" ); - if (m_szXmlStreamToBeInitialized) { - free( m_szXmlStreamToBeInitialized ); - m_szXmlStreamToBeInitialized = NULL; - } - - HXML n = xi.createNode( _T("xml"), NULL, 1 ) << XATTR( _T("version"), _T("1.0")) << XATTR( _T("encoding"), _T("UTF-8")); - - HXML stream = n << XCHILDNS( _T("stream:stream" ), _T("jabber:client")) << XATTR( _T("to"), _A2T(info->server)) - << XATTR( _T("xmlns:stream"), _T("http://etherx.jabber.org/streams")); - - if ( m_tszSelectedLang ) - xmlAddAttr( stream, _T("xml:lang"), m_tszSelectedLang ); - - if ( !m_options.Disable3920auth ) - xmlAddAttr( stream, _T("version"), _T("1.0")); - - LPTSTR xmlQuery = xi.toString( n, NULL ); - char* buf = mir_utf8encodeT( xmlQuery ); - int bufLen = (int)strlen( buf ); - if ( bufLen > 2 ) { - strdel( buf + bufLen - 2, 1 ); - bufLen--; - } - - info->send( buf, bufLen ); - mir_free( buf ); - xi.freeMem( xmlQuery ); - xi.destroyNode( n ); -} - -void CJabberProto::ServerThread( ThreadData* info ) -{ - DBVARIANT dbv; - char* buffer; - int datalen; - int oldStatus; - - Log( "Thread started: type=%d", info->type ); - - info->resolveID = -1; - info->auth = NULL; - - if ( m_options.ManualConnect == TRUE ) { - if ( !DBGetContactSettingString( NULL, m_szModuleName, "ManualHost", &dbv )) { - strncpy( info->manualHost, dbv.pszVal, SIZEOF( info->manualHost )); - info->manualHost[SIZEOF( info->manualHost )-1] = '\0'; - JFreeVariant( &dbv ); - } - info->port = JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ); - } - else info->port = JGetWord( NULL, "Port", JABBER_DEFAULT_PORT ); - - info->useSSL = m_options.UseSSL; - - if ( info->type == JABBER_SESSION_NORMAL ) { - - // Normal server connection, we will fetch all connection parameters - // e.g. username, password, etc. from the database. - - if ( m_ThreadInfo != NULL ) { - // Will not start another connection thread if a thread is already running. - // Make APC call to the main thread. This will immediately wake the thread up - // in case it is asleep in the reconnect loop so that it will immediately - // reconnect. - QueueUserAPC( JabberDummyApcFunc, m_ThreadInfo->hThread, 0 ); - Log( "Thread ended, another normal thread is running" ); -LBL_Exit: - delete info; - return; - } - - m_ThreadInfo = info; - if ( m_szStreamId ) mir_free( m_szStreamId ); - m_szStreamId = NULL; - - if ( !JGetStringT( NULL, "LoginName", &dbv )) { - _tcsncpy( info->username, dbv.ptszVal, SIZEOF( info->username )-1 ); - JFreeVariant( &dbv ); - } - - if ( *trtrim(info->username) == '\0' ) { - DWORD dwSize = SIZEOF( info->username ); - if ( GetUserName( info->username, &dwSize )) - JSetStringT( NULL, "LoginName", info->username ); - else - info->username[0] = 0; - } - - if ( *trtrim(info->username) == '\0' ) { - Log( "Thread ended, login name is not configured" ); - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); -LBL_FatalError: - m_ThreadInfo = NULL; - oldStatus = m_iStatus; - m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - goto LBL_Exit; - } - - if ( !DBGetContactSettingString( NULL, m_szModuleName, "LoginServer", &dbv )) { - strncpy( info->server, dbv.pszVal, SIZEOF( info->server )-1 ); - JFreeVariant( &dbv ); - } - else { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); - Log( "Thread ended, login server is not configured" ); - goto LBL_FatalError; - } - - if ( m_options.HostNameAsResource == FALSE ) { - if ( !JGetStringT( NULL, "Resource", &dbv )) { - _tcsncpy( info->resource, dbv.ptszVal, SIZEOF( info->resource ) - 1 ); - JFreeVariant( &dbv ); - } - else _tcscpy( info->resource, _T("Miranda")); - } - else { - DWORD dwCompNameLen = SIZEOF( info->resource ) - 1; - if ( !GetComputerName( info->resource, &dwCompNameLen )) - _tcscpy( info->resource, _T( "Miranda" )); - } - - TCHAR jidStr[512]; - mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM) _T("/%s"), info->username, info->server, info->resource ); - _tcsncpy( info->fullJID, jidStr, SIZEOF( info->fullJID )-1 ); - - if ( m_options.SavePassword == FALSE ) { - if (*m_savedPassword) { - _tcsncpy( info->password, m_savedPassword, SIZEOF( info->password )); - info->password[ SIZEOF( info->password )-1] = '\0'; - } - else { - mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server ); - - JabberPasswordDlgParam param; - param.pro = this; - param.ptszJid = jidStr; - param.hEventPasswdDlg = CreateEvent( NULL, FALSE, FALSE, NULL ); - CallFunctionAsync( JabberPasswordCreateDialogApcProc, ¶m ); - WaitForSingleObject( param.hEventPasswdDlg, INFINITE ); - CloseHandle( param.hEventPasswdDlg ); - - if ( param.dlgResult == IDCANCEL ) { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); - Log( "Thread ended, password request dialog was canceled" ); - goto LBL_FatalError; - } - - if ( param.saveOnlinePassword ) lstrcpy(m_savedPassword, param.onlinePassword); - else *m_savedPassword = 0; - - _tcsncpy( info->password, param.onlinePassword, SIZEOF( info->password )); - info->password[ SIZEOF( info->password )-1] = '\0'; - } - } - else { - TCHAR *passw = JGetStringCrypt(NULL, "LoginPassword"); - if ( passw == NULL ) { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); - Log( "Thread ended, password is not configured" ); - goto LBL_FatalError; - } - _tcsncpy( info->password, passw, SIZEOF( info->password )); - info->password[SIZEOF( info->password )-1] = '\0'; - mir_free( passw ); - } } - - else if ( info->type == JABBER_SESSION_REGISTER ) { - // Register new user connection, all connection parameters are already filled-in. - // Multiple thread allowed, although not possible : ) - // thinking again.. multiple thread should not be allowed - info->reg_done = FALSE; - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 25, ( LPARAM )TranslateT( "Connecting..." )); - iqIdRegGetReg = -1; - iqIdRegSetReg = -1; - } - else { - Log( "Thread ended, invalid session type" ); - goto LBL_FatalError; - } - - int jabberNetworkBufferSize = 2048; - if (( buffer=( char* )mir_alloc( jabberNetworkBufferSize + 1 )) == NULL ) { // +1 is for '\0' when debug logging this buffer - Log( "Cannot allocate network buffer, thread ended" ); - if ( info->type == JABBER_SESSION_NORMAL ) { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); - } - else if ( info->type == JABBER_SESSION_REGISTER ) { - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Not enough memory" )); - } - Log( "Thread ended, network buffer cannot be allocated" ); - goto LBL_FatalError; - } - - if ( info->manualHost[0] == 0 ) { - info->xmpp_client_query(); - if ( info->s == NULL ) { - strncpy( info->manualHost, info->server, SIZEOF(info->manualHost)); - info->s = WsConnect( info->manualHost, info->port ); - } - } - else - info->s = WsConnect( info->manualHost, info->port ); - - Log( "Thread type=%d server='%s' port='%d'", info->type, info->manualHost, info->port ); - if ( info->s == NULL ) { - Log( "Connection failed ( %d )", WSAGetLastError()); - if ( info->type == JABBER_SESSION_NORMAL ) { - if ( m_ThreadInfo == info ) { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); - } } - else if ( info->type == JABBER_SESSION_REGISTER ) - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" )); - - Log( "Thread ended, connection failed" ); - mir_free( buffer ); - goto LBL_FatalError; - } - - // Determine local IP - if ( info->useSSL ) { - Log( "Intializing SSL connection" ); - if (!CallService( MS_NETLIB_STARTSSL, ( WPARAM )info->s, 0)) { - Log( "SSL intialization failed" ); - if ( info->type == JABBER_SESSION_NORMAL ) { - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); - } - else if ( info->type == JABBER_SESSION_REGISTER ) { - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" )); - } - mir_free( buffer ); - info->close(); - Log( "Thread ended, SSL connection failed" ); - goto LBL_FatalError; - } } - - // User may change status to OFFLINE while we are connecting above - if ( m_iDesiredStatus != ID_STATUS_OFFLINE || info->type == JABBER_SESSION_REGISTER ) { - - if ( info->type == JABBER_SESSION_NORMAL ) { - m_bJabberConnected = TRUE; - size_t len = _tcslen( info->username ) + strlen( info->server )+1; - m_szJabberJID = ( TCHAR* )mir_alloc( sizeof( TCHAR)*( len+1 )); - mir_sntprintf( m_szJabberJID, len+1, _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server ); - m_bSendKeepAlive = m_options.KeepAlive != 0; - JSetStringT(NULL, "jid", m_szJabberJID); // store jid in database - } - - xmlStreamInitializeNow( info ); - const TCHAR* tag = _T("stream:stream"); - - Log( "Entering main recv loop" ); - datalen = 0; - - // cache values - DWORD dwConnectionKeepAliveInterval = m_options.ConnectionKeepAliveInterval; - for ( ;; ) { - if ( !info->useZlib || info->zRecvReady ) { - DWORD dwIdle = GetTickCount() - m_lastTicks; - if ( dwIdle >= dwConnectionKeepAliveInterval ) - dwIdle = dwConnectionKeepAliveInterval - 10; // now! - - NETLIBSELECT nls = {0}; - nls.cbSize = sizeof( NETLIBSELECT ); - nls.dwTimeout = dwConnectionKeepAliveInterval - dwIdle; - nls.hReadConns[0] = info->s; - int nSelRes = CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ); - if ( nSelRes == -1 ) // error - break; - else if ( nSelRes == 0 && m_bSendKeepAlive ) { - if ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PING ) { - CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnPingReply, JABBER_IQ_TYPE_GET, NULL, 0, -1, this ); - pInfo->SetTimeout( m_options.ConnectionKeepAliveTimeout ); - info->send( XmlNodeIq( pInfo ) << XATTR( _T("from"), m_ThreadInfo->fullJID ) << XCHILDNS( _T("ping"), _T(JABBER_FEAT_PING))); - } - else info->send( " \t " ); - continue; - } } - - int recvResult = info->recv( buffer + datalen, jabberNetworkBufferSize - datalen); - Log( "recvResult = %d", recvResult ); - if ( recvResult <= 0 ) - break; - datalen += recvResult; - -recvRest: - buffer[datalen] = '\0'; - - TCHAR* str; - str = mir_utf8decodeW( buffer ); - - int bytesParsed = 0; - XmlNode root( str, &bytesParsed, tag ); - if ( root && tag ) - { - char *p = strstr( buffer, "stream:stream" ); - if ( p ) p = strchr( p, '>' ); - if ( p ) - bytesParsed = p - buffer + 1; - else { - root = XmlNode(); - bytesParsed = 0; - } - - mir_free(str); - - } - else { - if ( root ) str[ bytesParsed ] = 0; - bytesParsed = ( root ) ? mir_utf8lenW( str ) : 0; - mir_free(str); - } - - Log( "bytesParsed = %d", bytesParsed ); - if ( root ) tag = NULL; - - if ( xmlGetName( root ) == NULL ) { - for ( int i=0; ; i++ ) { - HXML n = xmlGetChild( root , i ); - if ( !n ) - break; - OnProcessProtocol( n, info ); - } - } - else OnProcessProtocol( root, info ); - - if ( bytesParsed > 0 ) { - if ( bytesParsed < datalen ) - memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); - datalen -= bytesParsed; - } - else if ( datalen >= jabberNetworkBufferSize ) { - //jabberNetworkBufferSize += 65536; - jabberNetworkBufferSize *= 2; - Log( "Increasing network buffer size to %d", jabberNetworkBufferSize ); - if (( buffer=( char* )mir_realloc( buffer, jabberNetworkBufferSize + 1 )) == NULL ) { - Log( "Cannot reallocate more network buffer, go offline now" ); - break; - } } - else Log( "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize ); - - if ( m_szXmlStreamToBeInitialized ) { - xmlStreamInitializeNow( info ); - tag = _T("stream:stream"); - } - if ( root && datalen ) - goto recvRest; - } - - if ( info->type == JABBER_SESSION_NORMAL ) { - m_iqManager.ExpireAll( info ); - m_bJabberOnline = FALSE; - m_bJabberConnected = FALSE; - info->zlibUninit(); - EnableMenuItems( FALSE ); - RebuildInfoFrame(); - if ( m_hwndJabberChangePassword ) { - //DestroyWindow( hwndJabberChangePassword ); - // Since this is a different thread, simulate the click on the cancel button instead - SendMessage( m_hwndJabberChangePassword, WM_COMMAND, MAKEWORD( IDCANCEL, 0 ), 0 ); - } - - if ( jabberChatDllPresent ) - CallFunctionAsync( JabberOfflineChatWindows, this ); - - ListRemoveList( LIST_CHATROOM ); - ListRemoveList( LIST_BOOKMARK ); - //UI_SAFE_NOTIFY(m_pDlgJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE); - UI_SAFE_NOTIFY_HWND(m_hwndJabberAddBookmark, WM_JABBER_CHECK_ONLINE); - //UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_CHECK_ONLINE); - WindowNotify(WM_JABBER_CHECK_ONLINE); - - // Set status to offline - oldStatus = m_iStatus; - m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - - // Set all contacts to offline - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - if ( !lstrcmpA(( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ), m_szModuleName )) - { - SetContactOfflineStatus( hContact ); - MenuHideSrmmIcon( hContact ); - } - - hContact = db_find_next(hContact); - } - - mir_free( m_szJabberJID ); - m_szJabberJID = NULL; - m_tmJabberLoggedInTime = 0; - ListWipe(); - - WindowNotify(WM_JABBER_REFRESH_VCARD); - } - else if ( info->type==JABBER_SESSION_REGISTER && !info->reg_done ) - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Connection lost" )); - } - else if ( info->type == JABBER_SESSION_NORMAL ) { - oldStatus = m_iStatus; - m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; - JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); - } - - Log( "Thread ended: type=%d server='%s'", info->type, info->server ); - - if ( info->type==JABBER_SESSION_NORMAL && m_ThreadInfo==info ) { - if ( m_szStreamId ) mir_free( m_szStreamId ); - m_szStreamId = NULL; - m_ThreadInfo = NULL; - } - - info->close(); - mir_free( buffer ); - Log( "Exiting ServerThread" ); - goto LBL_Exit; -} - -void CJabberProto::PerformRegistration( ThreadData* info ) -{ - iqIdRegGetReg = SerialNext(); - info->send( XmlNodeIq( _T("get"), iqIdRegGetReg, NULL) << XQUERY( _T(JABBER_FEAT_REGISTER ))); - - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 50, ( LPARAM )TranslateT( "Requesting registration instruction..." )); -} - -void CJabberProto::PerformIqAuth( ThreadData* info ) -{ - if ( info->type == JABBER_SESSION_NORMAL ) { - int iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetAuth ); - info->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T("jabber:iq:auth" )) << XCHILD( _T("username"), info->username )); - } - else if ( info->type == JABBER_SESSION_REGISTER ) - PerformRegistration( info ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CJabberProto::OnProcessStreamOpening( HXML node, ThreadData *info ) -{ - if ( lstrcmp( xmlGetName( node ), _T("stream:stream"))) - return; - - if ( info->type == JABBER_SESSION_NORMAL ) { - const TCHAR* sid = xmlGetAttrValue( node, _T("id")); - if ( sid != NULL ) { - char* pszSid = mir_t2a( sid ); - replaceStr( info->proto->m_szStreamId, pszSid ); - mir_free( pszSid ); - } } - - // old server - disable SASL then - if ( xmlGetAttrValue( node, _T("version")) == NULL ) - info->proto->m_options.Disable3920auth = TRUE; - - if ( info->proto->m_options.Disable3920auth ) - info->proto->PerformIqAuth( info ); -} - -void CJabberProto::PerformAuthentication( ThreadData* info ) -{ - TJabberAuth* auth = NULL; - char* request = NULL; - - if ( info->auth ) { - delete info->auth; - info->auth = NULL; - } - - if ( m_AuthMechs.isSpnegoAvailable ) { - m_AuthMechs.isSpnegoAvailable = false; - auth = new TNtlmAuth( info, "GSS-SPNEGO" ); - if ( !auth->isValid()) { - delete auth; - auth = NULL; - } } - - if ( auth == NULL && m_AuthMechs.isNtlmAvailable ) { - m_AuthMechs.isNtlmAvailable = false; - auth = new TNtlmAuth( info, "NTLM" ); - if ( !auth->isValid()) { - delete auth; - auth = NULL; - } } - - if ( auth == NULL && m_AuthMechs.isKerberosAvailable ) { - m_AuthMechs.isKerberosAvailable = false; - auth = new TNtlmAuth( info, "GSSAPI", m_AuthMechs.m_gssapiHostName ); - if ( !auth->isValid()) { - delete auth; - auth = NULL; - } else { - request = auth->getInitialRequest(); - if ( !request ) { - delete auth; - auth = NULL; - } } } - - if ( auth == NULL && m_AuthMechs.isScramAvailable ) { - m_AuthMechs.isScramAvailable = false; - auth = new TScramAuth( info ); - } - - if ( auth == NULL && m_AuthMechs.isMd5Available ) { - m_AuthMechs.isMd5Available = false; - auth = new TMD5Auth( info ); - } - - if ( auth == NULL && m_AuthMechs.isPlainAvailable ) { - m_AuthMechs.isPlainAvailable = false; - auth = new TPlainAuth( info, false ); - } - - if ( auth == NULL && m_AuthMechs.isPlainOldAvailable ) { - m_AuthMechs.isPlainOldAvailable = false; - auth = new TPlainAuth( info, true ); - } - - if ( auth == NULL ) { - if ( m_AuthMechs.isAuthAvailable ) { // no known mechanisms but iq_auth is available - m_AuthMechs.isAuthAvailable = false; - PerformIqAuth( info ); - return; - } - - TCHAR text[1024]; - mir_sntprintf( text, SIZEOF( text ), _T("%s %s@")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server ); - MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); - info->send( "</stream:stream>" ); - m_ThreadInfo = NULL; - return; - } - - info->auth = auth; - - if ( !request ) request = auth->getInitialRequest(); - info->send( XmlNode( _T("auth"), _A2T(request)) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-sasl")) - << XATTR( _T("mechanism"), _A2T(auth->getName()))); - mir_free( request ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CJabberProto::OnProcessFeatures( HXML node, ThreadData* info ) -{ - bool isRegisterAvailable = false; - bool areMechanismsDefined = false; - - for ( int i=0; ;i++ ) { - HXML n = xmlGetChild( node ,i); - if ( !n ) - break; - - if ( !_tcscmp( xmlGetName( n ), _T("starttls"))) { - if ( !info->useSSL && m_options.UseTLS ) { - Log( "Requesting TLS" ); - info->send( XmlNode( xmlGetName( n )) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-tls" ))); - return; - } } - - if ( !_tcscmp( xmlGetName( n ), _T("compression")) && m_options.EnableZlib == TRUE ) { - Log("Server compression available"); - for ( int k=0; ; k++ ) { - HXML c = xmlGetChild( n ,k); - if ( !c ) - break; - - if ( !_tcscmp( xmlGetName( c ), _T("method"))) { - if ( !_tcscmp( xmlGetText( c ), _T("zlib")) && info->zlibInit() == TRUE ) { - Log("Requesting Zlib compression"); - info->send( XmlNode( _T("compress")) << XATTR( _T("xmlns"), _T("http://jabber.org/protocol/compress")) - << XCHILD( _T("method"), _T("zlib"))); - return; - } } } } - - if ( !_tcscmp( xmlGetName( n ), _T("mechanisms"))) { - m_AuthMechs.isPlainAvailable = false; - m_AuthMechs.isPlainOldAvailable = false; - m_AuthMechs.isMd5Available = false; - m_AuthMechs.isScramAvailable = false; - m_AuthMechs.isNtlmAvailable = false; - m_AuthMechs.isSpnegoAvailable = false; - m_AuthMechs.isKerberosAvailable = false; - mir_free( m_AuthMechs.m_gssapiHostName ); m_AuthMechs.m_gssapiHostName = NULL; - - areMechanismsDefined = true; - //JabberLog("%d mechanisms\n",n->numChild); - for ( int k=0; ; k++ ) { - HXML c = xmlGetChild( n ,k); - if ( !c ) - break; - - if ( !_tcscmp( xmlGetName( c ), _T("mechanism"))) { - //JabberLog("Mechanism: %s",xmlGetText( c )); - if ( !_tcscmp( xmlGetText( c ), _T("PLAIN"))) m_AuthMechs.isPlainOldAvailable = m_AuthMechs.isPlainAvailable = true; - else if ( !_tcscmp( xmlGetText( c ), _T("DIGEST-MD5"))) m_AuthMechs.isMd5Available = true; - else if ( !_tcscmp( xmlGetText( c ), _T("SCRAM-SHA-1"))) m_AuthMechs.isScramAvailable = true; - else if ( !_tcscmp( xmlGetText( c ), _T("NTLM"))) m_AuthMechs.isNtlmAvailable = true; - else if ( !_tcscmp( xmlGetText( c ), _T("GSS-SPNEGO"))) m_AuthMechs.isSpnegoAvailable = true; - else if ( !_tcscmp( xmlGetText( c ), _T("GSSAPI"))) m_AuthMechs.isKerberosAvailable = true; - } - else if ( !_tcscmp( xmlGetName( c ), _T("hostname"))) { - const TCHAR *mech = xmlGetAttrValue( c, _T("mechanism")); - if ( mech && _tcsicmp( mech, _T("GSSAPI")) == 0 ) { - m_AuthMechs.m_gssapiHostName = mir_tstrdup( xmlGetText( c )); - } - } - } } - else if ( !_tcscmp( xmlGetName( n ), _T("register" ))) isRegisterAvailable = true; - else if ( !_tcscmp( xmlGetName( n ), _T("auth" ))) m_AuthMechs.isAuthAvailable = true; - else if ( !_tcscmp( xmlGetName( n ), _T("session" ))) m_AuthMechs.isSessionAvailable = true; - } - - if ( areMechanismsDefined ) { - if ( info->type == JABBER_SESSION_NORMAL ) - PerformAuthentication( info ); - else if ( info->type == JABBER_SESSION_REGISTER ) - PerformRegistration( info ); - else - info->send( "</stream:stream>" ); - return; - } - - // mechanisms are not defined. - if ( info->auth ) { //We are already logged-in - info->send( - XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET )) - << XCHILDNS( _T("bind"), _T("urn:ietf:params:xml:ns:xmpp-bind" )) - << XCHILD( _T("resource"), info->resource )); - - if ( m_AuthMechs.isSessionAvailable ) - info->bIsSessionAvailable = TRUE; - - return; - } - - //mechanisms not available and we are not logged in - PerformIqAuth( info ); -} - -void CJabberProto::OnProcessFailure( HXML node, ThreadData* info ) -{ - const TCHAR* type; -//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" - if (( type = xmlGetAttrValue( node, _T("xmlns"))) == NULL ) return; - if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl"))) { - PerformAuthentication( info ); -} } - -void CJabberProto::OnProcessError( HXML node, ThreadData* info ) -{ - TCHAR *buff; - int i; - int pos; - bool skipMsg = false; - - //failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" - if ( !xmlGetChild( node ,0)) - return; - - buff = (TCHAR *)mir_alloc(1024*sizeof(TCHAR)); - pos=0; - for ( i=0; ; i++ ) { - HXML n = xmlGetChild( node , i ); - if ( !n ) - break; - - const TCHAR *name = xmlGetName( n ); - const TCHAR *desc = xmlGetText( n ); - if ( desc ) - pos += mir_sntprintf( buff+pos, 1024-pos, _T("%s: %s\r\n"), name, desc ); - else - pos += mir_sntprintf( buff+pos, 1024-pos, _T("%s\r\n"), name ); - - if ( !_tcscmp( name, _T("conflict"))) - JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION); - else if ( !_tcscmp( name, _T("see-other-host"))) { - skipMsg = true; - } - } - if (!skipMsg) MsgPopup( NULL, buff, TranslateT( "Jabber Error" )); - mir_free(buff); - info->send( "</stream:stream>" ); -} - -void CJabberProto::OnProcessSuccess( HXML node, ThreadData* info ) -{ - const TCHAR* type; -// int iqId; - // RECVED: <success ... - // ACTION: if successfully logged in, continue by requesting roster list and set my initial status - if (( type = xmlGetAttrValue( node, _T("xmlns"))) == NULL ) - return; - - if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl"))) { - DBVARIANT dbv; - - if ( !info->auth->validateLogin( xmlGetText( node ))) { - info->send( "</stream:stream>" ); - return; - } - - Log( "Success: Logged-in." ); - if ( DBGetContactSettingString( NULL, m_szModuleName, "Nick", &dbv )) - JSetStringT( NULL, "Nick", info->username ); - else - JFreeVariant( &dbv ); - xmlStreamInitialize( "after successful sasl" ); - } - else Log( "Success: unknown action "TCHAR_STR_PARAM".",type); -} - -void CJabberProto::OnProcessChallenge( HXML node, ThreadData* info ) -{ - if ( info->auth == NULL ) { - Log( "No previous auth have been made, exiting..." ); - return; - } - - if ( lstrcmp( xmlGetAttrValue( node, _T("xmlns")), _T("urn:ietf:params:xml:ns:xmpp-sasl"))) - return; - - char* challenge = info->auth->getChallenge( xmlGetText( node )); - info->send( XmlNode( _T("response"), _A2T(challenge)) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-sasl"))); - mir_free( challenge ); -} - -void CJabberProto::OnProcessProtocol( HXML node, ThreadData* info ) -{ - OnConsoleProcessXml(node, JCPF_IN); - - if ( !lstrcmp( xmlGetName( node ), _T("proceed"))) - OnProcessProceed( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("compressed"))) - OnProcessCompressed( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("stream:features"))) - OnProcessFeatures( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("stream:stream"))) - OnProcessStreamOpening( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("success"))) - OnProcessSuccess( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("failure"))) - OnProcessFailure( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("stream:error"))) - OnProcessError( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("challenge"))) - OnProcessChallenge( node, info ); - else if ( info->type == JABBER_SESSION_NORMAL ) { - if ( !lstrcmp( xmlGetName( node ), _T("message"))) - OnProcessMessage( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("presence"))) - OnProcessPresence( node, info ); - else if ( !lstrcmp( xmlGetName( node ), _T("iq"))) - OnProcessIq( node ); - else - Log( "Invalid top-level tag ( only <message/> <presence/> and <iq/> allowed )" ); - } - else if ( info->type == JABBER_SESSION_REGISTER ) { - if ( !lstrcmp( xmlGetName( node ), _T("iq"))) - OnProcessRegIq( node, info ); - else - Log( "Invalid top-level tag ( only <iq/> allowed )" ); -} } - -void CJabberProto::OnProcessProceed( HXML node, ThreadData* info ) -{ - const TCHAR* type; - if (( type = xmlGetAttrValue( node, _T("xmlns"))) != NULL && !lstrcmp( type, _T("error"))) - return; - - if ( !lstrcmp( type, _T("urn:ietf:params:xml:ns:xmpp-tls" ))) { - Log("Starting TLS..."); - - char* gtlk = strstr(info->manualHost, "google.com"); - bool isHosted = gtlk && !gtlk[10] && stricmp(info->server, "gmail.com") && - stricmp(info->server, "googlemail.com"); - - NETLIBSSL ssl = {0}; - ssl.cbSize = sizeof(ssl); - ssl.host = isHosted ? info->manualHost : info->server; - if (!CallService( MS_NETLIB_STARTSSL, ( WPARAM )info->s, ( LPARAM )&ssl)) { - Log( "SSL initialization failed" ); - info->send( "</stream:stream>" ); - info->shutdown(); - } - else - xmlStreamInitialize( "after successful StartTLS" ); -} } - -void CJabberProto::OnProcessCompressed( HXML node, ThreadData* info ) -{ - const TCHAR* type; - - Log( "Compression confirmed" ); - - if (( type = xmlGetAttrValue( node, _T("xmlns"))) != NULL && !lstrcmp( type, _T( "error" ))) - return; - if ( lstrcmp( type, _T( "http://jabber.org/protocol/compress" ))) - return; - - Log( "Starting Zlib stream compression..." ); - - info->useZlib = TRUE; - info->zRecvData = ( char* )mir_alloc( ZLIB_CHUNK_SIZE ); - - xmlStreamInitialize( "after successful Zlib init" ); -} - -void CJabberProto::OnProcessPubsubEvent( HXML node ) -{ - const TCHAR* from = xmlGetAttrValue( node, _T("from")); - if ( !from ) - return; - - HXML eventNode = xmlGetChildByTag( node, "event", "xmlns", _T(JABBER_FEAT_PUBSUB_EVENT)); - if ( !eventNode ) - return; - - m_pepServices.ProcessEvent(from, eventNode); - - HANDLE hContact = HContactFromJID( from ); - if ( !hContact ) - return; - - HXML itemsNode; - if ( m_options.EnableUserTune && (itemsNode = xmlGetChildByTag( eventNode, "items", "node", _T(JABBER_FEAT_USER_TUNE)))) { - // node retract? - if ( xmlGetChild( itemsNode , "retract" )) { - SetContactTune( hContact, NULL, NULL, NULL, NULL, NULL ); - return; - } - - HXML tuneNode = XPath( itemsNode, _T("item/tune[@xmlns='") _T(JABBER_FEAT_USER_TUNE) _T("']")); - if ( !tuneNode ) - return; - - const TCHAR *szArtist = XPathT( tuneNode, "artist" ); - const TCHAR *szLength = XPathT( tuneNode, "length" ); - const TCHAR *szSource = XPathT( tuneNode, "source" ); - const TCHAR *szTitle = XPathT( tuneNode, "title" ); - const TCHAR *szTrack = XPathT( tuneNode, "track" ); - - TCHAR szLengthInTime[32]; - szLengthInTime[0] = _T('\0'); - if ( szLength ) { - int nLength = _ttoi( szLength ); - mir_sntprintf( szLengthInTime, SIZEOF( szLengthInTime ), _T("%02d:%02d:%02d"), - nLength / 3600, (nLength / 60) % 60, nLength % 60 ); - } - - SetContactTune( hContact, szArtist, szLength ? szLengthInTime : NULL, szSource, szTitle, szTrack ); - } -} - -// returns 0, if error or no events -DWORD JabberGetLastContactMessageTime( HANDLE hContact ) -{ - // TODO: time cache can improve performance - HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0 ); - if ( !hDbEvent ) - return 0; - - DWORD dwTime = 0; - - DBEVENTINFO dbei = { 0 }; - dbei.cbSize = sizeof(dbei); - dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); - if ( dbei.cbBlob != -1 ) { - dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); - int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); - if ( !nGetTextResult ) - dwTime = dbei.timestamp; - mir_free( dbei.pBlob ); - } - return dwTime; -} - -HANDLE CJabberProto::CreateTemporaryContact( const TCHAR *szJid, JABBER_LIST_ITEM* chatItem ) -{ - HANDLE hContact = NULL; - if ( chatItem ) { - const TCHAR* p = _tcschr( szJid, '/' ); - if ( p != NULL && p[1] != '\0' ) - p++; - else - p = szJid; - hContact = DBCreateContact( szJid, p, TRUE, FALSE ); - - for ( int i=0; i < chatItem->resourceCount; i++ ) { - if ( !lstrcmp( chatItem->resource[i].resourceName, p )) { - JSetWord( hContact, "Status", chatItem->resource[i].status ); - break; - } - } - } - else { - TCHAR *nick = JabberNickFromJID( szJid ); - hContact = DBCreateContact( szJid, nick, TRUE, TRUE ); - mir_free( nick ); - } - return hContact; -} - -void CJabberProto::OnProcessMessage( HXML node, ThreadData* info ) -{ - HXML subjectNode, xNode, inviteNode, idNode, n; - LPCTSTR from, type, idStr, fromResource; - HANDLE hContact; - - if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("message"))) - return; - - type = xmlGetAttrValue( node, _T("type")); - if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) - return; - - idStr = xmlGetAttrValue( node, _T("id")); - JABBER_RESOURCE_STATUS *resourceStatus = ResourceInfoFromJID( from ); - - // Message receipts delivery request. Reply here, before a call to HandleMessagePermanent() to make sure message receipts are handled for external plugins too. - if ( ( !type || _tcsicmp( type, _T("error"))) && xmlGetChildByTag( node, "request", "xmlns", _T( JABBER_FEAT_MESSAGE_RECEIPTS ))) { - info->send( - XmlNode( _T("message")) << XATTR( _T("to"), from ) << XATTR( _T("id"), idStr ) - << XCHILDNS( _T("received"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)) << XATTR( _T("id"), idStr )); - - if ( resourceStatus ) - resourceStatus->jcbManualDiscoveredCaps |= JABBER_CAPS_MESSAGE_RECEIPTS; - } - - if ( m_messageManager.HandleMessagePermanent( node, info )) - return; - - hContact = HContactFromJID( from ); - JABBER_LIST_ITEM *chatItem = ListGetItemPtr( LIST_CHATROOM, from ); - if ( chatItem ) { - HXML xCaptcha = xmlGetChild( node, "captcha" ); - if ( xCaptcha ) - if ( ProcessCaptcha( xCaptcha, node, info )) - return; - } - - const TCHAR* szMessage = NULL; - HXML bodyNode = xmlGetChildByTag( node , "body", "xml:lang", m_tszSelectedLang ); - if ( bodyNode == NULL ) - bodyNode = xmlGetChild( node , "body" ); - if ( bodyNode != NULL && xmlGetText( bodyNode )) - szMessage = xmlGetText( bodyNode ); - if (( subjectNode = xmlGetChild( node , "subject" )) && xmlGetText( subjectNode ) && xmlGetText( subjectNode )[0] != _T('\0')) { - size_t cbLen = (szMessage ? _tcslen( szMessage ) : 0) + _tcslen( xmlGetText( subjectNode )) + 128; - TCHAR* szTmp = ( TCHAR * )alloca( sizeof(TCHAR) * cbLen ); - szTmp[0] = _T('\0'); - if ( szMessage ) - _tcscat( szTmp, _T("Subject: ")); - _tcscat( szTmp, xmlGetText( subjectNode )); - if ( szMessage ) { - _tcscat( szTmp, _T("\r\n")); - _tcscat( szTmp, szMessage ); - } - szMessage = szTmp; - } - - if ( szMessage && (n = xmlGetChildByTag( node, "addresses", "xmlns", _T(JABBER_FEAT_EXT_ADDRESSING)))) { - HXML addressNode = xmlGetChildByTag( n, "address", "type", _T("ofrom")); - if ( addressNode ) { - const TCHAR* szJid = xmlGetAttrValue( addressNode, _T("jid")); - if ( szJid ) { - size_t cbLen = _tcslen( szMessage ) + 1000; - TCHAR* p = ( TCHAR* )alloca( sizeof( TCHAR ) * cbLen ); - mir_sntprintf( p, cbLen, TranslateT("Message redirected from: %s\r\n%s"), from, szMessage ); - szMessage = p; - from = szJid; - // rewrite hContact - hContact = HContactFromJID( from ); - } - } - } - - // If message is from a stranger ( not in roster ), item is NULL - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, from ); - if ( !item ) - item = ListGetItemPtr( LIST_VCARD_TEMP, from ); - - time_t msgTime = 0; - BOOL isChatRoomInvitation = FALSE; - const TCHAR* inviteRoomJid = NULL; - const TCHAR* inviteFromJid = NULL; - const TCHAR* inviteReason = NULL; - const TCHAR* invitePassword = NULL; - BOOL delivered = FALSE; - - // check chatstates availability - if ( resourceStatus && xmlGetChildByTag( node, "active", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) - resourceStatus->jcbManualDiscoveredCaps |= JABBER_CAPS_CHATSTATES; - - // chatstates composing event - if ( hContact && xmlGetChildByTag( node, "composing", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, 60 ); - - // chatstates paused event - if ( hContact && xmlGetChildByTag( node, "paused", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, PROTOTYPE_CONTACTTYPING_OFF ); - - // chatstates inactive event - if ( hContact && xmlGetChildByTag( node, "inactive", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, PROTOTYPE_CONTACTTYPING_OFF ); - - // message receipts delivery notification - if ( n = xmlGetChildByTag( node, "received", "xmlns", _T( JABBER_FEAT_MESSAGE_RECEIPTS ))) { - int nPacketId = JabberGetPacketID( n ); - if ( nPacketId == -1 ) - nPacketId = JabberGetPacketID( node ); - if ( nPacketId != -1) - JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) nPacketId, 0 ); - } - - // XEP-0203 delay support - if ( n = xmlGetChildByTag( node, "delay", "xmlns", _T("urn:xmpp:delay")) ) { - const TCHAR* ptszTimeStamp = xmlGetAttrValue( n, _T("stamp")); - if ( ptszTimeStamp != NULL ) { - // skip '-' chars - TCHAR* szStamp = mir_tstrdup( ptszTimeStamp ); - int si = 0, sj = 0; - while (1) { - if ( szStamp[si] == _T('-')) - si++; - else - if ( !( szStamp[sj++] = szStamp[si++] )) - break; - }; - msgTime = JabberIsoToUnixTime( szStamp ); - mir_free( szStamp ); - } - } - - // XEP-0224 support (Attention/Nudge) - if ( xmlGetChildByTag( node, "attention", "xmlns", _T( JABBER_FEAT_ATTENTION )) || - xmlGetChildByTag( node, "attention", "xmlns", _T( JABBER_FEAT_ATTENTION_0 ))) { - if ( !hContact ) - hContact = CreateTemporaryContact( from, chatItem ); - if ( hContact ) - NotifyEventHooks( m_hEventNudge, (WPARAM)hContact, 0 ); - } - - // chatstates gone event - if ( hContact && xmlGetChildByTag( node, "gone", "xmlns", _T( JABBER_FEAT_CHATSTATES )) && m_options.LogChatstates ) { - DBEVENTINFO dbei; - BYTE bEventType = JABBER_DB_EVENT_CHATSTATES_GONE; // gone event - dbei.cbSize = sizeof(dbei); - dbei.pBlob = &bEventType; - dbei.cbBlob = 1; - dbei.eventType = JABBER_DB_EVENT_TYPE_CHATSTATES; - dbei.flags = DBEF_READ; - dbei.timestamp = time(NULL); - dbei.szModule = m_szModuleName; - CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); - } - - if (( n = xmlGetChildByTag( node, "confirm", "xmlns", _T( JABBER_FEAT_HTTP_AUTH ))) && m_options.AcceptHttpAuth ) { - const TCHAR *szId = xmlGetAttrValue( n, _T("id")); - const TCHAR *szMethod = xmlGetAttrValue( n, _T("method")); - const TCHAR *szUrl = xmlGetAttrValue( n, _T("url")); - if ( !szId || !szMethod || !szUrl ) - return; - - CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)mir_alloc( sizeof( CJabberHttpAuthParams )); - if ( !pParams ) - return; - - ZeroMemory( pParams, sizeof( CJabberHttpAuthParams )); - pParams->m_nType = CJabberHttpAuthParams::MSG; - pParams->m_szFrom = mir_tstrdup( from ); - HXML pThreadNode = xmlGetChild( node , "thread" ); - if ( pThreadNode && xmlGetText( pThreadNode ) && xmlGetText( pThreadNode )[0] ) - pParams->m_szThreadId = mir_tstrdup( xmlGetText( pThreadNode )); - pParams->m_szId = mir_tstrdup( szId ); - pParams->m_szMethod = mir_tstrdup( szMethod ); - pParams->m_szUrl = mir_tstrdup( szUrl ); - - AddClistHttpAuthEvent( pParams ); - return; - } - - for ( int i = 0; ( xNode = xmlGetChild( node, i )) != NULL; i++ ) { - xNode = xmlGetNthChild( node, _T("x"), i + 1 ); - if ( xNode == NULL ) { - xNode = xmlGetNthChild( node, _T("user:x"), i + 1 ); - if ( xNode == NULL ) - continue; - } - - const TCHAR* ptszXmlns = xmlGetAttrValue( xNode, _T("xmlns")); - if ( ptszXmlns == NULL ) - ptszXmlns = xmlGetAttrValue( xNode, _T("xmlns:user")); - if ( ptszXmlns == NULL ) - continue; - - if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MIRANDA_NOTES))) { - if (OnIncomingNote(from, xmlGetChild(xNode, "note"))) - return; - } - else if ( !_tcscmp( ptszXmlns, _T("jabber:x:encrypted" ))) { - if ( xmlGetText( xNode ) == NULL ) - return; - - TCHAR* prolog = _T("-----BEGIN PGP MESSAGE-----\r\n\r\n"); - TCHAR* epilog = _T("\r\n-----END PGP MESSAGE-----\r\n"); - TCHAR* tempstring = ( TCHAR* )alloca( sizeof( TCHAR ) * ( _tcslen( prolog ) + _tcslen( xmlGetText( xNode )) + _tcslen( epilog ) + 3 )); - _tcsncpy( tempstring, prolog, _tcslen( prolog ) + 1 ); - _tcsncpy( tempstring + _tcslen( prolog ), xmlGetText( xNode ), _tcslen( xmlGetText( xNode )) + 1); - _tcsncpy( tempstring + _tcslen( prolog ) + _tcslen(xmlGetText( xNode )), epilog, _tcslen( epilog ) + 1); - szMessage = tempstring; - } - else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_DELAY)) && msgTime == 0 ) { - const TCHAR* ptszTimeStamp = xmlGetAttrValue( xNode, _T("stamp")); - if ( ptszTimeStamp != NULL ) - msgTime = JabberIsoToUnixTime( ptszTimeStamp ); - } - else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MESSAGE_EVENTS))) { - - // set events support only if we discovered caps and if events not already set - JabberCapsBits jcbCaps = GetResourceCapabilites( from, TRUE ); - if ( jcbCaps & JABBER_RESOURCE_CAPS_ERROR ) - jcbCaps = JABBER_RESOURCE_CAPS_NONE; - // FIXME: disabled due to expired XEP-0022 and problems with bombus delivery checks -// if ( jcbCaps && resourceStatus && (!(jcbCaps & JABBER_CAPS_MESSAGE_EVENTS))) -// resourceStatus->jcbManualDiscoveredCaps |= (JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY); - - if ( bodyNode == NULL ) { - idNode = xmlGetChild( xNode , "id" ); - if ( xmlGetChild( xNode , "delivered" ) != NULL || xmlGetChild( xNode , "offline" ) != NULL ) { - int id = -1; - if ( idNode != NULL && xmlGetText( idNode ) != NULL ) - if ( !_tcsncmp( xmlGetText( idNode ), _T(JABBER_IQID), strlen( JABBER_IQID ))) - id = _ttoi(( xmlGetText( idNode ))+strlen( JABBER_IQID )); - - if ( id != -1 ) - JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); - } - - if ( hContact && xmlGetChild( xNode , "composing" ) != NULL ) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 ); - - // Maybe a cancel to the previous composing - HXML child = xmlGetChild( xNode ,0); - if ( hContact && ( !child || ( child && idNode != NULL ))) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF ); - } - else { - // Check whether any event is requested - if ( !delivered && ( n = xmlGetChild( xNode , "delivered" )) != NULL ) { - delivered = TRUE; - - XmlNode m( _T("message" )); m << XATTR( _T("to"), from ); - HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); - x << XCHILD( _T("delivered")); - x << XCHILD( _T("id"), idStr ); - info->send( m ); - } - if ( item != NULL && xmlGetChild( xNode , "composing" ) != NULL ) { - if ( item->messageEventIdStr ) - mir_free( item->messageEventIdStr ); - item->messageEventIdStr = ( idStr==NULL )?NULL:mir_tstrdup( idStr ); - } } - } - else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_OOB2))) { - HXML urlNode; - if ( ((urlNode = xmlGetChild( xNode , "url" )) != NULL) && xmlGetText( urlNode ) && xmlGetText( urlNode )[0] != _T('\0')) { - size_t cbLen = (szMessage ? _tcslen( szMessage ) : 0) + _tcslen( xmlGetText( urlNode )) + 32; - TCHAR* szTmp = ( TCHAR * )alloca( sizeof(TCHAR) * cbLen ); - _tcscpy( szTmp, xmlGetText( urlNode )); - if ( szMessage ) { - _tcscat( szTmp, _T("\r\n")); - _tcscat( szTmp, szMessage ); - } - szMessage = szTmp; - } - } - else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MUC_USER))) { - inviteNode = xmlGetChild( xNode , _T("invite")); - if ( inviteNode == NULL ) - inviteNode = xmlGetChild( xNode , _T("user:invite")); - - if ( inviteNode != NULL ) { - inviteFromJid = xmlGetAttrValue( inviteNode, _T("from")); - n = xmlGetChild( inviteNode , _T("reason")); - if ( n == NULL ) - n = xmlGetChild( inviteNode , _T("user:reason")); - if ( n != NULL ) - inviteReason = xmlGetText( n ); - } - inviteRoomJid = from; - if ( !inviteReason ) - inviteReason = szMessage; - isChatRoomInvitation = TRUE; - if (( n = xmlGetChild( xNode , "password" )) != NULL ) - invitePassword = xmlGetText( n ); - } - else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_ROSTER_EXCHANGE)) && - item != NULL && (item->subscription == SUB_BOTH || item->subscription == SUB_TO)) { - TCHAR chkJID[JABBER_MAX_JID_LEN] = _T("@"); - JabberStripJid( from, chkJID + 1, SIZEOF(chkJID) - 1 ); - for ( int i = 1; ; ++i ) { - HXML iNode = xmlGetNthChild( xNode , _T("item"), i ); - if ( iNode == NULL ) break; - const TCHAR *action = xmlGetAttrValue( iNode, _T("action")); - const TCHAR *jid = xmlGetAttrValue( iNode, _T("jid")); - const TCHAR *nick = xmlGetAttrValue( iNode, _T("name")); - const TCHAR *group = xmlGetText( xmlGetChild( iNode, _T("group"))); - if ( action && jid && _tcsstr( jid, chkJID )) { - if ( !_tcscmp( action, _T("add"))) { - HANDLE hContact = DBCreateContact( jid, nick, FALSE, FALSE ); - if ( group ) - DBWriteContactSettingTString( hContact, "CList", "Group", group ); - } - else if ( !_tcscmp( action, _T("modify"))) { -// HANDLE hContact = HContactFromJID( jid ); - } - else if ( !_tcscmp( action, _T("delete"))) { - HANDLE hContact = HContactFromJID( jid ); - if ( hContact ) - CallService( MS_DB_CONTACT_DELETE, ( WPARAM ) hContact, 0 ); - } - } - } - } - else if ( !isChatRoomInvitation && !_tcscmp( ptszXmlns, _T("jabber:x:conference"))) { - inviteRoomJid = xmlGetAttrValue( xNode, _T("jid")); - inviteFromJid = from; - if ( inviteReason == NULL ) - inviteReason = xmlGetText( xNode ); - if ( !inviteReason ) - inviteReason = szMessage; - isChatRoomInvitation = TRUE; - } - } - - if ( isChatRoomInvitation ) { - if ( inviteRoomJid != NULL ) { - if ( m_options.IgnoreMUCInvites ) { - // FIXME: temporary disabled due to MUC inconsistence on server side - /* - XmlNode m( "message" ); xmlAddAttr( m, "to", from ); - XmlNode xNode = xmlAddChild( m, "x" ); - xmlAddAttr( xNode, "xmlns", JABBER_FEAT_MUC_USER ); - XmlNode declineNode = xmlAddChild( xNode, "decline" ); - xmlAddAttr( declineNode, "from", inviteRoomJid ); - XmlNode reasonNode = xmlAddChild( declineNode, "reason", "The user has chosen to not accept chat invites" ); - info->send( m ); - */ - } - else - GroupchatProcessInvite( inviteRoomJid, inviteFromJid, inviteReason, invitePassword ); - } - return; - } - - if ( szMessage ) { - if (( szMessage = JabberUnixToDosT( szMessage )) == NULL ) - szMessage = mir_tstrdup( _T("")); - - char* buf = mir_utf8encodeW( szMessage ); - - if ( item != NULL ) { - if ( resourceStatus ) resourceStatus->bMessageSessionActive = TRUE; - if ( hContact != NULL ) - CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF ); - - // no we will monitor last resource in all modes - if ( /*item->resourceMode==RSMODE_LASTSEEN &&*/ ( fromResource = _tcschr( from, '/' ))!=NULL ) { - fromResource++; - if ( *fromResource != '\0' ) { - for ( int i=0; i<item->resourceCount; i++ ) { - if ( !lstrcmp( item->resource[i].resourceName, fromResource )) { - int nLastSeenResource = item->lastSeenResource; - item->lastSeenResource = i; - if ((item->resourceMode==RSMODE_LASTSEEN) && (i != nLastSeenResource)) - UpdateMirVer(item); - break; - } } } } } - - // Create a temporary contact - if ( hContact == NULL ) - hContact = CreateTemporaryContact( from, chatItem ); - - time_t now = time( NULL ); - if ( !msgTime ) - msgTime = now; - - if ( m_options.FixIncorrectTimestamps && ( msgTime > now || ( msgTime < ( time_t )JabberGetLastContactMessageTime( hContact )))) - msgTime = now; - - PROTORECVEVENT recv; - recv.flags = PREF_UTF; - recv.timestamp = ( DWORD )msgTime; - recv.szMessage = buf; - - EnterCriticalSection( &m_csLastResourceMap ); - recv.lParam = (LPARAM)AddToLastResourceMap( from ); - LeaveCriticalSection( &m_csLastResourceMap ); - - CCSDATA ccs; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.szProtoService = PSR_MESSAGE; - ccs.lParam = ( LPARAM )&recv; - CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); - - mir_free(( void* )szMessage ); - mir_free( buf ); - } -} - -// XEP-0115: Entity Capabilities -void CJabberProto::OnProcessPresenceCapabilites( HXML node ) -{ - const TCHAR* from; - if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) - return; - - Log("presence: for jid " TCHAR_STR_PARAM, from); - - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( from ); - if ( r == NULL ) return; - - HXML n; - - // check XEP-0115 support, and old style: - if (( n = xmlGetChildByTag( node, "c", "xmlns", _T(JABBER_FEAT_ENTITY_CAPS))) != NULL || - ( n = xmlGetChildByTag( node, "caps:c", "xmlns:caps", _T(JABBER_FEAT_ENTITY_CAPS))) != NULL || - ( n = xmlGetChild( node, "c" )) != NULL ) { - const TCHAR *szNode = xmlGetAttrValue( n, _T("node")); - const TCHAR *szVer = xmlGetAttrValue( n, _T("ver")); - const TCHAR *szExt = xmlGetAttrValue( n, _T("ext")); - if ( szNode && szVer ) { - replaceStrT( r->szCapsNode, szNode ); - replaceStrT( r->szCapsVer, szVer ); - replaceStrT( r->szCapsExt, szExt ); - HANDLE hContact = HContactFromJID( from ); - if ( hContact ) - UpdateMirVer( hContact, r ); - } - } - - // update user's caps - // JabberCapsBits jcbCaps = GetResourceCapabilites( from, TRUE ); -} - -void CJabberProto::UpdateJidDbSettings( const TCHAR *jid ) -{ - JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, jid ); - if ( !item ) return; - HANDLE hContact = HContactFromJID( jid ); - if ( !hContact ) return; - - int status = ID_STATUS_OFFLINE; - if ( !item->resourceCount ) { - // set offline only if jid has resources - if ( _tcschr( jid, '/' )==NULL ) - status = item->itemResource.status; - if ( item->itemResource.statusMessage ) - DBWriteContactSettingTString( hContact, "CList", "StatusMsg", item->itemResource.statusMessage ); - else - DBDeleteContactSetting( hContact, "CList", "StatusMsg" ); - } - - // Determine status to show for the contact based on the remaining resources - int nSelectedResource = -1, i = 0; - int nMaxPriority = -999; // -128...+127 valid range - for ( i = 0; i < item->resourceCount; i++ ) - { - if ( item->resource[i].priority > nMaxPriority ) { - nMaxPriority = item->resource[i].priority; - status = item->resource[i].status; - nSelectedResource = i; - } - else if ( item->resource[i].priority == nMaxPriority) { - if (( status = JabberCombineStatus( status, item->resource[i].status )) == item->resource[i].status ) - nSelectedResource = i; - } - } - item->itemResource.status = status; - if ( nSelectedResource != -1 ) { - Log("JabberUpdateJidDbSettings: updating jid " TCHAR_STR_PARAM " to rc " TCHAR_STR_PARAM, item->jid, item->resource[nSelectedResource].resourceName ); - if ( item->resource[nSelectedResource].statusMessage ) - DBWriteContactSettingTString( hContact, "CList", "StatusMsg", item->resource[nSelectedResource].statusMessage ); - else - DBDeleteContactSetting( hContact, "CList", "StatusMsg" ); - UpdateMirVer( hContact, &item->resource[nSelectedResource] ); - } - else { - JDeleteSetting( hContact, DBSETTING_DISPLAY_UID ); - } - - if ( _tcschr( jid, '@' )!=NULL || m_options.ShowTransport==TRUE ) - if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status ) - JSetWord( hContact, "Status", ( WORD )status ); - - if (status == ID_STATUS_OFFLINE) - { // remove x-status icon - JDeleteSetting( hContact, DBSETTING_XSTATUSID ); - JDeleteSetting( hContact, DBSETTING_XSTATUSNAME ); - JDeleteSetting( hContact, DBSETTING_XSTATUSMSG ); - //JabberUpdateContactExtraIcon(hContact); - } - - MenuUpdateSrmmIcon( item ); -} - -void CJabberProto::OnProcessPresence( HXML node, ThreadData* info ) -{ - HANDLE hContact; - HXML showNode, statusNode, priorityNode; - JABBER_LIST_ITEM *item; - LPCTSTR from, show, p; - TCHAR *nick; - - if ( !node || !xmlGetName( node ) ||_tcscmp( xmlGetName( node ), _T("presence"))) return; - if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; - - if ( m_presenceManager.HandlePresencePermanent( node, info )) - return; - - if ( ListExist( LIST_CHATROOM, from )) { - GroupchatProcessPresence( node ); - return; - } - - BOOL bSelfPresence = FALSE; - TCHAR szBareFrom[ JABBER_MAX_JID_LEN ]; - JabberStripJid( from, szBareFrom, SIZEOF( szBareFrom )); - TCHAR szBareOurJid[ JABBER_MAX_JID_LEN ]; - JabberStripJid( info->fullJID, szBareOurJid, SIZEOF( szBareOurJid )); - - if ( !_tcsicmp( szBareFrom, szBareOurJid )) - bSelfPresence = TRUE; - - LPCTSTR type = xmlGetAttrValue( node, _T("type")); - if ( type == NULL || !_tcscmp( type, _T("available"))) { - if (( nick = JabberNickFromJID( from )) == NULL ) - return; - - if (( hContact = HContactFromJID( from )) == NULL ) { - if ( !_tcsicmp( info->fullJID, from ) || ( !bSelfPresence && !ListExist( LIST_ROSTER, from ))) { - Log("SKIP Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster and not in list - skiping)", from ); - mir_free( nick ); - return; - } - hContact = DBCreateContact( from, nick, TRUE, TRUE ); - } - if ( !ListExist( LIST_ROSTER, from )) { - Log("Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster )", from ); - ListAdd( LIST_ROSTER, from ); - } - DBCheckIsTransportedContact( from, hContact ); - int status = ID_STATUS_ONLINE; - if (( showNode = xmlGetChild( node , "show" )) != NULL ) { - if (( show = xmlGetText( showNode )) != NULL ) { - if ( !_tcscmp( show, _T("away"))) status = ID_STATUS_AWAY; - else if ( !_tcscmp( show, _T("xa"))) status = ID_STATUS_NA; - else if ( !_tcscmp( show, _T("dnd"))) status = ID_STATUS_DND; - else if ( !_tcscmp( show, _T("chat"))) status = ID_STATUS_FREECHAT; - } } - - char priority = 0; - if (( priorityNode = xmlGetChild( node , "priority" )) != NULL && xmlGetText( priorityNode ) != NULL ) - priority = (char)_ttoi( xmlGetText( priorityNode )); - - if (( statusNode = xmlGetChild( node , "status" )) != NULL && xmlGetText( statusNode ) != NULL ) - p = xmlGetText( statusNode ); - else - p = NULL; - ListAddResource( LIST_ROSTER, from, status, p, priority ); - - // XEP-0115: Entity Capabilities - OnProcessPresenceCapabilites( node ); - - UpdateJidDbSettings( from ); - - if ( _tcschr( from, '@' )==NULL ) { - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - } - Log( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) online, set contact status to %s", nick, from, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,(WPARAM)status,0 )); - mir_free( nick ); - - HXML xNode; - if ( m_options.EnableAvatars ) { - BOOL hasAvatar = false; - BOOL removedAvatar = false; - - Log( "Avatar enabled" ); - for ( int i = 1; ( xNode=xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) { - if ( !lstrcmp( xmlGetAttrValue( xNode, _T("xmlns")), _T("jabber:x:avatar"))) { - if (( xNode = xmlGetChild( xNode , "hash" )) != NULL && xmlGetText( xNode ) != NULL ) { - JDeleteSetting(hContact,"AvatarXVcard"); - Log( "AvatarXVcard deleted" ); - JSetStringT( hContact, "AvatarHash", xmlGetText( xNode )); - hasAvatar = true; - DBVARIANT dbv; - int result = JGetStringT( hContact, "AvatarSaved", &dbv ); - if ( result || lstrcmp( dbv.ptszVal, xmlGetText( xNode ))) { - Log( "Avatar was changed" ); - JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL ); - } else Log( "Not broadcasting avatar changed" ); - if ( !result ) JFreeVariant( &dbv ); - } else { - removedAvatar = true; - } - } } - if ( !hasAvatar ) { //no jabber:x:avatar. try vcard-temp:x:update - Log( "Not hasXAvatar" ); - for ( int i = 1; ( xNode=xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) { - if ( !lstrcmp( xmlGetAttrValue( xNode, _T("xmlns")), _T("vcard-temp:x:update"))) { - if (( xNode = xmlGetChild( xNode , "photo" )) != NULL ) { - LPCTSTR txt = xmlGetText( xNode ); - if ( txt != NULL && txt[0] != 0) { - JSetByte( hContact, "AvatarXVcard", 1 ); - Log( "AvatarXVcard set" ); - JSetStringT( hContact, "AvatarHash", txt ); - hasAvatar = true; - DBVARIANT dbv; - int result = JGetStringT( hContact, "AvatarSaved", &dbv ); - if ( result || lstrcmp( dbv.ptszVal, txt )) { - Log( "Avatar was changed. Using vcard-temp:x:update" ); - JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL ); - } - else Log( "Not broadcasting avatar changed" ); - if ( !result ) JFreeVariant( &dbv ); - } else { - removedAvatar = true; - } - } } } } - if ( !hasAvatar && removedAvatar ) { - Log( "Has no avatar" ); - JDeleteSetting( hContact, "AvatarHash" ); - DBVARIANT dbv = {0}; - if ( !JGetStringT( hContact, "AvatarSaved", &dbv )) { - JFreeVariant( &dbv ); - JDeleteSetting( hContact, "AvatarSaved" ); - JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, NULL, NULL ); - } } } - return; - } - - if ( !_tcscmp( type, _T("unavailable"))) { - hContact = HContactFromJID( from ); - if (( item = ListGetItemPtr( LIST_ROSTER, from )) != NULL ) { - ListRemoveResource( LIST_ROSTER, from ); - - hContact = HContactFromJID( from ); - if ( hContact && DBGetContactSettingByte( hContact, "CList", "NotOnList", 0) == 1 ) { - // remove selfcontact, if where is no more another resources - if ( item->resourceCount == 1 && ResourceInfoFromJID( info->fullJID )) - ListRemoveResource( LIST_ROSTER, info->fullJID ); - } - - - // set status only if no more available resources - if ( !item->resourceCount ) - { - item->itemResource.status = ID_STATUS_OFFLINE; - if ((( statusNode = xmlGetChild( node , "status" )) != NULL ) && xmlGetText( statusNode )) - replaceStrT( item->itemResource.statusMessage, xmlGetText( statusNode )); - else - replaceStrT( item->itemResource.statusMessage, NULL ); - } - } - else Log( "SKIP Receive presence offline from " TCHAR_STR_PARAM " ( who is not in my roster )", from ); - - UpdateJidDbSettings( from ); - - if ( _tcschr( from, '@' )==NULL ) { - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - } - DBCheckIsTransportedContact(from, hContact); - return; - } - - if ( !_tcscmp( type, _T("subscribe"))) { - if (hContact = HContactFromJID( from )) - AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_SUBSCRIBE ); - - // automatically send authorization allowed to agent/transport - if ( _tcschr( from, '@' ) == NULL || m_options.AutoAcceptAuthorization ) { - ListAdd( LIST_ROSTER, from ); - info->send( XmlNode( _T("presence")) << XATTR( _T("to"), from ) << XATTR( _T("type"), _T("subscribed"))); - - if ( m_options.AutoAdd == TRUE ) { - if (( item = ListGetItemPtr( LIST_ROSTER, from )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) { - Log( "Try adding contact automatically jid = " TCHAR_STR_PARAM, from ); - if (( hContact=AddToListByJID( from, 0 )) != NULL ) { - // Trigger actual add by removing the "NotOnList" added by AddToListByJID() - // See AddToListByJID() and JabberDbSettingChanged(). - DBDeleteContactSetting( hContact, "CList", "NotOnList" ); - } } } - RebuildInfoFrame(); - } - else { - HXML n = xmlGetChild( node , "nick" ); - nick = ( n == NULL ) ? JabberNickFromJID( from ) : mir_tstrdup( xmlGetText( n )); - if ( nick != NULL ) { - Log( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) requests authorization", nick, from ); - DBAddAuthRequest( from, nick ); - mir_free( nick ); - } } - return; - } - - if ( !_tcscmp( type, _T("unsubscribe"))) { - if (hContact = HContactFromJID( from )) - AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE ); - } - - if ( !_tcscmp( type, _T("unsubscribed"))) { - if (hContact = HContactFromJID( from )) - AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED ); - } - - if ( !_tcscmp( type, _T("error"))) { - if (hContact = HContactFromJID( from )) { - AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_ERROR ); - } - } - - if ( !_tcscmp( type, _T("subscribed"))) { - - if (hContact = HContactFromJID( from )) - AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_SUBSCRIBED ); - - if (( item=ListGetItemPtr( LIST_ROSTER, from )) != NULL ) { - if ( item->subscription == SUB_FROM ) item->subscription = SUB_BOTH; - else if ( item->subscription == SUB_NONE ) { - item->subscription = SUB_TO; - if ( _tcschr( from, '@' )==NULL ) { - UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - } - } - UpdateSubscriptionInfo( hContact, item ); - } - } -} - -void CJabberProto::OnIqResultVersion( HXML /*node*/, CJabberIqInfo *pInfo ) -{ - JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); - if ( r == NULL ) return; - - r->dwVersionRequestTime = -1; - - replaceStrT( r->software, NULL ); - replaceStrT( r->version, NULL ); - replaceStrT( r->system, NULL ); - - HXML queryNode = pInfo->GetChildNode(); - - if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && queryNode) { - HXML n; - if (( n = xmlGetChild( queryNode , "name" ))!=NULL && xmlGetText( n )) - r->software = mir_tstrdup( xmlGetText( n )); - if (( n = xmlGetChild( queryNode , "version" ))!=NULL && xmlGetText( n )) - r->version = mir_tstrdup( xmlGetText( n )); - if (( n = xmlGetChild( queryNode , "os" ))!=NULL && xmlGetText( n )) - r->system = mir_tstrdup( xmlGetText( n )); - } - - GetResourceCapabilites( pInfo->GetFrom(), TRUE ); - if ( pInfo->GetHContact()) - UpdateMirVer( pInfo->GetHContact(), r ); - - JabberUserInfoUpdate(pInfo->GetHContact()); -} - -BOOL CJabberProto::OnProcessJingle( HXML node ) -{ - LPCTSTR type; - HXML child = xmlGetChildByTag( node, _T("jingle"), _T("xmlns"), _T(JABBER_FEAT_JINGLE)); - - if ( child ) { - if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return FALSE; - if (( !_tcscmp( type, _T("get")) || !_tcscmp( type, _T("set")))) { - LPCTSTR szAction = xmlGetAttrValue( child, _T("action")); - LPCTSTR idStr = xmlGetAttrValue( node, _T("id")); - LPCTSTR from = xmlGetAttrValue( node, _T("from")); - if ( szAction && !_tcscmp( szAction, _T("session-initiate"))) { - // if this is a Jingle 'session-initiate' and noone processed it yet, reply with "unsupported-applications" - m_ThreadInfo->send( XmlNodeIq( _T("result"), idStr, from )); - - XmlNodeIq iq( _T("set"), SerialNext(), from ); - HXML jingleNode = iq << XCHILDNS( _T("jingle"), _T(JABBER_FEAT_JINGLE)); - - jingleNode << XATTR( _T("action"), _T("session-terminate")); - LPCTSTR szInitiator = xmlGetAttrValue( child, _T("initiator")); - if ( szInitiator ) - jingleNode << XATTR( _T("initiator"), szInitiator ); - LPCTSTR szSid = xmlGetAttrValue( child, _T("sid")); - if ( szSid ) - jingleNode << XATTR( _T("sid"), szSid ); - - jingleNode << XCHILD( _T("reason")) - << XCHILD( _T("unsupported-applications")); - m_ThreadInfo->send( iq ); - return TRUE; - } - else { - // if it's something else than 'session-initiate' and noone processed it yet, reply with "unknown-session" - XmlNodeIq iq( _T("error"), idStr, from ); - HXML errNode = iq << XCHILD( _T("error")); - errNode << XATTR( _T("type"), _T("cancel")); - errNode << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - errNode << XCHILDNS( _T("unknown-session"), _T("urn:xmpp:jingle:errors:1")); - m_ThreadInfo->send( iq ); - return TRUE; - } - } - } - return FALSE; -} - -void CJabberProto::OnProcessIq( HXML node ) -{ - HXML queryNode; - const TCHAR *type, *xmlns; - JABBER_IQ_PFUNC pfunc; - - if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("iq"))) return; - if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return; - - int id = JabberGetPacketID( node ); - const TCHAR* idStr = xmlGetAttrValue( node, _T("id")); - - queryNode = xmlGetChild( node , "query" ); - xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); - - // new match by id - if ( m_iqManager.HandleIq( id, node )) - return; - - // new iq handler engine - if ( m_iqManager.HandleIqPermanent( node )) - return; - - // Jingle support - if ( OnProcessJingle( node )) - return; - - ///////////////////////////////////////////////////////////////////////// - // OLD MATCH BY ID - ///////////////////////////////////////////////////////////////////////// - if ( ( !_tcscmp( type, _T("result")) || !_tcscmp( type, _T("error"))) && (( pfunc=JabberIqFetchFunc( id )) != NULL )) { - Log( "Handling iq request for id=%d", id ); - (this->*pfunc)( node ); - return; - } - // RECVED: <iq type='error'> ... - else if ( !_tcscmp( type, _T("error"))) { - Log( "XXX on entry" ); - // Check for file transfer deny by comparing idStr with ft->iqId - LISTFOREACH(i, this, LIST_FILE) - { - JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); - if ( item->ft != NULL && item->ft->state == FT_CONNECTING && !_tcscmp( idStr, item->ft->iqId )) { - Log( "Denying file sending request" ); - item->ft->state = FT_DENIED; - if ( item->ft->hFileEvent != NULL ) - SetEvent( item->ft->hFileEvent ); // Simulate the termination of file server connection - } - } } - else if (( !_tcscmp( type, _T("get")) || !_tcscmp( type, _T("set")))) { - XmlNodeIq iq( _T("error"), idStr, xmlGetAttrValue( node, _T("from"))); - - HXML pFirstChild = xmlGetChild( node , 0 ); - if ( pFirstChild ) - xmlAddChild( iq, pFirstChild ); - - iq << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) - << XCHILDNS( _T("service-unavailable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); - m_ThreadInfo->send( iq ); - } -} - -void CJabberProto::OnProcessRegIq( HXML node, ThreadData* info ) -{ - HXML errorNode; - const TCHAR *type; - - if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("iq"))) return; - if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return; - - int id = JabberGetPacketID( node ); - - if ( !_tcscmp( type, _T("result"))) { - - // RECVED: result of the request for registration mechanism - // ACTION: send account registration information - if ( id == iqIdRegGetReg ) { - iqIdRegSetReg = SerialNext(); - - XmlNodeIq iq( _T("set"), iqIdRegSetReg ); - HXML query = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); - query << XCHILD( _T("password"), info->password ); - query << XCHILD( _T("username"), info->username ); - info->send( iq ); - - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 75, ( LPARAM )TranslateT( "Sending registration information..." )); - } - // RECVED: result of the registration process - // ACTION: account registration successful - else if ( id == iqIdRegSetReg ) { - info->send( "</stream:stream>" ); - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" )); - info->reg_done = TRUE; - } } - - else if ( !_tcscmp( type, _T("error"))) { - errorNode = xmlGetChild( node , "error" ); - TCHAR* str = JabberErrorMsg( errorNode ); - SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str ); - mir_free( str ); - info->reg_done = TRUE; - info->send( "</stream:stream>" ); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// ThreadData constructor & destructor - -ThreadData::ThreadData( CJabberProto* aproto, JABBER_SESSION_TYPE parType ) -{ - memset( this, 0, sizeof( *this )); - type = parType; - proto = aproto; - iomutex = CreateMutex(NULL, FALSE, NULL); -} - -ThreadData::~ThreadData() -{ - if ( auth ) delete auth; - mir_free( zRecvData ); - CloseHandle( iomutex ); - CloseHandle(hThread); -} - -void ThreadData::close( void ) -{ - if ( s ) { - Netlib_CloseHandle(s); - s = NULL; -} } - -void ThreadData::shutdown( void ) -{ - if ( s ) - Netlib_Shutdown(s); -} - -int ThreadData::recvws( char* buf, size_t len, int flags ) -{ - if ( this == NULL ) - return 0; - - return proto->WsRecv( s, buf, (int)len, flags ); -} - -int ThreadData::recv( char* buf, size_t len ) -{ - if ( useZlib ) - return zlibRecv( buf, (long)len ); - - return recvws( buf, len, MSG_DUMPASTEXT ); -} - -int ThreadData::sendws( char* buffer, size_t bufsize, int flags ) -{ - return proto->WsSend( s, buffer, (int)bufsize, flags ); -} - -int ThreadData::send( char* buffer, int bufsize ) -{ - if ( this == NULL ) - return 0; - - int result; - - WaitForSingleObject( iomutex, 6000 ); - - if ( useZlib ) - result = zlibSend( buffer, bufsize ); - else - result = sendws( buffer, bufsize, MSG_DUMPASTEXT ); - - ReleaseMutex( iomutex ); - return result; -} - -// Caution: DO NOT use ->send() to send binary ( non-string ) data -int ThreadData::send( HXML node ) -{ - if ( this == NULL ) - return 0; - - while ( HXML parent = xi.getParent( node )) - node = parent; - - if ( proto->m_sendManager.HandleSendPermanent( node, this )) - return 0; - - proto->OnConsoleProcessXml(node, JCPF_OUT); - - TCHAR* str = xi.toString( node, NULL ); - - // strip forbidden control characters from outgoing XML stream - TCHAR *q = str; - for (TCHAR *p = str; *p; ++p) { - - WCHAR c = *p; - - if (c < 0x9 || c > 0x9 && c < 0xA || c > 0xA && c < 0xD || c > 0xD && c < 0x20 || c > 0xD7FF && c < 0xE000 || c > 0xFFFD) - continue; - - *q++ = *p; - } - *q = 0; - - - char* utfStr = mir_utf8encodeT( str ); - int result = send( utfStr, (int)strlen( utfStr )); - mir_free( utfStr ); - - xi.freeMem( str ); - return result; -} - -int ThreadData::send( const char* fmt, ... ) -{ - if ( this == NULL ) - return 0; - - va_list vararg; - va_start( vararg, fmt ); - int size = 512; - char* str = ( char* )mir_alloc( size ); - while ( _vsnprintf( str, size, fmt, vararg ) == -1 ) { - size += 512; - str = ( char* )mir_realloc( str, size ); - } - va_end( vararg ); - - int result = send( str, (int)strlen( str )); - - mir_free( str ); - return result; -} diff --git a/protocols/JabberG/jabber_treelist.cpp b/protocols/JabberG/jabber_treelist.cpp deleted file mode 100644 index 8e1e28cb45..0000000000 --- a/protocols/JabberG/jabber_treelist.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#define TLIF_VISIBLE 0x01 -#define TLIF_EXPANDED 0x02 -#define TLIF_MODIFIED 0x04 -#define TLIF_ROOT 0X08 -#define TLIF_HASITEM 0X10 -#define TLIF_REBUILD 0x20 -#define TLIF_FAKEPARENT 0x40 -#define TLIF_FILTERED 0x80 - -struct TTreeList_ItemInfo -{ - BYTE flags; - int indent, sortIndex; - - struct TTreeList_ItemInfo *parent; - int iIcon, iOverlay; - LIST<TCHAR> text; - LPARAM data; - LIST<TTreeList_ItemInfo> subItems; - - TTreeList_ItemInfo(int columns = 3, int children = 5): - text(columns), subItems(children), parent(NULL), - flags(0), indent(0), sortIndex(0), iIcon(0), iOverlay(0), data(0) {} - ~TTreeList_ItemInfo() - { - int i; - for (i = text.getCount(); i--; ) - mir_free(text[i]); - text.destroy(); - for (i = subItems.getCount(); i--; ) - delete subItems[i]; - subItems.destroy(); - } -}; - -struct TTreeList_Data -{ - int mode, sortMode; - TCHAR *filter; - HTREELISTITEM hItemSelected; - TTreeList_ItemInfo *root; - - TTreeList_Data() - { - sortMode = 0; - filter = NULL; - mode = TLM_TREE; - root = NULL; - } - ~TTreeList_Data() - { - if (root) delete root; - if (filter) mir_free(filter); - } -}; - -// static utilities -static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data); -static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data); -static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data); -static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data); -static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data); -static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); - -static __forceinline void sttTreeList_SeWindowData(HWND hwnd, HANDLE data) -{ - SetPropA(hwnd, "Miranda.TreeList", (HANDLE)data); -} - -static __forceinline HANDLE sttTreeList_GeWindowData(HWND hwnd) -{ - return GetPropA(hwnd, "Miranda.TreeList"); -} - -// tree list implementation -LPARAM TreeList_GetData(HTREELISTITEM hItem) -{ - return hItem->data; -} - -HTREELISTITEM TreeList_GetRoot(HWND hwnd) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - return data->root; -} - -int TreeList_GetChildrenCount(HTREELISTITEM hItem) -{ - return hItem->subItems.getCount(); -} - -HTREELISTITEM TreeList_GetChild(HTREELISTITEM hItem, int i) -{ - return hItem->subItems[i]; -} - -void TreeList_Create(HWND hwnd) -{ - TTreeList_Data *data = new TTreeList_Data; - data->root = new TTreeList_ItemInfo; - data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT; - data->root->indent = -1; - data->hItemSelected = data->root; - sttTreeList_SeWindowData(hwnd, data); - - ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES | LVS_EX_INFOTIP ); - - HIMAGELIST hIml; - hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1); - ListView_SetImageList (hwnd, hIml, LVSIL_SMALL); - - hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1); - ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPOPEN, 0 )); - ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPSHUT, 0 )); - ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_DOWNARROW, 0 )); - ListView_SetImageList (hwnd, hIml, LVSIL_STATE); -} - -void TreeList_Destroy(HWND hwnd) -{ - ListView_DeleteAllItems(hwnd); - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - delete data; -} - -void TreeList_Reset(HWND hwnd) -{ - ListView_DeleteAllItems(hwnd); - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - delete data->root; - data->root = new TTreeList_ItemInfo; - data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT; - data->root->indent = -1; - data->hItemSelected = data->root; -} - -void TreeList_SetMode(HWND hwnd, int mode) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - data->mode = mode; - ListView_DeleteAllItems(hwnd); - TreeList_Update(hwnd); -} - -void TreeList_SetSortMode(HWND hwnd, int col, BOOL descending) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - if ((col >= 0) && (col < 2)) - data->sortMode = 1 + col * 2 + (descending ? 1 : 0); - else - data->sortMode = 0; - TreeList_Update(hwnd); -} - -void TreeList_SetFilter(HWND hwnd, TCHAR *filter) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - if (data->filter) mir_free(data->filter); - data->filter = NULL; - if (filter) data->filter = mir_tstrdup(filter); - TreeList_Update(hwnd); -} - -HTREELISTITEM TreeList_GetActiveItem(HWND hwnd) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - LVITEM lvi = {0}; - lvi.mask = LVIF_PARAM; - lvi.iItem = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED); - if (lvi.iItem < 0) - return (data->hItemSelected->flags & TLIF_ROOT) ? NULL : data->hItemSelected; - ListView_GetItem(hwnd, &lvi); - return (HTREELISTITEM)lvi.lParam; -} - -HTREELISTITEM TreeList_AddItem(HWND hwnd, HTREELISTITEM hParent, TCHAR *text, LPARAM nodeDdata) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - if (!hParent) hParent = data->root; - - TTreeList_ItemInfo *item = new TTreeList_ItemInfo; - item->data = nodeDdata; - item->parent = hParent; - item->text.insert(mir_tstrdup(text)); - item->flags |= TLIF_MODIFIED; - if (hParent->flags & TLIF_ROOT) - { - item->flags |= TLIF_EXPANDED; - data->hItemSelected = item; - } - item->indent = hParent->indent+1; - hParent->subItems.insert(item); - return item; -} - -void TreeList_ResetItem(HWND hwnd, HTREELISTITEM hParent) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - - for (int i = hParent->subItems.getCount(); i--; ) - delete hParent->subItems[i]; - hParent->subItems.destroy(); - - data->hItemSelected = hParent; - ListView_DeleteAllItems(hwnd); -} - -void TreeList_MakeFakeParent(HTREELISTITEM hItem, BOOL flag) -{ - if (flag) - hItem->flags |= TLIF_FAKEPARENT; - else - hItem->flags &= ~TLIF_FAKEPARENT; - hItem->flags |= TLIF_MODIFIED; -} - -void TreeList_AppendColumn(HTREELISTITEM hItem, TCHAR *text) -{ - hItem->text.insert(mir_tstrdup(text)); - hItem->flags |= TLIF_MODIFIED; -} - -int TreeList_AddIcon(HWND hwnd, HICON hIcon, int iOverlay) -{ - HIMAGELIST hIml = ListView_GetImageList(hwnd, LVSIL_SMALL); - int idx = ImageList_AddIcon(hIml, hIcon); - g_ReleaseIcon(hIcon); - if (iOverlay) ImageList_SetOverlayImage(hIml, idx, iOverlay); - return idx; -} - -void TreeList_SetIcon(HTREELISTITEM hItem, int iIcon, int iOverlay) -{ - if (iIcon >= 0) hItem->iIcon = iIcon; - if (iOverlay >= 0) hItem->iOverlay = iOverlay; - if ((iIcon >= 0) || (iOverlay >= 0)) hItem->flags |= TLIF_MODIFIED; -} - -void TreeList_RecursiveApply(HTREELISTITEM hItem, void (*func)(HTREELISTITEM, LPARAM), LPARAM data) -{ - for ( int i = 0; i < hItem->subItems.getCount(); i++ ) { - func( hItem->subItems[i], data ); - TreeList_RecursiveApply( hItem->subItems[i], func, data ); -} } - -void TreeList_Update(HWND hwnd) -{ - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); - HTREELISTITEM hItem = data->root; - int sortIndex = 0; - - SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); - if (data->sortMode) - TreeList_RecursiveApply(hItem, sttTreeList_SortItems, (LPARAM)data->sortMode); - TreeList_RecursiveApply(hItem, sttTreeList_ResetIndex, (LPARAM)&sortIndex); - if (data->filter) - TreeList_RecursiveApply(hItem, sttTreeList_FilterItems, (LPARAM)data->filter); - for ( int i = ListView_GetItemCount(hwnd); i--; ) { - LVITEM lvi = {0}; - lvi.mask = LVIF_PARAM; - lvi.iItem = i; - lvi.iSubItem = 0; - ListView_GetItem(hwnd, &lvi); - - HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam; - if (( ptli->flags & TLIF_VISIBLE ) && (!data->filter || ( ptli->flags & TLIF_FILTERED ))) { - ptli->flags |= TLIF_HASITEM; - if ( ptli->flags & TLIF_MODIFIED ) { - lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE | LVIF_TEXT; - lvi.iItem = i; - lvi.iSubItem = 0; - lvi.pszText = ptli->text[0]; - lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; - lvi.iImage = ptli->iIcon; - if (data->mode == TLM_TREE) - { - lvi.state = - INDEXTOSTATEIMAGEMASK( - ((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 : - (ptli->flags & TLIF_EXPANDED) ? 1 : 2 ) | - INDEXTOOVERLAYMASK( ptli->iOverlay ); - } else - { - lvi.state = - INDEXTOSTATEIMAGEMASK( - ((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) | - INDEXTOOVERLAYMASK( ptli->iOverlay ); - } - ListView_SetItem(hwnd, &lvi); - for (int j = 1; j < ptli->text.getCount(); ++j) - ListView_SetItemText( hwnd, i, j, ptli->text[j]); - } - } - else ListView_DeleteItem(hwnd, i); - } - if (data->mode == TLM_TREE) - TreeList_RecursiveApply(hItem, sttTreeList_CreateItems, (LPARAM)hwnd); - else - { - for (int i = data->hItemSelected->subItems.getCount(); i--; ) - sttTreeList_CreateItems_List(data->hItemSelected->subItems[i], (LPARAM)hwnd); - for (HTREELISTITEM hItem = data->hItemSelected; !(hItem->flags & TLIF_ROOT); hItem = hItem->parent) - sttTreeList_CreateItems_List(hItem, (LPARAM)hwnd); - } - ListView_SortItems(hwnd, sttTreeList_SortFunc, 0); - SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); - UpdateWindow(hwnd); -} - -BOOL TreeList_ProcessMessage(HWND hwnd, UINT msg, WPARAM, LPARAM lparam, UINT idc, BOOL* ) -{ - LVITEM lvi = {0}; - - switch (msg) { - case WM_NOTIFY: - { - if (((LPNMHDR)lparam)->idFrom != idc) - break; - - TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(GetDlgItem(hwnd, idc)); - switch (((LPNMHDR)lparam)->code) { - case LVN_COLUMNCLICK: - { - LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam; - TreeList_SetSortMode(lpnmlv->hdr.hwndFrom, lpnmlv->iSubItem, FALSE); - } - break; - - case LVN_ITEMACTIVATE: - if (data->mode == TLM_REPORT) { - LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam; - lvi.mask = LVIF_PARAM; - lvi.iItem = lpnmia->iItem; - ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi); - - HTREELISTITEM hItem = (lvi.iItem < 0) ? data-> root : (HTREELISTITEM)lvi.lParam; - if (!hItem->subItems.getCount() && !(hItem->flags & TLIF_FAKEPARENT)) break; - data->hItemSelected = hItem; - - NMTREEVIEW nmtv; - nmtv.hdr.code = TVN_ITEMEXPANDED; - nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom; - nmtv.hdr.idFrom = lpnmia->hdr.idFrom; - nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam; - SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv); - - if (data->mode == TLM_REPORT) - { - ListView_DeleteAllItems(lpnmia->hdr.hwndFrom); - TreeList_Update(lpnmia->hdr.hwndFrom); - } - } - break; - - case LVN_KEYDOWN: - if (data->mode == TLM_TREE) { - LPNMLVKEYDOWN lpnmlvk = (LPNMLVKEYDOWN)lparam; - - lvi.mask = LVIF_PARAM|LVIF_INDENT; - lvi.iItem = ListView_GetNextItem(lpnmlvk->hdr.hwndFrom, -1, LVNI_SELECTED); - if (lvi.iItem < 0) return FALSE; - lvi.iSubItem = 0; - ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi); - HTREELISTITEM hItem = (HTREELISTITEM)lvi.lParam; - - switch (lpnmlvk->wVKey) { - case VK_SUBTRACT: - case VK_LEFT: - { - if ( hItem->subItems.getCount() && (hItem->flags & TLIF_EXPANDED )) { - hItem->flags &= ~TLIF_EXPANDED; - hItem->flags |= TLIF_MODIFIED; - TreeList_Update( lpnmlvk->hdr.hwndFrom ); - } - else if ( hItem->indent && (lpnmlvk->wVKey != VK_SUBTRACT )) { - for ( int i = lvi.iItem; i--; ) { - lvi.mask = LVIF_INDENT; - lvi.iItem = i; - lvi.iSubItem = 0; - ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi); - if (lvi.iIndent < hItem->indent) { - lvi.mask = LVIF_STATE; - lvi.iItem = i; - lvi.iSubItem = 0; - lvi.state = lvi.stateMask = LVIS_FOCUSED|LVNI_SELECTED; - ListView_SetItem(lpnmlvk->hdr.hwndFrom, &lvi); - break; - } } } - break; - } - - case VK_ADD: - case VK_RIGHT: - if ( (hItem->subItems.getCount() || (hItem->flags & TLIF_FAKEPARENT)) && - !( hItem->flags & TLIF_EXPANDED )) - { - hItem->flags |= TLIF_EXPANDED; - hItem->flags |= TLIF_MODIFIED; - - NMTREEVIEW nmtv; - nmtv.hdr.code = TVN_ITEMEXPANDED; - nmtv.hdr.hwndFrom = lpnmlvk->hdr.hwndFrom; - nmtv.hdr.idFrom = lpnmlvk->hdr.idFrom; - nmtv.itemNew.hItem = (HTREEITEM)hItem; - SendMessage(hwnd, WM_NOTIFY, lpnmlvk->hdr.idFrom, (LPARAM)&nmtv); - TreeList_Update( lpnmlvk->hdr.hwndFrom ); - } - break; - } } - break; - - case NM_CLICK: - if (data->mode == TLM_TREE) { - LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam; - LVHITTESTINFO lvhti = {0}; - lvi.mask = LVIF_PARAM; - lvi.iItem = lpnmia->iItem; - ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi); - lvhti.pt = lpnmia->ptAction; - ListView_HitTest(lpnmia->hdr.hwndFrom, &lvhti); - - HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam; - if ((lvhti.iSubItem == 0) && ( (lvhti.flags&LVHT_ONITEM) == LVHT_ONITEMSTATEICON ) && - (ptli->subItems.getCount() || ptli->flags & TLIF_FAKEPARENT)) - { - if ( ptli->flags & TLIF_EXPANDED ) - ptli->flags &= ~TLIF_EXPANDED; - else { - ptli->flags |= TLIF_EXPANDED; - - NMTREEVIEW nmtv; - nmtv.hdr.code = TVN_ITEMEXPANDED; - nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom; - nmtv.hdr.idFrom = lpnmia->hdr.idFrom; - nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam; - SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv); - } - ptli->flags |= TLIF_MODIFIED; - TreeList_Update( lpnmia->hdr.hwndFrom ); - } } - break; - } - break; - } } - return FALSE; -} - -/////////////////////////////////////////////////////////////////////////// -static int sttTreeList_SortItems_Cmp0(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); } -static int sttTreeList_SortItems_Cmp1(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); } -static int sttTreeList_SortItems_Cmp2(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); } -static int sttTreeList_SortItems_Cmp3(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); } -static int sttTreeList_SortItems_Cmp4(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); } -static int sttTreeList_SortItems_Cmp5(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); } - -static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data) -{ - if (!hItem->subItems.getCount()) return; - - typedef int (__cdecl *TQSortCmp)(const void *, const void *); - static TQSortCmp funcs[] = - { - sttTreeList_SortItems_Cmp0, - sttTreeList_SortItems_Cmp1, - sttTreeList_SortItems_Cmp2, - sttTreeList_SortItems_Cmp3, - sttTreeList_SortItems_Cmp4, - sttTreeList_SortItems_Cmp5, - }; - qsort(((SortedList *)&hItem->subItems)->items, hItem->subItems.getCount(), sizeof(void *), funcs[data-1]); -} - -static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data) -{ - hItem->flags &= ~TLIF_HASITEM; - - if ( !hItem->parent || (hItem->parent->flags & TLIF_VISIBLE) && (hItem->parent->flags & TLIF_EXPANDED )) - hItem->flags |= TLIF_VISIBLE; - else - hItem->flags &= ~TLIF_VISIBLE; - - hItem->sortIndex = (*(int *)data)++; -} - -static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data) -{ - int i = 0; - for (i = 0; i < hItem->text.getCount(); ++i) - if (JabberStrIStr(hItem->text[i], (TCHAR *)data)) - break; - - if (i < hItem->text.getCount()) - { - while (!(hItem->flags & TLIF_ROOT)) - { - hItem->flags |= TLIF_FILTERED; - hItem = hItem->parent; - } - } else - { - hItem->flags &= ~TLIF_FILTERED; - } -} - -static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data) -{ - TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data); - if (( hItem->flags & TLIF_VISIBLE ) && (!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) { - LVITEM lvi = {0}; - lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE; - lvi.iIndent = hItem->indent; - lvi.lParam = (LPARAM)hItem; - lvi.pszText = hItem->text[0]; - lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; - lvi.iImage = hItem->iIcon; - lvi.state = - INDEXTOSTATEIMAGEMASK( - ((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 : - (hItem->flags & TLIF_EXPANDED) ? 1 : 2 ) | - INDEXTOOVERLAYMASK(hItem->iOverlay); - - int idx = ListView_InsertItem((HWND)data, &lvi); - for ( int i = 1; i < hItem->text.getCount(); i++ ) - ListView_SetItemText((HWND)data, idx, i, hItem->text[i]); -} } - -static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data) -{ - TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data); - if ((!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) { - LVITEM lvi = {0}; - lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE; - lvi.iIndent = hItem->indent; - lvi.lParam = (LPARAM)hItem; - lvi.pszText = hItem->text[0]; - lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; - lvi.iImage = hItem->iIcon; - lvi.state = - INDEXTOSTATEIMAGEMASK( - ((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) | - INDEXTOOVERLAYMASK( hItem->iOverlay ); - - int idx = ListView_InsertItem((HWND)data, &lvi); - for ( int i = 1; i < hItem->text.getCount(); i++ ) - ListView_SetItemText((HWND)data, idx, i, hItem->text[i]); -} } - -static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM ) -{ - HTREELISTITEM p1 = ( HTREELISTITEM )lParam1, p2 = ( HTREELISTITEM )lParam2; - if ( p1->sortIndex < p2->sortIndex ) - return -1; - - if ( p1->sortIndex > p2->sortIndex ) - return +1; - - return 0; -} diff --git a/protocols/JabberG/jabber_userinfo.cpp b/protocols/JabberG/jabber_userinfo.cpp deleted file mode 100644 index 9d8b476851..0000000000 --- a/protocols/JabberG/jabber_userinfo.cpp +++ /dev/null @@ -1,896 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "m_icolib.h" - -#include <fcntl.h> -#include <io.h> -#include <sys/stat.h> - -#include "jabber_list.h" - -static HANDLE hUserInfoList = NULL; - -struct UserInfoStringBuf -{ - enum { STRINGBUF_INCREMENT = 1024 }; - - TCHAR *buf; - int size; - int offset; - - UserInfoStringBuf() { buf = 0; size = 0; offset = 0; } - ~UserInfoStringBuf() { mir_free(buf); } - - void append( TCHAR *str ) { - if ( !str ) return; - - int length = lstrlen( str ); - if ( size - offset < length + 1 ) { - size += ( length + STRINGBUF_INCREMENT ); - buf = ( TCHAR * )mir_realloc( buf, size * sizeof( TCHAR )); - } - lstrcpy( buf + offset, str ); - offset += length; - } - - TCHAR *allocate( int length ) { - if ( size - offset < length ) { - size += ( length + STRINGBUF_INCREMENT ); - buf = ( TCHAR * )mir_realloc( buf, size * sizeof( TCHAR )); - } - return buf + offset; - } - - void actualize() { - if ( buf ) offset = lstrlen( buf ); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberUserInfoDlgProc - main user info dialog - -struct JabberUserInfoDlgData -{ - CJabberProto* ppro; - HANDLE hContact; - JABBER_LIST_ITEM* item; - int resourceCount; -}; - -enum -{ - INFOLINE_DELETE = 0x80000000, - INFOLINE_MASK = 0x7fffffff, - INFOLINE_BAD_ID = 0x7fffffff, - - INFOLINE_NAME = 1, - INFOLINE_MOOD, - INFOLINE_ACTIVITY, - INFOLINE_TUNE, - INFOLINE_OFFLINE, - INFOLINE_MESSAGE, - INFOLINE_SOFTWARE, - INFOLINE_VERSION, - INFOLINE_SYSTEM, - INFOLINE_PRIORITY, - INFOLINE_IDLE, - INFOLINE_CAPS, - INFOLINE_SOFTWARE_INFORMATION, - INFOLINE_SUBSCRIPTION, - INFOLINE_LOGOFF, - INFOLINE_LOGOFF_MSG, - INFOLINE_LASTACTIVE, -}; - -__forceinline DWORD sttInfoLineId(DWORD res, DWORD type, DWORD line=0) -{ - return - ( type << 24 ) & 0x7f000000 | - ( res << 12 ) & 0x00fff000 | - ( line ) & 0x00000fff; -} - -static HTREEITEM sttFindInfoLine( HWND hwndTree, HTREEITEM htiRoot, LPARAM id=INFOLINE_BAD_ID ) -{ - if ( id == INFOLINE_BAD_ID ) return NULL; - for (HTREEITEM hti = TreeView_GetChild(hwndTree, htiRoot); hti; hti = TreeView_GetNextSibling(hwndTree, hti)) - { - TVITEMEX tvi = {0}; - tvi.mask = TVIF_HANDLE|TVIF_PARAM; - tvi.hItem = hti; - TreeView_GetItem(hwndTree, &tvi); - if ((tvi.lParam&INFOLINE_MASK) == (id&INFOLINE_MASK)) - return hti; - } - return NULL; -} - -void sttCleanupInfo(HWND hwndTree, int stage) -{ - HTREEITEM hItem = TreeView_GetRoot(hwndTree); - while (hItem) { - TVITEMEX tvi = {0}; - tvi.mask = TVIF_HANDLE|TVIF_PARAM; - tvi.hItem = hItem; - TreeView_GetItem(hwndTree, &tvi); - - switch (stage) { - case 0: - tvi.lParam |= INFOLINE_DELETE; - TreeView_SetItem(hwndTree, &tvi); - break; - - case 1: - if (tvi.lParam & INFOLINE_DELETE) { - hItem = TreeView_GetNextSibling(hwndTree, hItem); - TreeView_DeleteItem(hwndTree, tvi.hItem); - continue; - } - break; - } - - HTREEITEM hItemTmp = 0; - if (hItemTmp = TreeView_GetChild(hwndTree, hItem)) - hItem = hItemTmp; - else if (hItemTmp = TreeView_GetNextSibling(hwndTree, hItem)) - hItem = hItemTmp; - else { - while (1) { - if (!(hItem = TreeView_GetParent(hwndTree, hItem))) break; - if (hItemTmp = TreeView_GetNextSibling(hwndTree, hItem)) { - hItem = hItemTmp; - break; - } - } - } - } -} - -static HTREEITEM sttFillInfoLine( HWND hwndTree, HTREEITEM htiRoot, HICON hIcon, TCHAR *title, TCHAR *value, LPARAM id=INFOLINE_BAD_ID, bool expand=false ) -{ - HTREEITEM hti = sttFindInfoLine(hwndTree, htiRoot, id); - - TCHAR buf[256]; - if ( title ) - mir_sntprintf( buf, SIZEOF(buf), _T("%s: %s"), title, value ); - else - lstrcpyn( buf, value, SIZEOF( buf )); - - TVINSERTSTRUCT tvis = {0}; - tvis.hParent = htiRoot; - tvis.hInsertAfter = TVI_LAST; - tvis.itemex.mask = TVIF_TEXT|TVIF_PARAM; - tvis.itemex.pszText = buf; - tvis.itemex.lParam = id; - - if ( hIcon ) { - HIMAGELIST himl = TreeView_GetImageList( hwndTree, TVSIL_NORMAL ); - tvis.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; - tvis.itemex.iImage = - tvis.itemex.iSelectedImage = ImageList_AddIcon( himl, hIcon ); - g_ReleaseIcon( hIcon ); - } - - if ( hti ) { - tvis.itemex.mask |= TVIF_HANDLE; - tvis.itemex.hItem = hti; - TreeView_SetItem( hwndTree, &tvis.itemex ); - } - else { - tvis.itemex.mask |= TVIF_STATE; - tvis.itemex.stateMask = TVIS_EXPANDED; - tvis.itemex.state = expand ? TVIS_EXPANDED : 0; - hti = TreeView_InsertItem( hwndTree, &tvis ); - } - - return hti; -} - -static void sttFillResourceInfo( CJabberProto* ppro, HWND hwndTree, HTREEITEM htiRoot, JABBER_LIST_ITEM *item, int resource ) -{ - TCHAR buf[256]; - HTREEITEM htiResource = htiRoot; - JABBER_RESOURCE_STATUS *res = resource ? &item->resource[resource-1] : &item->itemResource; - - if ( res->resourceName && *res->resourceName ) - htiResource = sttFillInfoLine( hwndTree, htiRoot, LoadSkinnedProtoIcon( ppro->m_szModuleName, res->status ), - TranslateT("Resource"), res->resourceName, sttInfoLineId(resource, INFOLINE_NAME), true ); - - // StatusMsg - sttFillInfoLine( hwndTree, htiResource, NULL /*LoadSkinnedIcon( SKINICON_EVENT_MESSAGE )*/, - TranslateT( "Message" ), res->statusMessage ? res->statusMessage : TranslateT( "<not specified>" ), - sttInfoLineId(resource, INFOLINE_MESSAGE)); - - // Software - HICON hIcon = NULL; - if (ServiceExists(MS_FP_GETCLIENTICONT)) { - if (res->software != NULL) { - mir_sntprintf(buf, SIZEOF(buf), _T("%s %s"), res->software, res->version); - hIcon = (HICON)CallService( MS_FP_GETCLIENTICONT, (WPARAM)buf, 0 ); - } } - - sttFillInfoLine( hwndTree, htiResource, hIcon, TranslateT( "Software" ), - res->software ? res->software : TranslateT( "<not specified>" ), - sttInfoLineId(resource, INFOLINE_SOFTWARE)); - - if(hIcon) - DestroyIcon(hIcon); - - // Version - sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "Version" ), - res->version ? res->version : TranslateT( "<not specified>" ), - sttInfoLineId(resource, INFOLINE_VERSION)); - - // System - sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "System" ), - res->system ? res->system : TranslateT( "<not specified>" ), - sttInfoLineId(resource, INFOLINE_SYSTEM)); - - // Resource priority - TCHAR szPriority[128]; - mir_sntprintf( szPriority, SIZEOF( szPriority ), _T("%d"), (int)res->priority ); - sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "Resource priority" ), szPriority, sttInfoLineId(resource, INFOLINE_PRIORITY)); - - // Idle - if ( res->idleStartTime > 0 ) { - lstrcpyn(buf, _tctime( &res->idleStartTime ), SIZEOF( buf )); - int len = lstrlen(buf); - if (len > 0) buf[len-1] = 0; - } - else if ( !res->idleStartTime ) - lstrcpyn(buf, TranslateT( "unknown" ), SIZEOF( buf )); - else - lstrcpyn(buf, TranslateT( "<not specified>" ), SIZEOF( buf )); - - sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT("Idle since"), buf, sttInfoLineId(resource, INFOLINE_IDLE)); - - // caps - mir_sntprintf( buf, SIZEOF(buf), _T("%s/%s"), item->jid, res->resourceName ); - JabberCapsBits jcb = ppro->GetResourceCapabilites( buf, TRUE ); - - if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) { - HTREEITEM htiCaps = sttFillInfoLine( hwndTree, htiResource, ppro->LoadIconEx( "main" ), NULL, TranslateT( "Client capabilities" ), sttInfoLineId(resource, INFOLINE_CAPS)); - int i; - for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) - if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { - TCHAR szDescription[ 1024 ]; - if ( g_JabberFeatCapPairs[i].szDescription ) - mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s (%s)"), TranslateTS(g_JabberFeatCapPairs[i].szDescription), g_JabberFeatCapPairs[i].szFeature ); - else - mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s"), g_JabberFeatCapPairs[i].szFeature ); - sttFillInfoLine( hwndTree, htiCaps, NULL, NULL, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i)); - } - - for ( int j = 0; j < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); j++, i++ ) - if ( jcb & ppro->m_lstJabberFeatCapPairsDynamic[j]->jcbCap ) { - TCHAR szDescription[ 1024 ]; - if ( ppro->m_lstJabberFeatCapPairsDynamic[j]->szDescription ) - mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s (%s)"), TranslateTS(ppro->m_lstJabberFeatCapPairsDynamic[j]->szDescription), ppro->m_lstJabberFeatCapPairsDynamic[j]->szFeature ); - else - mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s"), ppro->m_lstJabberFeatCapPairsDynamic[j]->szFeature ); - sttFillInfoLine( hwndTree, htiCaps, NULL, NULL, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i)); - } - } - - // Software info - if ( res->pSoftwareInfo ) { - HTREEITEM htiSoftwareInfo = sttFillInfoLine( hwndTree, htiResource, ppro->LoadIconEx( "main" ), NULL, TranslateT( "Software information" ), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION)); - int nLineId = 0; - if ( res->pSoftwareInfo->szOs ) - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Operating system"), res->pSoftwareInfo->szOs, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - if ( res->pSoftwareInfo->szOsVersion ) - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Operating system version"), res->pSoftwareInfo->szOsVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - if ( res->pSoftwareInfo->szSoftware ) - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Software"), res->pSoftwareInfo->szSoftware, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - if ( res->pSoftwareInfo->szSoftwareVersion ) - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Software version"), res->pSoftwareInfo->szSoftwareVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - if ( res->pSoftwareInfo->szXMirandaCoreVersion ) { - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Miranda NG core version"), res->pSoftwareInfo->szXMirandaCoreVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Unicode build"), res->pSoftwareInfo->bXMirandaIsUnicode ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Alpha build"), res->pSoftwareInfo->bXMirandaIsAlpha ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Debug build"), res->pSoftwareInfo->bXMirandaIsDebug ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); - } - } -} - -static void sttFillAdvStatusInfo( CJabberProto* ppro, HWND hwndTree, HTREEITEM htiRoot, DWORD dwInfoLine, HANDLE hContact, TCHAR *szTitle, char *pszSlot ) -{ - char *szAdvStatusIcon = ppro->ReadAdvStatusA(hContact, pszSlot, ADVSTATUS_VAL_ICON); - TCHAR *szAdvStatusTitle = ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TITLE); - TCHAR *szAdvStatusText = ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TEXT); - - if (szAdvStatusIcon && szAdvStatusTitle && *szAdvStatusTitle) { - TCHAR szText[2048]; - if ( szAdvStatusText && *szAdvStatusText ) - mir_sntprintf(szText, 2047, _T("%s (%s)"), TranslateTS(szAdvStatusTitle), szAdvStatusText); - else - mir_sntprintf(szText, 2047, _T("%s"), TranslateTS(szAdvStatusTitle)); - sttFillInfoLine( hwndTree, htiRoot, (HICON)CallService(MS_SKIN2_GETICON, 0, - (LPARAM)szAdvStatusIcon), szTitle, szText, dwInfoLine); - } - - mir_free(szAdvStatusIcon); - mir_free(szAdvStatusTitle); - mir_free(szAdvStatusText); -} - -static void sttFillUserInfo( CJabberProto* ppro, HWND hwndTree, JABBER_LIST_ITEM *item ) -{ - SendMessage( hwndTree, WM_SETREDRAW, FALSE, 0 ); - - sttCleanupInfo(hwndTree, 0); - - HTREEITEM htiRoot = sttFillInfoLine( hwndTree, NULL, ppro->LoadIconEx( "main" ), _T( "JID" ), item->jid, sttInfoLineId(0, INFOLINE_NAME), true ); - TCHAR buf[256]; - - if (HANDLE hContact = ppro->HContactFromJID(item->jid)) { - sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_MOOD), hContact, TranslateT("Mood"), ADVSTATUS_MOOD ); - sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_ACTIVITY), hContact, TranslateT("Activity"), ADVSTATUS_ACTIVITY ); - sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_TUNE), hContact, TranslateT("Tune"), ADVSTATUS_TUNE ); - } - - // subscription - switch ( item->subscription ) { - case SUB_BOTH: - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "both" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); - break; - case SUB_TO: - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "to" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); - break; - case SUB_FROM: - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "from" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); - break; - default: - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "none" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); - break; - } - - // logoff - if ( item->itemResource.idleStartTime > 0 ) { - lstrcpyn( buf, _tctime( &item->itemResource.idleStartTime ), SIZEOF( buf )); - int len = lstrlen(buf); - if (len > 0) buf[len-1] = 0; - } - else if ( !item->itemResource.idleStartTime ) - lstrcpyn( buf, TranslateT( "unknown" ), SIZEOF( buf )); - else - lstrcpyn( buf, TranslateT( "<not specified>" ), SIZEOF( buf )); - - sttFillInfoLine( hwndTree, htiRoot, NULL, - ( item->jid && _tcschr( item->jid, _T( '@' ))) ? TranslateT( "Last logoff time" ) : TranslateT( "Uptime"), buf, - sttInfoLineId(0, INFOLINE_LOGOFF)); - - // logoff msg - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Logoff message" ), - item->itemResource.statusMessage ? item->itemResource.statusMessage : TranslateT( "<not specified>" ), sttInfoLineId(0, INFOLINE_LOGOFF_MSG)); - - // activity - if (( item->lastSeenResource >= 0 ) && ( item->lastSeenResource < item->resourceCount )) - lstrcpyn( buf, item->resource[item->lastSeenResource].resourceName, SIZEOF( buf )); - else - lstrcpyn( buf, TranslateT( "<no information available>" ), SIZEOF( buf )); - - sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Last active resource" ), buf, - sttInfoLineId(0, INFOLINE_LASTACTIVE)); - - // resources - if ( item->resourceCount ) { - for (int i = 0; i < item->resourceCount; ++i) - sttFillResourceInfo( ppro, hwndTree, htiRoot, item, i+1 ); - } - else if ( !_tcschr(item->jid, _T('@')) || (item->itemResource.status != ID_STATUS_OFFLINE)) - sttFillResourceInfo( ppro, hwndTree, htiRoot, item, 0 ); - - sttCleanupInfo(hwndTree, 1); - SendMessage( hwndTree, WM_SETREDRAW, TRUE, 0 ); - - RedrawWindow( hwndTree, NULL, NULL, RDW_INVALIDATE ); -} - -static void sttGetNodeText( HWND hwndTree, HTREEITEM hti, UserInfoStringBuf *buf, int indent = 0 ) -{ - for ( int i = 0; i < indent; ++i ) - buf->append( _T( "\t" )); - - TVITEMEX tvi = {0}; - tvi.mask = TVIF_HANDLE|TVIF_TEXT|TVIF_STATE; - tvi.hItem = hti; - tvi.cchTextMax = 256; - tvi.pszText = buf->allocate( tvi.cchTextMax ); - if (!TreeView_GetItem( hwndTree, &tvi )) { // failure, maybe item was removed... - buf->buf[ buf->offset ] = 0; - buf->actualize(); - return; - } - - buf->actualize(); - buf->append( _T( "\r\n" )); - - if ( tvi.state & TVIS_EXPANDED ) - for ( hti = TreeView_GetChild( hwndTree, hti ); hti; hti = TreeView_GetNextSibling( hwndTree, hti )) - sttGetNodeText( hwndTree, hti, buf, indent + 1 ); -} - -static INT_PTR CALLBACK JabberUserInfoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JabberUserInfoDlgData *dat = (JabberUserInfoDlgData *)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - // lParam is hContact - TranslateDialogDefault( hwndDlg ); - - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_OTHER_USERDETAILS)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS)); - - dat = (JabberUserInfoDlgData *)mir_alloc(sizeof(JabberUserInfoDlgData)); - ZeroMemory(dat, sizeof(JabberUserInfoDlgData)); - dat->resourceCount = -1; - - if ( CallService(MS_DB_CONTACT_IS, (WPARAM)lParam, 0 )) - dat->hContact = (HANDLE)lParam; - else if (!IsBadReadPtr((void *)lParam, sizeof(JABBER_LIST_ITEM))) { - dat->hContact = NULL; - dat->item = (JABBER_LIST_ITEM *)lParam; - } - - { - RECT rc; GetClientRect( hwndDlg, &rc ); - MoveWindow( GetDlgItem( hwndDlg, IDC_TV_INFO ), 5, 5, rc.right-10, rc.bottom-10, TRUE ); - - HIMAGELIST himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR|ILC_COLOR32|ILC_MASK, 5, 1); - ImageList_AddIcon_Icolib(himl, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT)); - TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TV_INFO), himl, TVSIL_NORMAL); - - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); - WindowList_Add(hUserInfoList, hwndDlg, dat->hContact); - } - break; - - case WM_JABBER_REFRESH: - if ( !dat ) break; - - if ( !dat->item ) { - DBVARIANT dbv = {0}; - if ( dat->ppro->JGetStringT(dat->hContact, "jid", &dbv)) - break; - - if (!(dat->item = dat->ppro->ListGetItemPtr(LIST_VCARD_TEMP, dbv.ptszVal))) - dat->item = dat->ppro->ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); - - if (!dat->item) - { - HWND hwndTree = GetDlgItem(hwndDlg, IDC_TV_INFO); - TreeView_DeleteAllItems( hwndTree ); - HTREEITEM htiRoot = sttFillInfoLine( hwndTree, NULL, dat->ppro->LoadIconEx( "main" ), _T( "JID" ), dbv.ptszVal, sttInfoLineId(0, INFOLINE_NAME), true ); - sttFillInfoLine( hwndTree, htiRoot, dat->ppro->LoadIconEx("vcard"), NULL, - TranslateT("Please switch online to see more details.")); - - JFreeVariant(&dbv); - break; - } - - JFreeVariant(&dbv); - } - sttFillUserInfo( dat->ppro, GetDlgItem(hwndDlg, IDC_TV_INFO), dat->item); - break; - - case WM_SIZE: - MoveWindow(GetDlgItem(hwndDlg, IDC_TV_INFO), 5, 5, LOWORD(lParam)-10, HIWORD(lParam)-10, TRUE); - break; - - case WM_CONTEXTMENU: - if ( GetWindowLongPtr(( HWND )wParam, GWL_ID ) == IDC_TV_INFO ) { - HWND hwndTree = GetDlgItem( hwndDlg, IDC_TV_INFO ); - POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; - HTREEITEM hItem = 0; - - if (( pt.x == -1 ) && ( pt.y == -1 )) { - if (hItem = TreeView_GetSelection( hwndTree )) { - RECT rc; - TreeView_GetItemRect( hwndTree, hItem, &rc, TRUE ); - pt.x = rc.left; - pt.y = rc.bottom; - ClientToScreen( hwndTree, &pt ); - } - } - else { - TVHITTESTINFO tvhti = {0}; - tvhti.pt = pt; - ScreenToClient( hwndTree, &tvhti.pt ); - TreeView_HitTest( hwndTree, &tvhti ); - if ( tvhti.flags & TVHT_ONITEM ) { - hItem = tvhti.hItem; - TreeView_Select(hwndTree, hItem, TVGN_CARET); - } } - - if ( hItem ) { - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy only this value")); - AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - int nReturnCmd = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL ); - if ( nReturnCmd == 1 ) { - UserInfoStringBuf buf; - sttGetNodeText( hwndTree, hItem, &buf ); - JabberCopyText( hwndDlg, buf.buf ); - } - else if ( nReturnCmd == 2 ) { - TCHAR szBuffer[ 1024 ]; - TVITEMEX tvi = {0}; - tvi.mask = TVIF_HANDLE|TVIF_TEXT|TVIF_STATE; - tvi.hItem = hItem; - tvi.cchTextMax = SIZEOF( szBuffer ); - tvi.pszText = szBuffer; - if ( TreeView_GetItem( hwndTree, &tvi )) { - if (TCHAR *str = _tcsstr(szBuffer, _T(": "))) - JabberCopyText( hwndDlg, str+2 ); - else - JabberCopyText( hwndDlg, szBuffer ); - } } - DestroyMenu( hMenu ); - } } - break; - - case WM_NOTIFY: - if (( ( LPNMHDR )lParam )->idFrom == 0 ) { - switch (( ( LPNMHDR )lParam )->code ) { - case PSN_INFOCHANGED: - { - HANDLE hContact = ( HANDLE ) (( LPPSHNOTIFY ) lParam )->lParam; - SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, ( LPARAM )hContact ); - } - break; - - case PSN_PARAMCHANGED: - dat->ppro = ( CJabberProto* )( CJabberProto* )(( PSHNOTIFY* )lParam )->lParam; - if ( dat->hContact != NULL ) { - DBVARIANT dbv = {0}; - if ( dat->ppro->JGetStringT(dat->hContact, "jid", &dbv)) - break; - - if ( !(dat->item = dat->ppro->ListGetItemPtr( LIST_VCARD_TEMP, dbv.ptszVal ))) - dat->item = dat->ppro->ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); - JFreeVariant(&dbv); - } - break; - } } - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - - case WM_DESTROY: - WindowList_Remove(hUserInfoList, hwndDlg); - if ( dat ) { - mir_free(dat); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - } - ImageList_Destroy(TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TV_INFO), NULL, TVSIL_NORMAL)); - WindowFreeIcon( hwndDlg ); - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberUserPhotoDlgProc - Jabber photo dialog - -struct USER_PHOTO_INFO -{ - HANDLE hContact; - HBITMAP hBitmap; - CJabberProto* ppro; -}; - -static INT_PTR CALLBACK JabberUserPhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - USER_PHOTO_INFO *photoInfo; - - photoInfo = ( USER_PHOTO_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - // lParam is hContact - TranslateDialogDefault( hwndDlg ); - photoInfo = ( USER_PHOTO_INFO * ) mir_alloc( sizeof( USER_PHOTO_INFO )); - photoInfo->hContact = ( HANDLE ) lParam; - photoInfo->ppro = NULL; - photoInfo->hBitmap = NULL; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) photoInfo ); - SendDlgItemMessage( hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_SAVE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); - SendDlgItemMessage( hwndDlg, IDC_SAVE, BUTTONSETASFLATBTN, TRUE, 0); - ShowWindow( GetDlgItem( hwndDlg, IDC_LOAD ), SW_HIDE ); - ShowWindow( GetDlgItem( hwndDlg, IDC_DELETE ), SW_HIDE ); - break; - - case WM_NOTIFY: - switch ((( LPNMHDR )lParam )->idFrom ) { - case 0: - switch ((( LPNMHDR )lParam )->code ) { - case PSN_INFOCHANGED: - SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 ); - break; - - case PSN_PARAMCHANGED: - photoInfo->ppro = ( CJabberProto* )(( PSHNOTIFY* )lParam )->lParam; - break; - } - break; - } - break; - - case WM_JABBER_REFRESH: - { - JABBER_LIST_ITEM *item; - DBVARIANT dbv; - - if ( photoInfo->hBitmap ) { - DeleteObject( photoInfo->hBitmap ); - photoInfo->hBitmap = NULL; - } - ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE ); - if ( !photoInfo->ppro->JGetStringT( photoInfo->hContact, "jid", &dbv )) { - TCHAR* jid = dbv.ptszVal; - if (( item = photoInfo->ppro->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) - item = photoInfo->ppro->ListGetItemPtr( LIST_ROSTER, jid ); - if ( item != NULL ) { - if ( item->photoFileName ) { - photoInfo->ppro->Log( "Showing picture from " TCHAR_STR_PARAM, item->photoFileName ); - char* p = mir_t2a( item->photoFileName ); - photoInfo->hBitmap = ( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p ); - mir_free( p ); - JabberBitmapPremultiplyChannels(photoInfo->hBitmap); - ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_SHOW ); - } - } - JFreeVariant( &dbv ); - } - InvalidateRect( hwndDlg, NULL, TRUE ); - UpdateWindow( hwndDlg ); - } - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDC_SAVE: - { - DBVARIANT dbv; - JABBER_LIST_ITEM *item; - HANDLE hFile; - static TCHAR szFilter[512]; - unsigned char buffer[3]; - TCHAR szFileName[MAX_PATH]; - DWORD n; - - if ( photoInfo->ppro->JGetStringT( photoInfo->hContact, "jid", &dbv )) - break; - - TCHAR* jid = dbv.ptszVal; - if (( item = photoInfo->ppro->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) - item = photoInfo->ppro->ListGetItemPtr( LIST_ROSTER, jid ); - if ( item != NULL ) { - if (( hFile=CreateFile( item->photoFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) { - if ( ReadFile( hFile, buffer, 3, &n, NULL ) && n==3 ) { - if ( !strncmp(( char* )buffer, "BM", 2 )) { - mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("BMP %s ( *.bmp )"), TranslateT( "format" )); - n = (DWORD)_tcslen( szFilter ); - _tcsncpy( szFilter+n+1, _T("*.BMP"), SIZEOF( szFilter )-n-2 ); - } - else if ( !strncmp(( char* )buffer, "GIF", 3 )) { - mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("GIF %s ( *.gif )"), TranslateT( "format" )); - n = (DWORD)_tcslen( szFilter ); - _tcsncpy( szFilter+n+1, _T("*.GIF"), SIZEOF( szFilter )-n-2 ); - } - else if ( buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff ) { - mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("JPEG %s ( *.jpg;*.jpeg )"), TranslateT( "format" )); - n = (DWORD)_tcslen( szFilter ); - _tcsncpy( szFilter+n+1, _T("*.JPG;*.JPEG"), SIZEOF( szFilter )-n-2 ); - } - else { - mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("%s ( *.* )"), TranslateT( "Unknown format" )); - n = (DWORD)_tcslen( szFilter ); - _tcsncpy( szFilter+n+1, _T("*.*"), SIZEOF( szFilter )-n-2 ); - } - szFilter[SIZEOF( szFilter )-1] = 0; - - OPENFILENAME ofn = { 0 }; - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = hwndDlg; - ofn.hInstance = NULL; - ofn.lpstrFilter = szFilter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 0; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = _MAX_PATH; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = NULL; - ofn.Flags = OFN_OVERWRITEPROMPT; - ofn.nFileOffset = 0; - ofn.nFileExtension = 0; - ofn.lpstrDefExt = NULL; - ofn.lCustData = 0L; - ofn.lpfnHook = NULL; - ofn.lpTemplateName = NULL; - szFileName[0] = '\0'; - if ( GetSaveFileName( &ofn )) { - photoInfo->ppro->Log( "File selected is %s", szFileName ); - CopyFile( item->photoFileName, szFileName, FALSE ); - } - } - CloseHandle( hFile ); - } - } - JFreeVariant( &dbv ); - - } - break; - } - break; - - case WM_PAINT: - if ( !photoInfo->ppro->m_bJabberOnline ) - SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<Photo not available while offline>" )); - else if ( !photoInfo->hBitmap ) - SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<No photo>" )); - else { - BITMAP bm; - POINT ptSize, ptOrg, pt, ptFitSize; - RECT rect; - - SetDlgItemTextA( hwndDlg, IDC_CANVAS, "" ); - HBITMAP hBitmap = photoInfo->hBitmap; - HWND hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS ); - HDC hdcCanvas = GetDC( hwndCanvas ); - HDC hdcMem = CreateCompatibleDC( hdcCanvas ); - SelectObject( hdcMem, hBitmap ); - SetMapMode( hdcMem, GetMapMode( hdcCanvas )); - GetObject( hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm ); - ptSize.x = bm.bmWidth; - ptSize.y = bm.bmHeight; - DPtoLP( hdcCanvas, &ptSize, 1 ); - ptOrg.x = ptOrg.y = 0; - DPtoLP( hdcMem, &ptOrg, 1 ); - GetClientRect( hwndCanvas, &rect ); - InvalidateRect( hwndCanvas, NULL, TRUE ); - UpdateWindow( hwndCanvas ); - if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) { - pt.x = ( rect.right - ptSize.x )/2; - pt.y = ( rect.bottom - ptSize.y )/2; - ptFitSize = ptSize; - } - else { - if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) { - ptFitSize.x = rect.right; - ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x; - pt.x = 0; - pt.y = ( rect.bottom - ptFitSize.y )/2; - } - else { - ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y; - ptFitSize.y = rect.bottom; - pt.x = ( rect.right - ptFitSize.x )/2; - pt.y = 0; - } - } - - if (JabberIsThemeActive && JabberDrawThemeParentBackground && JabberIsThemeActive()) { - RECT rc; GetClientRect(hwndCanvas, &rc); - JabberDrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc); - } - else { - RECT rc; GetClientRect(hwndCanvas, &rc); - FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE)); - } - - if (JabberAlphaBlend && bm.bmBitsPixel == 32 ) { - BLENDFUNCTION bf = {0}; - bf.AlphaFormat = AC_SRC_ALPHA; - bf.BlendOp = AC_SRC_OVER; - bf.SourceConstantAlpha = 255; - JabberAlphaBlend( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf ); - } - else { - SetStretchBltMode( hdcCanvas, COLORONCOLOR ); - StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY ); - } - - DeleteDC( hdcMem ); - } - break; - - case WM_DESTROY: - DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, 0 )); - if ( photoInfo->hBitmap ) { - photoInfo->ppro->Log( "Delete bitmap" ); - DeleteObject( photoInfo->hBitmap ); - } - if ( photoInfo ) mir_free( photoInfo ); - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnInfoInit - initializes user info option dialogs - -int CJabberProto::OnUserInfoInit( WPARAM wParam, LPARAM lParam ) -{ - if ( !CallService( MS_PROTO_ISPROTOCOLLOADED, 0, ( LPARAM )m_szModuleName )) - return 0; - - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof( odp ); - odp.hInstance = hInst; - odp.dwInitParam = ( LPARAM )this; - - HANDLE hContact = ( HANDLE )lParam; - if ( hContact ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { - odp.pfnDlgProc = JabberUserInfoDlgProc; - odp.position = -2000000000; - odp.pszTemplate = MAKEINTRESOURCEA( IDD_INFO_JABBER ); - odp.pszTitle = LPGEN("Account"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = JabberUserPhotoDlgProc; - odp.position = 2000000000; - odp.pszTemplate = MAKEINTRESOURCEA( IDD_VCARD_PHOTO ); - odp.pszTitle = LPGEN("Photo"); - UserInfo_AddPage(wParam, &odp); - } - } - else { - // Show our vcard - OnUserInfoInit_VCard(wParam, lParam); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberUserInfoUpdate - -void JabberUserInfoInit() -{ - hUserInfoList = ( HANDLE )CallService( MS_UTILS_ALLOCWINDOWLIST, 0, 0 ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberUserInfoUpdate - -void JabberUserInfoUpdate( HANDLE hContact ) -{ - if ( !hContact ) - WindowList_BroadcastAsync( hUserInfoList, WM_JABBER_REFRESH, 0, 0 ); - else if ( HWND hwnd = WindowList_Find( hUserInfoList, hContact )) - PostMessage( hwnd, WM_JABBER_REFRESH, 0, 0 ); -} diff --git a/protocols/JabberG/jabber_util.cpp b/protocols/JabberG/jabber_util.cpp deleted file mode 100644 index a7650c5cd0..0000000000 --- a/protocols/JabberG/jabber_util.cpp +++ /dev/null @@ -1,1752 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include <richedit.h> - -#include "jabber_list.h" -#include "jabber_caps.h" - -#include "m_clistint.h" - -extern CRITICAL_SECTION mutex; - -extern int bSecureIM; - -void CJabberProto::SerialInit( void ) -{ - InitializeCriticalSection( &m_csSerial ); - m_nSerial = 0; -} - -void CJabberProto::SerialUninit( void ) -{ - DeleteCriticalSection( &m_csSerial ); -} - -int CJabberProto::SerialNext( void ) -{ - unsigned int ret; - - EnterCriticalSection( &m_csSerial ); - ret = m_nSerial; - m_nSerial++; - LeaveCriticalSection( &m_csSerial ); - return ret; -} - -void CJabberProto::Log( const char* fmt, ... ) -{ - va_list vararg; - va_start( vararg, fmt ); - char* str = ( char* )alloca( 32000 ); - mir_vsnprintf( str, 32000, fmt, vararg ); - va_end( vararg ); - - CallService( MS_NETLIB_LOG, ( WPARAM )m_hNetlibUser, ( LPARAM )str ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberChatRoomHContactFromJID - looks for the char room HCONTACT with required JID - -HANDLE CJabberProto::ChatRoomHContactFromJID( const TCHAR* jid ) -{ - if ( jid == NULL ) - return ( HANDLE )NULL; - - HANDLE hContactMatched = NULL; - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( m_szModuleName, szProto )) { - DBVARIANT dbv; - int result = JGetStringT( hContact, "ChatRoomID", &dbv ); - if ( result ) - result = JGetStringT( hContact, "jid", &dbv ); - - if ( !result ) { - int result; - result = lstrcmpi( jid, dbv.ptszVal ); - JFreeVariant( &dbv ); - if ( !result && JGetByte( hContact, "ChatRoom", 0 ) != 0 ) { - hContactMatched = hContact; - break; - } } } - - hContact = db_find_next(hContact); - } - - return hContactMatched; -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberHContactFromJID - looks for the HCONTACT with required JID - -HANDLE CJabberProto::HContactFromJID( const TCHAR* jid , BOOL bStripResource ) -{ - if ( jid == NULL ) - return ( HANDLE )NULL; - - JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, jid ); - - HANDLE hContactMatched = NULL; - HANDLE hContact = ( HANDLE ) db_find_first(); - while ( hContact != NULL ) { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); - if ( szProto != NULL && !strcmp( m_szModuleName, szProto )) { - DBVARIANT dbv; - int result; - //safer way to check UID (coz some contact have both setting from convert to chat) - if(DBGetContactSettingByte(hContact, szProto, "ChatRoom",0)) - result = JGetStringT( hContact, "ChatRoomID", &dbv ); - else - result = JGetStringT( hContact, "jid", &dbv ); - - if ( !result ) { - int result; - if ( item != NULL ) - result = lstrcmpi( jid, dbv.ptszVal ); - else { - if ( bStripResource == 3 ) { - if (JGetByte(hContact, "ChatRoom", 0)) - result = lstrcmpi( jid, dbv.ptszVal ); // for chat room we have to have full contact matched - else if ( TRUE ) - result = _tcsnicmp( jid, dbv.ptszVal, _tcslen(dbv.ptszVal)); - else - result = JabberCompareJids( jid, dbv.ptszVal ); - } - // most probably it should just look full matching contact - else - result = lstrcmpi( jid, dbv.ptszVal ); - - } - JFreeVariant( &dbv ); - if ( !result ) { - hContactMatched = hContact; - break; - } } } - - hContact = db_find_next(hContact); - } - - return hContactMatched; -} - -TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid ) -{ - if (!jid) return mir_tstrdup(_T("")); - - const TCHAR* p; - TCHAR* nick; - - if (( p = _tcschr( jid, '@' )) == NULL ) - p = _tcschr( jid, '/' ); - - if ( p != NULL ) { - if (( nick=( TCHAR* )mir_alloc( sizeof(TCHAR)*( int( p-jid )+1 ))) != NULL ) { - _tcsncpy( nick, jid, p-jid ); - nick[p-jid] = '\0'; - } - } - else nick = mir_tstrdup( jid ); - return nick; -} - -JABBER_RESOURCE_STATUS* CJabberProto::ResourceInfoFromJID( const TCHAR* jid ) -{ - if ( !jid ) - return NULL; - - JABBER_LIST_ITEM *item = NULL; - if (( item = ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) - item = ListGetItemPtr( LIST_ROSTER, jid ); - if ( item == NULL ) return NULL; - - const TCHAR* p = _tcschr( jid, '/' ); - if ( p == NULL ) - return &item->itemResource; - if ( *++p == '\0' ) return NULL; - - JABBER_RESOURCE_STATUS *r = item->resource; - if ( r == NULL ) return NULL; - - int i; - for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, p ); i++, r++ ); - if ( i >= item->resourceCount ) - return NULL; - - return r; -} - -TCHAR* JabberPrepareJid( LPCTSTR jid ) -{ - if ( !jid ) return NULL; - TCHAR* szNewJid = mir_tstrdup( jid ); - if ( !szNewJid ) return NULL; - TCHAR* pDelimiter = _tcschr( szNewJid, _T('/')); - if ( pDelimiter ) *pDelimiter = _T('\0'); - CharLower( szNewJid ); - if ( pDelimiter ) *pDelimiter = _T('/'); - return szNewJid; -} - -void strdel( char* parBuffer, int len ) -{ - char* p; - for ( p = parBuffer+len; *p != 0; p++ ) - p[ -len ] = *p; - - p[ -len ] = '\0'; -} - -char* __stdcall JabberUrlDecode( char* str ) -{ - char* p, *q; - - if ( str == NULL ) - return NULL; - - for ( p=q=str; *p!='\0'; p++,q++ ) { - if ( *p == '<' ) { - // skip CDATA - if ( !strncmp( p, "<![CDATA[", 9 )) - { - p += 9; - char *tail = strstr(p, "]]>"); - size_t count = tail ? (tail-p) : strlen(p); - memmove(q, p, count); - q += count-1; - p = (tail ? (tail+3) : (p+count)) - 1; - } else - { - *q = *p; - } - } else - if ( *p == '&' ) { - if ( !strncmp( p, "&", 5 )) { *q = '&'; p += 4; } - else if ( !strncmp( p, "'", 6 )) { *q = '\''; p += 5; } - else if ( !strncmp( p, ">", 4 )) { *q = '>'; p += 3; } - else if ( !strncmp( p, "<", 4 )) { *q = '<'; p += 3; } - else if ( !strncmp( p, """, 6 )) { *q = '"'; p += 5; } - else { *q = *p; } - } else - { - *q = *p; - } - } - *q = '\0'; - return str; -} - -void __stdcall JabberUrlDecodeW( WCHAR* str ) -{ - if ( str == NULL ) - return; - - WCHAR* p, *q; - for ( p=q=str; *p!='\0'; p++,q++ ) { - if ( *p == '&' ) { - if ( !wcsncmp( p, L"&", 5 )) { *q = '&'; p += 4; } - else if ( !wcsncmp( p, L"'", 6 )) { *q = '\''; p += 5; } - else if ( !wcsncmp( p, L">", 4 )) { *q = '>'; p += 3; } - else if ( !wcsncmp( p, L"<", 4 )) { *q = '<'; p += 3; } - else if ( !wcsncmp( p, L""", 6 )) { *q = '"'; p += 5; } - else { *q = *p; } - } - else { - *q = *p; - } - } - *q = '\0'; -} - -char* __stdcall JabberUrlEncode( const char* str ) -{ - char* s, *p, *q; - int c; - - if ( str == NULL ) - return NULL; - - for ( c=0,p=( char* )str; *p!='\0'; p++ ) { - switch ( *p ) { - case '&': c += 5; break; - case '\'': c += 6; break; - case '>': c += 4; break; - case '<': c += 4; break; - case '"': c += 6; break; - default: c++; break; - } - } - if (( s=( char* )mir_alloc( c+1 )) != NULL ) { - for ( p=( char* )str,q=s; *p!='\0'; p++ ) { - switch ( *p ) { - case '&': strcpy( q, "&" ); q += 5; break; - case '\'': strcpy( q, "'" ); q += 6; break; - case '>': strcpy( q, ">" ); q += 4; break; - case '<': strcpy( q, "<" ); q += 4; break; - case '"': strcpy( q, """ ); q += 6; break; - default: - if ( *p > 0 && *p < 32 ) { - switch( *p ) { - case '\r': - case '\n': - case '\t': - *q = *p; - break; - default: - *q = '?'; - } - } - else *q = *p; - q++; - break; - } - } - *q = '\0'; - } - - return s; -} - -void __stdcall JabberUtfToTchar( const char* pszValue, size_t cbLen, LPTSTR& dest ) -{ - char* pszCopy = NULL; - bool bNeedsFree = false; - __try - { - // this code can cause access violation when a stack overflow occurs - pszCopy = ( char* )alloca( cbLen+1 ); - } - __except( EXCEPTION_EXECUTE_HANDLER ) - { - bNeedsFree = true; - pszCopy = ( char* )malloc( cbLen+1 ); - } - if ( pszCopy == NULL ) - return; - - memcpy( pszCopy, pszValue, cbLen ); - pszCopy[ cbLen ] = 0; - - JabberUrlDecode( pszCopy ); - - - mir_utf8decode( pszCopy, &dest ); - - - if ( bNeedsFree ) - free( pszCopy ); -} - -char* __stdcall JabberSha1( char* str ) -{ - mir_sha1_ctx sha; - mir_sha1_byte_t digest[20]; - char* result; - int i; - - if ( str == NULL ) - return NULL; - - mir_sha1_init( &sha ); - mir_sha1_append( &sha, (mir_sha1_byte_t* )str, (int)strlen( str )); - mir_sha1_finish( &sha, digest ); - if (( result=( char* )mir_alloc( 41 )) == NULL ) - return NULL; - - for ( i=0; i<20; i++ ) - sprintf( result+( i<<1 ), "%02x", digest[i] ); - return result; -} - -TCHAR* __stdcall JabberStrFixLines( const TCHAR* str ) -{ - if (!str) return NULL; - - const TCHAR *p; - int add = 0; - bool prev_r = false; - bool prev_n = false; - - for (p = str; p && *p; ++p) - if (*p == _T('\r') || *p == _T('\n')) - ++add; - - TCHAR *buf = (TCHAR *)mir_alloc((lstrlen(str) + add + 1) * sizeof(TCHAR)); - TCHAR *res = buf; - - for (p = str; p && *p; ++p) - { - if (*p == _T('\n') && !prev_r) - *res++ = _T('\r'); - if (*p != _T('\r') && *p != _T('\n') && prev_r) - *res++ = _T('\n'); - *res++ = *p; - prev_r = *p == _T('\r'); - prev_n = *p == _T('\n'); - } - *res = 0; - - return buf; -} - -char* __stdcall JabberUnixToDos( const char* str ) -{ - char* p, *q, *res; - int extra; - - if ( str==NULL || str[0]=='\0' ) - return NULL; - - extra = 0; - for ( p=( char* )str; *p!='\0'; p++ ) { - if ( *p == '\n' ) - extra++; - } - if (( res=( char* )mir_alloc( strlen( str )+extra+1 )) != NULL ) { - for ( p=( char* )str,q=res; *p!='\0'; p++,q++ ) { - if ( *p == '\n' ) { - *q = '\r'; - q++; - } - *q = *p; - } - *q = '\0'; - } - return res; -} - -WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str ) -{ - if ( str==NULL || str[0]=='\0' ) - return NULL; - - const WCHAR* p; - WCHAR* q, *res; - int extra = 0; - - for ( p = str; *p!='\0'; p++ ) { - if ( *p == '\n' ) - extra++; - } - if (( res = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str ) + extra + 1 ))) != NULL ) { - for ( p = str,q=res; *p!='\0'; p++,q++ ) { - if ( *p == '\n' ) { - *q = '\r'; - q++; - } - *q = *p; - } - *q = '\0'; - } - return res; -} - -TCHAR* __stdcall JabberHttpUrlEncode( const TCHAR* str ) -{ - TCHAR* p, *q, *res; - - if ( str == NULL ) return NULL; - res = ( TCHAR* ) mir_alloc( 3*_tcslen( str ) + 1 ); - for ( p = ( TCHAR* )str, q = res; *p!='\0'; p++,q++ ) { - if (( *p>='A' && *p<='Z' ) || ( *p>='a' && *p<='z' ) || ( *p>='0' && *p<='9' ) || strchr( "$-_.+!*'(),", *p )!=NULL ) { - *q = *p; - } - else { - wsprintf( q, _T("%%%02X"), *p ); - q += 2; - } - } - *q = '\0'; - return res; -} - -void __stdcall JabberHttpUrlDecode( TCHAR* str ) -{ - TCHAR* p, *q; - unsigned int code; - - if ( str == NULL ) return; - for ( p = q = ( TCHAR* )str; *p!='\0'; p++,q++ ) { - if ( *p=='%' && *( p+1 )!='\0' && isxdigit( *( p+1 )) && *( p+2 )!='\0' && isxdigit( *( p+2 ))) { - _stscanf(( TCHAR* )p+1, _T("%2x"), &code ); - *q = ( unsigned char ) code; - p += 2; - } - else { - *q = *p; - } } - - *q = '\0'; -} - -int __stdcall JabberCombineStatus( int status1, int status2 ) -{ - // Combine according to the following priority ( high to low ) - // ID_STATUS_FREECHAT - // ID_STATUS_ONLINE - // ID_STATUS_DND - // ID_STATUS_AWAY - // ID_STATUS_NA - // ID_STATUS_INVISIBLE ( valid only for TLEN_PLUGIN ) - // ID_STATUS_OFFLINE - // other ID_STATUS in random order ( actually return status1 ) - if ( status1==ID_STATUS_FREECHAT || status2==ID_STATUS_FREECHAT ) - return ID_STATUS_FREECHAT; - if ( status1==ID_STATUS_ONLINE || status2==ID_STATUS_ONLINE ) - return ID_STATUS_ONLINE; - if ( status1==ID_STATUS_DND || status2==ID_STATUS_DND ) - return ID_STATUS_DND; - if ( status1==ID_STATUS_AWAY || status2==ID_STATUS_AWAY ) - return ID_STATUS_AWAY; - if ( status1==ID_STATUS_NA || status2==ID_STATUS_NA ) - return ID_STATUS_NA; - if ( status1==ID_STATUS_INVISIBLE || status2==ID_STATUS_INVISIBLE ) - return ID_STATUS_INVISIBLE; - if ( status1==ID_STATUS_OFFLINE || status2==ID_STATUS_OFFLINE ) - return ID_STATUS_OFFLINE; - return status1; -} - -struct tagErrorCodeToStr { - int code; - TCHAR* str; -} -static JabberErrorCodeToStrMapping[] = { - { JABBER_ERROR_REDIRECT, _T("Redirect") }, - { JABBER_ERROR_BAD_REQUEST, _T("Bad request") }, - { JABBER_ERROR_UNAUTHORIZED, _T("Unauthorized") }, - { JABBER_ERROR_PAYMENT_REQUIRED, _T("Payment required") }, - { JABBER_ERROR_FORBIDDEN, _T("Forbidden") }, - { JABBER_ERROR_NOT_FOUND, _T("Not found") }, - { JABBER_ERROR_NOT_ALLOWED, _T("Not allowed") }, - { JABBER_ERROR_NOT_ACCEPTABLE, _T("Not acceptable") }, - { JABBER_ERROR_REGISTRATION_REQUIRED, _T("Registration required") }, - { JABBER_ERROR_REQUEST_TIMEOUT, _T("Request timeout") }, - { JABBER_ERROR_CONFLICT, _T("Conflict") }, - { JABBER_ERROR_INTERNAL_SERVER_ERROR, _T("Internal server error") }, - { JABBER_ERROR_NOT_IMPLEMENTED, _T("Not implemented") }, - { JABBER_ERROR_REMOTE_SERVER_ERROR, _T("Remote server error") }, - { JABBER_ERROR_SERVICE_UNAVAILABLE, _T("Service unavailable") }, - { JABBER_ERROR_REMOTE_SERVER_TIMEOUT, _T("Remote server timeout") }, - { -1, _T("Unknown error") } -}; - -TCHAR* __stdcall JabberErrorStr( int errorCode ) -{ - int i; - - for ( i=0; JabberErrorCodeToStrMapping[i].code!=-1 && JabberErrorCodeToStrMapping[i].code!=errorCode; i++ ); - return JabberErrorCodeToStrMapping[i].str; -} - -TCHAR* __stdcall JabberErrorMsg( HXML errorNode, int* pErrorCode ) -{ - TCHAR* errorStr = ( TCHAR* )mir_alloc( 256 * sizeof( TCHAR )); - if ( errorNode == NULL ) { - if ( pErrorCode ) - *pErrorCode = -1; - mir_sntprintf( errorStr, 256, _T("%s -1: %s"), TranslateT( "Error" ), TranslateT( "Unknown error message" )); - return errorStr; - } - - int errorCode = -1; - const TCHAR *str = xmlGetAttrValue( errorNode, _T("code")); - if ( str != NULL ) - errorCode = _ttoi( str ); - - str = xmlGetText( errorNode ); - if ( str == NULL ) - str = xmlGetText( xmlGetChild( errorNode, _T("text"))); - if ( str == NULL ) { - for (int i = 0; ; ++i ) { - HXML c = xmlGetChild( errorNode, i ); - if ( c == NULL ) break; - const TCHAR *attr = xmlGetAttrValue( c, _T("xmlns")); - if ( attr && !_tcscmp( attr, _T("urn:ietf:params:xml:ns:xmpp-stanzas"))) { - str = xmlGetName( c ); - break; - } - } - } - - if ( str != NULL ) - mir_sntprintf( errorStr, 256, _T("%s %d: %s\r\n%s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )), str ); - else - mir_sntprintf( errorStr, 256, _T("%s %d: %s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode ))); - - if ( pErrorCode ) - *pErrorCode = errorCode; - return errorStr; -} - -void CJabberProto::SendVisibleInvisiblePresence( BOOL invisible ) -{ - if ( !m_bJabberOnline ) return; - - LISTFOREACH(i, this, LIST_ROSTER) - { - JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); - if ( item == NULL ) - continue; - - HANDLE hContact = HContactFromJID( item->jid ); - if ( hContact == NULL ) - continue; - - WORD apparentMode = JGetWord( hContact, "ApparentMode", 0 ); - if ( invisible==TRUE && apparentMode==ID_STATUS_OFFLINE ) - m_ThreadInfo->send( XmlNode( _T("presence" )) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("invisible"))); - else if ( invisible==FALSE && apparentMode==ID_STATUS_ONLINE ) - SendPresenceTo( m_iStatus, item->jid, NULL ); -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberBase64Encode - -static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen ) -{ - if ( buffer==NULL || bufferLen<=0 ) - return NULL; - - char* res = (char*)mir_alloc(((( bufferLen+2 )*4 )/3 ) + 1); - if ( res == NULL ) - return NULL; - - unsigned char igroup[3]; - char *r = res; - const char* peob = buffer + bufferLen; - for ( const char* p = buffer; p < peob; ) { - igroup[ 0 ] = igroup[ 1 ] = igroup[ 2 ] = 0; - int n; - for ( n=0; n<3; n++ ) { - if ( p >= peob ) break; - igroup[n] = ( unsigned char ) *p; - p++; - } - - if ( n > 0 ) { - r[0] = b64table[ igroup[0]>>2 ]; - r[1] = b64table[ (( igroup[0]&3 )<<4 ) | ( igroup[1]>>4 ) ]; - r[2] = b64table[ (( igroup[1]&0xf )<<2 ) | ( igroup[2]>>6 ) ]; - r[3] = b64table[ igroup[2]&0x3f ]; - - if ( n < 3 ) { - r[3] = '='; - if ( n < 2 ) - r[2] = '='; - } - r += 4; - } } - - *r = '\0'; - - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberBase64Decode - -static unsigned char b64rtable[256]; - -char* __stdcall JabberBase64DecodeW( const WCHAR* str, int *resultLen ) -{ - char *stra = mir_u2a(str); - char *res = JabberBase64Decode(stra, resultLen); - mir_free(stra); - return res; -} - -char* __stdcall JabberBase64Decode( const char* str, int *resultLen ) -{ - char* res; - unsigned char* r, igroup[4], a[4]; - int n, num, count; - - if ( str==NULL || resultLen==NULL ) return NULL; - if (( res=( char* )mir_alloc(( ( strlen( str )+3 )/4 )*3 )) == NULL ) return NULL; - - for ( n=0; n<256; n++ ) - b64rtable[n] = ( unsigned char ) 0x80; - for ( n=0; n<26; n++ ) - b64rtable['A'+n] = n; - for ( n=0; n<26; n++ ) - b64rtable['a'+n] = n + 26; - for ( n=0; n<10; n++ ) - b64rtable['0'+n] = n + 52; - b64rtable['+'] = 62; - b64rtable['/'] = 63; - b64rtable['='] = 0; - count = 0; - for ( r=( unsigned char* )res; *str != '\0'; ) { - for ( n=0; n<4; n++ ) { - if ( BYTE(*str) == '\r' || BYTE(*str) == '\n' ) { - n--; str++; - continue; - } - - if ( BYTE(*str)=='\0' ) { - if ( n == 0 ) - goto LBL_Exit; - mir_free( res ); - return NULL; - } - - if ( b64rtable[BYTE(*str)]==0x80 ) { - mir_free( res ); - return NULL; - } - - a[n] = BYTE(*str); - igroup[n] = b64rtable[BYTE(*str)]; - str++; - } - r[0] = igroup[0]<<2 | igroup[1]>>4; - r[1] = igroup[1]<<4 | igroup[2]>>2; - r[2] = igroup[2]<<6 | igroup[3]; - r += 3; - num = ( a[2]=='='?1:( a[3]=='='?2:3 )); - count += num; - if ( num < 3 ) break; - } -LBL_Exit: - *resultLen = count; - return res; -} - -time_t __stdcall JabberIsoToUnixTime( const TCHAR* stamp ) -{ - struct tm timestamp; - TCHAR date[9]; - int i, y; - time_t t; - - if ( stamp == NULL ) return ( time_t ) 0; - - const TCHAR *p = stamp; - - // Get the date part - for ( i=0; *p!='\0' && i<8 && isdigit( *p ); p++,i++ ) - date[i] = *p; - - // Parse year - if ( i == 6 ) { - // 2-digit year ( 1970-2069 ) - y = ( date[0]-'0' )*10 + ( date[1]-'0' ); - if ( y < 70 ) y += 100; - } - else if ( i == 8 ) { - // 4-digit year - y = ( date[0]-'0' )*1000 + ( date[1]-'0' )*100 + ( date[2]-'0' )*10 + date[3]-'0'; - y -= 1900; - } - else - return ( time_t ) 0; - timestamp.tm_year = y; - // Parse month - timestamp.tm_mon = ( date[i-4]-'0' )*10 + date[i-3]-'0' - 1; - // Parse date - timestamp.tm_mday = ( date[i-2]-'0' )*10 + date[i-1]-'0'; - - // Skip any date/time delimiter - for ( ; *p!='\0' && !isdigit( *p ); p++ ); - - // Parse time - if ( _stscanf( p, _T("%d:%d:%d"), ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec ) != 3 ) - return ( time_t ) 0; - - timestamp.tm_isdst = 0; // DST is already present in _timezone below - t = mktime( ×tamp ); - - _tzset(); - t -= _timezone; - - if ( t >= 0 ) - return t; - else - return ( time_t ) 0; -} - -void CJabberProto::SendPresenceTo( int status, TCHAR* to, HXML extra, const TCHAR *msg ) -{ - if ( !m_bJabberOnline ) return; - - // Send <presence/> update for status ( we won't handle ID_STATUS_OFFLINE here ) - short iPriority = (short)JGetWord( NULL, "Priority", 0 ); - UpdatePriorityMenu(iPriority); - - TCHAR szPriority[40]; - _itot( iPriority, szPriority, 10 ); - - XmlNode p( _T("presence")); p << XCHILD( _T("priority"), szPriority ); - if ( to != NULL ) - p << XATTR( _T("to"), to ); - - if ( extra ) - xmlAddChild( p, extra ); - - // XEP-0115:Entity Capabilities - HXML c = p << XCHILDNS( _T("c"), _T(JABBER_FEAT_ENTITY_CAPS)) << XATTR( _T("node"), _T(JABBER_CAPS_MIRANDA_NODE)) - << XATTR( _T("ver"), szCoreVersion); - - TCHAR szExtCaps[ 512 ] = _T(""); - - if ( m_bGoogleTalk ) - _tcscat( szExtCaps, _T(JABBER_EXT_GTALK_PMUC)); - - if ( bSecureIM ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_SECUREIM)); - } - - if ( m_options.EnableRemoteControl ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_COMMANDS)); - } - - if ( m_options.EnableUserMood ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_USER_MOOD)); - } - - if ( m_options.EnableUserTune ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_USER_TUNE)); - } - - if ( m_options.EnableUserActivity ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_USER_ACTIVITY)); - } - - if ( m_options.AcceptNotes ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, _T(JABBER_EXT_MIR_NOTES)); - } - - // add features enabled through IJabberNetInterface::AddFeatures() - for ( int i = 0; i < m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { - if ( m_uEnabledFeatCapsDynamic & m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { - if ( szExtCaps[0] ) - _tcscat( szExtCaps, _T(" ")); - _tcscat( szExtCaps, m_lstJabberFeatCapPairsDynamic[i]->szExt ); - } - } - - if ( szExtCaps[0] ) - xmlAddAttr( c, _T("ext"), szExtCaps ); - - if ( m_options.EnableAvatars ) { - char hashValue[ 50 ]; - if ( !JGetStaticString( "AvatarHash", NULL, hashValue, sizeof( hashValue ))) { - // XEP-0153: vCard-Based Avatars - HXML x = p << XCHILDNS( _T("x"), _T("vcard-temp:x:update")); - x << XCHILD( _T("photo"), _A2T(hashValue)); - } else { - HXML x = p << XCHILDNS( _T("x"), _T("vcard-temp:x:update")); - x << XCHILD( _T("photo")); - } - } - - EnterCriticalSection( &m_csModeMsgMutex ); - switch ( status ) { - case ID_STATUS_ONLINE: - if ( !msg ) msg = m_modeMsgs.szOnline; - break; - case ID_STATUS_INVISIBLE: - if (!m_bGoogleSharedStatus) p << XATTR( _T("type"), _T("invisible")); - break; - case ID_STATUS_AWAY: - case ID_STATUS_ONTHEPHONE: - case ID_STATUS_OUTTOLUNCH: - p << XCHILD( _T("show"), _T("away")); - if ( !msg ) msg = m_modeMsgs.szAway; - break; - case ID_STATUS_NA: - p << XCHILD( _T("show"), _T("xa")); - if ( !msg ) msg = m_modeMsgs.szNa; - break; - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - p << XCHILD( _T("show"), _T("dnd")); - if ( !msg ) msg = m_modeMsgs.szDnd; - break; - case ID_STATUS_FREECHAT: - p << XCHILD( _T("show"), _T("chat")); - if ( !msg ) msg = m_modeMsgs.szFreechat; - break; - default: - // Should not reach here - break; - } - - if ( msg ) - p << XCHILD( _T("status"), msg ); - - if ( m_bGoogleSharedStatus && !to ) - SendIqGoogleSharedStatus( status, msg ); - - LeaveCriticalSection( &m_csModeMsgMutex ); - m_ThreadInfo->send( p ); -} - -void CJabberProto::SendPresence( int status, bool bSendToAll ) -{ - SendPresenceTo( status, NULL, NULL ); - SendVisibleInvisiblePresence( status == ID_STATUS_INVISIBLE ); - - // Also update status in all chatrooms - if ( bSendToAll ) { - LISTFOREACH(i, this, LIST_CHATROOM) - { - JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); - if ( item != NULL ) { - TCHAR text[ 1024 ]; - mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, item->nick ); - SendPresenceTo( status == ID_STATUS_INVISIBLE ? ID_STATUS_ONLINE : status, text, NULL ); -} } } } - -///////////////////////////////////////////////////////////////////////////////////////// -// Google Shared Status - -void CJabberProto::OnIqResultGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo) { - m_bGoogleSharedStatus = (JABBER_IQ_TYPE_RESULT == pInfo->GetIqType()); - m_bGoogleSharedStatusLock = FALSE; -} - -BOOL CJabberProto::OnIqSetGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo) { - if (JABBER_IQ_TYPE_SET != pInfo->GetIqType()) return FALSE; - if (m_bGoogleSharedStatusLock) return TRUE; - - int status; - HXML query = xmlGetChild(iqNode, _T("query")); - HXML node = xmlGetChild(query, _T("invisible")); - if (0 == _tcsicmp(_T("true"), xmlGetAttrValue(node, _T("value")))) - status = ID_STATUS_INVISIBLE; - else { - LPCTSTR txt = xmlGetText(xmlGetChild(query, _T("show"))); - if (txt && 0 == _tcsicmp(_T("dnd"), txt)) - status = ID_STATUS_DND; - else if (m_iStatus == ID_STATUS_DND || m_iStatus == ID_STATUS_INVISIBLE) - status = ID_STATUS_ONLINE; - else - status = m_iStatus; - } - - if (status != m_iStatus) SetStatus(status); - - return TRUE; -} - -void CJabberProto::SendIqGoogleSharedStatus(int status, const TCHAR *msg) { - XmlNodeIq iq(m_iqManager.AddHandler(&CJabberProto::OnIqResultGoogleSharedStatus, JABBER_IQ_TYPE_SET)); - HXML query = iq << XQUERY(_T(JABBER_FEAT_GTALK_SHARED_STATUS)) << XATTR(_T("version"), _T("2")); - query << XCHILD(_T("status"), msg); - if (status == ID_STATUS_INVISIBLE) { - query << XCHILD(_T("show"), _T("default")); - query << XCHILD(_T("invisible")) << XATTR(_T("value"), _T("true")); - } else { - if (status == ID_STATUS_DND) - query << XCHILD(_T("show"), _T("dnd")); - else - query << XCHILD(_T("show"), _T("default")); - - query << XCHILD(_T("invisible")) << XATTR(_T("value"), _T("false")); - } - m_bGoogleSharedStatusLock = TRUE; - m_ThreadInfo->send(iq); -} - -void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ) -{ - va_list vararg; - char* p; - size_t size, len; - - if ( str == NULL ) return; - - if ( *str==NULL || *sizeAlloced<=0 ) { - *sizeAlloced = 2048; - size = 2048; - *str = ( char* )mir_alloc( size ); - len = 0; - } - else { - len = strlen( *str ); - size = *sizeAlloced - strlen( *str ); - } - - p = *str + len; - va_start( vararg, fmt ); - while ( _vsnprintf( p, size, fmt, vararg ) == -1 ) { - size += 2048; - ( *sizeAlloced ) += 2048; - *str = ( char* )mir_realloc( *str, *sizeAlloced ); - p = *str + len; - } - va_end( vararg ); -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberGetPacketID - converts the xml id attribute into an integer - -int __stdcall JabberGetPacketID( HXML n ) -{ - int result = -1; - - const TCHAR* str = xmlGetAttrValue( n, _T("id")); - if ( str ) - if ( !_tcsncmp( str, _T(JABBER_IQID), SIZEOF( JABBER_IQID )-1 )) - result = _ttoi( str + SIZEOF( JABBER_IQID )-1 ); - - return result; -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberGetClientJID - adds a resource postfix to a JID - -TCHAR* CJabberProto::GetClientJID( const TCHAR* jid, TCHAR* dest, size_t destLen ) -{ - if ( jid == NULL ) - return NULL; - - size_t len = _tcslen( jid ); - if ( len >= destLen ) - len = destLen-1; - - _tcsncpy( dest, jid, len ); - dest[ len ] = '\0'; - - TCHAR* p = _tcschr( dest, '/' ); - - JABBER_LIST_ITEM* LI = ListGetItemPtr( LIST_ROSTER, jid ); - if ( LI && LI->resourceCount == 1 && LI->resource[ 0 ].szCapsNode && - _tcsicmp( LI->resource[ 0 ].szCapsNode, _T( "http://talk.google.com/xmpp/bot/caps")) == 0) - { - if ( p ) *p = 0; - return dest; - } - - if ( p == NULL ) { - TCHAR* resource = ListGetBestResourceNamePtr( jid ); - if ( resource != NULL ) - mir_sntprintf( dest+len, destLen-len-1, _T("/%s"), resource ); - } - - return dest; -} - -/////////////////////////////////////////////////////////////////////////////// -// JabberStripJid - strips a resource postfix from a JID - -TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen ) -{ - if ( jid == NULL ) - *dest = 0; - else { - size_t len = _tcslen( jid ); - if ( len >= destLen ) - len = destLen-1; - - memcpy( dest, jid, len * sizeof( TCHAR )); - dest[ len ] = 0; - - TCHAR* p = _tcschr( dest, '/' ); - if ( p != NULL ) - *p = 0; - } - - return dest; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetPictureType - tries to autodetect the picture type from the buffer - -int __stdcall JabberGetPictureType( const char* buf ) -{ - if ( buf != NULL ) { - if ( memcmp( buf, "GIF8", 4 ) == 0 ) return PA_FORMAT_GIF; - if ( memcmp( buf, "\x89PNG", 4 ) == 0 ) return PA_FORMAT_PNG; - if ( memcmp( buf, "BM", 2 ) == 0 ) return PA_FORMAT_BMP; - if ( memcmp( buf, "\xFF\xD8", 2 ) == 0 ) return PA_FORMAT_JPEG; - } - - return PA_FORMAT_UNKNOWN; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// TStringPairs class members - -TStringPairs::TStringPairs( char* buffer ) : - elems( NULL ) -{ - TStringPairsElem tempElem[ 100 ]; - - char* token = strtok( buffer, "," ); - - for ( numElems=0; token != NULL; numElems++ ) { - char* p = strchr( token, '=' ), *p1; - if ( p == NULL ) - break; - - while( isspace( *token )) - token++; - - tempElem[ numElems ].name = rtrim( token ); - *p++ = 0; - if (( p1 = strchr( p, '\"' )) != NULL ) { - *p1 = 0; - p = p1+1; - } - - if (( p1 = strrchr( p, '\"' )) != NULL ) - *p1 = 0; - - tempElem[ numElems ].value = rtrim( p ); - token = strtok( NULL, "," ); - } - - if ( numElems ) { - elems = new TStringPairsElem[ numElems ]; - memcpy( elems, tempElem, sizeof(tempElem[0]) * numElems ); -} } - -TStringPairs::~TStringPairs() -{ - delete[] elems; -} - -const char* TStringPairs::operator[]( const char* key ) const -{ - for ( int i = 0; i < numElems; i++ ) - if ( !strcmp( elems[i].name, key )) - return elems[i].value; - - return ""; -} - -//////////////////////////////////////////////////////////////////////// -// Manage combo boxes with recent item list - -void CJabberProto::ComboLoadRecentStrings(HWND hwndDlg, UINT idcCombo, char *param, int recentCount) -{ - for (int i = 0; i < recentCount; ++i) { - DBVARIANT dbv; - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "%s%d", param, i); - if (!JGetStringT(NULL, setting, &dbv)) { - SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)dbv.ptszVal); - JFreeVariant(&dbv); - } } - if (!SendDlgItemMessage(hwndDlg, idcCombo, CB_GETCOUNT, 0, 0)) - SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)_T("")); -} - -void CJabberProto::ComboAddRecentString(HWND hwndDlg, UINT idcCombo, char *param, TCHAR *string, int recentCount) -{ - if (!string || !*string) - return; - if (SendDlgItemMessage(hwndDlg, idcCombo, CB_FINDSTRING, (WPARAM)-1, (LPARAM)string) != CB_ERR) - return; - - int id; - SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)string); - if ((id = SendDlgItemMessage(hwndDlg, idcCombo, CB_FINDSTRING, (WPARAM)-1, (LPARAM)_T(""))) != CB_ERR) - SendDlgItemMessage(hwndDlg, idcCombo, CB_DELETESTRING, id, 0); - - id = JGetByte(NULL, param, 0); - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, sizeof(setting), "%s%d", param, id); - JSetStringT(NULL, setting, string); - JSetByte(NULL, param, (id+1)%recentCount); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// jabber frame maintenance code - -static VOID CALLBACK sttRebuildInfoFrameApcProc( void* param ) -{ - CJabberProto *ppro = (CJabberProto *)param; - if (!ppro->m_pInfoFrame) - return; - - ppro->m_pInfoFrame->LockUpdates(); - if (!ppro->m_bJabberOnline) - { - ppro->m_pInfoFrame->RemoveInfoItem("$/PEP"); - ppro->m_pInfoFrame->RemoveInfoItem("$/Transports"); - ppro->m_pInfoFrame->UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), TranslateT("Offline")); - } else - { - ppro->m_pInfoFrame->UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), ppro->m_szJabberJID); - - if (!ppro->m_bPepSupported) - { - ppro->m_pInfoFrame->RemoveInfoItem("$/PEP"); - } else - { - ppro->m_pInfoFrame->RemoveInfoItem("$/PEP/"); - ppro->m_pInfoFrame->CreateInfoItem("$/PEP", false); - ppro->m_pInfoFrame->UpdateInfoItem("$/PEP", ppro->GetIconHandle(IDI_PL_LIST_ANY), TranslateT("Advanced Status")); - - ppro->m_pInfoFrame->CreateInfoItem("$/PEP/mood", true); - ppro->m_pInfoFrame->SetInfoItemCallback("$/PEP/mood", &CJabberProto::InfoFrame_OnUserMood); - ppro->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); - - ppro->m_pInfoFrame->CreateInfoItem("$/PEP/activity", true); - ppro->m_pInfoFrame->SetInfoItemCallback("$/PEP/activity", &CJabberProto::InfoFrame_OnUserActivity); - ppro->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); - } - - ppro->m_pInfoFrame->RemoveInfoItem("$/Transports/"); - ppro->m_pInfoFrame->CreateInfoItem("$/Transports", false); - ppro->m_pInfoFrame->UpdateInfoItem("$/Transports", ppro->GetIconHandle(IDI_TRANSPORT), TranslateT("Transports")); - - JABBER_LIST_ITEM *item = NULL; - LISTFOREACH(i, ppro, LIST_ROSTER) - { - if (( item=ppro->ListGetItemPtrFromIndex( i )) != NULL ) { - if ( _tcschr( item->jid, '@' )==NULL && _tcschr( item->jid, '/' )==NULL && item->subscription!=SUB_NONE ) { - HANDLE hContact = ppro->HContactFromJID( item->jid ); - if ( hContact == NULL ) continue; - - char name[128]; - char *jid_copy = mir_t2a(item->jid); - mir_snprintf(name, SIZEOF(name), "$/Transports/%s", jid_copy); - ppro->m_pInfoFrame->CreateInfoItem(name, true, (LPARAM)hContact); - ppro->m_pInfoFrame->UpdateInfoItem(name, ppro->GetIconHandle(IDI_TRANSPORTL), (TCHAR *)item->jid); - ppro->m_pInfoFrame->SetInfoItemCallback(name, &CJabberProto::InfoFrame_OnTransport); - mir_free(jid_copy); - } } - } - } - ppro->m_pInfoFrame->Update(); -} - -void CJabberProto::RebuildInfoFrame() -{ - CallFunctionAsync(sttRebuildInfoFrameApcProc, this); -} - -//////////////////////////////////////////////////////////////////////// -// case-insensitive _tcsstr -const TCHAR *JabberStrIStr( const TCHAR *str, const TCHAR *substr) -{ - TCHAR *str_up = NEWTSTR_ALLOCA(str); - TCHAR *substr_up = NEWTSTR_ALLOCA(substr); - - CharUpperBuff(str_up, lstrlen(str_up)); - CharUpperBuff(substr_up, lstrlen(substr_up)); - - TCHAR* p = _tcsstr(str_up, substr_up); - return p ? (str + (p - str_up)) : NULL; -} - -//////////////////////////////////////////////////////////////////////// -// clipboard processing -void JabberCopyText(HWND hwnd, TCHAR *text) -{ - if (!hwnd || !text) return; - - OpenClipboard(hwnd); - EmptyClipboard(); - HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR)*(lstrlen(text)+1)); - TCHAR *s = (TCHAR *)GlobalLock(hMem); - lstrcpy(s, text); - GlobalUnlock(hMem); - SetClipboardData(CF_UNICODETEXT, hMem); - CloseClipboard(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// One string entry dialog - -struct JabberEnterStringParams -{ - CJabberProto* ppro; - - int type; - TCHAR* caption; - TCHAR* result; - size_t resultLen; - char *windowName; - int recentCount; - int timeout; - - int idcControl; - int height; -}; - -static int sttEnterStringResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDC_TXT_MULTILINE: - case IDC_TXT_COMBO: - case IDC_TXT_RICHEDIT: - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - case IDOK: - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; -} - -static INT_PTR CALLBACK sttEnterStringDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - JabberEnterStringParams *params = (JabberEnterStringParams *)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - { - //SetWindowPos( hwndDlg, HWND_TOPMOST ,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE ); - TranslateDialogDefault( hwndDlg ); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_OTHER_RENAME)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_RENAME)); - JabberEnterStringParams *params = (JabberEnterStringParams *)lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )params ); - SetWindowText( hwndDlg, params->caption ); - - RECT rc; GetWindowRect(hwndDlg, &rc); - switch (params->type) - { - case JES_PASSWORD: - { - params->idcControl = IDC_TXT_PASSWORD; - params->height = rc.bottom-rc.top; - break; - } - case JES_MULTINE: - { - params->idcControl = IDC_TXT_MULTILINE; - params->height = 0; - rc.bottom += (rc.bottom-rc.top) * 2; - SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE|SWP_NOREPOSITION); - break; - } - case JES_COMBO: - { - params->idcControl = IDC_TXT_COMBO; - params->height = rc.bottom-rc.top; - if (params->windowName && params->recentCount) - params->ppro->ComboLoadRecentStrings(hwndDlg, IDC_TXT_COMBO, params->windowName, params->recentCount); - break; - } - case JES_RICHEDIT: - { - params->idcControl = IDC_TXT_RICHEDIT; - SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_AUTOURLDETECT, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_SETEVENTMASK, 0, ENM_LINK); - params->height = 0; - rc.bottom += (rc.bottom-rc.top) * 2; - SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE|SWP_NOREPOSITION); - break; - } - } - - ShowWindow(GetDlgItem(hwndDlg, params->idcControl), SW_SHOW); - SetDlgItemText( hwndDlg, params->idcControl, params->result ); - - if (params->windowName) - Utils_RestoreWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); - - SetTimer(hwndDlg, 1000, 50, NULL); - - if (params->timeout > 0) - { - SetTimer(hwndDlg, 1001, 1000, NULL); - TCHAR buf[128]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), params->timeout); - SetDlgItemText(hwndDlg, IDOK, buf); - } - - return TRUE; - } - case WM_DESTROY: - WindowFreeIcon( hwndDlg ); - break; - case WM_TIMER: - { - switch (wParam) - { - case 1000: - KillTimer(hwndDlg,1000); - EnableWindow(GetParent(hwndDlg), TRUE); - return TRUE; - - case 1001: - { - TCHAR buf[128]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), --params->timeout); - SetDlgItemText(hwndDlg, IDOK, buf); - - if (params->timeout < 0) - { - KillTimer(hwndDlg, 1001); - UIEmulateBtnClick(hwndDlg, IDOK); - } - - return TRUE; - } - } - } - case WM_SIZE: - { - UTILRESIZEDIALOG urd = {0}; - urd.cbSize = sizeof(urd); - urd.hInstance = hInst; - urd.hwndDlg = hwndDlg; - urd.lpTemplate = MAKEINTRESOURCEA(IDD_GROUPCHAT_INPUT); - urd.pfnResizer = sttEnterStringResizer; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); - break; - } - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - if (params && params->height) - lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y = params->height; - break; - } - case WM_NOTIFY: - { - ENLINK *param = (ENLINK *)lParam; - if (param->nmhdr.idFrom != IDC_TXT_RICHEDIT) break; - if (param->nmhdr.code != EN_LINK) break; - if (param->msg != WM_LBUTTONUP) break; - - CHARRANGE sel; - SendMessage(param->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel); - if (sel.cpMin != sel.cpMax) break; // allow link selection - - TEXTRANGE tr; - tr.chrg = param->chrg; - tr.lpstrText = (TCHAR *)mir_alloc(sizeof(TCHAR)*(tr.chrg.cpMax - tr.chrg.cpMin + 2)); - SendMessage(param->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM) & tr); - - char *tmp = mir_t2a(tr.lpstrText); - CallService(MS_UTILS_OPENURL, 1, (LPARAM)tmp); - mir_free(tmp); - mir_free(tr.lpstrText); - return TRUE; - } - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDOK: - GetDlgItemText( hwndDlg, params->idcControl, params->result, (int)params->resultLen ); - params->result[ params->resultLen-1 ] = 0; - - if ((params->type == JES_COMBO) && params->windowName && params->recentCount) - params->ppro->ComboAddRecentString(hwndDlg, IDC_TXT_COMBO, params->windowName, params->result, params->recentCount); - if (params->windowName) - Utils_SaveWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); - - EndDialog( hwndDlg, 1 ); - break; - - case IDCANCEL: - if (params->windowName) - Utils_SaveWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); - - EndDialog( hwndDlg, 0 ); - break; - - case IDC_TXT_MULTILINE: - case IDC_TXT_RICHEDIT: - if ((HIWORD(wParam) != EN_SETFOCUS) && (HIWORD(wParam) != EN_KILLFOCUS)) - { - SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); - KillTimer(hwndDlg, 1001); - } - break; - - case IDC_TXT_COMBO: - if ((HIWORD(wParam) != CBN_SETFOCUS) && (HIWORD(wParam) != CBN_KILLFOCUS)) - { - SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); - KillTimer(hwndDlg, 1001); - } - break; - } } - - return FALSE; -} - -BOOL CJabberProto::EnterString(TCHAR *result, size_t resultLen, TCHAR *caption, int type, char *windowName, int recentCount, int timeout) -{ - bool free_caption = false; - if (!caption || (caption==result)) - { - free_caption = true; - caption = mir_tstrdup( result ); - result[ 0 ] = _T('\0'); - } - - JabberEnterStringParams params = { this, type, caption, result, resultLen, windowName, recentCount, timeout }; - - BOOL bRetVal = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INPUT ), GetForegroundWindow(), sttEnterStringDlgProc, LPARAM( ¶ms )); - - if (free_caption) mir_free( caption ); - - return bRetVal; -} - -//////////////////////////////////////////////////////////////////////// -// Premultiply bitmap channels for 32-bit bitmaps -void JabberBitmapPremultiplyChannels(HBITMAP hBitmap) -{ - BITMAP bmp; - DWORD dwLen; - BYTE *p; - int x, y; - - GetObject(hBitmap, sizeof(bmp), &bmp); - - if (bmp.bmBitsPixel != 32) - return; - - dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); - p = (BYTE *)malloc(dwLen); - if (p == NULL) - return; - memset(p, 0, dwLen); - - GetBitmapBits(hBitmap, dwLen, p); - - for (y = 0; y < bmp.bmHeight; ++y) - { - BYTE *px = p + bmp.bmWidth * 4 * y; - - for (x = 0; x < bmp.bmWidth; ++x) - { - px[0] = px[0] * px[3] / 255; - px[1] = px[1] * px[3] / 255; - px[2] = px[2] * px[3] / 255; - - px += 4; - } - } - - SetBitmapBits(hBitmap, dwLen, p); - - free(p); -} - -// Last resource map -void CJabberProto::CleanLastResourceMap() -{ - EnterCriticalSection( &m_csLastResourceMap ); - - m_dwResourceMapPointer = 0; - ZeroMemory( m_ulpResourceToDbEventMap, sizeof( m_ulpResourceToDbEventMap )); - - while ( m_pLastResourceList ) { - void *pNext = (( void ** )m_pLastResourceList )[ 0 ]; - mir_free( m_pLastResourceList ); - m_pLastResourceList = pNext; - } - - LeaveCriticalSection( &m_csLastResourceMap ); -} - -// lock CS before use -BOOL CJabberProto::IsLastResourceExists( void *pResource ) -{ - if ( !pResource ) - return FALSE; - - void *pOurResource = m_pLastResourceList; - while ( pOurResource ) { - if ( pOurResource == pResource ) - return TRUE; - pOurResource = (( void ** )pOurResource)[ 0 ]; - } - return FALSE; -} - -// lock CS before use -void* CJabberProto::AddToLastResourceMap( LPCTSTR szFullJid ) -{ - // detach resource from full jid - const TCHAR* szResource = _tcschr( szFullJid, '/' ); - if ( szResource == NULL ) - return NULL; - if ( *++szResource == '\0' ) - return NULL; - - DWORD dwResourceCount = 0; - - void *pNewTailResource = NULL; - void *pOurResource = m_pLastResourceList; - while ( pOurResource ) { - dwResourceCount++; - - if ( !_tcscmp(( TCHAR * )(( BYTE * )pOurResource + sizeof( void * )), szResource )) - return pOurResource; - - void *pTmp = (( void ** )pOurResource )[ 0 ]; - if ( pTmp && !((( void ** )pTmp )[ 0 ])) - pNewTailResource = pOurResource; - pOurResource = pTmp; - } - - if ( pNewTailResource && ( dwResourceCount > ( SIZEOF( m_ulpResourceToDbEventMap ) / 2 ))) { - void *pTmp = (( void ** )pNewTailResource )[ 0 ]; - (( void ** )pNewTailResource )[ 0 ] = NULL; - mir_free( pTmp ); - } - - void *pNewResource = mir_alloc( sizeof( void * ) + sizeof( TCHAR ) * ( _tcslen( szResource ) + 1 )); - if ( !pNewResource ) - return NULL; - - (( void ** )pNewResource)[ 0 ] = m_pLastResourceList; - _tcscpy(( TCHAR * )(( BYTE * )pNewResource + sizeof( void * )), szResource ); - - m_pLastResourceList = pNewResource; - - return pNewResource; -} - -// lock CS before use -TCHAR* CJabberProto::FindLastResourceByDbEvent( HANDLE hDbEvent ) -{ - for ( int i = 0; i < SIZEOF( m_ulpResourceToDbEventMap ); i += 2 ) { - if ( m_ulpResourceToDbEventMap[ i ] == ( ULONG_PTR )hDbEvent ) { - TCHAR *szRetVal = ( TCHAR * )( m_ulpResourceToDbEventMap[ i + 1 ] + sizeof( void * )); - m_ulpResourceToDbEventMap[ i ] = 0; - m_ulpResourceToDbEventMap[ i + 1 ] = 0; - return szRetVal; - } - } - return NULL; -} - -BOOL CJabberProto::IsMyOwnJID( LPCTSTR szJID ) -{ - if ( !m_ThreadInfo ) - return FALSE; - - TCHAR* szFrom = JabberPrepareJid( szJID ); - if ( !szFrom ) - return FALSE; - - TCHAR* szTo = JabberPrepareJid( m_ThreadInfo->fullJID ); - if ( !szTo ) { - mir_free( szFrom ); - return FALSE; - } - - TCHAR* pDelimiter = _tcschr( szFrom, _T('/')); - if ( pDelimiter ) *pDelimiter = _T('\0'); - - pDelimiter = _tcschr( szTo, _T('/')); - if ( pDelimiter ) *pDelimiter = _T('\0'); - - BOOL bRetVal = _tcscmp( szFrom, szTo ) == 0; - - mir_free( szFrom ); - mir_free( szTo ); - - return bRetVal; -} - -void __cdecl CJabberProto::LoadHttpAvatars(void* param) -{ - OBJLIST<JABBER_HTTP_AVATARS> &avs = *(OBJLIST<JABBER_HTTP_AVATARS>*)param; - HANDLE hHttpCon = NULL; - for (int i = 0; i < avs.getCount(); ++i) - { - NETLIBHTTPREQUEST nlhr = {0}; - nlhr.cbSize = sizeof(nlhr); - nlhr.requestType = REQUEST_GET; - nlhr.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT; - nlhr.szUrl = avs[i].Url; - nlhr.nlc = hHttpCon; - - NETLIBHTTPREQUEST * res = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&nlhr); - if (res) - { - hHttpCon = res->nlc; - if ( res->resultCode == 200 && res->dataLength ) - { - int pictureType = JabberGetPictureType( res->pData ); - if (pictureType != PA_FORMAT_UNKNOWN) - { - TCHAR tszFileName[ MAX_PATH ]; - - PROTO_AVATAR_INFORMATIONT AI; - AI.cbSize = sizeof(AI); - AI.format = pictureType; - AI.hContact = avs[i].hContact; - - if ( JGetByte( AI.hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) { - GetAvatarFileName( AI.hContact, tszFileName, SIZEOF(tszFileName)); - DeleteFile( tszFileName ); - } - - JSetByte( AI.hContact, "AvatarType", pictureType ); - - char cmpsha[ 41 ]; - char buffer[ 41 ]; - mir_sha1_byte_t digest[20]; - mir_sha1_ctx sha; - mir_sha1_init( &sha ); - mir_sha1_append( &sha, ( mir_sha1_byte_t* )res->pData, res->dataLength ); - mir_sha1_finish( &sha, digest ); - for ( int i=0; i<20; i++ ) - sprintf( buffer+( i<<1 ), "%02x", digest[i] ); - - if (JGetStaticString("AvatarSaved", AI.hContact, cmpsha, sizeof(cmpsha)) || strnicmp(cmpsha, buffer, sizeof(buffer))) - { - GetAvatarFileName( AI.hContact, tszFileName, SIZEOF(tszFileName)); - _tcsncpy(AI.filename, tszFileName, SIZEOF(AI.filename)); - FILE* out = _tfopen( tszFileName, _T("wb")); - if ( out != NULL ) { - fwrite( res->pData, res->dataLength, 1, out ); - fclose( out ); - JSetString( AI.hContact, "AvatarSaved", buffer ); - JSendBroadcast( AI.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0 ); - Log("Broadcast new avatar: %s",AI.filename); - } - else JSendBroadcast( AI.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, &AI, 0 ); - } - } - } - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)res); - } - else - hHttpCon = NULL; - } - delete &avs; - if ( hHttpCon ) - Netlib_CloseHandle(hHttpCon); -} \ No newline at end of file diff --git a/protocols/JabberG/jabber_vcard.cpp b/protocols/JabberG/jabber_vcard.cpp deleted file mode 100644 index 691f3516ed..0000000000 --- a/protocols/JabberG/jabber_vcard.cpp +++ /dev/null @@ -1,1250 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include <sys/stat.h> -#include <fcntl.h> -#include <io.h> -#include "jabber_iq.h" -#include "jabber_caps.h" - -///////////////////////////////////////////////////////////////////////////////////////// - -int CJabberProto::SendGetVcard( const TCHAR* jid ) -{ - if (!m_bJabberOnline) return 0; - - int iqId = SerialNext(); - JABBER_IQ_PROCID procId = !lstrcmp( jid, m_szJabberJID ) ? IQ_PROC_GETVCARD : IQ_PROC_NONE; - - IqAdd( iqId, procId, &CJabberProto::OnIqResultGetVcard ); - m_ThreadInfo->send( - XmlNodeIq( _T("get"), iqId, jid ) << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)) - << XATTR( _T("prodid"), _T("-//HandGen//NONSGML vGen v1.0//EN")) << XATTR( _T("version"), _T("2.0"))); - - return iqId; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void SetDialogField( CJabberProto* ppro, HWND hwndDlg, int nDlgItem, char* key, bool bTranslate = false ) -{ - DBVARIANT dbv; - - if ( !DBGetContactSettingTString( NULL, ppro->m_szModuleName, key, &dbv )) { - SetDlgItemText( hwndDlg, nDlgItem, ( bTranslate ) ? TranslateTS(dbv.ptszVal) : dbv.ptszVal ); - JFreeVariant( &dbv ); - } - else SetDlgItemTextA( hwndDlg, nDlgItem, "" ); -} - -static INT_PTR CALLBACK PersonalDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - const unsigned long iPageId = 0; - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - if ( lParam ) { - ppro = ( CJabberProto* )lParam; - TranslateDialogDefault( hwndDlg ); - SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Male" )); - SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Female" )); - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); - ppro->WindowSubscribe(hwndDlg); - } - break; - - case WM_JABBER_REFRESH_VCARD: - SetDialogField( ppro, hwndDlg, IDC_FULLNAME, "FullName" ); - SetDialogField( ppro, hwndDlg, IDC_NICKNAME, "Nick" ); - SetDialogField( ppro, hwndDlg, IDC_FIRSTNAME, "FirstName" ); - SetDialogField( ppro, hwndDlg, IDC_MIDDLE, "MiddleName" ); - SetDialogField( ppro, hwndDlg, IDC_LASTNAME, "LastName" ); - SetDialogField( ppro, hwndDlg, IDC_BIRTH, "BirthDate" ); - SetDialogField( ppro, hwndDlg, IDC_GENDER, "GenderString", true ); - SetDialogField( ppro, hwndDlg, IDC_OCCUPATION, "Role" ); - SetDialogField( ppro, hwndDlg, IDC_HOMEPAGE, "Homepage" ); - break; - - case WM_COMMAND: - if (( ( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) || - (( HWND )lParam==GetDlgItem( hwndDlg, IDC_GENDER ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) - { - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->idFrom == 0) { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - ppro->m_vCardUpdates &= ~(1UL<<iPageId); - ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!ppro->m_vCardUpdates) - ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); - break; - } } - break; - - case WM_DESTROY: - ppro->WindowUnsubscribe(hwndDlg); - break; - } - return FALSE; -} - -static INT_PTR CALLBACK HomeDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - const unsigned long iPageId = 1; - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - if ( lParam ) { - ppro = ( CJabberProto* )lParam; - TranslateDialogDefault( hwndDlg ); - for (int i = 0; i < g_cbCountries; i++) { - if ( g_countries[i].id != 0xFFFF && g_countries[i].id != 0) { - TCHAR *country = mir_a2t(g_countries[i].szName); - SendMessage( GetDlgItem( hwndDlg, IDC_COUNTRY ), CB_ADDSTRING, 0, ( LPARAM )TranslateTS(country)); - mir_free(country); - } - } - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); - ppro->WindowSubscribe(hwndDlg); - } - break; - - case WM_JABBER_REFRESH_VCARD: - SetDialogField( ppro, hwndDlg, IDC_ADDRESS1, "Street" ); - SetDialogField( ppro, hwndDlg, IDC_ADDRESS2, "Street2" ); - SetDialogField( ppro, hwndDlg, IDC_CITY, "City" ); - SetDialogField( ppro, hwndDlg, IDC_STATE, "State" ); - SetDialogField( ppro, hwndDlg, IDC_ZIP, "ZIP" ); - SetDialogField( ppro, hwndDlg, IDC_COUNTRY, "Country", true ); - break; - - case WM_COMMAND: - if ((( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE) || - (( HWND )lParam==GetDlgItem( hwndDlg, IDC_COUNTRY ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) - { - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->idFrom == 0) { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - ppro->m_vCardUpdates &= ~(1UL<<iPageId); - ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!ppro->m_vCardUpdates) - ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); - break; - } } - break; - - case WM_DESTROY: - ppro->WindowUnsubscribe(hwndDlg); - break; - } - return FALSE; -} - -static INT_PTR CALLBACK WorkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - const unsigned long iPageId = 2; - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - if ( lParam ) { // proto info is available - ppro = ( CJabberProto* )lParam; - TranslateDialogDefault( hwndDlg ); - for (int i = 0; i < g_cbCountries; i++) { - if ( g_countries[i].id != 0xFFFF && g_countries[i].id != 0 ) { - TCHAR *country = mir_a2t( g_countries[i].szName ); - SendMessage( GetDlgItem( hwndDlg, IDC_COUNTRY ), CB_ADDSTRING, 0, ( LPARAM )TranslateTS(country)); - mir_free(country); - } - } - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); - ppro->WindowSubscribe(hwndDlg); - } - break; - - case WM_JABBER_REFRESH_VCARD: - SetDialogField( ppro, hwndDlg, IDC_COMPANY, "Company" ); - SetDialogField( ppro, hwndDlg, IDC_DEPARTMENT, "CompanyDepartment" ); - SetDialogField( ppro, hwndDlg, IDC_TITLE, "CompanyPosition" ); - SetDialogField( ppro, hwndDlg, IDC_ADDRESS1, "CompanyStreet" ); - SetDialogField( ppro, hwndDlg, IDC_ADDRESS2, "CompanyStreet2" ); - SetDialogField( ppro, hwndDlg, IDC_CITY, "CompanyCity" ); - SetDialogField( ppro, hwndDlg, IDC_STATE, "CompanyState" ); - SetDialogField( ppro, hwndDlg, IDC_ZIP, "CompanyZIP" ); - SetDialogField( ppro, hwndDlg, IDC_COUNTRY, "CompanyCountry", true ); - break; - - case WM_COMMAND: - if ((( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE) || - (( HWND )lParam==GetDlgItem( hwndDlg, IDC_COUNTRY ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) - { - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->idFrom == 0) { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - ppro->m_vCardUpdates &= ~(1UL<<iPageId); - ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!ppro->m_vCardUpdates) - ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); - break; - } } - break; - - case WM_DESTROY: - ppro->WindowUnsubscribe(hwndDlg); - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct PhotoDlgProcData -{ - CJabberProto* ppro; -// char szPhotoFileName[MAX_PATH]; -// BOOL bPhotoChanged; - HBITMAP hBitmap; -}; - -static INT_PTR CALLBACK PhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - const unsigned long iPageId = 3; - - TCHAR szAvatarFileName[ MAX_PATH ], szTempPath[MAX_PATH], szTempFileName[MAX_PATH]; - PhotoDlgProcData* dat = ( PhotoDlgProcData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - if (!lParam) break; // Launched from userinfo - TranslateDialogDefault( hwndDlg ); - SendDlgItemMessage( hwndDlg, IDC_LOAD, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_OPEN ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); - SendDlgItemMessage( hwndDlg, IDC_LOAD, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage( hwndDlg, IDC_DELETE, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); - SendDlgItemMessage( hwndDlg, IDC_DELETE, BUTTONSETASFLATBTN, TRUE, 0); - ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE ); - { - dat = new PhotoDlgProcData; - dat->ppro = ( CJabberProto* )lParam; - dat->hBitmap = NULL; - dat->ppro->m_bPhotoChanged = FALSE; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )dat ); - dat->ppro->WindowSubscribe(hwndDlg); - } - SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); - break; - - case WM_JABBER_REFRESH_VCARD: - if ( dat->hBitmap ) { - DeleteObject( dat->hBitmap ); - dat->hBitmap = NULL; - DeleteFile( dat->ppro->m_szPhotoFileName ); - dat->ppro->m_szPhotoFileName[0] = '\0'; - } - EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE ); - dat->ppro->GetAvatarFileName( NULL, szAvatarFileName, SIZEOF( szAvatarFileName )); - if ( _taccess( szAvatarFileName, 0 ) == 0 ) { - if ( GetTempPath( SIZEOF( szTempPath ), szTempPath ) <= 0 ) - _tcscpy( szTempPath, _T(".\\")); - if ( GetTempFileName( szTempPath, _T("jab"), 0, szTempFileName ) > 0 ) { - dat->ppro->Log( "Temp file = " TCHAR_STR_PARAM, szTempFileName ); - if ( CopyFile( szAvatarFileName, szTempFileName, FALSE ) == TRUE ) { - char* p = mir_t2a( szTempFileName ); - if (( dat->hBitmap=( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p )) != NULL ) { - JabberBitmapPremultiplyChannels( dat->hBitmap ); - _tcscpy( dat->ppro->m_szPhotoFileName, szTempFileName ); - EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE ); - } - else DeleteFile( szTempFileName ); - mir_free(p); - } - else DeleteFile( szTempFileName ); - } } - - dat->ppro->m_bPhotoChanged = FALSE; - InvalidateRect( hwndDlg, NULL, TRUE ); - UpdateWindow( hwndDlg ); - break; - - case WM_JABBER_CHANGED: - dat->ppro->SetServerVcard( dat->ppro->m_bPhotoChanged, dat->ppro->m_szPhotoFileName ); - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDC_LOAD: - { - TCHAR szFilter[512]; - TCHAR szFileName[MAX_PATH]; - - CallService( MS_UTILS_GETBITMAPFILTERSTRINGST, SIZEOF( szFilter ), ( LPARAM )szFilter ); - - OPENFILENAME ofn = {0}; - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwndDlg; - ofn.lpstrFilter = szFilter; - ofn.lpstrCustomFilter = NULL; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = MAX_PATH; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_DONTADDTORECENT; - szFileName[0] = '\0'; - if ( GetOpenFileName( &ofn )) { - struct _stat st; - HBITMAP hNewBitmap; - - dat->ppro->Log( "File selected is " TCHAR_STR_PARAM, szFileName ); - if ( _tstat( szFileName, &st )<0 || st.st_size>40*1024 ) { - MessageBox( hwndDlg, TranslateT( "Only JPG, GIF, and BMP image files smaller than 40 KB are supported." ), TranslateT( "Jabber vCard" ), MB_OK|MB_SETFOREGROUND ); - break; - } - if ( GetTempPath( SIZEOF( szTempPath ), szTempPath ) <= 0 ) - _tcscpy( szTempPath, _T(".\\")); - if ( GetTempFileName( szTempPath, _T("jab"), 0, szTempFileName ) > 0 ) { - dat->ppro->Log( "Temp file = " TCHAR_STR_PARAM, szTempFileName ); - if ( CopyFile( szFileName, szTempFileName, FALSE ) == TRUE ) { - char* pszTemp = mir_t2a( szTempFileName ); - if (( hNewBitmap=( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )pszTemp )) != NULL ) { - if ( dat->hBitmap ) { - DeleteObject( dat->hBitmap ); - DeleteFile( dat->ppro->m_szPhotoFileName ); - } - - dat->hBitmap = hNewBitmap; - _tcscpy( dat->ppro->m_szPhotoFileName, szTempFileName ); - dat->ppro->m_bPhotoChanged = TRUE; - EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE ); - InvalidateRect( hwndDlg, NULL, TRUE ); - UpdateWindow( hwndDlg ); - dat->ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - else DeleteFile( szTempFileName ); - - mir_free( pszTemp ); - } - else DeleteFile( szTempFileName ); - } - } - } - break; - case IDC_DELETE: - if ( dat->hBitmap ) { - DeleteObject( dat->hBitmap ); - dat->hBitmap = NULL; - DeleteFile( dat->ppro->m_szPhotoFileName ); - dat->ppro->m_szPhotoFileName[0] = '\0'; - dat->ppro->m_bPhotoChanged = TRUE; - EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE ); - InvalidateRect( hwndDlg, NULL, TRUE ); - UpdateWindow( hwndDlg ); - dat->ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - break; - } - break; - case WM_PAINT: - if ( dat->hBitmap ) { - BITMAP bm; - HDC hdcMem; - HWND hwndCanvas; - HDC hdcCanvas; - POINT ptSize, ptOrg, pt, ptFitSize; - RECT rect; - - hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS ); - hdcCanvas = GetDC( hwndCanvas ); - hdcMem = CreateCompatibleDC( hdcCanvas ); - SelectObject( hdcMem, dat->hBitmap ); - SetMapMode( hdcMem, GetMapMode( hdcCanvas )); - GetObject( dat->hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm ); - ptSize.x = bm.bmWidth; - ptSize.y = bm.bmHeight; - DPtoLP( hdcCanvas, &ptSize, 1 ); - ptOrg.x = ptOrg.y = 0; - DPtoLP( hdcMem, &ptOrg, 1 ); - GetClientRect( hwndCanvas, &rect ); - InvalidateRect( hwndCanvas, NULL, TRUE ); - UpdateWindow( hwndCanvas ); - if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) { - pt.x = ( rect.right - ptSize.x )/2; - pt.y = ( rect.bottom - ptSize.y )/2; - ptFitSize = ptSize; - } - else { - if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) { - ptFitSize.x = rect.right; - ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x; - pt.x = 0; - pt.y = ( rect.bottom - ptFitSize.y )/2; - } - else { - ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y; - ptFitSize.y = rect.bottom; - pt.x = ( rect.right - ptFitSize.x )/2; - pt.y = 0; - } - } - - RECT rc; - GetClientRect(hwndCanvas, &rc); - if (JabberIsThemeActive && JabberDrawThemeParentBackground && JabberIsThemeActive()) - JabberDrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc); - else - FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE)); - - if (JabberAlphaBlend && (bm.bmBitsPixel == 32)) { - BLENDFUNCTION bf = {0}; - bf.AlphaFormat = AC_SRC_ALPHA; - bf.BlendOp = AC_SRC_OVER; - bf.SourceConstantAlpha = 255; - JabberAlphaBlend( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf ); - } - else { - SetStretchBltMode( hdcCanvas, COLORONCOLOR ); - StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY ); - } - - DeleteDC( hdcMem ); - } - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->idFrom == 0) { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - dat->ppro->m_vCardUpdates &= ~(1UL<<iPageId); - dat->ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!dat->ppro->m_vCardUpdates) - dat->ppro->SetServerVcard( dat->ppro->m_bPhotoChanged, dat->ppro->m_szPhotoFileName ); - break; - } } - break; - - case WM_DESTROY: - DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_LOAD, BM_SETIMAGE, IMAGE_ICON, 0 )); - DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_DELETE, BM_SETIMAGE, IMAGE_ICON, 0 )); - dat->ppro->WindowUnsubscribe(hwndDlg); - if ( dat->hBitmap ) { - dat->ppro->Log( "Delete bitmap" ); - DeleteObject( dat->hBitmap ); - DeleteFile( dat->ppro->m_szPhotoFileName ); - } - delete dat; - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static INT_PTR CALLBACK NoteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - const unsigned long iPageId = 4; - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - if (!lParam) break; // Launched from userinfo - ppro = ( CJabberProto* )lParam; - TranslateDialogDefault( hwndDlg ); - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); - ppro->WindowSubscribe(hwndDlg); - break; - case WM_JABBER_REFRESH_VCARD: - { - SetDialogField( ppro, hwndDlg, IDC_DESC, "About" ); - break; - } - case WM_COMMAND: - if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) - { - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - break; - case WM_NOTIFY: - if (((LPNMHDR)lParam)->idFrom == 0) { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - ppro->m_vCardUpdates &= ~(1UL<<iPageId); - ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!ppro->m_vCardUpdates) - ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); - break; - } } - break; - case WM_DESTROY: - ppro->WindowUnsubscribe(hwndDlg); - break; - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct EditDlgParam -{ - int id; - CJabberProto* ppro; -}; - -static INT_PTR CALLBACK EditEmailDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - EditDlgParam* dat = ( EditDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - { - EditDlgParam* dat = ( EditDlgParam* )lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - TranslateDialogDefault( hwndDlg ); - - if ( lParam >= 0 ) { - DBVARIANT dbv; - char idstr[33]; - WORD nFlag; - - SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Email Address" )); - wsprintfA( idstr, "e-mail%d", dat->id ); - if ( !DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) { - SetDlgItemTextA( hwndDlg, IDC_EMAIL, dbv.pszVal ); - JFreeVariant( &dbv ); - wsprintfA( idstr, "e-mailFlag%d", lParam ); - nFlag = DBGetContactSettingWord( NULL, dat->ppro->m_szModuleName, idstr, 0 ); - if ( nFlag & JABBER_VCEMAIL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE ); - if ( nFlag & JABBER_VCEMAIL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE ); - if ( nFlag & JABBER_VCEMAIL_INTERNET ) CheckDlgButton( hwndDlg, IDC_INTERNET, TRUE ); - if ( nFlag & JABBER_VCEMAIL_X400 ) CheckDlgButton( hwndDlg, IDC_X400, TRUE ); - } } } - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDOK: - { - TCHAR text[128]; - char idstr[33]; - DBVARIANT dbv; - WORD nFlag; - - if ( dat->id < 0 ) { - for ( dat->id=0;;dat->id++ ) { - mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", dat->id ); - if ( DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) break; - JFreeVariant( &dbv ); - } } - GetDlgItemText( hwndDlg, IDC_EMAIL, text, SIZEOF( text )); - mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", dat->id ); - dat->ppro->JSetStringT( NULL, idstr, text ); - - nFlag = 0; - if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCEMAIL_HOME; - if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCEMAIL_WORK; - if ( IsDlgButtonChecked( hwndDlg, IDC_INTERNET )) nFlag |= JABBER_VCEMAIL_INTERNET; - if ( IsDlgButtonChecked( hwndDlg, IDC_X400 )) nFlag |= JABBER_VCEMAIL_X400; - mir_snprintf( idstr, SIZEOF(idstr), "e-mailFlag%d", dat->id ); - dat->ppro->JSetWord( NULL, idstr, nFlag ); - } - // fall through - case IDCANCEL: - EndDialog( hwndDlg, wParam ); - break; - } - } - return FALSE; -} - -static INT_PTR CALLBACK EditPhoneDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - EditDlgParam* dat = ( EditDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch ( msg ) { - case WM_INITDIALOG: - { - EditDlgParam* dat = ( EditDlgParam* )lParam; - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - TranslateDialogDefault( hwndDlg ); - if ( dat->id >= 0 ) { - DBVARIANT dbv; - char idstr[33]; - WORD nFlag; - - SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Phone Number" )); - wsprintfA( idstr, "Phone%d", dat->id ); - if ( !DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) { - SetDlgItemTextA( hwndDlg, IDC_PHONE, dbv.pszVal ); - JFreeVariant( &dbv ); - wsprintfA( idstr, "PhoneFlag%d", dat->id ); - nFlag = dat->ppro->JGetWord( NULL, idstr, 0 ); - if ( nFlag & JABBER_VCTEL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE ); - if ( nFlag & JABBER_VCTEL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE ); - if ( nFlag & JABBER_VCTEL_VOICE ) CheckDlgButton( hwndDlg, IDC_VOICE, TRUE ); - if ( nFlag & JABBER_VCTEL_FAX ) CheckDlgButton( hwndDlg, IDC_FAX, TRUE ); - if ( nFlag & JABBER_VCTEL_PAGER ) CheckDlgButton( hwndDlg, IDC_PAGER, TRUE ); - if ( nFlag & JABBER_VCTEL_MSG ) CheckDlgButton( hwndDlg, IDC_MSG, TRUE ); - if ( nFlag & JABBER_VCTEL_CELL ) CheckDlgButton( hwndDlg, IDC_CELL, TRUE ); - if ( nFlag & JABBER_VCTEL_VIDEO ) CheckDlgButton( hwndDlg, IDC_VIDEO, TRUE ); - if ( nFlag & JABBER_VCTEL_BBS ) CheckDlgButton( hwndDlg, IDC_BBS, TRUE ); - if ( nFlag & JABBER_VCTEL_MODEM ) CheckDlgButton( hwndDlg, IDC_MODEM, TRUE ); - if ( nFlag & JABBER_VCTEL_ISDN ) CheckDlgButton( hwndDlg, IDC_ISDN, TRUE ); - if ( nFlag & JABBER_VCTEL_PCS ) CheckDlgButton( hwndDlg, IDC_PCS, TRUE ); - } } } - break; - - case WM_COMMAND: - switch ( LOWORD( wParam )) { - case IDOK: - { - char text[128]; - char idstr[33]; - DBVARIANT dbv; - WORD nFlag; - - if ( dat->id < 0 ) { - for ( dat->id=0;;dat->id++ ) { - wsprintfA( idstr, "Phone%d", dat->id ); - if ( DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) break; - JFreeVariant( &dbv ); - } - } - GetDlgItemTextA( hwndDlg, IDC_PHONE, text, SIZEOF( text )); - wsprintfA( idstr, "Phone%d", dat->id ); - dat->ppro->JSetString( NULL, idstr, text ); - nFlag = 0; - if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCTEL_HOME; - if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCTEL_WORK; - if ( IsDlgButtonChecked( hwndDlg, IDC_VOICE )) nFlag |= JABBER_VCTEL_VOICE; - if ( IsDlgButtonChecked( hwndDlg, IDC_FAX )) nFlag |= JABBER_VCTEL_FAX; - if ( IsDlgButtonChecked( hwndDlg, IDC_PAGER )) nFlag |= JABBER_VCTEL_PAGER; - if ( IsDlgButtonChecked( hwndDlg, IDC_MSG )) nFlag |= JABBER_VCTEL_MSG; - if ( IsDlgButtonChecked( hwndDlg, IDC_CELL )) nFlag |= JABBER_VCTEL_CELL; - if ( IsDlgButtonChecked( hwndDlg, IDC_VIDEO )) nFlag |= JABBER_VCTEL_VIDEO; - if ( IsDlgButtonChecked( hwndDlg, IDC_BBS )) nFlag |= JABBER_VCTEL_BBS; - if ( IsDlgButtonChecked( hwndDlg, IDC_MODEM )) nFlag |= JABBER_VCTEL_MODEM; - if ( IsDlgButtonChecked( hwndDlg, IDC_ISDN )) nFlag |= JABBER_VCTEL_ISDN; - if ( IsDlgButtonChecked( hwndDlg, IDC_PCS )) nFlag |= JABBER_VCTEL_PCS; - wsprintfA( idstr, "PhoneFlag%d", dat->id ); - dat->ppro->JSetWord( NULL, idstr, nFlag ); - } - // fall through - case IDCANCEL: - EndDialog( hwndDlg, wParam ); - break; - } - } - return FALSE; -} - -#define M_REMAKELISTS ( WM_USER+1 ) -static INT_PTR CALLBACK ContactDlgProc( HWND hwndDlg, UINT msg, WPARAM, LPARAM lParam ) -{ - const unsigned long iPageId = 5; - CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); - - switch( msg ) { - case WM_INITDIALOG: - if (!lParam) break; // Launched from userinfo - ppro = ( CJabberProto* )lParam; - { - LVCOLUMN lvc; - RECT rc; - - SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); - - TranslateDialogDefault( hwndDlg ); - GetClientRect( GetDlgItem( hwndDlg,IDC_EMAILS ), &rc ); - rc.right -= GetSystemMetrics( SM_CXVSCROLL ); - lvc.mask = LVCF_WIDTH; - lvc.cx = 30; - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 0, &lvc ); - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 0, &lvc ); - lvc.cx = rc.right - 30 - 40; - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 1, &lvc ); - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 1, &lvc ); - lvc.cx = 20; - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 2, &lvc ); - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 3, &lvc ); - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 2, &lvc ); - ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 3, &lvc ); - SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); - - ppro->WindowSubscribe(hwndDlg); - } - break; - case M_REMAKELISTS: - { - LVITEM lvi; - int i; - char idstr[33]; - TCHAR number[20]; - DBVARIANT dbv; - - //e-mails - ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_EMAILS )); - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.iSubItem = 0; - lvi.iItem = 0; - for ( i=0;;i++ ) { - wsprintfA( idstr, "e-mail%d", i ); - if ( DBGetContactSettingTString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; - wsprintf( number, _T("%d"), i+1 ); - lvi.pszText = number; - lvi.lParam = ( LPARAM )i; - ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi ); - ListView_SetItemText( GetDlgItem( hwndDlg, IDC_EMAILS ), lvi.iItem, 1, dbv.ptszVal ); - JFreeVariant( &dbv ); - lvi.iItem++; - } - lvi.mask = LVIF_PARAM; - lvi.lParam = ( LPARAM )( -1 ); - ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi ); - //phones - ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_PHONES )); - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.iSubItem = 0; - lvi.iItem = 0; - for ( i=0;;i++ ) { - wsprintfA( idstr, "Phone%d", i ); - if ( DBGetContactSettingTString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; - wsprintf( number, _T("%d"), i+1 ); - lvi.pszText = number; - lvi.lParam = ( LPARAM )i; - ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi ); - ListView_SetItemText( GetDlgItem( hwndDlg, IDC_PHONES ), lvi.iItem, 1, dbv.ptszVal ); - JFreeVariant( &dbv ); - lvi.iItem++; - } - lvi.mask = LVIF_PARAM; - lvi.lParam = ( LPARAM )( -1 ); - ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi ); - } - break; - case WM_NOTIFY: - switch (( ( LPNMHDR )lParam )->idFrom ) { - case 0: { - switch (((LPNMHDR)lParam)->code) { - case PSN_PARAMCHANGED: - SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); - break; - case PSN_APPLY: - ppro->m_vCardUpdates &= ~(1UL<<iPageId); - ppro->SaveVcardToDB( hwndDlg, iPageId ); - if (!ppro->m_vCardUpdates) - ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); - break; - } } - break; - - case IDC_EMAILS: - case IDC_PHONES: - switch (( ( LPNMHDR )lParam )->code ) { - case NM_CUSTOMDRAW: - { - NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam; - - switch ( nm->nmcd.dwDrawStage ) { - case CDDS_PREPAINT: - case CDDS_ITEMPREPAINT: - SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW ); - return TRUE; - case CDDS_SUBITEM|CDDS_ITEMPREPAINT: - { - RECT rc; - HICON hIcon; - - ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc ); - if ( nm->nmcd.lItemlParam==( LPARAM )( -1 ) && nm->iSubItem==3 ) - hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); - else if ( nm->iSubItem==2 && nm->nmcd.lItemlParam!=( LPARAM )( -1 )) - hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_EDIT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); - else if ( nm->iSubItem==3 && nm->nmcd.lItemlParam!=( LPARAM )( -1 )) - hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); - else break; - DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, NULL, DI_NORMAL ); - DestroyIcon( hIcon ); - SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT ); - } - return TRUE; - } - } - break; - case NM_CLICK: - { - NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam; - LVITEM lvi; - const char* szIdTemplate = nm->hdr.idFrom==IDC_PHONES?"Phone%d":"e-mail%d"; - const char* szFlagTemplate = nm->hdr.idFrom==IDC_PHONES?"PhoneFlag%d":"e-mailFlag%d"; - LVHITTESTINFO hti; - - if ( nm->iSubItem < 2 ) break; - hti.pt.x = ( short ) LOWORD( GetMessagePos()); - hti.pt.y = ( short ) HIWORD( GetMessagePos()); - ScreenToClient( nm->hdr.hwndFrom, &hti.pt ); - if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 ) break; - lvi.mask = LVIF_PARAM; - lvi.iItem = hti.iItem; - lvi.iSubItem = 0; - ListView_GetItem( nm->hdr.hwndFrom, &lvi ); - if ( lvi.lParam == ( LPARAM )( -1 )) { - if ( hti.iSubItem == 3 ) { - //add - EditDlgParam param = { -1, ppro }; - int res; - if ( nm->hdr.idFrom == IDC_PHONES ) - res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDPHONE ), hwndDlg, EditPhoneDlgProc, ( LPARAM )¶m ); - else - res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDEMAIL ), hwndDlg, EditEmailDlgProc, ( LPARAM )¶m ); - if ( res != IDOK ) - break; - SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - } - else { - if ( hti.iSubItem == 3 ) { - //delete - int i; - char idstr[33]; - DBVARIANT dbv; - - for ( i=lvi.lParam;;i++ ) { - WORD nFlag; - - wsprintfA( idstr, szIdTemplate, i+1 ); - if ( DBGetContactSettingString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; - wsprintfA( idstr,szIdTemplate,i ); - ppro->JSetString( NULL, idstr, dbv.pszVal ); - wsprintfA( idstr, szFlagTemplate, i+1 ); - JFreeVariant( &dbv ); - nFlag = ppro->JGetWord( NULL, idstr, 0 ); - wsprintfA( idstr, szFlagTemplate, i ); - ppro->JSetWord( NULL, idstr, nFlag ); - } - wsprintfA( idstr, szIdTemplate, i ); - ppro->JDeleteSetting( NULL, idstr ); - wsprintfA( idstr, szFlagTemplate, i ); - ppro->JDeleteSetting( NULL, idstr ); - SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - else if ( hti.iSubItem == 2 ) { - EditDlgParam param = { lvi.lParam, ppro }; - int res; - if ( nm->hdr.idFrom == IDC_PHONES ) - res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDPHONE ), hwndDlg, EditPhoneDlgProc, ( LPARAM )¶m ); - else - res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDEMAIL ), hwndDlg, EditEmailDlgProc, ( LPARAM )¶m ); - if ( res != IDOK ) - break; - SendMessage( hwndDlg,M_REMAKELISTS,0,0 ); - ppro->m_vCardUpdates |= (1UL<<iPageId); - SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); - } - } - } - break; - } - break; - } - break; - case WM_SETCURSOR: - if ( LOWORD( lParam ) != HTCLIENT ) break; - if ( GetForegroundWindow() == GetParent( hwndDlg )) { - POINT pt; - GetCursorPos( &pt ); - ScreenToClient( hwndDlg,&pt ); - SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click - } - break; - case WM_DESTROY: - ppro->WindowUnsubscribe(hwndDlg); - break; - } - return FALSE; -} - -void CJabberProto::SaveVcardToDB( HWND hwndPage, int iPage ) -{ - TCHAR text[2048]; - - // Page 0: Personal - switch (iPage) { - case 0: - GetDlgItemText( hwndPage, IDC_FULLNAME, text, SIZEOF( text )); - JSetStringT( NULL, "FullName", text ); - GetDlgItemText( hwndPage, IDC_NICKNAME, text, SIZEOF( text )); - JSetStringT( NULL, "Nick", text ); - GetDlgItemText( hwndPage, IDC_FIRSTNAME, text, SIZEOF( text )); - JSetStringT( NULL, "FirstName", text ); - GetDlgItemText( hwndPage, IDC_MIDDLE, text, SIZEOF( text )); - JSetStringT( NULL, "MiddleName", text ); - GetDlgItemText( hwndPage, IDC_LASTNAME, text, SIZEOF( text )); - JSetStringT( NULL, "LastName", text ); - GetDlgItemText( hwndPage, IDC_BIRTH, text, SIZEOF( text )); - JSetStringT( NULL, "BirthDate", text ); - switch( SendMessage( GetDlgItem( hwndPage, IDC_GENDER ), CB_GETCURSEL, 0, 0 )) { - case 0: JSetString( NULL, "GenderString", "Male" ); break; - case 1: JSetString( NULL, "GenderString", "Female" ); break; - default: JSetString( NULL, "GenderString", "" ); break; - } - GetDlgItemText( hwndPage, IDC_OCCUPATION, text, SIZEOF( text )); - JSetStringT( NULL, "Role", text ); - GetDlgItemText( hwndPage, IDC_HOMEPAGE, text, SIZEOF( text )); - JSetStringT( NULL, "Homepage", text ); - break; - - // Page 1: Home - case 1: - GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text )); - JSetStringT( NULL, "Street", text ); - GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text )); - JSetStringT( NULL, "Street2", text ); - GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text )); - JSetStringT( NULL, "City", text ); - GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text )); - JSetStringT( NULL, "State", text ); - GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text )); - JSetStringT( NULL, "ZIP", text ); - { - int i = SendMessage( GetDlgItem( hwndPage, IDC_COUNTRY ), CB_GETCURSEL, 0, 0 ); - TCHAR *country = mir_a2t((i) ? g_countries[i+2].szName : g_countries[1].szName); - JSetStringT( NULL, "Country", country ); - mir_free(country); - } - break; - - // Page 2: Work - case 2: - GetDlgItemText( hwndPage, IDC_COMPANY, text, SIZEOF( text )); - JSetStringT( NULL, "Company", text ); - GetDlgItemText( hwndPage, IDC_DEPARTMENT, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyDepartment", text ); - GetDlgItemText( hwndPage, IDC_TITLE, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyPosition", text ); - GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyStreet", text ); - GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyStreet2", text ); - GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyCity", text ); - GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyState", text ); - GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text )); - JSetStringT( NULL, "CompanyZIP", text ); - { - int i = SendMessage( GetDlgItem( hwndPage, IDC_COUNTRY ), CB_GETCURSEL, 0, 0 ); - TCHAR *country = mir_a2t((i) ? g_countries[i+2].szName : g_countries[1].szName); - JSetStringT( NULL, "CompanyCountry", country ); - mir_free(country); - } - break; - - // Page 3: Photo - // not needed to be saved into db - - // Page 4: Note - case 4: - GetDlgItemText( hwndPage, IDC_DESC, text, SIZEOF( text )); - JSetStringT( NULL, "About", text ); - break; - - // Page 5: Contacts - // is always synced with db -} } - -void CJabberProto::AppendVcardFromDB( HXML n, char* tag, char* key ) -{ - if ( n == NULL || tag == NULL || key == NULL ) - return; - - DBVARIANT dbv; - if ( DBGetContactSettingTString( NULL, m_szModuleName, key, &dbv )) - n << XCHILD( _A2T(tag)); - else { - n << XCHILD( _A2T(tag), dbv.ptszVal ); - JFreeVariant( &dbv ); -} } - -void CJabberProto::SetServerVcard( BOOL bPhotoChanged, TCHAR* szPhotoFileName ) -{ - if (!m_bJabberOnline) return; - - DBVARIANT dbv; - int iqId; - TCHAR *szFileName; - int i; - char idstr[33]; - WORD nFlag; - - iqId = SerialNext(); - IqAdd( iqId, IQ_PROC_SETVCARD, &CJabberProto::OnIqResultSetVcard ); - - XmlNodeIq iq( _T("set"), iqId ); - HXML v = iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); - - AppendVcardFromDB( v, "FN", "FullName" ); - - HXML n = v << XCHILD( _T("N")); - AppendVcardFromDB( n, "GIVEN", "FirstName" ); - AppendVcardFromDB( n, "MIDDLE", "MiddleName" ); - AppendVcardFromDB( n, "FAMILY", "LastName" ); - - AppendVcardFromDB( v, "NICKNAME", "Nick" ); - AppendVcardFromDB( v, "BDAY", "BirthDate" ); - AppendVcardFromDB( v, "GENDER", "GenderString" ); - - for ( i=0;;i++ ) { - wsprintfA( idstr, "e-mail%d", i ); - if ( DBGetContactSettingTString( NULL, m_szModuleName, idstr, &dbv )) - break; - - HXML e = v << XCHILD( _T("EMAIL"), dbv.ptszVal ); - JFreeVariant( &dbv ); - AppendVcardFromDB( e, "USERID", idstr ); - - wsprintfA( idstr, "e-mailFlag%d", i ); - nFlag = DBGetContactSettingWord( NULL, m_szModuleName, idstr, 0 ); - if ( nFlag & JABBER_VCEMAIL_HOME ) e << XCHILD( _T("HOME")); - if ( nFlag & JABBER_VCEMAIL_WORK ) e << XCHILD( _T("WORK")); - if ( nFlag & JABBER_VCEMAIL_INTERNET ) e << XCHILD( _T("INTERNET")); - if ( nFlag & JABBER_VCEMAIL_X400 ) e << XCHILD( _T("X400")); - } - - n = v << XCHILD( _T("ADR")); - n << XCHILD( _T("HOME")); - AppendVcardFromDB( n, "STREET", "Street" ); - AppendVcardFromDB( n, "EXTADR", "Street2" ); - AppendVcardFromDB( n, "EXTADD", "Street2" ); // for compatibility with client using old vcard format - AppendVcardFromDB( n, "LOCALITY", "City" ); - AppendVcardFromDB( n, "REGION", "State" ); - AppendVcardFromDB( n, "PCODE", "ZIP" ); - AppendVcardFromDB( n, "CTRY", "Country" ); - AppendVcardFromDB( n, "COUNTRY", "Country" ); // for compatibility with client using old vcard format - - n = v << XCHILD( _T("ADR")); - n << XCHILD( _T("WORK")); - AppendVcardFromDB( n, "STREET", "CompanyStreet" ); - AppendVcardFromDB( n, "EXTADR", "CompanyStreet2" ); - AppendVcardFromDB( n, "EXTADD", "CompanyStreet2" ); // for compatibility with client using old vcard format - AppendVcardFromDB( n, "LOCALITY", "CompanyCity" ); - AppendVcardFromDB( n, "REGION", "CompanyState" ); - AppendVcardFromDB( n, "PCODE", "CompanyZIP" ); - AppendVcardFromDB( n, "CTRY", "CompanyCountry" ); - AppendVcardFromDB( n, "COUNTRY", "CompanyCountry" ); // for compatibility with client using old vcard format - - n = v << XCHILD( _T("ORG")); - AppendVcardFromDB( n, "ORGNAME", "Company" ); - AppendVcardFromDB( n, "ORGUNIT", "CompanyDepartment" ); - - AppendVcardFromDB( v, "TITLE", "CompanyPosition" ); - AppendVcardFromDB( v, "ROLE", "Role" ); - AppendVcardFromDB( v, "URL", "Homepage" ); - AppendVcardFromDB( v, "DESC", "About" ); - - for ( i=0;;i++ ) { - wsprintfA( idstr, "Phone%d", i ); - if ( DBGetContactSettingTString( NULL, m_szModuleName, idstr, &dbv )) break; - JFreeVariant( &dbv ); - - n = v << XCHILD( _T("TEL")); - AppendVcardFromDB( n, "NUMBER", idstr ); - - wsprintfA( idstr, "PhoneFlag%d", i ); - nFlag = JGetWord( NULL, idstr, 0 ); - if ( nFlag & JABBER_VCTEL_HOME ) n << XCHILD( _T("HOME")); - if ( nFlag & JABBER_VCTEL_WORK ) n << XCHILD( _T("WORK")); - if ( nFlag & JABBER_VCTEL_VOICE ) n << XCHILD( _T("VOICE")); - if ( nFlag & JABBER_VCTEL_FAX ) n << XCHILD( _T("FAX")); - if ( nFlag & JABBER_VCTEL_PAGER ) n << XCHILD( _T("PAGER")); - if ( nFlag & JABBER_VCTEL_MSG ) n << XCHILD( _T("MSG")); - if ( nFlag & JABBER_VCTEL_CELL ) n << XCHILD( _T("CELL")); - if ( nFlag & JABBER_VCTEL_VIDEO ) n << XCHILD( _T("VIDEO")); - if ( nFlag & JABBER_VCTEL_BBS ) n << XCHILD( _T("BBS")); - if ( nFlag & JABBER_VCTEL_MODEM ) n << XCHILD( _T("MODEM")); - if ( nFlag & JABBER_VCTEL_ISDN ) n << XCHILD( _T("ISDN")); - if ( nFlag & JABBER_VCTEL_PCS ) n << XCHILD( _T("PCS")); - } - - TCHAR szAvatarName[ MAX_PATH ]; - GetAvatarFileName( NULL, szAvatarName, SIZEOF( szAvatarName )); - if ( bPhotoChanged ) - szFileName = szPhotoFileName; - else - szFileName = szAvatarName; - - // Set photo element, also update the global jabberVcardPhotoFileName to reflect the update - Log( "Before update, file name = " TCHAR_STR_PARAM, szFileName ); - if ( szFileName == NULL || szFileName[0] == 0 ) { - v << XCHILD( _T("PHOTO")); - DeleteFile( szAvatarName ); - JDeleteSetting( NULL, "AvatarSaved" ); - JDeleteSetting( NULL, "AvatarHash" ); - } - else { - HANDLE hFile; - struct _stat st; - char* buffer, *str; - DWORD nRead; - - Log( "Saving picture from " TCHAR_STR_PARAM, szFileName ); - if ( _tstat( szFileName, &st ) >= 0 ) { - // Note the FILE_SHARE_READ attribute so that the CopyFile can succeed - if (( hFile=CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) { - if (( buffer=( char* )mir_alloc( st.st_size )) != NULL ) { - if ( ReadFile( hFile, buffer, st.st_size, &nRead, NULL )) { - if (( str=JabberBase64Encode( buffer, nRead )) != NULL ) { - n = v << XCHILD( _T("PHOTO")); - TCHAR* szFileType; - switch( JabberGetPictureType( buffer )) { - case PA_FORMAT_PNG: szFileType = _T("image/png"); break; - case PA_FORMAT_GIF: szFileType = _T("image/gif"); break; - case PA_FORMAT_BMP: szFileType = _T("image/bmp"); break; - default: szFileType = _T("image/jpeg"); break; - } - n << XCHILD( _T("TYPE"), szFileType ); - - n << XCHILD( _T("BINVAL"), _A2T(str)); - mir_free( str ); - - // NEED TO UPDATE OUR AVATAR HASH: - - mir_sha1_byte_t digest[MIR_SHA1_HASH_SIZE]; - mir_sha1_ctx sha1ctx; - mir_sha1_init( &sha1ctx ); - mir_sha1_append( &sha1ctx, (mir_sha1_byte_t*)buffer, nRead ); - mir_sha1_finish( &sha1ctx, digest ); - - char buf[MIR_SHA1_HASH_SIZE*2+1]; - for ( int j=0; j<MIR_SHA1_HASH_SIZE; j++ ) - sprintf( buf+( j<<1 ), "%02x", digest[j] ); - - m_options.AvatarType = JabberGetPictureType( buffer ); - - if ( bPhotoChanged ) { - DeleteFile( szAvatarName ); - - GetAvatarFileName( NULL, szAvatarName, SIZEOF( szAvatarName )); - - CopyFile( szFileName, szAvatarName, FALSE ); - } - - JSetString( NULL, "AvatarHash", buf ); - JSetString( NULL, "AvatarSaved", buf ); - } } - mir_free( buffer ); - } - CloseHandle( hFile ); - } } } - - m_ThreadInfo->send( iq ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CJabberProto::OnUserInfoInit_VCard( WPARAM wParam, LPARAM ) -{ - m_vCardUpdates = 0; - m_bPhotoChanged = FALSE; - m_szPhotoFileName[0] = 0; - - OPTIONSDIALOGPAGE odp = {0}; - odp.cbSize = sizeof(odp); - odp.hInstance = hInst; - odp.dwInitParam = (LPARAM)this; - odp.flags = ODPF_TCHAR|ODPF_USERINFOTAB|ODPF_DONTTRANSLATE; - odp.ptszTitle = m_tszUserName; - - odp.pfnDlgProc = PersonalDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_PERSONAL); - odp.ptszTab = LPGENT("General"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = ContactDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_CONTACT); - odp.ptszTab = LPGENT("Contacts"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = HomeDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_HOME); - odp.ptszTab = LPGENT("Home"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = WorkDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_WORK); - odp.ptszTab = LPGENT("Work"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = PhotoDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_PHOTO); - odp.ptszTab = LPGENT("Photo"); - UserInfo_AddPage(wParam, &odp); - - odp.pfnDlgProc = NoteDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_NOTE); - odp.ptszTab = LPGENT("Note"); - UserInfo_AddPage(wParam, &odp); - - SendGetVcard( m_szJabberJID ); -} diff --git a/protocols/JabberG/jabber_ws.cpp b/protocols/JabberG/jabber_ws.cpp deleted file mode 100644 index 494dcf3454..0000000000 --- a/protocols/JabberG/jabber_ws.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -BOOL CJabberProto::WsInit( void ) -{ - m_lastTicks = ::GetTickCount(); - - TCHAR name[128]; - mir_sntprintf( name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); - - NETLIBUSER nlu = {0}; - nlu.cbSize = sizeof( nlu ); - nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR; // | NUF_HTTPGATEWAY; - nlu.ptszDescriptiveName = name; - nlu.szSettingsModule = m_szModuleName; - //nlu.szHttpGatewayHello = "http://http.proxy.icq.com/hello"; - //nlu.szHttpGatewayUserAgent = "Mozilla/4.08 [en] ( WinNT; U ;Nav )"; - //nlu.pfnHttpGatewayInit = JabberHttpGatewayInit; - //nlu.pfnHttpGatewayBegin = JabberHttpGatewayBegin; - //nlu.pfnHttpGatewayWrapSend = JabberHttpGatewayWrapSend; - //nlu.pfnHttpGatewayUnwrapRecv = JabberHttpGatewayUnwrapRecv; - m_hNetlibUser = ( HANDLE ) CallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu ); - - return m_hNetlibUser != NULL; -} - -void CJabberProto::WsUninit( void ) -{ - Netlib_CloseHandle( m_hNetlibUser ); - m_hNetlibUser = NULL; -} - -JABBER_SOCKET CJabberProto::WsConnect( char* host, WORD port ) -{ - NETLIBOPENCONNECTION nloc = { 0 }; - nloc.cbSize = sizeof( nloc ); - nloc.szHost = host; - nloc.wPort = port; - nloc.timeout = 6; - return ( HANDLE )CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); -} - -int CJabberProto::WsSend( JABBER_SOCKET hConn, char* data, int datalen, int flags ) -{ - m_lastTicks = ::GetTickCount(); - int len; - - if (( len = Netlib_Send( hConn, data, datalen, flags )) == SOCKET_ERROR || len != datalen ) { - Log( "Netlib_Send() failed, error=%d", WSAGetLastError()); - return SOCKET_ERROR; - } - return len; -} - -int CJabberProto::WsRecv( JABBER_SOCKET hConn, char* data, long datalen, int flags ) -{ - int ret; - - ret = Netlib_Recv( hConn, data, datalen, flags ); - if ( ret == SOCKET_ERROR ) { - Log( "Netlib_Recv() failed, error=%d", WSAGetLastError()); - return 0; - } - if ( ret == 0 ) { - Log( "Connection closed gracefully" ); - return 0; - } - return ret; -} diff --git a/protocols/JabberG/jabber_xml.cpp b/protocols/JabberG/jabber_xml.cpp deleted file mode 100644 index 287a335243..0000000000 --- a/protocols/JabberG/jabber_xml.cpp +++ /dev/null @@ -1,524 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -#define TAG_MAX_LEN 128 -#define ATTR_MAX_LEN 8192 - -#define T2UTF(A) A - -///////////////////////////////////////////////////////////////////////////////////////// -// XmlNodeIq class members - -XmlNodeIq::XmlNodeIq( const TCHAR* type, int id, LPCTSTR to ) : - XmlNode( _T( "iq" )) -{ - if ( type != NULL ) *this << XATTR( _T("type"), type ); - if ( to != NULL ) *this << XATTR( _T("to"), to ); - if ( id != -1 ) *this << XATTRID( id ); -} - -XmlNodeIq::XmlNodeIq( const TCHAR* type, LPCTSTR idStr, LPCTSTR to ) : - XmlNode( _T( "iq" )) -{ - if ( type != NULL ) *this << XATTR( _T("type"), type ); - if ( to != NULL ) *this << XATTR( _T("to"), to ); - if ( idStr != NULL ) *this << XATTR( _T("id"), idStr ); -} - -XmlNodeIq::XmlNodeIq( const TCHAR* type, HXML node, LPCTSTR to ) : - XmlNode( _T( "iq" )) -{ - if ( type != NULL ) *this << XATTR( _T("type"), type ); - if ( to != NULL ) *this << XATTR( _T("to"), to ); - if ( node != NULL ) { - const TCHAR *iqId = xmlGetAttrValue( *this, _T( "id" )); - if ( iqId != NULL ) *this << XATTR( _T("id"), iqId ); - } -} - -XmlNodeIq::XmlNodeIq( CJabberIqInfo* pInfo ) : - XmlNode( _T( "iq" )) -{ - if ( pInfo ) { - if ( pInfo->GetCharIqType() != NULL ) *this << XATTR( _T("type"), _A2T(pInfo->GetCharIqType())); - if ( pInfo->GetReceiver() != NULL ) *this << XATTR( _T("to"), pInfo->GetReceiver()); - if ( pInfo->GetIqId() != -1 ) *this << XATTRID( pInfo->GetIqId()); - } -} - -XmlNodeIq::XmlNodeIq( const TCHAR* type, CJabberIqInfo* pInfo ) : - XmlNode( _T( "iq" )) -{ - if ( type != NULL ) *this << XATTR( _T("type"), type ); - if ( pInfo ) { - if ( pInfo->GetFrom() != NULL ) *this << XATTR( _T("to"), pInfo->GetFrom()); - if ( pInfo->GetIdStr() != NULL ) *this << XATTR( _T("id"), pInfo->GetIdStr()); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// XmlNode class members - -XmlNode::XmlNode( LPCTSTR pszName ) -{ - m_hXml = xi.createNode( T2UTF(pszName), NULL, 0 ); -} - -XmlNode::XmlNode( LPCTSTR pszName, LPCTSTR ptszText ) -{ - m_hXml = xi.createNode( T2UTF(pszName), ptszText, 0 ); -} - -XmlNode::XmlNode( const XmlNode& n ) -{ - m_hXml = xi.copyNode( n ); -} - -XmlNode& XmlNode::operator =( const XmlNode& n ) -{ - if ( m_hXml ) - xi.destroyNode( m_hXml ); - m_hXml = xi.copyNode( n ); - return *this; -} - -XmlNode::~XmlNode() -{ - if ( m_hXml ) { - xi.destroyNode( m_hXml ); - m_hXml = NULL; -} } - -///////////////////////////////////////////////////////////////////////////////////////// - -HXML __fastcall operator<<( HXML node, const XCHILDNS& child ) -{ - HXML res = xmlAddChild( node, child.name ); - xmlAddAttr( res, _T("xmlns"), child.ns ); - return res; -} - -HXML __fastcall operator<<( HXML node, const XQUERY& child ) -{ - HXML n = xmlAddChild( node, _T("query")); - if ( n ) - xmlAddAttr( n, _T("xmlns"), child.ns ); - return n; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void __fastcall xmlAddAttr( HXML hXml, LPCTSTR name, LPCTSTR value ) -{ - if ( value ) - xi.addAttr( hXml, name, T2UTF(value)); -} - -void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, int value ) -{ - xi.addAttrInt( hXml, T2UTF(pszName), value ); -} - -void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, unsigned __int64 value ) -{ - TCHAR buf[60]; - _ui64tot( value, buf, 10 ); - - xi.addAttr( hXml, T2UTF(pszName), T2UTF(buf)); -} - -void __fastcall xmlAddAttrID( HXML hXml, int id ) -{ - TCHAR text[ 100 ]; - mir_sntprintf( text, SIZEOF(text), _T("mir_%d"), id ); - xmlAddAttr( hXml, _T("id"), text ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -LPCTSTR __fastcall xmlGetAttr( HXML hXml, int n ) -{ - return xi.getAttr( hXml, n ); -} - -int __fastcall xmlGetAttrCount( HXML hXml ) -{ - return xi.getAttrCount( hXml ); -} - -LPCTSTR __fastcall xmlGetAttrName( HXML hXml, int n ) -{ - return xi.getAttrName( hXml, n ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void __fastcall xmlAddChild( HXML hXml, HXML n ) -{ - xi.addChild2( n, hXml ); -} - -HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name ) -{ - return xi.addChild( hXml, T2UTF(name), NULL ); -} - -HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name, LPCTSTR value ) -{ - return xi.addChild( hXml, T2UTF(name), T2UTF(value)); -} - -HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name, int value ) -{ - TCHAR buf[40]; - _itot( value, buf, 10 ); - return xi.addChild( hXml, T2UTF(name), buf ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -LPCTSTR __fastcall xmlGetAttrValue( HXML hXml, LPCTSTR key ) -{ - return xi.getAttrValue( hXml, key ); -} - -HXML __fastcall xmlGetChild( HXML hXml, int n ) -{ - return xi.getChild( hXml, n ); -} - -HXML __fastcall xmlGetChild( HXML hXml, LPCTSTR key ) -{ - return xi.getNthChild( hXml, key, 0 ); -} - -HXML __fastcall xmlGetChild( HXML hXml, LPCSTR key ) -{ - LPTSTR wszKey = mir_a2t( key ); - HXML result = xi.getNthChild( hXml, wszKey, 0 ); - mir_free( wszKey ); - return result; -} - -HXML __fastcall xmlGetChildByTag( HXML hXml, LPCTSTR key, LPCTSTR attrName, LPCTSTR attrValue ) -{ - return xi.getChildByAttrValue( hXml, key, attrName, attrValue ); -} - -HXML __fastcall xmlGetChildByTag( HXML hXml, LPCSTR key, LPCSTR attrName, LPCTSTR attrValue ) -{ - LPTSTR wszKey = mir_a2t( key ), wszName = mir_a2t( attrName ); - HXML result = xi.getChildByAttrValue( hXml, wszKey, wszName, attrValue ); - mir_free( wszKey ), mir_free( wszName ); - return result; -} - -int __fastcall xmlGetChildCount( HXML hXml ) -{ - return xi.getChildCount( hXml ); -} - -HXML __fastcall xmlGetNthChild( HXML hXml, LPCTSTR tag, int nth ) -{ - int i, num; - - if ( !hXml || tag == NULL || _tcslen( tag ) <= 0 || nth < 1 ) - return NULL; - - num = 1; - for ( i=0; ; i++ ) { - HXML n = xi.getChild( hXml, i ); - if ( !n ) - break; - if ( !lstrcmp( tag, xmlGetName( n ))) { - if ( num == nth ) - return n; - - num++; - } } - - return NULL; -} - -LPCTSTR __fastcall xmlGetName( HXML xml ) -{ - return xi.getName( xml ); -} - -LPCTSTR __fastcall xmlGetText( HXML xml ) -{ - return xi.getText( xml ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void XPath::ProcessPath(LookupInfo &info, bool bCreate) -{ - if (!info.nodeName) return; - - TCHAR *nodeName = (TCHAR *)alloca(sizeof(TCHAR) * (info.nodeName.length+1)); - lstrcpyn(nodeName, info.nodeName.p, info.nodeName.length+1); - - if (info.attrName && info.attrValue) - { - TCHAR *attrName = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrName.length+1)); - lstrcpyn(attrName, info.attrName.p, info.attrName.length+1); - TCHAR *attrValue = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrValue.length+1)); - lstrcpyn(attrValue, info.attrValue.p, info.attrValue.length+1); - HXML hXml = xmlGetChildByTag(m_hXml, nodeName, attrName, attrValue); - - m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName) << XATTR(attrName, attrValue)); - } else - if (info.nodeIndex) - { - int idx = _ttoi(info.nodeIndex.p); - m_hXml = lstrcmp(nodeName, _T("*")) ? xmlGetNthChild(m_hXml, nodeName, idx) : xmlGetChild(m_hXml, idx-1); - - // no support for such creation mode - } else - { - HXML hXml = xmlGetChild(m_hXml, nodeName); - m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName)); - } - - info.Reset(); -} - -XPath::PathType XPath::LookupImpl(bool bCreate) -{ - LookupState state = S_START; - LookupInfo info = {0}; - - for (LPCTSTR p = m_szPath; state < S_FINAL; ++p) - { - switch (state) - { - case S_START: - { - ProcessPath(info, bCreate); - if (!m_hXml) - { - state = S_FINAL_ERROR; - break; - } - - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T('@'): - info.attrName.Begin(p+1); - state = S_ATTR_STEP; - break; - case _T('/'): - break; - default: - info.nodeName.Begin(p); - state = S_NODE_NAME; - break; - }; - break; - } - case S_ATTR_STEP: - { - switch (*p) - { - case 0: - info.attrName.End(p); - state = S_FINAL_ATTR; - break; - default: - break; - }; - break; - } - case S_NODE_NAME: - { - switch (*p) - { - case 0: - info.nodeName.End(p); - state = S_FINAL_NODESET; - break; - case _T('['): - info.nodeName.End(p); - state = S_NODE_OPENBRACKET; - break; - case _T('/'): - info.nodeName.End(p); - state = S_START; - break; - default: - break; - }; - break; - } - case S_NODE_OPENBRACKET: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T('@'): - info.attrName.Begin(p+1); - state = S_NODE_ATTRNAME; - break; - case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): - case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): - info.nodeIndex.Begin(p); - state = S_NODE_INDEX; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - case S_NODE_INDEX: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T(']'): - info.nodeIndex.End(p); - state = S_NODE_CLOSEBRACKET; - break; - case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): - case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - case S_NODE_ATTRNAME: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T('='): - info.attrName.End(p); - state = S_NODE_ATTREQUALS; - break; - default: - break; - }; - break; - } - case S_NODE_ATTREQUALS: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T('\''): - info.attrValue.Begin(p+1); - state = S_NODE_ATTRVALUE; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - case S_NODE_ATTRVALUE: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T('\''): - info.attrValue.End(p); - state = S_NODE_ATTRCLOSEVALUE; - break; - default: - break; - }; - break; - } - case S_NODE_ATTRCLOSEVALUE: - { - switch (*p) - { - case 0: - state = S_FINAL_ERROR; - break; - case _T(']'): - state = S_NODE_CLOSEBRACKET; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - case S_NODE_CLOSEBRACKET: - { - switch (*p) - { - case 0: - state = S_FINAL_NODE; - break; - case _T('/'): - state = S_START; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - } - - if (!*p && (state < S_FINAL)) - { - state = S_FINAL_ERROR; - } - } - - switch (state) - { - case S_FINAL_ATTR: - m_szParam = info.attrName.p; - return T_ATTRIBUTE; - case S_FINAL_NODE: - ProcessPath(info, bCreate); - return T_NODE; - case S_FINAL_NODESET: - m_szParam = info.nodeName.p; - return T_NODESET; - } - - return T_ERROR; -} diff --git a/protocols/JabberG/jabber_xml.h b/protocols/JabberG/jabber_xml.h deleted file mode 100644 index 0a1b41e511..0000000000 --- a/protocols/JabberG/jabber_xml.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_XML_H_ -#define _JABBER_XML_H_ - -#include <m_xml.h> - -void __fastcall xmlAddChild( HXML, HXML ); -HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName ); -HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName, LPCTSTR ptszValue ); -HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName, int iValue ); - -LPCTSTR __fastcall xmlGetAttrValue( HXML, LPCTSTR key ); -HXML __fastcall xmlGetChild( HXML, int n = 0 ); -HXML __fastcall xmlGetChild( HXML, LPCSTR key ); -HXML __fastcall xmlGetChild( HXML, LPCTSTR key ); -int __fastcall xmlGetChildCount( HXML ); -HXML __fastcall xmlGetChildByTag( HXML, LPCTSTR key, LPCTSTR attrName, LPCTSTR attrValue ); -HXML __fastcall xmlGetChildByTag( HXML, LPCSTR key, LPCSTR attrName, LPCTSTR attrValue ); -HXML __fastcall xmlGetNthChild( HXML, LPCTSTR key, int n = 0 ); - -LPCTSTR __fastcall xmlGetName( HXML ); -LPCTSTR __fastcall xmlGetText( HXML ); - -void __fastcall xmlAddAttr( HXML, LPCTSTR pszName, LPCTSTR ptszValue ); -void __fastcall xmlAddAttr( HXML, LPCTSTR pszName, int value ); -void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, unsigned __int64 value ); -void __fastcall xmlAddAttrID( HXML, int id ); - -int __fastcall xmlGetAttrCount( HXML ); -LPCTSTR __fastcall xmlGetAttr( HXML, int n ); -LPCTSTR __fastcall xmlGetAttrName( HXML, int n ); -LPCTSTR __fastcall xmlGetAttrValue( HXML, LPCTSTR key ); - -struct XmlNode -{ - __forceinline XmlNode() { m_hXml = NULL; } - - __forceinline XmlNode( LPCTSTR pszString, int* numBytes, LPCTSTR ptszTag ) - { - m_hXml = xi.parseString( pszString, numBytes, ptszTag ); - } - - XmlNode( const XmlNode& n ); - XmlNode( LPCTSTR name ); - XmlNode( LPCTSTR pszName, LPCTSTR ptszText ); - ~XmlNode(); - - XmlNode& operator =( const XmlNode& n ); - - __forceinline operator HXML() const - { return m_hXml; - } - -private: - HXML m_hXml; -}; - -class CJabberIqInfo; - -struct XmlNodeIq : public XmlNode -{ - XmlNodeIq( const TCHAR* type, int id = -1, const TCHAR* to = NULL ); - XmlNodeIq( const TCHAR* type, const TCHAR* idStr, const TCHAR* to ); - XmlNodeIq( const TCHAR* type, HXML node, const TCHAR* to ); - // new request - XmlNodeIq( CJabberIqInfo* pInfo ); - // answer to request - XmlNodeIq( const TCHAR* type, CJabberIqInfo* pInfo ); -}; - -typedef void ( *JABBER_XML_CALLBACK )( HXML, void* ); - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XATTR -{ - LPCTSTR name, value; - - __forceinline XATTR( LPCTSTR _name, LPCTSTR _value ) : - name( _name ), - value( _value ) - {} -}; - -HXML __forceinline operator<<( HXML node, const XATTR& attr ) -{ xmlAddAttr( node, attr.name, attr.value ); - return node; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XATTRI -{ - LPCTSTR name; - int value; - - __forceinline XATTRI( LPCTSTR _name, int _value ) : - name( _name ), - value( _value ) - {} -}; - -HXML __forceinline operator<<( HXML node, const XATTRI& attr ) -{ xmlAddAttr( node, attr.name, attr.value ); - return node; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XATTRI64 -{ - LPCTSTR name; - unsigned __int64 value; - - __forceinline XATTRI64( LPCTSTR _name, unsigned __int64 _value ) : - name( _name ), - value( _value ) - {} -}; - -HXML __forceinline operator<<( HXML node, const XATTRI64& attr ) -{ xmlAddAttr( node, attr.name, attr.value ); - return node; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XATTRID -{ - int id; - - __forceinline XATTRID( int _value ) : - id( _value ) - {} -}; - -HXML __forceinline operator<<( HXML node, const XATTRID& attr ) -{ xmlAddAttrID( node, attr.id ); - return node; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XCHILD -{ - LPCTSTR name, value; - - __forceinline XCHILD( LPCTSTR _name, LPCTSTR _value = NULL ) : - name( _name ), - value( _value ) - {} -}; - -HXML __forceinline operator<<( HXML node, const XCHILD& child ) -{ return xmlAddChild( node, child.name, child.value ); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XCHILDNS -{ - LPCTSTR name, ns; - - __forceinline XCHILDNS( LPCTSTR _name, LPCTSTR _ns = NULL ) : - name( _name ), - ns( _ns ) - {} -}; - -HXML __fastcall operator<<( HXML node, const XCHILDNS& child ); - -///////////////////////////////////////////////////////////////////////////////////////// - -struct XQUERY -{ - LPCTSTR ns; - - __forceinline XQUERY( LPCTSTR _ns ) : - ns( _ns ) - {} -}; - -HXML __fastcall operator<<( HXML node, const XQUERY& child ); - -///////////////////////////////////////////////////////////////////////////////////////// -// Limited XPath support -// path should look like: "node-spec/node-spec/.../result-spec" -// where "node-spec" can be "node-name", "node-name[@attr-name='attr-value']" or "node-name[node-index]" -// result may be either "node-spec", or "@attr-name" -// -// Samples: -// LPCTSTR s = XPathT(node, "child/subchild[@attr='value']"); // get node text -// LPCTSTR s = XPathT(node, "child/subchild[2]/@attr"); // get attribute value -// XPathT(node, "child/subchild[@name='test']/@attr") = _T("Hello"); // create path if needed and set attribute value -// -// XPathT(node, "child/subchild[@name='test']") = _T("Hello"); // TODO: create path if needed and set node text - -#define XPathT(a,b) XPath(a, _T(b)) - -class XPath -{ -public: - __forceinline XPath(HXML hXml, TCHAR *path): - m_type(T_UNKNOWN), - m_hXml(hXml), - m_szPath(path), - m_szParam(NULL) - {} - - // Read data - operator HXML() - { - switch (Lookup()) - { - case T_NODE: return m_hXml; - case T_NODESET: return xmlGetNthChild(m_hXml, m_szParam, 1); - } - return NULL; - } - operator LPTSTR() - { - switch (Lookup()) - { - case T_ATTRIBUTE: return (TCHAR *)xmlGetAttrValue(m_hXml, m_szParam); - case T_NODE: return (TCHAR *)xmlGetText(m_hXml); - case T_NODESET: return (TCHAR *)xmlGetText(xmlGetNthChild(m_hXml, m_szParam, 1)); - } - return NULL; - } - operator int() - { - if (TCHAR *s = *this) return _ttoi(s); - return 0; - } - __forceinline bool operator== (TCHAR *str) - { - return !lstrcmp((LPCTSTR)*this, str); - } - __forceinline bool operator!= (TCHAR *str) - { - return lstrcmp((LPCTSTR)*this, str) ? true : false; - } - HXML operator[] (int idx) - { - return (Lookup() == T_NODESET) ? xmlGetNthChild(m_hXml, m_szParam, idx) : NULL; - } - - // Write data - void operator= (LPCTSTR value) - { - switch (Lookup(true)) - { - case T_ATTRIBUTE: xmlAddAttr(m_hXml, m_szParam, value); break; - case T_NODE: break; // TODO: set node text - } - } - void operator= (int value) - { - TCHAR buf[16]; - _itot(value, buf, 10); - *this = buf; - } - -private: - enum PathType - { - T_UNKNOWN, - T_ERROR, - T_NODE, - T_ATTRIBUTE, - T_NODESET - }; - - __forceinline PathType Lookup(bool bCreate=false) - { - return (m_type == T_UNKNOWN) ? LookupImpl(bCreate) : m_type; - } - - enum LookupState - { - S_START, - S_ATTR_STEP, - S_NODE_NAME, - S_NODE_OPENBRACKET, - S_NODE_INDEX, - S_NODE_ATTRNAME, - S_NODE_ATTREQUALS, - S_NODE_ATTRVALUE, - S_NODE_ATTRCLOSEVALUE, - S_NODE_CLOSEBRACKET, - - S_FINAL, - S_FINAL_ERROR, - S_FINAL_ATTR, - S_FINAL_NODESET, - S_FINAL_NODE - }; - - struct LookupString - { - void Begin(const TCHAR *p_) { p = p_; } - void End(const TCHAR *p_) { length = p_ - p; } - operator bool() { return p ? true : false; } - - const TCHAR *p; - int length; - - }; - - struct LookupInfo - { - void Reset() { memset(this, 0, sizeof(*this)); } - LookupString nodeName; - LookupString attrName; - LookupString attrValue; - LookupString nodeIndex; - }; - - void ProcessPath(LookupInfo &info, bool bCreate); - PathType LookupImpl(bool bCreate); - - PathType m_type; - HXML m_hXml; - LPCTSTR m_szPath; - LPCTSTR m_szParam; -}; - -class XPathFmt: public XPath -{ -public: - enum { BUFSIZE = 512 }; - XPathFmt(HXML hXml, TCHAR *path, ...): XPath(hXml, m_buf) - { - *m_buf = 0; - - va_list args; - va_start(args, path); - _vsntprintf(m_buf, BUFSIZE, path, args); - m_buf[BUFSIZE-1] = 0; - va_end(args); - } - - XPathFmt(HXML hXml, char *path, ...): XPath(hXml, m_buf) - { - *m_buf = 0; - char buf[BUFSIZE]; - - va_list args; - va_start(args, path); - _vsnprintf(buf, BUFSIZE, path, args); - buf[BUFSIZE-1] = 0; - MultiByteToWideChar(CP_ACP, 0, buf, -1, m_buf, BUFSIZE); - va_end(args); - } - -private: - TCHAR m_buf[BUFSIZE]; -}; - -#endif diff --git a/protocols/JabberG/jabber_xstatus.cpp b/protocols/JabberG/jabber_xstatus.cpp deleted file mode 100644 index d15cae2bcd..0000000000 --- a/protocols/JabberG/jabber_xstatus.cpp +++ /dev/null @@ -1,2138 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Maxim Mluhov - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" -#include "jabber_caps.h" - -#include <m_genmenu.h> -#include <m_icolib.h> -#include <m_fontservice.h> - -#include <m_cluiframes.h> - -#include "m_proto_listeningto.h" -#include "m_skin_eng.h" -#include "m_extraicons.h" - -/////////////////////////////////////////////////////////////////////////////// -// Simple dialog with timer and ok/cancel buttons -class CJabberDlgPepBase: public CJabberDlgBase -{ - typedef CJabberDlgBase CSuper; -public: - CJabberDlgPepBase(CJabberProto *proto, int id); - -protected: - CPepService *m_pepService; - - CCtrlButton m_btnOk; - CCtrlButton m_btnCancel; - - void OnInitDialog(); - int Resizer(UTILRESIZECONTROL *urc); - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - void StopTimer(); - -private: - int m_time; -}; - -CJabberDlgPepBase::CJabberDlgPepBase(CJabberProto *proto, int id): - CJabberDlgBase(proto, id, NULL), - m_btnOk(this, IDOK), - m_btnCancel(this, IDCANCEL) -{ -} - -void CJabberDlgPepBase::OnInitDialog() -{ - CSuper::OnInitDialog(); - - m_time = 5; - SetTimer(m_hwnd, 1, 1000, NULL); - - TCHAR buf[128]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), m_time); - m_btnOk.SetText(buf); -} - -int CJabberDlgPepBase::Resizer(UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDOK: - case IDCANCEL: - return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; - } - - return CSuper::Resizer(urc); -} - -INT_PTR CJabberDlgPepBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_TIMER: - if (wParam == 1) { - TCHAR buf[128]; - mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), --m_time); - m_btnOk.SetText(buf); - - if (m_time < 0) { - KillTimer(m_hwnd, 1); - UIEmulateBtnClick(m_hwnd, IDOK); - } - - return TRUE; - } - - break; - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -void CJabberDlgPepBase::StopTimer() -{ - KillTimer(m_hwnd, 1); - m_btnOk.SetText(TranslateT("OK")); -} - -/////////////////////////////////////////////////////////////////////////////// -// Simple PEP status -class CJabberDlgPepSimple: public CJabberDlgPepBase -{ - typedef CJabberDlgPepBase CSuper; -public: - CJabberDlgPepSimple(CJabberProto *proto, TCHAR *title); - ~CJabberDlgPepSimple(); - - bool OkClicked() { return m_bOkClicked; } - void AddStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem = false); - void SetActiveStatus(LPARAM id, TCHAR *text); - LPARAM GetStatusMode(); - TCHAR *GetStatusText(); - -protected: - CCtrlCombo m_cbModes; - CCtrlEdit m_txtDescription; - - void OnInitDialog(); - int Resizer(UTILRESIZECONTROL *urc); - - UI_MESSAGE_MAP(CJabberDlgPepSimple, CSuper); - UI_MESSAGE(WM_MEASUREITEM, OnWmMeasureItem); - UI_MESSAGE(WM_DRAWITEM, OnWmDrawItem); - UI_MESSAGE(WM_GETMINMAXINFO, OnWmGetMinMaxInfo); - UI_MESSAGE_MAP_END(); - - BOOL OnWmMeasureItem(UINT msg, WPARAM wParam, LPARAM lParam); - BOOL OnWmDrawItem(UINT msg, WPARAM wParam, LPARAM lParam); - BOOL OnWmGetMinMaxInfo(UINT msg, WPARAM wParam, LPARAM lParam); - -private: - struct CStatusMode - { - LPARAM m_id; - char *m_name; - HICON m_hIcon; - TCHAR *m_title; - bool m_subitem; - - CStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem): m_id(id), m_name(name), m_hIcon(hIcon), m_title(title), m_subitem(subitem) {} - ~CStatusMode() { g_ReleaseIcon( m_hIcon ); } - }; - - OBJLIST<CStatusMode> m_modes; - TCHAR *m_text; - TCHAR *m_title; - int m_time; - int m_prevSelected; - int m_selected; - bool m_bOkClicked; - - LPARAM m_active; - TCHAR *m_activeText; - - void btnOk_OnClick(CCtrlButton *btn); - void global_OnChange(CCtrlData *); - void cbModes_OnChange(CCtrlData *); -}; - -CJabberDlgPepSimple::CJabberDlgPepSimple(CJabberProto *proto, TCHAR *title): - CJabberDlgPepBase(proto, IDD_PEP_SIMPLE), - m_cbModes(this, IDC_CB_MODES), - m_txtDescription(this, IDC_TXT_DESCRIPTION), - m_modes(10), - m_text(NULL), - m_selected(0), - m_prevSelected(-1), - m_active(-1), - m_bOkClicked(false), - m_title(title) -{ - m_btnOk.OnClick = Callback(this, &CJabberDlgPepSimple::btnOk_OnClick); - m_cbModes.OnChange = Callback(this, &CJabberDlgPepSimple::cbModes_OnChange); - m_cbModes.OnDropdown = - m_txtDescription.OnChange = Callback(this, &CJabberDlgPepSimple::global_OnChange); - - m_modes.insert(new CStatusMode(-1, "<none>", LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT), TranslateT("None"), false)); -} - -CJabberDlgPepSimple::~CJabberDlgPepSimple() -{ - mir_free(m_text); -} - -void CJabberDlgPepSimple::AddStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem) -{ - m_modes.insert(new CStatusMode(id, name, hIcon, title, subitem)); -} - -void CJabberDlgPepSimple::SetActiveStatus(LPARAM id, TCHAR *text) -{ - m_active = id; - m_activeText = text; -} - -LPARAM CJabberDlgPepSimple::GetStatusMode() -{ - return m_modes[m_selected].m_id; -} - -TCHAR *CJabberDlgPepSimple::GetStatusText() -{ - return m_text; -} - -void CJabberDlgPepSimple::OnInitDialog() -{ - CSuper::OnInitDialog(); - - WindowSetIcon( m_hwnd, m_proto, "main" ); - SetWindowText(m_hwnd, m_title); - - m_txtDescription.Enable(false); - for (int i = 0; i < m_modes.getCount(); ++i) - { - int idx = m_cbModes.AddString(m_modes[i].m_title, i); - if ((m_modes[i].m_id == m_active) || !idx) - { - m_prevSelected = idx; - m_cbModes.SetCurSel(idx); - if (idx) m_txtDescription.Enable(); - } - } - if (m_activeText) - { - m_txtDescription.SetText(m_activeText); - } -} - -int CJabberDlgPepSimple::Resizer(UTILRESIZECONTROL *urc) -{ - switch (urc->wId) - { - case IDC_CB_MODES: - return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; - case IDC_TXT_DESCRIPTION: - return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; - } - - return CSuper::Resizer(urc); -} - -void CJabberDlgPepSimple::btnOk_OnClick(CCtrlButton*) -{ - m_text = m_txtDescription.GetText(); - m_selected = m_cbModes.GetCurSel(); - m_bOkClicked = true; -} - -void CJabberDlgPepSimple::global_OnChange(CCtrlData *) -{ - StopTimer(); -} - -void CJabberDlgPepSimple::cbModes_OnChange(CCtrlData *) -{ - StopTimer(); - - if (m_prevSelected == m_cbModes.GetCurSel()) - return; - - char szSetting[128]; - - if ((m_prevSelected >= 0) && (m_modes[m_cbModes.GetItemData(m_prevSelected)].m_id >= 0)) - { - TCHAR *txt = m_txtDescription.GetText(); - mir_snprintf(szSetting, SIZEOF(szSetting), "PepMsg_%s", m_modes[m_cbModes.GetItemData(m_prevSelected)].m_name); - m_proto->JSetStringT(NULL, szSetting, txt); - mir_free(txt); - } - - m_prevSelected = m_cbModes.GetCurSel(); - if ((m_prevSelected >= 0) && (m_modes[m_cbModes.GetItemData(m_prevSelected)].m_id >= 0)) - { - mir_snprintf(szSetting, SIZEOF(szSetting), "PepMsg_%s", m_modes[m_cbModes.GetItemData(m_prevSelected)].m_name); - - DBVARIANT dbv; - if (!m_proto->JGetStringT(NULL, szSetting, &dbv)) - { - m_txtDescription.SetText(dbv.ptszVal); - JFreeVariant(&dbv); - } else - { - m_txtDescription.SetTextA(""); - } - m_txtDescription.Enable(true); - } else - { - m_txtDescription.SetTextA(""); - m_txtDescription.Enable(false); - } -} - -BOOL CJabberDlgPepSimple::OnWmMeasureItem(UINT, WPARAM, LPARAM lParam) -{ - LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; - if (lpmis->CtlID != IDC_CB_MODES) - return FALSE; - - TEXTMETRIC tm = {0}; - HDC hdc = GetDC(m_cbModes.GetHwnd()); - GetTextMetrics(hdc, &tm); - ReleaseDC(m_cbModes.GetHwnd(), hdc); - - lpmis->itemHeight = max(tm.tmHeight, 18); - if (lpmis->itemHeight < 18) lpmis->itemHeight = 18; - - return TRUE; -} - -BOOL CJabberDlgPepSimple::OnWmDrawItem(UINT, WPARAM, LPARAM lParam) -{ - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; - if (lpdis->CtlID != IDC_CB_MODES) - return FALSE; - - if (lpdis->itemData == -1) return FALSE; - - CStatusMode *mode = &m_modes[lpdis->itemData]; - - TEXTMETRIC tm = {0}; - GetTextMetrics(lpdis->hDC, &tm); - - SetBkMode(lpdis->hDC, TRANSPARENT); - if (lpdis->itemState & ODS_SELECTED) - { - SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); - } else - { - SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT)); - FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); - } - - if (!mode->m_subitem || (lpdis->itemState & ODS_COMBOBOXEDIT)) - { - TCHAR text[128]; - if (mode->m_subitem) - { - for (int i = lpdis->itemData; i >= 0; --i) - if (!m_modes[i].m_subitem) - { - mir_sntprintf(text, SIZEOF(text), _T("%s [%s]"), m_modes[i].m_title, mode->m_title); - break; - } - } else - { - lstrcpyn(text, mode->m_title, SIZEOF(text)); - } - - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+2, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, mode->m_hIcon, 16, 16, 0, NULL, DI_NORMAL); - TextOut(lpdis->hDC, lpdis->rcItem.left + 23, (lpdis->rcItem.top+lpdis->rcItem.bottom-tm.tmHeight)/2, text, lstrlen(text)); - } else - { - TCHAR text[128]; - mir_sntprintf(text, SIZEOF(text), _T("...%s"), mode->m_title); - DrawIconEx(lpdis->hDC, lpdis->rcItem.left+23, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, mode->m_hIcon, 16, 16, 0, NULL, DI_NORMAL); - TextOut(lpdis->hDC, lpdis->rcItem.left + 44, (lpdis->rcItem.top+lpdis->rcItem.bottom-tm.tmHeight)/2, text, lstrlen(text)); - } - - return TRUE; -} - -BOOL CJabberDlgPepSimple::OnWmGetMinMaxInfo(UINT, WPARAM, LPARAM lParam) -{ - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - lpmmi->ptMinTrackSize.x = 200; - lpmmi->ptMinTrackSize.y = 200; - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// CPepService base class -CPepService::CPepService(CJabberProto *proto, char *name, TCHAR *node): - m_proto(proto), - m_name(name), - m_node(node), - m_hMenuItem(NULL) -{ -} - -CPepService::~CPepService() -{ -} - -void CPepService::Publish() -{ - XmlNodeIq iq( _T("set"), m_proto->SerialNext()); - CreateData( - iq << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) - << XCHILD( _T("publish")) << XATTR( _T("node"), m_node ) - << XCHILD( _T("item")) << XATTR( _T("id"), _T("current"))); - m_proto->m_ThreadInfo->send( iq ); - - m_wasPublished = TRUE; -} - -void CPepService::Retract() -{ - TCHAR* tempName = mir_a2t( m_name ); - _tcslwr( tempName ); - - m_proto->m_ThreadInfo->send( - XmlNodeIq( _T("set"), m_proto->SerialNext()) - << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) - << XCHILD( _T("publish")) << XATTR( _T("node"), m_node ) - << XCHILD( _T("item")) - << XCHILDNS( tempName, m_node )); - - mir_free( tempName ); -} - -void CPepService::ResetPublish() -{ - m_wasPublished = FALSE; -} - -void CPepService::ForceRepublishOnLogin() -{ - if (!m_wasPublished) - Publish(); -} - -/////////////////////////////////////////////////////////////////////////////// -// CPepGuiService base class - -CPepGuiService::CPepGuiService(CJabberProto *proto, char *name, TCHAR *node): - CPepService(proto, name, node), - m_bGuiOpen(false), - m_hIcolibItem(NULL), - m_szText(NULL), - m_hMenuService(NULL) -{ -} - -CPepGuiService::~CPepGuiService() -{ - if (m_hMenuService) - { - DestroyServiceFunction(m_hMenuService); - m_hMenuService = NULL; - } - - if (m_szText) mir_free(m_szText); -} - -void CPepGuiService::InitGui() -{ - char szService[128]; - mir_snprintf(szService, SIZEOF(szService), "%s/AdvStatusSet/%s", m_proto->m_szModuleName, m_name); - - int (__cdecl CPepGuiService::*serviceProc)(WPARAM, LPARAM); - serviceProc = &CPepGuiService::OnMenuItemClick; - m_hMenuService = CreateServiceFunctionObj(szService, (MIRANDASERVICEOBJ)*(void **)&serviceProc, this); - - RebuildMenu(); -} - -void CPepGuiService::RebuildMenu() -{ - HGENMENU hJabberRoot = MO_GetProtoRootMenu( m_proto->m_szModuleName ); - if ( hJabberRoot ) { - char szService[128]; - mir_snprintf(szService, SIZEOF(szService), "%s/AdvStatusSet/%s", m_proto->m_szModuleName, m_name); - - CLISTMENUITEM mi = { 0 }; - mi.cbSize = sizeof(mi); - mi.hParentMenu = hJabberRoot; - mi.pszService = szService; - mi.position = 200010; - mi.flags = CMIF_TCHAR | CMIF_ICONFROMICOLIB | CMIF_HIDDEN | CMIF_ROOTHANDLE; - - mi.icolibItem = m_hIcolibItem; - mi.ptszName = m_szText ? m_szText : _T("<advanced status slot>"); - m_hMenuItem = Menu_AddProtoMenuItem(&mi); -} } - -bool CPepGuiService::LaunchSetGui(BYTE bQuiet) -{ - if (m_bGuiOpen) return false; - - m_bGuiOpen = true; - ShowSetDialog(bQuiet); - m_bGuiOpen = false; - - return true; -} - -void CPepGuiService::UpdateMenuItem(HANDLE hIcolibIcon, TCHAR *text) -{ - m_hIcolibItem = hIcolibIcon; - if (m_szText) mir_free(m_szText); - m_szText = text ? mir_tstrdup(text) : NULL; - - if (!m_hMenuItem) return; - - CLISTMENUITEM mi = {0}; - mi.cbSize = sizeof(mi); - mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIM_ICON|CMIM_NAME; - mi.icolibItem = m_hIcolibItem; - mi.ptszName = m_szText ? m_szText : _T("<advanced status slot>"); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)m_hMenuItem, (LPARAM)&mi); -} - -int CPepGuiService::OnMenuItemClick(WPARAM, LPARAM) -{ - LaunchSetGui(0); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// CPepMood - -struct -{ - TCHAR *szName; - char* szTag; -} static g_arrMoods[] = -{ - { LPGENT("None"), NULL }, - { LPGENT("Afraid"), "afraid" }, - { LPGENT("Amazed"), "amazed" }, - { LPGENT("Amorous"), "amorous" }, - { LPGENT("Angry"), "angry" }, - { LPGENT("Annoyed"), "annoyed" }, - { LPGENT("Anxious"), "anxious" }, - { LPGENT("Aroused"), "aroused" }, - { LPGENT("Ashamed"), "ashamed" }, - { LPGENT("Bored"), "bored" }, - { LPGENT("Brave"), "brave" }, - { LPGENT("Calm"), "calm" }, - { LPGENT("Cautious"), "cautious" }, - { LPGENT("Cold"), "cold" }, - { LPGENT("Confident"), "confident" }, - { LPGENT("Confused"), "confused" }, - { LPGENT("Contemplative"),"contemplative" }, - { LPGENT("Contented"), "contented" }, - { LPGENT("Cranky"), "cranky" }, - { LPGENT("Crazy"), "crazy" }, - { LPGENT("Creative"), "creative" }, - { LPGENT("Curious"), "curious" }, - { LPGENT("Dejected"), "dejected" }, - { LPGENT("Depressed"), "depressed" }, - { LPGENT("Disappointed"), "disappointed" }, - { LPGENT("Disgusted"), "disgusted" }, - { LPGENT("Dismayed"), "dismayed" }, - { LPGENT("Distracted"), "distracted" }, - { LPGENT("Embarrassed"), "embarrassed" }, - { LPGENT("Envious"), "envious" }, - { LPGENT("Excited"), "excited" }, - { LPGENT("Flirtatious"), "flirtatious" }, - { LPGENT("Frustrated"), "frustrated" }, - { LPGENT("Grateful"), "grateful" }, - { LPGENT("Grieving"), "grieving" }, - { LPGENT("Grumpy"), "grumpy" }, - { LPGENT("Guilty"), "guilty" }, - { LPGENT("Happy"), "happy" }, - { LPGENT("Hopeful"), "hopeful" }, - { LPGENT("Hot"), "hot" }, - { LPGENT("Humbled"), "humbled" }, - { LPGENT("Humiliated"), "humiliated" }, - { LPGENT("Hungry"), "hungry" }, - { LPGENT("Hurt"), "hurt" }, - { LPGENT("Impressed"), "impressed" }, - { LPGENT("In awe"), "in_awe" }, - { LPGENT("In love"), "in_love" }, - { LPGENT("Indignant"), "indignant" }, - { LPGENT("Interested"), "interested" }, - { LPGENT("Intoxicated"), "intoxicated" }, - { LPGENT("Invincible"), "invincible" }, - { LPGENT("Jealous"), "jealous" }, - { LPGENT("Lonely"), "lonely" }, - { LPGENT("Lost"), "lost" }, - { LPGENT("Lucky"), "lucky" }, - { LPGENT("Mean"), "mean" }, - { LPGENT("Moody"), "moody" }, - { LPGENT("Nervous"), "nervous" }, - { LPGENT("Neutral"), "neutral" }, - { LPGENT("Offended"), "offended" }, - { LPGENT("Outraged"), "outraged" }, - { LPGENT("Playful"), "playful" }, - { LPGENT("Proud"), "proud" }, - { LPGENT("Relaxed"), "relaxed" }, - { LPGENT("Relieved"), "relieved" }, - { LPGENT("Remorseful"), "remorseful" }, - { LPGENT("Restless"), "restless" }, - { LPGENT("Sad"), "sad" }, - { LPGENT("Sarcastic"), "sarcastic" }, - { LPGENT("Satisfied"), "satisfied" }, - { LPGENT("Serious"), "serious" }, - { LPGENT("Shocked"), "shocked" }, - { LPGENT("Shy"), "shy" }, - { LPGENT("Sick"), "sick" }, - { LPGENT("Sleepy"), "sleepy" }, - { LPGENT("Spontaneous"), "spontaneous" }, - { LPGENT("Stressed"), "stressed" }, - { LPGENT("Strong"), "strong" }, - { LPGENT("Surprised"), "surprised" }, - { LPGENT("Thankful"), "thankful" }, - { LPGENT("Thirsty"), "thirsty" }, - { LPGENT("Tired"), "tired" }, - { LPGENT("Undefined"), "undefined" }, - { LPGENT("Weak"), "weak" }, - { LPGENT("Worried"), "worried" }, -}; - -CPepMood::CPepMood(CJabberProto *proto): - CPepGuiService(proto, "Mood", _T(JABBER_FEAT_USER_MOOD)), - m_icons(proto), - m_text(NULL), - m_mode(-1) -{ - UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set mood...")); -} - -CPepMood::~CPepMood() -{ - if (m_text) mir_free(m_text); -} - -void CPepMood::InitGui() -{ - CSuper::InitGui(); - - char szFile[MAX_PATH]; - GetModuleFileNameA(hInst, szFile, MAX_PATH); - if (char *p = strrchr(szFile, '\\')) - strcpy( p+1, "..\\Icons\\xstatus_jabber.dll" ); - - TCHAR szSection[100]; - - mir_sntprintf(szSection, SIZEOF(szSection), _T("Status Icons/%s/Moods"), m_proto->m_tszUserName); - for (int i = 1; i < SIZEOF(g_arrMoods); i++) - m_icons.RegisterIcon( g_arrMoods[i].szTag, szFile, -(200+i), szSection, TranslateTS(g_arrMoods[i].szName)); -} - -void CPepMood::ProcessItems(const TCHAR *from, HXML itemsNode) -{ - HANDLE hContact = NULL, hSelfContact = NULL; - if ( !m_proto->IsMyOwnJID( from )) - { - hContact = m_proto->HContactFromJID(from); - if (!hContact) return; - } - else - hSelfContact = m_proto->HContactFromJID(from); - - if ( xmlGetChild( itemsNode, _T("retract"))) - { - if (hSelfContact) - SetMood(hSelfContact, NULL, NULL); - SetMood(hContact, NULL, NULL); - return; - } - - HXML n, moodNode = XPath( itemsNode, _T("item/mood[@xmlns='") _T(JABBER_FEAT_USER_MOOD) _T("']")); - if ( !moodNode ) return; - - LPCTSTR moodType = NULL, moodText = NULL; - for ( int i = 0; n = xmlGetChild( moodNode, i ); i++ ) { - if ( !_tcscmp( xmlGetName( n ), _T("text"))) - moodText = xmlGetText( n ); - else - moodType = xmlGetName( n ); - } - - TCHAR *fixedText = JabberStrFixLines( moodText ); - if (hSelfContact) - SetMood(hSelfContact, moodType, fixedText); - SetMood(hContact, moodType, fixedText); - mir_free( fixedText ); - - if (!hContact && m_mode >= 0) - ForceRepublishOnLogin(); -} - -void CPepMood::CreateData( HXML n ) -{ - HXML moodNode = n << XCHILDNS( _T("mood"), _T(JABBER_FEAT_USER_MOOD)); - moodNode << XCHILD( _A2T(g_arrMoods[m_mode].szTag)); - if ( m_text ) - moodNode << XCHILD( _T("text"), m_text ); -} - -void CPepMood::ResetExtraIcon(HANDLE hContact) -{ - char *szMood = m_proto->ReadAdvStatusA(hContact, ADVSTATUS_MOOD, "id"); - SetExtraIcon(hContact, szMood); - mir_free(szMood); -} - -void CPepMood::SetExtraIcon(HANDLE hContact, char *szMood) -{ - if (hExtraMood != NULL) - { - ExtraIcon_SetIcon(hExtraMood, hContact, szMood == NULL ? NULL : m_icons.GetIcolibName(szMood)); - } - else - { - IconExtraColumn iec; - iec.cbSize = sizeof(iec); - iec.hImage = m_icons.GetClistHandle(szMood); - iec.ColumnType = EXTRA_ICON_ADV1; - CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); - } -} - -void CPepMood::SetMood(HANDLE hContact, const TCHAR *szMood, const TCHAR *szText) -{ - int mood = -1; - if (szMood) - { - char* p = mir_t2a( szMood ); - - for (int i = 1; i < SIZEOF(g_arrMoods); ++i) - if (!lstrcmpA(g_arrMoods[i].szTag, p )) - { - mood = i; - break; - } - - mir_free( p ); - - if (mood < 0) - return; - } - - if (!hContact) - { - m_mode = mood; - replaceStrT(m_text, szText); - - HANDLE hIcon = (mood >= 0) ? m_icons.GetIcolibHandle(g_arrMoods[mood].szTag) : LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT); - TCHAR title[128]; - - if (mood >= 0) - { - mir_sntprintf(title, SIZEOF(title), TranslateT("Mood: %s"), TranslateTS(g_arrMoods[mood].szName)); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", m_icons.GetIcolibHandle(g_arrMoods[mood].szTag), TranslateTS(g_arrMoods[mood].szName)); - } else - { - lstrcpy(title, LPGENT("Set mood...")); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); - } - - UpdateMenuItem(hIcon, title); - } else - { - SetExtraIcon(hContact, mood < 0 ? NULL : g_arrMoods[mood].szTag); - } - - if (szMood) - { - m_proto->JSetByte(hContact, DBSETTING_XSTATUSID, mood); - m_proto->JSetStringT(hContact, DBSETTING_XSTATUSNAME, TranslateTS(g_arrMoods[mood].szName)); - if (szText) - m_proto->JSetStringT(hContact, DBSETTING_XSTATUSMSG, szText); - else - m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSMSG); - - m_proto->WriteAdvStatus(hContact, ADVSTATUS_MOOD, szMood, m_icons.GetIcolibName(g_arrMoods[mood].szTag), TranslateTS(g_arrMoods[mood].szName), szText); - } else - { - m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSID); - m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSNAME); - m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSMSG); - - m_proto->ResetAdvStatus(hContact, ADVSTATUS_MOOD); - } - - NotifyEventHooks(m_proto->m_hEventXStatusChanged, (WPARAM)hContact, 0); -} - -void CPepMood::ShowSetDialog(BYTE bQuiet) -{ - if ( !bQuiet ) { - CJabberDlgPepSimple dlg(m_proto, TranslateT("Set Mood")); - for (int i = 1; i < SIZEOF(g_arrMoods); ++i) - dlg.AddStatusMode(i, g_arrMoods[i].szTag, m_icons.GetIcon(g_arrMoods[i].szTag), TranslateTS(g_arrMoods[i].szName)); - dlg.SetActiveStatus(m_mode, m_text); - dlg.DoModal(); - if (!dlg.OkClicked()) - return; - - m_mode = dlg.GetStatusMode(); - replaceStrT(m_text, dlg.GetStatusText()); - } - - if (m_mode >= 0) - { - Publish(); - - UpdateMenuItem(m_icons.GetIcolibHandle(g_arrMoods[m_mode].szTag), g_arrMoods[m_mode].szName); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", m_icons.GetIcolibHandle(g_arrMoods[m_mode].szTag), TranslateTS(g_arrMoods[m_mode].szName)); - } else - { - Retract(); - UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set mood...")); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// CPepActivity -#define ACTIVITY_ICON(section, item) -(300 + (section) * 20 + (item)) - -struct -{ - char *szFirst; - char *szSecond; - TCHAR *szTitle; - int iconid; -} g_arrActivities[] = -{ - { "doing_chores", NULL, _T("Doing chores"), ACTIVITY_ICON( 0, 0) }, - { NULL, "buying_groceries", _T("buying groceries"), ACTIVITY_ICON( 0, 1) }, - { NULL, "cleaning", _T("cleaning"), ACTIVITY_ICON( 0, 2) }, - { NULL, "cooking", _T("cooking"), ACTIVITY_ICON( 0, 3) }, - { NULL, "doing_maintenance", _T("doing maintenance"), ACTIVITY_ICON( 0, 4) }, - { NULL, "doing_the_dishes", _T("doing the dishes"), ACTIVITY_ICON( 0, 5) }, - { NULL, "doing_the_laundry", _T("doing the laundry"), ACTIVITY_ICON( 0, 6) }, - { NULL, "gardening", _T("gardening"), ACTIVITY_ICON( 0, 7) }, - { NULL, "running_an_errand", _T("running an errand"), ACTIVITY_ICON( 0, 8) }, - { NULL, "walking_the_dog", _T("walking the dog"), ACTIVITY_ICON( 0, 9) }, - { "drinking", NULL, _T("Drinking"), ACTIVITY_ICON( 1, 0) }, - { NULL, "having_a_beer", _T("having a beer"), ACTIVITY_ICON( 1, 1) }, - { NULL, "having_coffee", _T("having coffee"), ACTIVITY_ICON( 1, 2) }, - { NULL, "having_tea", _T("having tea"), ACTIVITY_ICON( 1, 3) }, - { "eating", NULL, _T("Eating"), ACTIVITY_ICON( 2, 0) }, - { NULL, "having_a_snack", _T("having a snack"), ACTIVITY_ICON( 2, 1) }, - { NULL, "having_breakfast", _T("having breakfast"), ACTIVITY_ICON( 2, 2) }, - { NULL, "having_dinner", _T("having dinner"), ACTIVITY_ICON( 2, 3) }, - { NULL, "having_lunch", _T("having lunch"), ACTIVITY_ICON( 2, 4) }, - { "exercising", NULL, _T("Exercising"), ACTIVITY_ICON( 3, 0) }, - { NULL, "cycling", _T("cycling"), ACTIVITY_ICON( 3, 1) }, - { NULL, "dancing", _T("dancing"), ACTIVITY_ICON( 3, 2) }, - { NULL, "hiking", _T("hiking"), ACTIVITY_ICON( 3, 3) }, - { NULL, "jogging", _T("jogging"), ACTIVITY_ICON( 3, 4) }, - { NULL, "playing_sports", _T("playing sports"), ACTIVITY_ICON( 3, 5) }, - { NULL, "running", _T("running"), ACTIVITY_ICON( 3, 6) }, - { NULL, "skiing", _T("skiing"), ACTIVITY_ICON( 3, 7) }, - { NULL, "swimming", _T("swimming"), ACTIVITY_ICON( 3, 8) }, - { NULL, "working_out", _T("working out"), ACTIVITY_ICON( 3, 9) }, - { "grooming", NULL, _T("Grooming"), ACTIVITY_ICON( 4, 0) }, - { NULL, "at_the_spa", _T("at the spa"), ACTIVITY_ICON( 4, 1) }, - { NULL, "brushing_teeth", _T("brushing teeth"), ACTIVITY_ICON( 4, 2) }, - { NULL, "getting_a_haircut", _T("getting a haircut"), ACTIVITY_ICON( 4, 3) }, - { NULL, "shaving", _T("shaving"), ACTIVITY_ICON( 4, 4) }, - { NULL, "taking_a_bath", _T("taking a bath"), ACTIVITY_ICON( 4, 5) }, - { NULL, "taking_a_shower", _T("taking a shower"), ACTIVITY_ICON( 4, 6) }, - { "having_appointment", NULL, _T("Having appointment"), ACTIVITY_ICON( 5, 0) }, - { "inactive", NULL, _T("Inactive"), ACTIVITY_ICON( 6, 0) }, - { NULL, "day_off", _T("day off"), ACTIVITY_ICON( 6, 1) }, - { NULL, "hanging_out", _T("hanging out"), ACTIVITY_ICON( 6, 2) }, - { NULL, "hiding", _T("hiding"), ACTIVITY_ICON( 6, 3) }, - { NULL, "on_vacation", _T("on vacation"), ACTIVITY_ICON( 6, 4) }, - { NULL, "praying", _T("praying"), ACTIVITY_ICON( 6, 5) }, - { NULL, "scheduled_holiday", _T("scheduled holiday"), ACTIVITY_ICON( 6, 6) }, - { NULL, "sleeping", _T("sleeping"), ACTIVITY_ICON( 6, 7) }, - { NULL, "thinking", _T("thinking"), ACTIVITY_ICON( 6, 8) }, - { "relaxing", NULL, _T("Relaxing"), ACTIVITY_ICON( 7, 0) }, - { NULL, "fishing", _T("fishing"), ACTIVITY_ICON( 7, 1) }, - { NULL, "gaming", _T("gaming"), ACTIVITY_ICON( 7, 2) }, - { NULL, "going_out", _T("going out"), ACTIVITY_ICON( 7, 3) }, - { NULL, "partying", _T("partying"), ACTIVITY_ICON( 7, 4) }, - { NULL, "reading", _T("reading"), ACTIVITY_ICON( 7, 5) }, - { NULL, "rehearsing", _T("rehearsing"), ACTIVITY_ICON( 7, 6) }, - { NULL, "shopping", _T("shopping"), ACTIVITY_ICON( 7, 7) }, - { NULL, "smoking", _T("smoking"), ACTIVITY_ICON( 7, 8) }, - { NULL, "socializing", _T("socializing"), ACTIVITY_ICON( 7, 9) }, - { NULL, "sunbathing", _T("sunbathing"), ACTIVITY_ICON( 7, 10) }, - { NULL, "watching_tv", _T("watching TV"), ACTIVITY_ICON( 7, 11) }, - { NULL, "watching_a_movie", _T("watching a movie"), ACTIVITY_ICON( 7, 12) }, - { "talking", NULL, _T("Talking"), ACTIVITY_ICON( 8, 0) }, - { NULL, "in_real_life", _T("in real life"), ACTIVITY_ICON( 8, 1) }, - { NULL, "on_the_phone", _T("on the phone"), ACTIVITY_ICON( 8, 2) }, - { NULL, "on_video_phone", _T("on video phone"), ACTIVITY_ICON( 8, 3) }, - { "traveling", NULL, _T("Traveling"), ACTIVITY_ICON( 9, 0) }, - { NULL, "commuting", _T("commuting"), ACTIVITY_ICON( 9, 1) }, - { NULL, "cycling", _T("cycling"), ACTIVITY_ICON( 9, 2) }, - { NULL, "driving", _T("driving"), ACTIVITY_ICON( 9, 3) }, - { NULL, "in_a_car", _T("in a car"), ACTIVITY_ICON( 9, 4) }, - { NULL, "on_a_bus", _T("on a bus"), ACTIVITY_ICON( 9, 5) }, - { NULL, "on_a_plane", _T("on a plane"), ACTIVITY_ICON( 9, 6) }, - { NULL, "on_a_train", _T("on a train"), ACTIVITY_ICON( 9, 7) }, - { NULL, "on_a_trip", _T("on a trip"), ACTIVITY_ICON( 9, 8) }, - { NULL, "walking", _T("walking"), ACTIVITY_ICON( 9, 9) }, - { "working", NULL, _T("Working"), ACTIVITY_ICON(10, 0) }, - { NULL, "coding", _T("coding"), ACTIVITY_ICON(10, 1) }, - { NULL, "in_a_meeting", _T("in a meeting"), ACTIVITY_ICON(10, 2) }, - { NULL, "studying", _T("studying"), ACTIVITY_ICON(10, 3) }, - { NULL, "writing", _T("writing"), ACTIVITY_ICON(10, 4) }, - { NULL, NULL, NULL } // the end, don't delete this -}; - -inline char *ActivityGetId(int id) -{ - return g_arrActivities[id].szSecond ? g_arrActivities[id].szSecond : g_arrActivities[id].szFirst; -} - -// -1 if not found, otherwise activity number -static int ActivityCheck( LPCTSTR szFirstNode, LPCTSTR szSecondNode ) -{ - if (!szFirstNode) return 0; - - char *s1 = mir_t2a( szFirstNode ), *s2 = mir_t2a( szSecondNode ); - - int i = 0, nFirst = -1, nSecond = -1; - while ( g_arrActivities[i].szFirst || g_arrActivities[i].szSecond ) { - // check first node - if ( g_arrActivities[i].szFirst && !strcmp( s1, g_arrActivities[i].szFirst )) { - // first part found - nFirst = i; - if ( !s2 ) { - nSecond = i; - break; - } - i++; // move to next - while ( g_arrActivities[i].szSecond ) { - if ( !strcmp( g_arrActivities[i].szSecond, s2 )) { - nSecond = i; - break; - } - i++; - } - break; - } - i++; - } - - mir_free( s1 ); - mir_free( s2 ); - - if ( nSecond != -1 ) - return nSecond; - - return nFirst; -} - -char *returnActivity (int id){ - if (g_arrActivities[id].szFirst) - return g_arrActivities[id].szFirst; - if (g_arrActivities[id].szSecond) - return g_arrActivities[id].szSecond; - return NULL;} - -char *ActivityGetFirst(int id) -{ - if (id >= SIZEOF(g_arrActivities) - 1) - return NULL; - - while (id >= 0) - { - if (g_arrActivities[id].szFirst) - return g_arrActivities[id].szFirst; - --id; - } - - return NULL; -} - -char *ActivityGetFirst(char *szId) -{ - if (!szId) return NULL; - - int id = SIZEOF(g_arrActivities) - 1; - bool found_second = false; - - while (id >= 0) - { - if (g_arrActivities[id].szFirst && (found_second || !lstrcmpA(g_arrActivities[id].szFirst, szId))) - return g_arrActivities[id].szFirst; - if (g_arrActivities[id].szSecond && !found_second && !lstrcmpA(g_arrActivities[id].szSecond, szId)) - found_second = true; - --id; - } - - return NULL; -} - -char *ActivityGetSecond(int id) -{ - return (id >= 0) ? g_arrActivities[id].szSecond : NULL; -} - -TCHAR *ActivityGetFirstTitle(int id) -{ - if (id >= SIZEOF(g_arrActivities) - 1) - return NULL; - - while (id >= 0) - { - if (g_arrActivities[id].szFirst) - return g_arrActivities[id].szTitle; - --id; - } - - return NULL; -} - -TCHAR *ActivityGetSecondTitle(int id) -{ - return ((id >= 0) && g_arrActivities[id].szSecond) ? g_arrActivities[id].szTitle : NULL; -} - -void ActivityBuildTitle(int id, TCHAR *buf, int size) -{ - TCHAR *szFirst = ActivityGetFirstTitle(id); - TCHAR *szSecond = ActivityGetSecondTitle(id); - - if (szFirst) - { - if (szSecond) - mir_sntprintf(buf, size, _T("%s [%s]"), TranslateTS(szFirst), TranslateTS(szSecond)); - else - lstrcpyn(buf, TranslateTS(szFirst), size); - } else - *buf = 0; -} - -CPepActivity::CPepActivity(CJabberProto *proto): - CPepGuiService(proto, "Activity", _T(JABBER_FEAT_USER_ACTIVITY)), - m_icons(proto), - m_text(NULL), - m_mode(-1) -{ - UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set activity...")); -} - -CPepActivity::~CPepActivity() -{ - if (m_text) mir_free(m_text); -} - -void CPepActivity::InitGui() -{ - CSuper::InitGui(); - - char szFile[MAX_PATH]; - GetModuleFileNameA(hInst, szFile, MAX_PATH); - if (char *p = strrchr(szFile, '\\')) - strcpy( p+1, "..\\Icons\\xstatus_jabber.dll" ); - - TCHAR szSection[100]; - - mir_sntprintf(szSection, SIZEOF(szSection), _T("Status Icons/%s/Activities"), m_proto->m_tszUserName); - for (int i = 0; i < SIZEOF(g_arrActivities); i++) { - if (g_arrActivities[i].szFirst) - m_icons.RegisterIcon(g_arrActivities[i].szFirst, szFile, g_arrActivities[i].iconid, szSection, TranslateTS(g_arrActivities[i].szTitle)); - if (g_arrActivities[i].szSecond) - m_icons.RegisterIcon(g_arrActivities[i].szSecond, szFile, g_arrActivities[i].iconid, szSection, TranslateTS(g_arrActivities[i].szTitle));} - -} - -void CPepActivity::ProcessItems(const TCHAR *from, HXML itemsNode) -{ - HANDLE hContact = NULL, hSelfContact = NULL; - if ( !m_proto->IsMyOwnJID( from )) - { - hContact = m_proto->HContactFromJID(from); - if (!hContact) return; - } - else - hSelfContact = m_proto->HContactFromJID(from); - - if ( xmlGetChild( itemsNode, "retract")) - { - if (hSelfContact) - SetActivity(hSelfContact, NULL, NULL, NULL); - SetActivity(hContact, NULL, NULL, NULL); - return; - } - - HXML actNode = XPath( itemsNode, _T("item/activity[@xmlns='") _T(JABBER_FEAT_USER_ACTIVITY) _T("']")); - if ( !actNode ) return; - - LPCTSTR szText = XPathT( actNode, "text" ); - LPCTSTR szFirstNode = NULL, szSecondNode = NULL; - - HXML n; - for ( int i = 0; n = xmlGetChild( actNode, i ); i++ ) { - if ( lstrcmp( xmlGetName( n ), _T("text"))) - { - szFirstNode = xmlGetName( n ); - HXML secondNode = xmlGetChild( n, 0 ); - if (szFirstNode && secondNode && xmlGetName( secondNode )) - szSecondNode = xmlGetName( secondNode ); - break; - } - } - - TCHAR *fixedText = JabberStrFixLines( szText ); - if (hSelfContact) - SetActivity(hSelfContact, szFirstNode, szSecondNode, fixedText); - SetActivity(hContact, szFirstNode, szSecondNode, fixedText); - mir_free( fixedText ); - - if (!hContact && m_mode >= 0) - ForceRepublishOnLogin(); -} - -void CPepActivity::CreateData( HXML n ) -{ - char *szFirstNode = ActivityGetFirst(m_mode); - char *szSecondNode = ActivityGetSecond(m_mode); - - HXML activityNode = n << XCHILDNS( _T("activity"), _T(JABBER_FEAT_USER_ACTIVITY)); - HXML firstNode = activityNode << XCHILD( _A2T( szFirstNode )); - - if (firstNode && szSecondNode) - firstNode << XCHILD( _A2T(szSecondNode)); - - if (m_text) - activityNode << XCHILD( _T("text"), m_text); -} - -void CPepActivity::ResetExtraIcon(HANDLE hContact) -{ - char *szActivity = m_proto->ReadAdvStatusA(hContact, ADVSTATUS_ACTIVITY, "id"); - SetExtraIcon(hContact, szActivity); - mir_free(szActivity); -} - -void CPepActivity::SetExtraIcon(HANDLE hContact, char *szActivity) -{ - if (hExtraActivity != NULL) - { - ExtraIcon_SetIcon(hExtraActivity, hContact, - szActivity == NULL ? NULL : m_icons.GetIcolibName(szActivity)); - } - else - { - IconExtraColumn iec; - iec.cbSize = sizeof(iec); - iec.hImage = m_icons.GetClistHandle(szActivity); - iec.ColumnType = EXTRA_ICON_ADV2; - CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); - } -} - -void CPepActivity::SetActivity(HANDLE hContact, LPCTSTR szFirst, LPCTSTR szSecond, LPCTSTR szText) -{ - int activity = -1; - if (szFirst || szSecond) - { - activity = ActivityCheck(szFirst, szSecond); - - if (activity < 0) - return; - } - - TCHAR activityTitle[128]; - ActivityBuildTitle(activity, activityTitle, SIZEOF(activityTitle)); - - if (!hContact) - { - m_mode = activity; - replaceStrT(m_text, szText); - - HANDLE hIcon = (activity >= 0) ? m_icons.GetIcolibHandle(returnActivity(activity)) : LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT); - TCHAR title[128]; - - if (activity >= 0) - { - mir_sntprintf(title, SIZEOF(title), TranslateT("Activity: %s"), activityTitle); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", m_icons.GetIcolibHandle(returnActivity(activity)), activityTitle); - } else - { - lstrcpy(title, LPGENT("Set activity...")); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); - } - - UpdateMenuItem(hIcon, title); - } else - { - SetExtraIcon(hContact, activity < 0 ? NULL : returnActivity(activity)); - } - - - if (activity >= 0) { - TCHAR* p = mir_a2t( ActivityGetId(activity)); - m_proto->WriteAdvStatus(hContact, ADVSTATUS_ACTIVITY, p, m_icons.GetIcolibName(returnActivity(activity)), activityTitle, szText); - mir_free( p ); - } - else - m_proto->ResetAdvStatus(hContact, ADVSTATUS_ACTIVITY); -} - -void CPepActivity::ShowSetDialog(BYTE bQuiet) -{ - CJabberDlgPepSimple dlg(m_proto, TranslateT("Set Activity")); - for (int i = 0; i < SIZEOF(g_arrActivities); ++i) - if (g_arrActivities[i].szFirst || g_arrActivities[i].szSecond) - dlg.AddStatusMode(i, ActivityGetId(i), m_icons.GetIcon(returnActivity(i)), TranslateTS(g_arrActivities[i].szTitle), (g_arrActivities[i].szSecond != NULL)); - dlg.SetActiveStatus(m_mode, m_text); - dlg.DoModal(); - - if (!dlg.OkClicked()) return; - - m_mode = dlg.GetStatusMode(); - if (m_mode >= 0) - { - replaceStrT(m_text, dlg.GetStatusText()); - Publish(); - - UpdateMenuItem(m_icons.GetIcolibHandle(returnActivity(m_mode)), g_arrActivities[m_mode].szTitle); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", m_icons.GetIcolibHandle(returnActivity(m_mode)), TranslateTS(g_arrActivities[m_mode].szTitle)); - } else - { - Retract(); - UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set activity...")); - m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// icq api emulation - -HICON CJabberProto::GetXStatusIcon(int bStatus, UINT flags) -{ - CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); - HICON icon = pepMood->m_icons.GetIcon(g_arrMoods[bStatus].szTag, (flags & LR_BIGICON) != 0); - return ( flags & LR_SHARED ) ? icon : CopyIcon( icon ); -} - -int CJabberProto::CListMW_ExtraIconsApply( WPARAM wParam, LPARAM ) -{ - if (m_bJabberOnline && m_bPepSupported && ServiceExists(MS_CLIST_EXTRA_SET_ICON)) - { - char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 ); - if ( szProto==NULL || strcmp( szProto, m_szModuleName )) - return 0; // only apply icons to our contacts, do not mess others - - m_pepServices.ResetExtraIcon((HANDLE)wParam); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetXStatus - gets the extended status info (mood) - -INT_PTR __cdecl CJabberProto::OnGetXStatus( WPARAM wParam, LPARAM lParam ) -{ - if ( !m_bJabberOnline || !m_bPepSupported ) - return 0; - - if ( wParam ) *(( char** )wParam ) = DBSETTING_XSTATUSNAME; - if ( lParam ) *(( char** )lParam ) = DBSETTING_XSTATUSMSG; - return ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; -} - -// not needed anymore and therefore commented out - -/*INT_PTR __cdecl CJabberProto::OnGetXStatusEx( WPARAM wParam, LPARAM lParam ) -{ - JABBER_CUSTOM_STATUS *pData = (JABBER_CUSTOM_STATUS*)lParam; - HANDLE hContact = (HANDLE)wParam; - - if ( !m_bJabberOnline || !m_bPepSupported ) - return 1; - - if (pData->cbSize < sizeof(JABBER_CUSTOM_STATUS)) return 1; // Failure - - - if ( wParam ) *(( char** )wParam ) = DBSETTING_XSTATUSNAME; - if ( lParam ) *(( char** )lParam ) = DBSETTING_XSTATUSMSG; - return ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; -}*/ -///////////////////////////////////////////////////////////////////////////////////////// -// JabberGetXStatusIcon - Retrieves specified custom status icon -//wParam = (int)N // custom status id, 0 = my current custom status -//lParam = flags // use LR_SHARED for shared HICON -//return = HICON // custom status icon (use DestroyIcon to release resources if not LR_SHARED) - -INT_PTR __cdecl CJabberProto::OnGetXStatusIcon( WPARAM wParam, LPARAM lParam ) -{ - if ( !m_bJabberOnline ) - return 0; - - if ( !wParam ) - wParam = ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; - - if ( wParam < 1 || wParam >= SIZEOF(g_arrMoods)) - return 0; - - int flags = 0; - if ( lParam & LR_SHARED ) flags |= LR_SHARED; - if ( lParam & LR_BIGICON ) flags |= LR_BIGICON; - - return (INT_PTR)GetXStatusIcon( wParam, flags ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// SendPepMood - sends mood - -BOOL CJabberProto::SendPepTune( TCHAR* szArtist, TCHAR* szLength, TCHAR* szSource, TCHAR* szTitle, TCHAR* szTrack, TCHAR* szUri ) -{ - if ( !m_bJabberOnline || !m_bPepSupported ) - return FALSE; - - XmlNodeIq iq( _T("set"), SerialNext()); - HXML tuneNode = iq << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) - << XCHILD( _T("publish")) << XATTR( _T("node"), _T(JABBER_FEAT_USER_TUNE)) - << XCHILD( _T("item")) << XCHILDNS( _T("tune"), _T(JABBER_FEAT_USER_TUNE)); - - if ( szArtist || szLength || szSource || szTitle || szUri ) { - if ( szArtist ) tuneNode << XCHILD( _T("artist"), szArtist ); - if ( szLength ) tuneNode << XCHILD( _T("length"), szLength ); - if ( szSource ) tuneNode << XCHILD( _T("source"), szSource ); - if ( szTitle ) tuneNode << XCHILD( _T("title"), szTitle ); - if ( szTrack ) tuneNode << XCHILD( _T("track"), szTrack ); - if ( szUri ) tuneNode << XCHILD( _T("uri"), szUri ); - } - m_ThreadInfo->send( iq ); - - return TRUE; -} - -void CJabberProto::SetContactTune( HANDLE hContact, LPCTSTR szArtist, LPCTSTR szLength, LPCTSTR szSource, LPCTSTR szTitle, LPCTSTR szTrack ) -{ - if ( !szArtist && !szTitle ) { - JDeleteSetting( hContact, "ListeningTo" ); - ResetAdvStatus( hContact, ADVSTATUS_TUNE ); - return; - } - - TCHAR *szListeningTo; - if ( ServiceExists( MS_LISTENINGTO_GETPARSEDTEXT )) { - LISTENINGTOINFO li; - ZeroMemory( &li, sizeof( li )); - li.cbSize = sizeof( li ); - li.dwFlags = LTI_TCHAR; - li.ptszArtist = ( TCHAR* )szArtist; - li.ptszLength = ( TCHAR* )szLength; - li.ptszAlbum = ( TCHAR* )szSource; - li.ptszTitle = ( TCHAR* )szTitle; - li.ptszTrack = ( TCHAR* )szTrack; - szListeningTo = (TCHAR *)CallService( MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM)_T("%title% - %artist%"), (LPARAM)&li ); - } - else { - szListeningTo = (TCHAR *) mir_alloc( 2048 * sizeof( TCHAR )); - mir_sntprintf( szListeningTo, 2047, _T("%s - %s"), szTitle ? szTitle : _T(""), szArtist ? szArtist : _T("")); - } - - JSetStringT( hContact, "ListeningTo", szListeningTo ); - - char tuneIcon[128]; - mir_snprintf(tuneIcon, SIZEOF(tuneIcon), "%s_%s", m_szModuleName, "main"); - WriteAdvStatus( hContact, ADVSTATUS_TUNE, _T("listening_to"), tuneIcon, TranslateT("Listening To"), szListeningTo ); - - mir_free( szListeningTo ); -} - -TCHAR* a2tf( const TCHAR* str, BOOL unicode ) -{ - if ( str == NULL ) - return NULL; - - return ( unicode ) ? mir_tstrdup( str ) : mir_a2t(( char* )str ); -} - -void overrideStr( TCHAR*& dest, const TCHAR* src, BOOL unicode, const TCHAR* def = NULL ) -{ - if ( dest != NULL ) - { - mir_free( dest ); - dest = NULL; - } - - if ( src != NULL ) - dest = a2tf( src, unicode ); - else if ( def != NULL ) - dest = mir_tstrdup( def ); -} - -INT_PTR __cdecl CJabberProto::OnSetListeningTo( WPARAM, LPARAM lParam ) -{ - LISTENINGTOINFO *cm = (LISTENINGTOINFO *)lParam; - if ( !cm || cm->cbSize != sizeof(LISTENINGTOINFO)) { - SendPepTune( NULL, NULL, NULL, NULL, NULL, NULL ); - JDeleteSetting( NULL, "ListeningTo" ); - } - else { - TCHAR *szArtist = NULL, *szLength = NULL, *szSource = NULL; - TCHAR *szTitle = NULL, *szTrack = NULL; - - BOOL unicode = cm->dwFlags & LTI_UNICODE; - - overrideStr( szArtist, cm->ptszArtist, unicode ); - overrideStr( szSource, cm->ptszAlbum, unicode ); - overrideStr( szTitle, cm->ptszTitle, unicode ); - overrideStr( szTrack, cm->ptszTrack, unicode ); - overrideStr( szLength, cm->ptszLength, unicode ); - - TCHAR szLengthInSec[ 32 ]; - szLengthInSec[ 0 ] = _T('\0'); - if ( szLength ) { - unsigned int multiplier = 1, result = 0; - for ( TCHAR *p = szLength; *p; p++ ) { - if ( *p == _T(':')) multiplier *= 60; - } - if ( multiplier <= 3600 ) { - TCHAR *szTmp = szLength; - while ( szTmp[0] ) { - result += ( _ttoi( szTmp ) * multiplier ); - multiplier /= 60; - szTmp = _tcschr( szTmp, _T(':')); - if ( !szTmp ) - break; - szTmp++; - } - } - mir_sntprintf( szLengthInSec, SIZEOF( szLengthInSec ), _T("%d"), result ); - } - - SendPepTune( szArtist, szLength ? szLengthInSec : NULL, szSource, szTitle, szTrack, NULL ); - SetContactTune( NULL, szArtist, szLength, szSource, szTitle, szTrack ); - - mir_free( szArtist ); - mir_free( szLength ); - mir_free( szSource ); - mir_free( szTitle ); - mir_free( szTrack ); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// process InfoFrame clicks - -void CJabberProto::InfoFrame_OnUserMood(CJabberInfoFrame_Event*) -{ - m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD))->LaunchSetGui(); -} - -void CJabberProto::InfoFrame_OnUserActivity(CJabberInfoFrame_Event*) -{ - m_pepServices.Find(_T(JABBER_FEAT_USER_ACTIVITY))->LaunchSetGui(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// builds xstatus menu - -void CJabberProto::XStatusInit() -{ - if (hExtraMood == NULL) - JHookEvent( ME_CLIST_EXTRA_IMAGE_APPLY, &CJabberProto::CListMW_ExtraIconsApply ); - - RegisterAdvStatusSlot( ADVSTATUS_MOOD ); - RegisterAdvStatusSlot( ADVSTATUS_TUNE ); - RegisterAdvStatusSlot( ADVSTATUS_ACTIVITY ); -} - -void CJabberProto::XStatusUninit() -{ - if ( m_hHookExtraIconsRebuild ) - UnhookEvent( m_hHookExtraIconsRebuild ); - - if ( m_hHookExtraIconsApply ) - UnhookEvent( m_hHookExtraIconsApply ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// JabberSetXStatus - sets the extended status info (mood) - -INT_PTR __cdecl CJabberProto::OnSetXStatus( WPARAM wParam, LPARAM ) -{ - if ( !m_bPepSupported || !m_bJabberOnline ) - return 0; - - CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); - if ( !wParam ) { - pepMood->m_mode = -1; - pepMood->Retract(); - return 0; - } - - if ( wParam > 0 && wParam < SIZEOF(g_arrMoods)) { - pepMood->m_mode = wParam; - pepMood->LaunchSetGui( 0 ); - return wParam; - } - - return 0; -} - -INT_PTR __cdecl CJabberProto::OnSetXStatusEx( WPARAM wParam, LPARAM lParam) -{ - JABBER_CUSTOM_STATUS *pData = (JABBER_CUSTOM_STATUS*)lParam; - - if ( !m_bPepSupported || !m_bJabberOnline ) - return 1; - - if (pData->cbSize < sizeof(JABBER_CUSTOM_STATUS)) return 1; // Failure - - CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); - - int status = *pData->status; - if (status > 0 && status < SIZEOF(g_arrMoods)) { - pepMood->m_mode = status; - pepMood->m_text = JabberStrFixLines( pData->ptszMessage ); - pepMood->LaunchSetGui( 1 ); - return 0; - } - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Advanced status slots -// DB data format: -// Contact / AdvStatus / Proto/Status/id = mode_id -// Contact / AdvStatus / Proto/Status/icon = icon -// Contact / AdvStatus / Proto/Status/title = title -// Contact / AdvStatus / Proto/Status/text = title - -void CJabberProto::RegisterAdvStatusSlot(const char *pszSlot) -{ - char szSetting[256]; - mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/id", m_szModuleName, pszSlot); - CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); - mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/icon", m_szModuleName, pszSlot); - CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); - mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/title", m_szModuleName, pszSlot); - CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); - mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/text", m_szModuleName, pszSlot); - CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); -} - -void CJabberProto::ResetAdvStatus(HANDLE hContact, const char *pszSlot) -{ // set empty text before DBDeleteContactSetting to make resident setting manager happy - char szSetting[128]; - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/id", m_szModuleName, pszSlot); - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); - DBDeleteContactSetting(hContact, "AdvStatus", szSetting); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/icon", m_szModuleName, pszSlot); - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); - DBDeleteContactSetting(hContact, "AdvStatus", szSetting); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/title", m_szModuleName, pszSlot); - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); - DBDeleteContactSetting(hContact, "AdvStatus", szSetting); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/text", m_szModuleName, pszSlot); - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); - DBDeleteContactSetting(hContact, "AdvStatus", szSetting); -} - -void CJabberProto::WriteAdvStatus(HANDLE hContact, const char *pszSlot, const TCHAR *pszMode, const char *pszIcon, const TCHAR *pszTitle, const TCHAR *pszText) -{ - char szSetting[128]; - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/id", m_szModuleName, pszSlot); - DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszMode); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/icon", m_szModuleName, pszSlot); - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, pszIcon); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/title", m_szModuleName, pszSlot); - DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszTitle); - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/text", m_szModuleName, pszSlot); - if (pszText) { - DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszText); - } else - { - // set empty text before DBDeleteContactSetting to make resident setting manager happy - DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); - DBDeleteContactSetting(hContact, "AdvStatus", szSetting); - } -} - -char *CJabberProto::ReadAdvStatusA(HANDLE hContact, const char *pszSlot, const char *pszValue) -{ - char szSetting[128]; - DBVARIANT dbv = {0}; - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", m_szModuleName, pszSlot, pszValue); - if (DBGetContactSettingString(hContact, "AdvStatus", szSetting, &dbv)) - return NULL; - - char *res = mir_strdup(dbv.pszVal); - DBFreeVariant(&dbv); - return res; -} - -TCHAR *CJabberProto::ReadAdvStatusT(HANDLE hContact, const char *pszSlot, const char *pszValue) -{ - char szSetting[128]; - DBVARIANT dbv = {0}; - - mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", m_szModuleName, pszSlot, pszValue); - if (DBGetContactSettingTString(hContact, "AdvStatus", szSetting, &dbv)) - return NULL; - - TCHAR *res = mir_tstrdup(dbv.ptszVal); - DBFreeVariant(&dbv); - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CJabberInfoFrame - -class CJabberInfoFrameItem -{ -public: - char *m_pszName; - HANDLE m_hIcolibIcon; - TCHAR *m_pszText; - LPARAM m_pUserData; - bool m_bCompact; - bool m_bShow; - void (CJabberProto::*m_onEvent)(CJabberInfoFrame_Event *); - RECT m_rcItem; - int m_tooltipId; - -public: -/* - CJabberInfoFrameItem(): - m_pszName(NULL), m_hIcolibIcon(NULL), m_pszText(NULL) - { - } -*/ - CJabberInfoFrameItem(char *pszName, bool bCompact=false, LPARAM pUserData=0): - m_pszName(NULL), m_hIcolibIcon(NULL), m_pszText(NULL), m_bShow(true), m_bCompact(bCompact), m_pUserData(pUserData), m_onEvent(NULL) - { - m_pszName = mir_strdup(pszName); - } - ~CJabberInfoFrameItem() - { - mir_free(m_pszName); - mir_free(m_pszText); - } - - void SetInfo(HANDLE hIcolibIcon, TCHAR *pszText) - { - mir_free(m_pszText); - m_pszText = pszText ? mir_tstrdup(pszText) : NULL; - m_hIcolibIcon = hIcolibIcon; - } - - static int cmp(const CJabberInfoFrameItem *p1, const CJabberInfoFrameItem *p2) - { - return lstrcmpA(p1->m_pszName, p2->m_pszName); - } -}; - -CJabberInfoFrame::CJabberInfoFrame(CJabberProto *proto): - m_pItems(3, CJabberInfoFrameItem::cmp), m_compact(false) -{ - m_proto = proto; - m_hwnd = m_hwndToolTip = NULL; - m_clickedItem = -1; - m_hiddenItemCount = 0; - m_bLocked = false; - m_nextTooltipId = 0; - m_hhkFontsChanged = 0; - - if (!proto->m_options.DisableFrame && ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) - { - InitClass(); - - CLISTFrame frame = {0}; - frame.cbSize = sizeof(frame); - HWND hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); - frame.hWnd = CreateWindowEx(0, _T("JabberInfoFrameClass"), NULL, WS_CHILD|WS_VISIBLE, 0, 0, 100, 100, hwndClist, NULL, hInst, this); - frame.align = alBottom; - frame.height = 2 * SZ_FRAMEPADDING + GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING; // compact height by default - frame.Flags = F_VISIBLE|F_LOCKED|F_NOBORDER|F_TCHAR; - frame.tname = mir_a2t(proto->m_szModuleName); - frame.TBtname = proto->m_tszUserName; - m_frameId = CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM)&frame, 0); - mir_free(frame.tname); - if (m_frameId == -1) { - DestroyWindow(frame.hWnd); - return; - } - - m_hhkFontsChanged = HookEventMessage(ME_FONT_RELOAD, m_hwnd, WM_APP); - ReloadFonts(); - - m_hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, - WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - m_hwnd, NULL, hInst, NULL); - SetWindowPos(m_hwndToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - - CreateInfoItem("$", true); - UpdateInfoItem("$", proto->GetIconHandle(IDI_JABBER), proto->m_tszUserName); - - CreateInfoItem("$/JID", true); - UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), _T("Offline")); - SetInfoItemCallback("$/JID", &CJabberProto::InfoFrame_OnSetup); - } -} - -CJabberInfoFrame::~CJabberInfoFrame() -{ - if (!m_hwnd) return; - - if (m_hhkFontsChanged) UnhookEvent(m_hhkFontsChanged); - CallService(MS_CLIST_FRAMES_REMOVEFRAME, (WPARAM)m_frameId, 0); - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); - DestroyWindow(m_hwnd); - DestroyWindow(m_hwndToolTip); - DeleteObject(m_hfntText); - DeleteObject(m_hfntTitle); - m_hwnd = NULL; -} - -void CJabberInfoFrame::InitClass() -{ - static bool bClassRegistered = false; - if (bClassRegistered) return; - - WNDCLASSEX wcx = {0}; - wcx.cbSize = sizeof(wcx); - wcx.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; - wcx.lpfnWndProc = GlobalWndProc; - wcx.hInstance = hInst; - wcx.lpszClassName = _T("JabberInfoFrameClass"); - wcx.hCursor = LoadCursor(NULL, IDC_ARROW); - RegisterClassEx(&wcx); - bClassRegistered = true; -} - -LRESULT CALLBACK CJabberInfoFrame::GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CJabberInfoFrame *pFrame; - - if (msg == WM_CREATE) - { - CREATESTRUCT *pcs = (CREATESTRUCT *)lParam; - pFrame = (CJabberInfoFrame *)pcs->lpCreateParams; - if (pFrame) pFrame->m_hwnd = hwnd; - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pFrame); - } else - { - pFrame = (CJabberInfoFrame *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - } - - return pFrame ? pFrame->WndProc(msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam); -} - -LRESULT CJabberInfoFrame::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_APP: - { - ReloadFonts(); - return 0; - } - - case WM_PAINT: - { - RECT rc; GetClientRect(m_hwnd, &rc); - m_compact = rc.bottom < (2 * (GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING) + SZ_LINESPACING + 2 * SZ_FRAMEPADDING); - - PAINTSTRUCT ps; - HDC hdc = BeginPaint(m_hwnd, &ps); - m_compact ? PaintCompact(hdc) : PaintNormal(hdc); - EndPaint(m_hwnd, &ps); - return 0; - } - - case WM_RBUTTONUP: - { - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - MapWindowPoints(m_hwnd, NULL, &pt, 1); - HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDFRAMECONTEXT, m_frameId, 0); - int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL); - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, 0), m_frameId); - return 0; - } - - case WM_LBUTTONDOWN: - { - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - for (int i = 0; i < m_pItems.getCount(); ++i) - if (m_pItems[i].m_onEvent && PtInRect(&m_pItems[i].m_rcItem, pt)) - { - m_clickedItem = i; - return 0; - } - - return 0; - } - - case WM_LBUTTONUP: - { - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - if ((m_clickedItem >= 0) && (m_clickedItem < m_pItems.getCount()) && m_pItems[m_clickedItem].m_onEvent && PtInRect(&m_pItems[m_clickedItem].m_rcItem, pt)) - { - CJabberInfoFrame_Event evt; - evt.m_event = CJabberInfoFrame_Event::CLICK; - evt.m_pszName = m_pItems[m_clickedItem].m_pszName; - evt.m_pUserData = m_pItems[m_clickedItem].m_pUserData; - (m_proto->*m_pItems[m_clickedItem].m_onEvent)(&evt); - return 0; - } - - m_clickedItem = -1; - - return 0; - } - - case WM_LBUTTONDBLCLK: - { - m_compact = !m_compact; - UpdateSize(); - return 0; - } - } - - return DefWindowProc(m_hwnd, msg, wParam, lParam); -} - -void CJabberInfoFrame::LockUpdates() -{ - m_bLocked = true; -} - -void CJabberInfoFrame::Update() -{ - m_bLocked = false; - UpdateSize(); -} - -void CJabberInfoFrame::ReloadFonts() -{ - LOGFONT lfFont; - - FontID fontid = {0}; - fontid.cbSize = sizeof(fontid); - lstrcpyA(fontid.group, "Jabber"); - lstrcpyA(fontid.name, "Frame title"); - m_clTitle = CallService(MS_FONT_GET, (WPARAM)&fontid, (LPARAM)&lfFont); - DeleteObject(m_hfntTitle); - m_hfntTitle = CreateFontIndirect(&lfFont); - lstrcpyA(fontid.name, "Frame text"); - m_clText = CallService(MS_FONT_GET, (WPARAM)&fontid, (LPARAM)&lfFont); - DeleteObject(m_hfntText); - m_hfntText = CreateFontIndirect(&lfFont); - - ColourID colourid = {0}; - colourid.cbSize = sizeof(colourid); - lstrcpyA(colourid.group, "Jabber"); - lstrcpyA(colourid.name, "Background"); - m_clBack = CallService(MS_COLOUR_GET, (WPARAM)&colourid, 0); - - UpdateSize(); -} - -void CJabberInfoFrame::UpdateSize() -{ - if (!m_hwnd) return; - if (m_bLocked) return; - - int line_count = m_compact ? 1 : (m_pItems.getCount() - m_hiddenItemCount); - int height = 2 * SZ_FRAMEPADDING + line_count * (GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING) + (line_count - 1) * SZ_LINESPACING; - - if (CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, m_frameId), 0) & F_VISIBLE) - { - if (!ServiceExists(MS_SKIN_DRAWGLYPH)) - { - // crazy resizing for clist_nicer... - CallService(MS_CLIST_FRAMES_SHFRAME, m_frameId, 0); - CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); - CallService(MS_CLIST_FRAMES_SHFRAME, m_frameId, 0); - } else - { - CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); - RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); - } - } else - { - CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); - } -} - -void CJabberInfoFrame::RemoveTooltip(int id) -{ - TOOLINFO ti = {0}; - ti.cbSize = sizeof(TOOLINFO); - - ti.hwnd = m_hwnd; - ti.uId = id; - SendMessage(m_hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); -} - -void CJabberInfoFrame::SetToolTip(int id, RECT *rc, TCHAR *pszText) -{ - TOOLINFO ti = {0}; - ti.cbSize = sizeof(TOOLINFO); - - ti.hwnd = m_hwnd; - ti.uId = id; - SendMessage(m_hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); - - ti.uFlags = TTF_SUBCLASS; - ti.hwnd = m_hwnd; - ti.uId = id; - ti.hinst = hInst; - ti.lpszText = pszText; - ti.rect = *rc; - SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); -} - -void CJabberInfoFrame::PaintSkinGlyph(HDC hdc, RECT *rc, char **glyphs, COLORREF fallback) -{ - if (ServiceExists(MS_SKIN_DRAWGLYPH)) - { - SKINDRAWREQUEST rq = {0}; - rq.hDC = hdc; - rq.rcDestRect = *rc; - rq.rcClipRect = *rc; - - for ( ; *glyphs; ++glyphs) - { - strncpy(rq.szObjectID, *glyphs, sizeof(rq.szObjectID)); - if (!CallService(MS_SKIN_DRAWGLYPH, (WPARAM)&rq, 0)) - return; - } - } - - if (fallback != 0xFFFFFFFF) - { - HBRUSH hbr = CreateSolidBrush(fallback); - FillRect(hdc, rc, hbr); - DeleteObject(hbr); - } -} - -void CJabberInfoFrame::PaintCompact(HDC hdc) -{ - RECT rc; GetClientRect(m_hwnd, &rc); - char *glyphs[] = { "Main,ID=ProtoInfo", "Main,ID=EventArea", "Main,ID=StatusBar", NULL }; - PaintSkinGlyph(hdc, &rc, glyphs, m_clBack); - - HFONT hfntSave = (HFONT)SelectObject(hdc, m_hfntTitle); - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, m_clTitle); - - int cx_icon = GetSystemMetrics(SM_CXSMICON); - int cy_icon = GetSystemMetrics(SM_CYSMICON); - - int cx = rc.right - cx_icon - SZ_FRAMEPADDING; - for (int i = m_pItems.getCount(); i--; ) - { - CJabberInfoFrameItem &item = m_pItems[i]; - - SetRect(&item.m_rcItem, 0, 0, 0, 0); - if (!item.m_bShow) continue; - if (!item.m_bCompact) continue; - - int depth = 0; - for (char *p = item.m_pszName; p = strchr(p+1, '/'); ++depth) ; - - if (depth == 0) - { - if (item.m_hIcolibIcon) - { - HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); - if (hIcon) - { - DrawIconEx(hdc, SZ_FRAMEPADDING, (rc.bottom-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); - g_ReleaseIcon(hIcon); - } - } - - RECT rcText; SetRect(&rcText, cx_icon + SZ_FRAMEPADDING + SZ_ICONSPACING, 0, rc.right - SZ_FRAMEPADDING, rc.bottom); - DrawText(hdc, item.m_pszText, lstrlen(item.m_pszText), &rcText, DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS); - } else - { - if (item.m_hIcolibIcon) - { - HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); - if (hIcon) - { - SetRect(&item.m_rcItem, cx, (rc.bottom-cy_icon)/2, cx+cx_icon, (rc.bottom-cy_icon)/2+cy_icon); - DrawIconEx(hdc, cx, (rc.bottom-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); - cx -= cx_icon; - - g_ReleaseIcon(hIcon); - - SetToolTip(item.m_tooltipId, &item.m_rcItem, item.m_pszText); - } - } - } - } - - SelectObject(hdc, hfntSave); -} - -void CJabberInfoFrame::PaintNormal(HDC hdc) -{ - RECT rc; GetClientRect(m_hwnd, &rc); - char *glyphs[] = { "Main,ID=ProtoInfo", "Main,ID=EventArea", "Main,ID=StatusBar", NULL }; - PaintSkinGlyph(hdc, &rc, glyphs, m_clBack); - - HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); - SetBkMode(hdc, TRANSPARENT); - - int cx_icon = GetSystemMetrics(SM_CXSMICON); - int cy_icon = GetSystemMetrics(SM_CYSMICON); - int line_height = cy_icon + SZ_LINEPADDING; - int cy = SZ_FRAMEPADDING; - - for (int i = 0; i < m_pItems.getCount(); ++i) - { - CJabberInfoFrameItem &item = m_pItems[i]; - - if (!item.m_bShow) - { - SetRect(&item.m_rcItem, 0, 0, 0, 0); - continue; - } - - int cx = SZ_FRAMEPADDING; - int depth = 0; - for (char *p = item.m_pszName; p = strchr(p+1, '/'); cx += cx_icon) ++depth; - - SetRect(&item.m_rcItem, cx, cy, rc.right - SZ_FRAMEPADDING, cy + line_height); - - if (item.m_hIcolibIcon) - { - HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); - if (hIcon) - { - DrawIconEx(hdc, cx, cy + (line_height-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); - cx += cx_icon + SZ_ICONSPACING; - - g_ReleaseIcon(hIcon); - } - } - - SelectObject(hdc, depth ? m_hfntText : m_hfntTitle); - SetTextColor(hdc, depth ? m_clText : m_clTitle); - - RECT rcText; SetRect(&rcText, cx, cy, rc.right - SZ_FRAMEPADDING, cy + line_height); - DrawText(hdc, item.m_pszText, lstrlen(item.m_pszText), &rcText, DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS); - - RemoveTooltip(item.m_tooltipId); - - cy += line_height + SZ_LINESPACING; - } - - SelectObject(hdc, hfntSave); -} - -void CJabberInfoFrame::CreateInfoItem(char *pszName, bool bCompact, LPARAM pUserData) -{ - CJabberInfoFrameItem item(pszName); - if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) - return; - - CJabberInfoFrameItem *newItem = new CJabberInfoFrameItem(pszName, bCompact, pUserData); - newItem->m_tooltipId = m_nextTooltipId++; - m_pItems.insert(newItem); - UpdateSize(); -} - -void CJabberInfoFrame::SetInfoItemCallback(char *pszName, void (CJabberProto::*onEvent)(CJabberInfoFrame_Event *)) -{ - CJabberInfoFrameItem item(pszName); - if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) - { - pItem->m_onEvent = onEvent; - } -} - -void CJabberInfoFrame::UpdateInfoItem(char *pszName, HANDLE hIcolibIcon, TCHAR *pszText) -{ - CJabberInfoFrameItem item(pszName); - if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) - pItem->SetInfo(hIcolibIcon, pszText); - if (m_hwnd) - RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); -} - -void CJabberInfoFrame::ShowInfoItem(char *pszName, bool bShow) -{ - bool bUpdate = false; - size_t length = strlen(pszName); - for (int i = 0; i < m_pItems.getCount(); ++i) - if ((m_pItems[i].m_bShow != bShow) && !strncmp(m_pItems[i].m_pszName, pszName, length)) - { - m_pItems[i].m_bShow = bShow; - m_hiddenItemCount += bShow ? -1 : 1; - bUpdate = true; - } - - if (bUpdate) - UpdateSize(); -} - -void CJabberInfoFrame::RemoveInfoItem(char *pszName) -{ - bool bUpdate = false; - size_t length = strlen(pszName); - for (int i = 0; i < m_pItems.getCount(); ++i) - if (!strncmp(m_pItems[i].m_pszName, pszName, length)) - { - if (!m_pItems[i].m_bShow) --m_hiddenItemCount; - RemoveTooltip(m_pItems[i].m_tooltipId); - m_pItems.remove(i); - bUpdate = true; - --i; - } - - if (bUpdate) - UpdateSize(); -} diff --git a/protocols/JabberG/jabber_xstatus.h b/protocols/JabberG/jabber_xstatus.h deleted file mode 100644 index ae12ebae86..0000000000 --- a/protocols/JabberG/jabber_xstatus.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef _JABBER_XSTATUS_H_ -#define _JABBER_XSTATUS_H_ - -struct CJabberProto; - -class CPepService -{ -public: - CPepService(CJabberProto *proto, char *name, TCHAR *node); - virtual ~CPepService(); - - HANDLE GetMenu() { return m_hMenuItem; } - TCHAR *GetNode() { return m_node; } - virtual void ProcessItems(const TCHAR *from, HXML items) = 0; - - void Publish(); - void Retract(); - void ResetPublish(); - - virtual void InitGui() {} - virtual void RebuildMenu() {} - virtual void ResetExtraIcon(HANDLE /*hContact*/) {} - virtual bool LaunchSetGui() { return false; } - -protected: - CJabberProto *m_proto; - char *m_name; - TCHAR *m_node; - HANDLE m_hMenuItem; - - int m_wasPublished; - - virtual void CreateData( HXML ) = 0; - void ForceRepublishOnLogin(); -}; - -class CPepServiceList: public OBJLIST<CPepService> -{ -public: - CPepServiceList(): OBJLIST<CPepService>(1) {} - - void ProcessEvent(const TCHAR *from, HXML eventNode) - { - for (int i = 0; i < getCount(); ++i) - { - CPepService &pepSvc = (*this)[i]; - HXML itemsNode = xmlGetChildByTag( eventNode, _T("items"), _T("node"), pepSvc.GetNode()); - if ( itemsNode ) - pepSvc.ProcessItems(from, itemsNode); - } - } - - void InitGui() - { - for (int i = 0; i < getCount(); ++i) - (*this)[i].InitGui(); - } - - void RebuildMenu() - { - for (int i = 0; i < getCount(); ++i) - (*this)[i].RebuildMenu(); - } - - void ResetExtraIcon(HANDLE hContact) - { - for (int i = 0; i < getCount(); ++i) - (*this)[i].ResetExtraIcon(hContact); - } - - void PublishAll() - { - for (int i = 0; i < getCount(); ++i) - (*this)[i].Publish(); - } - - void RetractAll() - { - for (int i = 0; i < getCount(); ++i) - (*this)[i].Retract(); - } - - void ResetPublishAll() - { - for(int i = 0; i < getCount(); ++i) - (*this)[i].ResetPublish(); - } - - CPepService *Find(TCHAR *node) - { - for (int i = 0; i < getCount(); ++i) - if (!lstrcmp((*this)[i].GetNode(), node)) - return &((*this)[i]); - return NULL; - } -}; - -class CPepGuiService: public CPepService -{ - typedef CPepService CSuper; -public: - CPepGuiService(CJabberProto *proto, char *name, TCHAR *node); - ~CPepGuiService(); - void InitGui(); - void RebuildMenu(); - bool LaunchSetGui(BYTE bQuiet); - -protected: - void UpdateMenuItem(HANDLE hIcolibIcon, TCHAR *text); - virtual void ShowSetDialog(BYTE bQuiet) = 0; - -private: - HANDLE m_hMenuService; - HANDLE m_hIcolibItem; - TCHAR *m_szText; - - bool m_bGuiOpen; - - int __cdecl OnMenuItemClick(WPARAM, LPARAM); -}; - -class CPepMood: public CPepGuiService -{ - typedef CPepGuiService CSuper; -public: - CPepMood(CJabberProto *proto); - ~CPepMood(); - void InitGui(); - void ProcessItems(const TCHAR *from, HXML items); - void ResetExtraIcon(HANDLE hContact); - -public: // FIXME: ugly hack - CIconPool m_icons; - TCHAR *m_text; - int m_mode; - -protected: - void CreateData( HXML ); - void ShowSetDialog(BYTE bQuiet); - void SetExtraIcon(HANDLE hContact, char *szMood); - - void SetMood(HANDLE hContact, const TCHAR *szMood, const TCHAR *szText); -}; - -class CPepActivity: public CPepGuiService -{ - typedef CPepGuiService CSuper; -public: - CPepActivity(CJabberProto *proto); - ~CPepActivity(); - void InitGui(); - void ProcessItems(const TCHAR *from, HXML items); - void ResetExtraIcon(HANDLE hContact); - -protected: - CIconPool m_icons; - TCHAR *m_text; - int m_mode; - - void CreateData( HXML ); - void ShowSetDialog(BYTE bQuiet); - void SetExtraIcon(HANDLE hContact, char *szActivity); - - void SetActivity(HANDLE hContact, LPCTSTR szFirst, LPCTSTR szSecond, LPCTSTR szText); -}; - -#endif // _JABBER_XSTATUS_H_ diff --git a/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS.rc b/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS.rc deleted file mode 100644 index 9497ab6117..0000000000 --- a/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS.rc +++ /dev/null @@ -1,198 +0,0 @@ -//Microsoft Developer Studio generated resource script. -// - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -201 ICON DISCARDABLE "icos/moods/afraid.ico" -202 ICON DISCARDABLE "icos/moods/amazed.ico" -203 ICON DISCARDABLE "icos/moods/amorous.ico" -204 ICON DISCARDABLE "icos/moods/angry.ico" -205 ICON DISCARDABLE "icos/moods/annoyed.ico" -206 ICON DISCARDABLE "icos/moods/anxious.ico" -207 ICON DISCARDABLE "icos/moods/aroused.ico" -208 ICON DISCARDABLE "icos/moods/ashamed.ico" -209 ICON DISCARDABLE "icos/moods/bored.ico" -210 ICON DISCARDABLE "icos/moods/brave.ico" -211 ICON DISCARDABLE "icos/moods/calm.ico" -212 ICON DISCARDABLE "icos/moods/cautious.ico" -213 ICON DISCARDABLE "icos/moods/cold.ico" -214 ICON DISCARDABLE "icos/moods/confident.ico" -215 ICON DISCARDABLE "icos/moods/confused.ico" -216 ICON DISCARDABLE "icos/moods/contemplative.ico" -217 ICON DISCARDABLE "icos/moods/contented.ico" -218 ICON DISCARDABLE "icos/moods/cranky.ico" -219 ICON DISCARDABLE "icos/moods/crazy.ico" -220 ICON DISCARDABLE "icos/moods/creative.ico" -221 ICON DISCARDABLE "icos/moods/curious.ico" -222 ICON DISCARDABLE "icos/moods/dejected.ico" -223 ICON DISCARDABLE "icos/moods/depressed.ico" -224 ICON DISCARDABLE "icos/moods/disappointed.ico" -225 ICON DISCARDABLE "icos/moods/disgusted.ico" -226 ICON DISCARDABLE "icos/moods/dismayed.ico" -227 ICON DISCARDABLE "icos/moods/distracted.ico" -228 ICON DISCARDABLE "icos/moods/embarrassed.ico" -229 ICON DISCARDABLE "icos/moods/envious.ico" -230 ICON DISCARDABLE "icos/moods/excited.ico" -231 ICON DISCARDABLE "icos/moods/flirtatious.ico" -232 ICON DISCARDABLE "icos/moods/frustrated.ico" -233 ICON DISCARDABLE "icos/moods/grateful.ico" -234 ICON DISCARDABLE "icos/moods/grieving.ico" -235 ICON DISCARDABLE "icos/moods/grumpy.ico" -236 ICON DISCARDABLE "icos/moods/guilty.ico" -237 ICON DISCARDABLE "icos/moods/happy.ico" -238 ICON DISCARDABLE "icos/moods/hopeful.ico" -239 ICON DISCARDABLE "icos/moods/hot.ico" -240 ICON DISCARDABLE "icos/moods/humbled.ico" -241 ICON DISCARDABLE "icos/moods/humiliated.ico" -242 ICON DISCARDABLE "icos/moods/hungry.ico" -243 ICON DISCARDABLE "icos/moods/hurt.ico" -244 ICON DISCARDABLE "icos/moods/impressed.ico" -245 ICON DISCARDABLE "icos/moods/in_awe.ico" -246 ICON DISCARDABLE "icos/moods/in_love.ico" -247 ICON DISCARDABLE "icos/moods/indignant.ico" -248 ICON DISCARDABLE "icos/moods/interested.ico" -249 ICON DISCARDABLE "icos/moods/intoxicated.ico" -250 ICON DISCARDABLE "icos/moods/invincible.ico" -251 ICON DISCARDABLE "icos/moods/jealous.ico" -252 ICON DISCARDABLE "icos/moods/lonely.ico" -253 ICON DISCARDABLE "icos/moods/lost.ico" -254 ICON DISCARDABLE "icos/moods/lucky.ico" -255 ICON DISCARDABLE "icos/moods/mean.ico" -256 ICON DISCARDABLE "icos/moods/moody.ico" -257 ICON DISCARDABLE "icos/moods/nervous.ico" -258 ICON DISCARDABLE "icos/moods/neutral.ico" -259 ICON DISCARDABLE "icos/moods/offended.ico" -260 ICON DISCARDABLE "icos/moods/outraged.ico" -261 ICON DISCARDABLE "icos/moods/playful.ico" -262 ICON DISCARDABLE "icos/moods/proud.ico" -263 ICON DISCARDABLE "icos/moods/relaxed.ico" -264 ICON DISCARDABLE "icos/moods/relieved.ico" -265 ICON DISCARDABLE "icos/moods/remorseful.ico" -266 ICON DISCARDABLE "icos/moods/restless.ico" -267 ICON DISCARDABLE "icos/moods/sad.ico" -268 ICON DISCARDABLE "icos/moods/sarcastic.ico" -269 ICON DISCARDABLE "icos/moods/satisfied.ico" -270 ICON DISCARDABLE "icos/moods/serious.ico" -271 ICON DISCARDABLE "icos/moods/shocked.ico" -272 ICON DISCARDABLE "icos/moods/shy.ico" -273 ICON DISCARDABLE "icos/moods/sick.ico" -274 ICON DISCARDABLE "icos/moods/sleepy.ico" -275 ICON DISCARDABLE "icos/moods/spontaneous.ico" -276 ICON DISCARDABLE "icos/moods/stressed.ico" -277 ICON DISCARDABLE "icos/moods/strong.ico" -278 ICON DISCARDABLE "icos/moods/surprised.ico" -279 ICON DISCARDABLE "icos/moods/thankful.ico" -280 ICON DISCARDABLE "icos/moods/thirsty.ico" -281 ICON DISCARDABLE "icos/moods/tired.ico" -282 ICON DISCARDABLE "icos/moods/undefined.ico" -283 ICON DISCARDABLE "icos/moods/weak.ico" -284 ICON DISCARDABLE "icos/moods/worried.ico" - - -300 ICON DISCARDABLE "icos/activities/doing_chores.ico" -301 ICON DISCARDABLE "icos/activities/buying_groceries.ico" -302 ICON DISCARDABLE "icos/activities/cleaning.ico" -303 ICON DISCARDABLE "icos/activities/cooking.ico" -304 ICON DISCARDABLE "icos/activities/doing_maintenance.ico" -305 ICON DISCARDABLE "icos/activities/doing_the_dishes.ico" -306 ICON DISCARDABLE "icos/activities/doing_the_laundry.ico" -307 ICON DISCARDABLE "icos/activities/gardening.ico" -308 ICON DISCARDABLE "icos/activities/running_an_errand.ico" -309 ICON DISCARDABLE "icos/activities/walking_the_dog.ico" -320 ICON DISCARDABLE "icos/activities/drinking.ico" -321 ICON DISCARDABLE "icos/activities/having_a_beer.ico" -322 ICON DISCARDABLE "icos/activities/having_coffee.ico" -323 ICON DISCARDABLE "icos/activities/having_tea.ico" -340 ICON DISCARDABLE "icos/activities/eating.ico" -341 ICON DISCARDABLE "icos/activities/having_a_snack.ico" -342 ICON DISCARDABLE "icos/activities/having_breakfast.ico" -343 ICON DISCARDABLE "icos/activities/having_dinner.ico" -344 ICON DISCARDABLE "icos/activities/having_lunch.ico" -360 ICON DISCARDABLE "icos/activities/exercising.ico" -361 ICON DISCARDABLE "icos/activities/cycling.ico" -362 ICON DISCARDABLE "icos/activities/dancing.ico" -363 ICON DISCARDABLE "icos/activities/hiking.ico" -364 ICON DISCARDABLE "icos/activities/jogging.ico" -365 ICON DISCARDABLE "icos/activities/playing_sports.ico" -366 ICON DISCARDABLE "icos/activities/running.ico" -367 ICON DISCARDABLE "icos/activities/skiing.ico" -368 ICON DISCARDABLE "icos/activities/swimming.ico" -369 ICON DISCARDABLE "icos/activities/working_out.ico" -380 ICON DISCARDABLE "icos/activities/grooming.ico" -381 ICON DISCARDABLE "icos/activities/at_the_spa.ico" -382 ICON DISCARDABLE "icos/activities/brushing_teeth.ico" -383 ICON DISCARDABLE "icos/activities/getting_a_haircut.ico" -384 ICON DISCARDABLE "icos/activities/shaving.ico" -385 ICON DISCARDABLE "icos/activities/taking_a_bath.ico" -386 ICON DISCARDABLE "icos/activities/taking_a_shower.ico" -400 ICON DISCARDABLE "icos/activities/having_appointment.ico" -420 ICON DISCARDABLE "icos/activities/inactive.ico" -421 ICON DISCARDABLE "icos/activities/day_off.ico" -422 ICON DISCARDABLE "icos/activities/hanging_out.ico" -423 ICON DISCARDABLE "icos/activities/hiding.ico" -424 ICON DISCARDABLE "icos/activities/on_vacation.ico" -425 ICON DISCARDABLE "icos/activities/praying.ico" -426 ICON DISCARDABLE "icos/activities/scheduled_holiday.ico" -427 ICON DISCARDABLE "icos/activities/sleeping.ico" -428 ICON DISCARDABLE "icos/activities/thinking.ico" -440 ICON DISCARDABLE "icos/activities/relaxing.ico" -441 ICON DISCARDABLE "icos/activities/fishing.ico" -442 ICON DISCARDABLE "icos/activities/gaming.ico" -443 ICON DISCARDABLE "icos/activities/going_out.ico" -444 ICON DISCARDABLE "icos/activities/partying.ico" -445 ICON DISCARDABLE "icos/activities/reading.ico" -446 ICON DISCARDABLE "icos/activities/rehearsing.ico" -447 ICON DISCARDABLE "icos/activities/shopping.ico" -448 ICON DISCARDABLE "icos/activities/smoking.ico" -449 ICON DISCARDABLE "icos/activities/socializing.ico" -450 ICON DISCARDABLE "icos/activities/sunbathing.ico" -451 ICON DISCARDABLE "icos/activities/watching_tv.ico" -452 ICON DISCARDABLE "icos/activities/watching_a_movie.ico" -460 ICON DISCARDABLE "icos/activities/talking.ico" -461 ICON DISCARDABLE "icos/activities/in_real_life.ico" -462 ICON DISCARDABLE "icos/activities/on_the_phone.ico" -463 ICON DISCARDABLE "icos/activities/on_video_phone.ico" -480 ICON DISCARDABLE "icos/activities/traveling.ico" -481 ICON DISCARDABLE "icos/activities/commuting.ico" -482 ICON DISCARDABLE "icos/activities/cycling.ico" -483 ICON DISCARDABLE "icos/activities/driving.ico" -484 ICON DISCARDABLE "icos/activities/in_a_car.ico" -485 ICON DISCARDABLE "icos/activities/on_a_bus.ico" -486 ICON DISCARDABLE "icos/activities/on_a_plane.ico" -487 ICON DISCARDABLE "icos/activities/on_a_train.ico" -488 ICON DISCARDABLE "icos/activities/on_a_trip.ico" -489 ICON DISCARDABLE "icos/activities/walking.ico" -500 ICON DISCARDABLE "icos/activities/working.ico" -501 ICON DISCARDABLE "icos/activities/coding.ico" -502 ICON DISCARDABLE "icos/activities/in_a_meeting.ico" -503 ICON DISCARDABLE "icos/activities/studying.ico" -504 ICON DISCARDABLE "icos/activities/writing.ico" - - - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - diff --git a/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS_10.vcxproj b/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS_10.vcxproj index 5a4d9ff785..0f52450e72 100644 --- a/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS_10.vcxproj +++ b/protocols/JabberG/jabber_xstatus/JABBER_XSTATUS_10.vcxproj @@ -120,7 +120,7 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ResourceCompile Include="JABBER_XSTATUS.rc" /> + <ResourceCompile Include="res\JABBER_XSTATUS.rc" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/at_the_spa.ico b/protocols/JabberG/jabber_xstatus/icos/activities/at_the_spa.ico deleted file mode 100644 index cca4982a86..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/at_the_spa.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/bicycling.ico b/protocols/JabberG/jabber_xstatus/icos/activities/bicycling.ico deleted file mode 100644 index 8e684f44ff..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/bicycling.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/brushing_teeth.ico b/protocols/JabberG/jabber_xstatus/icos/activities/brushing_teeth.ico deleted file mode 100644 index ffe652710d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/brushing_teeth.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/buying_groceries.ico b/protocols/JabberG/jabber_xstatus/icos/activities/buying_groceries.ico deleted file mode 100644 index d1502a55be..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/buying_groceries.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/cleaning.ico b/protocols/JabberG/jabber_xstatus/icos/activities/cleaning.ico deleted file mode 100644 index 722f98f472..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/cleaning.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/coding.ico b/protocols/JabberG/jabber_xstatus/icos/activities/coding.ico deleted file mode 100644 index 63c812d442..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/coding.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/commuting.ico b/protocols/JabberG/jabber_xstatus/icos/activities/commuting.ico deleted file mode 100644 index 197a7a7817..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/commuting.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/cooking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/cooking.ico deleted file mode 100644 index e0f5dd91a3..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/cooking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/cycling.ico b/protocols/JabberG/jabber_xstatus/icos/activities/cycling.ico deleted file mode 100644 index 0145d83b87..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/cycling.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/dancing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/dancing.ico deleted file mode 100644 index 97084e0885..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/dancing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/day_off.ico b/protocols/JabberG/jabber_xstatus/icos/activities/day_off.ico deleted file mode 100644 index 3d1ccabae0..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/day_off.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/doing_chores.ico b/protocols/JabberG/jabber_xstatus/icos/activities/doing_chores.ico deleted file mode 100644 index 0f619fa093..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/doing_chores.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/doing_maintenance.ico b/protocols/JabberG/jabber_xstatus/icos/activities/doing_maintenance.ico deleted file mode 100644 index 4269f50c1f..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/doing_maintenance.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_dishes.ico b/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_dishes.ico deleted file mode 100644 index 853c7d2694..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_dishes.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_laundry.ico b/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_laundry.ico deleted file mode 100644 index f24f5da48e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/doing_the_laundry.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/drinking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/drinking.ico deleted file mode 100644 index fe836c7e07..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/drinking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/driving.ico b/protocols/JabberG/jabber_xstatus/icos/activities/driving.ico deleted file mode 100644 index 0cb11be5b1..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/driving.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/eating.ico b/protocols/JabberG/jabber_xstatus/icos/activities/eating.ico deleted file mode 100644 index f6fa60ad88..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/eating.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/exercising.ico b/protocols/JabberG/jabber_xstatus/icos/activities/exercising.ico deleted file mode 100644 index 7ccc6c7684..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/exercising.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/fishing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/fishing.ico deleted file mode 100644 index c06b871787..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/fishing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/gaming.ico b/protocols/JabberG/jabber_xstatus/icos/activities/gaming.ico deleted file mode 100644 index a65b48d77b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/gaming.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/gardening.ico b/protocols/JabberG/jabber_xstatus/icos/activities/gardening.ico deleted file mode 100644 index f6ee46440d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/gardening.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/getting_a_haircut.ico b/protocols/JabberG/jabber_xstatus/icos/activities/getting_a_haircut.ico deleted file mode 100644 index 237a8c5252..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/getting_a_haircut.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/going_out.ico b/protocols/JabberG/jabber_xstatus/icos/activities/going_out.ico deleted file mode 100644 index ca66ddc627..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/going_out.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/grooming.ico b/protocols/JabberG/jabber_xstatus/icos/activities/grooming.ico deleted file mode 100644 index f01b5348cf..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/grooming.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/hanging_out.ico b/protocols/JabberG/jabber_xstatus/icos/activities/hanging_out.ico deleted file mode 100644 index d7f94262f2..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/hanging_out.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_a_beer.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_a_beer.ico deleted file mode 100644 index 20d634f85e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_a_beer.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_a_snack.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_a_snack.ico deleted file mode 100644 index be74f572fc..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_a_snack.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_appointment.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_appointment.ico deleted file mode 100644 index 5e849b224e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_appointment.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_breakfast.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_breakfast.ico deleted file mode 100644 index c58ec2ef4e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_breakfast.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_coffee.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_coffee.ico deleted file mode 100644 index 2646fedb5e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_coffee.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_dinner.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_dinner.ico deleted file mode 100644 index 8dbb710ecf..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_dinner.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_lunch.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_lunch.ico deleted file mode 100644 index 4235afbe91..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_lunch.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/having_tea.ico b/protocols/JabberG/jabber_xstatus/icos/activities/having_tea.ico deleted file mode 100644 index cf112ec7f5..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/having_tea.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/hiding.ico b/protocols/JabberG/jabber_xstatus/icos/activities/hiding.ico deleted file mode 100644 index a5cc19e99c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/hiding.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/hiking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/hiking.ico deleted file mode 100644 index 48e94d2358..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/hiking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/in_a_car.ico b/protocols/JabberG/jabber_xstatus/icos/activities/in_a_car.ico deleted file mode 100644 index b97e49fcb0..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/in_a_car.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/in_a_meeting.ico b/protocols/JabberG/jabber_xstatus/icos/activities/in_a_meeting.ico deleted file mode 100644 index 371da3a59a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/in_a_meeting.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/in_real_life.ico b/protocols/JabberG/jabber_xstatus/icos/activities/in_real_life.ico deleted file mode 100644 index bb9bc0f931..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/in_real_life.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/inactive.ico b/protocols/JabberG/jabber_xstatus/icos/activities/inactive.ico deleted file mode 100644 index 74911a62ca..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/inactive.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/jogging.ico b/protocols/JabberG/jabber_xstatus/icos/activities/jogging.ico deleted file mode 100644 index 082df08b77..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/jogging.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_bus.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_a_bus.ico deleted file mode 100644 index 3f6c315e6a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_bus.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_plane.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_a_plane.ico deleted file mode 100644 index 3391fb0d20..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_plane.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_train.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_a_train.ico deleted file mode 100644 index 5a455b7a8b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_train.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_trip.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_a_trip.ico deleted file mode 100644 index 287b16d0ce..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_a_trip.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_the_phone.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_the_phone.ico deleted file mode 100644 index 111397e7fa..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_the_phone.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_vacation.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_vacation.ico deleted file mode 100644 index c9b43ef894..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_vacation.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/on_video_phone.ico b/protocols/JabberG/jabber_xstatus/icos/activities/on_video_phone.ico deleted file mode 100644 index 45fa03ebfd..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/on_video_phone.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/partying.ico b/protocols/JabberG/jabber_xstatus/icos/activities/partying.ico deleted file mode 100644 index 3b02879831..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/partying.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/playing_sports.ico b/protocols/JabberG/jabber_xstatus/icos/activities/playing_sports.ico deleted file mode 100644 index 2d5bca3a3c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/playing_sports.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/praying.ico b/protocols/JabberG/jabber_xstatus/icos/activities/praying.ico deleted file mode 100644 index d687a69a40..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/praying.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/reading.ico b/protocols/JabberG/jabber_xstatus/icos/activities/reading.ico deleted file mode 100644 index 8f218850b8..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/reading.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/rehearsing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/rehearsing.ico deleted file mode 100644 index f01323b74d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/rehearsing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/relaxing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/relaxing.ico deleted file mode 100644 index d7cbe0abd5..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/relaxing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/running.ico b/protocols/JabberG/jabber_xstatus/icos/activities/running.ico deleted file mode 100644 index bc4c3f151e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/running.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/running_an_errand.ico b/protocols/JabberG/jabber_xstatus/icos/activities/running_an_errand.ico deleted file mode 100644 index c0dd30c95e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/running_an_errand.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/scheduled_holiday.ico b/protocols/JabberG/jabber_xstatus/icos/activities/scheduled_holiday.ico deleted file mode 100644 index 774980c16b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/scheduled_holiday.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/shaving.ico b/protocols/JabberG/jabber_xstatus/icos/activities/shaving.ico deleted file mode 100644 index 7ed6b0bdc9..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/shaving.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/shopping.ico b/protocols/JabberG/jabber_xstatus/icos/activities/shopping.ico deleted file mode 100644 index 71ba041daf..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/shopping.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/skiing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/skiing.ico deleted file mode 100644 index 9cd96cf809..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/skiing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/sleeping.ico b/protocols/JabberG/jabber_xstatus/icos/activities/sleeping.ico deleted file mode 100644 index e8fc48edf7..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/sleeping.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/smoking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/smoking.ico deleted file mode 100644 index f3261a83a6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/smoking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/socializing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/socializing.ico deleted file mode 100644 index 83297d3084..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/socializing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/studying.ico b/protocols/JabberG/jabber_xstatus/icos/activities/studying.ico deleted file mode 100644 index 9dba262974..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/studying.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/sunbathing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/sunbathing.ico deleted file mode 100644 index 22c489631c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/sunbathing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/swimming.ico b/protocols/JabberG/jabber_xstatus/icos/activities/swimming.ico deleted file mode 100644 index 2b455683d0..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/swimming.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_bath.ico b/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_bath.ico deleted file mode 100644 index b93f86c523..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_bath.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_shower.ico b/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_shower.ico deleted file mode 100644 index c2021e851b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/taking_a_shower.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/talking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/talking.ico deleted file mode 100644 index e747618b86..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/talking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/thinking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/thinking.ico deleted file mode 100644 index e8c8ebed48..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/thinking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/traveling.ico b/protocols/JabberG/jabber_xstatus/icos/activities/traveling.ico deleted file mode 100644 index 2dfa197732..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/traveling.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/walking.ico b/protocols/JabberG/jabber_xstatus/icos/activities/walking.ico deleted file mode 100644 index 586ed93029..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/walking.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/walking_the_dog.ico b/protocols/JabberG/jabber_xstatus/icos/activities/walking_the_dog.ico deleted file mode 100644 index 2be18c864f..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/walking_the_dog.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/watching_a_movie.ico b/protocols/JabberG/jabber_xstatus/icos/activities/watching_a_movie.ico deleted file mode 100644 index c5c8603a4e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/watching_a_movie.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/watching_tv.ico b/protocols/JabberG/jabber_xstatus/icos/activities/watching_tv.ico deleted file mode 100644 index 887f949657..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/watching_tv.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/working.ico b/protocols/JabberG/jabber_xstatus/icos/activities/working.ico deleted file mode 100644 index 025581a407..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/working.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/working_out.ico b/protocols/JabberG/jabber_xstatus/icos/activities/working_out.ico deleted file mode 100644 index 668a5aa7f6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/working_out.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/activities/writing.ico b/protocols/JabberG/jabber_xstatus/icos/activities/writing.ico deleted file mode 100644 index 64b74636e1..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/activities/writing.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/afraid.ico b/protocols/JabberG/jabber_xstatus/icos/moods/afraid.ico deleted file mode 100644 index d45fe8ee11..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/afraid.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/amazed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/amazed.ico deleted file mode 100644 index 49c2b23e60..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/amazed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/amorous.ico b/protocols/JabberG/jabber_xstatus/icos/moods/amorous.ico deleted file mode 100644 index 302d2e0395..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/amorous.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/angry.ico b/protocols/JabberG/jabber_xstatus/icos/moods/angry.ico deleted file mode 100644 index c8947a4d22..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/angry.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/annoyed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/annoyed.ico deleted file mode 100644 index 850c323a2d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/annoyed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/anxious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/anxious.ico deleted file mode 100644 index d7db20d85d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/anxious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/aroused.ico b/protocols/JabberG/jabber_xstatus/icos/moods/aroused.ico deleted file mode 100644 index c29feaa8c0..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/aroused.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/ashamed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/ashamed.ico deleted file mode 100644 index 6a961f2226..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/ashamed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/bored.ico b/protocols/JabberG/jabber_xstatus/icos/moods/bored.ico deleted file mode 100644 index 0bf725ae5e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/bored.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/brave.ico b/protocols/JabberG/jabber_xstatus/icos/moods/brave.ico deleted file mode 100644 index 8b6b917bc7..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/brave.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/calm.ico b/protocols/JabberG/jabber_xstatus/icos/moods/calm.ico deleted file mode 100644 index 0ed992ba0d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/calm.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/cautious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/cautious.ico deleted file mode 100644 index df89f579f9..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/cautious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/cold.ico b/protocols/JabberG/jabber_xstatus/icos/moods/cold.ico deleted file mode 100644 index b6b7c1e884..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/cold.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/confident.ico b/protocols/JabberG/jabber_xstatus/icos/moods/confident.ico deleted file mode 100644 index bce9395830..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/confident.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/confused.ico b/protocols/JabberG/jabber_xstatus/icos/moods/confused.ico deleted file mode 100644 index 41f2e7eb4c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/confused.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/contemplative.ico b/protocols/JabberG/jabber_xstatus/icos/moods/contemplative.ico deleted file mode 100644 index bd005f816f..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/contemplative.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/contented.ico b/protocols/JabberG/jabber_xstatus/icos/moods/contented.ico deleted file mode 100644 index e97d4b9db3..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/contented.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/cranky.ico b/protocols/JabberG/jabber_xstatus/icos/moods/cranky.ico deleted file mode 100644 index ce8468307a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/cranky.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/crazy.ico b/protocols/JabberG/jabber_xstatus/icos/moods/crazy.ico deleted file mode 100644 index b2538674b6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/crazy.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/creative.ico b/protocols/JabberG/jabber_xstatus/icos/moods/creative.ico deleted file mode 100644 index 2ac57e40af..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/creative.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/curious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/curious.ico deleted file mode 100644 index 6bedb50282..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/curious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/dejected.ico b/protocols/JabberG/jabber_xstatus/icos/moods/dejected.ico deleted file mode 100644 index aea3675a09..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/dejected.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/depressed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/depressed.ico deleted file mode 100644 index 074ffd921d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/depressed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/disappointed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/disappointed.ico deleted file mode 100644 index 092df4b59c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/disappointed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/disgusted.ico b/protocols/JabberG/jabber_xstatus/icos/moods/disgusted.ico deleted file mode 100644 index d83ce3b7df..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/disgusted.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/dismayed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/dismayed.ico deleted file mode 100644 index abda47285c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/dismayed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/distracted.ico b/protocols/JabberG/jabber_xstatus/icos/moods/distracted.ico deleted file mode 100644 index e9809551fc..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/distracted.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/embarrassed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/embarrassed.ico deleted file mode 100644 index 62cdcd4c60..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/embarrassed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/envious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/envious.ico deleted file mode 100644 index 29a23da950..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/envious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/excited.ico b/protocols/JabberG/jabber_xstatus/icos/moods/excited.ico deleted file mode 100644 index 42a149ef5b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/excited.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/flirtatious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/flirtatious.ico deleted file mode 100644 index af9b114955..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/flirtatious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/frustrated.ico b/protocols/JabberG/jabber_xstatus/icos/moods/frustrated.ico deleted file mode 100644 index 790573ad4d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/frustrated.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/grateful.ico b/protocols/JabberG/jabber_xstatus/icos/moods/grateful.ico deleted file mode 100644 index 857b34c6c2..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/grateful.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/grieving.ico b/protocols/JabberG/jabber_xstatus/icos/moods/grieving.ico deleted file mode 100644 index 5b5774b9af..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/grieving.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/grumpy.ico b/protocols/JabberG/jabber_xstatus/icos/moods/grumpy.ico deleted file mode 100644 index f37395703a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/grumpy.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/guilty.ico b/protocols/JabberG/jabber_xstatus/icos/moods/guilty.ico deleted file mode 100644 index 154d32ed1e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/guilty.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/happy.ico b/protocols/JabberG/jabber_xstatus/icos/moods/happy.ico deleted file mode 100644 index f6b97adbd0..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/happy.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/hopeful.ico b/protocols/JabberG/jabber_xstatus/icos/moods/hopeful.ico deleted file mode 100644 index c012b33ee1..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/hopeful.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/hot.ico b/protocols/JabberG/jabber_xstatus/icos/moods/hot.ico deleted file mode 100644 index 1fc519a092..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/hot.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/humbled.ico b/protocols/JabberG/jabber_xstatus/icos/moods/humbled.ico deleted file mode 100644 index 8df3f7fca4..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/humbled.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/humiliated.ico b/protocols/JabberG/jabber_xstatus/icos/moods/humiliated.ico deleted file mode 100644 index 6c2c2ebb92..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/humiliated.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/hungry.ico b/protocols/JabberG/jabber_xstatus/icos/moods/hungry.ico deleted file mode 100644 index 9b4f03c9d9..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/hungry.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/hurt.ico b/protocols/JabberG/jabber_xstatus/icos/moods/hurt.ico deleted file mode 100644 index a23f46d955..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/hurt.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/impressed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/impressed.ico deleted file mode 100644 index c2af48ccc4..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/impressed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/in_awe.ico b/protocols/JabberG/jabber_xstatus/icos/moods/in_awe.ico deleted file mode 100644 index d0f4ee317b..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/in_awe.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/in_love.ico b/protocols/JabberG/jabber_xstatus/icos/moods/in_love.ico deleted file mode 100644 index 81426556d9..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/in_love.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/indignant.ico b/protocols/JabberG/jabber_xstatus/icos/moods/indignant.ico deleted file mode 100644 index c2a566bbff..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/indignant.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/interested.ico b/protocols/JabberG/jabber_xstatus/icos/moods/interested.ico deleted file mode 100644 index 0e728994a7..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/interested.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/intoxicated.ico b/protocols/JabberG/jabber_xstatus/icos/moods/intoxicated.ico deleted file mode 100644 index e7295c7762..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/intoxicated.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/invincible.ico b/protocols/JabberG/jabber_xstatus/icos/moods/invincible.ico deleted file mode 100644 index 08f145fc00..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/invincible.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/jealous.ico b/protocols/JabberG/jabber_xstatus/icos/moods/jealous.ico deleted file mode 100644 index c1ac6dd000..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/jealous.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/lonely.ico b/protocols/JabberG/jabber_xstatus/icos/moods/lonely.ico deleted file mode 100644 index 8ce7bbbe82..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/lonely.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/lost.ico b/protocols/JabberG/jabber_xstatus/icos/moods/lost.ico deleted file mode 100644 index db23931d39..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/lost.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/lucky.ico b/protocols/JabberG/jabber_xstatus/icos/moods/lucky.ico deleted file mode 100644 index 4e2894114d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/lucky.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/mean.ico b/protocols/JabberG/jabber_xstatus/icos/moods/mean.ico deleted file mode 100644 index 9a5825cf04..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/mean.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/moody.ico b/protocols/JabberG/jabber_xstatus/icos/moods/moody.ico deleted file mode 100644 index d025001a5a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/moody.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/nervous.ico b/protocols/JabberG/jabber_xstatus/icos/moods/nervous.ico deleted file mode 100644 index a8b42584b6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/nervous.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/neutral.ico b/protocols/JabberG/jabber_xstatus/icos/moods/neutral.ico deleted file mode 100644 index bc3f8ad45c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/neutral.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/offended.ico b/protocols/JabberG/jabber_xstatus/icos/moods/offended.ico deleted file mode 100644 index eb74f4235c..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/offended.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/outraged.ico b/protocols/JabberG/jabber_xstatus/icos/moods/outraged.ico deleted file mode 100644 index 1b8e99ee31..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/outraged.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/playful.ico b/protocols/JabberG/jabber_xstatus/icos/moods/playful.ico deleted file mode 100644 index b6f7e55745..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/playful.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/proud.ico b/protocols/JabberG/jabber_xstatus/icos/moods/proud.ico deleted file mode 100644 index 7ad6f97064..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/proud.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/relaxed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/relaxed.ico deleted file mode 100644 index bba4906d3e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/relaxed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/relieved.ico b/protocols/JabberG/jabber_xstatus/icos/moods/relieved.ico deleted file mode 100644 index 3bbb2ae30d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/relieved.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/remorseful.ico b/protocols/JabberG/jabber_xstatus/icos/moods/remorseful.ico deleted file mode 100644 index 095e18e468..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/remorseful.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/restless.ico b/protocols/JabberG/jabber_xstatus/icos/moods/restless.ico deleted file mode 100644 index 6e4083a57d..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/restless.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/sad.ico b/protocols/JabberG/jabber_xstatus/icos/moods/sad.ico deleted file mode 100644 index 07eae404a4..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/sad.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/sarcastic.ico b/protocols/JabberG/jabber_xstatus/icos/moods/sarcastic.ico deleted file mode 100644 index b23431bfaa..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/sarcastic.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/satisfied.ico b/protocols/JabberG/jabber_xstatus/icos/moods/satisfied.ico deleted file mode 100644 index aecdf590ff..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/satisfied.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/serious.ico b/protocols/JabberG/jabber_xstatus/icos/moods/serious.ico deleted file mode 100644 index b9005bebb2..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/serious.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/shocked.ico b/protocols/JabberG/jabber_xstatus/icos/moods/shocked.ico deleted file mode 100644 index 011dea4e60..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/shocked.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/shy.ico b/protocols/JabberG/jabber_xstatus/icos/moods/shy.ico deleted file mode 100644 index a7c02b7916..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/shy.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/sick.ico b/protocols/JabberG/jabber_xstatus/icos/moods/sick.ico deleted file mode 100644 index d3a0338b87..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/sick.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/sleepy.ico b/protocols/JabberG/jabber_xstatus/icos/moods/sleepy.ico deleted file mode 100644 index 998164780e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/sleepy.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/spontaneous.ico b/protocols/JabberG/jabber_xstatus/icos/moods/spontaneous.ico deleted file mode 100644 index 3670422597..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/spontaneous.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/stressed.ico b/protocols/JabberG/jabber_xstatus/icos/moods/stressed.ico deleted file mode 100644 index 94f0472574..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/stressed.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/strong.ico b/protocols/JabberG/jabber_xstatus/icos/moods/strong.ico deleted file mode 100644 index 01657488b6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/strong.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/surprised.ico b/protocols/JabberG/jabber_xstatus/icos/moods/surprised.ico deleted file mode 100644 index 882cfcd60a..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/surprised.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/thankful.ico b/protocols/JabberG/jabber_xstatus/icos/moods/thankful.ico deleted file mode 100644 index 56cfc59961..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/thankful.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/thirsty.ico b/protocols/JabberG/jabber_xstatus/icos/moods/thirsty.ico deleted file mode 100644 index d678569bd6..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/thirsty.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/tired.ico b/protocols/JabberG/jabber_xstatus/icos/moods/tired.ico deleted file mode 100644 index 90292c7e0e..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/tired.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/undefined.ico b/protocols/JabberG/jabber_xstatus/icos/moods/undefined.ico deleted file mode 100644 index 078db99f8f..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/undefined.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/weak.ico b/protocols/JabberG/jabber_xstatus/icos/moods/weak.ico deleted file mode 100644 index 408b769b93..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/weak.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/icos/moods/worried.ico b/protocols/JabberG/jabber_xstatus/icos/moods/worried.ico deleted file mode 100644 index 45942e7c43..0000000000 Binary files a/protocols/JabberG/jabber_xstatus/icos/moods/worried.ico and /dev/null differ diff --git a/protocols/JabberG/jabber_xstatus/res/JABBER_XSTATUS.rc b/protocols/JabberG/jabber_xstatus/res/JABBER_XSTATUS.rc new file mode 100644 index 0000000000..40eb3e2084 --- /dev/null +++ b/protocols/JabberG/jabber_xstatus/res/JABBER_XSTATUS.rc @@ -0,0 +1,198 @@ +//Microsoft Developer Studio generated resource script. +// + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +201 ICON "moods/afraid.ico" +202 ICON "moods/amazed.ico" +203 ICON "moods/amorous.ico" +204 ICON "moods/angry.ico" +205 ICON "moods/annoyed.ico" +206 ICON "moods/anxious.ico" +207 ICON "moods/aroused.ico" +208 ICON "moods/ashamed.ico" +209 ICON "moods/bored.ico" +210 ICON "moods/brave.ico" +211 ICON "moods/calm.ico" +212 ICON "moods/cautious.ico" +213 ICON "moods/cold.ico" +214 ICON "moods/confident.ico" +215 ICON "moods/confused.ico" +216 ICON "moods/contemplative.ico" +217 ICON "moods/contented.ico" +218 ICON "moods/cranky.ico" +219 ICON "moods/crazy.ico" +220 ICON "moods/creative.ico" +221 ICON "moods/curious.ico" +222 ICON "moods/dejected.ico" +223 ICON "moods/depressed.ico" +224 ICON "moods/disappointed.ico" +225 ICON "moods/disgusted.ico" +226 ICON "moods/dismayed.ico" +227 ICON "moods/distracted.ico" +228 ICON "moods/embarrassed.ico" +229 ICON "moods/envious.ico" +230 ICON "moods/excited.ico" +231 ICON "moods/flirtatious.ico" +232 ICON "moods/frustrated.ico" +233 ICON "moods/grateful.ico" +234 ICON "moods/grieving.ico" +235 ICON "moods/grumpy.ico" +236 ICON "moods/guilty.ico" +237 ICON "moods/happy.ico" +238 ICON "moods/hopeful.ico" +239 ICON "moods/hot.ico" +240 ICON "moods/humbled.ico" +241 ICON "moods/humiliated.ico" +242 ICON "moods/hungry.ico" +243 ICON "moods/hurt.ico" +244 ICON "moods/impressed.ico" +245 ICON "moods/in_awe.ico" +246 ICON "moods/in_love.ico" +247 ICON "moods/indignant.ico" +248 ICON "moods/interested.ico" +249 ICON "moods/intoxicated.ico" +250 ICON "moods/invincible.ico" +251 ICON "moods/jealous.ico" +252 ICON "moods/lonely.ico" +253 ICON "moods/lost.ico" +254 ICON "moods/lucky.ico" +255 ICON "moods/mean.ico" +256 ICON "moods/moody.ico" +257 ICON "moods/nervous.ico" +258 ICON "moods/neutral.ico" +259 ICON "moods/offended.ico" +260 ICON "moods/outraged.ico" +261 ICON "moods/playful.ico" +262 ICON "moods/proud.ico" +263 ICON "moods/relaxed.ico" +264 ICON "moods/relieved.ico" +265 ICON "moods/remorseful.ico" +266 ICON "moods/restless.ico" +267 ICON "moods/sad.ico" +268 ICON "moods/sarcastic.ico" +269 ICON "moods/satisfied.ico" +270 ICON "moods/serious.ico" +271 ICON "moods/shocked.ico" +272 ICON "moods/shy.ico" +273 ICON "moods/sick.ico" +274 ICON "moods/sleepy.ico" +275 ICON "moods/spontaneous.ico" +276 ICON "moods/stressed.ico" +277 ICON "moods/strong.ico" +278 ICON "moods/surprised.ico" +279 ICON "moods/thankful.ico" +280 ICON "moods/thirsty.ico" +281 ICON "moods/tired.ico" +282 ICON "moods/undefined.ico" +283 ICON "moods/weak.ico" +284 ICON "moods/worried.ico" + + +300 ICON "activities/doing_chores.ico" +301 ICON "activities/buying_groceries.ico" +302 ICON "activities/cleaning.ico" +303 ICON "activities/cooking.ico" +304 ICON "activities/doing_maintenance.ico" +305 ICON "activities/doing_the_dishes.ico" +306 ICON "activities/doing_the_laundry.ico" +307 ICON "activities/gardening.ico" +308 ICON "activities/running_an_errand.ico" +309 ICON "activities/walking_the_dog.ico" +320 ICON "activities/drinking.ico" +321 ICON "activities/having_a_beer.ico" +322 ICON "activities/having_coffee.ico" +323 ICON "activities/having_tea.ico" +340 ICON "activities/eating.ico" +341 ICON "activities/having_a_snack.ico" +342 ICON "activities/having_breakfast.ico" +343 ICON "activities/having_dinner.ico" +344 ICON "activities/having_lunch.ico" +360 ICON "activities/exercising.ico" +361 ICON "activities/cycling.ico" +362 ICON "activities/dancing.ico" +363 ICON "activities/hiking.ico" +364 ICON "activities/jogging.ico" +365 ICON "activities/playing_sports.ico" +366 ICON "activities/running.ico" +367 ICON "activities/skiing.ico" +368 ICON "activities/swimming.ico" +369 ICON "activities/working_out.ico" +380 ICON "activities/grooming.ico" +381 ICON "activities/at_the_spa.ico" +382 ICON "activities/brushing_teeth.ico" +383 ICON "activities/getting_a_haircut.ico" +384 ICON "activities/shaving.ico" +385 ICON "activities/taking_a_bath.ico" +386 ICON "activities/taking_a_shower.ico" +400 ICON "activities/having_appointment.ico" +420 ICON "activities/inactive.ico" +421 ICON "activities/day_off.ico" +422 ICON "activities/hanging_out.ico" +423 ICON "activities/hiding.ico" +424 ICON "activities/on_vacation.ico" +425 ICON "activities/praying.ico" +426 ICON "activities/scheduled_holiday.ico" +427 ICON "activities/sleeping.ico" +428 ICON "activities/thinking.ico" +440 ICON "activities/relaxing.ico" +441 ICON "activities/fishing.ico" +442 ICON "activities/gaming.ico" +443 ICON "activities/going_out.ico" +444 ICON "activities/partying.ico" +445 ICON "activities/reading.ico" +446 ICON "activities/rehearsing.ico" +447 ICON "activities/shopping.ico" +448 ICON "activities/smoking.ico" +449 ICON "activities/socializing.ico" +450 ICON "activities/sunbathing.ico" +451 ICON "activities/watching_tv.ico" +452 ICON "activities/watching_a_movie.ico" +460 ICON "activities/talking.ico" +461 ICON "activities/in_real_life.ico" +462 ICON "activities/on_the_phone.ico" +463 ICON "activities/on_video_phone.ico" +480 ICON "activities/traveling.ico" +481 ICON "activities/commuting.ico" +482 ICON "activities/cycling.ico" +483 ICON "activities/driving.ico" +484 ICON "activities/in_a_car.ico" +485 ICON "activities/on_a_bus.ico" +486 ICON "activities/on_a_plane.ico" +487 ICON "activities/on_a_train.ico" +488 ICON "activities/on_a_trip.ico" +489 ICON "activities/walking.ico" +500 ICON "activities/working.ico" +501 ICON "activities/coding.ico" +502 ICON "activities/in_a_meeting.ico" +503 ICON "activities/studying.ico" +504 ICON "activities/writing.ico" + + + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + diff --git a/protocols/JabberG/jabber_xstatus/res/activities/at_the_spa.ico b/protocols/JabberG/jabber_xstatus/res/activities/at_the_spa.ico new file mode 100644 index 0000000000..cca4982a86 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/at_the_spa.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/bicycling.ico b/protocols/JabberG/jabber_xstatus/res/activities/bicycling.ico new file mode 100644 index 0000000000..8e684f44ff Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/bicycling.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/brushing_teeth.ico b/protocols/JabberG/jabber_xstatus/res/activities/brushing_teeth.ico new file mode 100644 index 0000000000..ffe652710d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/brushing_teeth.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/buying_groceries.ico b/protocols/JabberG/jabber_xstatus/res/activities/buying_groceries.ico new file mode 100644 index 0000000000..d1502a55be Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/buying_groceries.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/cleaning.ico b/protocols/JabberG/jabber_xstatus/res/activities/cleaning.ico new file mode 100644 index 0000000000..722f98f472 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/cleaning.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/coding.ico b/protocols/JabberG/jabber_xstatus/res/activities/coding.ico new file mode 100644 index 0000000000..63c812d442 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/coding.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/commuting.ico b/protocols/JabberG/jabber_xstatus/res/activities/commuting.ico new file mode 100644 index 0000000000..197a7a7817 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/commuting.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/cooking.ico b/protocols/JabberG/jabber_xstatus/res/activities/cooking.ico new file mode 100644 index 0000000000..e0f5dd91a3 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/cooking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/cycling.ico b/protocols/JabberG/jabber_xstatus/res/activities/cycling.ico new file mode 100644 index 0000000000..0145d83b87 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/cycling.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/dancing.ico b/protocols/JabberG/jabber_xstatus/res/activities/dancing.ico new file mode 100644 index 0000000000..97084e0885 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/dancing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/day_off.ico b/protocols/JabberG/jabber_xstatus/res/activities/day_off.ico new file mode 100644 index 0000000000..3d1ccabae0 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/day_off.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/doing_chores.ico b/protocols/JabberG/jabber_xstatus/res/activities/doing_chores.ico new file mode 100644 index 0000000000..0f619fa093 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/doing_chores.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/doing_maintenance.ico b/protocols/JabberG/jabber_xstatus/res/activities/doing_maintenance.ico new file mode 100644 index 0000000000..4269f50c1f Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/doing_maintenance.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/doing_the_dishes.ico b/protocols/JabberG/jabber_xstatus/res/activities/doing_the_dishes.ico new file mode 100644 index 0000000000..853c7d2694 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/doing_the_dishes.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/doing_the_laundry.ico b/protocols/JabberG/jabber_xstatus/res/activities/doing_the_laundry.ico new file mode 100644 index 0000000000..f24f5da48e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/doing_the_laundry.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/drinking.ico b/protocols/JabberG/jabber_xstatus/res/activities/drinking.ico new file mode 100644 index 0000000000..fe836c7e07 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/drinking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/driving.ico b/protocols/JabberG/jabber_xstatus/res/activities/driving.ico new file mode 100644 index 0000000000..0cb11be5b1 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/driving.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/eating.ico b/protocols/JabberG/jabber_xstatus/res/activities/eating.ico new file mode 100644 index 0000000000..f6fa60ad88 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/eating.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/exercising.ico b/protocols/JabberG/jabber_xstatus/res/activities/exercising.ico new file mode 100644 index 0000000000..7ccc6c7684 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/exercising.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/fishing.ico b/protocols/JabberG/jabber_xstatus/res/activities/fishing.ico new file mode 100644 index 0000000000..c06b871787 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/fishing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/gaming.ico b/protocols/JabberG/jabber_xstatus/res/activities/gaming.ico new file mode 100644 index 0000000000..a65b48d77b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/gaming.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/gardening.ico b/protocols/JabberG/jabber_xstatus/res/activities/gardening.ico new file mode 100644 index 0000000000..f6ee46440d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/gardening.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/getting_a_haircut.ico b/protocols/JabberG/jabber_xstatus/res/activities/getting_a_haircut.ico new file mode 100644 index 0000000000..237a8c5252 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/getting_a_haircut.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/going_out.ico b/protocols/JabberG/jabber_xstatus/res/activities/going_out.ico new file mode 100644 index 0000000000..ca66ddc627 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/going_out.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/grooming.ico b/protocols/JabberG/jabber_xstatus/res/activities/grooming.ico new file mode 100644 index 0000000000..f01b5348cf Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/grooming.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/hanging_out.ico b/protocols/JabberG/jabber_xstatus/res/activities/hanging_out.ico new file mode 100644 index 0000000000..d7f94262f2 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/hanging_out.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_a_beer.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_a_beer.ico new file mode 100644 index 0000000000..20d634f85e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_a_beer.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_a_snack.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_a_snack.ico new file mode 100644 index 0000000000..be74f572fc Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_a_snack.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_appointment.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_appointment.ico new file mode 100644 index 0000000000..5e849b224e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_appointment.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_breakfast.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_breakfast.ico new file mode 100644 index 0000000000..c58ec2ef4e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_breakfast.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_coffee.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_coffee.ico new file mode 100644 index 0000000000..2646fedb5e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_coffee.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_dinner.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_dinner.ico new file mode 100644 index 0000000000..8dbb710ecf Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_dinner.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_lunch.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_lunch.ico new file mode 100644 index 0000000000..4235afbe91 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_lunch.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/having_tea.ico b/protocols/JabberG/jabber_xstatus/res/activities/having_tea.ico new file mode 100644 index 0000000000..cf112ec7f5 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/having_tea.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/hiding.ico b/protocols/JabberG/jabber_xstatus/res/activities/hiding.ico new file mode 100644 index 0000000000..a5cc19e99c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/hiding.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/hiking.ico b/protocols/JabberG/jabber_xstatus/res/activities/hiking.ico new file mode 100644 index 0000000000..48e94d2358 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/hiking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/in_a_car.ico b/protocols/JabberG/jabber_xstatus/res/activities/in_a_car.ico new file mode 100644 index 0000000000..b97e49fcb0 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/in_a_car.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/in_a_meeting.ico b/protocols/JabberG/jabber_xstatus/res/activities/in_a_meeting.ico new file mode 100644 index 0000000000..371da3a59a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/in_a_meeting.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/in_real_life.ico b/protocols/JabberG/jabber_xstatus/res/activities/in_real_life.ico new file mode 100644 index 0000000000..bb9bc0f931 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/in_real_life.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/inactive.ico b/protocols/JabberG/jabber_xstatus/res/activities/inactive.ico new file mode 100644 index 0000000000..74911a62ca Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/inactive.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/jogging.ico b/protocols/JabberG/jabber_xstatus/res/activities/jogging.ico new file mode 100644 index 0000000000..082df08b77 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/jogging.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_a_bus.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_a_bus.ico new file mode 100644 index 0000000000..3f6c315e6a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_a_bus.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_a_plane.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_a_plane.ico new file mode 100644 index 0000000000..3391fb0d20 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_a_plane.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_a_train.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_a_train.ico new file mode 100644 index 0000000000..5a455b7a8b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_a_train.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_a_trip.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_a_trip.ico new file mode 100644 index 0000000000..287b16d0ce Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_a_trip.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_the_phone.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_the_phone.ico new file mode 100644 index 0000000000..111397e7fa Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_the_phone.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_vacation.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_vacation.ico new file mode 100644 index 0000000000..c9b43ef894 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_vacation.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/on_video_phone.ico b/protocols/JabberG/jabber_xstatus/res/activities/on_video_phone.ico new file mode 100644 index 0000000000..45fa03ebfd Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/on_video_phone.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/partying.ico b/protocols/JabberG/jabber_xstatus/res/activities/partying.ico new file mode 100644 index 0000000000..3b02879831 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/partying.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/playing_sports.ico b/protocols/JabberG/jabber_xstatus/res/activities/playing_sports.ico new file mode 100644 index 0000000000..2d5bca3a3c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/playing_sports.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/praying.ico b/protocols/JabberG/jabber_xstatus/res/activities/praying.ico new file mode 100644 index 0000000000..d687a69a40 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/praying.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/reading.ico b/protocols/JabberG/jabber_xstatus/res/activities/reading.ico new file mode 100644 index 0000000000..8f218850b8 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/reading.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/rehearsing.ico b/protocols/JabberG/jabber_xstatus/res/activities/rehearsing.ico new file mode 100644 index 0000000000..f01323b74d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/rehearsing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/relaxing.ico b/protocols/JabberG/jabber_xstatus/res/activities/relaxing.ico new file mode 100644 index 0000000000..d7cbe0abd5 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/relaxing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/running.ico b/protocols/JabberG/jabber_xstatus/res/activities/running.ico new file mode 100644 index 0000000000..bc4c3f151e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/running.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/running_an_errand.ico b/protocols/JabberG/jabber_xstatus/res/activities/running_an_errand.ico new file mode 100644 index 0000000000..c0dd30c95e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/running_an_errand.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/scheduled_holiday.ico b/protocols/JabberG/jabber_xstatus/res/activities/scheduled_holiday.ico new file mode 100644 index 0000000000..774980c16b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/scheduled_holiday.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/shaving.ico b/protocols/JabberG/jabber_xstatus/res/activities/shaving.ico new file mode 100644 index 0000000000..7ed6b0bdc9 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/shaving.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/shopping.ico b/protocols/JabberG/jabber_xstatus/res/activities/shopping.ico new file mode 100644 index 0000000000..71ba041daf Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/shopping.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/skiing.ico b/protocols/JabberG/jabber_xstatus/res/activities/skiing.ico new file mode 100644 index 0000000000..9cd96cf809 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/skiing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/sleeping.ico b/protocols/JabberG/jabber_xstatus/res/activities/sleeping.ico new file mode 100644 index 0000000000..e8fc48edf7 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/sleeping.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/smoking.ico b/protocols/JabberG/jabber_xstatus/res/activities/smoking.ico new file mode 100644 index 0000000000..f3261a83a6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/smoking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/socializing.ico b/protocols/JabberG/jabber_xstatus/res/activities/socializing.ico new file mode 100644 index 0000000000..83297d3084 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/socializing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/studying.ico b/protocols/JabberG/jabber_xstatus/res/activities/studying.ico new file mode 100644 index 0000000000..9dba262974 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/studying.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/sunbathing.ico b/protocols/JabberG/jabber_xstatus/res/activities/sunbathing.ico new file mode 100644 index 0000000000..22c489631c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/sunbathing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/swimming.ico b/protocols/JabberG/jabber_xstatus/res/activities/swimming.ico new file mode 100644 index 0000000000..2b455683d0 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/swimming.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/taking_a_bath.ico b/protocols/JabberG/jabber_xstatus/res/activities/taking_a_bath.ico new file mode 100644 index 0000000000..b93f86c523 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/taking_a_bath.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/taking_a_shower.ico b/protocols/JabberG/jabber_xstatus/res/activities/taking_a_shower.ico new file mode 100644 index 0000000000..c2021e851b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/taking_a_shower.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/talking.ico b/protocols/JabberG/jabber_xstatus/res/activities/talking.ico new file mode 100644 index 0000000000..e747618b86 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/talking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/thinking.ico b/protocols/JabberG/jabber_xstatus/res/activities/thinking.ico new file mode 100644 index 0000000000..e8c8ebed48 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/thinking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/traveling.ico b/protocols/JabberG/jabber_xstatus/res/activities/traveling.ico new file mode 100644 index 0000000000..2dfa197732 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/traveling.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/walking.ico b/protocols/JabberG/jabber_xstatus/res/activities/walking.ico new file mode 100644 index 0000000000..586ed93029 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/walking.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/walking_the_dog.ico b/protocols/JabberG/jabber_xstatus/res/activities/walking_the_dog.ico new file mode 100644 index 0000000000..2be18c864f Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/walking_the_dog.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/watching_a_movie.ico b/protocols/JabberG/jabber_xstatus/res/activities/watching_a_movie.ico new file mode 100644 index 0000000000..c5c8603a4e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/watching_a_movie.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/watching_tv.ico b/protocols/JabberG/jabber_xstatus/res/activities/watching_tv.ico new file mode 100644 index 0000000000..887f949657 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/watching_tv.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/working.ico b/protocols/JabberG/jabber_xstatus/res/activities/working.ico new file mode 100644 index 0000000000..025581a407 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/working.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/working_out.ico b/protocols/JabberG/jabber_xstatus/res/activities/working_out.ico new file mode 100644 index 0000000000..668a5aa7f6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/working_out.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/activities/writing.ico b/protocols/JabberG/jabber_xstatus/res/activities/writing.ico new file mode 100644 index 0000000000..64b74636e1 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/activities/writing.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/afraid.ico b/protocols/JabberG/jabber_xstatus/res/moods/afraid.ico new file mode 100644 index 0000000000..d45fe8ee11 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/afraid.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/amazed.ico b/protocols/JabberG/jabber_xstatus/res/moods/amazed.ico new file mode 100644 index 0000000000..49c2b23e60 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/amazed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/amorous.ico b/protocols/JabberG/jabber_xstatus/res/moods/amorous.ico new file mode 100644 index 0000000000..302d2e0395 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/amorous.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/angry.ico b/protocols/JabberG/jabber_xstatus/res/moods/angry.ico new file mode 100644 index 0000000000..c8947a4d22 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/angry.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/annoyed.ico b/protocols/JabberG/jabber_xstatus/res/moods/annoyed.ico new file mode 100644 index 0000000000..850c323a2d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/annoyed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/anxious.ico b/protocols/JabberG/jabber_xstatus/res/moods/anxious.ico new file mode 100644 index 0000000000..d7db20d85d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/anxious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/aroused.ico b/protocols/JabberG/jabber_xstatus/res/moods/aroused.ico new file mode 100644 index 0000000000..c29feaa8c0 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/aroused.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/ashamed.ico b/protocols/JabberG/jabber_xstatus/res/moods/ashamed.ico new file mode 100644 index 0000000000..6a961f2226 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/ashamed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/bored.ico b/protocols/JabberG/jabber_xstatus/res/moods/bored.ico new file mode 100644 index 0000000000..0bf725ae5e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/bored.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/brave.ico b/protocols/JabberG/jabber_xstatus/res/moods/brave.ico new file mode 100644 index 0000000000..8b6b917bc7 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/brave.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/calm.ico b/protocols/JabberG/jabber_xstatus/res/moods/calm.ico new file mode 100644 index 0000000000..0ed992ba0d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/calm.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/cautious.ico b/protocols/JabberG/jabber_xstatus/res/moods/cautious.ico new file mode 100644 index 0000000000..df89f579f9 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/cautious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/cold.ico b/protocols/JabberG/jabber_xstatus/res/moods/cold.ico new file mode 100644 index 0000000000..b6b7c1e884 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/cold.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/confident.ico b/protocols/JabberG/jabber_xstatus/res/moods/confident.ico new file mode 100644 index 0000000000..bce9395830 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/confident.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/confused.ico b/protocols/JabberG/jabber_xstatus/res/moods/confused.ico new file mode 100644 index 0000000000..41f2e7eb4c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/confused.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/contemplative.ico b/protocols/JabberG/jabber_xstatus/res/moods/contemplative.ico new file mode 100644 index 0000000000..bd005f816f Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/contemplative.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/contented.ico b/protocols/JabberG/jabber_xstatus/res/moods/contented.ico new file mode 100644 index 0000000000..e97d4b9db3 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/contented.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/cranky.ico b/protocols/JabberG/jabber_xstatus/res/moods/cranky.ico new file mode 100644 index 0000000000..ce8468307a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/cranky.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/crazy.ico b/protocols/JabberG/jabber_xstatus/res/moods/crazy.ico new file mode 100644 index 0000000000..b2538674b6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/crazy.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/creative.ico b/protocols/JabberG/jabber_xstatus/res/moods/creative.ico new file mode 100644 index 0000000000..2ac57e40af Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/creative.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/curious.ico b/protocols/JabberG/jabber_xstatus/res/moods/curious.ico new file mode 100644 index 0000000000..6bedb50282 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/curious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/dejected.ico b/protocols/JabberG/jabber_xstatus/res/moods/dejected.ico new file mode 100644 index 0000000000..aea3675a09 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/dejected.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/depressed.ico b/protocols/JabberG/jabber_xstatus/res/moods/depressed.ico new file mode 100644 index 0000000000..074ffd921d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/depressed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/disappointed.ico b/protocols/JabberG/jabber_xstatus/res/moods/disappointed.ico new file mode 100644 index 0000000000..092df4b59c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/disappointed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/disgusted.ico b/protocols/JabberG/jabber_xstatus/res/moods/disgusted.ico new file mode 100644 index 0000000000..d83ce3b7df Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/disgusted.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/dismayed.ico b/protocols/JabberG/jabber_xstatus/res/moods/dismayed.ico new file mode 100644 index 0000000000..abda47285c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/dismayed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/distracted.ico b/protocols/JabberG/jabber_xstatus/res/moods/distracted.ico new file mode 100644 index 0000000000..e9809551fc Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/distracted.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/embarrassed.ico b/protocols/JabberG/jabber_xstatus/res/moods/embarrassed.ico new file mode 100644 index 0000000000..62cdcd4c60 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/embarrassed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/envious.ico b/protocols/JabberG/jabber_xstatus/res/moods/envious.ico new file mode 100644 index 0000000000..29a23da950 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/envious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/excited.ico b/protocols/JabberG/jabber_xstatus/res/moods/excited.ico new file mode 100644 index 0000000000..42a149ef5b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/excited.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/flirtatious.ico b/protocols/JabberG/jabber_xstatus/res/moods/flirtatious.ico new file mode 100644 index 0000000000..af9b114955 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/flirtatious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/frustrated.ico b/protocols/JabberG/jabber_xstatus/res/moods/frustrated.ico new file mode 100644 index 0000000000..790573ad4d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/frustrated.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/grateful.ico b/protocols/JabberG/jabber_xstatus/res/moods/grateful.ico new file mode 100644 index 0000000000..857b34c6c2 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/grateful.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/grieving.ico b/protocols/JabberG/jabber_xstatus/res/moods/grieving.ico new file mode 100644 index 0000000000..5b5774b9af Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/grieving.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/grumpy.ico b/protocols/JabberG/jabber_xstatus/res/moods/grumpy.ico new file mode 100644 index 0000000000..f37395703a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/grumpy.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/guilty.ico b/protocols/JabberG/jabber_xstatus/res/moods/guilty.ico new file mode 100644 index 0000000000..154d32ed1e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/guilty.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/happy.ico b/protocols/JabberG/jabber_xstatus/res/moods/happy.ico new file mode 100644 index 0000000000..f6b97adbd0 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/happy.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/hopeful.ico b/protocols/JabberG/jabber_xstatus/res/moods/hopeful.ico new file mode 100644 index 0000000000..c012b33ee1 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/hopeful.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/hot.ico b/protocols/JabberG/jabber_xstatus/res/moods/hot.ico new file mode 100644 index 0000000000..1fc519a092 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/hot.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/humbled.ico b/protocols/JabberG/jabber_xstatus/res/moods/humbled.ico new file mode 100644 index 0000000000..8df3f7fca4 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/humbled.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/humiliated.ico b/protocols/JabberG/jabber_xstatus/res/moods/humiliated.ico new file mode 100644 index 0000000000..6c2c2ebb92 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/humiliated.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/hungry.ico b/protocols/JabberG/jabber_xstatus/res/moods/hungry.ico new file mode 100644 index 0000000000..9b4f03c9d9 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/hungry.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/hurt.ico b/protocols/JabberG/jabber_xstatus/res/moods/hurt.ico new file mode 100644 index 0000000000..a23f46d955 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/hurt.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/impressed.ico b/protocols/JabberG/jabber_xstatus/res/moods/impressed.ico new file mode 100644 index 0000000000..c2af48ccc4 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/impressed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/in_awe.ico b/protocols/JabberG/jabber_xstatus/res/moods/in_awe.ico new file mode 100644 index 0000000000..d0f4ee317b Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/in_awe.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/in_love.ico b/protocols/JabberG/jabber_xstatus/res/moods/in_love.ico new file mode 100644 index 0000000000..81426556d9 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/in_love.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/indignant.ico b/protocols/JabberG/jabber_xstatus/res/moods/indignant.ico new file mode 100644 index 0000000000..c2a566bbff Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/indignant.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/interested.ico b/protocols/JabberG/jabber_xstatus/res/moods/interested.ico new file mode 100644 index 0000000000..0e728994a7 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/interested.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/intoxicated.ico b/protocols/JabberG/jabber_xstatus/res/moods/intoxicated.ico new file mode 100644 index 0000000000..e7295c7762 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/intoxicated.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/invincible.ico b/protocols/JabberG/jabber_xstatus/res/moods/invincible.ico new file mode 100644 index 0000000000..08f145fc00 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/invincible.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/jealous.ico b/protocols/JabberG/jabber_xstatus/res/moods/jealous.ico new file mode 100644 index 0000000000..c1ac6dd000 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/jealous.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/lonely.ico b/protocols/JabberG/jabber_xstatus/res/moods/lonely.ico new file mode 100644 index 0000000000..8ce7bbbe82 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/lonely.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/lost.ico b/protocols/JabberG/jabber_xstatus/res/moods/lost.ico new file mode 100644 index 0000000000..db23931d39 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/lost.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/lucky.ico b/protocols/JabberG/jabber_xstatus/res/moods/lucky.ico new file mode 100644 index 0000000000..4e2894114d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/lucky.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/mean.ico b/protocols/JabberG/jabber_xstatus/res/moods/mean.ico new file mode 100644 index 0000000000..9a5825cf04 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/mean.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/moody.ico b/protocols/JabberG/jabber_xstatus/res/moods/moody.ico new file mode 100644 index 0000000000..d025001a5a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/moody.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/nervous.ico b/protocols/JabberG/jabber_xstatus/res/moods/nervous.ico new file mode 100644 index 0000000000..a8b42584b6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/nervous.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/neutral.ico b/protocols/JabberG/jabber_xstatus/res/moods/neutral.ico new file mode 100644 index 0000000000..bc3f8ad45c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/neutral.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/offended.ico b/protocols/JabberG/jabber_xstatus/res/moods/offended.ico new file mode 100644 index 0000000000..eb74f4235c Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/offended.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/outraged.ico b/protocols/JabberG/jabber_xstatus/res/moods/outraged.ico new file mode 100644 index 0000000000..1b8e99ee31 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/outraged.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/playful.ico b/protocols/JabberG/jabber_xstatus/res/moods/playful.ico new file mode 100644 index 0000000000..b6f7e55745 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/playful.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/proud.ico b/protocols/JabberG/jabber_xstatus/res/moods/proud.ico new file mode 100644 index 0000000000..7ad6f97064 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/proud.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/relaxed.ico b/protocols/JabberG/jabber_xstatus/res/moods/relaxed.ico new file mode 100644 index 0000000000..bba4906d3e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/relaxed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/relieved.ico b/protocols/JabberG/jabber_xstatus/res/moods/relieved.ico new file mode 100644 index 0000000000..3bbb2ae30d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/relieved.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/remorseful.ico b/protocols/JabberG/jabber_xstatus/res/moods/remorseful.ico new file mode 100644 index 0000000000..095e18e468 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/remorseful.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/restless.ico b/protocols/JabberG/jabber_xstatus/res/moods/restless.ico new file mode 100644 index 0000000000..6e4083a57d Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/restless.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/sad.ico b/protocols/JabberG/jabber_xstatus/res/moods/sad.ico new file mode 100644 index 0000000000..07eae404a4 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/sad.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/sarcastic.ico b/protocols/JabberG/jabber_xstatus/res/moods/sarcastic.ico new file mode 100644 index 0000000000..b23431bfaa Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/sarcastic.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/satisfied.ico b/protocols/JabberG/jabber_xstatus/res/moods/satisfied.ico new file mode 100644 index 0000000000..aecdf590ff Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/satisfied.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/serious.ico b/protocols/JabberG/jabber_xstatus/res/moods/serious.ico new file mode 100644 index 0000000000..b9005bebb2 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/serious.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/shocked.ico b/protocols/JabberG/jabber_xstatus/res/moods/shocked.ico new file mode 100644 index 0000000000..011dea4e60 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/shocked.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/shy.ico b/protocols/JabberG/jabber_xstatus/res/moods/shy.ico new file mode 100644 index 0000000000..a7c02b7916 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/shy.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/sick.ico b/protocols/JabberG/jabber_xstatus/res/moods/sick.ico new file mode 100644 index 0000000000..d3a0338b87 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/sick.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/sleepy.ico b/protocols/JabberG/jabber_xstatus/res/moods/sleepy.ico new file mode 100644 index 0000000000..998164780e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/sleepy.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/spontaneous.ico b/protocols/JabberG/jabber_xstatus/res/moods/spontaneous.ico new file mode 100644 index 0000000000..3670422597 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/spontaneous.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/stressed.ico b/protocols/JabberG/jabber_xstatus/res/moods/stressed.ico new file mode 100644 index 0000000000..94f0472574 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/stressed.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/strong.ico b/protocols/JabberG/jabber_xstatus/res/moods/strong.ico new file mode 100644 index 0000000000..01657488b6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/strong.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/surprised.ico b/protocols/JabberG/jabber_xstatus/res/moods/surprised.ico new file mode 100644 index 0000000000..882cfcd60a Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/surprised.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/thankful.ico b/protocols/JabberG/jabber_xstatus/res/moods/thankful.ico new file mode 100644 index 0000000000..56cfc59961 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/thankful.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/thirsty.ico b/protocols/JabberG/jabber_xstatus/res/moods/thirsty.ico new file mode 100644 index 0000000000..d678569bd6 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/thirsty.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/tired.ico b/protocols/JabberG/jabber_xstatus/res/moods/tired.ico new file mode 100644 index 0000000000..90292c7e0e Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/tired.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/undefined.ico b/protocols/JabberG/jabber_xstatus/res/moods/undefined.ico new file mode 100644 index 0000000000..078db99f8f Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/undefined.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/weak.ico b/protocols/JabberG/jabber_xstatus/res/moods/weak.ico new file mode 100644 index 0000000000..408b769b93 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/weak.ico differ diff --git a/protocols/JabberG/jabber_xstatus/res/moods/worried.ico b/protocols/JabberG/jabber_xstatus/res/moods/worried.ico new file mode 100644 index 0000000000..45942e7c43 Binary files /dev/null and b/protocols/JabberG/jabber_xstatus/res/moods/worried.ico differ diff --git a/protocols/JabberG/jabber_zstream.cpp b/protocols/JabberG/jabber_zstream.cpp deleted file mode 100644 index 11829bf401..0000000000 --- a/protocols/JabberG/jabber_zstream.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -XEP-0138 (Stream Compression) implementation - -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007 Kostya Chukavin, Taras Zackrepa - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -BOOL ThreadData::zlibInit( void ) -{ - proto->Log( "Zlib init..." ); - zStreamIn.zalloc = Z_NULL; - zStreamIn.zfree = Z_NULL; - zStreamIn.opaque = Z_NULL; - zStreamIn.next_in = Z_NULL; - zStreamIn.avail_in = 0; - - zStreamOut.zalloc = Z_NULL; - zStreamOut.zfree = Z_NULL; - zStreamOut.opaque = Z_NULL; - - if ( deflateInit( &zStreamOut, Z_BEST_COMPRESSION) != Z_OK ) return FALSE; - if ( inflateInit( &zStreamIn ) != Z_OK ) return FALSE; - - zRecvReady = true; - return TRUE; -} - -void ThreadData::zlibUninit( void ) -{ - deflateEnd( &zStreamOut ); - inflateEnd( &zStreamIn ); -} - -int ThreadData::zlibSend( char* data, int datalen ) -{ - char send_data[ ZLIB_CHUNK_SIZE ]; - int bytesOut = 0; - - zStreamOut.avail_in = datalen; - zStreamOut.next_in = ( unsigned char* )data; - - do { - zStreamOut.avail_out = ZLIB_CHUNK_SIZE; - zStreamOut.next_out = ( unsigned char* )send_data; - - switch ( deflate( &zStreamOut, Z_SYNC_FLUSH )) { - case Z_OK: proto->Log( "Deflate: Z_OK" ); break; - case Z_BUF_ERROR: proto->Log( "Deflate: Z_BUF_ERROR" ); break; - case Z_DATA_ERROR: proto->Log( "Deflate: Z_DATA_ERROR" ); break; - case Z_MEM_ERROR: proto->Log( "Deflate: Z_MEM_ERROR" ); break; - } - - int len, send_datalen = ZLIB_CHUNK_SIZE - zStreamOut.avail_out; - - if (( len = sendws( send_data, send_datalen, MSG_NODUMP )) == SOCKET_ERROR || len != send_datalen ) { - proto->Log( "Netlib_Send() failed, error=%d", WSAGetLastError()); - return FALSE; - } - - bytesOut += len; - } - while ( zStreamOut.avail_out == 0 ); - - if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) - proto->Log( "(ZLIB) Data sent\n%s\n===OUT: %d(%d) bytes", data, datalen, bytesOut ); - - return TRUE; -} - -int ThreadData::zlibRecv( char* data, long datalen ) -{ - if ( zRecvReady ) { -retry: - zRecvDatalen = recvws( zRecvData, ZLIB_CHUNK_SIZE, MSG_NODUMP ); - if ( zRecvDatalen == SOCKET_ERROR ) { - proto->Log( "Netlib_Recv() failed, error=%d", WSAGetLastError()); - return SOCKET_ERROR; - } - if ( zRecvDatalen == 0 ) - return 0; - - zStreamIn.avail_in = zRecvDatalen; - zStreamIn.next_in = ( Bytef* )zRecvData; - } - - zStreamIn.avail_out = datalen; - zStreamIn.next_out = ( BYTE* )data; - - switch ( inflate( &zStreamIn, Z_NO_FLUSH )) { - case Z_OK: proto->Log( "Inflate: Z_OK" ); break; - case Z_BUF_ERROR: proto->Log( "Inflate: Z_BUF_ERROR" ); break; - case Z_DATA_ERROR: proto->Log( "Inflate: Z_DATA_ERROR" ); break; - case Z_MEM_ERROR: proto->Log( "Inflate: Z_MEM_ERROR" ); break; - } - - int len = datalen - zStreamIn.avail_out; - if ( DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", TRUE ) == TRUE ) { - char* szLogBuffer = ( char* )alloca( len+32 ); - memcpy( szLogBuffer, data, len ); - szLogBuffer[ len ]='\0'; - proto->Log( "(ZLIB) Data received\n%s\n===IN: %d(%d) bytes", szLogBuffer, len, zRecvDatalen ); - } - - if ( len == 0 ) - goto retry; - - zRecvReady = ( zStreamIn.avail_out != 0 ); - return len; -} diff --git a/protocols/JabberG/jabberg-translation.txt b/protocols/JabberG/jabberg-translation.txt deleted file mode 100644 index 3e58b30b19..0000000000 --- a/protocols/JabberG/jabberg-translation.txt +++ /dev/null @@ -1,835 +0,0 @@ -; Common strings that belong to many files -;[OK] -;[Account] -;[Add] -;[Add to roster] -;[Are you sure?] -;[Authentication failed for] -;[Away] -;[Bookmarks] -;[Cancel] -;[Change Password] -;[Change nickname in] -;[Change password] -;[Close] -;[Conferences] -;[Connecting...] -;[Custom1] -;[Download] -;[Edit] -;[Free for chat] -;[General] -;[Grant authorization] -;[Home] -;[JID] -;[JID List] -;[Jabber] -;[Jabber Agent Registration] -;[Jabber Authentication] -;[Jabber Error] -;[Jabber Resource] -;[Loading...] -;[Login/logout] -;[Member Information] -;[No message] -;[Node] -;[None] -;[Notes] -;[Offline] -;[Online] -;[Photo] -;[Privacy Lists] -;[Reason to ban] -;[Register] -;[Registered transports] -;[Registration successful] -;[Remove] -;[Request authorization] -;[Resolve nicks] -;[Resource priority] -;[Revoke authorization] -;[Service Discovery] -;[Set activity...] -;[Set mood...] -;[Subscription] -;[Transports] -;[Upload] -;[View as list] -;[View as tree] -;[Work] -;[XML Console] -;[from] - -; ../../protocols/JabberG/jabber.cpp -;[Jabber Link Protocol] -;[Jabber protocol plugin for Miranda IM (%s)] - -; ../../protocols/JabberG/jabber.h -;[/me slaps %s around a bit with a large trout] -;[I'm happy Miranda IM user. Get it at http://miranda-im.org/.] - -; ../../protocols/JabberG/jabber.rc -;[&Accept] -;[&Invite] -;[<room jid>\nIncoming groupchat invitation.] -;[<room jid>\nSend groupchat invitation.] -;[Account type:] -;[Activate (Space)] -;[Add list... (Ins)] -;[Add rule (Ins)] -;[Address1:] -;[Address2:] -;[Advanced Mode] -;[Affiliation:] -;[Allow file sending through bytestream proxy server:] -;[Allow file sending through direct peer-to-peer connection] -;[Alternate nick:] -;[Apply Filter] -;[Authorization Request] -;[Authorize] -;[Auto-join (Automatically join Bookmarks must be enabled in Miranda options)] -;[Automatically delete contacts not in my roster] -;[BBS] -;[Back] -;[Bookmark Details] -;[Bookmark Name:] -;[Bookmark Type] -;[Bots Challenge Test] -;[Browse] -;[Browse/Join chat room...] -;[Cellular] -;[Change %s Message] -;[Chat options] -;[City:] -;[Closing in %d] -;[Command] -;[Company:] -;[Complete] -;[Conference] -;[Conference server:] -;[Confirm New Password:] -;[Country:] -;[Create or Join Groupchat] -;[Current Password:] -;[Custom messages] -;[Data form test] -;[Date of birth:] -;[Delete] -;[Deny] -;[Department:] -;[Description:] -;[Dialog] -;[Domain/Server:] -;[E-mail:] -;[Edit Note] -;[Edit rule... (F2)] -;[Email address:] -;[Enter the name of the new list:] -;[Expert] -;[Export to file] -;[Favourites] -;[Fax] -;[File Transfer] -;[First name:] -;[Full name:] -;[Gender:] -;[Go] -;[Groupchat Invitation] -;[HTTP Authorization\nAccept or reject incoming request] -;[Hint:] -;[Homepage:] -;[Host:] -;[ISDN] -;[If you wish to confirm this request, please click authorize. Otherwise, press deny to reject it.] -;[If:] -;[Import from file] -;[Incoming presence] -;[Instruction:] -;[Internet] -;[Invitation reason:] -;[Invite Users] -;[JID:] -;[Jabber Account Information:] -;[Jabber Account Registration] -;[Jabber Agents] -;[Jabber Bookmarks] -;[Jabber Form] -;[Jabber Multi-User Conference] -;[Jabber Multi-User Conference\nCreate or join existing conference room.] -;[Jabber Notebook] -;[Jabber Password] -;[Jabber notebook\nStore notes on server and access them from anywhere.] -;[Jabber server:] -;[Jabber vCard: Add Email Address] -;[Jabber vCard: Add Phone Number] -;[Keep connection alive] -;[Language for human-readable resources:] -;[Last name:] -;[List of public servers] -;[List4] -;[Lists:] -;[Load] -;[Log off] -;[Log on] -;[Login server:] -;[Manually specify connection host] -;[Member Information\n<user id>] -;[Messages] -;[Middle:] -;[Miscellaneous] -;[Modem] -;[Move rule down (Alt+Down)] -;[Move rule up (Alt+Up)] -;[New Password:] -;[New privacy list name:] -;[Next] -;[Nick name:] -;[Nickname:] -;[Node:] -;[Occupation:] -;[Other JID:] -;[Outgoing presence] -;[PCS] -;[Pager] -;[Password:] -;[Phone number:] -;[Phone:] -;[Port:] -;[Priority:] -;[Privacy Lists\nFlexible way to configure visibility and more.] -;[Privacy rule] -;[Progress1] -;[Queries] -;[Quit:] -;[Recently visited chatrooms:] -;[Refresh] -;[Register account now] -;[Register new user] -;[Register with a new service...] -;[Register...] -;[Register/Search Jabber Agents] -;[Registered Jabber Transports] -;[Remove list (Del)] -;[Remove rule (Del)] -;[Request method is:] -;[Request was sent from JID:] -;[Reset Filter] -;[Resource:] -;[Role:] -;[Room JID/ URL:] -;[Room:] -;[Roster Editor] -;[Roster editor\nView and modify your server-side contact list.] -;[Rules:] -;[Save] -;[Save password] -;[Save password for this session] -;[Search service] -;[Search...] -;[Server side bookmarks\nStore conference rooms and web links on server.] -;[Set affiliation] -;[Set as default (Ctrl+Space)] -;[Set role] -;[Simple Mode] -;[Slap:] -;[Someone (maybe you) has requested the following file:] -;[Specify external address:] -;[Spin1] -;[State:] -;[Status message:] -;[Submit] -;[Tags:] -;[Text/Messaging] -;[The transaction identifier is:] -;[Then:] -;[Title:] -;[Transport] -;[Try to uncheck all checkmarks above if you're experiencing troubles with sending files. But it can cause problems with transfer of large files.] -;[Type:] -;[URL] -;[Unregister] -;[Use Domain Login] -;[Use SSL] -;[Use TLS] -;[Use custom connection host and port:] -;[Use hostname as resource] -;[User directory:] -;[User:] -;[Username:] -;[Video] -;[Voice] -;[X400] -;[YYYY-MM-DD] -;[You are invited to conference room by] -;[ZIP:] -;[following stanza types:] -;[with following reason:] - -; ../../protocols/JabberG/jabber_adhoc.cpp -;[Done] -;[Error %s %s] -;[Execute] -;[In progress. Please Wait...] -;[Jabber Ad-Hoc commands at] -;[Not supported] -;[Requesting command list. Please wait...] -;[Select Command] -;[Sending Ad-Hoc command to] - -; ../../protocols/JabberG/jabber_agent.cpp -;[Please wait...] - -; ../../protocols/JabberG/jabber_bookmarks.cpp -;[Address (JID or URL)] -;[Bookmark Name] -;[Links] -;[Nickname] - -; ../../protocols/JabberG/jabber_byte.cpp -;[Bytestream Proxy not available] - -; ../../protocols/JabberG/jabber_captcha.cpp -;[Enter the text you see] - -; ../../protocols/JabberG/jabber_chat.cpp -;[&Add to roster] -;[&Admin] -;[&Admin list] -;[&Affiliations] -;[&Configure...] -;[&Copy to clipboard] -;[&Destroy room] -;[&Invite a user] -;[&Kick] -;[&Leave chat session] -;[&Member] -;[&Member list] -;[&Moderator] -;[&Moderator list] -;[&None] -;[&Owner] -;[&Owner list] -;[&Participant] -;[&Participant list] -;[&Roles] -;[&Room options] -;[&Send presence] -;[&Slap] -;[&User details] -;[&Visitor] -;[Add to &bookmarks] -;[Admin] -;[Affiliation of %s was changed to '%s'.] -;[Change &nickname] -;[Copy &nickname] -;[Copy in-room JID] -;[Copy real &JID] -;[Copy room &JID] -;[Copy room topic] -;[DND] -;[Invite %s to %s] -;[Invite to room] -;[Lin&ks] -;[Member] -;[Member &info] -;[Member Info:] -;[Moderator] -;[NA] -;[Outcast] -;[Outcast (&ban)] -;[Outcast list (&ban)] -;[Owner] -;[Participant] -;[Real &JID: %s] -;[Real JID not available] -;[Reason to destroy] -;[Reason to kick] -;[Role of %s was changed to '%s'.] -;[Room configuration was changed.] -;[Send groupchat invitation.] -;[Set &affiliation] -;[Set &role] -;[Set topic for] -;[User %s changed status to %s] -;[User %s changed status to %s with message: %s] -;[User %s in now banned.] -;[User &details] -;[View/change &topic] -;[Visitor] -;[because room is now members-only] -;[not on roster] -;[user banned] - -; ../../protocols/JabberG/jabber_console.cpp -;[Can't send data while you are offline.] -;[Outgoing XML parsing error] - -; ../../protocols/JabberG/jabber_disco.cpp -;[Browse all favorites] -;[Browse chatrooms] -;[Browse local transports] -;[Navigate] -;[Node hierarchy] -;[Remove all favorites] -;[request timeout.] - -; ../../protocols/JabberG/jabber_disco.h -;[Category] -;[Identities] -;[Info request error] -;[Items request error] -;[Supported features] -;[Type] -;[category] -;[type] - -; ../../protocols/JabberG/jabber_groupchat.cpp -;[<no nick>] -;[Bookmarks...] -;[Failed to retrieve room list from server.] -;[Incoming groupchat invitation.] -;[No rooms available on server.] -;[Please specify groupchat directory first.] -;[Please wait for room list to download.] -;[Room list request timed out.] -;[has set the subject to:] - -; ../../protocols/JabberG/jabber_icolib.cpp -;[%s] -;[Accounts] -;[Active privacy list] -;[AdHoc Command] -;[Agents list] -;[Allow Messages] -;[Allow Presences (in)] -;[Allow Presences (out)] -;[Allow Queries] -;[Apply filter] -;[Browse node] -;[Convert to room] -;[Default privacy list] -;[Deny Messages] -;[Deny Presences (in)] -;[Deny Presences (out)] -;[Deny Queries] -;[Dialogs] -;[Dialogs/Discovery] -;[Dialogs/Privacy] -;[Discovery failed] -;[Discovery in progress] -;[Discovery succeeded] -;[Generic privacy list] -;[Move down] -;[Move up] -;[Multi-User Conference] -;[Navigate home] -;[OpenID Request] -;[Personal vCard] -;[Protocols] -;[RSS service] -;[Refresh node] -;[Reset filter] -;[Send note] -;[Server] -;[Storage service] -;[Weather service] - -; ../../protocols/JabberG/jabber_iq_handlers.cpp -;[Http authentication request received] - -; ../../protocols/JabberG/jabber_iqid.cpp -;[Jabber Bookmarks Error] -;[Password cannot be changed.] -;[Password is successfully changed. Don't forget to update your password in the Jabber protocol option.] - -; ../../protocols/JabberG/jabber_iqid_muc.cpp -;[%s, %d items (%s)] -;[Admin List] -;[Ban List] -;[Member List] -;[Moderator List] -;[Owner List] -;[Removing] -;[Voice List] - -; ../../protocols/JabberG/jabber_menu.cpp -;[&Convert to Chat Room] -;[&Convert to Contact] -;[Add to Bookmarks] -;[Browse Chatrooms] -;[Commands] -;[Convert] -;[Create/Join groupchat] -;[Highest priority (server's choice)] -;[Last Active] -;[Last active] -;[Local Server Transports] -;[No activity yet, use server's choice] -;[Options...] -;[Registered Transports] -;[Resource priority [%d]] -;[Roster editor] -;[Send Note] -;[Send Presence] -;[Server's Choice] -;[Services...] -;[Status Message] - -; ../../protocols/JabberG/jabber_misc.cpp -;[Both] -;[CHAT plugin is required for conferences. Install it before chatting] -;[Errors] -;[From] -;[To] - -; ../../protocols/JabberG/jabber_notes.cpp -;[All tags] -;[From: %s] -;[Incoming note] -;[Incoming note from %s] -;[Notes are not saved, close this window without uploading data to server?] -;[Send note to %s] - -; ../../protocols/JabberG/jabber_opt.cpp -;[Accept HTTP Authentication requests (XEP-0070)] -;[Accept only in band incoming filetransfers (don't disclose own IP)] -;[Account removal warning] -;[Advanced] -;[Affiliation changes] -;[Allow servers to request version (XEP-0092)] -;[Autoaccept multiuser chat invitations] -;[Automatically accept authorization requests] -;[Automatically add contact when accept authorization] -;[Automatically join bookmarks on login] -;[Automatically join conferences on login] -;[Automatically save received notes] -;[Ban notifications] -;[Confirm password] -;[Disable SASL authentication (for old servers)] -;[Disable frame] -;[Do not show multiuser chat invitations] -;[Downloading...] -;[Enable XMPP link processing (requires Association Manager)] -;[Enable avatars] -;[Enable remote controlling (from another resource of same JID only)] -;[Enable stream compression (if possible)] -;[Enable user activity receiving] -;[Enable user moods receiving] -;[Enable user tunes receiving] -;[Facebook Chat] -;[Filter history messages] -;[Fix incorrect timestamps in incoming messages] -;[Google Talk!] -;[Group] -;[Hide conference windows at startup] -;[Jabber Protocol Option] -;[Keep contacts assigned to local groups (ignore roster group)] -;[LiveJournal Talk] -;[Log chat state changes] -;[Log events] -;[Log presence errors] -;[Log presence subscription state changes] -;[Messaging] -;[Network] -;[Nick Name] -;[Other] -;[Passwords do not match.] -;[Public XMPP Network] -;[Receive notes] -;[Role changes] -;[Room configuration changes] -;[S.ms] -;[Secure XMPP Network] -;[Secure XMPP Network (old style)] -;[Security] -;[Send messages slower, but with full acknowledgement] -;[Server options] -;[Show information about operating system in version replies] -;[Show transport agents on contact list] -;[Some changes will take effect the next time you connect to the Jabber network.] -;[Status changes] -;[These changes will take effect the next time you connect to the Jabber network.] -;[This operation will kill your account, roster and all another information stored at the server. Are you ready to do that?] -;[Uploading...] -;[Vkontakte] -;[XML for MS Excel (UTF-8 encoded)] -;[You can change your password only when you are online] -;[You must be online] - -; ../../protocols/JabberG/jabber_password.cpp -;[Current password is incorrect.] -;[New password does not match.] -;[Set New Password for] - -; ../../protocols/JabberG/jabber_privacy.cpp -;[ (act., def.)] -;[ (active)] -;[ (default)] -;[ (nickname: ] -;[ and ] -;[** Default **] -;[** Subsription: both **] -;[** Subsription: from **] -;[** Subsription: none **] -;[** Subsription: to **] -;[<none>] -;[Activate] -;[Active privacy list successfully declined] -;[Add JID] -;[Add list...] -;[Add rule] -;[Advanced mode] -;[Default privacy list successfully declined] -;[Delete rule] -;[Edit rule] -;[Else ] -;[Error occurred while applying changes] -;[Error occurred while setting active list] -;[Error occurred while setting default list] -;[First, save the list] -;[If group is '] -;[If jabber id is '] -;[If subscription is '] -;[List Editor...] -;[Move rule down] -;[Move rule up] -;[Please save list before activating] -;[Please save list before you make it the default list] -;[Privacy list %s set as active] -;[Privacy list %s set as default] -;[Privacy lists are not saved, discard any changes and exit?] -;[Privacy lists successfully saved] -;[Ready.] -;[Remove list] -;[Set default] -;[Simple mode] -;[Unable to save list because you are currently offline.] -;[Warning: privacy lists were changed on server.] -;[all.] -;[allow ] -;[deny ] -;[incoming presences] -;[messages] -;[outgoing presences] -;[queries] -;[then ] - -; ../../protocols/JabberG/jabber_proto.cpp -;[No compatible file transfer machanism exist] -;[Protocol is offline or no jid] - -; ../../protocols/JabberG/jabber_rc.cpp -;[%d message(s) forwarded] -;[%d message(s) to be forwarded] -;[Automatically Accept File Transfers] -;[Change Status] -;[Change global status] -;[Choose the groupchats you want to leave] -;[Choose the status and status message] -;[Command completed successfully] -;[Confirmation needed] -;[Disable remote controlling (check twice what you are doing)] -;[Do Not Disturb] -;[Error %d occured during workstation lock] -;[Error occured during processing command] -;[Extended Away (N/A)] -;[Forward options] -;[Forward unread messages] -;[Invisible] -;[Leave groupchats] -;[Lock workstation] -;[Mark messages as read] -;[Play sounds] -;[Please confirm Miranda IM shutdown] -;[Priority] -;[Quit Miranda IM] -;[Set Options] -;[Set options] -;[Set status] -;[Set the desired options] -;[Status] -;[Status message] -;[There is no groupchats to leave] -;[There is no messages to forward] -;[Workstation successfully locked] - -; ../../protocols/JabberG/jabber_search.cpp -;[Error %s %s\r\nPlease select other server] -;[Error %s %s\r\nTry to specify more detailed] -;[Error Unknown reply recieved\r\nPlease select other server] -;[Please wait...\r\nConnecting search server...] -;[Search error] -;[Select/type search service URL above and press <Go>] -;[You have to be connected to server] - -; ../../protocols/JabberG/jabber_svc.cpp -;[approved subscription request] -;[closed chat session] -;[declined subscription] -;[sent error presence] -;[sent subscription request] -;[sent unknown presence type] - -; ../../protocols/JabberG/jabber_thread.cpp -;[Enter password for] -;[Error: Cannot connect to the server] -;[Error: Connection lost] -;[Error: Not enough memory] -;[Message redirected from: %s\r\n%s] -;[Requesting registration instruction...] -;[Sending registration information...] - -; ../../protocols/JabberG/jabber_userinfo.cpp -;[<No photo>] -;[<Photo not available while offline>] -;[<no information available>] -;[<not specified>] -;[Activity] -;[Alpha build] -;[Client capabilities] -;[Copy] -;[Copy only this value] -;[Debug build] -;[Idle since] -;[Last active resource] -;[Last logoff time] -;[Logoff message] -;[Message] -;[Miranda IM core version] -;[Mood] -;[No] -;[Operating system] -;[Operating system version] -;[Please switch online to see more details.] -;[Resource] -;[Software] -;[Software information] -;[Software version] -;[System] -;[Tune] -;[Unicode build] -;[Unknown format] -;[Uptime] -;[Version] -;[Yes] -;[both] -;[format] -;[none] -;[to] -;[unknown] - -; ../../protocols/JabberG/jabber_util.cpp -;[Advanced Status] -;[Error] -;[Unknown error message] - -; ../../protocols/JabberG/jabber_vcard.cpp -;[Contacts] -;[Female] -;[Jabber vCard] -;[Jabber vCard: Edit Email Address] -;[Jabber vCard: Edit Phone Number] -;[Male] -;[Note] -;[Only JPG, GIF, and BMP image files smaller than 40 KB are supported.] - -; ../../protocols/JabberG/jabber_ws.cpp -;[%s connection] - -; ../../protocols/JabberG/jabber_xstatus.cpp -;[Activity: %s] -;[Afraid] -;[Amazed] -;[Amorous] -;[Angry] -;[Annoyed] -;[Anxious] -;[Aroused] -;[Ashamed] -;[Bored] -;[Brave] -;[Calm] -;[Cautious] -;[Cold] -;[Confident] -;[Confused] -;[Contemplative] -;[Contented] -;[Cranky] -;[Crazy] -;[Creative] -;[Curious] -;[Dejected] -;[Depressed] -;[Disappointed] -;[Disgusted] -;[Dismayed] -;[Distracted] -;[Embarrassed] -;[Envious] -;[Excited] -;[Flirtatious] -;[Frustrated] -;[Grateful] -;[Grieving] -;[Grumpy] -;[Guilty] -;[Happy] -;[Hopeful] -;[Hot] -;[Humbled] -;[Humiliated] -;[Hungry] -;[Hurt] -;[Impressed] -;[In awe] -;[In love] -;[Indignant] -;[Interested] -;[Intoxicated] -;[Invincible] -;[Jealous] -;[Listening To] -;[Lonely] -;[Lost] -;[Lucky] -;[Mean] -;[Mood: %s] -;[Moody] -;[Nervous] -;[Neutral] -;[Offended] -;[Outraged] -;[Playful] -;[Proud] -;[Relaxed] -;[Relieved] -;[Remorseful] -;[Restless] -;[Sad] -;[Sarcastic] -;[Satisfied] -;[Serious] -;[Set Activity] -;[Set Mood] -;[Shocked] -;[Shy] -;[Sick] -;[Sleepy] -;[Spontaneous] -;[Stressed] -;[Strong] -;[Surprised] -;[Thankful] -;[Thirsty] -;[Tired] -;[Undefined] -;[Weak] -;[Worried] - -; ../../protocols/JabberG/ui_utils.cpp -;[Set filter...] - -; ../../protocols/JabberG/version.rc -;[Reset log] -;[Send] diff --git a/protocols/JabberG/proto_jabber/Proto_Jabber.rc b/protocols/JabberG/proto_jabber/Proto_Jabber.rc deleted file mode 100644 index b3188f3d4a..0000000000 Binary files a/protocols/JabberG/proto_jabber/Proto_Jabber.rc and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj b/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj index 1051ada6bb..59d93a3827 100644 --- a/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj +++ b/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj @@ -119,10 +119,10 @@ </ResourceCompile> </ItemDefinitionGroup> <ItemGroup> - <ClInclude Include="resource.h" /> + <ClInclude Include="src\resource.h" /> </ItemGroup> <ItemGroup> - <ResourceCompile Include="Proto_Jabber.rc" /> + <ResourceCompile Include="res\Proto_Jabber.rc" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj.filters b/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj.filters index f78bc8dede..ae91eacccf 100644 --- a/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj.filters +++ b/protocols/JabberG/proto_jabber/Proto_Jabber.vcxproj.filters @@ -11,12 +11,12 @@ </Filter> </ItemGroup> <ItemGroup> - <ClInclude Include="resource.h"> + <ClInclude Include="src\resource.h"> <Filter>Header Files</Filter> </ClInclude> </ItemGroup> <ItemGroup> - <ResourceCompile Include="Proto_Jabber.rc"> + <ResourceCompile Include="res\Proto_Jabber.rc"> <Filter>Resource Files</Filter> </ResourceCompile> </ItemGroup> diff --git a/protocols/JabberG/proto_jabber/icos/Away.ico b/protocols/JabberG/proto_jabber/icos/Away.ico deleted file mode 100644 index d9efcb6be9..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/Away.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/DND.ico b/protocols/JabberG/proto_jabber/icos/DND.ico deleted file mode 100644 index 5a96752278..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/DND.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/FFC.ico b/protocols/JabberG/proto_jabber/icos/FFC.ico deleted file mode 100644 index 7a7ca70b2e..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/FFC.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/Invisible.ico b/protocols/JabberG/proto_jabber/icos/Invisible.ico deleted file mode 100644 index 4636cc20f3..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/Invisible.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/NA.ico b/protocols/JabberG/proto_jabber/icos/NA.ico deleted file mode 100644 index f3c08d0ecf..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/NA.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/Offline.ico b/protocols/JabberG/proto_jabber/icos/Offline.ico deleted file mode 100644 index ba6d39a5aa..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/Offline.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/icos/Online.ico b/protocols/JabberG/proto_jabber/icos/Online.ico deleted file mode 100644 index 9e18c3dd74..0000000000 Binary files a/protocols/JabberG/proto_jabber/icos/Online.ico and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/res/Away.ico b/protocols/JabberG/proto_jabber/res/Away.ico new file mode 100644 index 0000000000..d9efcb6be9 Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/Away.ico differ diff --git a/protocols/JabberG/proto_jabber/res/DND.ico b/protocols/JabberG/proto_jabber/res/DND.ico new file mode 100644 index 0000000000..5a96752278 Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/DND.ico differ diff --git a/protocols/JabberG/proto_jabber/res/FFC.ico b/protocols/JabberG/proto_jabber/res/FFC.ico new file mode 100644 index 0000000000..7a7ca70b2e Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/FFC.ico differ diff --git a/protocols/JabberG/proto_jabber/res/Invisible.ico b/protocols/JabberG/proto_jabber/res/Invisible.ico new file mode 100644 index 0000000000..4636cc20f3 Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/Invisible.ico differ diff --git a/protocols/JabberG/proto_jabber/res/NA.ico b/protocols/JabberG/proto_jabber/res/NA.ico new file mode 100644 index 0000000000..f3c08d0ecf Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/NA.ico differ diff --git a/protocols/JabberG/proto_jabber/res/Offline.ico b/protocols/JabberG/proto_jabber/res/Offline.ico new file mode 100644 index 0000000000..ba6d39a5aa Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/Offline.ico differ diff --git a/protocols/JabberG/proto_jabber/res/Online.ico b/protocols/JabberG/proto_jabber/res/Online.ico new file mode 100644 index 0000000000..9e18c3dd74 Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/Online.ico differ diff --git a/protocols/JabberG/proto_jabber/res/Proto_Jabber.rc b/protocols/JabberG/proto_jabber/res/Proto_Jabber.rc new file mode 100644 index 0000000000..03cfefcd8b Binary files /dev/null and b/protocols/JabberG/proto_jabber/res/Proto_Jabber.rc differ diff --git a/protocols/JabberG/proto_jabber/resource.h b/protocols/JabberG/proto_jabber/resource.h deleted file mode 100644 index d7b66a17e2..0000000000 Binary files a/protocols/JabberG/proto_jabber/resource.h and /dev/null differ diff --git a/protocols/JabberG/proto_jabber/src/resource.h b/protocols/JabberG/proto_jabber/src/resource.h new file mode 100644 index 0000000000..d7b66a17e2 Binary files /dev/null and b/protocols/JabberG/proto_jabber/src/resource.h differ diff --git a/protocols/JabberG/res/add2roster.ico b/protocols/JabberG/res/add2roster.ico new file mode 100644 index 0000000000..0b0d1462c3 Binary files /dev/null and b/protocols/JabberG/res/add2roster.ico differ diff --git a/protocols/JabberG/res/addcontact.ico b/protocols/JabberG/res/addcontact.ico new file mode 100644 index 0000000000..596593efb1 Binary files /dev/null and b/protocols/JabberG/res/addcontact.ico differ diff --git a/protocols/JabberG/res/arrow_down.ico b/protocols/JabberG/res/arrow_down.ico new file mode 100644 index 0000000000..777cbfe161 Binary files /dev/null and b/protocols/JabberG/res/arrow_down.ico differ diff --git a/protocols/JabberG/res/arrow_up.ico b/protocols/JabberG/res/arrow_up.ico new file mode 100644 index 0000000000..543644cbbc Binary files /dev/null and b/protocols/JabberG/res/arrow_up.ico differ diff --git a/protocols/JabberG/res/auth_revoke.ico b/protocols/JabberG/res/auth_revoke.ico new file mode 100644 index 0000000000..42dda06ce4 Binary files /dev/null and b/protocols/JabberG/res/auth_revoke.ico differ diff --git a/protocols/JabberG/res/bookmarks.ico b/protocols/JabberG/res/bookmarks.ico new file mode 100644 index 0000000000..e66ee868f9 Binary files /dev/null and b/protocols/JabberG/res/bookmarks.ico differ diff --git a/protocols/JabberG/res/command.ico b/protocols/JabberG/res/command.ico new file mode 100644 index 0000000000..1138c0b882 Binary files /dev/null and b/protocols/JabberG/res/command.ico differ diff --git a/protocols/JabberG/res/console.ico b/protocols/JabberG/res/console.ico new file mode 100644 index 0000000000..ec2ea2159f Binary files /dev/null and b/protocols/JabberG/res/console.ico differ diff --git a/protocols/JabberG/res/delete.ico b/protocols/JabberG/res/delete.ico new file mode 100644 index 0000000000..e4b674dcd5 Binary files /dev/null and b/protocols/JabberG/res/delete.ico differ diff --git a/protocols/JabberG/res/disco_fail.ico b/protocols/JabberG/res/disco_fail.ico new file mode 100644 index 0000000000..39e5a1b800 Binary files /dev/null and b/protocols/JabberG/res/disco_fail.ico differ diff --git a/protocols/JabberG/res/disco_in_progress.ico b/protocols/JabberG/res/disco_in_progress.ico new file mode 100644 index 0000000000..c1c3e243c5 Binary files /dev/null and b/protocols/JabberG/res/disco_in_progress.ico differ diff --git a/protocols/JabberG/res/disco_ok.ico b/protocols/JabberG/res/disco_ok.ico new file mode 100644 index 0000000000..d117a9ab46 Binary files /dev/null and b/protocols/JabberG/res/disco_ok.ico differ diff --git a/protocols/JabberG/res/filter.ico b/protocols/JabberG/res/filter.ico new file mode 100644 index 0000000000..f4d5347cea Binary files /dev/null and b/protocols/JabberG/res/filter.ico differ diff --git a/protocols/JabberG/res/go.ico b/protocols/JabberG/res/go.ico new file mode 100644 index 0000000000..22abe8e7cc Binary files /dev/null and b/protocols/JabberG/res/go.ico differ diff --git a/protocols/JabberG/res/grant.ico b/protocols/JabberG/res/grant.ico new file mode 100644 index 0000000000..8e18fe3754 Binary files /dev/null and b/protocols/JabberG/res/grant.ico differ diff --git a/protocols/JabberG/res/group.ico b/protocols/JabberG/res/group.ico new file mode 100644 index 0000000000..3e4cfcc606 Binary files /dev/null and b/protocols/JabberG/res/group.ico differ diff --git a/protocols/JabberG/res/home.ico b/protocols/JabberG/res/home.ico new file mode 100644 index 0000000000..2328a8ef16 Binary files /dev/null and b/protocols/JabberG/res/home.ico differ diff --git a/protocols/JabberG/res/jabber.ico b/protocols/JabberG/res/jabber.ico new file mode 100644 index 0000000000..61644cbfe9 Binary files /dev/null and b/protocols/JabberG/res/jabber.ico differ diff --git a/protocols/JabberG/res/jabber.rc b/protocols/JabberG/res/jabber.rc new file mode 100644 index 0000000000..7e88d2cd4a --- /dev/null +++ b/protocols/JabberG/res/jabber.rc @@ -0,0 +1,974 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "richedit.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NOTE_EDIT DIALOGEX 0, 0, 279, 241 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Edit Note" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_TXT_TITLE,7,7,266,12,ES_AUTOHSCROLL + EDITTEXT IDC_TXT_TEXT,7,24,266,150,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + LTEXT "Tags:",IDC_ST_TAGS,7,179,266,8 + EDITTEXT IDC_TXT_TAGS,7,190,266,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,168,207,50,14 + PUSHBUTTON "Cancel",IDCANCEL,223,207,50,14 +END + +IDD_ACCMGRUI DIALOGEX 0, 0, 189, 144 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,0,0,53,12,SS_CENTERIMAGE + COMBOBOX IDC_CB_TYPE,61,0,124,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "User:",IDC_STATIC,0,16,53,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_USERNAME,61,16,124,12,ES_AUTOHSCROLL + LTEXT "Domain/Server:",IDC_STATIC,0,31,60,12,SS_CENTERIMAGE + COMBOBOX IDC_EDIT_LOGIN_SERVER,61,31,124,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Password:",IDC_STATIC,0,46,53,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_PASSWORD,61,46,124,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,61,124,10 + LTEXT "Resource:",IDC_RESOURCE_T,0,83,53,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_RESOURCE,61,83,124,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,107,99,78,13 + CONTROL "Use custom connection host and port:",IDC_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,115,189,10 + EDITTEXT IDC_HOST,41,125,106,12,ES_AUTOHSCROLL | WS_DISABLED + CTEXT ":",IDC_STATIC,148,124,8,12,SS_CENTERIMAGE + EDITTEXT IDC_PORT,156,125,30,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,72,119,10 +END + +IDD_SEARCHUSER DIALOGEX 0, 0, 109, 148 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Go",IDC_GO,93,11,16,13,WS_DISABLED + LTEXT "Search service",IDC_STATIC,0,1,97,8 + SCROLLBAR IDC_VSCROLL,97,49,12,99,SBS_BOTTOMALIGN | SBS_VERT | NOT WS_VISIBLE + EDITTEXT IDC_INSTRUCTIONS,0,27,105,22,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "",IDC_FRAME,0,49,97,99,NOT WS_GROUP + COMBOBOX IDC_SERVER,0,11,92,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP +END + +IDD_OPT_JABBER3 DIALOGEX 0, 0, 424, 288 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Roster Editor" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Roster editor\nView and modify your server-side contact list.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + CONTROL "",IDC_ROSTER,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,38,413,225 + PUSHBUTTON "Download",IDC_DOWNLOAD,5,268,60,15,WS_DISABLED + PUSHBUTTON "Upload",IDC_UPLOAD,70,268,60,15,WS_DISABLED + PUSHBUTTON "Import from file",IDC_IMPORT,347,268,71,15 + PUSHBUTTON "Export to file",IDC_EXPORT,272,268,71,15 +END + +IDD_OPT_JABBER DIALOGEX 0, 0, 304, 228 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Jabber",IDC_SIMPLE,4,3,295,114 + LTEXT "Username:",IDC_STATIC,12,18,50,8 + EDITTEXT IDC_EDIT_USERNAME,66,16,86,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,12,32,45,8 + EDITTEXT IDC_EDIT_PASSWORD,66,30,86,12,ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "Change password",IDC_BUTTON_CHANGE_PASSWORD,156,30,78,13 + CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,66,45,89,10 + LTEXT "Priority:",IDC_PRIORITY_LABEL,12,59,41,8 + EDITTEXT IDC_PRIORITY,66,57,85,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_PRIORITY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,151,57,12,12 + LTEXT "Resource:",IDC_RESOURCE_T,12,74,45,8 + COMBOBOX IDC_COMBO_RESOURCE,66,71,86,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + CONTROL "Use hostname as resource",IDC_HOSTNAME_AS_RESOURCE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,73,138,9 + LTEXT "Domain/Server:",IDC_STATIC,12,87,52,8 + COMBOBOX IDC_EDIT_LOGIN_SERVER,66,85,86,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER, + "Hyperlink",WS_TABSTOP,161,86,79,11 + LTEXT "Port:",IDC_STATIC,12,101,45,8 + EDITTEXT IDC_PORT,66,99,26,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Use SSL",IDC_USE_SSL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,100,82,10 + CONTROL "Use TLS",IDC_USE_TLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,189,100,97,10 + PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,156,16,78,13 + PUSHBUTTON "Unregister",IDC_UNREGISTER,235,16,56,13 + GROUPBOX "Expert",IDC_STATIC,4,120,295,105 + CONTROL "Manually specify connection host",IDC_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,134,223,10 + LTEXT "Host:",IDC_STATIC,26,147,30,8 + EDITTEXT IDC_HOST,57,145,90,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Port:",IDC_STATIC,156,148,27,8 + EDITTEXT IDC_HOSTPORT,186,145,31,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,158,221,10 + CONTROL "Automatically delete contacts not in my roster",IDC_ROSTER_SYNC, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,221,10 + LTEXT "User directory:",IDC_JUD_LABEL,11,188,170,8 + EDITTEXT IDC_JUD,188,185,103,12,ES_AUTOHSCROLL + LTEXT "Language for human-readable resources:",IDC_MSGLANG_LABEL,11,203,170,8 + COMBOBOX IDC_MSGLANG,188,201,103,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,45,137,9 +END + +IDD_OPT_JABBER2 DIALOGEX 0, 0, 304, 228 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "File Transfer",IDC_STATIC,4,3,295,71 + CONTROL "Allow file sending through direct peer-to-peer connection",IDC_DIRECT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,14,284,10 + CONTROL "Specify external address:",IDC_DIRECT_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,27,166,10 + EDITTEXT IDC_DIRECT_ADDR,200,25,94,12,ES_AUTOHSCROLL + CONTROL "Allow file sending through bytestream proxy server:",IDC_PROXY_MANUAL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,41,183,10 + EDITTEXT IDC_PROXY_ADDR,200,39,94,12,ES_AUTOHSCROLL | WS_GROUP + GROUPBOX "Miscellaneous",IDC_STATIC,4,76,295,149 + RTEXT "Hint:",IDC_STATIC,12,56,27,8 + LTEXT "Try to uncheck all checkmarks above if you're experiencing troubles with sending files. But it can cause problems with transfer of large files.",IDC_STATIC,46,53,245,16 + CONTROL "",IDC_OPTTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | WS_BORDER | WS_HSCROLL | WS_TABSTOP,9,88,285,132 +END + +IDD_INFO_JABBER DIALOGEX 0, 0, 221, 152 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_TV_INFO,"SysTreeView32",TVS_HASBUTTONS | TVS_DISABLEDRAGDROP | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,5,5,211,141 +END + +IDD_DATAFORM_PAGE DIALOGEX 0, 0, 250, 239 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT | WS_EX_STATICEDGE +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN +END + +IDD_OPT_REGISTER DIALOGEX 0, 0, 173, 69 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "Jabber Account Registration" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "",IDC_REG_STATUS,4,7,164,26 + CONTROL "Progress1",IDC_PROGRESS_REG,"msctls_progress32",NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,18,37,130,7 + DEFPUSHBUTTON "OK",IDOK,55,50,50,14 +END + +IDD_AGENTS DIALOGEX 0, 0, 294, 254 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Jabber Agents" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Register/Search Jabber Agents",IDC_STATIC,7,7,280,115 + LTEXT "Jabber server:",IDC_STATIC,13,20,47,8 + EDITTEXT IDC_AGENT_SERVER,65,19,136,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "Browse",IDC_AGENT_BROWSE,209,19,46,13,WS_DISABLED + CONTROL "List1",IDC_AGENT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,36,267,60 + PUSHBUTTON "Register...",IDC_AGENT_REGISTER,13,100,50,14,WS_DISABLED + PUSHBUTTON "Browse/Join chat room...",IDC_JOIN,69,100,93,14,WS_DISABLED + PUSHBUTTON "Search...",IDC_AGENT_SEARCH,171,100,50,14,NOT WS_VISIBLE | WS_DISABLED + GROUPBOX "Registered Jabber Transports",IDC_STATIC,7,128,280,99 + CONTROL "List1",IDC_AGENT_TRANSPORT,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,142,267,60 + PUSHBUTTON "Log on",IDC_AGENT_LOGON,13,206,50,14,WS_DISABLED + PUSHBUTTON "Log off",IDC_AGENT_LOGOFF,69,206,50,14,WS_DISABLED + PUSHBUTTON "Unregister",IDC_AGENT_UNREGISTER,125,206,50,14,WS_DISABLED + PUSHBUTTON "Register with a new service...",IDC_MANUAL_REGISTER,7,233,106,14 + PUSHBUTTON "Close",IDCLOSE,237,233,50,14 + PUSHBUTTON "Command",IDC_COMMANDS1,230,100,50,14,WS_DISABLED + PUSHBUTTON "Command",IDC_COMMANDS2,231,206,50,14,WS_DISABLED +END + +IDD_FORM DIALOGEX 0, 0, 258, 224 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Jabber Form" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25 + LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP + EDITTEXT IDC_INSTRUCTION,17,17,233,1,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1 + CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1 + LTEXT "",IDC_FRAME,0,27,250,169,NOT WS_GROUP + EDITTEXT IDC_FRAME_TEXT,18,101,220,33,ES_CENTER | ES_MULTILINE | ES_READONLY | NOT WS_BORDER + SCROLLBAR IDC_VSCROLL,246,28,11,167,SBS_VERT + DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14 + DEFPUSHBUTTON "Next",IDC_NEXT,50,203,40,14,NOT WS_VISIBLE | WS_DISABLED + DEFPUSHBUTTON "Back",IDC_PREV,6,203,42,14,NOT WS_VISIBLE | WS_DISABLED + DEFPUSHBUTTON "Complete",IDC_COMPLETE,150,203,46,14,NOT WS_VISIBLE | WS_DISABLED +END + +IDD_PASSWORD DIALOGEX 0, 0, 286, 63 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Jabber Password" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_JID,7,7,272,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT IDC_PASSWORD,7,22,272,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Save password for this session",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,42,157,14 + DEFPUSHBUTTON "OK",IDOK,175,42,50,14 + PUSHBUTTON "Cancel",IDCANCEL,229,42,50,14 +END + +IDD_DATAFORM_TEST DIALOGEX 0, 0, 153, 148 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Data form test" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Custom1",IDC_DATAFORM,"JabberDataFormControl",WS_TABSTOP,7,6,139,135 +END + +IDD_VCARD_HOME DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Address1:",IDC_STATIC,5,7,59,8 + EDITTEXT IDC_ADDRESS1,67,5,148,12,ES_AUTOHSCROLL + LTEXT "Address2:",IDC_STATIC,5,21,59,8 + EDITTEXT IDC_ADDRESS2,67,19,148,12,ES_AUTOHSCROLL + LTEXT "City:",IDC_STATIC,5,35,59,8 + EDITTEXT IDC_CITY,67,33,75,12,ES_AUTOHSCROLL + LTEXT "State:",IDC_STATIC,5,49,59,8 + EDITTEXT IDC_STATE,67,47,75,12,ES_AUTOHSCROLL + LTEXT "ZIP:",IDC_STATIC,5,63,59,8 + EDITTEXT IDC_ZIP,67,61,58,12,ES_AUTOHSCROLL + LTEXT "Country:",IDC_STATIC,5,77,59,8 + COMBOBOX IDC_COUNTRY,67,75,91,172,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +IDD_VCARD_PERSONAL DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Full name:",IDC_STATIC,5,7,51,8 + EDITTEXT IDC_FULLNAME,58,5,159,12,ES_AUTOHSCROLL + LTEXT "Nick name:",IDC_STATIC,5,20,51,8 + EDITTEXT IDC_NICKNAME,58,19,82,12,ES_AUTOHSCROLL + LTEXT "First name:",IDC_STATIC,5,34,51,8 + EDITTEXT IDC_FIRSTNAME,58,33,82,12,ES_AUTOHSCROLL + RTEXT "Middle:",IDC_STATIC,142,35,35,8,0,WS_EX_RIGHT + EDITTEXT IDC_MIDDLE,178,33,39,12,ES_AUTOHSCROLL + LTEXT "Last name:",IDC_STATIC,5,48,51,8 + EDITTEXT IDC_LASTNAME,58,47,82,12,ES_AUTOHSCROLL + LTEXT "Date of birth:",IDC_STATIC,5,63,51,8 + EDITTEXT IDC_BIRTH,58,61,62,12,ES_AUTOHSCROLL + LTEXT "YYYY-MM-DD",IDC_STATIC,124,63,90,8 + LTEXT "Gender:",IDC_STATIC,5,77,51,8 + COMBOBOX IDC_GENDER,58,75,62,52,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Occupation:",IDC_STATIC,5,90,51,8 + EDITTEXT IDC_OCCUPATION,58,89,159,12,ES_AUTOHSCROLL + LTEXT "Homepage:",IDC_STATIC,6,104,51,8 + EDITTEXT IDC_HOMEPAGE,58,102,159,12,ES_AUTOHSCROLL +END + +IDD_VCARD_WORK DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Company:",IDC_STATIC,6,7,60,8 + EDITTEXT IDC_COMPANY,67,5,148,12,ES_AUTOHSCROLL + LTEXT "Department:",IDC_STATIC,6,20,60,8 + EDITTEXT IDC_DEPARTMENT,67,19,148,12,ES_AUTOHSCROLL + LTEXT "Title:",IDC_STATIC,6,33,60,8 + EDITTEXT IDC_TITLE,67,32,75,12,ES_AUTOHSCROLL + LTEXT "Address1:",IDC_STATIC,5,47,60,8 + EDITTEXT IDC_ADDRESS1,67,45,148,12,ES_AUTOHSCROLL + LTEXT "Address2:",IDC_STATIC,5,61,60,8 + EDITTEXT IDC_ADDRESS2,67,59,148,12,ES_AUTOHSCROLL + LTEXT "City:",IDC_STATIC,5,75,60,8 + EDITTEXT IDC_CITY,67,73,75,12,ES_AUTOHSCROLL + LTEXT "State:",IDC_STATIC,5,88,60,8 + EDITTEXT IDC_STATE,67,87,75,12,ES_AUTOHSCROLL + LTEXT "ZIP:",IDC_STATIC,5,103,60,8 + EDITTEXT IDC_ZIP,67,101,58,12,ES_AUTOHSCROLL + LTEXT "Country:",IDC_STATIC,5,116,60,8 + COMBOBOX IDC_COUNTRY,67,115,91,172,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +IDD_VCARD_CONTACT DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "E-mail:",IDC_STATIC,5,5,212,8 + CONTROL "List1",IDC_EMAILS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,14,212,50 + LTEXT "Phone:",IDC_STATIC,5,68,212,8 + CONTROL "List1",IDC_PHONES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,77,212,50 +END + +IDD_VCARD_ADDEMAIL DIALOGEX 0, 0, 186, 89 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Jabber vCard: Add Email Address" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Email address:",IDC_STATIC,7,8,52,8 + EDITTEXT IDC_EMAIL,61,7,118,12,ES_AUTOHSCROLL + CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,23,110,10 + CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,33,111,10 + CONTROL "Internet",IDC_INTERNET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,43,110,10 + CONTROL "X400",IDC_X400,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,53,110,10 + DEFPUSHBUTTON "OK",IDOK,40,68,50,14 + PUSHBUTTON "Cancel",IDCANCEL,96,68,50,14 +END + +IDD_VCARD_ADDPHONE DIALOGEX 0, 0, 186, 110 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Jabber vCard: Add Phone Number" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Phone number:",IDC_STATIC,7,8,49,8 + EDITTEXT IDC_PHONE,61,7,118,12,ES_AUTOHSCROLL + CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,23,67,10 + CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,33,67,10 + CONTROL "Voice",IDC_VOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,43,67,10 + CONTROL "Fax",IDC_FAX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,53,67,10 + CONTROL "Pager",IDC_PAGER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,63,67,10 + CONTROL "Text/Messaging",IDC_MSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,73,67,10 + CONTROL "Cellular",IDC_CELL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,23,71,10 + CONTROL "Video",IDC_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,33,71,10 + CONTROL "BBS",IDC_BBS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,43,71,10 + CONTROL "Modem",IDC_MODEM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,53,71,10 + CONTROL "ISDN",IDC_ISDN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,63,71,10 + CONTROL "PCS",IDC_PCS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,73,71,10 + DEFPUSHBUTTON "OK",IDOK,40,88,50,14 + PUSHBUTTON "Cancel",IDCANCEL,96,88,50,14 +END + +IDD_VCARD_PHOTO DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Load",IDC_LOAD,"MButtonClass",WS_TABSTOP,200,5,17,14 + CONTROL "Save",IDC_SAVE,"MButtonClass",WS_TABSTOP,200,5,17,14 + CTEXT "",IDC_CANVAS,5,5,189,122,SS_CENTERIMAGE + CONTROL "Delete",IDC_DELETE,"MButtonClass",WS_DISABLED | WS_TABSTOP,200,23,17,14 +END + +IDD_VCARD_NOTE DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Description:",IDC_STATIC,5,5,212,8 + EDITTEXT IDC_DESC,5,15,212,112,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL +END + +IDD_CHANGEPASSWORD DIALOGEX 0, 0, 181, 79 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Change Password" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Current Password:",IDC_STATIC,7,8,81,8 + EDITTEXT IDC_OLDPASSWD,95,7,79,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "New Password:",IDC_STATIC,7,22,81,8 + EDITTEXT IDC_NEWPASSWD,95,21,79,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Confirm New Password:",IDC_STATIC,7,36,81,8 + EDITTEXT IDC_NEWPASSWD2,95,35,79,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,38,58,50,14 + PUSHBUTTON "Cancel",IDCANCEL,92,58,50,14 +END + +IDD_GROUPCHAT DIALOGEX 0, 0, 306, 208 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Jabber Multi-User Conference" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Conference server:",-1,5,8,70,8 + COMBOBOX IDC_SERVER,80,7,168,79,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Browse",IDC_BROWSE,253,7,46,13 + CONTROL "List1",IDC_ROOM,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,5,24,294,160 + PUSHBUTTON "Close",IDCLOSE,249,189,50,14 +END + +IDD_GROUPCHAT_JOIN DIALOGEX 0, 0, 258, 211 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Create or Join Groupchat" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Jabber Multi-User Conference\nCreate or join existing conference room.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + LTEXT "Conference server:",IDC_STATIC,7,38,63,12,SS_CENTERIMAGE,WS_EX_RIGHT + COMBOBOX IDC_SERVER,75,38,176,100,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Room:",IDC_STATIC,7,56,63,12,SS_CENTERIMAGE,WS_EX_RIGHT + COMBOBOX IDC_ROOM,75,56,176,158,CBS_DROPDOWN | CBS_OWNERDRAWVARIABLE | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + LTEXT "Nick name:",IDC_STATIC,7,73,63,12,SS_CENTERIMAGE,WS_EX_RIGHT + EDITTEXT IDC_NICK,75,73,176,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,7,90,63,12,SS_CENTERIMAGE,WS_EX_RIGHT + EDITTEXT IDC_PASSWORD,75,90,176,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Recently visited chatrooms:",IDC_TXT_RECENT,7,107,244,8 + CONTROL "",IDC_RECENT1,"Hyperlink",WS_TABSTOP,27,120,224,11 + CONTROL "",IDC_RECENT2,"Hyperlink",WS_TABSTOP,27,131,224,11 + CONTROL "",IDC_RECENT3,"Hyperlink",WS_TABSTOP,27,142,224,11 + CONTROL "",IDC_RECENT4,"Hyperlink",WS_TABSTOP,27,153,224,11 + CONTROL "",IDC_RECENT5,"Hyperlink",WS_TABSTOP,27,164,224,11 + CONTROL "Bookmarks",IDC_BOOKMARKS,"MButtonClass",WS_TABSTOP,7,179,16,14 + DEFPUSHBUTTON "OK",IDOK,145,179,50,14 + PUSHBUTTON "Cancel",IDCANCEL,201,179,50,14 +END + +IDD_JIDLIST DIALOGEX 0, 0, 208, 165 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT +CAPTION "JID List" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "List4",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,198,136 + EDITTEXT IDC_FILTER,5,147,161,12,ES_AUTOHSCROLL + CONTROL "Apply Filter",IDC_BTN_FILTERAPPLY,"MButtonClass",WS_TABSTOP,171,146,16,14 + CONTROL "Reset Filter",IDC_BTN_FILTERRESET,"MButtonClass",WS_TABSTOP,187,146,16,14 +END + +IDD_AGENT_MANUAL_REGISTER DIALOGEX 0, 0, 186, 45 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Jabber Agent Registration" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "JID:",IDC_STATIC,5,9,17,8 + EDITTEXT IDC_JID,29,7,150,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "Register",IDOK,75,24,50,14,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END + +IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 215, 275 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Invite Users" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "<room jid>\nSend groupchat invitation.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,215,25 + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,7,40,201,116,WS_EX_CLIENTEDGE + LTEXT "Other JID:",IDC_STATIC,7,162,46,8 + EDITTEXT IDC_NEWJID,59,160,127,12,ES_AUTOHSCROLL + CONTROL "Add",IDC_ADDJID,"MButtonClass",WS_TABSTOP,192,159,16,14 + CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,178,214,1 + LTEXT "Invitation reason:",IDC_STATIC,7,184,201,8 + EDITTEXT IDC_REASON,17,195,191,44,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL + DEFPUSHBUTTON "&Invite",IDC_INVITE,104,243,50,14 + PUSHBUTTON "Cancel",IDCANCEL,158,243,50,14 +END + +IDD_GROUPCHAT_INVITE_ACCEPT DIALOGEX 0, 0, 216, 174 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Groupchat Invitation" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "<room jid>\nIncoming groupchat invitation.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,216,25 + LTEXT "You are invited to conference room by",IDC_STATIC,7,40,202,8 + EDITTEXT IDC_FROM,17,51,192,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "with following reason:",IDC_STATIC,7,69,202,8 + EDITTEXT IDC_REASON,17,80,192,34,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL + CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,119,215,1 + LTEXT "Nickname:",IDC_STATIC,7,125,52,12,SS_CENTERIMAGE + EDITTEXT IDC_NICK,62,125,147,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "&Accept",IDC_ACCEPT,104,142,50,14 + PUSHBUTTON "Cancel",IDCANCEL,159,142,50,14 +END + +IDD_BOOKMARKS DIALOGEX 0, 0, 295, 261 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Jabber Bookmarks" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Server side bookmarks\nStore conference rooms and web links on server.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + CONTROL "List1",IDC_BM_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,5,38,285,187 + CONTROL "Remove",IDC_REMOVE,"MButtonClass",WS_TABSTOP,37,229,16,14 + CONTROL "Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,21,229,16,14 + CONTROL "Add",IDC_ADD,"MButtonClass",WS_TABSTOP,5,229,16,14 + PUSHBUTTON "Close",IDCANCEL,240,229,50,14 +END + +IDD_BOOKMARK_ADD DIALOGEX 0, 0, 221, 143 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Bookmark Details" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Bookmark Type",IDC_BOOKMARK_TYPE,6,4,208,52 + CONTROL "Conference",IDC_ROOM_RADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,15,14,59,10 + CONTROL "Transport",IDC_AGENT_RADIO,"Button",BS_AUTORADIOBUTTON,79,14,66,10 + CONTROL "URL",IDC_URL_RADIO,"Button",BS_AUTORADIOBUTTON,157,14,48,10 + CONTROL "Auto-join (Automatically join Bookmarks must be enabled in Miranda options)",IDC_CHECK_BM_AUTOJOIN, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,15,28,191,24 + LTEXT "Room JID/ URL:",IDC_STATIC,7,62,65,8 + EDITTEXT IDC_ROOM_JID,76,62,138,12,ES_AUTOHSCROLL + LTEXT "Bookmark Name:",IDC_STATIC,7,77,65,8 + EDITTEXT IDC_NAME,76,75,138,12,ES_AUTOHSCROLL + LTEXT "Nick name:",IDC_STATIC,7,91,65,8 + EDITTEXT IDC_NICK,76,90,138,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,7,105,65,8 + EDITTEXT IDC_PASSWORD,76,104,138,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,51,122,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,122,50,14 +END + +IDD_PRIVACY_LISTS DIALOGEX 0, 0, 424, 287 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Privacy Lists" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Privacy Lists\nFlexible way to configure visibility and more.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + LTEXT "Lists:",IDC_TXT_LISTS,5,38,121,14,SS_CENTERIMAGE + LISTBOX IDC_LB_LISTS,5,55,122,196,LBS_SORT | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Rules:",IDC_TXT_RULES,135,38,58,14,SS_CENTERIMAGE + LISTBOX IDC_PL_RULES_LIST,135,55,283,196,LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,135,55,283,160,WS_EX_CLIENTEDGE + CONTROL "Simple Mode",IDC_BTN_SIMPLE,"MButtonClass",WS_TABSTOP,386,38,16,14 + CONTROL "Advanced Mode",IDC_BTN_ADVANCED,"MButtonClass",WS_TABSTOP,402,38,16,14 + RTEXT "Other JID:",IDC_TXT_OTHERJID,135,237,49,14,SS_CENTERIMAGE + EDITTEXT IDC_NEWJID,187,238,210,12,ES_AUTOHSCROLL + CONTROL "",IDC_ADDJID,"MButtonClass",WS_TABSTOP,402,237,16,14 + CONTROL "Add list... (Ins)",IDC_ADD_LIST,"MButtonClass",WS_TABSTOP,5,255,16,14 + CONTROL "Activate (Space)",IDC_ACTIVATE,"MButtonClass",WS_TABSTOP,26,255,16,14 + CONTROL "Set as default (Ctrl+Space)",IDC_SET_DEFAULT, + "MButtonClass",WS_TABSTOP,42,255,16,14 + CONTROL "Remove list (Del)",IDC_REMOVE_LIST,"MButtonClass",WS_TABSTOP,63,255,16,14 + CONTROL "Add rule (Ins)",IDC_ADD_RULE,"MButtonClass",WS_TABSTOP,135,255,16,14 + CONTROL "Edit rule... (F2)",IDC_EDIT_RULE,"MButtonClass",WS_TABSTOP,156,255,16,14 + CONTROL "Move rule up (Alt+Up)",IDC_UP_RULE,"MButtonClass",WS_TABSTOP,177,255,16,14 + CONTROL "Move rule down (Alt+Down)",IDC_DOWN_RULE,"MButtonClass",WS_TABSTOP,193,255,16,14 + CONTROL "Remove rule (Del)",IDC_REMOVE_RULE,"MButtonClass",WS_TABSTOP,214,255,16,14 + PUSHBUTTON "Save",IDC_APPLY,313,255,50,14 + PUSHBUTTON "Close",IDCANCEL,368,255,50,14 + CONTROL "",IDC_CANVAS,"Static",SS_OWNERDRAW,135,218,283,14,WS_EX_TRANSPARENT +END + +IDD_PRIVACY_RULE DIALOGEX 0, 0, 261, 90 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Privacy rule" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + RTEXT "If:",IDC_STATIC,5,5,35,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_TYPE,43,5,76,179,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_VALUE,124,5,132,142,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_VALUES,124,5,132,142,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Then:",IDC_STATIC,5,21,35,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_ACTION,43,21,76,206,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "following stanza types:",IDC_STATIC,124,21,132,12,SS_CENTERIMAGE + ICON "",IDC_ICO_MESSAGE,43,38,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE + CONTROL "Messages",IDC_CHECK_MESSAGES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,38,89,14 + ICON "",IDC_ICO_QUERY,43,52,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE + CONTROL "Queries",IDC_CHECK_QUERIES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,52,89,14 + ICON "",IDC_ICO_PRESENCEIN,150,38,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE + CONTROL "Incoming presence",IDC_CHECK_PRESENCE_IN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,38,90,14 + ICON "",IDC_ICO_PRESENCEOUT,150,52,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE + CONTROL "Outgoing presence",IDC_CHECK_PRESENCE_OUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,52,90,14 + PUSHBUTTON "OK",IDOK,152,71,50,14 + PUSHBUTTON "Cancel",IDCANCEL,206,71,50,14 +END + +IDD_PRIVACY_ADD_LIST DIALOGEX 0, 0, 142, 54 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "New privacy list name:" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Enter the name of the new list:",IDC_STATIC,5,7,135,8 + EDITTEXT IDC_EDIT_NAME,5,18,130,14,ES_AUTOHSCROLL + PUSHBUTTON "OK",IDOK,31,35,50,14 + PUSHBUTTON "Cancel",IDCANCEL,85,35,50,14 +END + +IDD_SERVICE_DISCOVERY DIALOGEX 0, 0, 353, 221 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Service Discovery" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "View as tree",IDC_BTN_VIEWTREE,"MButtonClass",WS_TABSTOP,5,5,16,14 + CONTROL "View as list",IDC_BTN_VIEWLIST,"MButtonClass",WS_TABSTOP,21,5,16,14 + CONTROL "Home",IDC_BTN_NAVHOME,"MButtonClass",WS_TABSTOP,42,5,16,14 + CONTROL "Favourites",IDC_BTN_FAVORITE,"MButtonClass",WS_TABSTOP,58,5,16,14 + CONTROL "Refresh",IDC_BTN_REFRESH,"MButtonClass",WS_TABSTOP,74,5,16,14 + LTEXT "JID:",IDC_STATIC,95,5,14,14,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_JID,112,6,99,70,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Node:",IDC_TXT_NODELABEL,216,5,24,14,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_NODE,243,6,84,70,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Go",IDC_BUTTON_BROWSE,"MButtonClass",WS_TABSTOP,332,5,16,14 + CONTROL "",IDC_TREE_DISCO,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,5,21,343,180 +END + +IDD_SETMOODMSG DIALOGEX 0, 0, 187, 72 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Change %s Message" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_MSG_MOOD,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + DEFPUSHBUTTON "Closing in %d",IDOK,61,53,65,14 +END + +IDD_MODERNOPT DIALOGEX 0, 0, 260, 164 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + RTEXT "Account type:",IDC_STATIC,9,15,51,12,SS_CENTERIMAGE + RTEXT "Username:",IDC_STATIC,9,32,51,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_USERNAME,65,32,194,12,ES_AUTOHSCROLL + RTEXT "Password:",IDC_STATIC,9,49,51,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_PASSWORD,65,49,194,12,ES_PASSWORD | ES_AUTOHSCROLL + RTEXT "Login server:",IDC_STATIC,9,66,51,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_LOGIN_SERVER,65,66,194,12,ES_AUTOHSCROLL + RTEXT "Port:",IDC_STATIC,163,83,30,12,SS_CENTERIMAGE + EDITTEXT IDC_PORT,216,83,43,12,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "Register account now",IDC_BUTTON_REGISTER,65,83,92,13 + COMBOBOX IDC_COMBO_ACCTYPE,65,15,194,39,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER, + "Hyperlink",WS_TABSTOP,10,129,249,11 + COMBOBOX IDC_COMBO_RESOURCE,65,101,194,52,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + RTEXT "Resource:",IDC_STATIC,10,101,51,12,SS_CENTERIMAGE + LTEXT "Jabber Account Information:",IDC_TITLE1,0,0,255,8 +END + +IDD_GROUPCHAT_INFO DIALOGEX 0, 0, 183, 144 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Member Information" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Member Information\n<user id>",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,183,25 + ICON IDI_JABBER,IDC_ICO_STATUS,5,38,16,17,SS_CENTERIMAGE | SS_REALSIZEIMAGE + EDITTEXT IDC_TXT_NICK,26,38,152,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_TXT_JID,36,47,142,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + RTEXT "Role:",IDC_STATIC,5,59,36,12,SS_CENTERIMAGE + COMBOBOX IDC_TXT_ROLE,45,59,112,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Set role",IDC_BTN_ROLE,"MButtonClass",WS_TABSTOP,162,58,16,14 + RTEXT "Affiliation:",IDC_STATIC,5,73,36,12,SS_CENTERIMAGE + COMBOBOX IDC_TXT_AFFILIATION,45,73,112,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Set affiliation",IDC_BTN_AFFILIATION,"MButtonClass",WS_TABSTOP,162,72,16,14 + LTEXT "Status message:",IDC_STATIC,5,89,173,8 + EDITTEXT IDC_TXT_STATUS,26,99,152,40,ES_MULTILINE | ES_READONLY | WS_VSCROLL +END + +IDD_OPT_JABBER4 DIALOGEX 0, 0, 304, 228 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Chat options",IDC_STATIC,4,3,295,175 + CONTROL "",IDC_OPTTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | WS_BORDER | WS_HSCROLL | WS_TABSTOP,9,15,285,140 + LTEXT "Alternate nick:",IDC_STATIC,11,161,174,8 + EDITTEXT IDC_TXT_ALTNICK,190,159,104,14,ES_AUTOHSCROLL + GROUPBOX "Custom messages",IDC_STATIC,4,180,295,45 + EDITTEXT IDC_TXT_QUIT,45,192,249,12,ES_AUTOHSCROLL + EDITTEXT IDC_TXT_SLAP,45,208,249,12,ES_AUTOHSCROLL + RTEXT "Quit:",IDC_STATIC,9,192,31,12,SS_CENTERIMAGE + RTEXT "Slap:",IDC_STATIC,9,208,31,12,SS_CENTERIMAGE +END + +IDD_HTTP_AUTH DIALOGEX 0, 0, 217, 188 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authorization Request" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "HTTP Authorization\nAccept or reject incoming request",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + LTEXT "Someone (maybe you) has requested the following file:",IDC_STATIC,7,38,203,8 + EDITTEXT IDC_TXT_URL,27,49,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Request was sent from JID:",IDC_STATIC,7,61,203,8 + EDITTEXT IDC_TXT_FROM,27,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "The transaction identifier is:",IDC_STATIC,7,84,203,8 + EDITTEXT IDC_TXT_ID,27,95,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Request method is:",IDC_STATIC,7,107,203,8 + EDITTEXT IDC_TXT_METHOD,27,118,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "If you wish to confirm this request, please click authorize. Otherwise, press deny to reject it.",IDC_STATIC,7,130,203,16 + PUSHBUTTON "Authorize",IDOK,104,156,50,14 + PUSHBUTTON "Deny",IDCANCEL,160,156,50,14 +END + +IDD_GROUPCHAT_INFO_TABS DIALOGEX 0, 0, 265, 242 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Data form test" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_TABS,"SysTabControl32",TCS_MULTILINE,7,6,251,203 +END + +IDD_GROUPCHAT_ADMLIST DIALOGEX 0, 0, 208, 165 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_FILTER,5,147,161,12,ES_AUTOHSCROLL + CONTROL "Apply Filter",IDC_BTN_FILTERAPPLY,"MButtonClass",WS_TABSTOP,171,146,16,14 + CONTROL "Reset Filter",IDC_BTN_FILTERRESET,"MButtonClass",WS_TABSTOP,187,146,16,14 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,5,5,198,136 +END + +IDD_PEP_SIMPLE DIALOGEX 0, 0, 201, 140 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_CB_MODES,5,5,191,78,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_TXT_DESCRIPTION,5,22,191,82,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,90,109,50,14 + PUSHBUTTON "Cancel",IDCANCEL,145,109,51,14 +END + +IDD_NOTEBOOK DIALOGEX 0, 0, 353, 261 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Jabber Notebook" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Jabber notebook\nStore notes on server and access them from anywhere.",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,428,25 + CONTROL "Remove",IDC_REMOVE,"MButtonClass",WS_TABSTOP,37,229,16,14 + CONTROL "Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,21,229,16,14 + CONTROL "Add",IDC_ADD,"MButtonClass",WS_TABSTOP,5,229,16,14 + PUSHBUTTON "Close",IDCANCEL,297,229,50,14 + CONTROL "",IDC_TV_FILTER,"SysTreeView32",TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,5,38,100,187 + LISTBOX IDC_LST_NOTES,110,38,237,187,LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Save",IDC_APPLY,242,229,50,14 +END + +IDD_CAPTCHAFORM DIALOGEX 0, 0, 258, 224 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Bots Challenge Test" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_VALUE,4,203,137,14,ES_AUTOHSCROLL + CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25 + LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP + EDITTEXT IDC_INSTRUCTION,17,16,233,8,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1 + CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1 + DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14 + PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14 +END + +IDD_CONSOLE DIALOGEX 0, 0, 354, 240 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "XML Console" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_CONSOLE,RICHEDIT_CLASS,WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x804,5,5,343,137 + CONTROL "Custom1",IDC_BTN_MSG,"MButtonClass",WS_TABSTOP,5,147,16,14 + CONTROL "Custom1",IDC_BTN_PRESENCE,"MButtonClass",WS_TABSTOP,21,147,16,14 + CONTROL "Custom1",IDC_BTN_IQ,"MButtonClass",WS_TABSTOP,37,147,16,14 + CONTROL "Custom1",IDC_BTN_FILTER,"MButtonClass",WS_TABSTOP,68,147,16,14 + COMBOBOX IDC_CB_FILTER,86,147,245,91,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Custom1",IDC_BTN_FILTER_REFRESH,"MButtonClass",WS_TABSTOP,333,147,16,14 + EDITTEXT IDC_CONSOLEIN,5,166,343,38,ES_MULTILINE | WS_VSCROLL + PUSHBUTTON "Reset log",IDC_RESET,244,209,50,14 + DEFPUSHBUTTON "Send",IDOK,299,209,50,14 +END + +IDD_GROUPCHAT_INPUT DIALOGEX 0, 0, 242, 42 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_TXT_MULTILINE,6,6,230,12,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | NOT WS_VISIBLE | WS_VSCROLL + EDITTEXT IDC_TXT_PASSWORD,6,6,230,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | ES_PASSWORD + COMBOBOX IDC_TXT_COMBO,6,6,230,92,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_TXT_RICHEDIT,RICHEDIT_CLASS,NOT WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x1004,6,6,230,12 + DEFPUSHBUTTON "OK",IDOK,131,23,50,14 + PUSHBUTTON "Cancel",IDCANCEL,186,23,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NOTE_EDIT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 273 + TOPMARGIN, 7 + HORZGUIDE, 19 + HORZGUIDE, 24 + HORZGUIDE, 174 + HORZGUIDE, 179 + HORZGUIDE, 187 + HORZGUIDE, 202 + HORZGUIDE, 207 + HORZGUIDE, 221 + END + + IDD_ACCMGRUI, DIALOG + BEGIN + RIGHTMARGIN, 184 + END + + IDD_OPT_REGISTER, DIALOG + BEGIN + RIGHTMARGIN, 165 + BOTTOMMARGIN, 61 + END + + IDD_PASSWORD, DIALOG + BEGIN + VERTGUIDE, 7 + VERTGUIDE, 279 + HORZGUIDE, 42 + HORZGUIDE, 56 + END + + IDD_BOOKMARK_ADD, DIALOG + BEGIN + BOTTOMMARGIN, 137 + END + + IDD_NOTEBOOK, DIALOG + BEGIN + VERTGUIDE, 292 + VERTGUIDE, 297 + HORZGUIDE, 229 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_JABBER ICON "jabber.ico" +IDI_ARROW_DOWN ICON "arrow_down.ico" +IDI_ARROW_UP ICON "arrow_up.ico" +IDI_DISCO_PROGRESS ICON "disco_in_progress.ico" +IDI_NODE_RSS ICON "rss.ico" +IDI_NODE_SERVER ICON "server.ico" +IDI_NODE_STORE ICON "store.ico" +IDI_NODE_WEATHER ICON "weather.ico" +IDI_DISCO_OK ICON "disco_ok.ico" +IDI_DISCO_FAIL ICON "disco_fail.ico" +IDI_GROUP ICON "group.ico" +IDI_KEYS ICON "key.ico" +IDI_ADDCONTACT ICON "addcontact.ico" +IDI_ADDROSTER ICON "add2roster.ico" +IDI_AGENTS ICON "roster.ico" +IDI_VCARD ICON "pages.ico" +IDI_DELETE ICON "delete.ico" +IDI_EDIT ICON "rename.ico" +IDI_GRANT ICON "grant.ico" +IDI_OPEN ICON "open.ico" +IDI_REQUEST ICON "request.ico" +IDI_USER2ROOM ICON "user2room.ico" +IDI_SAVE ICON "save.ico" +IDI_LOGIN ICON "login.ico" +IDI_AUTHREVOKE ICON "auth_revoke.ico" +IDI_REFRESH ICON "refresh.ico" +IDI_COMMAND ICON "command.ico" +IDI_BOOKMARKS ICON "bookmarks.ico" +IDI_PRIVACY_LISTS ICON "privacy_lists.ico" +IDI_SERVICE_DISCOVERY ICON "service_discovery.ico" +IDI_VIEW_LIST ICON "view_as_list.ico" +IDI_VIEW_TREE ICON "view_as_tree.ico" +IDI_FILTER_APPLY ICON "filter.ico" +IDI_BROWSE ICON "go.ico" +IDI_NAV_HOME ICON "home.ico" +IDI_NAV_REFRESH ICON "refresh_node.ico" +IDI_FILTER_RESET ICON "reset_filter.ico" +IDI_CONSOLE ICON "console.ico" +IDI_PL_MSG_ALLOW ICON "message_allow.ico" +IDI_PL_MSG_DENY ICON "message_deny.ico" +IDI_PL_PRIN_ALLOW ICON "presence_in_allow.ico" +IDI_PL_PRIN_DENY ICON "presence_in_deny.ico" +IDI_PL_PROUT_ALLOW ICON "presence_out_allow.ico" +IDI_PL_PROUT_DENY ICON "presence_out_deny.ico" +IDI_PL_QUERY_ALLOW ICON "query_allow.ico" +IDI_PL_QUERY_DENY ICON "query_deny.ico" +IDI_PL_LIST_ACTIVE ICON "plist_active.ico" +IDI_PL_LIST_ANY ICON "plist_any.ico" +IDI_PL_LIST_DEFAULT ICON "plist_default.ico" +IDI_TRANSPORT ICON "transport.ico" +IDI_TRANSPORTL ICON "transport_local.ico" +IDI_HTTP_AUTH ICON "openid.ico" +IDI_NOTES ICON "notes.ico" +IDI_SEND_NOTE ICON "send_note.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""richedit.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/JabberG/res/key.ico b/protocols/JabberG/res/key.ico new file mode 100644 index 0000000000..17f9bc23e8 Binary files /dev/null and b/protocols/JabberG/res/key.ico differ diff --git a/protocols/JabberG/res/login.ico b/protocols/JabberG/res/login.ico new file mode 100644 index 0000000000..5b72f5e87a Binary files /dev/null and b/protocols/JabberG/res/login.ico differ diff --git a/protocols/JabberG/res/message_allow.ico b/protocols/JabberG/res/message_allow.ico new file mode 100644 index 0000000000..b82dc84cb4 Binary files /dev/null and b/protocols/JabberG/res/message_allow.ico differ diff --git a/protocols/JabberG/res/message_deny.ico b/protocols/JabberG/res/message_deny.ico new file mode 100644 index 0000000000..4f67487b7a Binary files /dev/null and b/protocols/JabberG/res/message_deny.ico differ diff --git a/protocols/JabberG/res/notes.ico b/protocols/JabberG/res/notes.ico new file mode 100644 index 0000000000..4a2eb48dfa Binary files /dev/null and b/protocols/JabberG/res/notes.ico differ diff --git a/protocols/JabberG/res/open.ico b/protocols/JabberG/res/open.ico new file mode 100644 index 0000000000..bc56c4f149 Binary files /dev/null and b/protocols/JabberG/res/open.ico differ diff --git a/protocols/JabberG/res/openid.ico b/protocols/JabberG/res/openid.ico new file mode 100644 index 0000000000..d8e2f9f240 Binary files /dev/null and b/protocols/JabberG/res/openid.ico differ diff --git a/protocols/JabberG/res/pages.ico b/protocols/JabberG/res/pages.ico new file mode 100644 index 0000000000..715b7a1bec Binary files /dev/null and b/protocols/JabberG/res/pages.ico differ diff --git a/protocols/JabberG/res/plist_active.ico b/protocols/JabberG/res/plist_active.ico new file mode 100644 index 0000000000..3cffd4d21d Binary files /dev/null and b/protocols/JabberG/res/plist_active.ico differ diff --git a/protocols/JabberG/res/plist_any.ico b/protocols/JabberG/res/plist_any.ico new file mode 100644 index 0000000000..052e670921 Binary files /dev/null and b/protocols/JabberG/res/plist_any.ico differ diff --git a/protocols/JabberG/res/plist_default.ico b/protocols/JabberG/res/plist_default.ico new file mode 100644 index 0000000000..f282227f9a Binary files /dev/null and b/protocols/JabberG/res/plist_default.ico differ diff --git a/protocols/JabberG/res/presence_in_allow.ico b/protocols/JabberG/res/presence_in_allow.ico new file mode 100644 index 0000000000..400b8b6f13 Binary files /dev/null and b/protocols/JabberG/res/presence_in_allow.ico differ diff --git a/protocols/JabberG/res/presence_in_deny.ico b/protocols/JabberG/res/presence_in_deny.ico new file mode 100644 index 0000000000..99bd3a0ec7 Binary files /dev/null and b/protocols/JabberG/res/presence_in_deny.ico differ diff --git a/protocols/JabberG/res/presence_out_allow.ico b/protocols/JabberG/res/presence_out_allow.ico new file mode 100644 index 0000000000..b7d644e8fb Binary files /dev/null and b/protocols/JabberG/res/presence_out_allow.ico differ diff --git a/protocols/JabberG/res/presence_out_deny.ico b/protocols/JabberG/res/presence_out_deny.ico new file mode 100644 index 0000000000..8bfa078d5b Binary files /dev/null and b/protocols/JabberG/res/presence_out_deny.ico differ diff --git a/protocols/JabberG/res/privacy_lists.ico b/protocols/JabberG/res/privacy_lists.ico new file mode 100644 index 0000000000..2a55157ff7 Binary files /dev/null and b/protocols/JabberG/res/privacy_lists.ico differ diff --git a/protocols/JabberG/res/query_allow.ico b/protocols/JabberG/res/query_allow.ico new file mode 100644 index 0000000000..e6c3a4bfe6 Binary files /dev/null and b/protocols/JabberG/res/query_allow.ico differ diff --git a/protocols/JabberG/res/query_deny.ico b/protocols/JabberG/res/query_deny.ico new file mode 100644 index 0000000000..dd358a484e Binary files /dev/null and b/protocols/JabberG/res/query_deny.ico differ diff --git a/protocols/JabberG/res/refresh.ico b/protocols/JabberG/res/refresh.ico new file mode 100644 index 0000000000..81c6d95f4a Binary files /dev/null and b/protocols/JabberG/res/refresh.ico differ diff --git a/protocols/JabberG/res/refresh_node.ico b/protocols/JabberG/res/refresh_node.ico new file mode 100644 index 0000000000..6c7efc744f Binary files /dev/null and b/protocols/JabberG/res/refresh_node.ico differ diff --git a/protocols/JabberG/res/rename.ico b/protocols/JabberG/res/rename.ico new file mode 100644 index 0000000000..fa8abc8785 Binary files /dev/null and b/protocols/JabberG/res/rename.ico differ diff --git a/protocols/JabberG/res/request.ico b/protocols/JabberG/res/request.ico new file mode 100644 index 0000000000..94ee8e60c3 Binary files /dev/null and b/protocols/JabberG/res/request.ico differ diff --git a/protocols/JabberG/res/reset_filter.ico b/protocols/JabberG/res/reset_filter.ico new file mode 100644 index 0000000000..e1e54dbeb6 Binary files /dev/null and b/protocols/JabberG/res/reset_filter.ico differ diff --git a/protocols/JabberG/res/roster.ico b/protocols/JabberG/res/roster.ico new file mode 100644 index 0000000000..89e9430443 Binary files /dev/null and b/protocols/JabberG/res/roster.ico differ diff --git a/protocols/JabberG/res/rss.ico b/protocols/JabberG/res/rss.ico new file mode 100644 index 0000000000..9069672b7d Binary files /dev/null and b/protocols/JabberG/res/rss.ico differ diff --git a/protocols/JabberG/res/save.ico b/protocols/JabberG/res/save.ico new file mode 100644 index 0000000000..fadf04c4da Binary files /dev/null and b/protocols/JabberG/res/save.ico differ diff --git a/protocols/JabberG/res/send_note.ico b/protocols/JabberG/res/send_note.ico new file mode 100644 index 0000000000..c77fa5e35d Binary files /dev/null and b/protocols/JabberG/res/send_note.ico differ diff --git a/protocols/JabberG/res/server.ico b/protocols/JabberG/res/server.ico new file mode 100644 index 0000000000..1e4af66351 Binary files /dev/null and b/protocols/JabberG/res/server.ico differ diff --git a/protocols/JabberG/res/service_discovery.ico b/protocols/JabberG/res/service_discovery.ico new file mode 100644 index 0000000000..b361d5ab2a Binary files /dev/null and b/protocols/JabberG/res/service_discovery.ico differ diff --git a/protocols/JabberG/res/store.ico b/protocols/JabberG/res/store.ico new file mode 100644 index 0000000000..86efc4935e Binary files /dev/null and b/protocols/JabberG/res/store.ico differ diff --git a/protocols/JabberG/res/transport.ico b/protocols/JabberG/res/transport.ico new file mode 100644 index 0000000000..5082add068 Binary files /dev/null and b/protocols/JabberG/res/transport.ico differ diff --git a/protocols/JabberG/res/transport_local.ico b/protocols/JabberG/res/transport_local.ico new file mode 100644 index 0000000000..c1b79901a2 Binary files /dev/null and b/protocols/JabberG/res/transport_local.ico differ diff --git a/protocols/JabberG/res/user2room.ico b/protocols/JabberG/res/user2room.ico new file mode 100644 index 0000000000..94c37db75e Binary files /dev/null and b/protocols/JabberG/res/user2room.ico differ diff --git a/protocols/JabberG/res/version.rc b/protocols/JabberG/res/version.rc new file mode 100644 index 0000000000..d50daca899 --- /dev/null +++ b/protocols/JabberG/res/version.rc @@ -0,0 +1,53 @@ +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include "..\src\version.h" +#include "winres.h" + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page( 1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Miranda\0" + VALUE "FileDescription", "Jabber Protocol Plugin for Miranda NG\0" + VALUE "FileVersion", __VERSION_STRING + VALUE "InternalName", "jabber\0" + VALUE "LegalCopyright", "Copyright ( c) 2002-04 Santithorn Bunchua, 2005 George Hazan \0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "jabber.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Jabber Protocol Plugin for Miranda NG\0" + VALUE "ProductVersion", __VERSION_STRING + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/protocols/JabberG/res/view_as_list.ico b/protocols/JabberG/res/view_as_list.ico new file mode 100644 index 0000000000..6baf9d9d3d Binary files /dev/null and b/protocols/JabberG/res/view_as_list.ico differ diff --git a/protocols/JabberG/res/view_as_tree.ico b/protocols/JabberG/res/view_as_tree.ico new file mode 100644 index 0000000000..0a1c408f34 Binary files /dev/null and b/protocols/JabberG/res/view_as_tree.ico differ diff --git a/protocols/JabberG/res/weather.ico b/protocols/JabberG/res/weather.ico new file mode 100644 index 0000000000..6fa9c8f5a5 Binary files /dev/null and b/protocols/JabberG/res/weather.ico differ diff --git a/protocols/JabberG/resource.h b/protocols/JabberG/resource.h deleted file mode 100644 index 5cbc583aa5..0000000000 --- a/protocols/JabberG/resource.h +++ /dev/null @@ -1,358 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by jabber.rc -// -#define IDD_OPT_JABBER 101 -#define IDI_JABBER 102 -#define IDD_INFO_JABBER 103 -#define IDD_OPT_REGISTER 105 -#define IDD_AGENTS 106 -#define IDD_FORM 107 -#define IDI_ADDROSTER 108 -#define IDI_USER2ROOM 109 -#define IDI_REFRESH 110 -#define IDD_PASSWORD 111 -#define IDI_ADDCONTACT 122 -#define IDI_DELETE 123 -#define IDI_EDIT 124 -#define IDD_DATAFORM_TEST 125 -#define IDD_VCARD_HOME 126 -#define IDD_VCARD_PERSONAL 127 -#define IDD_VCARD_WORK 128 -#define IDD_VCARD_CONTACT 129 -#define IDD_VCARD_ADDEMAIL 130 -#define IDD_VCARD_ADDPHONE 131 -#define IDI_OPEN 131 -#define IDD_VCARD_PHOTO 132 -#define IDD_VCARD_NOTE 133 -#define IDD_CHANGEPASSWORD 136 -#define IDD_SEARCHUSER 138 -#define IDD_OPT_JABBER2 140 -#define IDI_REQUEST 141 -#define IDD_GROUPCHAT 141 -#define IDI_GRANT 142 -#define IDI_KEYS 144 -#define IDI_GROUP 147 -#define IDD_GROUPCHAT_JOIN 148 -#define IDI_AGENTS 154 -#define IDI_VCARD 155 -#define IDI_SAVE 166 -#define IDD_GROUPCHAT_INPUT 167 -#define IDD_JIDLIST 171 -#define IDD_AGENT_MANUAL_REGISTER 182 -#define IDD_GROUPCHAT_INVITE 183 -#define IDD_GROUPCHAT_INVITE_ACCEPT 184 -#define IDD_OPT_JABBER3 185 -#define IDI_LOGIN 186 -#define IDI_AUTHREVOKE 187 -#define IDI_COMMAND 188 -#define IDI_DISCO_OK 190 -#define IDI_DISCO_FAIL 191 -#define IDI_VIEW_LIST 192 -#define IDI_VIEW_TREE 193 -#define IDI_FILTER_APPLY 194 -#define IDI_BROWSE 195 -#define IDI_NAV_HOME 196 -#define IDI_NAV_REFRESH 197 -#define IDI_FILTER_RESET 198 -#define IDI_DISCO_PROGRESS 199 -#define IDI_NODE_RSS 200 -#define IDI_NODE_SERVER 201 -#define IDI_NODE_STORE 202 -#define IDI_NODE_WEATHER 203 -#define IDD_CONSOLE 205 -#define IDI_CONSOLE 207 -#define IDD_DATAFORM_PAGE 208 -#define IDI_PL_MSG_ALLOW 209 -#define IDI_PL_MSG_DENY 210 -#define IDI_PL_PRIN_ALLOW 211 -#define IDI_PL_PRIN_DENY 212 -#define IDI_PL_PROUT_ALLOW 213 -#define IDI_PL_PROUT_DENY 214 -#define IDI_PL_QUERY_ALLOW 215 -#define IDD_SETMOODMSG 216 -#define IDI_PL_QUERY_DENY 216 -#define IDI_PL_LIST_ACTIVE 217 -#define IDI_PL_LIST_ANY 218 -#define IDI_PL_LIST_DEFAULT 219 -#define IDI_ARROW_DOWN 220 -#define IDI_ARROW_UP 221 -#define IDI_TRANSPORT 222 -#define IDI_TRANSPORTL 223 -#define IDD_GROUPCHAT_INFO 224 -#define IDD_OPT_JABBER4 226 -#define IDD_ACCMGRUI 227 -#define IDD_HTTP_AUTH 228 -#define IDI_HTTP_AUTH 229 -#define IDD_PEP_SIMPLE 230 -#define IDD_NOTEBOOK 231 -#define IDD_NOTE_EDIT 232 -#define IDI_NOTES 233 -#define IDI_SEND_NOTE 234 -#define IDC_STATUSBAR 999 -#define IDC_EDIT_USERNAME 1000 -#define IDC_SAVE 1000 -#define IDC_EDIT_PASSWORD 1001 -#define IDC_BUTTON_REGISTER 1002 -#define IDC_EDIT_LOGIN_SERVER 1003 -#define IDC_PORT 1004 -#define IDC_BUTTON_CHANGE_PASSWORD 1005 -#define IDC_LINK_PUBLIC_SERVER 1009 -#define IDC_NAME 1009 -#define IDC_PROGRESS_REG 1011 -#define IDC_AGENT_TRANSPORT 1015 -#define IDC_AGENT_REGISTER 1016 -#define IDC_AGENT_LOGON 1017 -#define IDC_AGENT_UNREGISTER 1018 -#define IDC_AGENT_SERVER 1019 -#define IDC_AGENT_LOGOFF 1020 -#define IDC_AGENT_LIST 1021 -#define IDC_AGENT_SEARCH 1022 -#define IDC_SUBMIT 1023 -#define IDC_NEXT 1025 -#define IDC_PREV 1026 -#define IDC_COMPLETE 1027 -#define IDC_AGENT_BROWSE 1029 -#define IDC_INSTRUCTION 1030 -#define IDC_FRAME 1037 -#define IDC_FRAME_TEXT 1038 -#define IDC_SIMPLE 1041 -#define IDC_KEEPALIVE 1042 -#define IDC_HOST 1043 -#define IDC_HOSTPORT 1044 -#define IDC_USE_SSL 1045 -#define IDC_MANUAL 1046 -#define IDC_RESOURCE_T 1047 -#define IDC_SAVEPASSWORD 1048 -#define IDC_MSGLANG 1049 -#define IDC_PASSWORD 1050 -#define IDC_JID 1051 -#define IDC_NEWPASSWD2 1052 -#define IDC_ROSTER_SYNC 1052 -#define IDC_OLDPASSWD 1053 -#define IDC_ADDRESS1 1056 -#define IDC_ADDRESS2 1057 -#define IDC_CITY 1058 -#define IDC_STATE 1059 -#define IDC_COUNTRY 1060 -#define IDC_FULLNAME 1061 -#define IDC_ZIP 1061 -#define IDC_NICKNAME 1062 -#define IDC_COMPANY 1062 -#define IDC_FIRSTNAME 1063 -#define IDC_DEPARTMENT 1063 -#define IDC_LASTNAME 1064 -#define IDC_BIRTH 1065 -#define IDC_OCCUPATION 1066 -#define IDC_HOMEPAGE 1067 -#define IDC_MIDDLE 1072 -#define IDC_EMAIL 1073 -#define IDC_HOME 1074 -#define IDC_INTERNET 1075 -#define IDC_X400 1076 -#define IDC_WORK 1077 -#define IDC_PHONE 1078 -#define IDC_CELL 1079 -#define IDC_VIDEO 1080 -#define IDC_BBS 1081 -#define IDC_MODEM 1082 -#define IDC_PAGER 1083 -#define IDC_MSG 1084 -#define IDC_ISDN 1085 -#define IDC_PCS 1086 -#define IDC_VOICE 1087 -#define IDC_FAX 1088 -#define IDC_TITLE 1089 -#define IDC_DESC 1090 -#define IDC_DELETE 1092 -#define IDC_LOAD 1093 -#define IDC_CANVAS 1094 -#define IDC_GENDER 1096 -#define IDC_JUD 1097 -#define IDC_JUD_LABEL 1098 -#define IDC_MSGLANG_LABEL 1099 -#define IDC_PRIORITY_SPIN 1104 -#define IDC_PRIORITY 1105 -#define IDC_PRIORITY_LABEL 1106 -#define IDC_NEWPASSWD 1107 -#define IDC_COMBO_ACCTYPE 1108 -#define IDD_MODERNOPT 1110 -#define IDC_PROXY_ADDR 1112 -#define IDC_DIRECT_ADDR 1114 -#define IDC_DIRECT_MANUAL 1121 -#define IDC_REG_STATUS 1122 -#define IDC_JOIN 1123 -#define IDC_DIRECT 1123 -#define IDC_ROOM 1124 -#define IDC_PROXY_MANUAL 1124 -#define IDC_SERVER 1125 -#define IDC_BROWSE 1126 -#define IDC_VSCROLL 1128 -#define IDC_NICK 1129 -#define IDC_EDIT 1131 -#define IDC_LIST 1133 -#define IDC_TABS 1141 -#define IDC_TXT_MULTILINE 1141 -#define IDC_TXT_PASSWORD 1142 -#define IDC_MANUAL_REGISTER 1167 -#define IDC_REASON 1171 -#define IDC_CLIST 1172 -#define IDC_NEWJID 1173 -#define IDC_ADDJID 1174 -#define IDC_INVITE 1175 -#define IDC_BTN_ADVANCED 1175 -#define IDC_ACCEPT 1176 -#define IDC_BTN_SIMPLE 1176 -#define IDC_FROM 1177 -#define IDC_USE_TLS 1180 -#define IDC_UNREGISTER 1183 -#define IDC_GO 1196 -#define IDC_HOSTNAME_AS_RESOURCE 1214 -#define IDC_COMMANDS1 1216 -#define IDC_COMMANDS2 1217 -#define IDC_COMBO_RESOURCE 1218 -#define IDC_PL_RULES_LIST 1219 -#define IDC_WHITERECT 1220 -#define IDC_ADD_RULE 1221 -#define IDC_EDIT_RULE 1222 -#define IDC_REMOVE_RULE 1223 -#define IDC_ADD_LIST 1225 -#define IDC_REMOVE_LIST 1226 -#define IDC_COMBO_TYPE 1230 -#define IDC_EDIT_VALUE 1231 -#define IDC_COMBO_ACTION 1232 -#define IDC_CHECK_MESSAGES 1233 -#define IDC_CHECK_QUERIES 1234 -#define IDC_CHECK_PRESENCE_OUT 1235 -#define IDC_CHECK_PRESENCE_IN 1236 -#define IDC_COMBO_VALUE 1237 -#define IDC_EDIT_NAME 1238 -#define IDC_TREE_DISCO 1240 -#define IDC_FRAME1 1241 -#define IDC_FRAME2 1242 -#define IDC_COMBO_JID 1243 -#define IDC_TXT_JID 1243 -#define IDC_COMBO_NODE 1244 -#define IDC_BUTTON_BROWSE 1245 -#define IDC_DOWNLOAD 1245 -#define IDC_ACTIVATE 1245 -#define IDC_BTN_NAVHOME 1246 -#define IDC_UPLOAD 1246 -#define IDC_TXT_FILTERTEXT 1247 -#define IDC_IMPORT 1247 -#define IDC_BTN_FILTERRESET 1248 -#define IDC_EXPORT 1248 -#define IDC_TXT_FILTER 1249 -#define IDC_TXT_NODELABEL 1250 -#define IDC_BTN_FAVORITE 1251 -#define IDC_BTN_REFRESH 1253 -#define IDC_BTN_VIEWTREE 1254 -#define IDC_BTN_VIEWLIST 1255 -#define IDC_BTN_FILTERAPPLY 1258 -#define IDC_ROSTER 1261 -#define IDC_MSG_MOOD 1262 -#define IDC_OPTTREE 1263 -#define IDC_LB_LISTS 1264 -#define IDC_LST_NOTES 1264 -#define IDC_TITLE1 1265 -#define IDC_CONSOLE 1266 -#define IDC_CONSOLEIN 1267 -#define IDC_RESET 1268 -#define IDC_BOOKMARKS 1270 -#define IDC_BTN_MSG 1270 -#define IDC_BTN_ROLE 1270 -#define IDC_DATAFORM 1270 -#define IDC_BTN_PRESENCE 1271 -#define IDC_BTN_AFFILIATION 1271 -#define IDC_SET_DEFAULT 1272 -#define IDC_BTN_IQ 1272 -#define IDC_TXT_RULES 1273 -#define IDC_TXT_LISTS 1274 -#define IDC_TV_INFO 1276 -#define IDC_TXT_OTHERJID 1277 -#define IDC_TXT_MESSAGE 1278 -#define IDC_TXT_QUERY 1279 -#define IDC_TXT_INPRESENCE 1280 -#define IDC_TXT_OUTPRESENCE 1281 -#define IDC_ICO_OUTPRESENCE 1282 -#define IDC_ICO_INPRESENCE 1283 -#define IDC_ICO_QUERY 1284 -#define IDC_ICO_MESSAGE 1285 -#define IDC_ICO_PRESENCEIN 1286 -#define IDC_ICO_PRESENCEOUT 1287 -#define IDC_RECENT1 1288 -#define IDC_RECENT2 1289 -#define IDC_RECENT3 1290 -#define IDC_RECENT4 1291 -#define IDC_RECENT5 1292 -#define IDC_TXT_RECENT 1293 -#define IDC_FILTER 1294 -#define IDC_TXT_NICK 1294 -#define IDC_TXT_QUIT 1294 -#define IDC_EDIT_HTTP_AUTH_INFO 1294 -#define IDC_TXT_URL 1294 -#define IDC_TXT_DESCRIPTION 1294 -#define IDC_TXT_TITLE 1294 -#define IDC_BTN_FILTER 1295 -#define IDC_TXT_ID 1295 -#define IDC_CB_FILTER 1296 -#define IDC_TXT_ROLE 1296 -#define IDC_TXT_COMBO 1296 -#define IDC_CB_TYPE 1296 -#define IDC_TXT_METHOD 1296 -#define IDC_CB_MODES 1296 -#define IDC_BTN_FILTER_REFRESH 1297 -#define IDC_TXT_STATUS 1298 -#define IDC_TXT_FROM 1298 -#define IDC_TXT_AFFILIATION 1299 -#define IDC_ICO_STATUS 1300 -#define IDC_TXT_RICHEDIT 1302 -#define IDC_TXT_SLAP 1304 -#define IDC_TXT_TAGS 1304 -#define IDC_EMAILS 1306 -#define IDC_TV_FILTER 1307 -#define IDC_PHONES 1308 -#define IDC_TXT_TEXT 1308 -#define IDC_ST_TAGS 1309 -#define IDC_INSTRUCTIONS 1315 -#define IDC_COMBO_VALUES 1319 -#define IDC_HEADERBAR 1320 -#define IDC_USEDOMAINLOGIN 1323 -#define IDC_TXT_ALTNICK 1323 -#define IDI_BOOKMARKS 3000 -#define IDD_BOOKMARKS 3001 -#define IDC_BM_LIST 3002 -#define IDC_ADD 3004 -#define IDC_REMOVE 3005 -#define IDD_BOOKMARK_ADD 3006 -#define IDC_UP_RULE 3006 -#define IDC_ROOM_JID 3007 -#define IDD_PRIVACY_LISTS 3007 -#define IDC_DOWN_RULE 3007 -#define IDC_APPLY 3008 -#define IDD_PRIVACY_RULE 3008 -#define IDC_ROOM_RADIO 3009 -#define IDD_PRIVACY_ADD_LIST 3009 -#define IDD_SERVICE_DISCOVERY 3010 -#define IDC_URL_RADIO 3011 -#define IDD_GROUPCHAT_INFO_TABS 3011 -#define IDC_AGENT_RADIO 3012 -#define IDD_GROUPCHAT_ADMLIST 3012 -#define IDC_BOOKMARK_TYPE 3013 -#define IDC_CHECK_BM_AUTOJOIN 3014 -#define IDI_PRIVACY_LISTS 3016 -#define IDI_SERVICE_DISCOVERY 3017 -#define IDD_CAPTCHAFORM 3018 -#define IDC_VALUE 3019 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 235 -#define _APS_NEXT_COMMAND_VALUE 40017 -#define _APS_NEXT_CONTROL_VALUE 1324 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/protocols/JabberG/src/MString.cpp b/protocols/JabberG/src/MString.cpp new file mode 100644 index 0000000000..773871d1a5 --- /dev/null +++ b/protocols/JabberG/src/MString.cpp @@ -0,0 +1,201 @@ +#include "jabber.h" +#include "MString.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +CNilMStringData CMBaseString::m_nil; + +CMStringData* CMBaseString::Allocate( int nChars, int nCharSize ) +{ + CMStringData* pData; + nChars++; // nil char + size_t nDataBytes = nCharSize * nChars; + size_t nTotalSize = nDataBytes + sizeof(CMStringData); + + pData = static_cast<CMStringData*>(malloc(nTotalSize)); + if (pData == NULL) + return NULL; + + pData->nRefs = 1; + pData->nAllocLength = nChars - 1; + pData->nDataLength = 0; + return pData; +} + +void CMBaseString::Free(CMStringData* pData) +{ + free(pData); +} + +CMStringData* CMBaseString::Realloc(CMStringData* pData, int nChars, int nCharSize) +{ + CMStringData* pNewData; + nChars++; // nil char + ULONG nDataBytes = nCharSize * nChars; + ULONG nTotalSize = nDataBytes + sizeof(CMStringData); + + pNewData = static_cast<CMStringData*>(realloc(pData, nTotalSize)); + if (pNewData == NULL) + return NULL; + + pNewData->nAllocLength = nChars - 1; + return pNewData; +} + +CMStringData* CMBaseString::GetNilString() +{ + m_nil.AddRef(); + return &m_nil; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CMStringData + +void* CMStringData::data() +{ + return (this + 1); +} + +void CMStringData::AddRef() +{ + InterlockedIncrement(&nRefs); +} + +bool CMStringData::IsLocked() const +{ + return nRefs < 0; +} + +bool CMStringData::IsShared() const +{ + return (nRefs > 1); +} + +void CMStringData::Lock() +{ + nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary + if ( nRefs == 0 ) + nRefs = -1; +} + +void CMStringData::Release() +{ + if (InterlockedDecrement(&nRefs) <= 0) + CMBaseString::Free(this); +} + +void CMStringData::Unlock() +{ + if (IsLocked()) + { + nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary + if (nRefs == 0) + nRefs = 1; + } +} + +CNilMStringData::CNilMStringData() +{ + nRefs = 2; // Never gets freed + nDataLength = 0; + nAllocLength = 0; + achNil[0] = 0; + achNil[1] = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT<wchar_t> + +#if _MSC_VER < 1400 +static HINSTANCE hCrt = NULL; + +typedef int ( __cdecl *_vscprintf_func )( LPCSTR pszFormat, va_list args ); +static _vscprintf_func _vscprintf_ptr = NULL; + +typedef int ( __cdecl *_vscwprintf_func )( LPCWSTR pszFormat, va_list args ); +static _vscwprintf_func _vscwprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnprintf_func )( char*, size_t, const char*, va_list ); +static _vsnprintf_func _vsnprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnwprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static _vsnwprintf_func _vsnwprintf_ptr = NULL; + +typedef int ( __cdecl *vswprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static vswprintf_func vswprintf_ptr = NULL; + +typedef int ( __cdecl *vsprintf_func )( char*, size_t, const char*, va_list ); +static vsprintf_func vsprintf_ptr = NULL; + +static void checkCrt( void ) +{ + if ( hCrt == NULL ) { + hCrt = GetModuleHandleA( "msvcrt.dll" ); + _vscprintf_ptr = (_vscprintf_func)GetProcAddress( hCrt, "_vscprintf" ); + _vscwprintf_ptr = (_vscwprintf_func)GetProcAddress( hCrt, "_vscwprintf" ); + _vsnprintf_ptr = (_vsnprintf_func)GetProcAddress( hCrt, "_vsnprintf" ); + _vsnwprintf_ptr = (_vsnwprintf_func)GetProcAddress( hCrt, "_vsnwprintf" ); + vswprintf_ptr = (vswprintf_func)GetProcAddress( hCrt, "vswprintf" ); + vsprintf_ptr = (vsprintf_func)GetProcAddress( hCrt, "vsprintf" ); +} } +#endif + +int __stdcall ChTraitsCRT<wchar_t>::GetFormattedLength( LPCWSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscwprintf_ptr != NULL ) + return _vscwprintf_ptr( pszFormat, args ); + + WCHAR buf[ 4000 ]; + return vswprintf_ptr( buf, SIZEOF(buf), pszFormat, args ); + #else + return _vscwprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT<wchar_t>::Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vsnwprintf_ptr != NULL ) + return _vsnwprintf_ptr( pszBuffer, nLength, pszFormat, args ); + + return vswprintf_ptr( pszBuffer, nLength, pszFormat, args ); + #else + return _vsnwprintf( pszBuffer, nLength, pszFormat, args ); + #endif +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT<char> + +int __stdcall ChTraitsCRT<char>::GetFormattedLength( LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscprintf_ptr != NULL ) + return _vscprintf_ptr( pszFormat, args ); + + char buf[4000]; + return vsprintf_ptr( buf, sizeof(buf), pszFormat, args ); + #else + return _vscprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT<char>::Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + return _vsnprintf( pszBuffer, nlength, pszFormat, args ); + #else + return vsprintf_s( pszBuffer, nlength, pszFormat, args ); + #endif +} + diff --git a/protocols/JabberG/src/MString.h b/protocols/JabberG/src/MString.h new file mode 100644 index 0000000000..7cc16ff4a3 --- /dev/null +++ b/protocols/JabberG/src/MString.h @@ -0,0 +1,2300 @@ +#pragma once + +#include <string.h> +#include <mbstring.h> +#include <wchar.h> + +#ifdef __MINGW32__ +#include <limits.h> + +__inline size_t strnlen(const char *string, size_t maxlen) +{ + const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} +__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) +{ + const wchar_t *end = wmemchr (string, L'\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +/* FIXME: This may be wrong assumption about _AtlGetConversionACP */ +#define _AtlGetConversionACP() CP_THREAD_ACP +/* FIXME: This is unsafe */ +#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) +/* FIXME: This is quite silly implementation of _mbsstr */ +#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) +#define __max(x,y) (((x)<(y))?(y):(x)) +#endif /* __MINGW32__ */ + +struct CMStringData +{ + int nDataLength; // Length of currently used data in XCHARs (not including terminating null) + int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) + long nRefs; // Reference count: negative == locked + // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data + void* data(); + void AddRef(); + bool IsLocked() const; + bool IsShared() const; + void Lock(); + void Release(); + void Unlock(); +}; + +class CNilMStringData : public CMStringData +{ +public: + CNilMStringData(); + +public: + wchar_t achNil[2]; +}; + +template< typename BaseType = char > +class ChTraitsBase +{ +public: + typedef char XCHAR; + typedef LPSTR PXSTR; + typedef LPCSTR PCXSTR; + typedef wchar_t YCHAR; + typedef LPWSTR PYSTR; + typedef LPCWSTR PCYSTR; +}; + +template<> +class ChTraitsBase< wchar_t > +{ +public: + typedef wchar_t XCHAR; + typedef LPWSTR PXSTR; + typedef LPCWSTR PCXSTR; + typedef char YCHAR; + typedef LPSTR PYSTR; + typedef LPCSTR PCYSTR; +}; + +class CMBaseString +{ +public: + static CMStringData* Allocate(int nChars, int nCharSize); + static void Free(CMStringData* pData); + static CMStringData* Realloc(CMStringData* pData, int nChars, int nCharSize); + +protected: + static CMStringData* GetNilString(); + static CNilMStringData m_nil; +}; + +template< typename BaseType > +class CMSimpleStringT : public CMBaseString +{ +public: + typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; + typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; + typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; + typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; + typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; + typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; + +public: + explicit CMSimpleStringT() + { + CMStringData* pData = GetNilString(); + Attach(pData); + } + + CMSimpleStringT(const CMSimpleStringT& strSrc) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pNewData = CloneData( pSrcData ); + Attach( pNewData ); + } + + CMSimpleStringT(PCXSTR pszSrc) + { + int nLength = StringLength( pszSrc ); + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if (pData != NULL) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pszSrc, nLength ); + } + } + CMSimpleStringT(const XCHAR* pchSrc, int nLength) + { + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if ( pData != NULL ) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pchSrc, nLength ); + } + } + ~CMSimpleStringT() + { + CMStringData* pData = GetData(); + pData->Release(); + } + + operator CMSimpleStringT<BaseType>&() + { + return *(CMSimpleStringT<BaseType>*)this; + } + + CMSimpleStringT& operator=(const CMSimpleStringT& strSrc ) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pOldData = GetData(); + if ( pSrcData != pOldData) + { + if ( pOldData->IsLocked()) + SetString( strSrc.GetString(), strSrc.GetLength()); + else + { + CMStringData* pNewData = CloneData( pSrcData ); + pOldData->Release(); + Attach( pNewData ); + } + } + + return *this; + } + + CMSimpleStringT& operator=(PCXSTR pszSrc) + { + SetString( pszSrc ); + return *this; + } + + CMSimpleStringT& operator+=( const CMSimpleStringT& strSrc ) + { + Append( strSrc ); + + return *this; + } + + CMSimpleStringT& operator+=( PCXSTR pszSrc ) + { + Append( pszSrc ); + + return *this; + } + CMSimpleStringT& operator+=( char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( unsigned char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( wchar_t ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + + XCHAR operator[]( int iChar ) const + { + return m_pszData[iChar]; + } + + operator PCXSTR() const + { + return m_pszData; + } + + PCXSTR c_str() const + { + return m_pszData; + } + + void Append( PCXSTR pszSrc ) + { + Append( pszSrc, StringLength( pszSrc )); + } + void Append( PCXSTR pszSrc, int nLength ) + { + // See comment in SetString() about why we do this + UINT_PTR nOffset = pszSrc - GetString(); + + UINT nOldLength = GetLength(); + if (nOldLength < 0) + { + // protects from underflow + nOldLength = 0; + } + + //Make sure we don't read pass end of the terminating NULL + int nSrcLength = StringLength(pszSrc); + nLength = nLength > nSrcLength ? nSrcLength: nLength; + + int nNewLength = nOldLength+nLength; + PXSTR pszBuffer = GetBuffer( nNewLength ); + if ( nOffset <= nOldLength ) + { + pszSrc = pszBuffer+nOffset; + // No need to call CopyCharsOverlapped, since the destination is + // beyond the end of the original buffer + } + CopyChars( pszBuffer+nOldLength, nLength, pszSrc, nLength ); + ReleaseBufferSetLength( nNewLength ); + } + void AppendChar( XCHAR ch ) + { + UINT nOldLength = GetLength(); + int nNewLength = nOldLength+1; + PXSTR pszBuffer = GetBuffer( nNewLength ); + pszBuffer[nOldLength] = ch; + ReleaseBufferSetLength( nNewLength ); + } + void Append( const CMSimpleStringT& strSrc ) + { + Append( strSrc.GetString(), strSrc.GetLength()); + } + void Empty() + { + CMStringData* pOldData = GetData(); + if ( pOldData->nDataLength == 0 ) + return; + + if ( pOldData->IsLocked()) + { + // Don't reallocate a locked buffer that's shrinking + SetLength( 0 ); + } + else + { + pOldData->Release(); + CMStringData* pNewData = GetNilString(); + Attach( pNewData ); + } + } + void FreeExtra() + { + CMStringData* pOldData = GetData(); + int nLength = pOldData->nDataLength; + if ( pOldData->nAllocLength == nLength ) + return; + + if ( !pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking + { + CMStringData* pNewData = Allocate( nLength, sizeof( XCHAR )); + if ( pNewData == NULL ) { + SetLength( nLength ); + return; + } + + CopyChars( PXSTR( pNewData->data()), nLength, PCXSTR( pOldData->data()), nLength ); + + pOldData->Release(); + Attach( pNewData ); + SetLength( nLength ); + } + } + + int GetAllocLength() const + { + return GetData()->nAllocLength; + } + XCHAR GetAt( int iChar ) const + { + return m_pszData[iChar]; + } + PXSTR GetBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + Fork( pData->nDataLength ); + + return m_pszData; + } + PXSTR GetBuffer( int nMinBufferLength ) + { + return PrepareWrite( nMinBufferLength ); + } + PXSTR GetBufferSetLength( int nLength ) + { + PXSTR pszBuffer = GetBuffer( nLength ); + SetLength( nLength ); + + return pszBuffer; + } + int GetLength() const + { + return GetData()->nDataLength; + } + + PCXSTR GetString() const + { + return m_pszData; + } + bool IsEmpty() const + { + return GetLength() == 0; + } + PXSTR LockBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + { + Fork( pData->nDataLength ); + pData = GetData(); // Do it again, because the fork might have changed it + } + pData->Lock(); + + return m_pszData; + } + void UnlockBuffer() + { + CMStringData* pData = GetData(); + pData->Unlock(); + } + void Preallocate( int nLength ) + { + PrepareWrite( nLength ); + } + void ReleaseBuffer( int nNewLength = -1 ) + { + if ( nNewLength == -1 ) + { + int nAlloc = GetData()->nAllocLength; + nNewLength = StringLengthN( m_pszData, nAlloc); + } + SetLength( nNewLength ); + } + void ReleaseBufferSetLength( int nNewLength ) + { + SetLength( nNewLength ); + } + void Truncate( int nNewLength ) + { + GetBuffer( nNewLength ); + ReleaseBufferSetLength( nNewLength ); + } + void SetAt( int iChar, XCHAR ch ) + { + int nLength = GetLength(); + PXSTR pszBuffer = GetBuffer(); + pszBuffer[iChar] = ch; + ReleaseBufferSetLength( nLength ); + + } + void SetString( PCXSTR pszSrc ) + { + SetString( pszSrc, StringLength( pszSrc )); + } + void SetString( PCXSTR pszSrc, int nLength ) + { + if ( nLength == 0 ) + { + Empty(); + } + else + { + + UINT nOldLength = GetLength(); + UINT_PTR nOffset = pszSrc - GetString(); + + PXSTR pszBuffer = GetBuffer( nLength ); + if ( nOffset <= nOldLength ) + { + CopyCharsOverlapped( pszBuffer, GetAllocLength(), + pszBuffer+nOffset, nLength ); + } + else + { + CopyChars( pszBuffer, GetAllocLength(), pszSrc, nLength ); + } + ReleaseBufferSetLength( nLength ); + } + } +public: + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength()); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, PCXSTR psz2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(PCXSTR psz1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return s; + } + + static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars ) + { + #if _MSC_VER >= 1400 + memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memcpy(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) + { + #if _MSC_VER >= 1400 + memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memmove(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + static int __stdcall StringLength(const char* psz) + { + if (psz == NULL) + { + return(0); + } + return (int(strlen(psz))); + } + static int __stdcall StringLength(const wchar_t* psz) + { + if (psz == NULL) + return 0; + + return int(wcslen(psz)); + } + static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( strnlen( psz, sizeInXChar )); + } + static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( wcsnlen( psz, sizeInXChar )); + } +protected: + static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) + { + int nNewLength = nLength1+nLength2; + PXSTR pszBuffer = strResult.GetBuffer(nNewLength); + CopyChars(pszBuffer, nLength1, psz1, nLength1 ); + CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); + strResult.ReleaseBufferSetLength(nNewLength); + } + // Implementation +private: + void Attach(CMStringData* pData) + { + m_pszData = static_cast<PXSTR>(pData->data()); + } + void Fork(int nLength) + { + CMStringData* pOldData = GetData(); + int nOldLength = pOldData->nDataLength; + CMStringData* pNewData = Allocate(nLength, sizeof(XCHAR)); + if (pNewData != NULL) + { + int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0' + CopyChars( PXSTR( pNewData->data()), nCharsToCopy, PCXSTR( pOldData->data()), nCharsToCopy ); + pNewData->nDataLength = nOldLength; + pOldData->Release(); + Attach(pNewData); + } + } + CMStringData* GetData() const + { + return (reinterpret_cast<CMStringData *>(m_pszData) - 1); + } + PXSTR PrepareWrite( int nLength ) + { + CMStringData* pOldData = GetData(); + int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false + int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false + if ((nShared | nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data + PrepareWrite2(nLength); + + return m_pszData; + } + void PrepareWrite2(int nLength) + { + CMStringData* pOldData = GetData(); + if (pOldData->nDataLength > nLength) + nLength = pOldData->nDataLength; + + if (pOldData->IsShared()) + { + Fork(nLength); + } + else if (pOldData->nAllocLength < nLength) + { + // Grow exponentially, until we hit 1K. + int nNewLength = pOldData->nAllocLength; + if ( nNewLength > 1024 ) + nNewLength += 1024; + else + nNewLength *= 2; + + if ( nNewLength < nLength ) + nNewLength = nLength; + + Reallocate( nNewLength ); + } + } + void Reallocate( int nLength ) + { + CMStringData* pOldData = GetData(); + if ( pOldData->nAllocLength >= nLength || nLength <= 0) + return; + + CMStringData* pNewData = Realloc( pOldData, nLength, sizeof( XCHAR )); + if ( pNewData != NULL ) + Attach( pNewData ); + } + + void SetLength( int nLength ) + { + GetData()->nDataLength = nLength; + m_pszData[nLength] = 0; + } + + static CMStringData* __stdcall CloneData(CMStringData* pData) + { + CMStringData* pNewData = NULL; + + if (!pData->IsLocked()) { + pNewData = pData; + pNewData->AddRef(); + } + + return pNewData; + } + +public : + // typedef CStrBufT<BaseType> CStrBuf; +private: + PXSTR m_pszData; +}; + + +template< typename _CharType = char > +class ChTraitsCRT : public ChTraitsBase< _CharType > +{ +public: + static char* __stdcall CharNext( const char* p ) + { + return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ))); + } + + static int __stdcall IsDigit( char ch ) + { + return _ismbcdigit( ch ); + } + + static int __stdcall IsSpace( char ch ) + { + return _ismbcspace( ch ); + } + + static int __stdcall StringCompare( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollate( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static LPCSTR __stdcall StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static LPSTR __stdcall StringFindString( LPSTR pszBlock, LPCSTR pszMatch ) + { + return const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch )); + } + + static LPCSTR __stdcall StringFindChar( LPCSTR pszBlock, char chMatch ) + { + return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch )); + } + + static LPCSTR __stdcall StringFindCharRev( LPCSTR psz, char ch ) + { + return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch )); + } + + static LPCSTR __stdcall StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static int __stdcall StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static int __stdcall StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static LPSTR __stdcall StringUppercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringLowercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringUppercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size); + #else + _mbsupr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringLowercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size ); + #else + _mbslwr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringReverse( LPSTR psz ) + { + return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz )) ); + } + + static int __stdcall GetFormattedLength( LPCSTR pszFormat, va_list args ); + + static int __stdcall Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vsprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + + } + + static int __stdcall Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer length in XCHARs + return int( strlen( pszSrc )); + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer length in XCHARs + return nLength; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource, int nLength ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL ); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in XCHARs + memcpy_s( pszDest, nDestLength*sizeof( char ), + pszSrc, nSrcLength*sizeof( char )); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) + { + // nLen is in XCHARs + ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL ); + } + + static void ConvertToOem( _CharType* pstrString) + { + BOOL fSuccess=::CharToOemA(pstrString, pstrString); + } + + static void ConvertToAnsi( _CharType* pstrString) + { + BOOL fSuccess=::OemToCharA(pstrString, pstrString); + } + + static void ConvertToOem( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + { + return; + } + DWORD dwSize=static_cast<DWORD>(size); + BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize); + } + + static void ConvertToAnsi( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + return; + + DWORD dwSize=static_cast<DWORD>(size); + BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize); + } + + static void __stdcall FloodCharacters( char ch, int nLength, char* pch ) + { + // nLength is in XCHARs + memset( pch, ch, nLength ); + } + + static BSTR __stdcall AllocSysString( const char* pchData, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BSTR bstr = ::SysAllocStringLen( NULL, nLen ); + if ( bstr != NULL ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, bstr, nLen ); + + return bstr; + } + + static BOOL __stdcall ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen ); + if ( bSuccess ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen ); + + return bSuccess; + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? int( strlen( psz )) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? int( wcslen( psz )) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return int( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize ) + { + return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize ); + } +}; + +// specialization for wchar_t +template<> +class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > +{ + static DWORD __stdcall _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) + { + return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize ); + } + +public: + static LPWSTR __stdcall CharNext( LPCWSTR psz ) + { + return const_cast< LPWSTR >( psz+1 ); + } + + static int __stdcall IsDigit( wchar_t ch ) + { + return iswdigit( static_cast<unsigned short>(ch)); + } + + static int __stdcall IsSpace( wchar_t ch ) + { + return iswspace( static_cast<unsigned short>(ch)); + } + + static int __stdcall StringCompare( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscmp( pszA, pszB ); + } + + static int __stdcall StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicmp( pszA, pszB ); + } + + static int __stdcall StringCollate( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscoll( pszA, pszB ); + } + + static int __stdcall StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicoll( pszA, pszB ); + } + + static LPCWSTR __stdcall StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcsstr( pszBlock, pszMatch ); + } + + static LPWSTR __stdcall StringFindString( LPWSTR pszBlock, LPCWSTR pszMatch ) + { + return const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch )); + } + + static LPCWSTR __stdcall StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) + { + return wcschr( pszBlock, chMatch ); + } + + static LPCWSTR __stdcall StringFindCharRev( LPCWSTR psz, wchar_t ch ) + { + return wcsrchr( psz, ch ); + } + + static LPCWSTR __stdcall StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcspbrk( pszBlock, pszMatch ); + } + + static int __stdcall StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcsspn( pszBlock, pszSet ); + } + + static int __stdcall StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcscspn( pszBlock, pszSet ); + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcsupr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcslwr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz, size_t ) + { + return _wcsupr( psz ); + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz, size_t ) + { + return _wcslwr( psz ); + } + + static LPWSTR __stdcall StringReverse( LPWSTR psz ) + { + return _wcsrev( psz ); + } + + static int __stdcall GetFormattedLength( LPCWSTR pszFormat, va_list args); + + static int __stdcall Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vswprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + } + + static int __stdcall Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, NULL, 0 )-1; + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nLength, NULL, 0 ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return (int)wcslen( pszSrc ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer size in wchar_ts + return nLength; + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) + { + // nLen is in wchar_ts + ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength ); + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in wchar_ts + #if _MSC_VER >= 1400 + wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); + #else + wmemcpy(pszDest, pszSrc, nDestLength); + #endif + } + + static void __stdcall FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) + { + // nLength is in XCHARs + for ( int i = 0; i < nLength; i++ ) + { + psz[i] = ch; + } + } + + static BSTR __stdcall AllocSysString( const wchar_t* pchData, int nDataLength ) + { + return ::SysAllocStringLen( pchData, nDataLength ); + } + + static BOOL __stdcall ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) + { + return ::SysReAllocStringLen( pbstr, pchData, nDataLength ); + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? (int)strlen( psz ) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? (int)wcslen( psz ) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + (void)pch; + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) + { + return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize ); + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/, size_t ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/, size_t ) + { + } +}; + +template< typename BaseType, class StringTraits > +class CMStringT : public CMSimpleStringT< BaseType > +{ +public: + typedef CMSimpleStringT< BaseType> CThisSimpleString; + typedef typename CThisSimpleString::XCHAR XCHAR; + typedef typename CThisSimpleString::PXSTR PXSTR; + typedef typename CThisSimpleString::PCXSTR PCXSTR; + typedef typename CThisSimpleString::YCHAR YCHAR; + typedef typename CThisSimpleString::PYSTR PYSTR; + typedef typename CThisSimpleString::PCYSTR PCYSTR; + +public: + CMStringT() : CThisSimpleString() + { + } + + static void __stdcall Construct( CMStringT* pString ) + { + new( pString ) CMStringT; + } + + // Copy constructor + CMStringT( const CMStringT& strSrc ) : + CThisSimpleString( strSrc ) + { + } + + CMStringT( const XCHAR* pszSrc ) : + CThisSimpleString() + { + // nDestLength is in XCHARs + *this = pszSrc; + } + + CMStringT( const YCHAR* pszSrc ) : + CThisSimpleString() + { + *this = pszSrc; + } + + + CMStringT( const unsigned char* pszSrc ) : + CThisSimpleString() + { + *this = reinterpret_cast< const char* >( pszSrc ); + } + + CMStringT( char ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + } + } + + CMStringT( wchar_t ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + //Convert ch to the BaseType + wchar_t pszCh[2] = { ch , 0 }; + int nBaseTypeCharLen = 1; + + if(ch != L'\0') + { + nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); + } + + XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; + StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 ); + //Allocate enough characters in String and flood (replicate) with the (converted character)*nLength + PXSTR pszBuffer = this->GetBuffer( nLength*nBaseTypeCharLen ); + if (nBaseTypeCharLen == 1) + { //Optimization for a common case - wide char translates to 1 ansi/wide char. + StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer ); + } else + { + XCHAR* p=pszBuffer; + for (int i=0 ; i < nLength ;++i) + { + for (int j=0 ; j < nBaseTypeCharLen ;++j) + { + *p=buffBaseTypeChar[j]; + ++p; + } + } + } + this->ReleaseBufferSetLength( nLength*nBaseTypeCharLen ); + delete [] buffBaseTypeChar; + } + } + + CMStringT( const XCHAR* pch, int nLength ) : + CThisSimpleString( pch, nLength ) + { + } + + CMStringT( const YCHAR* pch, int nLength ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength ); + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength ); + this->ReleaseBufferSetLength( nDestLength ); + } + } + + // Destructor + ~CMStringT() + { + } + + // Assignment operators + CMStringT& operator=( const CMStringT& strSrc ) + { + CThisSimpleString::operator=( strSrc ); + + return *this; + } + + CMStringT& operator=( PCXSTR pszSrc ) + { + CThisSimpleString::operator=( pszSrc ); + + return *this; + } + + CMStringT& operator=( PCYSTR pszSrc ) + { + // nDestLength is in XCHARs + int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0; + if ( nDestLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc); + this->ReleaseBufferSetLength( nDestLength ); + } + else + { + this->Empty(); + } + + return *this; + } + + CMStringT& operator=( const unsigned char* pszSrc ) + { + return operator=( reinterpret_cast< const char* >( pszSrc )); + } + + CMStringT& operator=( char ch ) + { + char ach[2] = { ch, 0 }; + + return operator=( ach ); + } + + CMStringT& operator=( wchar_t ch ) + { + wchar_t ach[2] = { ch, 0 }; + + return operator=( ach ); + } + +// CMStringT& operator=( const VARIANT& var ); + + CMStringT& operator+=( const CMStringT& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( const CThisSimpleString& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( PCXSTR pszSrc ) + { + CThisSimpleString::operator+=( pszSrc ); + return *this; + } +// template< int t_nSize > +// CMStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc ) +// { +// CThisSimpleString::operator+=( strSrc ); +// +// return *this; +// } + CMStringT& operator+=( PCYSTR pszSrc ) + { + CMStringT str( pszSrc ); + + return operator+=( str ); + } + + CMStringT& operator+=( char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( unsigned char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( wchar_t ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + // Comparison + + int Compare( PCXSTR psz ) const + { + return StringTraits::StringCompare( this->GetString(), psz ); + } + + int CompareNoCase( PCXSTR psz ) const + { + return StringTraits::StringCompareIgnore( this->GetString(), psz ); + } + + int Collate( PCXSTR psz ) const + { + return StringTraits::StringCollate( this->GetString(), psz ); + } + + int CollateNoCase( PCXSTR psz ) const + { + return StringTraits::StringCollateIgnore( this->GetString(), psz ); + } + + // Advanced manipulation + + // Delete 'nCount' characters, starting at index 'iIndex' + int Delete( int iIndex, int nCount = 1 ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( nCount < 0 ) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount + iIndex > nLength ) + { + nCount = nLength-iIndex; + } + if ( nCount > 0 ) + { + int nNewLength = nLength-nCount; + int nXCHARsToCopy = nLength-(iIndex+nCount)+1; + PXSTR pszBuffer = this->GetBuffer(); + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return this->GetLength(); + } + + // Insert character 'ch' before index 'iIndex' + int Insert( int iIndex, XCHAR ch ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + iIndex = this->GetLength(); + + int nNewLength = this->GetLength()+1; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #endif + pszBuffer[iIndex] = ch; + + this->ReleaseBufferSetLength( nNewLength ); + return nNewLength; + } + + // Insert string 'psz' before index 'iIndex' + int Insert( int iIndex, PCXSTR psz ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + { + iIndex = this->GetLength(); + } + + // nInsertLength and nNewLength are in XCHARs + int nInsertLength = StringTraits::SafeStringLen( psz ); + int nNewLength = this->GetLength(); + if ( nInsertLength > 0 ) + { + nNewLength += nInsertLength; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), psz, nInsertLength*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return nNewLength; + } + + // Replace all occurrences of character 'chOld' with character 'chNew' + int Replace( XCHAR chOld, XCHAR chNew ) + { + int nCount = 0; + + // short-circuit the nop case + if ( chOld != chNew ) + { + // otherwise modify each character that matches in the string + bool bCopied = false; + PXSTR pszBuffer = const_cast< PXSTR >( this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). + + int nLength = this->GetLength(); + int iChar = 0; + while( iChar < nLength ) + { + // replace instances of the specified character only + if ( pszBuffer[iChar] == chOld ) + { + if ( !bCopied ) + { + bCopied = true; + pszBuffer = this->GetBuffer( nLength ); + } + pszBuffer[iChar] = chNew; + nCount++; + } + iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer ); + } + if ( bCopied ) + { + this->ReleaseBufferSetLength( nLength ); + } + } + + return nCount; + } + + // Replace all occurrences of string 'pszOld' with string 'pszNew' + int Replace( PCXSTR pszOld, PCXSTR pszNew ) + { + // can't have empty or NULL lpszOld + + // nSourceLen is in XCHARs + int nSourceLen = StringTraits::SafeStringLen( pszOld ); + if ( nSourceLen == 0 ) + return 0; + // nReplacementLen is in XCHARs + int nReplacementLen = StringTraits::SafeStringLen( pszNew ); + + // loop once to figure out the size of the result string + int nCount = 0; + { + PCXSTR pszStart = this->GetString(); + PCXSTR pszEnd = pszStart+this->GetLength(); + while( pszStart < pszEnd ) + { + PCXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL) + { + nCount++; + pszStart = pszTarget+nSourceLen; + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + } + + // if any changes were made, make them + if ( nCount > 0 ) + { + // if the buffer is too small, just + // allocate a new buffer (slow but sure) + int nOldLength = this->GetLength(); + int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; + + PXSTR pszBuffer = this->GetBuffer( __max( nNewLength, nOldLength )); + + PXSTR pszStart = pszBuffer; + PXSTR pszEnd = pszStart+nOldLength; + + // loop again to actually do the work + while( pszStart < pszEnd ) + { + PXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL ) + { + int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); + memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), + pszTarget+nSourceLen, nBalance*sizeof( XCHAR )); + memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), + pszNew, nReplacementLen*sizeof( XCHAR )); + pszStart = pszTarget+nReplacementLen; + pszTarget[nReplacementLen+nBalance] = 0; + nOldLength += (nReplacementLen-nSourceLen); + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + this->ReleaseBufferSetLength( nNewLength ); + } + + return nCount; + } + + // Remove all occurrences of character 'chRemove' + int Remove( XCHAR chRemove ) + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + + PXSTR pszSource = pszBuffer; + PXSTR pszDest = pszBuffer; + PXSTR pszEnd = pszBuffer+nLength; + + while( pszSource < pszEnd ) + { + PXSTR pszNewSource = StringTraits::CharNext( pszSource ); + if ( *pszSource != chRemove ) + { + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + size_t NewSourceGap = (pszNewSource-pszSource); + PXSTR pszNewDest = pszDest + NewSourceGap; + size_t i = 0; + for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) + { + *pszDest = *pszSource; + pszSource++; + pszDest++; + } + } + pszSource = pszNewSource; + } + *pszDest = 0; + int nCount = int( pszSource-pszDest ); + this->ReleaseBufferSetLength( nLength-nCount ); + + return nCount; + } + + CMStringT Tokenize( PCXSTR pszTokens, int& iStart ) const + { + if ( (pszTokens == NULL) || (*pszTokens == (XCHAR)0)) + { + if (iStart < this->GetLength()) + return CMStringT( this->GetString()+iStart ); + } + else + { + PCXSTR pszPlace = this->GetString()+iStart; + PCXSTR pszEnd = this->GetString()+this->GetLength(); + if ( pszPlace < pszEnd ) + { + int nIncluding = StringTraits::StringSpanIncluding( pszPlace, pszTokens ); + + if ( (pszPlace+nIncluding) < pszEnd ) + { + pszPlace += nIncluding; + int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens ); + + int iFrom = iStart+nIncluding; + int nUntil = nExcluding; + iStart = iFrom+nUntil+1; + + return Mid( iFrom, nUntil ); + } + } + } + + // return empty string, done tokenizing + iStart = -1; + + return CMStringT(); + } + + // find routines + + // Find the first occurrence of character 'ch', starting at index 'iStart' + int Find( XCHAR ch, int iStart = 0 ) const + { + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart >= nLength) + return -1; + + // find first single character + PCXSTR psz = StringTraits::StringFindChar( this->GetString()+iStart, ch ); + + // return -1 if not found and index otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // look for a specific sub-string + + // Find the first occurrence of string 'pszSub', starting at index 'iStart' + int Find( PCXSTR pszSub, int iStart = 0 ) const + { + // iStart is in XCHARs + if(pszSub == NULL) + return -1; + + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart > nLength ) + return -1; + + // find first matching substring + PCXSTR psz = StringTraits::StringFindString( this->GetString()+iStart, pszSub ); + + // return -1 for not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the first occurrence of any of the characters in string 'pszCharSet' + int FindOneOf( PCXSTR pszCharSet ) const + { + PCXSTR psz = StringTraits::StringScanSet( this->GetString(), pszCharSet ); + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the last occurrence of character 'ch' + int ReverseFind( XCHAR ch ) const + { + // find last single character + PCXSTR psz = StringTraits::StringFindCharRev( this->GetString(), ch ); + + // return -1 if not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // manipulation + + // Convert the string to uppercase + CMStringT& MakeUpper() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringUppercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Convert the string to lowercase + CMStringT& MakeLower() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringLowercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Reverse the string + CMStringT& MakeReverse() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringReverse( pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // trimming + + // Remove all trailing whitespace + CMStringT& TrimRight() + { + // find beginning of trailing spaces by starting + // at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::IsSpace( *psz )) + { + if ( pszLast == NULL ) + pszLast = psz; + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at trailing space start + int iLast = int( pszLast-this->GetString()); + + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading whitespace + CMStringT& TrimLeft() + { + // find first non-space character + + PCXSTR psz = this->GetString(); + + while( StringTraits::IsSpace( *psz )) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading and trailing whitespace + CMStringT& Trim() + { + return TrimRight().TrimLeft(); + } + + // Remove all leading and trailing occurrences of character 'chTarget' + CMStringT& Trim( XCHAR chTarget ) + { + return TrimRight( chTarget ).TrimLeft( chTarget ); + } + + // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' + CMStringT& Trim( PCXSTR pszTargets ) + { + return TrimRight( pszTargets ).TrimLeft( pszTargets ); + } + + // trimming anything (either side) + + // Remove all trailing occurrences of character 'chTarget' + CMStringT& TrimRight( XCHAR chTarget ) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( *psz == chTarget ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all trailing occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimRight( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::StringFindChar( pszTargets, *psz ) != NULL ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading occurrences of character 'chTarget' + CMStringT& TrimLeft( XCHAR chTarget ) + { + // find first non-matching character + PCXSTR psz = this->GetString(); + + while( chTarget == *psz ) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimLeft( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + PCXSTR psz = this->GetString(); + while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL)) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Convert the string to the OEM character set + void AnsiToOem() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToOem( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Convert the string to the ANSI character set + void OemToAnsi() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToAnsi( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Very simple sub-string extraction + + // Return the substring starting at index 'iFirst' + CMStringT Mid( int iFirst ) const + { + return Mid( iFirst, this->GetLength()-iFirst ); + } + + // Return the substring starting at index 'iFirst', with length 'nCount' + CMStringT Mid( int iFirst, int nCount ) const + { + // nCount is in XCHARs + + // out-of-bounds requests return sensible things + if (iFirst < 0) + iFirst = 0; + if (nCount < 0) + nCount = 0; + + if ( (iFirst + nCount) > this->GetLength()) + nCount = this->GetLength()-iFirst; + + if ( iFirst > this->GetLength()) + nCount = 0; + + // optimize case of returning entire string + if ( (iFirst == 0) && ((iFirst+nCount) == this->GetLength())) + return *this; + + return CMStringT( this->GetString()+iFirst, nCount ); + } + + // Return the substring consisting of the rightmost 'nCount' characters + CMStringT Right( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + { + return *this; + } + + return CMStringT( this->GetString()+nLength-nCount, nCount ); + } + + // Return the substring consisting of the leftmost 'nCount' characters + CMStringT Left( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + return *this; + + return CMStringT( this->GetString(), nCount ); + } + + // Return the substring consisting of the leftmost characters in the set 'pszCharSet' + CMStringT SpanIncluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanIncluding( this->GetString(), pszCharSet )); + } + + // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' + CMStringT SpanExcluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanExcluding( this->GetString(), pszCharSet )); + } + + // Format data using format string 'pszFormat' + void Format( PCXSTR pszFormat, ... ); + + // Append formatted data using format string 'pszFormat' + void AppendFormat( PCXSTR pszFormat, ... ); + + void AppendFormatV( PCXSTR pszFormat, va_list args ) + { + int nCurrentLength = this->GetLength(); + int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nCurrentLength+nAppendLength ); + StringTraits::Format( pszBuffer+nCurrentLength, + nAppendLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nCurrentLength+nAppendLength ); + } + + void FormatV( PCXSTR pszFormat, va_list args ) + { + int nLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::Format( pszBuffer, nLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nLength ); + } + + // OLE BSTR support + + // Allocate a BSTR containing a copy of the string + BSTR AllocSysString() const + { + BSTR bstrResult = StringTraits::AllocSysString( this->GetString(), this->GetLength()); + return bstrResult; + } + + BSTR SetSysString( BSTR* pbstr ) const + { + StringTraits::ReAllocSysString( this->GetString(), pbstr, this->GetLength()); + return *pbstr; + } + + // Set the string to the value of environment variable 'pszVar' + BOOL GetEnvironmentVariable( PCXSTR pszVar ) + { + ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 ); + BOOL bRetVal = FALSE; + + if ( nLength == 0 ) + { + this->Empty(); + } + else + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength ); + this->ReleaseBuffer(); + bRetVal = TRUE; + } + + return bRetVal; + } + + // Load the string from resource 'nID' + BOOL LoadString( UINT nID ) + { + HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID ); + if ( hInst == NULL ) + return FALSE; + + return LoadString( hInst, nID ); + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, PCXSTR psz2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return strResult; + } + + friend CMStringT __stdcall operator+( PCXSTR psz1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, wchar_t ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, char ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( wchar_t ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( char ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend bool __stdcall operator==( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) == 0; + } + + friend bool __stdcall operator==( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 == str2; + } + + friend bool __stdcall operator==( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 == str2; + } + + friend bool __stdcall operator!=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) != 0; + } + + friend bool __stdcall operator!=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 != str2; + } + + friend bool __stdcall operator!=( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 != str2; + } + + friend bool __stdcall operator<( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) < 0; + } + + friend bool __stdcall operator<( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) < 0; + } + + friend bool __stdcall operator<( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) > 0; + } + + friend bool __stdcall operator>( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) < 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) <= 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) <= 0; + } + + friend bool __stdcall operator<=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) >= 0; + } + + friend bool __stdcall operator>=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) <= 0; + } + + friend bool __stdcall operator==( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() == 1) && (str2[0] == ch1); + } + + friend bool __stdcall operator==( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() == 1) && (str1[0] == ch2); + } + + friend bool __stdcall operator!=( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() != 1) || (str2[0] != ch1); + } + + friend bool __stdcall operator!=( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() != 1) || (str1[0] != ch2); + } +}; + +template< typename BaseType, class StringTraits > +inline void CMStringT<BaseType, StringTraits>::Format(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + FormatV( pszFormat, argList ); + va_end( argList ); +} + +template< typename BaseType, class StringTraits > +inline void CMStringT<BaseType, StringTraits>::AppendFormat(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + AppendFormatV( pszFormat, argList ); + va_end( argList ); +} + +typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; +typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; +typedef CMStringT< TCHAR, ChTraitsCRT< TCHAR > > CMString; diff --git a/protocols/JabberG/src/jabber.cpp b/protocols/JabberG/src/jabber.cpp new file mode 100644 index 0000000000..a3dd31a3fa --- /dev/null +++ b/protocols/JabberG/src/jabber.cpp @@ -0,0 +1,279 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "jabber_rc.h" + +#include <locale.h> + +#include <m_fontservice.h> +#include <m_icolib.h> + +#include "m_assocmgr.h" +#include "m_folders.h" +#include "m_toptoolbar.h" +#include "m_extraicons.h" + +HINSTANCE hInst; + +int hLangpack; + +int g_cbCountries; +struct CountryListEntry* g_countries; + +TCHAR szCoreVersion[100]; + +PLUGININFOEX pluginInfo = { + sizeof( PLUGININFOEX ), + "Jabber Protocol", + __VERSION_DWORD, + "Jabber protocol plugin for Miranda NG.", + "George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura", + "ghazan@miranda-im.org", + "(c) 2005-2012 George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura", + "http://miranda-ng.org/", + UNICODE_AWARE, + {0x144e80a2, 0xd198, 0x428b, {0xac, 0xbe, 0x9d, 0x55, 0xda, 0xcc, 0x7f, 0xde}} // {144E80A2-D198-428b-ACBE-9D55DACC7FDE} +}; + +XML_API xi; +TIME_API tmi; + +CLIST_INTERFACE* pcli; + +///////////////////////////////////////////////////////////////////////////// +// Theme API +BOOL (WINAPI *JabberAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION) = NULL; +BOOL (WINAPI *JabberIsThemeActive)() = NULL; +HRESULT (WINAPI *JabberDrawThemeParentBackground)(HWND, HDC, RECT *) = NULL; +///////////////////////////////////////////////////////////////////////////// + +BOOL jabberChatDllPresent = FALSE; +HANDLE hModulesLoaded, hModulesLoadedTB; + +HANDLE hExtraActivity = NULL; +HANDLE hExtraMood = NULL; + +void JabberUserInfoInit(void); + +int bSecureIM; + +///////////////////////////////////////////////////////////////////////////// +// Protocol instances +static int sttCompareProtocols(const CJabberProto *p1, const CJabberProto *p2) +{ + return lstrcmp(p1->m_tszUserName, p2->m_tszUserName); +} + +LIST<CJabberProto> g_Instances(1, sttCompareProtocols); +///////////////////////////////////////////////////////////////////////////// + +BOOL WINAPI DllMain( HINSTANCE hModule, DWORD, LPVOID ) +{ + hInst = hModule; + return TRUE; +} + +extern "C" __declspec( dllexport ) PLUGININFOEX *MirandaPluginInfoEx( DWORD mirandaVersion ) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +/////////////////////////////////////////////////////////////////////////////// +// OnPreShutdown - prepares Miranda to be shut down + +int __cdecl CJabberProto::OnPreShutdown( WPARAM, LPARAM ) +{ + UI_SAFE_CLOSE_HWND(m_hwndAgentRegInput); + UI_SAFE_CLOSE_HWND(m_hwndRegProgress); + UI_SAFE_CLOSE_HWND(m_hwndMucVoiceList); + UI_SAFE_CLOSE_HWND(m_hwndMucMemberList); + UI_SAFE_CLOSE_HWND(m_hwndMucModeratorList); + UI_SAFE_CLOSE_HWND(m_hwndMucBanList); + UI_SAFE_CLOSE_HWND(m_hwndMucAdminList); + UI_SAFE_CLOSE_HWND(m_hwndMucOwnerList); + UI_SAFE_CLOSE_HWND(m_hwndJabberChangePassword); + UI_SAFE_CLOSE_HWND(m_hwndJabberAddBookmark); + UI_SAFE_CLOSE_HWND(m_hwndPrivacyRule); + + UI_SAFE_CLOSE(m_pDlgPrivacyLists); + UI_SAFE_CLOSE(m_pDlgBookmarks); + UI_SAFE_CLOSE(m_pDlgServiceDiscovery); + UI_SAFE_CLOSE(m_pDlgJabberJoinGroupchat); + UI_SAFE_CLOSE(m_pDlgNotes); + + m_iqManager.ExpireAll(); + m_iqManager.Shutdown(); + m_messageManager.Shutdown(); + m_presenceManager.Shutdown(); + m_sendManager.Shutdown(); + ConsoleUninit(); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnModulesLoaded - execute some code when all plugins are initialized + +static INT_PTR g_SvcParseXmppUri(WPARAM w, LPARAM l) +{ + if (CJabberProto *ppro = JabberChooseInstance(true)) + return ppro->JabberServiceParseXmppURI(w, l); + return 0; +} + +static int OnModulesLoaded( WPARAM, LPARAM ) +{ + hModulesLoadedTB = HookEvent(ME_TTB_MODULELOADED, g_OnToolbarInit); + + bSecureIM = (ServiceExists("SecureIM/IsContactSecured")); + + // file associations manager plugin support + if ( ServiceExists( MS_ASSOCMGR_ADDNEWURLTYPE )) { + CreateServiceFunction("JABBER/*" JS_PARSE_XMPP_URI, g_SvcParseXmppUri ); + AssocMgr_AddNewUrlTypeT( "xmpp:", TranslateT("Jabber Link Protocol"), hInst, IDI_JABBER, "JABBER/*" JS_PARSE_XMPP_URI, 0 ); + } + + // init fontservice for info frame + FontID fontid = {0}; + fontid.cbSize = sizeof(fontid); + strcpy(fontid.group, "Jabber"); + strcpy(fontid.dbSettingsGroup, GLOBAL_SETTING_MODULE); + strcpy(fontid.backgroundGroup, "Jabber"); + strcpy(fontid.backgroundName,"Background"); + fontid.flags = FIDF_DEFAULTVALID; + + fontid.deffontsettings.charset = DEFAULT_CHARSET; + fontid.deffontsettings.colour = GetSysColor(COLOR_WINDOWTEXT); + fontid.deffontsettings.size = -11; + lstrcpyA(fontid.deffontsettings.szFace, "MS Shell Dlg"); + fontid.deffontsettings.style = 0; + + strcpy(fontid.name, "Frame title"); + strcpy(fontid.prefix, "fntFrameTitle"); + fontid.deffontsettings.style = DBFONTF_BOLD; + FontRegister(&fontid); + + strcpy(fontid.name, "Frame text"); + strcpy(fontid.prefix, "fntFrameClock"); + fontid.deffontsettings.style = 0; + FontRegister(&fontid); + + ColourID colourid = {0}; + colourid.cbSize = sizeof(colourid); + strcpy(colourid.group, "Jabber"); + strcpy(colourid.dbSettingsGroup, GLOBAL_SETTING_MODULE); + + strcpy(colourid.name, "Background"); + strcpy(colourid.setting, "clFrameBack"); + colourid.defcolour = GetSysColor(COLOR_WINDOW); + ColourRegister(&colourid); + + // Init extra icons + hExtraActivity = ExtraIcon_Register("activity", "Jabber Activity" /* No icons registered, "working" */); + hExtraMood = ExtraIcon_Register("mood", "Jabber Mood" /* No icons registered, "amazed" */); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnLoad - initialize the plugin instance + +static CJabberProto* jabberProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) +{ + CJabberProto *ppro = new CJabberProto( pszProtoName, tszUserName ); + g_Instances.insert(ppro); + return ppro; +} + +static int jabberProtoUninit( CJabberProto* ppro ) +{ + g_Instances.remove(ppro); + delete ppro; + return 0; +} + +extern "C" int __declspec( dllexport ) Load() +{ + // set the memory, lists & utf8 managers + mir_getXI( &xi ); + mir_getTMI( &tmi ); + mir_getLP( &pluginInfo ); + + WORD v[4]; + CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)v); + mir_sntprintf(szCoreVersion, SIZEOF(szCoreVersion), _T("%d.%d.%d.%d"), v[0], v[1], v[2], v[3]); + + CallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM )&g_cbCountries, ( LPARAM )&g_countries ); + + setlocale(LC_ALL, ""); + + pcli = ( CLIST_INTERFACE* )CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, (LPARAM)hInst); + + // Register protocol module + PROTOCOLDESCRIPTOR pd; + ZeroMemory( &pd, sizeof( PROTOCOLDESCRIPTOR )); + pd.cbSize = sizeof( PROTOCOLDESCRIPTOR ); + pd.szName = "JABBER"; + pd.fnInit = ( pfnInitProto )jabberProtoInit; + pd.fnUninit = ( pfnUninitProto )jabberProtoUninit; + pd.type = PROTOTYPE_PROTOCOL; + CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd ); + + // Load some fuctions + HMODULE hDll; + if ( hDll = GetModuleHandleA( "gdi32.dll" )) + JabberAlphaBlend = (BOOL (WINAPI *)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION)) GetProcAddress(hDll, "GdiAlphaBlend"); + if ( JabberAlphaBlend == NULL && ( hDll = LoadLibraryA("msimg32.dll" ))) + JabberAlphaBlend = (BOOL (WINAPI *)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION)) GetProcAddress(hDll, "AlphaBlend"); + + if ( IsWinVerXPPlus()) { + if ( hDll = GetModuleHandleA("uxtheme")) { + JabberDrawThemeParentBackground = (HRESULT (WINAPI *)(HWND,HDC,RECT *))GetProcAddress(hDll, "DrawThemeParentBackground"); + JabberIsThemeActive = (BOOL (WINAPI *)())GetProcAddress(hDll, "IsThemeActive"); + } } + + g_IconsInit(); + g_MenuInit(); + hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + JabberUserInfoInit(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// Unload - destroy the plugin instance + +extern "C" int __declspec( dllexport ) Unload( void ) +{ + UnhookEvent(hModulesLoaded); + UnhookEvent(hModulesLoadedTB); + + g_MenuUninit(); + + g_Instances.destroy(); + return 0; +} diff --git a/protocols/JabberG/src/jabber.h b/protocols/JabberG/src/jabber.h new file mode 100644 index 0000000000..957b7d66bf --- /dev/null +++ b/protocols/JabberG/src/jabber.h @@ -0,0 +1,767 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_H_ +#define _JABBER_H_ + +#ifdef _MSC_VER + #pragma warning(disable:4706 4121 4127) +#endif + +#define MIRANDA_VER 0x0A00 + +#include "m_stdhdr.h" + +#define LISTFOREACH(var__, obj__, list__) \ + for (int var__ = 0; (var__ = obj__->ListFindNext(list__, var__)) >= 0; ++var__) +#define LISTFOREACH_NODEF(var__, obj__, list__) \ + for (var__ = 0; (var__ = obj__->ListFindNext(list__, var__)) >= 0; ++var__) + +/******************************************************************* + * Global header files + *******************************************************************/ +#define _WIN32_WINNT 0x501 +#define _WIN32_IE 0x501 +#include <windows.h> +#include <commctrl.h> +#include <uxtheme.h> +#include <process.h> +#include <stdio.h> +#include <stdarg.h> +#include <time.h> +#include <limits.h> +#include <ctype.h> +#include <stdarg.h> +#include <newpluginapi.h> +#include <m_system.h> +#include <m_system_cpp.h> +#include <m_netlib.h> +#include <m_protomod.h> +#include <m_protosvc.h> +#include <m_protoint.h> +#include <m_clist.h> +#include <m_clui.h> +#include <m_options.h> +#include <m_userinfo.h> +#include <m_database.h> +#include <m_langpack.h> +#include <m_utils.h> +#include <m_message.h> +#include <m_skin.h> +#include <m_chat.h> +#include <m_clc.h> +#include <m_clistint.h> +#include <m_button.h> +#include <m_avatars.h> +#include <m_idle.h> +#include <m_timezones.h> +#include <m_jabber.h> +#include <m_fingerprint.h> +#include <win2k.h> + +#include "../../plugins/zlib/zlib.h" + +#include "resource.h" +#include "version.h" + +#include "MString.h" + +#include "jabber_xml.h" +#include "jabber_byte.h" +#include "jabber_ibb.h" +#include "jabber_db_utils.h" +#include "ui_utils.h" + +struct CJabberProto; + +class CJabberDlgBase: public CProtoDlgBase<CJabberProto> +{ + typedef CProtoDlgBase<CJabberProto> CSuper; +protected: + __inline CJabberDlgBase(CJabberProto *proto, int idDialog, HWND parent, bool show_label=true ) : + CSuper( proto, idDialog, parent, show_label ) + { + } + + int Resizer(UTILRESIZECONTROL *urc) + { + switch (urc->wId) { + case IDC_HEADERBAR: + urc->rcItem.right = urc->dlgNewSize.cx; + return 0; + } + + return CSuper::Resizer(urc); + } +}; + +#if !defined(OPENFILENAME_SIZE_VERSION_400) + #define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME) +#endif + +/******************************************************************* + * Global constants + *******************************************************************/ + +#define GLOBAL_SETTING_PREFIX "JABBER" +#define GLOBAL_SETTING_MODULE "JABBER" + +#define JABBER_DEFAULT_PORT 5222 +#define JABBER_IQID "mir_" +#define JABBER_MAX_JID_LEN 1024 + +#define JABBER_GC_MSG_QUIT LPGENT("I'm happy Miranda NG user. Get it at http://miranda-ng.org/.") +#define JABBER_GC_MSG_SLAP LPGENT("/me slaps %s around a bit with a large trout") + +// registered db event types +#define JABBER_DB_EVENT_TYPE_CHATSTATES 2000 +#define JS_DB_GETEVENTTEXT_CHATSTATES "/GetEventText2000" +#define JABBER_DB_EVENT_CHATSTATES_GONE 1 +#define JABBER_DB_EVENT_TYPE_PRESENCE 2001 +#define JS_DB_GETEVENTTEXT_PRESENCE "/GetEventText2001" +#define JABBER_DB_EVENT_PRESENCE_SUBSCRIBE 1 +#define JABBER_DB_EVENT_PRESENCE_SUBSCRIBED 2 +#define JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE 3 +#define JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED 4 +#define JABBER_DB_EVENT_PRESENCE_ERROR 5 + +// User-defined message +#define WM_JABBER_REGDLG_UPDATE (WM_PROTO_LAST + 100) +#define WM_JABBER_AGENT_REFRESH (WM_PROTO_LAST + 101) +#define WM_JABBER_TRANSPORT_REFRESH (WM_PROTO_LAST + 102) +#define WM_JABBER_REGINPUT_ACTIVATE (WM_PROTO_LAST + 103) +#define WM_JABBER_REFRESH WM_PROTO_REFRESH +#define WM_JABBER_CHECK_ONLINE WM_PROTO_CHECK_ONLINE +#define WM_JABBER_ACTIVATE WM_PROTO_ACTIVATE +#define WM_JABBER_CHANGED (WM_PROTO_LAST + 106) +#define WM_JABBER_SET_FONT (WM_PROTO_LAST + 108) +#define WM_JABBER_FLASHWND (WM_PROTO_LAST + 109) +#define WM_JABBER_GC_MEMBER_ADD (WM_PROTO_LAST + 110) +#define WM_JABBER_GC_FORCE_QUIT (WM_PROTO_LAST + 111) +#define WM_JABBER_SHUTDOWN (WM_PROTO_LAST + 112) +#define WM_JABBER_SMILEY (WM_PROTO_LAST + 113) +#define WM_JABBER_JOIN (WM_PROTO_LAST + 114) +#define WM_JABBER_ADD_TO_ROSTER (WM_PROTO_LAST + 115) +#define WM_JABBER_ADD_TO_BOOKMARKS (WM_PROTO_LAST + 116) +#define WM_JABBER_REFRESH_VCARD (WM_PROTO_LAST + 117) + + +// Error code +#define JABBER_ERROR_REDIRECT 302 +#define JABBER_ERROR_BAD_REQUEST 400 +#define JABBER_ERROR_UNAUTHORIZED 401 +#define JABBER_ERROR_PAYMENT_REQUIRED 402 +#define JABBER_ERROR_FORBIDDEN 403 +#define JABBER_ERROR_NOT_FOUND 404 +#define JABBER_ERROR_NOT_ALLOWED 405 +#define JABBER_ERROR_NOT_ACCEPTABLE 406 +#define JABBER_ERROR_REGISTRATION_REQUIRED 407 +#define JABBER_ERROR_REQUEST_TIMEOUT 408 +#define JABBER_ERROR_CONFLICT 409 +#define JABBER_ERROR_INTERNAL_SERVER_ERROR 500 +#define JABBER_ERROR_NOT_IMPLEMENTED 501 +#define JABBER_ERROR_REMOTE_SERVER_ERROR 502 +#define JABBER_ERROR_SERVICE_UNAVAILABLE 503 +#define JABBER_ERROR_REMOTE_SERVER_TIMEOUT 504 + +// Vcard flags +#define JABBER_VCEMAIL_HOME 1 +#define JABBER_VCEMAIL_WORK 2 +#define JABBER_VCEMAIL_INTERNET 4 +#define JABBER_VCEMAIL_X400 8 + +#define JABBER_VCTEL_HOME 0x0001 +#define JABBER_VCTEL_WORK 0x0002 +#define JABBER_VCTEL_VOICE 0x0004 +#define JABBER_VCTEL_FAX 0x0008 +#define JABBER_VCTEL_PAGER 0x0010 +#define JABBER_VCTEL_MSG 0x0020 +#define JABBER_VCTEL_CELL 0x0040 +#define JABBER_VCTEL_VIDEO 0x0080 +#define JABBER_VCTEL_BBS 0x0100 +#define JABBER_VCTEL_MODEM 0x0200 +#define JABBER_VCTEL_ISDN 0x0400 +#define JABBER_VCTEL_PCS 0x0800 + +// File transfer setting +#define JABBER_OPTION_FT_DIRECT 0 // Direct connection +#define JABBER_OPTION_FT_PASS 1 // Use PASS server +#define JABBER_OPTION_FT_PROXY 2 // Use proxy with local port forwarding + +// Font style saved in DB +#define JABBER_FONT_BOLD 1 +#define JABBER_FONT_ITALIC 2 + +// Font for groupchat log dialog +#define JABBER_GCLOG_NUM_FONT 6 // 6 fonts ( 0:send, 1:msg, 2:time, 3:nick, 4:sys, 5:/me ) + +// Old SDK don't have this +#ifndef SPI_GETSCREENSAVERRUNNING +#define SPI_GETSCREENSAVERRUNNING 114 +#endif + +// Icon list +enum { + JABBER_IDI_GCOWNER = 0, + JABBER_IDI_GCADMIN, + JABBER_IDI_GCMODERATOR, + JABBER_IDI_GCVOICE, + JABBER_ICON_TOTAL +}; + +// Services and Events +#define JS_PARSE_XMPP_URI "/ParseXmppURI" + +// XEP-0224 support (Attention/Nudge) +#define JS_SEND_NUDGE "/SendNudge" +#define JE_NUDGE "/Nudge" + +// Called when contact changes custom status and extra icon is set to clist_mw +//wParam = hContact // contact changing status +//lParam = hIcon // HANDLE to clist extra icon set as custom status +#define JE_CUSTOMSTATUS_EXTRAICON_CHANGED "/XStatusExtraIconChanged" +#define JE_CUSTOMSTATUS_CHANGED "/XStatusChanged" + +#define LR_BIGICON 0x40 + +#define JS_SENDXML "/SendXML" // Warning: This service is obsolete. Use IJabberNetInterface::SendXmlNode() instead. +#define JS_GETADVANCEDSTATUSICON "/GetAdvancedStatusIcon" +#define JS_GETCUSTOMSTATUSICON "/GetXStatusIcon" +#define JS_GETXSTATUS "/GetXStatus" +#define JS_SETXSTATUS "/SetXStatus" + +#define JS_HTTP_AUTH "/HttpAuthRequest" +#define JS_INCOMING_NOTE_EVENT "/IncomingNoteEvent" + +#define DBSETTING_DISPLAY_UID "display_uid" +#define DBSETTING_XSTATUSID "XStatusId" +#define DBSETTING_XSTATUSNAME "XStatusName" +#define DBSETTING_XSTATUSMSG "XStatusMsg" + +#define ADVSTATUS_MOOD "mood" +#define ADVSTATUS_ACTIVITY "activity" +#define ADVSTATUS_TUNE "tune" + +#define ADVSTATUS_VAL_ID "id" +#define ADVSTATUS_VAL_ICON "icon" +#define ADVSTATUS_VAL_TITLE "title" +#define ADVSTATUS_VAL_TEXT "text" + +struct CJabberHttpAuthParams +{ + enum {IQ = 1, MSG = 2} m_nType; + TCHAR *m_szFrom; + TCHAR *m_szIqId; + TCHAR *m_szThreadId; + TCHAR *m_szId; + TCHAR *m_szMethod; + TCHAR *m_szUrl; + CJabberHttpAuthParams() + { + ZeroMemory(this, sizeof(CJabberHttpAuthParams)); + } + ~CJabberHttpAuthParams() + { + Free(); + } + void Free() + { + mir_free(m_szFrom); + mir_free(m_szIqId); + mir_free(m_szThreadId); + mir_free(m_szId); + mir_free(m_szMethod); + mir_free(m_szUrl); + ZeroMemory(this, sizeof(CJabberHttpAuthParams)); + } +}; + +/******************************************************************* + * Global data structures and data type definitions + *******************************************************************/ +typedef HANDLE JABBER_SOCKET; + +enum JABBER_SESSION_TYPE +{ + JABBER_SESSION_NORMAL, + JABBER_SESSION_REGISTER +}; + +#define CAPS_BOOKMARK 0x0001 +#define CAPS_BOOKMARKS_LOADED 0x8000 + +#define ZLIB_CHUNK_SIZE 2048 + +#include "jabber_caps.h" + +#define JABBER_LOGIN_ROSTER 0x0001 +#define JABBER_LOGIN_BOOKMARKS 0x0002 +#define JABBER_LOGIN_SERVERINFO 0x0004 +#define JABBER_LOGIN_BOOKMARKS_AJ 0x0008 + +struct ThreadData +{ + ThreadData( CJabberProto* _ppro, JABBER_SESSION_TYPE parType ); + ~ThreadData(); + + HANDLE hThread; + JABBER_SESSION_TYPE type; + + // network support + JABBER_SOCKET s; + BOOL useSSL; + HANDLE iomutex; // protects i/o operations + CJabberProto* proto; + + // XEP-0138 (Compression support) + BOOL useZlib; + z_stream zStreamIn,zStreamOut; + bool zRecvReady; + int zRecvDatalen; + char* zRecvData; + + void xmpp_client_query( void ); + + BOOL zlibInit( void ); + void zlibUninit(); + int zlibSend( char* data, int datalen ); + int zlibRecv( char* data, long datalen ); + + // for nick names resolving + int resolveID; + HANDLE resolveContact; + + // features & registration + HWND reg_hwndDlg; + BOOL reg_done, bIsSessionAvailable; + class TJabberAuth* auth; + JabberCapsBits jabberServerCaps; + BOOL bBookmarksLoaded; + DWORD dwLoginRqs; + + // connection & login data + TCHAR username[512]; + TCHAR password[512]; + char server[128]; + char manualHost[128]; + TCHAR resource[128]; + TCHAR fullJID[JABBER_MAX_JID_LEN]; + WORD port; + TCHAR newPassword[512]; + + void close( void ); + void shutdown( void ); + int recv( char* buf, size_t len ); + int send( char* buffer, int bufsize ); + int send( const char* fmt, ... ); + int send( HXML node ); + + int recvws( char* buffer, size_t bufsize, int flags ); + int sendws( char* buffer, size_t bufsize, int flags ); +}; + +struct JABBER_MODEMSGS +{ + TCHAR* szOnline; + TCHAR* szAway; + TCHAR* szNa; + TCHAR* szDnd; + TCHAR* szFreechat; +}; + +struct JABBER_REG_ACCOUNT +{ + TCHAR username[512]; + TCHAR password[512]; + char server[128]; + char manualHost[128]; + WORD port; + BOOL useSSL; +}; + +typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM, FT_IBB } JABBER_FT_TYPE; +typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED } JABBER_FILE_STATE; + +struct filetransfer +{ + filetransfer( CJabberProto* proto ); + ~filetransfer(); + + void close(); + void complete(); + int create(); + + PROTOFILETRANSFERSTATUS std; + +// HANDLE hContact; + JABBER_FT_TYPE type; + JABBER_SOCKET s; + JABBER_FILE_STATE state; + TCHAR* jid; + int fileId; + TCHAR* iqId; + TCHAR* sid; + int bCompleted; + HANDLE hWaitEvent; + + // For type == FT_BYTESTREAM + JABBER_BYTE_TRANSFER *jbt; + + JABBER_IBB_TRANSFER *jibb; + + // Used by file receiving only + char* httpHostName; + WORD httpPort; + TCHAR* httpPath; + unsigned __int64 dwExpectedRecvFileSize; + + // Used by file sending only + HANDLE hFileEvent; + unsigned __int64 *fileSize; + TCHAR* szDescription; + + CJabberProto* ppro; +}; + +struct JABBER_SEARCH_RESULT +{ + PROTOSEARCHRESULT hdr; + TCHAR jid[JABBER_MAX_JID_LEN]; +}; + +struct JABBER_GCLOG_FONT +{ + char face[LF_FACESIZE]; // LF_FACESIZE is from LOGFONT struct + BYTE style; + char size; // signed + BYTE charset; + COLORREF color; +}; + +struct JABBER_FIELD_MAP +{ + int id; + char* name; +}; + +enum JABBER_MUC_JIDLIST_TYPE +{ + MUC_VOICELIST, + MUC_MEMBERLIST, + MUC_MODERATORLIST, + MUC_BANLIST, + MUC_ADMINLIST, + MUC_OWNERLIST +}; + +struct JABBER_MUC_JIDLIST_INFO +{ + ~JABBER_MUC_JIDLIST_INFO(); + + JABBER_MUC_JIDLIST_TYPE type; + TCHAR* roomJid; // filled-in by the WM_JABBER_REFRESH code + HXML iqNode; + CJabberProto* ppro; + + TCHAR* type2str( void ) const; +}; + +typedef void ( CJabberProto::*JABBER_FORM_SUBMIT_FUNC )( HXML values, void *userdata ); + +//---- jabber_treelist.c ------------------------------------------------ + +typedef struct TTreeList_ItemInfo *HTREELISTITEM; +enum { TLM_TREE, TLM_REPORT }; + +//---- proto frame ------------------------------------------------ + +class CJabberInfoFrameItem; + +struct CJabberInfoFrame_Event +{ + enum { CLICK, DESTROY } m_event; + const char *m_pszName; + LPARAM m_pUserData; +}; + +class CJabberInfoFrame +{ +public: + CJabberInfoFrame(CJabberProto *proto); + ~CJabberInfoFrame(); + + void CreateInfoItem(char *pszName, bool bCompact=false, LPARAM pUserData=0); + void SetInfoItemCallback(char *pszName, void (CJabberProto::*onEvent)(CJabberInfoFrame_Event *)); + void UpdateInfoItem(char *pszName, HANDLE hIcolibItem, TCHAR *pszText); + void ShowInfoItem(char *pszName, bool bShow); + void RemoveInfoItem(char *pszName); + + void LockUpdates(); + void Update(); + +private: + CJabberProto *m_proto; + HWND m_hwnd; + int m_frameId; + bool m_compact; + OBJLIST<CJabberInfoFrameItem> m_pItems; + int m_hiddenItemCount; + int m_clickedItem; + bool m_bLocked; + int m_nextTooltipId; + HWND m_hwndToolTip; + + HANDLE m_hhkFontsChanged; + HFONT m_hfntTitle, m_hfntText; + COLORREF m_clTitle, m_clText, m_clBack; + + static void InitClass(); + static LRESULT CALLBACK GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam); + + void ReloadFonts(); + void UpdateSize(); + + void RemoveTooltip(int id); + void SetToolTip(int id, RECT *rc, TCHAR *pszText); + + void PaintSkinGlyph(HDC hdc, RECT *rc, char **glyphs, COLORREF fallback); + void PaintCompact(HDC hdc); + void PaintNormal(HDC hdc); + + enum + { + SZ_FRAMEPADDING = 2, // padding inside frame + SZ_LINEPADDING = 0, // line height will be incremented by this value + SZ_LINESPACING = 0, // between lines + SZ_ICONSPACING = 2, // between icon and text + }; +}; + +#include "jabber_list.h" +#include "jabber_proto.h" + +/******************************************************************* + * Global variables + *******************************************************************/ +extern HINSTANCE hInst; +extern BOOL jabberChatDllPresent; + +extern HANDLE hExtraMood; +extern HANDLE hExtraActivity; + +// Theme API +extern BOOL (WINAPI *JabberAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); +extern BOOL (WINAPI *JabberIsThemeActive)(); +extern HRESULT (WINAPI *JabberDrawThemeParentBackground)(HWND, HDC, RECT *); + +extern const TCHAR xmlnsOwner[]; +extern TCHAR szCoreVersion[]; + +extern int g_cbCountries; +extern struct CountryListEntry* g_countries; + +/******************************************************************* + * Function declarations + *******************************************************************/ + +//---- jabber_treelist.c ------------------------------------------------ + +void TreeList_Create(HWND hwnd); +void TreeList_Destroy(HWND hwnd); +void TreeList_Reset(HWND hwnd); +void TreeList_SetMode(HWND hwnd, int mode); +HTREELISTITEM TreeList_GetActiveItem(HWND hwnd); +void TreeList_SetSortMode(HWND hwnd, int col, BOOL descending); +void TreeList_SetFilter(HWND hwnd, TCHAR *filter); +HTREELISTITEM TreeList_AddItem(HWND hwnd, HTREELISTITEM hParent, TCHAR *text, LPARAM data); +void TreeList_ResetItem(HWND hwnd, HTREELISTITEM hParent); +void TreeList_MakeFakeParent(HTREELISTITEM hItem, BOOL flag); +void TreeList_AppendColumn(HTREELISTITEM hItem, TCHAR *text); +int TreeList_AddIcon(HWND hwnd, HICON hIcon, int iOverlay); +void TreeList_SetIcon(HTREELISTITEM hItem, int iIcon, int iOverlay); +LPARAM TreeList_GetData(HTREELISTITEM hItem); +HTREELISTITEM TreeList_GetRoot(HWND hwnd); +int TreeList_GetChildrenCount(HTREELISTITEM hItem); +HTREELISTITEM TreeList_GetChild(HTREELISTITEM hItem, int i); +void sttTreeList_RecursiveApply(HTREELISTITEM hItem, void (*func)(HTREELISTITEM, LPARAM), LPARAM data); +void TreeList_Update(HWND hwnd); +BOOL TreeList_ProcessMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT idc, BOOL *result); + +//---- jabber_form.c ------------------------------------------------ + +enum TJabberFormControlType +{ + JFORM_CTYPE_NONE, JFORM_CTYPE_TEXT_PRIVATE, JFORM_CTYPE_TEXT_MULTI, + JFORM_CTYPE_BOOLEAN, JFORM_CTYPE_LIST_SINGLE, JFORM_CTYPE_LIST_MULTI, + JFORM_CTYPE_FIXED, JFORM_CTYPE_HIDDEN, JFORM_CTYPE_TEXT_SINGLE +}; + +typedef struct TJabberFormControlInfo *HJFORMCTRL; +typedef struct TJabberFormLayoutInfo *HJFORMLAYOUT; + +void JabberFormCreateUI( HWND hwndStatic, HXML xNode, int *formHeight, BOOL bCompact = FALSE ); +void JabberFormDestroyUI(HWND hwndStatic); +void JabberFormSetInstruction( HWND hwndForm, const TCHAR *text ); +HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic); // use mir_free to destroy +HJFORMCTRL JabberFormAppendControl(HWND hwndStatic, HJFORMLAYOUT layout_info, TJabberFormControlType type, const TCHAR *labelStr, const TCHAR *valueStr); +void JabberFormAddListItem(HJFORMCTRL item, const TCHAR *text, bool selected); +void JabberFormLayoutControls(HWND hwndStatic, HJFORMLAYOUT layout_info, int *formHeight); + +void JabberFormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ); + +HXML JabberFormGetData( HWND hwndStatic, HXML xNode ); + +//---- jabber_icolib.c ---------------------------------------------- + +void g_IconsInit(); +HANDLE g_GetIconHandle( int iconId ); +HICON g_LoadIconEx( const char* name, bool big = false ); +void g_ReleaseIcon( HICON hIcon ); + +void ImageList_AddIcon_Icolib( HIMAGELIST hIml, HICON hIcon ); +void WindowSetIcon(HWND hWnd, CJabberProto *proto, const char* name); +void WindowFreeIcon(HWND hWnd); + +int ReloadIconsEventHook(WPARAM wParam, LPARAM lParam); + +//---- jabber_libstr.c ---------------------------------------------- + +int lstrcmp_null(const TCHAR *s1, const TCHAR *s2); + +//---- jabber_menu.c ------------------------------------------------ + +void g_MenuInit(); +void g_MenuUninit(); +int g_OnToolbarInit(WPARAM, LPARAM); + +//---- jabber_misc.c ------------------------------------------------ + +void JabberChatDllError( void ); +int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 ); +void JabberContactListCreateGroup( TCHAR* groupName ); +TCHAR* EscapeChatTags(TCHAR* pszText); +TCHAR* UnEscapeChatTags(TCHAR* str_in); + +//---- jabber_adhoc.cpp --------------------------------------------- + +struct CJabberAdhocStartupParams +{ + TCHAR* m_szJid; + TCHAR* m_szNode; + CJabberProto* m_pProto; + + CJabberAdhocStartupParams( CJabberProto* proto, TCHAR* szJid, TCHAR* szNode = NULL ) + { + m_pProto = proto; + m_szJid = mir_tstrdup( szJid ); + m_szNode = szNode ? mir_tstrdup( szNode ) : NULL; + } + ~CJabberAdhocStartupParams() + { + if ( m_szJid ) + mir_free( m_szJid ); + if ( m_szNode ) + mir_free( m_szNode ); + } +}; + +struct JabberAdHocData +{ + CJabberProto* proto; + int CurrentHeight; + int curPos; + int frameHeight; + RECT frameRect; + HXML AdHocNode; + HXML CommandsNode; + TCHAR* ResponderJID; +}; + +//---- jabber_std.cpp ------------------------------------------------------------------- + +void __fastcall JFreeVariant( DBVARIANT* dbv ); +char* __fastcall JTranslate( const char* str ); + +//---- jabber_util.cpp ------------------------------------------------------------------ + +struct TStringPairsElem +{ + const char *name, *value; +}; + +struct TStringPairs +{ + TStringPairs( char* ); + ~TStringPairs(); + + const char* operator[]( const char* name ) const; + + int numElems; + TStringPairsElem* elems; +}; + +TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid ); +TCHAR* JabberPrepareJid( LPCTSTR jid ); +char* __stdcall JabberUrlDecode( char* str ); +void __stdcall JabberUrlDecodeW( WCHAR* str ); +char* __stdcall JabberUrlEncode( const char* str ); +char* __stdcall JabberSha1( char* str ); +TCHAR* __stdcall JabberStrFixLines( const TCHAR* str ); +char* __stdcall JabberUnixToDos( const char* str ); +WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str ); +void __stdcall JabberHttpUrlDecode( TCHAR* str ); +TCHAR* __stdcall JabberHttpUrlEncode( const TCHAR* str ); +int __stdcall JabberCombineStatus( int status1, int status2 ); +TCHAR* __stdcall JabberErrorStr( int errorCode ); +TCHAR* __stdcall JabberErrorMsg( HXML errorNode, int* errorCode = NULL ); +void __stdcall JabberUtfToTchar( const char* str, size_t cbLen, LPTSTR& dest ); +char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen ); +char* __stdcall JabberBase64Decode( const char* buffer, int *resultLen ); +char* __stdcall JabberBase64DecodeW( const WCHAR* buffer, int *resultLen ); +time_t __stdcall JabberIsoToUnixTime( const TCHAR* stamp ); +void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ); +TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen ); +int __stdcall JabberGetPictureType( const char* buf ); +int __stdcall JabberGetPacketID( HXML n ); + +#define JabberUnixToDosT JabberUnixToDosW +#define JabberBase64DecodeT JabberBase64DecodeW + +const TCHAR *JabberStrIStr( const TCHAR *str, const TCHAR *substr); +void JabberCopyText(HWND hwnd, TCHAR *text); +void JabberBitmapPremultiplyChannels(HBITMAP hBitmap); +CJabberProto *JabberChooseInstance(bool bIsLink=false); + +//---- jabber_xml.cpp ------------------------------------------------------------------- + +void strdel( char* parBuffer, int len ); + +//---- jabber_userinfo.cpp -------------------------------------------------------------- + +void JabberUserInfoUpdate( HANDLE hContact ); + +//---- jabber_iq_handlers.cpp +BOOL GetOSDisplayString(LPTSTR pszOS, int BUFSIZE); + +#endif diff --git a/protocols/JabberG/src/jabber_adhoc.cpp b/protocols/JabberG/src/jabber_adhoc.cpp new file mode 100644 index 0000000000..09884e79df --- /dev/null +++ b/protocols/JabberG/src/jabber_adhoc.cpp @@ -0,0 +1,609 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2007 Artem Shpynov +Copyright ( C ) 2005-12 George Hazan + +Module implements an XMPP protocol extension for reporting and executing ad-hoc, +human-oriented commands according to XEP-0050: Ad-Hoc Commands +http://www.xmpp.org/extensions/xep-0050.html + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <CommCtrl.h> +#include "jabber_iq.h" +#include "m_clui.h" +#include "jabber_caps.h" + + +#define ShowDlgItem( a, b, c ) ShowWindow( GetDlgItem( a, b ), c ) +#define EnableDlgItem( a, b, c ) EnableWindow( GetDlgItem( a, b ), c ) + +enum +{ + JAHM_COMMANDLISTRESULT = WM_USER+1, + JAHM_PROCESSRESULT +}; + +//Declarations +static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ); + +//implementations + +// convert iqID to dialog hwnd +HWND CJabberProto::GetWindowFromIq( HXML iqNode ) +{ + const TCHAR* id = xmlGetAttrValue( iqNode, _T( "id" )); + if (_tcslen(id)>4) + return (HWND)_tcstol(id+4,NULL,10); + return m_hwndCommandWindow; + +} +// Callback to clear form content +static BOOL CALLBACK sttDeleteChildWindowsProc( HWND hwnd, LPARAM ) +{ + DestroyWindow( hwnd ); + return TRUE; +} + +static void sttEnableControls( HWND hwndDlg, BOOL bEnable, const int * controlsID ) +{ + int i=0; + while ( controlsID[i]!=0 ) + EnableDlgItem( hwndDlg, controlsID[i++], bEnable ); +} + +static void sttShowControls( HWND hwndDlg, BOOL bShow, int * controlsID ) +{ + int i=0; + while ( controlsID[i]!=0 ) + ShowDlgItem( hwndDlg, controlsID[i++], (bShow) ? SW_SHOW : SW_HIDE ); +} + +static void JabberAdHoc_RefreshFrameScroll(HWND hwndDlg, JabberAdHocData * dat) +{ + HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); + HWND hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); + RECT rc; + RECT rcScrollRc; + GetClientRect( hFrame, &rc ); + GetClientRect( hFrame, &dat->frameRect ); + GetWindowRect( hwndScroll, &rcScrollRc ); + dat->frameRect.right-=(rcScrollRc.right-rcScrollRc.left); + dat->frameHeight = rc.bottom-rc.top; + if ( dat->frameHeight < dat->CurrentHeight) { + ShowWindow( hwndScroll, SW_SHOW ); + EnableWindow( hwndScroll, TRUE ); + } + else ShowWindow( hwndScroll, SW_HIDE ); + + SetScrollRange( hwndScroll, SB_CTL, 0, dat->CurrentHeight-dat->frameHeight, FALSE ); + +} + +////////////////////////////////////////////////////////////////////////// +// Iq handlers +// Forwards to dialog window procedure + +void CJabberProto::OnIqResult_ListOfCommands( HXML iqNode ) +{ + SendMessage( GetWindowFromIq( iqNode ), JAHM_COMMANDLISTRESULT, 0, (LPARAM)xi.copyNode( iqNode )); +} + +void CJabberProto::OnIqResult_CommandExecution( HXML iqNode ) +{ + SendMessage( GetWindowFromIq( iqNode ), JAHM_PROCESSRESULT, (WPARAM)xi.copyNode( iqNode ), 0 ); +} + +int CJabberProto::AdHoc_RequestListOfCommands( TCHAR * szResponder, HWND hwndDlg ) +{ + int iqId = (int)hwndDlg; + IqAdd( iqId, IQ_PROC_DISCOCOMMANDS, &CJabberProto::OnIqResult_ListOfCommands ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szResponder ) << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)) + << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS))); + return iqId; +} + +int CJabberProto::AdHoc_ExecuteCommand( HWND hwndDlg, TCHAR*, JabberAdHocData* dat ) +{ + for ( int i = 1; ; i++ ) { + HXML itemNode = xmlGetNthChild( dat->CommandsNode, _T("item"), i ); + if ( !itemNode) + break; + if ( !IsDlgButtonChecked( GetDlgItem( hwndDlg, IDC_FRAME ), i )) + continue; + const TCHAR* node = xmlGetAttrValue( itemNode, _T("node")); + if ( node ) { + const TCHAR *jid2 = xmlGetAttrValue( itemNode, _T("jid")); + + int iqId = (int)hwndDlg; + IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); + m_ThreadInfo->send( + XmlNodeIq( _T("set"), iqId, jid2 ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), node ) << XATTR( _T("action"), _T("execute"))); + + EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE ); + SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" )); + } } + + xi.destroyNode( dat->CommandsNode ); dat->CommandsNode = NULL; + return TRUE; +} + +//Messages handlers +int CJabberProto::AdHoc_OnJAHMCommandListResult( HWND hwndDlg, HXML iqNode, JabberAdHocData* dat ) +{ + int nodeIdx = 0; + const TCHAR * type = xmlGetAttrValue( iqNode, _T("type")); + if ( !type || !_tcscmp( type, _T( "error" )) ) { + // error occurred here + TCHAR buff[255]; + const TCHAR* code = NULL; + const TCHAR* description = NULL; + + HXML errorNode = xmlGetChild( iqNode, "error" ); + if ( errorNode ) { + code = xmlGetAttrValue( errorNode, _T("code")); + description = xmlGetText( errorNode ); + } + _sntprintf( buff, SIZEOF(buff), TranslateT( "Error %s %s" ), (code) ? code : _T(""), (description) ? description : _T("")); + JabberFormSetInstruction( hwndDlg, buff ); + } + else if ( !_tcscmp( type, _T("result")) ) { + BOOL validResponse = FALSE; + EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 ); + dat->CurrentHeight = 0; + dat->curPos = 0; + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode ) { + const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T( "xmlns" )); + const TCHAR* node = xmlGetAttrValue( queryNode, _T( "node" )); + if ( xmlns && node + && !_tcscmp( xmlns, _T( JABBER_FEAT_DISCO_ITEMS )) + && !_tcscmp( node, _T( JABBER_FEAT_COMMANDS )) ) + validResponse = TRUE; + } + if ( queryNode && xmlGetChild( queryNode ,0) && validResponse ) { + dat->CommandsNode = xi.copyNode( queryNode ); + + nodeIdx = 1; + int ypos = 20; + for (nodeIdx = 1; ; nodeIdx++ ) { + HXML itemNode = xmlGetNthChild( queryNode, _T("item"), nodeIdx ); + if ( itemNode ) { + const TCHAR *name = xmlGetAttrValue( itemNode, _T("name")); + if (!name) name = xmlGetAttrValue( itemNode, _T("node")); + ypos = AdHoc_AddCommandRadio( GetDlgItem( hwndDlg,IDC_FRAME ), TranslateTS(name), nodeIdx, ypos, (nodeIdx==1) ? 1 : 0); + dat->CurrentHeight = ypos; + } + else break; + } } + + if (nodeIdx>1) { + JabberFormSetInstruction( hwndDlg, TranslateT("Select Command")); + ShowDlgItem( hwndDlg, IDC_FRAME, SW_SHOW); + ShowDlgItem( hwndDlg, IDC_VSCROLL, SW_SHOW); + EnableDlgItem( hwndDlg, IDC_SUBMIT, TRUE); + } else { + JabberFormSetInstruction(hwndDlg, TranslateT("Not supported")); + } } + + JabberAdHoc_RefreshFrameScroll( hwndDlg, dat ); + return (TRUE); +} + +int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, HXML workNode, JabberAdHocData* dat) +{ + EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 ); + dat->CurrentHeight = 0; + dat->curPos = 0; + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); + + if ( workNode == NULL ) + return TRUE; + + dat->AdHocNode = xi.copyNode( workNode ); + + const TCHAR *type; + if (( type = xmlGetAttrValue( workNode, _T("type"))) == NULL ) return TRUE; + if ( !lstrcmp( type, _T("result")) ) { + // wParam = <iq/> node from responder as a result of command execution + HXML commandNode, xNode, n; + if (( commandNode = xmlGetChild( dat->AdHocNode, _T("command"))) == NULL ) + return TRUE; + + const TCHAR * status = xmlGetAttrValue( commandNode, _T("status")); + if (!status) status = _T("completed"); + + if (( xNode = xmlGetChild( commandNode , "x" ))) { + // use jabber:x:data form + HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); + ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE ); + if (( n = xmlGetChild( xNode , "instructions" )) != NULL && xmlGetText( n )!=NULL ) + JabberFormSetInstruction( hwndDlg, xmlGetText( n )); + else if (( n = xmlGetChild( xNode , "title" )) != NULL && xmlGetText( n )!=NULL ) + JabberFormSetInstruction( hwndDlg, xmlGetText( n )); + else + JabberFormSetInstruction(hwndDlg, TranslateTS(status)); + JabberFormCreateUI( hFrame, xNode, &dat->CurrentHeight ); + ShowDlgItem( hwndDlg, IDC_FRAME , SW_SHOW); + } + else { + //NO X FORM + int toHide[]={ IDC_FRAME_TEXT, IDC_FRAME, IDC_VSCROLL, 0}; + sttShowControls(hwndDlg, FALSE, toHide ); + + const TCHAR * noteText=NULL; + HXML noteNode = xmlGetChild( commandNode , "note"); + if (noteNode) + noteText = xmlGetText( noteNode ); + + JabberFormSetInstruction(hwndDlg, noteText ? noteText : TranslateTS(status)); + } + + //check actions + HXML actionsNode = xmlGetChild( commandNode , "actions"); + if ( actionsNode != NULL ) { + ShowDlgItem( hwndDlg, IDC_PREV, ( xmlGetChild( actionsNode , "prev")!=NULL) ? SW_SHOW : SW_HIDE); + ShowDlgItem( hwndDlg, IDC_NEXT, ( xmlGetChild( actionsNode , "next")!=NULL) ? SW_SHOW : SW_HIDE); + ShowDlgItem( hwndDlg, IDC_COMPLETE, ( xmlGetChild( actionsNode , "complete")!=NULL) ? SW_SHOW : SW_HIDE); + ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE); + + int toEnable[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; + sttEnableControls( hwndDlg, TRUE, toEnable ); + } else { + int toHide[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; + sttShowControls(hwndDlg, FALSE, toHide ); + + ShowDlgItem(hwndDlg,IDC_SUBMIT, SW_SHOW); + EnableDlgItem(hwndDlg,IDC_SUBMIT, TRUE); + } + + if (!status || _tcscmp(status,_T("executing"))) { + ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE); + SetWindowText(GetDlgItem(hwndDlg,IDCANCEL), TranslateT("Done")); + } } + else if ( !lstrcmp( type, _T("error"))) { + // error occurred here + int toHide[]={ IDC_FRAME, IDC_FRAME_TEXT, IDC_VSCROLL, + IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_SUBMIT, 0}; + + sttShowControls(hwndDlg, FALSE, toHide ); + + const TCHAR* code=NULL; + const TCHAR* description=NULL; + TCHAR buff[255]; + HXML errorNode = xmlGetChild( workNode , "error"); + if ( errorNode ) { + code = xmlGetAttrValue( errorNode, _T("code")); + description = xmlGetText( errorNode ); + } + _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s"),code ? code : _T(""),description?description:_T("")); + JabberFormSetInstruction(hwndDlg,buff); + } + JabberAdHoc_RefreshFrameScroll( hwndDlg, dat ); + return TRUE; +} + +int CJabberProto::AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData* dat, TCHAR* action) +{ + HXML commandNode = xmlGetChild( dat->AdHocNode, "command" ); + HXML xNode = xmlGetChild( commandNode , "x" ); + HXML dataNode = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), xNode); + + int iqId = (int)hwndDlg; + XmlNodeIq iq( _T("set"), iqId, xmlGetAttrValue( dat->AdHocNode, _T("from"))); + HXML command = iq << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)); + + const TCHAR* sessionId = xmlGetAttrValue( commandNode, _T("sessionid")); + if ( sessionId ) + command << XATTR( _T("sessionid"), sessionId ); + + const TCHAR* node = xmlGetAttrValue( commandNode, _T("node")); + if ( node ) + command << XATTR( _T("node"), node ); + + if ( action ) + command << XATTR( _T("action"), action ); + + xmlAddChild( command, dataNode ); + IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); + m_ThreadInfo->send( iq ); + + xi.destroyNode( dataNode ); + + JabberFormSetInstruction(hwndDlg,TranslateT("In progress. Please Wait...")); + + static const int toDisable[]={IDC_SUBMIT, IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0}; + sttEnableControls( hwndDlg, FALSE, toDisable); + + return TRUE; +} + + +int CJabberProto::AdHoc_AddCommandRadio(HWND hFrame, TCHAR * labelStr, int id, int ypos, int value) +{ + int labelHeight; + RECT strRect={0}; + + int verticalStep=4; + int ctrlMinHeight=18; + HWND hCtrl=NULL; + + RECT rcFrame; + GetClientRect(hFrame,&rcFrame); + + int ctrlOffset=20; + int ctrlWidth=rcFrame.right-ctrlOffset; + + HDC hdc = GetDC( hFrame ); + labelHeight = max(ctrlMinHeight, DrawText( hdc , labelStr, -1, &strRect, DT_CALCRECT )); + ctrlWidth=min( ctrlWidth, strRect.right-strRect.left+20 ); + ReleaseDC( hFrame, hdc ); + + hCtrl = CreateWindowEx( 0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTORADIOBUTTON, ctrlOffset, ypos, ctrlWidth, labelHeight, hFrame, ( HMENU ) id, hInst, NULL ); + SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) SendMessage( GetParent(hFrame), WM_GETFONT, 0, 0 ), 0 ); + SendMessage( hCtrl, BM_SETCHECK, value, 0 ); + return (ypos + labelHeight + verticalStep); + +} + +static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JabberAdHocData* dat = ( JabberAdHocData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + switch (msg) + { + case WM_INITDIALOG: + { + CJabberAdhocStartupParams* pStartupParams = (CJabberAdhocStartupParams *)lParam; + dat=(JabberAdHocData *)mir_alloc(sizeof(JabberAdHocData)); + memset(dat,0,sizeof(JabberAdHocData)); + + //hmmm, useless code? if (dat->ResponderJID) mir_free(dat->ResponderJID); + dat->ResponderJID = mir_tstrdup(pStartupParams->m_szJid); + dat->proto = pStartupParams->m_pProto; + + SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat); + WindowSetIcon( hwndDlg, dat->proto, "adhoc" ); + dat->proto->m_hwndCommandWindow = hwndDlg; + TranslateDialogDefault( hwndDlg ); + + //Firstly hide frame + LONG frameExStyle = GetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE ); + frameExStyle |= WS_EX_CONTROLPARENT; + + SetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); + + int toHide[]={ IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_FRAME_TEXT, 0}; + sttShowControls(hwndDlg, FALSE, toHide ); + + int toShow[]={ IDC_INSTRUCTION, IDC_SUBMIT, IDCANCEL, 0}; + sttShowControls(hwndDlg, TRUE, toShow ); + + EnableDlgItem(hwndDlg,IDC_VSCROLL,TRUE); + + SetWindowPos(GetDlgItem(hwndDlg,IDC_VSCROLL),HWND_BOTTOM,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); + + SetDlgItemText(hwndDlg,IDC_SUBMIT, TranslateT("Execute")); + JabberFormSetInstruction(hwndDlg,TranslateT("Requesting command list. Please wait...")); + + if ( !pStartupParams->m_szNode ) { + dat->proto->AdHoc_RequestListOfCommands(pStartupParams->m_szJid, hwndDlg); + + TCHAR Caption[ 512 ]; + _sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Jabber Ad-Hoc commands at"), dat->ResponderJID ); + SetWindowText(hwndDlg, Caption); + } + else + { + int iqId = (int)hwndDlg; + dat->proto->IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution ); + dat->proto->m_ThreadInfo->send( + XmlNodeIq( _T("set"), iqId, pStartupParams->m_szJid ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) + << XATTR( _T("node"), pStartupParams->m_szNode ) << XATTR( _T("action"), _T("execute"))); + + EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE ); + SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" )); + + TCHAR Caption[ 512 ]; + _sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Sending Ad-Hoc command to"), dat->ResponderJID ); + SetWindowText(hwndDlg, Caption); + } + + delete pStartupParams; + + return TRUE; + } + case WM_CTLCOLORSTATIC: + if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) + { + return (INT_PTR)GetStockObject(WHITE_BRUSH); + } else + { + return NULL; + } + case WM_COMMAND: + { + switch ( LOWORD( wParam )) + { + + case IDC_PREV: + return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("prev")); + case IDC_NEXT: + return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("next")); + case IDC_COMPLETE: + return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("complete")); + case IDC_SUBMIT: + if (!dat->AdHocNode && dat->CommandsNode && LOWORD( wParam )==IDC_SUBMIT) + return dat->proto->AdHoc_ExecuteCommand(hwndDlg,dat->ResponderJID, dat); + else + return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat, NULL); + case IDCLOSE: + case IDCANCEL: + xi.destroyNode( dat->AdHocNode ); dat->AdHocNode = NULL; + DestroyWindow( hwndDlg ); + return TRUE; + } + break; + } + case JAHM_COMMANDLISTRESULT: + return dat->proto->AdHoc_OnJAHMCommandListResult(hwndDlg,(HXML)lParam,dat); + case JAHM_PROCESSRESULT: + return dat->proto->AdHoc_OnJAHMProcessResult(hwndDlg, (HXML)wParam,dat); + + case WM_MOUSEWHEEL: + { + int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); + if ( zDelta ) { + int nScrollLines=0; + SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,(void*)&nScrollLines,0); + for (int i=0; i<(nScrollLines+1)/2; i++) + SendMessage(hwndDlg,WM_VSCROLL, (zDelta<0)?SB_LINEDOWN:SB_LINEUP,0); + } } + return TRUE; + + case WM_VSCROLL: + { + int pos; + if ( dat != NULL ) { + pos = dat->curPos; + switch ( LOWORD( wParam )) + { + case SB_LINEDOWN: + pos += 10; + break; + case SB_LINEUP: + pos -= 10; + break; + case SB_PAGEDOWN: + pos += ( dat->CurrentHeight - 10 ); + break; + case SB_PAGEUP: + pos -= ( dat->CurrentHeight - 10 ); + break; + case SB_THUMBTRACK: + pos = HIWORD( wParam ); + break; + } + if ( pos > ( dat->CurrentHeight - dat->frameHeight )) + pos = dat->CurrentHeight - dat->frameHeight; + if ( pos < 0 ) + pos = 0; + if ( dat->curPos != pos ) { + ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL , &( dat->frameRect )); + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); + RECT Invalid=dat->frameRect; + if (dat->curPos - pos >0) + Invalid.bottom=Invalid.top+(dat->curPos - pos); + else + Invalid.top=Invalid.bottom+(dat->curPos - pos); + + RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_UPDATENOW |RDW_ALLCHILDREN); + dat->curPos = pos; + } } + break; + } + case WM_DESTROY: + { + JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME)); + WindowFreeIcon(hwndDlg); + + dat->proto->m_hwndCommandWindow = NULL; + mir_free( dat->ResponderJID ); + xi.destroyNode( dat->CommandsNode ); + xi.destroyNode( dat->AdHocNode ); + mir_free(dat); + dat=NULL; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + break; + } + } + return FALSE; +} + +int __cdecl CJabberProto::ContactMenuRunCommands(WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact; + DBVARIANT dbv; + int res = -1; + JABBER_LIST_ITEM * item=NULL; + + if ((( hContact=( HANDLE ) wParam )!=NULL || (lParam!=0)) && m_bJabberOnline ) { + if ( wParam && !JGetStringT( hContact, "jid", &dbv )) { + TCHAR jid[ JABBER_MAX_JID_LEN ]; + int selected = 0; + _tcsncpy(jid, dbv.ptszVal, SIZEOF(jid)); + + ListLock(); + { + item = ListGetItemPtr( LIST_ROSTER, jid); + if (item) + { + if (item->resourceCount>1) + { + HMENU hMenu=CreatePopupMenu(); + for (int i=0; i<item->resourceCount; i++) + AppendMenu(hMenu,MF_STRING,i+1, item->resource[i].resourceName); + HWND hwndTemp=CreateWindowEx(WS_EX_TOOLWINDOW,_T("button"),_T("PopupMenuHost"),0,0,0,10,10,NULL,NULL,hInst,NULL); + SetForegroundWindow(hwndTemp); + POINT pt; + GetCursorPos(&pt); + RECT rc; + selected=TrackPopupMenu(hMenu,TPM_RETURNCMD,pt.x,pt.y,0,hwndTemp,&rc); + DestroyMenu(hMenu); + DestroyWindow(hwndTemp); + } + else selected=1; + + if (selected>0) + { + selected--; + if (item->resource) + { + _tcsncat(jid,_T("/"),SIZEOF(jid)); + _tcsncat(jid,item->resource[selected].resourceName,SIZEOF(jid)); + } + selected=1; + } + } + } + ListUnlock(); + + if (!item || selected) { + CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams( this, jid, NULL ); + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, ( LPARAM )(pStartupParams)); + } + JFreeVariant( &dbv ); + + } + else if (lParam!=0) + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, lParam ); + } + return res; +} + +void CJabberProto::ContactMenuAdhocCommands( CJabberAdhocStartupParams* param ) +{ + if ( param ) + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, (LPARAM)param ); +} diff --git a/protocols/JabberG/src/jabber_agent.cpp b/protocols/JabberG/src/jabber_agent.cpp new file mode 100644 index 0000000000..b0ad17e8a0 --- /dev/null +++ b/protocols/JabberG/src/jabber_agent.cpp @@ -0,0 +1,283 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Agent registration progress dialog + +class CAgentRegProgressDlg : public CJabberDlgBase +{ + CCtrlButton m_ok; + +public: + CAgentRegProgressDlg( CJabberProto* _ppro, HWND _owner ) : + CJabberDlgBase( _ppro, IDD_OPT_REGISTER, _owner, false ), + m_ok( this, IDOK ) + { + m_ok.OnClick = Callback( this, &CAgentRegProgressDlg::OnOk ); + } + + virtual void OnInitDialog() + { + m_proto->m_hwndRegProgress = m_hwnd; + SetWindowTextA( m_hwnd, "Jabber Agent Registration" ); + TranslateDialogDefault( m_hwnd ); + } + + virtual INT_PTR DlgProc( UINT msg, WPARAM wParam, LPARAM lParam ) + { + if ( msg == WM_JABBER_REGDLG_UPDATE ) { + if (( TCHAR* )lParam == NULL ) + SetDlgItemText( m_hwnd, IDC_REG_STATUS, TranslateT( "No message" )); + else + SetDlgItemText( m_hwnd, IDC_REG_STATUS, ( TCHAR* )lParam ); + if ( wParam >= 0 ) + SendMessage( GetDlgItem( m_hwnd, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 ); + if ( wParam >= 100 ) + m_ok.SetText( TranslateT( "OK" )); + } + + return CJabberDlgBase::DlgProc( msg, wParam, lParam ); + } + + void OnOk( CCtrlButton* ) + { + m_proto->m_hwndRegProgress = NULL; + EndDialog( m_hwnd, 0 ); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Transport registration form + +class CAgentRegDlg : public CJabberDlgBase +{ + int m_curPos; + int m_formHeight, m_frameHeight; + RECT m_frameRect; + HXML m_agentRegIqNode; + TCHAR* m_jid; + + CCtrlButton m_submit; + +public: + CAgentRegDlg( CJabberProto* _ppro, TCHAR* _jid ) : + CJabberDlgBase( _ppro, IDD_FORM, NULL, false ), + m_submit( this, IDC_SUBMIT ), + m_jid( _jid ), + m_agentRegIqNode( NULL ) + { + m_submit.OnClick = Callback( this, &CAgentRegDlg::OnSubmit ); + } + + virtual void OnInitDialog() + { + EnableWindow( GetParent( m_hwnd ), FALSE ); + m_proto->m_hwndAgentRegInput = m_hwnd; + SetWindowText( m_hwnd, TranslateT( "Jabber Agent Registration" )); + SetDlgItemText( m_hwnd, IDC_SUBMIT, TranslateT( "Register" )); + SetDlgItemText( m_hwnd, IDC_FRAME_TEXT, TranslateT( "Please wait..." )); + + int iqId = m_proto->SerialNext(); + m_proto->IqAdd( iqId, IQ_PROC_GETREGISTER, &CJabberProto::OnIqResultGetRegister ); + m_proto->m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, m_jid ) << XQUERY( _T(JABBER_FEAT_REGISTER))); + + // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children ) + LONG frameExStyle = GetWindowLongPtr( GetDlgItem( m_hwnd, IDC_FRAME ), GWL_EXSTYLE ); + frameExStyle |= WS_EX_CONTROLPARENT; + SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); + } + + virtual void OnDestroy() + { + xi.destroyNode( m_agentRegIqNode ); + JabberFormDestroyUI(GetDlgItem(m_hwnd, IDC_FRAME)); + m_proto->m_hwndAgentRegInput = NULL; + EnableWindow( GetParent( m_hwnd ), TRUE ); + SetActiveWindow( GetParent( m_hwnd )); + } + + virtual INT_PTR DlgProc( UINT msg, WPARAM wParam, LPARAM lParam ) + { + switch( msg ) { + case WM_CTLCOLORSTATIC: + switch( GetDlgCtrlID(( HWND )lParam )) { + case IDC_WHITERECT: case IDC_INSTRUCTION: case IDC_TITLE: + return (INT_PTR)GetStockObject(WHITE_BRUSH); + default: + return NULL; + } + + case WM_JABBER_REGINPUT_ACTIVATE: + if ( wParam == 1 ) { // success + // lParam = <iq/> node from agent JID as a result of "get jabber:iq:register" + HWND hFrame = GetDlgItem( m_hwnd, IDC_FRAME ); + ShowWindow( GetDlgItem( m_hwnd, IDC_FRAME_TEXT ), SW_HIDE ); + + HXML queryNode, xNode; + if (( m_agentRegIqNode = ( HXML )lParam ) == NULL ) return TRUE; + if (( queryNode = xmlGetChild( m_agentRegIqNode , "query" )) == NULL ) return TRUE; + + RECT rect; + + m_curPos = 0; + GetClientRect( GetDlgItem( m_hwnd, IDC_FRAME ), &( m_frameRect )); + GetClientRect( GetDlgItem( m_hwnd, IDC_VSCROLL ), &rect ); + m_frameRect.right -= ( rect.right - rect.left ); + GetClientRect( GetDlgItem( m_hwnd, IDC_FRAME ), &rect ); + m_frameHeight = rect.bottom - rect.top; + + if (( xNode=xmlGetChild( queryNode , "x" )) != NULL ) { + // use new jabber:x:data form + HXML n = xmlGetChild( xNode , "instructions" ); + if ( n != NULL && xmlGetText( n )!=NULL ) + JabberFormSetInstruction( m_hwnd, xmlGetText( n )); + + JabberFormCreateUI( hFrame, xNode, &m_formHeight /*dummy*/ ); + } + else { + // use old registration information form + HJFORMLAYOUT layout_info = JabberFormCreateLayout(hFrame); + for ( int i=0; ; i++ ) { + HXML n = xmlGetChild( queryNode ,i); + if ( !n ) + break; + + if ( xmlGetName( n )) { + if ( !lstrcmp( xmlGetName( n ), _T("instructions"))) { + JabberFormSetInstruction( m_hwnd, xmlGetText( n )); + } + else if ( !lstrcmp( xmlGetName( n ), _T("key")) || !lstrcmp( xmlGetName( n ), _T("registered"))) { + // do nothing + } + else if ( !lstrcmp( xmlGetName( n ), _T("password"))) + JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_PRIVATE, xmlGetName( n ), xmlGetText( n )); + else // everything else is a normal text field + JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_SINGLE, xmlGetName( n ), xmlGetText( n )); + } } + JabberFormLayoutControls(hFrame, layout_info, &m_formHeight); + mir_free(layout_info); + } + + if ( m_formHeight > m_frameHeight ) { + HWND hwndScroll; + + hwndScroll = GetDlgItem( m_hwnd, IDC_VSCROLL ); + EnableWindow( hwndScroll, TRUE ); + SetScrollRange( hwndScroll, SB_CTL, 0, m_formHeight - m_frameHeight, FALSE ); + m_curPos = 0; + } + + EnableWindow( GetDlgItem( m_hwnd, IDC_SUBMIT ), TRUE ); + } + else if ( wParam == 0 ) { + // lParam = error message + SetDlgItemText( m_hwnd, IDC_FRAME_TEXT, ( LPCTSTR ) lParam ); + } + return TRUE; + + case WM_VSCROLL: + int pos = m_curPos; + switch ( LOWORD( wParam )) { + case SB_LINEDOWN: pos += 10; break; + case SB_LINEUP: pos -= 10; break; + case SB_PAGEDOWN: pos += ( m_frameHeight - 10 ); break; + case SB_PAGEUP: pos -= ( m_frameHeight - 10 ); break; + case SB_THUMBTRACK: pos = HIWORD( wParam ); break; + } + if ( pos > ( m_formHeight - m_frameHeight )) + pos = m_formHeight - m_frameHeight; + if ( pos < 0 ) + pos = 0; + if ( m_curPos != pos ) { + ScrollWindow( GetDlgItem( m_hwnd, IDC_FRAME ), 0, m_curPos - pos, NULL, &( m_frameRect )); + SetScrollPos( GetDlgItem( m_hwnd, IDC_VSCROLL ), SB_CTL, pos, TRUE ); + m_curPos = pos; + } } + + return CJabberDlgBase::DlgProc( msg, wParam, lParam ); + } + + void OnSubmit( CCtrlButton* ) + { + HXML queryNode, xNode; + const TCHAR *from; + + if ( m_agentRegIqNode == NULL ) return; + if (( from = xmlGetAttrValue( m_agentRegIqNode, _T("from"))) == NULL ) return; + if (( queryNode = xmlGetChild( m_agentRegIqNode , "query" )) == NULL ) return; + HWND hFrame = GetDlgItem( m_hwnd, IDC_FRAME ); + + TCHAR *str2 = ( TCHAR* )alloca( sizeof(TCHAR) * 128 ); + int id = 0; + + int iqId = m_proto->SerialNext(); + m_proto->IqAdd( iqId, IQ_PROC_SETREGISTER, &CJabberProto::OnIqResultSetRegister ); + + XmlNodeIq iq( _T("set"), iqId, from ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); + + if (( xNode = xmlGetChild( queryNode , "x" )) != NULL ) { + // use new jabber:x:data form + HXML n = JabberFormGetData( hFrame, xNode ); + xmlAddChild( query, n ); + xi.destroyNode( n ); + } + else { + // use old registration information form + for ( int i=0; ; i++ ) { + HXML n = xmlGetChild( queryNode ,i); + if ( !n ) + break; + + if ( xmlGetName( n )) { + if ( !lstrcmp( xmlGetName( n ), _T("key"))) { + // field that must be passed along with the registration + if ( xmlGetText( n )) + xmlAddChild( query, xmlGetName( n ), xmlGetText( n )); + else + xmlAddChild( query, xmlGetName( n )); + } + else if ( !lstrcmp( xmlGetName( n ), _T("registered")) || !lstrcmp( xmlGetName( n ), _T("instructions"))) { + // do nothing, we will skip these + } + else { + GetDlgItemText( hFrame, id, str2, 128 ); + xmlAddChild( query, xmlGetName( n ), str2 ); + id++; + } } } } + + m_proto->m_ThreadInfo->send( iq ); + + CAgentRegProgressDlg( m_proto, m_hwnd ).DoModal(); + + Close(); + } +}; + +void CJabberProto::RegisterAgent( HWND /*hwndDlg*/, TCHAR* jid ) +{ + ( new CAgentRegDlg( this, jid ))->Show(); +} diff --git a/protocols/JabberG/src/jabber_bookmarks.cpp b/protocols/JabberG/src/jabber_bookmarks.cpp new file mode 100644 index 0000000000..158f83e669 --- /dev/null +++ b/protocols/JabberG/src/jabber_bookmarks.cpp @@ -0,0 +1,483 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2007 Michael Stepura, George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Bookmarks editor window + +struct JabberAddBookmarkDlgParam { + CJabberProto* ppro; + JABBER_LIST_ITEM* m_item; +}; + +static INT_PTR CALLBACK JabberAddBookmarkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JabberAddBookmarkDlgParam* param = (JabberAddBookmarkDlgParam*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + TCHAR text[512]; + JABBER_LIST_ITEM *item; + + switch ( msg ) { + case WM_INITDIALOG: + param = (JabberAddBookmarkDlgParam*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + param->ppro->m_hwndJabberAddBookmark = hwndDlg; + TranslateDialogDefault( hwndDlg ); + if ( item = param->m_item ) { + if ( !lstrcmp( item->type, _T("conference"))) { + if (!_tcschr( item->jid, _T( '@' ))) { //no room name - consider it is transport + SendDlgItemMessage(hwndDlg, IDC_AGENT_RADIO, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); + } + else SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_SETCHECK, BST_CHECKED, 0); + } + else { + SendDlgItemMessage(hwndDlg, IDC_URL_RADIO, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); + SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); + } + + EnableWindow( GetDlgItem( hwndDlg, IDC_ROOM_RADIO), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_URL_RADIO), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_RADIO), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); + + if ( item->jid ) SetDlgItemText( hwndDlg, IDC_ROOM_JID, item->jid ); + if ( item->name ) SetDlgItemText( hwndDlg, IDC_NAME, item->name ); + if ( item->nick ) SetDlgItemText( hwndDlg, IDC_NICK, item->nick ); + if ( item->password ) SetDlgItemText( hwndDlg, IDC_PASSWORD, item->password ); + if ( item->bAutoJoin ) SendDlgItemMessage( hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_CHECKED, 0 ); + if ( SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_GETCHECK,0, 0) == BST_CHECKED ) + EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), TRUE ); + } + else { + EnableWindow( GetDlgItem( hwndDlg, IDOK ), FALSE ); + SendDlgItemMessage(hwndDlg, IDC_ROOM_RADIO, BM_SETCHECK, BST_CHECKED, 0); + } + return TRUE; + + case WM_COMMAND: + switch ( HIWORD(wParam)) { + case BN_CLICKED: + switch (LOWORD (wParam)) { + case IDC_ROOM_RADIO: + EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), TRUE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), TRUE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), TRUE ); + break; + case IDC_AGENT_RADIO: + case IDC_URL_RADIO: + EnableWindow( GetDlgItem( hwndDlg, IDC_NICK ), FALSE ); + EnableWindow( GetDlgItem( hwndDlg, IDC_PASSWORD ), FALSE ); + SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow( GetDlgItem( hwndDlg, IDC_CHECK_BM_AUTOJOIN), FALSE ); + break; + } + } + + switch ( LOWORD( wParam )) { + case IDC_ROOM_JID: + if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) + EnableWindow( GetDlgItem( hwndDlg, IDOK ), GetDlgItemText( hwndDlg, IDC_ROOM_JID, text, SIZEOF( text ))); + break; + + case IDOK: + { + GetDlgItemText( hwndDlg, IDC_ROOM_JID, text, SIZEOF( text )); + TCHAR* roomJID = NEWTSTR_ALLOCA( text ); + + if ( param->m_item ) + param->ppro->ListRemove( LIST_BOOKMARK, param->m_item->jid ); + + item = param->ppro->ListAdd( LIST_BOOKMARK, roomJID ); + item->bUseResource = TRUE; + + if ( SendDlgItemMessage(hwndDlg, IDC_URL_RADIO, BM_GETCHECK,0, 0) == BST_CHECKED ) + replaceStrT( item->type, _T( "url" )); + else + replaceStrT( item->type, _T( "conference" )); + + GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text )); + replaceStrT( item->nick, text ); + + GetDlgItemText( hwndDlg, IDC_PASSWORD, text, SIZEOF( text )); + replaceStrT( item->password, text ); + + GetDlgItemText( hwndDlg, IDC_NAME, text, SIZEOF( text )); + replaceStrT( item->name, ( text[0] == 0 ) ? roomJID : text ); + + item->bAutoJoin = (SendDlgItemMessage(hwndDlg, IDC_CHECK_BM_AUTOJOIN, BM_GETCHECK,0, 0) == BST_CHECKED ); + { + int iqId = param->ppro->SerialNext(); + param->ppro->IqAdd( iqId, IQ_PROC_SETBOOKMARKS, &CJabberProto::OnIqResultSetBookmarks); + + XmlNodeIq iq( _T("set"), iqId); + param->ppro->SetBookmarkRequest(iq); + param->ppro->m_ThreadInfo->send( iq ); + } + } + // fall through + case IDCANCEL: + EndDialog( hwndDlg, 0 ); + break; + } + break; + + case WM_JABBER_CHECK_ONLINE: + if ( !param->ppro->m_bJabberOnline ) + EndDialog( hwndDlg, 0 ); + break; + + case WM_DESTROY: + param->ppro->m_hwndJabberAddBookmark = NULL; + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Bookmarks manager window + +class CJabberDlgBookmarks : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgBookmarks(CJabberProto *proto); + + void UpdateData(); + +protected: + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + int Resizer(UTILRESIZECONTROL *urc); + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + void OnProtoCheckOnline(WPARAM wParam, LPARAM lParam); + void OnProtoRefresh(WPARAM wParam, LPARAM lParam); + void OpenBookmark(); + +private: + CCtrlMButton m_btnAdd; + CCtrlMButton m_btnEdit; + CCtrlMButton m_btnRemove; + CCtrlFilterListView m_lvBookmarks; + + void lvBookmarks_OnDoubleClick(CCtrlFilterListView *) + { + OpenBookmark(); + } + + void btnAdd_OnClick(CCtrlFilterListView *) + { + if (!m_proto->m_bJabberOnline) return; + + JabberAddBookmarkDlgParam param; + param.ppro = m_proto; + param.m_item = NULL; + DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), m_hwnd, JabberAddBookmarkDlgProc, (LPARAM)¶m); + } + + void btnEdit_OnClick(CCtrlFilterListView *) + { + if (!m_proto->m_bJabberOnline) return; + + int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); + if (iItem < 0) return; + + TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); + if (!address) return; + + JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); + if (!item) return; + + JabberAddBookmarkDlgParam param; + param.ppro = m_proto; + param.m_item = item; + DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), m_hwnd, JabberAddBookmarkDlgProc, (LPARAM)¶m); + } + + void btnRemove_OnClick(CCtrlFilterListView *) + { + if (!m_proto->m_bJabberOnline) return; + + int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); + if (iItem < 0) return; + + TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); + if (!address) return; + + JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); + if (!item) return; + + m_btnAdd.Disable(); + m_btnEdit.Disable(); + m_btnRemove.Disable(); + + m_proto->ListRemove(LIST_BOOKMARK, address); + + m_lvBookmarks.SetItemState(iItem, 0, LVIS_SELECTED); // Unselect the item + + int iqId = m_proto->SerialNext(); + m_proto->IqAdd(iqId, IQ_PROC_SETBOOKMARKS, &CJabberProto::OnIqResultSetBookmarks); + + XmlNodeIq iq( _T("set"), iqId); + m_proto->SetBookmarkRequest(iq); + m_proto->m_ThreadInfo->send(iq); + } + +}; + +CJabberDlgBookmarks::CJabberDlgBookmarks(CJabberProto *proto) : + CSuper(proto, IDD_BOOKMARKS, NULL), + m_btnAdd(this, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add")), + m_btnEdit(this, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit")), + m_btnRemove(this, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove")), + m_lvBookmarks(this, IDC_BM_LIST, true, true) +{ + m_lvBookmarks.OnItemActivate = Callback(this, &CJabberDlgBookmarks::lvBookmarks_OnDoubleClick); + m_btnAdd.OnClick = Callback(this, &CJabberDlgBookmarks::btnAdd_OnClick); + m_btnEdit.OnClick = Callback(this, &CJabberDlgBookmarks::btnEdit_OnClick); + m_btnRemove.OnClick = Callback(this, &CJabberDlgBookmarks::btnRemove_OnClick); +} + +void CJabberDlgBookmarks::UpdateData() +{ + if (!m_proto->m_bJabberOnline) return; + + int iqId = m_proto->SerialNext(); + m_proto->IqAdd( iqId, IQ_PROC_DISCOBOOKMARKS, &CJabberProto::OnIqResultDiscoBookmarks); + m_proto->m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) + << XCHILDNS( _T("storage"), _T("storage:bookmarks"))); +} + +void CJabberDlgBookmarks::OnInitDialog() +{ + CSuper::OnInitDialog(); + + WindowSetIcon( m_hwnd, m_proto, "bookmarks" ); + + m_btnAdd.Disable(); + m_btnEdit.Disable(); + m_btnRemove.Disable(); + + m_lvBookmarks.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP | (IsWinVerXPPlus() ? LVS_EX_DOUBLEBUFFER : 0)); + + HIMAGELIST hIml = m_lvBookmarks.CreateImageList(LVSIL_SMALL); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("group")); + ImageList_AddIcon_Icolib(hIml, LoadSkinnedIcon(SKINICON_EVENT_URL)); + + m_lvBookmarks.AddColumn(0, TranslateT("Bookmark Name"), m_proto->JGetWord(NULL, "bookmarksWnd_cx0", 120)); + m_lvBookmarks.AddColumn(1, TranslateT("Address (JID or URL)"), m_proto->JGetWord(NULL, "bookmarksWnd_cx1", 210)); + m_lvBookmarks.AddColumn(2, TranslateT("Nickname"), m_proto->JGetWord(NULL, "bookmarksWnd_cx2", 90)); + + m_lvBookmarks.EnableGroupView(TRUE); + m_lvBookmarks.AddGroup(0, TranslateT("Conferences")); + m_lvBookmarks.AddGroup(1, TranslateT("Links")); + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "bookmarksWnd_"); +} + +void CJabberDlgBookmarks::OnClose() +{ + LVCOLUMN lvc = {0}; + lvc.mask = LVCF_WIDTH; + m_lvBookmarks.GetColumn(0, &lvc); + m_proto->JSetWord(NULL, "bookmarksWnd_cx0", lvc.cx); + m_lvBookmarks.GetColumn(1, &lvc); + m_proto->JSetWord(NULL, "bookmarksWnd_cx1", lvc.cx); + m_lvBookmarks.GetColumn(2, &lvc); + m_proto->JSetWord(NULL, "bookmarksWnd_cx2", lvc.cx); + + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "bookmarksWnd_"); + + CSuper::OnClose(); +} + +void CJabberDlgBookmarks::OnDestroy() +{ + m_proto->m_pDlgBookmarks = NULL; + + CSuper::OnDestroy(); +} + +void CJabberDlgBookmarks::OpenBookmark() +{ + int iItem = m_lvBookmarks.GetNextItem(-1, LVNI_SELECTED); + if (iItem < 0) return; + + TCHAR *address = (TCHAR *)m_lvBookmarks.GetItemData(iItem); + if (!address) return; + + JABBER_LIST_ITEM *item = m_proto->ListGetItemPtr(LIST_BOOKMARK, address); + if (!item) return; + + if (!lstrcmpi(item->type, _T("conference"))) + { + if (!jabberChatDllPresent) + { + JabberChatDllError(); + return; + } + + m_lvBookmarks.SetItemState(iItem, 0, LVIS_SELECTED); // Unselect the item + + /* some hack for using bookmark to transport not under XEP-0048 */ + if (!_tcschr(item->jid, _T('@'))) + { //the room name is not provided let consider that it is transport and send request to registration + m_proto->RegisterAgent(NULL, item->jid); + } else + { + TCHAR *room = NEWTSTR_ALLOCA(item->jid); + TCHAR *server = _tcschr(room, _T('@')); + *(server++) = 0; + + if (item->nick && *item->nick) + { + m_proto->GroupchatJoinRoom(server, room, item->nick, item->password); + } else + { + TCHAR* nick = JabberNickFromJID(m_proto->m_szJabberJID); + m_proto->GroupchatJoinRoom(server, room, nick, item->password); + mir_free(nick); + } + } + } else + { + char *szUrl = mir_t2a(item->jid); + CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl); + mir_free(szUrl); + } +} + +INT_PTR CJabberDlgBookmarks::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 451; + lpmmi->ptMinTrackSize.y = 320; + return 0; + } + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + OpenBookmark(); + return TRUE; + } + } + break; + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +void CJabberDlgBookmarks::OnProtoCheckOnline(WPARAM, LPARAM) +{ + if (!m_proto->m_bJabberOnline) + { + m_btnAdd.Disable(); + m_btnEdit.Disable(); + m_btnRemove.Disable(); + } else + { + UpdateData(); + } + +} + +void CJabberDlgBookmarks::OnProtoRefresh(WPARAM, LPARAM) +{ + m_lvBookmarks.DeleteAllItems(); + + JABBER_LIST_ITEM *item = NULL; + LISTFOREACH(i, m_proto, LIST_BOOKMARK) + { + if (item = m_proto->ListGetItemPtrFromIndex(i)) + { + int itemType = lstrcmpi(item->type, _T("conference")) ? 1 : 0; + int iItem = m_lvBookmarks.AddItem(item->name, itemType, (LPARAM)item->jid, itemType); + m_lvBookmarks.SetItem(iItem, 1, item->jid); + if (itemType == 0) + m_lvBookmarks.SetItem(iItem, 2, item->nick); + } + } + + if (item) + { + m_btnEdit.Enable(); + m_btnRemove.Enable(); + } + + m_btnAdd.Enable(); +} + +int CJabberDlgBookmarks::Resizer(UTILRESIZECONTROL *urc) +{ + switch ( urc->wId ) { + case IDC_BM_LIST: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + + case IDC_ADD: + case IDC_EDIT: + case IDC_REMOVE: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + } + return CSuper::Resizer(urc); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Launches the Bookmarks manager window + +INT_PTR __cdecl CJabberProto::OnMenuHandleBookmarks( WPARAM, LPARAM) +{ + UI_SAFE_OPEN_EX(CJabberDlgBookmarks, m_pDlgBookmarks, pDlg); + pDlg->UpdateData(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Launches the Bookmark details window, lParam is JABBER_BOOKMARK_ITEM* +int CJabberProto::AddEditBookmark( JABBER_LIST_ITEM* item ) +{ + if ( m_bJabberOnline) { + JabberAddBookmarkDlgParam param; + param.ppro = this; + param.m_item = item;//(JABBER_LIST_ITEM*)lParam; + DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_BOOKMARK_ADD ), NULL, JabberAddBookmarkDlgProc, (LPARAM)¶m ); + } + return 0; +} diff --git a/protocols/JabberG/src/jabber_byte.cpp b/protocols/JabberG/src/jabber_byte.cpp new file mode 100644 index 0000000000..9e86b51388 --- /dev/null +++ b/protocols/JabberG/src/jabber_byte.cpp @@ -0,0 +1,778 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_byte.h" +#include "jabber_caps.h" + +#define JABBER_NETWORK_BUFFER_SIZE 4096 + +///////////////// Bytestream sending ///////////////////////// + +JABBER_BYTE_TRANSFER::~JABBER_BYTE_TRANSFER() +{ + filetransfer* pft = ft; + if ( pft ) + pft->jbt = NULL; + + mir_free( srcJID ); + mir_free( dstJID ); + mir_free( streamhostJID ); + mir_free( iqId ); + mir_free( sid ); + + xi.destroyNode( iqNode ); + + // XEP-0065 proxy support + mir_free( szProxyHost ); + mir_free( szProxyPort ); + mir_free( szProxyJid ); + mir_free( szStreamhostUsed ); +} + +void CJabberProto::IqResultProxyDiscovery( HXML iqNode, CJabberIqInfo* pInfo ) +{ + JABBER_BYTE_TRANSFER *jbt = ( JABBER_BYTE_TRANSFER * )pInfo->GetUserData(); + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode ) { + const TCHAR *queryXmlns = xmlGetAttrValue( queryNode, _T( "xmlns" )); + if (queryXmlns && !_tcscmp( queryXmlns, _T(JABBER_FEAT_BYTESTREAMS))) { + HXML streamHostNode = xmlGetChild( queryNode , "streamhost" ); + if ( streamHostNode ) { + const TCHAR *streamJid = xmlGetAttrValue( streamHostNode, _T( "jid" )); + const TCHAR *streamHost = xmlGetAttrValue( streamHostNode, _T( "host" )); + const TCHAR *streamPort = xmlGetAttrValue( streamHostNode, _T( "port" )); + if ( streamJid && streamHost && streamPort ) { + jbt->szProxyHost = mir_tstrdup( streamHost ); + jbt->szProxyJid = mir_tstrdup( streamJid ); + jbt->szProxyPort = mir_tstrdup( streamPort ); + jbt->bProxyDiscovered = TRUE; + } } } } } + else if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) + jbt->state = JBT_ERROR; + + if ( jbt->hProxyEvent ) + SetEvent( jbt->hProxyEvent ); +} + +void JabberByteSendConnection( HANDLE hConn, DWORD /*dwRemoteIP*/, void* extra ) +{ + CJabberProto* ppro = ( CJabberProto* )extra; + TCHAR szPort[8]; + JABBER_BYTE_TRANSFER *jbt; + int recvResult, bytesParsed; + HANDLE hListen; + JABBER_LIST_ITEM *item; + char* buffer; + int datalen; + + NETLIBCONNINFO connInfo = { sizeof(connInfo) }; + CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hConn, (LPARAM)&connInfo); + + mir_sntprintf( szPort, SIZEOF( szPort ), _T("%u"), connInfo.wPort ); + ppro->Log( "bytestream_send_connection incoming connection accepted: %s", connInfo.szIpPort ); + + if (( item = ppro->ListGetItemPtr( LIST_BYTE, szPort )) == NULL ) { + ppro->Log( "No bytestream session is currently active, connection closed." ); + Netlib_CloseHandle( hConn ); + return; + } + + jbt = item->jbt; + + if (( buffer = ( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { + ppro->Log( "bytestream_send cannot allocate network buffer, connection closed." ); + jbt->state = JBT_ERROR; + Netlib_CloseHandle( hConn ); + if ( jbt->hEvent != NULL ) SetEvent( jbt->hEvent ); + return; + } + + hListen = jbt->hConn; + jbt->hConn = hConn; + jbt->state = JBT_INIT; + datalen = 0; + while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR ) { + recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); + if ( recvResult <= 0 ) + break; + + datalen += recvResult; + bytesParsed = ppro->ByteSendParse( hConn, jbt, buffer, datalen ); + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + } + + if ( jbt->hConn ) + Netlib_CloseHandle( jbt->hConn ); + + ppro->Log( "bytestream_send_connection closing connection" ); + jbt->hConn = hListen; + mir_free( buffer ); + + if ( jbt->hEvent != NULL ) + SetEvent( jbt->hEvent ); +} + +void CJabberProto::ByteSendThread( JABBER_BYTE_TRANSFER *jbt ) +{ + char* localAddr = NULL; + DBVARIANT dbv; + TCHAR szPort[8]; + HANDLE hEvent = NULL; + TCHAR* proxyJid; + CJabberIqInfo* pInfo = NULL; + int nIqId = 0; + + Log( "Thread started: type=bytestream_send" ); + + BOOL bDirect = m_options.BsDirect; + + if ( m_options.BsProxyManual ) { + proxyJid = NULL; + if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsProxyServer", &dbv )) { + proxyJid = mir_a2t( dbv.pszVal ); + JFreeVariant( &dbv ); + } + + if ( proxyJid ) { + jbt->bProxyDiscovered = FALSE; + jbt->szProxyHost = NULL; + jbt->szProxyPort = NULL; + jbt->szProxyJid = NULL; + jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + + pInfo = m_iqManager.AddHandler( &CJabberProto::IqResultProxyDiscovery, JABBER_IQ_TYPE_GET, proxyJid, 0, -1, jbt ); + nIqId = pInfo->GetIqId(); + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)); + m_ThreadInfo->send( iq ); + + WaitForSingleObject( jbt->hProxyEvent, INFINITE ); + m_iqManager.ExpireIq ( nIqId ); + CloseHandle( jbt->hProxyEvent ); + jbt->hProxyEvent = NULL; + + mir_free( proxyJid ); + + if ( jbt->state == JBT_ERROR && !bDirect ) { + Log( "Bytestream proxy failure" ); + MsgPopup( pInfo->GetHContact(), TranslateT("Bytestream Proxy not available"), pInfo->GetReceiver()); + jbt->ft->state = FT_DENIED; + (this->*jbt->pfnFinal)( FALSE, jbt->ft ); + jbt->ft = NULL; + delete jbt; + return; + } + } } + + pInfo = m_iqManager.AddHandler( &CJabberProto::ByteInitiateResult, JABBER_IQ_TYPE_SET, jbt->dstJID, 0, -1, jbt ); + nIqId = pInfo->GetIqId(); + { + XmlNodeIq iq( pInfo ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) << XATTR( _T("sid"), jbt->sid ); + + if ( bDirect ) { + if ( m_options.BsDirectManual ) { + if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsDirectAddr", &dbv )) + localAddr = dbv.pszVal; + } + + NETLIBBIND nlb = {0}; + nlb.cbSize = sizeof( NETLIBBIND ); + nlb.pfnNewConnectionV2 = JabberByteSendConnection; + nlb.pExtra = this; + nlb.wPort = 0; // Use user-specified incoming port ranges, if available + jbt->hConn = ( HANDLE ) CallService( MS_NETLIB_BINDPORT, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nlb ); + if ( jbt->hConn == NULL ) { + Log( "Cannot allocate port for bytestream_send thread, thread ended." ); + delete jbt; + return; + } + + if ( localAddr == NULL ) + localAddr = (char*)CallService( MS_NETLIB_ADDRESSTOSTRING, 1, nlb.dwExternalIP ); + + mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort ); + JABBER_LIST_ITEM *item = ListAdd( LIST_BYTE, szPort ); + item->jbt = jbt; + hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + jbt->hEvent = hEvent; + jbt->hSendEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(localAddr)) << XATTRI( _T("port"), nlb.wPort ); + + NETLIBIPLIST* ihaddr = ( NETLIBIPLIST* )CallService( MS_NETLIB_GETMYIP, 1, 0 ); + for ( unsigned i = 0; i < ihaddr->cbNum; ++i ) + if ( strcmp( localAddr, ihaddr->szIp[i] )) + query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(ihaddr->szIp[i])) << XATTRI( _T("port"), nlb.wPort ); + + mir_free( ihaddr ); + mir_free( localAddr ); + } + + if ( jbt->bProxyDiscovered ) + query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), jbt->szProxyJid ) << XATTR( _T("host"), jbt->szProxyHost ) << XATTR( _T("port"), jbt->szProxyPort ); + + jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + jbt->szStreamhostUsed = NULL; + + m_ThreadInfo->send( iq ); + } + + WaitForSingleObject( jbt->hProxyEvent, INFINITE ); + m_iqManager.ExpireIq( nIqId ); + CloseHandle( jbt->hProxyEvent ); + jbt->hProxyEvent = NULL; + + if ( !jbt->szStreamhostUsed ) { + if ( bDirect ) { + SetEvent( jbt->hSendEvent ); + CloseHandle( jbt->hSendEvent ); + CloseHandle( hEvent ); + jbt->hEvent = NULL; + if ( jbt->hConn != NULL ) + Netlib_CloseHandle( jbt->hConn ); + jbt->hConn = NULL; + ListRemove( LIST_BYTE, szPort ); + } + (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); + jbt->ft = NULL; + // stupid fix: wait for listening thread exit + Sleep( 100 ); + delete jbt; + return; + } + + if ( jbt->bProxyDiscovered && !_tcscmp( jbt->szProxyJid, jbt->szStreamhostUsed )) { + // jabber proxy used + if ( bDirect ) { + SetEvent( jbt->hSendEvent ); + CloseHandle( jbt->hSendEvent ); + CloseHandle( hEvent ); + jbt->hEvent = NULL; + if ( jbt->hConn != NULL ) + Netlib_CloseHandle( jbt->hConn ); + jbt->hConn = NULL; + ListRemove( LIST_BYTE, szPort ); + } + ByteSendViaProxy( jbt ); + } + else { + SetEvent( jbt->hSendEvent ); + WaitForSingleObject( hEvent, INFINITE ); + CloseHandle( hEvent ); + CloseHandle( jbt->hSendEvent ); + jbt->hEvent = NULL; + (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); + jbt->ft = NULL; + if ( jbt->hConn != NULL ) + Netlib_CloseHandle( jbt->hConn ); + jbt->hConn = NULL; + ListRemove( LIST_BYTE, szPort ); + } + + // stupid fix: wait for listening connection thread exit + Sleep( 100 ); + delete jbt; + Log( "Thread ended: type=bytestream_send" ); +} + +void CJabberProto::ByteInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ) +{ + JABBER_BYTE_TRANSFER *jbt = ( JABBER_BYTE_TRANSFER * )pInfo->GetUserData(); + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode ) { + const TCHAR* queryXmlns = xmlGetAttrValue( queryNode, _T("xmlns")); + if ( queryXmlns && !_tcscmp( queryXmlns, _T( JABBER_FEAT_BYTESTREAMS ))) { + HXML streamHostNode = xmlGetChild( queryNode , "streamhost-used" ); + if ( streamHostNode ) { + const TCHAR* streamJid = xmlGetAttrValue( streamHostNode, _T("jid")); + if ( streamJid ) + jbt->szStreamhostUsed = mir_tstrdup( streamJid ); + } } } } + + if ( jbt->hProxyEvent ) + SetEvent( jbt->hProxyEvent ); +} + +int CJabberProto::ByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) +{ + int nMethods; + BYTE data[10]; + int i; + char* str; + + switch ( jbt->state ) { + case JBT_INIT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 nmethods + // 02-xx list of methods ( nmethods bytes ) + // send: + // 00-00 ver ( 0x05 ) + // 01-01 select method ( 0=no auth required ) + if ( datalen>=2 && buffer[0]==5 && buffer[1]+2==datalen ) { + nMethods = buffer[1]; + for ( i=0; i<nMethods && buffer[2+i]!=0; i++ ); + if ( i < nMethods ) { + data[1] = 0; + jbt->state = JBT_CONNECT; + } + else { + data[1] = 0xff; + jbt->state = JBT_ERROR; + } + data[0] = 5; + Netlib_Send( hConn, ( char* )data, 2, 0 ); + } + else jbt->state = JBT_ERROR; + break; + + case JBT_CONNECT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 cmd ( 1=connect ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 3 ) + // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) + // 45-46 dst.port ( 0 ) + // send: + // 00-00 ver ( 0x05 ) + // 01-01 reply ( 0=success,2=not allowed ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 1=IPv4 address ) + // 04-07 bnd.addr server bound address + // 08-09 bnd.port server bound port + if ( datalen == 47 && *(( DWORD* )buffer )==0x03000105 && buffer[4]==40 && *(( WORD* )( buffer+45 ))==0 ) { + TCHAR text[256]; + + TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); + TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); + mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); + mir_free(szInitiatorJid); + mir_free(szTargetJid); + + char* szAuthString = mir_utf8encodeT( text ); + Log( "Auth: '%s'", szAuthString ); + if (( str = JabberSha1( szAuthString )) != NULL ) { + for ( i=0; i<40 && buffer[i+5]==str[i]; i++ ); + mir_free( str ); + + ZeroMemory( data, 10 ); + data[1] = ( i>=20 )?0:2; + data[0] = 5; + data[3] = 1; + Netlib_Send( hConn, ( char* )data, 10, 0 ); + + // wait stream activation + WaitForSingleObject( jbt->hSendEvent, INFINITE ); + + if ( jbt->state == JBT_ERROR ) + break; + + if ( i>=20 && (this->*jbt->pfnSend)( hConn, jbt->ft )==TRUE ) + jbt->state = JBT_DONE; + else + jbt->state = JBT_ERROR; + } + mir_free( szAuthString ); + } + else + jbt->state = JBT_ERROR; + break; + } + + return datalen; +} + +///////////////// Bytestream receiving ///////////////////////// + +void CJabberProto::IqResultStreamActivate( HXML iqNode ) +{ + int id = JabberGetPacketID( iqNode ); + + TCHAR listJid[JABBER_MAX_JID_LEN]; + mir_sntprintf(listJid, SIZEOF( listJid ), _T("ftproxy_%d"), id); + + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTIQID, listJid ); + if ( !item ) + return; + + if ( !lstrcmp( xmlGetAttrValue( iqNode, _T("type")), _T( "result" ))) + item->jbt->bStreamActivated = TRUE; + + if ( item->jbt->hProxyEvent ) + SetEvent( item->jbt->hProxyEvent ); +} + + +void CJabberProto::ByteSendViaProxy( JABBER_BYTE_TRANSFER *jbt ) +{ + TCHAR *szHost, *szPort; + WORD port; + HANDLE hConn; + char data[3]; + char* buffer; + int datalen, bytesParsed, recvResult; + BOOL validStreamhost; + + if ( jbt == NULL ) return; + if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { + m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 406 ) << XATTR( _T("type"), _T("auth")) + << XCHILDNS( _T("not-acceptable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + return; + } + + jbt->state = JBT_INIT; + validStreamhost = FALSE; + szPort = jbt->szProxyPort; + szHost = jbt->szProxyHost; + + port = ( WORD )_ttoi( szPort ); + if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); + jbt->streamhostJID = mir_tstrdup( jbt->szProxyJid ); + + NETLIBOPENCONNECTION nloc = { 0 }; + nloc.cbSize = sizeof( nloc ); + nloc.szHost = mir_t2a(szHost); + nloc.wPort = port; + hConn = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); + mir_free((void*)nloc.szHost); + + if ( hConn != NULL ) { + jbt->hConn = hConn; + + data[0] = 5; + data[1] = 1; + data[2] = 0; + Netlib_Send( hConn, data, 3, 0 ); + + jbt->state = JBT_INIT; + datalen = 0; + while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { + recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); + if ( recvResult <= 0 ) + break; + + datalen += recvResult; + bytesParsed = ByteSendProxyParse( hConn, jbt, buffer, datalen ); + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + if ( jbt->state == JBT_DONE ) validStreamhost = TRUE; + } + Netlib_CloseHandle( hConn ); + } + mir_free( buffer ); + (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); + jbt->ft = NULL; + if ( !validStreamhost ) + m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); +} + +int CJabberProto::ByteSendProxyParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) +{ + int num = datalen; + + switch ( jbt->state ) { + case JBT_INIT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 selected method ( 0=no auth, 0xff=error ) + // send: + // 00-00 ver ( 0x05 ) + // 01-01 cmd ( 1=connect ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 3 ) + // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) + // 45-46 dst.port ( 0 ) + if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { + BYTE data[47]; + ZeroMemory( data, sizeof( data )); + *(( DWORD* )data ) = 0x03000105; + data[4] = 40; + + TCHAR text[256]; + + TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); + TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); + mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); + mir_free(szInitiatorJid); + mir_free(szTargetJid); + + char* szAuthString = mir_utf8encodeT( text ); + Log( "Auth: '%s'", szAuthString ); + char* szHash = JabberSha1( szAuthString ); + strncpy(( char* )( data+5 ), szHash, 40 ); + mir_free( szHash ); + Netlib_Send( hConn, ( char* )data, 47, 0 ); + jbt->state = JBT_CONNECT; + mir_free( szAuthString ); + } + else jbt->state = JBT_SOCKSERR; + break; + + case JBT_CONNECT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 reply ( 0=success,2=not allowed ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 1=IPv4 address,3=host address ) + // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) + // nn-nn+1 bnd.port server bound port + if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { + if ( buffer[3]==1 && datalen>=10 ) + num = 10; + else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) + num = buffer[4] + 7; + else if ( buffer[3]==0 && datalen>=6 ) + num = 6; + else { + jbt->state = JBT_SOCKSERR; + break; + } + jbt->state = JBT_SENDING; + + jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + jbt->bStreamActivated = FALSE; + + int iqId = SerialNext(); + + TCHAR listJid[256]; + mir_sntprintf(listJid, SIZEOF( listJid ), _T("ftproxy_%d"), iqId); + + JABBER_LIST_ITEM *item = ListAdd( LIST_FTIQID, listJid ); + item->jbt = jbt; + + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::IqResultStreamActivate ); + m_ThreadInfo->send( + XmlNodeIq( _T("set"), iqId, jbt->streamhostJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) + << XATTR( _T("sid"), jbt->sid ) << XCHILD( _T("activate"), jbt->dstJID )); + + WaitForSingleObject( jbt->hProxyEvent, INFINITE ); + + CloseHandle( jbt->hProxyEvent ); + jbt->hProxyEvent = NULL; + + ListRemove( LIST_FTIQID, listJid ); + + if ( jbt->bStreamActivated) + jbt->state = (this->*jbt->pfnSend)( hConn, jbt->ft ) ? JBT_DONE : JBT_ERROR; + else + jbt->state = JBT_ERROR; + } + else jbt->state = JBT_SOCKSERR; + break; + } + + return num; +} + + +void __cdecl CJabberProto::ByteReceiveThread( JABBER_BYTE_TRANSFER *jbt ) +{ + HXML iqNode, queryNode = NULL, n; + const TCHAR *sid = NULL, *from = NULL, *to = NULL, *szId = NULL, *szHost, *szPort, *str; + int i; + WORD port; + HANDLE hConn; + char data[3]; + char* buffer; + int datalen, bytesParsed, recvResult; + BOOL validStreamhost = FALSE; + + if ( jbt == NULL ) return; + + jbt->state = JBT_INIT; + + if ( iqNode = jbt->iqNode ) { + from = xmlGetAttrValue( iqNode, _T("from")); + to = xmlGetAttrValue( iqNode, _T("to")); + szId = xmlGetAttrValue( iqNode, _T("id")); + + queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode ) + sid = xmlGetAttrValue( queryNode, _T("sid")); + } + + if ( szId && from && to && sid && ( n = xmlGetChild( queryNode , "streamhost" ))!=NULL ) { + jbt->iqId = mir_tstrdup( szId ); + jbt->srcJID = mir_tstrdup( from ); + jbt->dstJID = mir_tstrdup( to ); + jbt->sid = mir_tstrdup( sid ); + + if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE ))) { + for ( i=1; ( n = xmlGetNthChild( queryNode, _T("streamhost"), i ))!=NULL; i++ ) { + if (( szHost = xmlGetAttrValue( n, _T("host"))) != NULL && + ( szPort = xmlGetAttrValue( n, _T("port"))) != NULL && + ( str = xmlGetAttrValue( n, _T("jid"))) != NULL ) { + + port = ( WORD )_ttoi( szPort ); + if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); + jbt->streamhostJID = mir_tstrdup( str ); + + Log( "bytestream_recv connecting to " TCHAR_STR_PARAM ":%d", szHost, port ); + NETLIBOPENCONNECTION nloc = { 0 }; + nloc.cbSize = sizeof( nloc ); + nloc.szHost = mir_t2a(szHost); + nloc.wPort = port; + hConn = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); + mir_free((void*)nloc.szHost); + + if ( hConn == NULL ) { + Log( "bytestream_recv_connection connection failed ( %d ), try next streamhost", WSAGetLastError()); + continue; + } + + jbt->hConn = hConn; + + data[0] = 5; + data[1] = 1; + data[2] = 0; + Netlib_Send( hConn, data, 3, 0 ); + + jbt->state = JBT_INIT; + datalen = 0; + while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { + recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); + if ( recvResult <= 0 ) break; + datalen += recvResult; + bytesParsed = ByteReceiveParse( hConn, jbt, buffer, datalen ); + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + if ( jbt->state == JBT_RECVING ) validStreamhost = TRUE; + } + Netlib_CloseHandle( hConn ); + Log( "bytestream_recv_connection closing connection" ); + } + if ( jbt->state==JBT_ERROR || validStreamhost==TRUE ) + break; + Log( "bytestream_recv_connection stream cannot be established, try next streamhost" ); + } + mir_free( buffer ); + } + } + + (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); + jbt->ft = NULL; + if ( !validStreamhost && szId && from ) { + Log( "bytestream_recv_connection session not completed" ); + + m_ThreadInfo->send( XmlNodeIq( _T("error"), szId, from ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + } + + delete jbt; + Log( "Thread ended: type=bytestream_recv" ); +} + +int CJabberProto::ByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) +{ + int bytesReceived, num = datalen; + + switch ( jbt->state ) { + case JBT_INIT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 selected method ( 0=no auth, 0xff=error ) + // send: + // 00-00 ver ( 0x05 ) + // 01-01 cmd ( 1=connect ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 3 ) + // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) + // 45-46 dst.port ( 0 ) + if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { + BYTE data[47]; + ZeroMemory( data, sizeof( data )); + *(( DWORD* )data ) = 0x03000105; + data[4] = 40; + + TCHAR text[JABBER_MAX_JID_LEN*2]; + TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); + TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); + mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); + mir_free(szInitiatorJid); + mir_free(szTargetJid); + char* szAuthString = mir_utf8encodeT( text ); + Log( "Auth: '%s'", szAuthString ); + char* szHash = JabberSha1( szAuthString ); + strncpy(( char* )( data+5 ), szHash, 40 ); + mir_free( szHash ); + Netlib_Send( hConn, ( char* )data, 47, 0 ); + jbt->state = JBT_CONNECT; + mir_free( szAuthString ); + } + else jbt->state = JBT_SOCKSERR; + break; + + case JBT_CONNECT: + // received: + // 00-00 ver ( 0x05 ) + // 01-01 reply ( 0=success,2=not allowed ) + // 02-02 reserved ( 0 ) + // 03-03 address type ( 1=IPv4 address,3=host address ) + // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) + // nn-nn+1 bnd.port server bound port + if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { + if ( buffer[3]==1 && datalen>=10 ) + num = 10; + else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) + num = buffer[4] + 7; + else if ( buffer[3]==0 && datalen>=6 ) + num = 6; + else { + jbt->state = JBT_SOCKSERR; + break; + } + jbt->state = JBT_RECVING; + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), jbt->iqId, jbt->srcJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) + << XCHILD( _T("streamhost-used")) << XATTR( _T("jid"), jbt->streamhostJID )); + } + else jbt->state = JBT_SOCKSERR; + break; + + case JBT_RECVING: + bytesReceived = (this->*jbt->pfnRecv)( hConn, jbt->ft, buffer, datalen ); + if ( bytesReceived < 0 ) + jbt->state = JBT_ERROR; + else if ( bytesReceived == 0 ) + jbt->state = JBT_DONE; + break; + } + + return num; +} diff --git a/protocols/JabberG/src/jabber_byte.h b/protocols/JabberG/src/jabber_byte.h new file mode 100644 index 0000000000..657d797fce --- /dev/null +++ b/protocols/JabberG/src/jabber_byte.h @@ -0,0 +1,61 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_BYTE_H_ +#define _JABBER_BYTE_H_ + +typedef enum { JBT_INIT, JBT_AUTH, JBT_CONNECT, JBT_SOCKSERR, JBT_SENDING, JBT_RECVING, JBT_DONE, JBT_ERROR } JABBER_BYTE_STATE; + +struct CJabberProto; +struct filetransfer; + +struct JABBER_BYTE_TRANSFER +{ + ~JABBER_BYTE_TRANSFER(); + + TCHAR* sid; + TCHAR* srcJID; + TCHAR* dstJID; + TCHAR* streamhostJID; + TCHAR* iqId; + JABBER_BYTE_STATE state; + HANDLE hConn; + HANDLE hEvent; + HXML iqNode; + BOOL ( CJabberProto::*pfnSend )( HANDLE hConn, filetransfer* ft ); + int ( CJabberProto::*pfnRecv )( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); + void ( CJabberProto::*pfnFinal )( BOOL success, filetransfer* ft ); + filetransfer* ft; + + // XEP-0065 proxy support + BOOL bProxyDiscovered; + HANDLE hProxyEvent; + TCHAR* szProxyHost; + TCHAR* szProxyPort; + TCHAR* szProxyJid; + TCHAR* szStreamhostUsed; + BOOL bStreamActivated; + HANDLE hSendEvent; +}; + +#endif diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp new file mode 100644 index 0000000000..380cf03087 --- /dev/null +++ b/protocols/JabberG/src/jabber_caps.cpp @@ -0,0 +1,697 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "version.h" + +const JabberFeatCapPair g_JabberFeatCapPairs[] = { + { _T(JABBER_FEAT_DISCO_INFO), JABBER_CAPS_DISCO_INFO, _T("Supports Service Discovery info"), }, + { _T(JABBER_FEAT_DISCO_ITEMS), JABBER_CAPS_DISCO_ITEMS, _T("Supports Service Discovery items list"), }, + { _T(JABBER_FEAT_ENTITY_CAPS), JABBER_CAPS_ENTITY_CAPS, _T("Can inform about its Jabber capabilities"), }, + { _T(JABBER_FEAT_SI), JABBER_CAPS_SI, _T("Supports stream initiation (for filetransfers for ex.)"), }, + { _T(JABBER_FEAT_SI_FT), JABBER_CAPS_SI_FT, _T("Supports stream initiation for file transfers"), }, + { _T(JABBER_FEAT_BYTESTREAMS), JABBER_CAPS_BYTESTREAMS, _T("Supports file transfers via SOCKS5 Bytestreams"), }, + { _T(JABBER_FEAT_IBB), JABBER_CAPS_IBB, _T("Supports file transfers via In-Band Bytestreams"), }, + { _T(JABBER_FEAT_OOB), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), }, + { _T(JABBER_FEAT_OOB2), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), }, + { _T(JABBER_FEAT_COMMANDS), JABBER_CAPS_COMMANDS, _T("Supports execution of Ad-Hoc commands"), }, + { _T(JABBER_FEAT_REGISTER), JABBER_CAPS_REGISTER, _T("Supports in-band registration"), }, + { _T(JABBER_FEAT_MUC), JABBER_CAPS_MUC, _T("Supports multi-user chat"), }, + { _T(JABBER_FEAT_CHATSTATES), JABBER_CAPS_CHATSTATES, _T("Can report chat state in a chat session"), }, + { _T(JABBER_FEAT_LAST_ACTIVITY), JABBER_CAPS_LAST_ACTIVITY, _T("Can report information about the last activity of the user"), }, + { _T(JABBER_FEAT_VERSION), JABBER_CAPS_VERSION, _T("Can report own version information"), }, + { _T(JABBER_FEAT_ENTITY_TIME), JABBER_CAPS_ENTITY_TIME, _T("Can report local time of the user"), }, + { _T(JABBER_FEAT_PING), JABBER_CAPS_PING, _T("Can send and receive ping requests"), }, + { _T(JABBER_FEAT_DATA_FORMS), JABBER_CAPS_DATA_FORMS, _T("Supports data forms"), }, + { _T(JABBER_FEAT_MESSAGE_EVENTS), JABBER_CAPS_MESSAGE_EVENTS, _T("Can request and respond to events relating to the delivery, display, and composition of messages"), }, + { _T(JABBER_FEAT_VCARD_TEMP), JABBER_CAPS_VCARD_TEMP, _T("Supports vCard"), }, + { _T(JABBER_FEAT_AVATAR), JABBER_CAPS_AVATAR, _T("Supports iq-based avatars"), }, + { _T(JABBER_FEAT_XHTML), JABBER_CAPS_XHTML, _T("Supports XHTML formatting of chat messages"), }, + { _T(JABBER_FEAT_AGENTS), JABBER_CAPS_AGENTS, _T("Supports Jabber Browsing"), }, + { _T(JABBER_FEAT_BROWSE), JABBER_CAPS_BROWSE, _T("Supports Jabber Browsing"), }, + { _T(JABBER_FEAT_FEATURE_NEG), JABBER_CAPS_FEATURE_NEG, _T("Can negotiate options for specific features"), }, + { _T(JABBER_FEAT_AMP), JABBER_CAPS_AMP, _T("Can request advanced processing of message stanzas"), }, + { _T(JABBER_FEAT_USER_MOOD), JABBER_CAPS_USER_MOOD, _T("Can report information about user moods"), }, + { _T(JABBER_FEAT_USER_MOOD_NOTIFY), JABBER_CAPS_USER_MOOD_NOTIFY, _T("Receives information about user moods"), }, + { _T(JABBER_FEAT_PUBSUB), JABBER_CAPS_PUBSUB, _T("Supports generic publish-subscribe functionality"), }, + { _T(JABBER_FEAT_SECUREIM), JABBER_CAPS_SECUREIM, _T("Supports SecureIM plugin for Miranda NG"), }, + { _T(JABBER_FEAT_PRIVACY_LISTS), JABBER_CAPS_PRIVACY_LISTS, _T("Can block communications from particular other users using Privacy lists"), }, + { _T(JABBER_FEAT_MESSAGE_RECEIPTS), JABBER_CAPS_MESSAGE_RECEIPTS, _T("Supports Message Receipts"), }, + { _T(JABBER_FEAT_USER_TUNE), JABBER_CAPS_USER_TUNE, _T("Can report information about the music to which a user is listening"), }, + { _T(JABBER_FEAT_USER_TUNE_NOTIFY), JABBER_CAPS_USER_TUNE_NOTIFY, _T("Receives information about the music to which a user is listening"), }, + { _T(JABBER_FEAT_PRIVATE_STORAGE), JABBER_CAPS_PRIVATE_STORAGE, _T("Supports private XML Storage (for bookmakrs and other)"), }, + { _T(JABBER_FEAT_ATTENTION), JABBER_CAPS_ATTENTION, _T("Supports attention requests ('nudge')"), }, + { _T(JABBER_FEAT_ATTENTION_0), JABBER_CAPS_ATTENTION_0, _T("Supports attention requests ('nudge')"), }, + { _T(JABBER_FEAT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY, _T("Can report information about user activity"), }, + { _T(JABBER_FEAT_USER_ACTIVITY_NOTIFY), JABBER_CAPS_USER_ACTIVITY_NOTIFY, _T("Receives information about user activity"), }, + { _T(JABBER_FEAT_MIRANDA_NOTES), JABBER_CAPS_MIRANDA_NOTES, _T("Supports Miranda NG notes extension"), }, + { _T(JABBER_FEAT_JINGLE), JABBER_CAPS_JINGLE, _T("Supports Jingle"), }, + { _T(JABBER_FEAT_ROSTER_EXCHANGE), JABBER_CAPS_ROSTER_EXCHANGE, _T("Supports Roster Exchange"), }, + { _T(JABBER_FEAT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC, _T("Supports GTalk private multi-user chat"), }, + { NULL, 0, NULL} +}; + +const JabberFeatCapPair g_JabberFeatCapPairsExt[] = { + { _T(JABBER_EXT_SECUREIM), JABBER_CAPS_SECUREIM }, + { _T(JABBER_EXT_COMMANDS), JABBER_CAPS_COMMANDS }, + { _T(JABBER_EXT_USER_MOOD), JABBER_CAPS_USER_MOOD_NOTIFY }, + { _T(JABBER_EXT_USER_TUNE), JABBER_CAPS_USER_TUNE_NOTIFY }, + { _T(JABBER_EXT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY_NOTIFY }, + { _T(JABBER_EXT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC }, + { _T(JABBER_EXT_MIR_NOTES), JABBER_CAPS_MIRANDA_NOTES, }, + { szCoreVersion, JABBER_CAPS_MIRANDA_PARTIAL }, + { NULL, 0 } +}; + +void CJabberProto::OnIqResultCapsDiscoInfoSI( HXML, CJabberIqInfo* pInfo ) +{ + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); + if ( !r ) + return; + + if ( r->szCapsNode == NULL ) + OnIqResultCapsDiscoInfo( NULL, pInfo ); + + HXML query = pInfo->GetChildNode(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && query ) { + // XEP-0232 support + HXML xform; + for ( int i = 1; ( xform = xmlGetNthChild( query, _T("x"), i)) != NULL; i++ ) { + TCHAR *szFormTypeValue = XPath( xform, _T("field[@var='FORM_TYPE']/value")); + if ( szFormTypeValue && !_tcscmp( szFormTypeValue, _T("urn:xmpp:dataforms:softwareinfo"))) { + if ( r->pSoftwareInfo ) + delete r->pSoftwareInfo; + r->pSoftwareInfo = new JABBER_XEP0232_SOFTWARE_INFO; + if ( r->pSoftwareInfo ) { + TCHAR *szTmp = XPath( xform, _T("field[@var='os']/value")); + if ( szTmp ) + r->pSoftwareInfo->szOs = mir_tstrdup( szTmp ); + szTmp = XPath( xform, _T("field[@var='os_version']/value")); + if ( szTmp ) + r->pSoftwareInfo->szOsVersion = mir_tstrdup( szTmp ); + szTmp = XPath( xform, _T("field[@var='software']/value")); + if ( szTmp ) + r->pSoftwareInfo->szSoftware = mir_tstrdup( szTmp ); + szTmp = XPath( xform, _T("field[@var='software_version']/value")); + if ( szTmp ) + r->pSoftwareInfo->szSoftwareVersion = mir_tstrdup( szTmp ); + szTmp = XPath( xform, _T("field[@var='x-miranda-core-version']/value")); + if ( szTmp ) + r->pSoftwareInfo->szXMirandaCoreVersion = mir_tstrdup( szTmp ); + szTmp = XPath( xform, _T("field[@var='x-miranda-core-is-unicode']/value")); + if ( !szTmp ) // old deprecated format + szTmp = XPath( xform, _T("field[@var='x-miranda-is-unicode']/value")); + if ( szTmp && _ttoi( szTmp )) + r->pSoftwareInfo->bXMirandaIsUnicode = TRUE; + szTmp = XPath( xform, _T("field[@var='x-miranda-core-is-alpha']/value")); + if ( !szTmp ) // old deprecated format + szTmp = XPath( xform, _T("field[@var='x-miranda-is-alpha']/value")); + if ( szTmp && _ttoi( szTmp )) + r->pSoftwareInfo->bXMirandaIsAlpha = TRUE; + szTmp = XPath( xform, _T("field[@var='x-miranda-jabber-is-debug']/value")); + if ( szTmp && _ttoi( szTmp )) + r->pSoftwareInfo->bXMirandaIsDebug = TRUE; + } + JabberUserInfoUpdate( pInfo->GetHContact()); + } + } + } +} + +void CJabberProto::OnIqResultCapsDiscoInfo( HXML, CJabberIqInfo* pInfo ) +{ + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); + + HXML query = pInfo->GetChildNode(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && query ) { + JabberCapsBits jcbCaps = 0; + HXML feature; + for ( int i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { + const TCHAR *featureName = xmlGetAttrValue( feature, _T("var")); + if ( featureName ) { + for ( int j = 0; g_JabberFeatCapPairs[j].szFeature; j++ ) { + if ( !_tcscmp( g_JabberFeatCapPairs[j].szFeature, featureName )) { + jcbCaps |= g_JabberFeatCapPairs[j].jcbCap; + break; + } } } } + + // no version info support and no XEP-0115 support? + if ( r && r->dwVersionRequestTime == -1 && !r->version && !r->software && !r->szCapsNode ) { + r->jcbCachedCaps = jcbCaps; + r->dwDiscoInfoRequestTime = -1; + return; + } + + if (!m_clientCapsManager.SetClientCaps( pInfo->GetIqId(), jcbCaps )) + if ( r ) + r->jcbCachedCaps = jcbCaps; + JabberUserInfoUpdate( pInfo->GetHContact()); + } + else { + // no version info support and no XEP-0115 support? + if ( r && r->dwVersionRequestTime == -1 && !r->version && !r->software && !r->szCapsNode ) { + r->jcbCachedCaps = JABBER_RESOURCE_CAPS_NONE; + r->dwDiscoInfoRequestTime = -1; + return; + } + m_clientCapsManager.SetClientCaps( pInfo->GetIqId(), JABBER_RESOURCE_CAPS_ERROR ); + } +} + +JabberCapsBits CJabberProto::GetTotalJidCapabilites( const TCHAR *jid ) +{ + if ( !jid ) + return JABBER_RESOURCE_CAPS_NONE; + + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( jid, szBareJid, SIZEOF( szBareJid )); + + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, szBareJid ); + if ( !item ) + item = ListGetItemPtr( LIST_VCARD_TEMP, szBareJid ); + + JabberCapsBits jcbToReturn = JABBER_RESOURCE_CAPS_NONE; + + // get bare jid info only if where is no resources + if ( !item || ( item && !item->resourceCount )) { + jcbToReturn = GetResourceCapabilites( szBareJid, FALSE ); + if ( jcbToReturn & JABBER_RESOURCE_CAPS_ERROR) + jcbToReturn = JABBER_RESOURCE_CAPS_NONE; + } + + if ( item ) { + for ( int i = 0; i < item->resourceCount; i++ ) { + TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; + mir_sntprintf( szFullJid, JABBER_MAX_JID_LEN, _T("%s/%s"), szBareJid, item->resource[i].resourceName ); + JabberCapsBits jcb = GetResourceCapabilites( szFullJid, FALSE ); + if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) + jcbToReturn |= jcb; + } + } + return jcbToReturn; +} + +JabberCapsBits CJabberProto::GetResourceCapabilites( const TCHAR *jid, BOOL appendBestResource ) +{ + TCHAR fullJid[ JABBER_MAX_JID_LEN ]; + if ( appendBestResource ) + GetClientJID( jid, fullJid, SIZEOF( fullJid )); + else + _tcsncpy( fullJid, jid, SIZEOF( fullJid )); + + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( fullJid ); + if ( r == NULL ) + return JABBER_RESOURCE_CAPS_ERROR; + + // XEP-0115 mode + if ( r->szCapsNode && r->szCapsVer ) { + JabberCapsBits jcbCaps = 0, jcbExtCaps = 0; + BOOL bRequestSent = FALSE; + JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps( r->szCapsNode, r->szCapsVer ); + + if ( jcbMainCaps == JABBER_RESOURCE_CAPS_TIMEOUT && !r->dwDiscoInfoRequestTime ) + jcbMainCaps = JABBER_RESOURCE_CAPS_ERROR; + + if ( jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT ) { + // send disco#info query + + CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); + pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); + m_clientCapsManager.SetClientCaps( r->szCapsNode, r->szCapsVer, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); + r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); + + TCHAR queryNode[512]; + mir_sntprintf( queryNode, SIZEOF(queryNode), _T("%s#%s"), r->szCapsNode, r->szCapsVer ); + m_ThreadInfo->send( XmlNodeIq( pInfo ) << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), queryNode )); + + bRequestSent = TRUE; + } + else if ( jcbMainCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS ) + bRequestSent = TRUE; + else if ( jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT ) + jcbCaps |= jcbMainCaps; + + if ( jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT && r->szCapsExt ) { + TCHAR *caps = mir_tstrdup( r->szCapsExt ); + + TCHAR *token = _tcstok( caps, _T(" ")); + while ( token ) { + switch ( jcbExtCaps = m_clientCapsManager.GetClientCaps( r->szCapsNode, token )) { + case JABBER_RESOURCE_CAPS_ERROR: + break; + + case JABBER_RESOURCE_CAPS_UNINIT: + { + // send disco#info query + + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); + pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); + m_clientCapsManager.SetClientCaps( r->szCapsNode, token, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); + + TCHAR queryNode[512]; + mir_sntprintf( queryNode, SIZEOF(queryNode), _T("%s#%s"), r->szCapsNode, token ); + m_ThreadInfo->send( + XmlNodeIq( pInfo ) << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), queryNode )); + + bRequestSent = TRUE; + break; + } + case JABBER_RESOURCE_CAPS_IN_PROGRESS: + bRequestSent = TRUE; + break; + + default: + jcbCaps |= jcbExtCaps; + } + + token = _tcstok( NULL, _T(" ")); + } + + mir_free(caps); + } + + if ( bRequestSent ) + return JABBER_RESOURCE_CAPS_IN_PROGRESS; + + return jcbCaps | r->jcbManualDiscoveredCaps; + } + + // capability mode (version request + service discovery) + + // no version info: + if ( !r->version && !r->software ) { + // version request not sent: + if ( !r->dwVersionRequestTime ) { + // send version query + + CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE ); + pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); + r->dwVersionRequestTime = pInfo->GetRequestTime(); + + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_VERSION)); + m_ThreadInfo->send( iq ); + return JABBER_RESOURCE_CAPS_IN_PROGRESS; + } + // version not received: + else if ( r->dwVersionRequestTime != -1 ) { + // no timeout? + if ( GetTickCount() - r->dwVersionRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) + return JABBER_RESOURCE_CAPS_IN_PROGRESS; + + // timeout + r->dwVersionRequestTime = -1; + } + // no version information, try direct service discovery + if ( !r->dwDiscoInfoRequestTime ) { + // send disco#info query + + CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); + pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); + r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); + + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); + m_ThreadInfo->send( iq ); + + return JABBER_RESOURCE_CAPS_IN_PROGRESS; + } + else if ( r->dwDiscoInfoRequestTime == -1 ) + return r->jcbCachedCaps | r->jcbManualDiscoveredCaps; + else if ( GetTickCount() - r->dwDiscoInfoRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) + return JABBER_RESOURCE_CAPS_IN_PROGRESS; + else + r->dwDiscoInfoRequestTime = -1; + // version request timeout: + return JABBER_RESOURCE_CAPS_NONE; + } + + // version info available: + if ( r->software && r->version ) { + JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps( r->software, r->version ); + if ( jcbMainCaps == JABBER_RESOURCE_CAPS_ERROR ) { + // Bombus hack: + if ( !_tcscmp( r->software, _T( "Bombus" )) || !_tcscmp( r->software, _T( "BombusMod" ))) { + jcbMainCaps = JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_IBB|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_VERSION|JABBER_CAPS_COMMANDS|JABBER_CAPS_VCARD_TEMP; + m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); + } + // Neos hack: + else if ( !_tcscmp( r->software, _T( "neos" ))) { + jcbMainCaps = JABBER_CAPS_OOB|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_VERSION; + m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); + } + // sim hack: + else if ( !_tcscmp( r->software, _T( "sim" ))) { + jcbMainCaps = JABBER_CAPS_OOB|JABBER_CAPS_VERSION|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY; + m_clientCapsManager.SetClientCaps( r->software, r->version, jcbMainCaps ); + } } + + else if ( jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT ) { + // send disco#info query + + CJabberIqInfo *pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE ); + pInfo->SetTimeout( JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ); + m_clientCapsManager.SetClientCaps( r->software, r->version, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); + r->dwDiscoInfoRequestTime = pInfo->GetRequestTime(); + + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); + m_ThreadInfo->send( iq ); + + jcbMainCaps = JABBER_RESOURCE_CAPS_IN_PROGRESS; + } + return jcbMainCaps | r->jcbManualDiscoveredCaps; + } + + return JABBER_RESOURCE_CAPS_NONE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CJabberClientPartialCaps class members + +CJabberClientPartialCaps::CJabberClientPartialCaps( const TCHAR *szVer ) +{ + m_szVer = mir_tstrdup( szVer ); + m_jcbCaps = JABBER_RESOURCE_CAPS_UNINIT; + m_pNext = NULL; + m_nIqId = -1; + m_dwRequestTime = 0; +} + +CJabberClientPartialCaps::~CJabberClientPartialCaps() +{ + mir_free( m_szVer ); + if ( m_pNext ) + delete m_pNext; +} + +CJabberClientPartialCaps* CJabberClientPartialCaps::SetNext( CJabberClientPartialCaps *pCaps ) +{ + CJabberClientPartialCaps *pRetVal = m_pNext; + m_pNext = pCaps; + return pRetVal; +} + +void CJabberClientPartialCaps::SetCaps( JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) +{ + if ( jcbCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS ) + m_dwRequestTime = GetTickCount(); + else + m_dwRequestTime = 0; + m_jcbCaps = jcbCaps; + m_nIqId = nIqId; +} + +JabberCapsBits CJabberClientPartialCaps::GetCaps() +{ + if ( m_jcbCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS && GetTickCount() - m_dwRequestTime > JABBER_RESOURCE_CAPS_QUERY_TIMEOUT ) { + m_jcbCaps = JABBER_RESOURCE_CAPS_TIMEOUT; + m_dwRequestTime = 0; + } + return m_jcbCaps; +} + +CJabberClientPartialCaps* CJabberClientCaps::FindByVersion( const TCHAR *szVer ) +{ + if ( !m_pCaps || !szVer ) + return NULL; + + CJabberClientPartialCaps *pCaps = m_pCaps; + while ( pCaps ) { + if ( !_tcscmp( szVer, pCaps->GetVersion())) + break; + pCaps = pCaps->GetNext(); + } + return pCaps; +} + +CJabberClientPartialCaps* CJabberClientCaps::FindById( int nIqId ) +{ + if ( !m_pCaps || nIqId == -1 ) + return NULL; + + CJabberClientPartialCaps *pCaps = m_pCaps; + while ( pCaps ) { + if ( pCaps->GetIqId() == nIqId ) + break; + pCaps = pCaps->GetNext(); + } + return pCaps; +} + +CJabberClientCaps::CJabberClientCaps( const TCHAR *szNode ) +{ + m_szNode = mir_tstrdup( szNode ); + m_pCaps = NULL; + m_pNext= NULL; +} + +CJabberClientCaps::~CJabberClientCaps() { + mir_free( m_szNode ); + if ( m_pCaps ) + delete m_pCaps; + if ( m_pNext ) + delete m_pNext; +} + +CJabberClientCaps* CJabberClientCaps::SetNext( CJabberClientCaps *pClient ) +{ + CJabberClientCaps *pRetVal = m_pNext; + m_pNext = pClient; + return pRetVal; +} + +JabberCapsBits CJabberClientCaps::GetPartialCaps( TCHAR *szVer ) { + CJabberClientPartialCaps *pCaps = FindByVersion( szVer ); + if ( !pCaps ) + return JABBER_RESOURCE_CAPS_UNINIT; + return pCaps->GetCaps(); +} + +BOOL CJabberClientCaps::SetPartialCaps( const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) { + CJabberClientPartialCaps *pCaps = FindByVersion( szVer ); + if ( !pCaps ) { + pCaps = new CJabberClientPartialCaps( szVer ); + if ( !pCaps ) + return FALSE; + pCaps->SetNext( m_pCaps ); + m_pCaps = pCaps; + } + if ( !(jcbCaps & JABBER_RESOURCE_CAPS_ERROR) && m_szNode && szVer ) { + if ( !_tcscmp( m_szNode, _T( "http://miranda-im.org/caps" )) && !_tcscmp( szVer, _T( "0.7.0.13" ))) + jcbCaps = jcbCaps & ( ~JABBER_CAPS_MESSAGE_RECEIPTS ); + } + pCaps->SetCaps( jcbCaps, nIqId ); + return TRUE; +} + +BOOL CJabberClientCaps::SetPartialCaps( int nIqId, JabberCapsBits jcbCaps ) { + CJabberClientPartialCaps *pCaps = FindById( nIqId ); + if ( !pCaps ) + return FALSE; + if ( !(jcbCaps & JABBER_RESOURCE_CAPS_ERROR) && m_szNode && pCaps->GetVersion()) { + if ( !_tcscmp( m_szNode, _T( "http://miranda-im.org/caps" )) && !_tcscmp( pCaps->GetVersion(), _T( "0.7.0.13" ))) + jcbCaps = jcbCaps & ( ~JABBER_CAPS_MESSAGE_RECEIPTS ); + } + pCaps->SetCaps( jcbCaps, -1 ); + return TRUE; +} + +CJabberClientCapsManager::CJabberClientCapsManager( CJabberProto* proto ) +{ + ppro = proto; + InitializeCriticalSection( &m_cs ); + m_pClients = NULL; +} + +CJabberClientCapsManager::~CJabberClientCapsManager() +{ + if ( m_pClients ) + delete m_pClients; + DeleteCriticalSection( &m_cs ); +} + +CJabberClientCaps * CJabberClientCapsManager::FindClient( const TCHAR *szNode ) +{ + if ( !m_pClients || !szNode ) + return NULL; + + CJabberClientCaps *pClient = m_pClients; + while ( pClient ) { + if ( !_tcscmp( szNode, pClient->GetNode())) + break; + pClient = pClient->GetNext(); + } + return pClient; +} + +void CJabberClientCapsManager::AddDefaultCaps() { + SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), szCoreVersion, JABBER_CAPS_MIRANDA_ALL ); + + for ( int i = 0; g_JabberFeatCapPairsExt[i].szFeature; i++ ) + SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), g_JabberFeatCapPairsExt[i].szFeature, g_JabberFeatCapPairsExt[i].jcbCap ); +} + +JabberCapsBits CJabberClientCapsManager::GetClientCaps( TCHAR *szNode, TCHAR *szVer ) +{ + Lock(); + CJabberClientCaps *pClient = FindClient( szNode ); + if ( !pClient ) { + Unlock(); + ppro->Log( "CAPS: get no caps for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, szNode, szVer ); + return JABBER_RESOURCE_CAPS_UNINIT; + } + JabberCapsBits jcbCaps = pClient->GetPartialCaps( szVer ); + Unlock(); + ppro->Log( "CAPS: get caps %I64x for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, jcbCaps, szNode, szVer ); + return jcbCaps; +} + +BOOL CJabberClientCapsManager::SetClientCaps( const TCHAR *szNode, const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId /*= -1*/ ) +{ + Lock(); + CJabberClientCaps *pClient = FindClient( szNode ); + if (!pClient) { + pClient = new CJabberClientCaps( szNode ); + if ( !pClient ) { + Unlock(); + return FALSE; + } + pClient->SetNext( m_pClients ); + m_pClients = pClient; + } + BOOL bOk = pClient->SetPartialCaps( szVer, jcbCaps, nIqId ); + Unlock(); + ppro->Log( "CAPS: set caps %I64x for: " TCHAR_STR_PARAM ", " TCHAR_STR_PARAM, jcbCaps, szNode, szVer ); + return bOk; +} + +BOOL CJabberClientCapsManager::SetClientCaps( int nIqId, JabberCapsBits jcbCaps ) +{ + Lock(); + if ( !m_pClients ) { + Unlock(); + return FALSE; + } + BOOL bOk = FALSE; + CJabberClientCaps *pClient = m_pClients; + while ( pClient ) { + if ( pClient->SetPartialCaps( nIqId, jcbCaps )) { + ppro->Log( "CAPS: set caps %I64x for iq %d", jcbCaps, nIqId ); + bOk = TRUE; + break; + } + pClient = pClient->GetNext(); + } + Unlock(); + return bOk; +} + +BOOL CJabberClientCapsManager::HandleInfoRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) +{ + int i; + JabberCapsBits jcb = 0; + + if ( szNode ) { + for ( i = 0; g_JabberFeatCapPairsExt[i].szFeature; i++ ) { + TCHAR szExtCap[ 512 ]; + mir_sntprintf( szExtCap, SIZEOF(szExtCap), _T("%s#%s"), _T(JABBER_CAPS_MIRANDA_NODE), g_JabberFeatCapPairsExt[i].szFeature ); + if ( !_tcscmp( szNode, szExtCap )) { + jcb = g_JabberFeatCapPairsExt[i].jcbCap; + break; + } + } + + // check features registered through IJabberNetInterface::RegisterFeature() and IJabberNetInterface::AddFeatures() + for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { + TCHAR szExtCap[ 512 ]; + mir_sntprintf( szExtCap, SIZEOF(szExtCap), _T("%s#%s"), _T(JABBER_CAPS_MIRANDA_NODE), ppro->m_lstJabberFeatCapPairsDynamic[i]->szExt ); + if ( !_tcscmp( szNode, szExtCap )) { + jcb = ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; + break; + } + } + + // unknown node, not XEP-0115 request + if ( !jcb ) + return FALSE; + } + else { + jcb = JABBER_CAPS_MIRANDA_ALL; + for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) + jcb |= ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; + } + + if (!ppro->m_options.AllowVersionRequests) + jcb &= ~JABBER_CAPS_VERSION; + + XmlNodeIq iq( _T("result"), pInfo ); + + HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); + if ( szNode ) + query << XATTR( _T("node"), szNode ); + + query << XCHILD( _T("identity")) << XATTR( _T("category"), _T("client")) + << XATTR( _T("type"), _T("pc")) << XATTR( _T("name"), _T("Miranda")); + + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) + if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) + query << XCHILD( _T("feature")) << XATTR( _T("var"), g_JabberFeatCapPairs[i].szFeature ); + + for ( i = 0; i < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) + if ( jcb & ppro->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) + query << XCHILD( _T("feature")) << XATTR( _T("var"), ppro->m_lstJabberFeatCapPairsDynamic[i]->szFeature ); + + if ( ppro->m_options.AllowVersionRequests && !szNode ) { + TCHAR szOsBuffer[256] = {0}; + TCHAR *os = szOsBuffer; + + if ( ppro->m_options.ShowOSVersion ) { + if (!GetOSDisplayString(szOsBuffer, SIZEOF(szOsBuffer))) + lstrcpyn(szOsBuffer, _T(""), SIZEOF(szOsBuffer)); + else { + TCHAR *szOsWindows = _T("Microsoft Windows"); + size_t nOsWindowsLength = _tcslen( szOsWindows ); + if (!_tcsnicmp(szOsBuffer, szOsWindows, nOsWindowsLength)) + os += nOsWindowsLength + 1; + } + } + + HXML form = query << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("result")); + form << XCHILD( _T("field")) << XATTR( _T("var"), _T("FORM_TYPE")) << XATTR( _T("type"), _T("hidden")) + << XCHILD( _T("value"), _T("urn:xmpp:dataforms:softwareinfo")); + + if ( ppro->m_options.ShowOSVersion ) { + form << XCHILD( _T("field")) << XATTR( _T("var"), _T("os")) << XCHILD( _T("value"), _T("Microsoft Windows")); + form << XCHILD( _T("field")) << XATTR( _T("var"), _T("os_version")) << XCHILD( _T("value"), os ); + } + form << XCHILD( _T("field")) << XATTR( _T("var"), _T("software")) << XCHILD( _T("value"), _T("Miranda NG Jabber Protocol")); + form << XCHILD( _T("field")) << XATTR( _T("var"), _T("software_version")) << XCHILD( _T("value"), szCoreVersion); + } + + ppro->m_ThreadInfo->send( iq ); + + return TRUE; +} diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h new file mode 100644 index 0000000000..e0525f2a16 --- /dev/null +++ b/protocols/JabberG/src/jabber_caps.h @@ -0,0 +1,287 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_CAPS_H_ +#define _JABBER_CAPS_H_ + +#include "jabber_iq.h" + +typedef unsigned __int64 JabberCapsBits; + +#define JABBER_RESOURCE_CAPS_QUERY_TIMEOUT 10000 + +#ifdef __GNUC__ +#define JABBER_RESOURCE_CAPS_ERROR 0x8000000000000000ULL +#define JABBER_RESOURCE_CAPS_IN_PROGRESS 0x8000000000000001ULL +#define JABBER_RESOURCE_CAPS_TIMEOUT 0x8000000000000002ULL +#define JABBER_RESOURCE_CAPS_UNINIT 0x8000000000000003ULL +#define JABBER_RESOURCE_CAPS_NONE 0x0000000000000000ULL +#else +#define JABBER_RESOURCE_CAPS_ERROR 0x8000000000000000 +#define JABBER_RESOURCE_CAPS_IN_PROGRESS 0x8000000000000001 +#define JABBER_RESOURCE_CAPS_TIMEOUT 0x8000000000000002 +#define JABBER_RESOURCE_CAPS_UNINIT 0x8000000000000003 +#define JABBER_RESOURCE_CAPS_NONE 0x0000000000000000 +#endif + +#define JABBER_FEAT_DISCO_INFO "http://jabber.org/protocol/disco#info" +#define JABBER_CAPS_DISCO_INFO ((JabberCapsBits)1) +#define JABBER_FEAT_DISCO_ITEMS "http://jabber.org/protocol/disco#items" +#define JABBER_CAPS_DISCO_ITEMS ((JabberCapsBits)1<<1) +#define JABBER_FEAT_ENTITY_CAPS "http://jabber.org/protocol/caps" +#define JABBER_CAPS_ENTITY_CAPS ((JabberCapsBits)1<<2) +#define JABBER_FEAT_SI "http://jabber.org/protocol/si" +#define JABBER_CAPS_SI ((JabberCapsBits)1<<3) +#define JABBER_FEAT_SI_FT "http://jabber.org/protocol/si/profile/file-transfer" +#define JABBER_CAPS_SI_FT ((JabberCapsBits)1<<4) +#define JABBER_FEAT_BYTESTREAMS "http://jabber.org/protocol/bytestreams" +#define JABBER_CAPS_BYTESTREAMS ((JabberCapsBits)1<<5) +#define JABBER_FEAT_IBB "http://jabber.org/protocol/ibb" +#define JABBER_CAPS_IBB ((JabberCapsBits)1<<6) +#define JABBER_FEAT_OOB "jabber:iq:oob" +#define JABBER_FEAT_OOB2 "jabber:x:oob" +#define JABBER_CAPS_OOB ((JabberCapsBits)1<<7) +#define JABBER_FEAT_COMMANDS "http://jabber.org/protocol/commands" +#define JABBER_CAPS_COMMANDS ((JabberCapsBits)1<<8) +#define JABBER_FEAT_REGISTER "jabber:iq:register" +#define JABBER_CAPS_REGISTER ((JabberCapsBits)1<<9) +#define JABBER_FEAT_MUC "http://jabber.org/protocol/muc" +#define JABBER_CAPS_MUC ((JabberCapsBits)1<<10) +#define JABBER_FEAT_CHATSTATES "http://jabber.org/protocol/chatstates" +#define JABBER_CAPS_CHATSTATES ((JabberCapsBits)1<<11) +#define JABBER_FEAT_LAST_ACTIVITY "jabber:iq:last" +#define JABBER_CAPS_LAST_ACTIVITY ((JabberCapsBits)1<<12) +#define JABBER_FEAT_VERSION "jabber:iq:version" +#define JABBER_CAPS_VERSION ((JabberCapsBits)1<<13) +#define JABBER_FEAT_ENTITY_TIME "urn:xmpp:time" +#define JABBER_CAPS_ENTITY_TIME ((JabberCapsBits)1<<14) +#define JABBER_FEAT_PING "urn:xmpp:ping" +#define JABBER_CAPS_PING ((JabberCapsBits)1<<15) +#define JABBER_FEAT_DATA_FORMS "jabber:x:data" +#define JABBER_CAPS_DATA_FORMS ((JabberCapsBits)1<<16) +#define JABBER_FEAT_MESSAGE_EVENTS "jabber:x:event" +#define JABBER_CAPS_MESSAGE_EVENTS ((JabberCapsBits)1<<17) +#define JABBER_FEAT_VCARD_TEMP "vcard-temp" +#define JABBER_CAPS_VCARD_TEMP ((JabberCapsBits)1<<18) +#define JABBER_FEAT_AVATAR "jabber:iq:avatar" +#define JABBER_FEAT_SERVER_AVATAR "storage:client:avatar" +#define JABBER_CAPS_AVATAR ((JabberCapsBits)1<<19) +#define JABBER_FEAT_XHTML "http://jabber.org/protocol/xhtml-im" +#define JABBER_CAPS_XHTML ((JabberCapsBits)1<<20) +#define JABBER_FEAT_AGENTS "jabber:iq:agents" +#define JABBER_CAPS_AGENTS ((JabberCapsBits)1<<21) +#define JABBER_FEAT_BROWSE "jabber:iq:browse" +#define JABBER_CAPS_BROWSE ((JabberCapsBits)1<<22) +#define JABBER_FEAT_FEATURE_NEG "http://jabber.org/protocol/feature-neg" +#define JABBER_CAPS_FEATURE_NEG ((JabberCapsBits)1<<23) +#define JABBER_FEAT_AMP "http://jabber.org/protocol/amp" +#define JABBER_CAPS_AMP ((JabberCapsBits)1<<24) +#define JABBER_FEAT_USER_MOOD "http://jabber.org/protocol/mood" +#define JABBER_CAPS_USER_MOOD ((JabberCapsBits)1<<25) +#define JABBER_FEAT_USER_MOOD_NOTIFY "http://jabber.org/protocol/mood+notify" +#define JABBER_CAPS_USER_MOOD_NOTIFY ((JabberCapsBits)1<<26) +#define JABBER_FEAT_PUBSUB "http://jabber.org/protocol/pubsub" +#define JABBER_CAPS_PUBSUB ((JabberCapsBits)1<<27) +#define JABBER_FEAT_SECUREIM "http://miranda-ng.org/caps/secureim" +#define JABBER_CAPS_SECUREIM ((JabberCapsBits)1<<28) +#define JABBER_FEAT_PRIVACY_LISTS "jabber:iq:privacy" +#define JABBER_CAPS_PRIVACY_LISTS ((JabberCapsBits)1<<29) +#define JABBER_FEAT_MESSAGE_RECEIPTS "urn:xmpp:receipts" +#define JABBER_CAPS_MESSAGE_RECEIPTS ((JabberCapsBits)1<<30) +#define JABBER_FEAT_USER_TUNE "http://jabber.org/protocol/tune" +#define JABBER_CAPS_USER_TUNE ((JabberCapsBits)1<<31) +#define JABBER_FEAT_USER_TUNE_NOTIFY "http://jabber.org/protocol/tune+notify" +#define JABBER_CAPS_USER_TUNE_NOTIFY ((JabberCapsBits)1<<32) +#define JABBER_FEAT_PRIVATE_STORAGE "jabber:iq:private" +#define JABBER_CAPS_PRIVATE_STORAGE ((JabberCapsBits)1<<33) +#define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha" +// deferred +#define JABBER_FEAT_ATTENTION "http://www.xmpp.org/extensions/xep-0224.html#ns" +#define JABBER_CAPS_ATTENTION ((JabberCapsBits)1<<34) +#define JABBER_FEAT_USER_ACTIVITY "http://jabber.org/protocol/activity" +#define JABBER_CAPS_USER_ACTIVITY ((JabberCapsBits)1<<35) +#define JABBER_FEAT_USER_ACTIVITY_NOTIFY "http://jabber.org/protocol/activity+notify" +#define JABBER_CAPS_USER_ACTIVITY_NOTIFY ((JabberCapsBits)1<<36) +#define JABBER_FEAT_ATTENTION_0 "urn:xmpp:attention:0" +#define JABBER_CAPS_ATTENTION_0 ((JabberCapsBits)1<<37) +#define JABBER_FEAT_MIRANDA_NOTES "http://miranda-ng.org/storage#notes" +#define JABBER_CAPS_MIRANDA_NOTES ((JabberCapsBits)1<<38) +#define JABBER_FEAT_JINGLE "urn:xmpp:jingle:1" +#define JABBER_CAPS_JINGLE ((JabberCapsBits)1<<39) +#define JABBER_FEAT_ROSTER_EXCHANGE "http://jabber.org/protocol/rosterx" +#define JABBER_CAPS_ROSTER_EXCHANGE ((JabberCapsBits)1<<40) +#define JABBER_FEAT_GTALK_PMUC "http://www.google.com/xmpp/protocol/pmuc/v1" +#define JABBER_CAPS_GTALK_PMUC ((JabberCapsBits)1<<41) + +#define JABBER_FEAT_PUBSUB_EVENT "http://jabber.org/protocol/pubsub#event" +#define JABBER_FEAT_PUBSUB_NODE_CONFIG "http://jabber.org/protocol/pubsub#node_config" + +#define JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY ((JabberCapsBits)1<<62) +#define JABBER_CAPS_OTHER_SPECIAL (JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_RESOURCE_CAPS_ERROR) // must contain all the caps not listed in g_JabberFeatCapPairs, to prevent using these bits for features registered through IJabberNetInterface::RegisterFeature() + +#define JABBER_CAPS_MIRANDA_NODE "http://miranda-ng.org/caps" +#define JABBER_CAPS_MIRANDA_ALL (JABBER_CAPS_DISCO_INFO|JABBER_CAPS_DISCO_ITEMS|JABBER_CAPS_MUC|JABBER_CAPS_ENTITY_CAPS|JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_BYTESTREAMS|JABBER_CAPS_IBB|JABBER_CAPS_OOB|JABBER_CAPS_CHATSTATES|JABBER_CAPS_AGENTS|JABBER_CAPS_BROWSE|JABBER_CAPS_VERSION|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_VCARD_TEMP|JABBER_CAPS_ENTITY_TIME|JABBER_CAPS_PING|JABBER_CAPS_PRIVACY_LISTS|JABBER_CAPS_MESSAGE_RECEIPTS|JABBER_CAPS_PRIVATE_STORAGE|JABBER_CAPS_ATTENTION_0|JABBER_CAPS_JINGLE|JABBER_CAPS_ROSTER_EXCHANGE|JABBER_CAPS_SECUREIM|JABBER_CAPS_COMMANDS|JABBER_CAPS_USER_MOOD_NOTIFY|JABBER_CAPS_USER_TUNE_NOTIFY|JABBER_CAPS_USER_ACTIVITY_NOTIFY) + +#define JABBER_CAPS_MIRANDA_PARTIAL (JABBER_CAPS_DISCO_INFO|JABBER_CAPS_DISCO_ITEMS|JABBER_CAPS_MUC|JABBER_CAPS_ENTITY_CAPS|JABBER_CAPS_SI|JABBER_CAPS_SI_FT|JABBER_CAPS_BYTESTREAMS|JABBER_CAPS_IBB|JABBER_CAPS_OOB|JABBER_CAPS_CHATSTATES|JABBER_CAPS_AGENTS|JABBER_CAPS_BROWSE|JABBER_CAPS_VERSION|JABBER_CAPS_LAST_ACTIVITY|JABBER_CAPS_DATA_FORMS|JABBER_CAPS_MESSAGE_EVENTS|JABBER_CAPS_VCARD_TEMP|JABBER_CAPS_ENTITY_TIME|JABBER_CAPS_PING|JABBER_CAPS_PRIVACY_LISTS|JABBER_CAPS_MESSAGE_RECEIPTS|JABBER_CAPS_PRIVATE_STORAGE|JABBER_CAPS_ATTENTION_0|JABBER_CAPS_JINGLE|JABBER_CAPS_ROSTER_EXCHANGE) + +#define JABBER_EXT_SECUREIM "secureim" +#define JABBER_EXT_COMMANDS "cmds" +#define JABBER_EXT_USER_MOOD "mood" +#define JABBER_EXT_USER_TUNE "tune" +#define JABBER_EXT_USER_ACTIVITY "activity" +#define JABBER_EXT_GTALK_PMUC "pmuc-v1" +#define JABBER_EXT_MIR_NOTES "mir_notes" + +#define JABBER_FEAT_EXT_ADDRESSING "http://jabber.org/protocol/address" +#define JABBER_FEAT_NESTED_ROSTER_GROUPS "roster:delimiter" + +#define JABBER_FEAT_RC "http://jabber.org/protocol/rc" +#define JABBER_FEAT_RC_SET_STATUS "http://jabber.org/protocol/rc#set-status" +#define JABBER_FEAT_RC_SET_OPTIONS "http://jabber.org/protocol/rc#set-options" +#define JABBER_FEAT_RC_FORWARD "http://jabber.org/protocol/rc#forward" +#define JABBER_FEAT_RC_LEAVE_GROUPCHATS "http://jabber.org/protocol/rc#leave-groupchats" +#define JABBER_FEAT_RC_WS_LOCK "http://miranda-ng.org/rc#lock_workstation" +#define JABBER_FEAT_RC_QUIT_MIRANDA "http://miranda-ng.org/rc#quit" + +#define JABBER_FEAT_IQ_ROSTER "jabber:iq:roster" +#define JABBER_FEAT_DELAY "jabber:x:delay" +#define JABBER_FEAT_ENTITY_TIME_OLD "jabber:iq:time" +#define JABBER_FEAT_GTALK_SHARED_STATUS "google:shared-status" + +#define JABBER_FEAT_MUC_USER "http://jabber.org/protocol/muc#user" +#define JABBER_FEAT_NICK "http://jabber.org/protocol/nick" + +#define JABBER_FEAT_HTTP_AUTH "http://jabber.org/protocol/http-auth" + + +class CJabberClientPartialCaps +{ + +protected: + TCHAR *m_szVer; + JabberCapsBits m_jcbCaps; + CJabberClientPartialCaps *m_pNext; + int m_nIqId; + DWORD m_dwRequestTime; + +public: + CJabberClientPartialCaps( const TCHAR *szVer ); + ~CJabberClientPartialCaps(); + + CJabberClientPartialCaps* SetNext( CJabberClientPartialCaps *pCaps ); + __inline CJabberClientPartialCaps* GetNext() + { return m_pNext; + } + + void SetCaps( JabberCapsBits jcbCaps, int nIqId = -1 ); + JabberCapsBits GetCaps(); + + __inline TCHAR* GetVersion() + { return m_szVer; + } + + __inline int GetIqId() + { return m_nIqId; + } +}; + +class CJabberClientCaps +{ + +protected: + TCHAR *m_szNode; + CJabberClientPartialCaps *m_pCaps; + CJabberClientCaps *m_pNext; + +protected: + CJabberClientPartialCaps* FindByVersion( const TCHAR *szVer ); + CJabberClientPartialCaps* FindById( int nIqId ); + +public: + CJabberClientCaps( const TCHAR *szNode ); + ~CJabberClientCaps(); + + CJabberClientCaps* SetNext( CJabberClientCaps *pClient ); + __inline CJabberClientCaps* GetNext() + { return m_pNext; + } + + JabberCapsBits GetPartialCaps( TCHAR *szVer ); + BOOL SetPartialCaps( const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId = -1 ); + BOOL SetPartialCaps( int nIqId, JabberCapsBits jcbCaps ); + + __inline TCHAR* GetNode() + { return m_szNode; + } +}; + +class CJabberClientCapsManager +{ + +protected: + CRITICAL_SECTION m_cs; + CJabberClientCaps *m_pClients; + CJabberProto* ppro; + +protected: + CJabberClientCaps *FindClient( const TCHAR *szNode ); + +public: + CJabberClientCapsManager( CJabberProto* proto ); + ~CJabberClientCapsManager(); + + __inline void Lock() + { EnterCriticalSection( &m_cs ); + } + __inline void Unlock() + { LeaveCriticalSection( &m_cs ); + } + + void AddDefaultCaps(); + + JabberCapsBits GetClientCaps( TCHAR *szNode, TCHAR *szVer ); + BOOL SetClientCaps( const TCHAR *szNode, const TCHAR *szVer, JabberCapsBits jcbCaps, int nIqId = -1 ); + BOOL SetClientCaps( int nIqId, JabberCapsBits jcbCaps ); + + BOOL HandleInfoRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); +}; + +struct JabberFeatCapPair +{ + const TCHAR *szFeature; + JabberCapsBits jcbCap; + const TCHAR *szDescription; +}; + +struct JabberFeatCapPairDynamic +{ + TCHAR *szExt; + TCHAR *szFeature; + JabberCapsBits jcbCap; + TCHAR *szDescription; +}; + +extern const JabberFeatCapPair g_JabberFeatCapPairs[]; +extern const JabberFeatCapPair g_JabberFeatCapPairsExt[]; + +#endif diff --git a/protocols/JabberG/src/jabber_captcha.cpp b/protocols/JabberG/src/jabber_captcha.cpp new file mode 100644 index 0000000000..88d3038ab7 --- /dev/null +++ b/protocols/JabberG/src/jabber_captcha.cpp @@ -0,0 +1,232 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +struct CAPTCHA_FORM_PARAMS +{ + LPCTSTR from; + LPCTSTR challenge; + LPCTSTR fromjid; + LPCTSTR sid; + LPCTSTR to; + LPCTSTR hint; + HBITMAP bmp; + int w,h; + TCHAR Result[MAX_PATH]; +}; + +INT_PTR CALLBACK JabberCaptchaFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + CAPTCHA_FORM_PARAMS *params = (CAPTCHA_FORM_PARAMS*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + switch (msg) { + case WM_INITDIALOG: { + TranslateDialogDefault( hwndDlg ); + SendMessage( hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(IDI_KEYS)); + SendMessage( hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(IDI_KEYS)); + params = (CAPTCHA_FORM_PARAMS*)lParam; + + LPCTSTR hint = params->hint; + if ( hint == NULL ) + hint = TranslateT("Enter the text you see"); + SetDlgItemText( hwndDlg, IDC_INSTRUCTION, TranslateTS( hint )); + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG )params ); + + return TRUE; + } + case WM_CTLCOLORSTATIC: + switch( GetWindowLongPtr((HWND)lParam, GWL_ID)) { + case IDC_WHITERECT: + case IDC_INSTRUCTION: + case IDC_TITLE: + return (BOOL)GetStockObject(WHITE_BRUSH); + } + return NULL; + + case WM_PAINT: + if ( params ) { + PAINTSTRUCT ps; + HDC hdc, hdcMem; + RECT rc; + + GetClientRect( hwndDlg, &rc ); + hdc = BeginPaint( hwndDlg, &ps ); + hdcMem = CreateCompatibleDC( hdc ); + HGDIOBJ hOld = SelectObject( hdcMem, params->bmp ); + + int y = ( rc.bottom + rc.top - params->h ) / 2; + int x = ( rc.right + rc.left - params->w ) / 2; + BitBlt( hdc, x, y, params->w, params->h, hdcMem, 0,0, SRCCOPY ); + SelectObject( hdcMem, hOld ); + DeleteDC( hdcMem ); + + EndPaint( hwndDlg, &ps ); + } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDCANCEL: + EndDialog( hwndDlg, 0 ); + return TRUE; + + case IDC_SUBMIT: + GetDlgItemText( hwndDlg, IDC_VALUE, params->Result, SIZEOF(params->Result)); + EndDialog( hwndDlg, 1 ); + return TRUE; + } + break; + + case WM_CLOSE: + EndDialog( hwndDlg, 0 ); + break; + + case WM_DESTROY: + WindowFreeIcon( hwndDlg ); + break; + } + return FALSE; +} + +bool CJabberProto::ProcessCaptcha (HXML node, HXML parentNode, ThreadData* info ) { + CAPTCHA_FORM_PARAMS param; + char *ImageBuf = 0; + const TCHAR *PicType = 0; + TCHAR *CaptchaPath = 0; + + HXML x = xmlGetChildByTag( node, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( x == NULL ) + return false; + + HXML y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("from")); + if ( y == NULL ) + return false; + if (( y = xmlGetChild( y, "value" )) == NULL ) + return false; + param.fromjid = xmlGetText( y ); + + if (( y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("sid"))) == NULL ) + return false; + if (( y = xmlGetChild( y, "value" )) == NULL ) + return false; + param.sid = xmlGetText( y ); + + if (( y = xmlGetChildByTag(x, _T("field"), _T("var"), _T("ocr"))) == NULL ) + return false; + param.hint = xmlGetAttrValue (y, _T("label")); + + param.from = xmlGetAttrValue( parentNode, _T("from")); + param.to = xmlGetAttrValue( parentNode, _T("to")); + param.challenge = xmlGetAttrValue( parentNode, _T("id")); + HXML o = xmlGetChild( parentNode, "data" ); + if ( o == NULL || xmlGetText( o ) == NULL ) + return false; + + GetCaptchaImage(parentNode, ImageBuf, PicType, CaptchaPath); + char* p = mir_t2a( CaptchaPath ); + param.bmp = ( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p ); + DeleteFile(CaptchaPath); + mir_free(CaptchaPath); + mir_free(p); + + BITMAP bmp = {0}; + GetObject( param.bmp, sizeof(bmp), &bmp ); + param.w = bmp.bmWidth; + param.h = bmp.bmHeight; + int res = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CAPTCHAFORM), NULL, JabberCaptchaFormDlgProc, (LPARAM)¶m); + if (lstrcmp(param.Result, _T("")) == 0 || !res) + sendCaptchaError(info, param.from, param.to, param.challenge); + else + sendCaptchaResult (param.Result, info, param.from, param.challenge, param.fromjid, param.sid); + return true; +} + +void CJabberProto::GetCaptchaImage ( HXML node, char *ImageBuf, const TCHAR *PicType, TCHAR*& CaptchaPath ) { + HXML o = xmlGetChild( node , "data" ); + int bufferLen; + char* buffer = JabberBase64DecodeT(xmlGetText( o ), &bufferLen ); + if ( buffer == NULL ) + return; + + const TCHAR* szPicType; + HXML m = xmlGetChild( node , "TYPE" ); + if ( m == NULL || xmlGetText( m ) == NULL ) { + LBL_NoTypeSpecified: + switch( JabberGetPictureType( buffer )) { + case PA_FORMAT_GIF: szPicType = _T("image/gif"); break; + case PA_FORMAT_BMP: szPicType = _T("image/bmp"); break; + case PA_FORMAT_PNG: szPicType = _T("image/png"); break; + case PA_FORMAT_JPEG: szPicType = _T("image/jpeg"); break; + default: + goto LBL_Ret; + } + } + else { + const TCHAR* tszType = xmlGetText( m ); + if ( !_tcscmp( tszType, _T("image/jpeg")) || + !_tcscmp( tszType, _T("image/png")) || + !_tcscmp( tszType, _T("image/gif")) || + !_tcscmp( tszType, _T("image/bmp"))) + szPicType = tszType; + else + goto LBL_NoTypeSpecified; + } + + DWORD nWritten; + +LBL_Ret: + TCHAR* ext = _tcsstr((TCHAR*)szPicType, _T("/"))+1; + TCHAR filename[MAX_PATH]; + mir_sntprintf(filename, SIZEOF(filename), _T("%%TEMP%%\\captcha.%s"), ext); + CaptchaPath = Utils_ReplaceVarsT(filename); + HANDLE hFile = CreateFile( CaptchaPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile == INVALID_HANDLE_VALUE ) + goto LBL_Ret; + + if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL )) + goto LBL_Ret; + + CloseHandle( hFile ); + + ImageBuf = buffer; + PicType = szPicType; +} + +void CJabberProto::sendCaptchaResult(TCHAR* buf, ThreadData* info, LPCTSTR from, LPCTSTR challenge, LPCTSTR fromjid, LPCTSTR sid){ + XmlNodeIq iq( _T("set"), SerialNext()); + HXML query= iq <<XATTR(_T("to"), from) << XCHILD(_T("captcha")) << XATTR( _T("xmlns"), _T("urn:xmpp:captcha")) << XCHILD (_T("x")) << XATTR(_T("xmlns"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR(_T("type"), _T("submit")); + query << XCHILD(_T("field")) << XATTR (_T("var"), _T("FORM_TYPE")) << XCHILD(_T("value"), _T("urn:xmpp:captcha")); + query << XCHILD(_T("field")) << XATTR (_T("var"), _T("from")) << XCHILD(_T("value"), fromjid); + query << XCHILD(_T("field")) << XATTR (_T("var"), _T("challenge")) << XCHILD(_T("value"), challenge); + query << XCHILD(_T("field")) << XATTR (_T("var"), _T("sid")) << XCHILD(_T("value"), sid); + query << XCHILD(_T("field")) << XATTR (_T("var"), _T("ocr")) << XCHILD(_T("value"), buf); + info -> send (iq); +} + +void CJabberProto::sendCaptchaError(ThreadData* info, LPCTSTR from, LPCTSTR to, LPCTSTR challenge ) { + XmlNode message( _T("message")); + HXML query= message << XATTR(_T("type"), _T("error")) << XATTR(_T("to"), from) << XATTR(_T("id"), challenge) << XATTR(_T("from"), to) + << XCHILD(_T("error")) << XATTR(_T("type"), _T("modify")) + << XCHILD(_T("not-acceptable")) << XATTR(_T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + info -> send (message); +} diff --git a/protocols/JabberG/src/jabber_chat.cpp b/protocols/JabberG/src/jabber_chat.cpp new file mode 100644 index 0000000000..8dacc24619 --- /dev/null +++ b/protocols/JabberG/src/jabber_chat.cpp @@ -0,0 +1,1628 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" + +#include <m_addcontact.h> + +const TCHAR xmlnsAdmin[] = _T("http://jabber.org/protocol/muc#admin"); +const TCHAR xmlnsOwner[] = _T("http://jabber.org/protocol/muc#owner"); + +///////////////////////////////////////////////////////////////////////////////////////// +// Global definitions + +enum { + IDM_CANCEL, + + IDM_ROLE, IDM_AFFLTN, + + IDM_CONFIG, IDM_NICK, IDM_DESTROY, IDM_INVITE, IDM_BOOKMARKS, IDM_LEAVE, IDM_TOPIC, + IDM_LST_PARTICIPANT, IDM_LST_MODERATOR, + IDM_LST_MEMBER, IDM_LST_ADMIN, IDM_LST_OWNER, IDM_LST_BAN, + + IDM_MESSAGE, IDM_SLAP, IDM_VCARD, IDM_INFO, IDM_KICK, + IDM_RJID, IDM_RJID_ADD, IDM_RJID_VCARD, IDM_RJID_COPY, + IDM_SET_VISITOR, IDM_SET_PARTICIPANT, IDM_SET_MODERATOR, + IDM_SET_NONE, IDM_SET_MEMBER, IDM_SET_ADMIN, IDM_SET_OWNER, IDM_SET_BAN, + IDM_CPY_NICK, IDM_CPY_TOPIC, IDM_CPY_RJID, IDM_CPY_INROOMJID, + + IDM_LINK0, IDM_LINK1, IDM_LINK2, IDM_LINK3, IDM_LINK4, IDM_LINK5, IDM_LINK6, IDM_LINK7, IDM_LINK8, IDM_LINK9, + + IDM_PRESENCE_ONLINE = ID_STATUS_ONLINE, + IDM_PRESENCE_AWAY = ID_STATUS_AWAY, + IDM_PRESENCE_NA = ID_STATUS_NA, + IDM_PRESENCE_DND = ID_STATUS_DND, + IDM_PRESENCE_FREE4CHAT = ID_STATUS_FREECHAT, +}; + +struct TRoleOrAffiliationInfo +{ + int value; + int id; + TCHAR *title_en; + int min_role; + int min_affiliation; + + TCHAR *title; + + BOOL check(JABBER_RESOURCE_STATUS *me, JABBER_RESOURCE_STATUS *him) + { + if (me->affiliation == AFFILIATION_OWNER) return TRUE; + if (me == him) return FALSE; + if (me->affiliation <= him->affiliation) return FALSE; + if (me->role < this->min_role) return FALSE; + if (me->affiliation < this->min_affiliation) return FALSE; + return TRUE; + } + void translate() + { + this->title = TranslateTS(this->title_en); + } +}; + +static TRoleOrAffiliationInfo sttAffiliationItems[] = +{ + { AFFILIATION_NONE, IDM_SET_NONE, LPGENT("None"), ROLE_NONE, AFFILIATION_ADMIN }, + { AFFILIATION_MEMBER, IDM_SET_MEMBER, LPGENT("Member"), ROLE_NONE, AFFILIATION_ADMIN }, + { AFFILIATION_ADMIN, IDM_SET_ADMIN, LPGENT("Admin"), ROLE_NONE, AFFILIATION_OWNER }, + { AFFILIATION_OWNER, IDM_SET_OWNER, LPGENT("Owner"), ROLE_NONE, AFFILIATION_OWNER }, +}; + +static TRoleOrAffiliationInfo sttRoleItems[] = +{ + { ROLE_VISITOR, IDM_SET_VISITOR, LPGENT("Visitor"), ROLE_MODERATOR, AFFILIATION_NONE }, + { ROLE_PARTICIPANT, IDM_SET_PARTICIPANT, LPGENT("Participant"), ROLE_MODERATOR, AFFILIATION_NONE }, + { ROLE_MODERATOR, IDM_SET_MODERATOR, LPGENT("Moderator"), ROLE_MODERATOR, AFFILIATION_ADMIN }, +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGcInit - initializes the new chat + +static const TCHAR* sttStatuses[] = { _T("Visitors"), _T("Participants"), _T("Moderators"), _T("Owners") }; + +int JabberGcGetStatus(JABBER_GC_AFFILIATION a, JABBER_GC_ROLE r) +{ + switch (a) { + case AFFILIATION_OWNER: return 3; + + default: + switch (r) { + case ROLE_MODERATOR: return 2; + case ROLE_PARTICIPANT: return 1; + } } + + return 0; +} + +int JabberGcGetStatus(JABBER_RESOURCE_STATUS *r) +{ + return JabberGcGetStatus(r->affiliation, r->role); +} + +int CJabberProto::JabberGcInit( WPARAM wParam, LPARAM ) +{ + int i; + JABBER_LIST_ITEM* item = ( JABBER_LIST_ITEM* )wParam; + GCSESSION gcw = {0}; + GCEVENT gce = {0}; + + // translate string for menus (this can't be done in initializer) + for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) sttAffiliationItems[i].translate(); + for (i = 0; i < SIZEOF(sttRoleItems); ++i) sttRoleItems[i].translate(); + + TCHAR* szNick = JabberNickFromJID( item->jid ); + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = szNick; + gcw.ptszID = item->jid; + gcw.dwFlags = GC_TCHAR; + CallServiceSync( MS_GC_NEWSESSION, NULL, (LPARAM)&gcw ); + + HANDLE hContact = HContactFromJID( item->jid ); + if ( hContact != NULL ) { + DBVARIANT dbv; + if ( JABBER_LIST_ITEM* bookmark = ListGetItemPtr( LIST_BOOKMARK, item->jid )) + if ( bookmark->name ) { + if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) + JFreeVariant( &dbv ); + else + DBWriteContactSettingTString( hContact, "CList", "MyHandle", bookmark->name ); + } + + if ( !JGetStringT( hContact, "MyNick", &dbv )) { + if ( !lstrcmp( dbv.ptszVal, szNick )) + JDeleteSetting( hContact, "MyNick" ); + else + JSetStringT( hContact, "MyNick", item->nick ); + JFreeVariant( &dbv ); + } + else JSetStringT( hContact, "MyNick", item->nick ); + + TCHAR *passw = JGetStringCrypt( hContact, "LoginPassword" ); + if ( lstrcmp_null( passw, item->password )) { + if ( !item->password || !item->password[0] ) + JDeleteSetting( hContact, "LoginPassword" ); + else + JSetStringCrypt( hContact, "LoginPassword", item->password ); + } + mir_free(passw); + } + mir_free( szNick ); + + item->bChatActive = TRUE; + + GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_ADDGROUP }; + gcd.ptszID = item->jid; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + for (i = SIZEOF(sttStatuses)-1; i >= 0; i-- ) { + gce.ptszStatus = TranslateTS( sttStatuses[i] ); + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + } + + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gcd.iType = GC_EVENT_CONTROL; + CallServiceSync( MS_GC_EVENT, (item->bAutoJoin && m_options.AutoJoinHidden) ? WINDOW_HIDDEN : SESSION_INITDONE, (LPARAM)&gce ); + CallServiceSync( MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce ); + return 0; +} + +void CJabberProto::GcLogCreate( JABBER_LIST_ITEM* item ) +{ + if ( item->bChatActive ) + return; + + NotifyEventHooks( m_hInitChat, (WPARAM)item, 0 ); +} + +void CJabberProto::GcLogShowInformation( JABBER_LIST_ITEM *item, JABBER_RESOURCE_STATUS *user, TJabberGcLogInfoType type ) +{ + if (!item || !user || (item->bChatActive != 2)) return; + + TCHAR buf[512] = _T(""); + + switch (type) + { + case INFO_BAN: + if (m_options.GcLogBans) + { + mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s in now banned."), user->resourceName); + } + break; + case INFO_STATUS: + if (m_options.GcLogStatuses) + { + if (user->statusMessage) + { + mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s changed status to %s with message: %s"), + user->resourceName, + CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, user->status, GSMDF_TCHAR), + user->statusMessage); + } else + { + mir_sntprintf(buf, SIZEOF(buf), TranslateT("User %s changed status to %s"), + user->resourceName, + CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, user->status, GSMDF_TCHAR)); + } + } + break; + case INFO_CONFIG: + if (m_options.GcLogConfig) + { + mir_sntprintf(buf, SIZEOF(buf), TranslateT("Room configuration was changed.")); + } + break; + case INFO_AFFILIATION: + if (m_options.GcLogAffiliations) + { + TCHAR *name = NULL; + switch (user->affiliation) + { + case AFFILIATION_NONE: name = TranslateT("None"); break; + case AFFILIATION_MEMBER: name = TranslateT("Member"); break; + case AFFILIATION_ADMIN: name = TranslateT("Admin"); break; + case AFFILIATION_OWNER: name = TranslateT("Owner"); break; + case AFFILIATION_OUTCAST: name = TranslateT("Outcast"); break; + } + if (name) mir_sntprintf(buf, SIZEOF(buf), TranslateT("Affiliation of %s was changed to '%s'."), user->resourceName, name); + } + break; + case INFO_ROLE: + if (m_options.GcLogRoles) + { + TCHAR *name = NULL; + switch (user->role) + { + case ROLE_NONE: name = TranslateT("None"); break; + case ROLE_VISITOR: name = TranslateT("Visitor"); break; + case ROLE_PARTICIPANT: name = TranslateT("Participant"); break; + case ROLE_MODERATOR: name = TranslateT("Moderator"); break; + } + if (name) mir_sntprintf(buf, SIZEOF(buf), TranslateT("Role of %s was changed to '%s'."), user->resourceName, name); + } + break; + } + + if (*buf) + { + GCDEST gcd = { m_szModuleName, 0, 0 }; + gcd.ptszID = item->jid; + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.ptszNick = user->resourceName; + gce.ptszUID = user->resourceName; + gce.ptszText = EscapeChatTags( buf ); + gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; + gce.pDest = &gcd; + gce.time = time(0); + gcd.iType = GC_EVENT_INFORMATION; + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + + mir_free( (void*)gce.ptszText ); // Since we processed msgText and created a new string + } +} + +void CJabberProto::GcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, const TCHAR* resource, const TCHAR* nick, const TCHAR* jid, int action, HXML reason, int nStatusCode ) +{ + int statusToSet = 0; + const TCHAR* szReason = NULL; + if ( reason != NULL && xmlGetText( reason ) != NULL ) + szReason = xmlGetText( reason ); + + if ( !szReason ) { + if ( nStatusCode == 322 ) + szReason = TranslateT( "because room is now members-only" ); + else if ( nStatusCode == 301 ) + szReason = TranslateT( "user banned" ); + } + + TCHAR* myNick = (item->nick == NULL) ? NULL : mir_tstrdup( item->nick ); + if ( myNick == NULL ) + myNick = JabberNickFromJID( m_szJabberJID ); + + GCDEST gcd = { m_szModuleName, 0, 0 }; + gcd.ptszID = item->jid; + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.ptszNick = nick; + gce.ptszUID = resource; + if (jid != NULL) + gce.ptszUserInfo = jid; + gce.ptszText = szReason; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + if ( item->bChatActive == 2 ) { + gce.dwFlags |= GCEF_ADDTOLOG; + gce.time = time(0); + } + + switch( gcd.iType = action ) { + case GC_EVENT_PART: break; + case GC_EVENT_KICK: + gce.ptszStatus = TranslateT( "Moderator" ); + break; + default: + for ( int i=0; i < item->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& JS = item->resource[i]; + if ( !lstrcmp( resource, JS.resourceName )) { + if ( action != GC_EVENT_JOIN ) { + switch( action ) { + case 0: + gcd.iType = GC_EVENT_ADDSTATUS; + case GC_EVENT_REMOVESTATUS: + gce.dwFlags &= ~GCEF_ADDTOLOG; + } + gce.ptszText = TranslateT( "Moderator" ); + } + gce.ptszStatus = TranslateTS( sttStatuses[JabberGcGetStatus(&JS)] ); + gce.bIsMe = ( lstrcmp( nick, myNick ) == 0 ); + statusToSet = JS.status; + break; + } } } + + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + + if ( statusToSet != 0 ) { + gce.ptszText = nick; + if ( statusToSet == ID_STATUS_AWAY || statusToSet == ID_STATUS_NA || statusToSet == ID_STATUS_DND ) + gce.dwItemData = 3; + else + gce.dwItemData = 1; + gcd.iType = GC_EVENT_SETSTATUSEX; + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + + gce.ptszUID = resource; + gce.dwItemData = statusToSet; + gcd.iType = GC_EVENT_SETCONTACTSTATUS; + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + } + + mir_free( myNick ); +} + +void CJabberProto::GcQuit( JABBER_LIST_ITEM* item, int code, HXML reason ) +{ + TCHAR *szMessage = NULL; + + const TCHAR* szReason = NULL; + if ( reason != NULL && xmlGetText( reason ) != NULL ) + szReason = xmlGetText( reason ); + + GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_CONTROL }; + gcd.ptszID = item->jid; + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.ptszUID = item->jid; + gce.ptszText = szReason; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + + if ( code != 307 && code != 301 ) { + CallServiceSync( MS_GC_EVENT, SESSION_TERMINATE, ( LPARAM )&gce ); + CallServiceSync( MS_GC_EVENT, WINDOW_CLEARLOG, ( LPARAM )&gce ); + + DBVARIANT dbvMessage; + if (!DBGetContactSettingTString( NULL, m_szModuleName, "GcMsgQuit", &dbvMessage)) { + szMessage = NEWTSTR_ALLOCA(dbvMessage.ptszVal); + DBFreeVariant(&dbvMessage); + } + else szMessage = TranslateTS(JABBER_GC_MSG_QUIT); + } + else { + TCHAR* myNick = JabberNickFromJID( m_szJabberJID ); + GcLogUpdateMemberStatus( item, myNick, myNick, NULL, GC_EVENT_KICK, reason ); + mir_free( myNick ); + CallServiceSync( MS_GC_EVENT, SESSION_OFFLINE, ( LPARAM )&gce ); + } + + DBDeleteContactSetting( HContactFromJID( item->jid ), "CList", "Hidden" ); + item->bChatActive = FALSE; + + if ( m_bJabberOnline ) { + TCHAR szPresenceTo[ JABBER_MAX_JID_LEN ]; + mir_sntprintf( szPresenceTo, SIZEOF( szPresenceTo ), _T("%s/%s"), item->jid, item->nick ); + + m_ThreadInfo->send( + XmlNode( _T("presence")) << XATTR( _T("to"), szPresenceTo ) << XATTR( _T("type"), _T("unavailable")) + << XCHILD( _T("status"), szMessage)); + + ListRemove( LIST_CHATROOM, item->jid ); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// Context menu hooks + +static struct gc_item *sttFindGcMenuItem(GCMENUITEMS *items, DWORD id) +{ + for (int i = 0; i < items->nItems; ++i) + if (items->Item[i].dwID == id) + return items->Item + i; + return NULL; +} + +static void sttSetupGcMenuItem(GCMENUITEMS *items, DWORD id, bool disabled) +{ + for (int i = 0; i < items->nItems; ++i) + if (!id || (items->Item[i].dwID == id)) + items->Item[i].bDisabled = disabled; +} + +static void sttShowGcMenuItem(GCMENUITEMS *items, DWORD id, int type) +{ + for (int i = 0; i < items->nItems; ++i) + if (!id || (items->Item[i].dwID == id)) + items->Item[i].uType = type; +} + +static void sttSetupGcMenuItems(GCMENUITEMS *items, DWORD *ids, bool disabled) +{ + for ( ; *ids; ++ids) + sttSetupGcMenuItem(items, *ids, disabled); +} + +static void sttShowGcMenuItems(GCMENUITEMS *items, DWORD *ids, int type) +{ + for ( ; *ids; ++ids) + sttShowGcMenuItem(items, *ids, type); +} + +static gc_item sttLogListItems[] = +{ + { LPGENT("Change &nickname"), IDM_NICK, MENU_ITEM }, + { LPGENT("&Invite a user"), IDM_INVITE, MENU_ITEM }, + { NULL, 0, MENU_SEPARATOR }, + + { LPGENT("&Roles"), IDM_ROLE, MENU_NEWPOPUP }, + { LPGENT("&Participant list"), IDM_LST_PARTICIPANT, MENU_POPUPITEM }, + { LPGENT("&Moderator list"), IDM_LST_MODERATOR, MENU_POPUPITEM }, + + { LPGENT("&Affiliations"), IDM_AFFLTN, MENU_NEWPOPUP }, + { LPGENT("&Member list"), IDM_LST_MEMBER, MENU_POPUPITEM }, + { LPGENT("&Admin list"), IDM_LST_ADMIN, MENU_POPUPITEM }, + { LPGENT("&Owner list"), IDM_LST_OWNER, MENU_POPUPITEM }, + { NULL, 0, MENU_POPUPSEPARATOR }, + { LPGENT("Outcast list (&ban)"), IDM_LST_BAN, MENU_POPUPITEM }, + + { LPGENT("&Room options"), 0, MENU_NEWPOPUP }, + { LPGENT("View/change &topic"), IDM_TOPIC, MENU_POPUPITEM }, + { LPGENT("Add to &bookmarks"), IDM_BOOKMARKS, MENU_POPUPITEM }, + { LPGENT("&Configure..."), IDM_CONFIG, MENU_POPUPITEM }, + { LPGENT("&Destroy room"), IDM_DESTROY, MENU_POPUPITEM }, + + { NULL, 0, MENU_SEPARATOR }, + + { LPGENT("Lin&ks"), 0, MENU_NEWPOPUP }, + { NULL, IDM_LINK0, 0 }, + { NULL, IDM_LINK1, 0 }, + { NULL, IDM_LINK2, 0 }, + { NULL, IDM_LINK3, 0 }, + { NULL, IDM_LINK4, 0 }, + { NULL, IDM_LINK5, 0 }, + { NULL, IDM_LINK6, 0 }, + { NULL, IDM_LINK7, 0 }, + { NULL, IDM_LINK8, 0 }, + { NULL, IDM_LINK9, 0 }, + + { LPGENT("Copy room &JID"), IDM_CPY_RJID, MENU_ITEM }, + { LPGENT("Copy room topic"), IDM_CPY_TOPIC, MENU_ITEM }, + { NULL, 0, MENU_SEPARATOR }, + + { LPGENT("&Send presence"), 0, MENU_NEWPOPUP}, + { LPGENT("Online"), IDM_PRESENCE_ONLINE, MENU_POPUPITEM }, + { LPGENT("Away"), IDM_PRESENCE_AWAY, MENU_POPUPITEM }, + { LPGENT("NA"), IDM_PRESENCE_NA, MENU_POPUPITEM }, + { LPGENT("DND"), IDM_PRESENCE_DND, MENU_POPUPITEM }, + { LPGENT("Free for chat"), IDM_PRESENCE_FREE4CHAT, MENU_POPUPITEM }, + + { LPGENT("&Leave chat session"), IDM_LEAVE, MENU_ITEM } +}; + +static TCHAR sttRJidBuf[JABBER_MAX_JID_LEN] = {0}; +static struct gc_item sttListItems[] = +{ + { LPGENT("&Slap"), IDM_SLAP, MENU_ITEM }, // 0 + { LPGENT("&User details"), IDM_VCARD, MENU_ITEM }, // 1 + { LPGENT("Member &info"), IDM_INFO, MENU_ITEM }, // 2 + + { sttRJidBuf, 0, MENU_NEWPOPUP }, // 3 -> accessed explicitly by index!!! + { LPGENT("User &details"), IDM_RJID_VCARD, MENU_POPUPITEM }, + { LPGENT("&Add to roster"), IDM_RJID_ADD, MENU_POPUPITEM }, + { LPGENT("&Copy to clipboard"), IDM_RJID_COPY, MENU_POPUPITEM }, + + { LPGENT("Invite to room"), 0, MENU_NEWPOPUP }, + { NULL, IDM_LINK0, 0 }, + { NULL, IDM_LINK1, 0 }, + { NULL, IDM_LINK2, 0 }, + { NULL, IDM_LINK3, 0 }, + { NULL, IDM_LINK4, 0 }, + { NULL, IDM_LINK5, 0 }, + { NULL, IDM_LINK6, 0 }, + { NULL, IDM_LINK7, 0 }, + { NULL, IDM_LINK8, 0 }, + { NULL, IDM_LINK9, 0 }, + + { NULL, 0, MENU_SEPARATOR }, + + { LPGENT("Set &role"), IDM_ROLE, MENU_NEWPOPUP }, + { LPGENT("&Visitor"), IDM_SET_VISITOR, MENU_POPUPITEM }, + { LPGENT("&Participant"), IDM_SET_PARTICIPANT, MENU_POPUPITEM }, + { LPGENT("&Moderator"), IDM_SET_MODERATOR, MENU_POPUPITEM }, + + { LPGENT("Set &affiliation"), IDM_AFFLTN, MENU_NEWPOPUP }, + { LPGENT("&None"), IDM_SET_NONE, MENU_POPUPITEM }, + { LPGENT("&Member"), IDM_SET_MEMBER, MENU_POPUPITEM }, + { LPGENT("&Admin"), IDM_SET_ADMIN, MENU_POPUPITEM }, + { LPGENT("&Owner"), IDM_SET_OWNER, MENU_POPUPITEM }, + { NULL, 0, MENU_POPUPSEPARATOR }, + { LPGENT("Outcast (&ban)"), IDM_SET_BAN, MENU_POPUPITEM }, + + { LPGENT("&Kick"), IDM_KICK, MENU_ITEM }, + { NULL, 0, MENU_SEPARATOR }, + { LPGENT("Copy &nickname"), IDM_CPY_NICK, MENU_ITEM }, + { LPGENT("Copy real &JID"), IDM_CPY_RJID, MENU_ITEM }, + { LPGENT("Copy in-room JID"), IDM_CPY_INROOMJID, MENU_ITEM } +}; + +int CJabberProto::JabberGcMenuHook( WPARAM, LPARAM lParam ) +{ + GCMENUITEMS* gcmi = ( GCMENUITEMS* )lParam; + if ( gcmi == NULL ) + return 0; + + if ( lstrcmpiA( gcmi->pszModule, m_szModuleName )) + return 0; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, gcmi->pszID ); + if ( item == NULL ) + return 0; + + JABBER_RESOURCE_STATUS *me = NULL, *him = NULL; + for ( int i=0; i < item->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& p = item->resource[i]; + if ( !lstrcmp( p.resourceName, item->nick )) me = &p; + if ( !lstrcmp( p.resourceName, gcmi->pszUID )) him = &p; + } + + if ( gcmi->Type == MENU_ON_LOG ) { + static TCHAR url_buf[1024] = {0}; + + gcmi->nItems = SIZEOF( sttLogListItems ); + gcmi->Item = sttLogListItems; + + static DWORD sttModeratorItems[] = { IDM_LST_PARTICIPANT, 0 }; + static DWORD sttAdminItems[] = { IDM_LST_MODERATOR, IDM_LST_MEMBER, IDM_LST_ADMIN, IDM_LST_OWNER, IDM_LST_BAN, 0 }; + static DWORD sttOwnerItems[] = { IDM_CONFIG, IDM_DESTROY, 0 }; + + sttSetupGcMenuItem(gcmi, 0, FALSE); + + int idx = IDM_LINK0; + if (item->itemResource.statusMessage && *item->itemResource.statusMessage) { + TCHAR *bufPtr = url_buf; + for (TCHAR *p = _tcsstr(item->itemResource.statusMessage, _T("http://")); p && *p; p = _tcsstr(p+1, _T("http://"))) { + lstrcpyn(bufPtr, p, SIZEOF(url_buf) - (bufPtr - url_buf)); + gc_item *pItem = sttFindGcMenuItem(gcmi, idx); + pItem->pszDesc = bufPtr; + pItem->uType = MENU_POPUPITEM; + for ( ; *bufPtr && !_istspace(*bufPtr); ++bufPtr) ; + *bufPtr++ = 0; + + if (++idx > IDM_LINK9) break; + } + } + for ( ; idx <= IDM_LINK9; ++idx) + sttFindGcMenuItem(gcmi, idx)->uType = 0; + + if ( !GetAsyncKeyState(VK_CONTROL)) { + if (me) { + sttSetupGcMenuItems(gcmi, sttModeratorItems, (me->role < ROLE_MODERATOR)); + sttSetupGcMenuItems(gcmi, sttAdminItems, (me->affiliation < AFFILIATION_ADMIN)); + sttSetupGcMenuItems(gcmi, sttOwnerItems, (me->affiliation < AFFILIATION_OWNER)); + } + if (m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE) + sttSetupGcMenuItem(gcmi, IDM_BOOKMARKS, FALSE); + } + } + else if ( gcmi->Type == MENU_ON_NICKLIST ) { + gcmi->nItems = SIZEOF(sttListItems); + gcmi->Item = sttListItems; + + static DWORD sttRJidItems[] = { IDM_RJID_VCARD, IDM_RJID_ADD, IDM_RJID_COPY, 0 }; + + if (me && him) { + int i, idx; + BOOL force = GetAsyncKeyState(VK_CONTROL); + sttSetupGcMenuItem(gcmi, 0, FALSE); + + idx = IDM_LINK0; + LISTFOREACH_NODEF(i, this, LIST_CHATROOM) + if (item = ListGetItemPtrFromIndex(i)) { + gc_item *pItem = sttFindGcMenuItem(gcmi, idx); + pItem->pszDesc = item->jid; + pItem->uType = MENU_POPUPITEM; + if (++idx > IDM_LINK9) break; + } + + for ( ; idx <= IDM_LINK9; ++idx) + sttFindGcMenuItem(gcmi, idx)->uType = 0; + + for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) { + struct gc_item *item = sttFindGcMenuItem(gcmi, sttAffiliationItems[i].id); + item->uType = (him->affiliation == sttAffiliationItems[i].value) ? MENU_POPUPCHECK : MENU_POPUPITEM; + item->bDisabled = !(force || sttAffiliationItems[i].check(me, him)); + } + + for (i = 0; i < SIZEOF(sttRoleItems); ++i) { + struct gc_item *item = sttFindGcMenuItem(gcmi, sttRoleItems[i].id); + item->uType = (him->role == sttRoleItems[i].value) ? MENU_POPUPCHECK : MENU_POPUPITEM; + item->bDisabled = !(force || sttRoleItems[i].check(me, him)); + } + + if (him->szRealJid && *him->szRealJid) { + mir_sntprintf(sttRJidBuf, SIZEOF(sttRJidBuf), TranslateT("Real &JID: %s"), him->szRealJid); + if (TCHAR *tmp = _tcschr(sttRJidBuf, _T('/'))) *tmp = 0; + + if (HANDLE hContact = HContactFromJID(him->szRealJid)) { + gcmi->Item[3].uType = MENU_HMENU; + gcmi->Item[3].dwID = CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + sttShowGcMenuItems(gcmi, sttRJidItems, 0); + } + else { + gcmi->Item[3].uType = MENU_NEWPOPUP; + sttShowGcMenuItems(gcmi, sttRJidItems, MENU_POPUPITEM); + } + + sttSetupGcMenuItem(gcmi, IDM_CPY_RJID, FALSE); + } + else { + gcmi->Item[3].uType = 0; + sttShowGcMenuItems(gcmi, sttRJidItems, 0); + + sttSetupGcMenuItem(gcmi, IDM_CPY_RJID, TRUE); + } + + if (!force) { + if (me->role < ROLE_MODERATOR || (me->affiliation <= him->affiliation)) + sttSetupGcMenuItem(gcmi, IDM_KICK, TRUE); + + if ((me->affiliation < AFFILIATION_ADMIN) || + (me->affiliation == AFFILIATION_ADMIN) && (me->affiliation <= him->affiliation)) + sttSetupGcMenuItem(gcmi, IDM_SET_BAN, TRUE); + } + } + else { + sttSetupGcMenuItem(gcmi, 0, TRUE); + gcmi->Item[2].uType = 0; + sttShowGcMenuItems(gcmi, sttRJidItems, 0); + } + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Conference invitation dialog + +class CGroupchatInviteDlg : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + struct JabberGcLogInviteDlgJidData + { + int hItem; + TCHAR jid[JABBER_MAX_JID_LEN]; + }; + + LIST<JabberGcLogInviteDlgJidData> m_newJids; + TCHAR *m_room; + + CCtrlButton m_btnInvite; + CCtrlEdit m_txtNewJid; + CCtrlMButton m_btnAddJid; + CCtrlEdit m_txtReason; + CCtrlClc m_clc; + + void FilterList(CCtrlClc *) + { + for (HANDLE hContact = db_find_first(); + hContact; + hContact = db_find_next(hContact)) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (lstrcmpA(proto, m_proto->m_szModuleName) || DBGetContactSettingByte(hContact, proto, "ChatRoom", 0)) + if (HANDLE hItem = m_clc.FindContact(hContact)) + m_clc.DeleteItem(hItem); + } } + + void ResetListOptions(CCtrlClc *) + { + m_clc.SetBkBitmap(0, NULL); + m_clc.SetBkColor(GetSysColor(COLOR_WINDOW)); + m_clc.SetGreyoutFlags(0); + m_clc.SetLeftMargin(4); + m_clc.SetIndent(10); + m_clc.SetHideEmptyGroups(1); + m_clc.SetHideOfflineRoot(1); + for (int i=0; i <= FONTID_MAX; i++) + m_clc.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT)); + } + + void InviteUser(TCHAR *pUser, TCHAR *text) + { + XmlNode msg( _T("message")); + HXML invite = msg << XATTR( _T("to"), m_room ) << XATTRID( m_proto->SerialNext()) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_MUC_USER)) + << XCHILD( _T("invite")) << XATTR( _T("to"), pUser ); + if ( text ) + invite << XCHILD( _T("reason"), text ); + + m_proto->m_ThreadInfo->send( msg ); + } + +public: + CGroupchatInviteDlg(CJabberProto* ppro, TCHAR *room) : + CSuper(ppro, IDD_GROUPCHAT_INVITE, NULL), + m_newJids(1), + m_btnInvite(this, IDC_INVITE), + m_txtNewJid(this, IDC_NEWJID), + m_btnAddJid(this, IDC_ADDJID, ppro->LoadIconEx("addroster"), "Add"), + m_txtReason(this, IDC_REASON), + m_clc(this, IDC_CLIST) + { + m_room = mir_tstrdup(room); + m_btnAddJid.OnClick = Callback( this, &CGroupchatInviteDlg::OnCommand_AddJid ); + m_btnInvite.OnClick = Callback( this, &CGroupchatInviteDlg::OnCommand_Invite ); + m_clc.OnNewContact = + m_clc.OnListRebuilt = Callback( this, &CGroupchatInviteDlg::FilterList ); + m_clc.OnOptionsChanged = Callback( this, &CGroupchatInviteDlg::ResetListOptions ); + } + + ~CGroupchatInviteDlg() + { + for (int i = 0; i < m_newJids.getCount(); ++i) + mir_free(m_newJids[i]); + mir_free(m_room); + } + + void OnInitDialog() + { + CSuper::OnInitDialog(); + + TCHAR buf[256]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s"), m_room, TranslateT("Send groupchat invitation.")); + SetDlgItemText(m_hwnd, IDC_HEADERBAR, buf); + WindowSetIcon(m_hwnd, m_proto, "group"); + + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE, + GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE)|CLS_HIDEOFFLINE|CLS_CHECKBOXES|CLS_HIDEEMPTYGROUPS|CLS_USEGROUPS|CLS_GREYALTERNATE|CLS_GROUPCHECKBOXES); + SendMessage(GetDlgItem(m_hwnd, IDC_CLIST), CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP|CLS_EX_TRACKSELECT, 0); + ResetListOptions(&m_clc); + FilterList(&m_clc); + } + + void OnCommand_AddJid( CCtrlButton* ) + { + TCHAR buf[JABBER_MAX_JID_LEN]; + m_txtNewJid.GetText(buf, SIZEOF(buf)); + m_txtNewJid.SetTextA(""); + + HANDLE hContact = m_proto->HContactFromJID(buf); + if ( hContact ) + { + int hItem = SendDlgItemMessage( m_hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0 ); + if ( hItem ) + SendDlgItemMessage( m_hwnd, IDC_CLIST, CLM_SETCHECKMARK, hItem, 1 ); + return; + } + + int i; + for (i = 0; i < m_newJids.getCount(); ++i) + if (!lstrcmp(m_newJids[i]->jid, buf)) + break; + if (i != m_newJids.getCount()) + return; + + JabberGcLogInviteDlgJidData *jidData = (JabberGcLogInviteDlgJidData *)mir_alloc(sizeof(JabberGcLogInviteDlgJidData)); + lstrcpy(jidData->jid, buf); + CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_CHECKBOX; + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%s)"), jidData->jid, TranslateT("not on roster")); + cii.pszText = buf; + jidData->hItem = SendDlgItemMessage(m_hwnd,IDC_CLIST,CLM_ADDINFOITEM,0,(LPARAM)&cii); + SendDlgItemMessage(m_hwnd, IDC_CLIST, CLM_SETCHECKMARK, jidData->hItem, 1); + m_newJids.insert(jidData); + } + + void OnCommand_Invite( CCtrlButton* ) + { + if (!m_room) return; + + TCHAR *text = m_txtReason.GetText(); + HWND hwndList = GetDlgItem(m_hwnd, IDC_CLIST); + + // invite users from roster + for (HANDLE hContact = db_find_first(); + hContact; + hContact = db_find_next(hContact)) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (!lstrcmpA(proto, m_proto->m_szModuleName) && !DBGetContactSettingByte(hContact, proto, "ChatRoom", 0)) + { + if (int hItem = SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0)) + { + if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) + { + DBVARIANT dbv={0}; + m_proto->JGetStringT(hContact, "jid", &dbv); + if (dbv.ptszVal && ( dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR )) + InviteUser(dbv.ptszVal, text); + JFreeVariant(&dbv); + } + } + } + } + + // invite others + for (int i = 0; i < m_newJids.getCount(); ++i) + if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)m_newJids[i]->hItem, 0)) + InviteUser(m_newJids[i]->jid, text); + + mir_free(text); + Close(); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Context menu processing + +void CJabberProto::AdminSet( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal ) +{ + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( szItem, itemVal ) << XATTR( var, varVal )); +} + +void CJabberProto::AdminSetReason( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal , const TCHAR* rsn) +{ m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( szItem, itemVal ) << XATTR( var, varVal ) << XCHILD( _T("reason"), rsn)); +} + +void CJabberProto::AdminGet( const TCHAR* to, const TCHAR* ns, const TCHAR* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo ) +{ + int id = SerialNext(); + IqAdd( id, IQ_PROC_NONE, foo ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), id, to ) << XQUERY( ns ) << XCHILD( _T("item")) << XATTR( var, varVal )); +} + +// Member info dialog +struct TUserInfoData +{ + CJabberProto* ppro; + JABBER_LIST_ITEM *item; + JABBER_RESOURCE_STATUS *me, *him; +}; + +static INT_PTR CALLBACK sttUserInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TUserInfoData *dat = (TUserInfoData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + { + int i, idx; + TCHAR buf[256]; + + TranslateDialogDefault(hwndDlg); + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + dat = (TUserInfoData *)lParam; + + WindowSetIcon( hwndDlg, dat->ppro, "group" ); + + LOGFONT lf; + GetObject((HFONT)SendDlgItemMessage(hwndDlg, IDC_TXT_NICK, WM_GETFONT, 0, 0), sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + HFONT hfnt = CreateFontIndirect(&lf); + SendDlgItemMessage(hwndDlg, IDC_TXT_NICK, WM_SETFONT, (WPARAM)hfnt, TRUE); + + SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE)); + SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_BTN_AFFILIATION, BUTTONADDTOOLTIP, (WPARAM)"Apply", 0); + + SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE)); + SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_BTN_ROLE, BUTTONADDTOOLTIP, (WPARAM)"Apply", 0); + + SendDlgItemMessage(hwndDlg, IDC_ICO_STATUS, STM_SETICON, (WPARAM)LoadSkinnedProtoIcon(dat->ppro->m_szModuleName, dat->him->status), 0); + + mir_sntprintf(buf, SIZEOF(buf), _T("%s %s"), TranslateT("Member Info:"), dat->him->resourceName); + SetWindowText(hwndDlg, buf); + + mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s %s %s"), TranslateT("Member Information"), dat->him->resourceName, TranslateT("from"), dat->item->jid); + SetDlgItemText(hwndDlg, IDC_HEADERBAR, buf); + + SetDlgItemText(hwndDlg, IDC_TXT_NICK, dat->him->resourceName); + SetDlgItemText(hwndDlg, IDC_TXT_JID, dat->him->szRealJid ? dat->him->szRealJid : TranslateT("Real JID not available")); + SetDlgItemText(hwndDlg, IDC_TXT_STATUS, dat->him->statusMessage); + + for (i = 0; i < SIZEOF(sttRoleItems); ++i) + { + if ((sttRoleItems[i].value == dat->him->role) || sttRoleItems[i].check(dat->me, dat->him)) + { + SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_SETITEMDATA, + idx = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_ADDSTRING, 0, (LPARAM)sttRoleItems[i].title), + sttRoleItems[i].value); + if (sttRoleItems[i].value == dat->him->role) + SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_SETCURSEL, idx, 0); + } + } + for (i = 0; i < SIZEOF(sttAffiliationItems); ++i) + { + if ((sttAffiliationItems[i].value == dat->him->affiliation) || sttAffiliationItems[i].check(dat->me, dat->him)) + { + SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_SETITEMDATA, + idx = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_ADDSTRING, 0, (LPARAM)sttAffiliationItems[i].title), + sttAffiliationItems[i].value); + if (sttAffiliationItems[i].value == dat->him->affiliation) + SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_SETCURSEL, idx, 0); + } + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_ROLE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_AFFILIATION), FALSE); + + break; + } + + case WM_COMMAND: + if (!dat)break; + + switch ( LOWORD( wParam )) { + case IDCANCEL: + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + break; + + case IDC_TXT_AFFILIATION: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + int value = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETITEMDATA, + SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETCURSEL, 0, 0), 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_AFFILIATION), dat->him->affiliation != value); + } + break; + + case IDC_BTN_AFFILIATION: + { + int value = SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETITEMDATA, + SendDlgItemMessage(hwndDlg, IDC_TXT_AFFILIATION, CB_GETCURSEL, 0, 0), 0); + if (dat->him->affiliation == value) break; + + switch (value) + { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( dat->him->szRealJid, szBareJid, SIZEOF(szBareJid)); + case AFFILIATION_NONE: + if (dat->him->szRealJid) + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("none")); + else + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("none")); + break; + case AFFILIATION_MEMBER: + if (dat->him->szRealJid) + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("member")); + else + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("member")); + break; + case AFFILIATION_ADMIN: + if (dat->him->szRealJid) + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("admin")); + else + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("admin")); + break; + case AFFILIATION_OWNER: + if (dat->him->szRealJid) + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("owner")); + else + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("affiliation"), _T("owner")); + break; + } + } + break; + + case IDC_TXT_ROLE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + int value = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETITEMDATA, + SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETCURSEL, 0, 0), 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_ROLE), dat->him->role != value); + } + break; + + case IDC_BTN_ROLE: + { + int value = SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETITEMDATA, + SendDlgItemMessage(hwndDlg, IDC_TXT_ROLE, CB_GETCURSEL, 0, 0), 0); + if (dat->him->role == value) break; + + switch (value) { + case ROLE_VISITOR: + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("visitor")); + break; + case ROLE_PARTICIPANT: + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("participant")); + break; + case ROLE_MODERATOR: + dat->ppro->AdminSet(dat->item->jid, xmlnsAdmin, _T("nick"), dat->him->resourceName, _T("role"), _T("moderator")); + break; + } + } + break; + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + { + WindowFreeIcon( hwndDlg ); + g_ReleaseIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_BTN_AFFILIATION, BM_SETIMAGE, IMAGE_ICON, 0 )); + g_ReleaseIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_BTN_ROLE, BM_SETIMAGE, IMAGE_ICON, 0 )); + TUserInfoData *dat = (TUserInfoData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (!dat)break; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + mir_free(dat); + break; + } + } + return FALSE; +} + +static void sttNickListHook( CJabberProto* ppro, JABBER_LIST_ITEM* item, GCHOOK* gch ) +{ + JABBER_RESOURCE_STATUS *me = NULL, *him = NULL; + for ( int i=0; i < item->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& p = item->resource[i]; + if ( !lstrcmp( p.resourceName, item->nick )) me = &p; + if ( !lstrcmp( p.resourceName, gch->ptszUID )) him = &p; + } + + if ( him == NULL || me == NULL ) + return; + + // 1 kick per second, prevents crashes... + enum { BAN_KICK_INTERVAL = 1000 }; + static DWORD dwLastBanKickTime = 0; + + TCHAR szBuffer[1024]; + TCHAR szTitle[256]; + + if ((gch->dwData >= CLISTMENUIDMIN) && (gch->dwData <= CLISTMENUIDMAX)) + { + if (him->szRealJid && *him->szRealJid) + if (HANDLE hContact = ppro->HContactFromJID(him->szRealJid)) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(gch->dwData, MPCF_CONTACTMENU), (LPARAM)hContact); + return; + } + + switch( gch->dwData ) { + case IDM_SLAP: + { + if ( ppro->m_bJabberOnline ) { + DBVARIANT dbv = {0}; + TCHAR *szMessage = DBGetContactSettingTString( NULL, ppro->m_szModuleName, "GcMsgSlap", &dbv) ? + NEWTSTR_ALLOCA(TranslateTS(JABBER_GC_MSG_SLAP)) : dbv.ptszVal; + + TCHAR buf[256]; + // do not use snprintf to avoid possible problems with % symbol + if (TCHAR *p = _tcsstr(szMessage, _T("%s"))) { + *p = 0; + mir_sntprintf(buf, SIZEOF(buf), _T("%s%s%s"), szMessage, him->resourceName, p+2); + } + else lstrcpyn(buf, szMessage, SIZEOF(buf)); + UnEscapeChatTags( buf ); + + ppro->m_ThreadInfo->send( + XmlNode( _T("message")) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("groupchat")) + << XCHILD( _T("body"), buf )); + + if (szMessage == dbv.ptszVal) + DBFreeVariant(&dbv); + } + break; + } + case IDM_VCARD: + { + HANDLE hContact; + JABBER_SEARCH_RESULT jsr = {0}; + mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s/%s"), item->jid, him->resourceName ); + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + + JABBER_LIST_ITEM* item = ppro->ListAdd( LIST_VCARD_TEMP, jsr.jid ); + item->bUseResource = TRUE; + ppro->ListAddResource( LIST_VCARD_TEMP, jsr.jid, him->status, him->statusMessage, him->priority ); + + hContact = ( HANDLE )CallProtoService( ppro->m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); + CallService( MS_USERINFO_SHOWDIALOG, ( WPARAM )hContact, 0 ); + break; + } + case IDM_INFO: + { + TUserInfoData *dat = (TUserInfoData *)mir_alloc(sizeof(TUserInfoData)); + dat->me = me; + dat->him = him; + dat->item = item; + dat->ppro = ppro; + HWND hwndInfo = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_GROUPCHAT_INFO), NULL, sttUserInfoDlgProc, (LPARAM)dat); + ShowWindow(hwndInfo, SW_SHOW); + break; + } + case IDM_KICK: + { + if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) + { + dwLastBanKickTime = GetTickCount(); + mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s: "), me->resourceName ); + mir_sntprintf( szTitle, SIZEOF(szTitle), _T("%s %s"), TranslateT( "Reason to kick" ), him->resourceName ); + TCHAR *resourceName_copy = mir_tstrdup(him->resourceName); // copy resource name to prevent possible crash if user list rebuilds + if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE, "gcReason_" )) + ppro->m_ThreadInfo->send( + XmlNodeIq( _T("set"), ppro->SerialNext(), item->jid ) << XQUERY( xmlnsAdmin ) + << XCHILD( _T("item")) << XATTR( _T("nick"), resourceName_copy ) << XATTR( _T("role"), _T("none")) + << XCHILD( _T("reason"), szBuffer )); + + mir_free(resourceName_copy); + } + dwLastBanKickTime = GetTickCount(); + break; + } + + case IDM_SET_VISITOR: + if (him->role != ROLE_VISITOR) + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("visitor")); + break; + case IDM_SET_PARTICIPANT: + if (him->role != ROLE_PARTICIPANT) + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("participant")); + break; + case IDM_SET_MODERATOR: + if (him->role != ROLE_MODERATOR) + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("role"), _T("moderator")); + break; + + case IDM_SET_NONE: + if (him->affiliation != AFFILIATION_NONE) + { + if (him->szRealJid) + { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); + ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("none")); + } + else + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("none")); + } + break; + case IDM_SET_MEMBER: + if (him->affiliation != AFFILIATION_MEMBER) + { + if (him->szRealJid) + { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); + ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("member")); + } + else + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("member")); + } + break; + case IDM_SET_ADMIN: + if (him->affiliation != AFFILIATION_ADMIN) + { + if (him->szRealJid) + { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); + ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("admin")); + } + else + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("admin")); + } + break; + case IDM_SET_OWNER: + if (him->affiliation != AFFILIATION_OWNER) + { + if (him->szRealJid) + { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( him->szRealJid, szBareJid, SIZEOF(szBareJid)); + ppro->AdminSet(item->jid, xmlnsAdmin, _T("jid"), szBareJid, _T("affiliation"), _T("owner")); + } + else + ppro->AdminSet(item->jid, xmlnsAdmin, _T("nick"), him->resourceName, _T("affiliation"), _T("owner")); + } + break; + + case IDM_SET_BAN: + if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) { + if ( him->szRealJid && *him->szRealJid ) { + TCHAR szVictimBareJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( him->szRealJid, szVictimBareJid, SIZEOF(szVictimBareJid)); + + mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s: "), me->resourceName ); + mir_sntprintf( szTitle, SIZEOF(szTitle), _T("%s %s"), TranslateT( "Reason to ban" ), him->resourceName ); + + if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE, "gcReason_" )) { + ppro->m_ThreadInfo->send( + XmlNodeIq( _T("set"), ppro->SerialNext(), item->jid ) << XQUERY( xmlnsAdmin ) + << XCHILD( _T("item")) << XATTR( _T("jid"), szVictimBareJid ) << XATTR( _T("affiliation"), _T("outcast")) + << XCHILD( _T("reason"), szBuffer )); + } + } + } + dwLastBanKickTime = GetTickCount(); + break; + + case IDM_LINK0: case IDM_LINK1: case IDM_LINK2: case IDM_LINK3: case IDM_LINK4: + case IDM_LINK5: case IDM_LINK6: case IDM_LINK7: case IDM_LINK8: case IDM_LINK9: + { + if ((GetTickCount() - dwLastBanKickTime) > BAN_KICK_INTERVAL) + { + TCHAR *resourceName_copy = NEWTSTR_ALLOCA(him->resourceName); // copy resource name to prevent possible crash if user list rebuilds + + TCHAR *szInviteTo = 0; + int idx = gch->dwData - IDM_LINK0; + LISTFOREACH(i, ppro, LIST_CHATROOM) + if (JABBER_LIST_ITEM *item = ppro->ListGetItemPtrFromIndex(i)) + if (!idx--) + { + szInviteTo = item->jid; + break; + } + + if (!szInviteTo) break; + + mir_sntprintf( szTitle, SIZEOF(szTitle), TranslateT("Invite %s to %s"), him->resourceName, szInviteTo ); + *szBuffer = 0; + if (!ppro->EnterString(szBuffer, SIZEOF(szBuffer), szTitle, JES_MULTINE)) + break; + + mir_sntprintf(szTitle, SIZEOF(szTitle), _T("%s/%s"), item->jid, resourceName_copy); + + XmlNode msg( _T("message")); + HXML invite = msg << XATTR( _T("to"), szTitle ) << XATTRID(ppro->SerialNext()) + << XCHILD(_T("x"), szBuffer) + << XATTR(_T("xmlns"), _T("jabber:x:conference")) + << XATTR( _T("jid"), szInviteTo ) + << XCHILD(_T("invite")) << XATTR(_T("from"), item->nick); + ppro->m_ThreadInfo->send( msg ); + } + dwLastBanKickTime = GetTickCount(); + break; + } + + case IDM_CPY_NICK: + JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), him->resourceName); + break; + case IDM_RJID_COPY: + case IDM_CPY_RJID: + JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), him->szRealJid); + break; + case IDM_CPY_INROOMJID: + mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s/%s"), item->jid, him->resourceName); + JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), szBuffer); + break; + + case IDM_RJID_VCARD: + if (him->szRealJid && *him->szRealJid) + { + HANDLE hContact; + JABBER_SEARCH_RESULT jsr ={0}; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s"), him->szRealJid); + if (TCHAR *tmp = _tcschr(jsr.jid, _T('/'))) *tmp = 0; + + JABBER_LIST_ITEM* item = ppro->ListAdd( LIST_VCARD_TEMP, jsr.jid ); + item->bUseResource = TRUE; + ppro->ListAddResource( LIST_VCARD_TEMP, jsr.jid, him->status, him->statusMessage, him->priority ); + + hContact = ( HANDLE )CallProtoService( ppro->m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); + CallService( MS_USERINFO_SHOWDIALOG, ( WPARAM )hContact, 0 ); + break; + } + + case IDM_RJID_ADD: + if (him->szRealJid && *him->szRealJid) + { + JABBER_SEARCH_RESULT jsr={0}; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + jsr.hdr.flags = PSR_TCHAR; + mir_sntprintf(jsr.jid, SIZEOF(jsr.jid), _T("%s"), him->szRealJid); + if (TCHAR *tmp = _tcschr(jsr.jid, _T('/'))) *tmp = 0; + jsr.hdr.nick = jsr.jid; + + ADDCONTACTSTRUCT acs={0}; + acs.handleType = HANDLE_SEARCHRESULT; + acs.szProto = ppro->m_szModuleName; + acs.psr = (PROTOSEARCHRESULT *)&jsr; + CallService(MS_ADDCONTACT_SHOW, (WPARAM)CallService(MS_CLUI_GETHWND, 0, 0), (LPARAM)&acs); + break; + } + } +} + +static void sttLogListHook( CJabberProto* ppro, JABBER_LIST_ITEM* item, GCHOOK* gch ) +{ + TCHAR szBuffer[ 1024 ]; + TCHAR szCaption[ 1024 ]; + szBuffer[ 0 ] = _T('\0'); + + switch( gch->dwData ) { + case IDM_LST_PARTICIPANT: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("role"), _T("participant"), &CJabberProto::OnIqResultMucGetVoiceList ); + break; + + case IDM_LST_MEMBER: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("member"), &CJabberProto::OnIqResultMucGetMemberList ); + break; + + case IDM_LST_MODERATOR: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("role"), _T("moderator"), &CJabberProto::OnIqResultMucGetModeratorList ); + break; + + case IDM_LST_BAN: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList ); + break; + + case IDM_LST_ADMIN: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("admin"), &CJabberProto::OnIqResultMucGetAdminList ); + break; + + case IDM_LST_OWNER: + ppro->AdminGet(gch->pDest->ptszID, xmlnsAdmin, _T("affiliation"), _T("owner"), &CJabberProto::OnIqResultMucGetOwnerList ); + break; + + case IDM_TOPIC: + mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s %s"), TranslateT( "Set topic for" ), gch->pDest->ptszID ); + TCHAR szTmpBuff[ SIZEOF(szBuffer) * 2 ]; + if ( item->itemResource.statusMessage ) { + int j = 0; + for ( int i = 0; i < SIZEOF(szTmpBuff); i++ ) { + if ( item->itemResource.statusMessage[ i ] != _T('\n') || ( i && item->itemResource.statusMessage[ i - 1 ] == _T('\r'))) + szTmpBuff[ j++ ] = item->itemResource.statusMessage[ i ]; + else { + szTmpBuff[ j++ ] = _T('\r'); + szTmpBuff[ j++ ] = _T('\n'); + } + if ( !item->itemResource.statusMessage[ i ] ) + break; + } + } + else szTmpBuff[ 0 ] = _T('\0'); + + if ( ppro->EnterString( szTmpBuff, SIZEOF(szTmpBuff), szCaption, JES_RICHEDIT, "gcTopic_" )) + ppro->m_ThreadInfo->send( + XmlNode( _T("message")) << XATTR( _T("to"), gch->pDest->ptszID ) << XATTR( _T("type"), _T("groupchat")) + << XCHILD( _T("subject"), szTmpBuff )); + + break; + + case IDM_NICK: + mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s %s"), TranslateT( "Change nickname in" ), gch->pDest->ptszID ); + if ( item->nick ) + mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s"), item->nick ); + if ( ppro->EnterString(szBuffer, SIZEOF(szBuffer), szCaption, JES_COMBO, "gcNick_" )) { + JABBER_LIST_ITEM* item = ppro->ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); + if ( item != NULL ) { + TCHAR text[ 1024 ]; + mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), gch->pDest->ptszID, szBuffer ); + ppro->SendPresenceTo( ppro->m_iStatus == ID_STATUS_INVISIBLE ? ID_STATUS_ONLINE : ppro->m_iStatus, text, NULL ); + } } + break; + + case IDM_INVITE: + { + CGroupchatInviteDlg *dlg = new CGroupchatInviteDlg( ppro, gch->pDest->ptszID ); + dlg->Show(); + break; + } + + case IDM_CONFIG: + { + int iqId = ppro->SerialNext(); + ppro->IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); + + XmlNodeIq iq( _T("get"), iqId, gch->pDest->ptszID ); + iq << XQUERY( xmlnsOwner ); + ppro->m_ThreadInfo->send( iq ); + break; + } + case IDM_BOOKMARKS: + { + JABBER_LIST_ITEM* item = ppro->ListGetItemPtr( LIST_BOOKMARK, gch->pDest->ptszID ); + if ( item == NULL ) { + item = ppro->ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); + if (item != NULL) { + item->type = _T("conference"); + HANDLE hContact = ppro->HContactFromJID( item->jid ); + item->name = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR ); + ppro->AddEditBookmark( item ); + } + } + break; + } + case IDM_DESTROY: + mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to destroy" ), gch->pDest->ptszID ); + if ( !ppro->EnterString(szBuffer, SIZEOF(szBuffer), NULL, JES_MULTINE, "gcReason_" )) + break; + + ppro->m_ThreadInfo->send( + XmlNodeIq( _T("set"), ppro->SerialNext(), gch->pDest->ptszID ) << XQUERY( xmlnsOwner ) + << XCHILD( _T("destroy")) << XCHILD( _T("reason"), szBuffer )); + + case IDM_LEAVE: + ppro->GcQuit( item, 0, NULL ); + break; + + case IDM_PRESENCE_ONLINE: + case IDM_PRESENCE_AWAY: + case IDM_PRESENCE_NA: + case IDM_PRESENCE_DND: + case IDM_PRESENCE_FREE4CHAT: + { + if ( HANDLE h = ppro->HContactFromJID( item->jid )) + ppro->OnMenuHandleDirectPresence( (WPARAM)h, 0, gch->dwData ); + break; + } + + + case IDM_LINK0: case IDM_LINK1: case IDM_LINK2: case IDM_LINK3: case IDM_LINK4: + case IDM_LINK5: case IDM_LINK6: case IDM_LINK7: case IDM_LINK8: case IDM_LINK9: + { + unsigned idx = IDM_LINK0; + for (TCHAR *p = _tcsstr(item->itemResource.statusMessage, _T("http://")); p && *p; p = _tcsstr(p+1, _T("http://"))) + { + if (idx == gch->dwData) + { + char *bufPtr, *url = mir_t2a(p); + for (bufPtr = url; *bufPtr && !isspace(*bufPtr); ++bufPtr) ; + *bufPtr++ = 0; + CallService(MS_UTILS_OPENURL, 1, (LPARAM)url); + mir_free(url); + break; + } + + if (++idx > IDM_LINK9) break; + } + + break; + } + + case IDM_CPY_RJID: + JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), item->jid); + break; + case IDM_CPY_TOPIC: + JabberCopyText((HWND)CallService(MS_CLUI_GETHWND, 0, 0), item->itemResource.statusMessage); + break; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Sends a private message to a chat user + +static void sttSendPrivateMessage( CJabberProto* ppro, JABBER_LIST_ITEM* item, const TCHAR* nick ) +{ + TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; + mir_sntprintf( szFullJid, SIZEOF(szFullJid), _T("%s/%s"), item->jid, nick ); + HANDLE hContact = ppro->DBCreateContact( szFullJid, NULL, TRUE, FALSE ); + if ( hContact != NULL ) { + for ( int i=0; i < item->resourceCount; i++ ) { + if ( _tcsicmp( item->resource[i].resourceName, nick ) == 0 ) { + ppro->JSetWord( hContact, "Status", item->resource[i].status ); + break; + } } + + DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 ); + ppro->JSetStringT( hContact, "Nick", nick ); + DBWriteContactSettingDword( hContact, "Ignore", "Mask1", 0 ); + CallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact, 0 ); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// General chat event processing hook + +int CJabberProto::JabberGcEventHook(WPARAM, LPARAM lParam) +{ + GCHOOK* gch = ( GCHOOK* )lParam; + if ( gch == NULL ) + return 0; + + if ( lstrcmpiA( gch->pDest->pszModule, m_szModuleName )) + return 0; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, gch->pDest->ptszID ); + if ( item == NULL ) + return 0; + + switch ( gch->pDest->iType ) { + case GC_USER_MESSAGE: + if ( gch->pszText && lstrlen( gch->ptszText) > 0 ) { + trtrim( gch->ptszText ); + + if ( m_bJabberOnline ) { + TCHAR* buf = NEWTSTR_ALLOCA(gch->ptszText); + UnEscapeChatTags( buf ); + m_ThreadInfo->send( + XmlNode( _T("message")) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("groupchat")) + << XCHILD( _T("body"), buf )); + } } + break; + + case GC_USER_PRIVMESS: + sttSendPrivateMessage( this, item, gch->ptszUID ); + break; + + case GC_USER_LOGMENU: + sttLogListHook( this, item, gch ); + break; + + case GC_USER_NICKLISTMENU: + sttNickListHook( this, item, gch ); + break; + + case GC_USER_CHANMGR: + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, item->jid ) << XQUERY( xmlnsOwner )); + break; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +void CJabberProto::AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str , TCHAR* rsn) +{ + const TCHAR* field = ( jidListInfo->type == MUC_BANLIST || _tcschr(str,'@')) ? _T("jid") : _T("nick"); + TCHAR* roomJid = jidListInfo->roomJid; + if ( jidListInfo->type == MUC_BANLIST ) { + AdminSetReason( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("outcast"), rsn); + AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList); +} } + +void CJabberProto::AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str ) +{ + const TCHAR* field = ( jidListInfo->type == MUC_BANLIST || _tcschr(str,'@')) ? _T("jid") : _T("nick"); + TCHAR* roomJid = jidListInfo->roomJid; + + switch (jidListInfo->type) { + case MUC_VOICELIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("role"), _T("participant")); + AdminGet( roomJid, xmlnsAdmin, _T("role"), _T("participant"), &CJabberProto::OnIqResultMucGetVoiceList); + break; + case MUC_MEMBERLIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("member")); + AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("member"), &CJabberProto::OnIqResultMucGetMemberList); + break; + case MUC_MODERATORLIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("role"), _T("moderator")); + AdminGet( roomJid, xmlnsAdmin, _T("role"), _T("moderator"), &CJabberProto::OnIqResultMucGetModeratorList); + break; + case MUC_BANLIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("outcast")); + AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("outcast"), &CJabberProto::OnIqResultMucGetBanList); + break; + case MUC_ADMINLIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("admin")); + AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("admin"), &CJabberProto::OnIqResultMucGetAdminList); + break; + case MUC_OWNERLIST: + AdminSet( roomJid, xmlnsAdmin, field, str, _T("affiliation"), _T("owner")); + AdminGet( roomJid, xmlnsAdmin, _T("affiliation"), _T("owner"), &CJabberProto::OnIqResultMucGetOwnerList); + break; +} } + +void CJabberProto::DeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid ) +{ + TCHAR* roomJid = jidListInfo->roomJid; + + switch ( jidListInfo->type ) { + case MUC_VOICELIST: // change role to visitor ( from participant ) + AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("role"), _T("visitor")); + break; + case MUC_BANLIST: // change affiliation to none ( from outcast ) + case MUC_MEMBERLIST: // change affiliation to none ( from member ) + AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("none")); + break; + case MUC_MODERATORLIST: // change role to participant ( from moderator ) + AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("role"), _T("participant")); + break; + case MUC_ADMINLIST: // change affiliation to member ( from admin ) + AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("member")); + break; + case MUC_OWNERLIST: // change affiliation to admin ( from owner ) + AdminSet( roomJid, xmlnsAdmin, _T("jid"), jid, _T("affiliation"), _T("admin")); + break; +} } diff --git a/protocols/JabberG/src/jabber_console.cpp b/protocols/JabberG/src/jabber_console.cpp new file mode 100644 index 0000000000..ca2c82b3e4 --- /dev/null +++ b/protocols/JabberG/src/jabber_console.cpp @@ -0,0 +1,716 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2007 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <richedit.h> + +#define JCPF_IN 0x01UL +#define JCPF_OUT 0x02UL +#define JCPF_ERROR 0x04UL + +#define JCPF_TCHAR 0x00UL + +#define WM_CREATECONSOLE WM_USER+1000 + +#ifndef SES_EXTENDBACKCOLOR +#define SES_EXTENDBACKCOLOR 4 +#endif + +/* increment buffer with 1K steps */ +#define STRINGBUF_INCREMENT 1024 + +struct StringBuf +{ + char *buf; + int size; + int offset; + int streamOffset; +}; + +static void sttAppendBufRaw(StringBuf *buf, const char *str); +static void sttAppendBufW(StringBuf *buf, const WCHAR *str); +#define sttAppendBufT(a,b) (sttAppendBufW((a),(b))) +static void sttEmptyBuf(StringBuf *buf); + +#define RTF_HEADER \ + "{\\rtf1\\ansi{\\colortbl;" \ + "\\red128\\green0\\blue0;" \ + "\\red0\\green0\\blue128;" \ + "\\red245\\green255\\blue245;" \ + "\\red245\\green245\\blue255;" \ + "\\red128\\green128\\blue128;" \ + "\\red255\\green235\\blue235;" \ + "}" +#define RTF_FOOTER "}" +#define RTF_BEGINTAG "\\pard " +#define RTF_INDENT_FMT "\\fi-100\\li%d " +#define RTF_ENDTAG "\\par" +#define RTF_BEGINTAGNAME "\\cf1\\b " +#define RTF_ENDTAGNAME "\\cf0\\b0 " +#define RTF_BEGINATTRNAME "\\cf2\\b " +#define RTF_ENDATTRNAME "\\cf0\\b0 " +#define RTF_BEGINATTRVAL "\\b0 " +#define RTF_ENDATTRVAL "" +#define RTF_BEGINTEXT "\\pard " +#define RTF_TEXTINDENT_FMT "\\fi0\\li%d " +#define RTF_ENDTEXT "\\par" +#define RTF_BEGINPLAINXML "\\pard\\fi0\\li100\\highlight6\\cf0 " +#define RTF_ENDPLAINXML "\\par" +#define RTF_SEPARATOR "\\sl-1\\slmult0\\highlight5\\cf5\\-\\par\\sl0" + +static void sttRtfAppendXml(StringBuf *buf, HXML node, DWORD flags, int indent); + +void CJabberProto::OnConsoleProcessXml(HXML node, DWORD flags) +{ + if ( node && m_pDlgConsole ) { + if ( xmlGetName( node )) { + if ( FilterXml( node, flags )) { + StringBuf buf = {0}; + sttAppendBufRaw(&buf, RTF_HEADER); + sttRtfAppendXml(&buf, node, flags, 1); + sttAppendBufRaw(&buf, RTF_SEPARATOR); + sttAppendBufRaw(&buf, RTF_FOOTER); + SendMessage(m_pDlgConsole->GetHwnd(), WM_JABBER_REFRESH, 0, (LPARAM)&buf); + sttEmptyBuf(&buf); + } + } + else { + for ( int i = 0; i < xmlGetChildCount( node ); i++ ) + OnConsoleProcessXml( xmlGetChild( node, i), flags ); + } + } +} + +bool CJabberProto::RecursiveCheckFilter(HXML node, DWORD flags) +{ + int i; + + for (i = 0; i < xmlGetAttrCount(node); ++i) + { + if ( JabberStrIStr( xmlGetAttr( node,i ), m_filterInfo.pattern )) + return true; + } + + for (i = 0; i < xmlGetChildCount( node ); ++i) { + if (RecursiveCheckFilter( xmlGetChild( node, i ), flags)) + return true; + } + + return false; +} + +bool CJabberProto::FilterXml(HXML node, DWORD flags) +{ + if (!m_filterInfo.msg && !lstrcmp(xmlGetName( node ), _T("message"))) return false; + if (!m_filterInfo.presence && !lstrcmp(xmlGetName( node ), _T("presence"))) return false; + if (!m_filterInfo.iq && !lstrcmp(xmlGetName( node ), _T("iq"))) return false; + if (m_filterInfo.type == TFilterInfo::T_OFF) return true; + + bool result = false; + EnterCriticalSection(&m_filterInfo.csPatternLock); + + switch (m_filterInfo.type) + { + case TFilterInfo::T_JID: + { + const TCHAR *attrValue = xmlGetAttrValue( node,(flags&JCPF_OUT)?_T("to"):_T("from")); + if (!attrValue) break; + + result = JabberStrIStr(attrValue, m_filterInfo.pattern) ? true : false; + break; + } + case TFilterInfo::T_XMLNS: + { + if ( !xmlGetChildCount( node )) break; + + const TCHAR *attrValue = xmlGetAttrValue( xmlGetChild( node, 0 ), _T("xmlns")); + if ( !attrValue ) + break; + + result = JabberStrIStr(attrValue, m_filterInfo.pattern) ? true : false; + break; + } + + case TFilterInfo::T_ANY: + { + result = RecursiveCheckFilter(node, flags); + break; + } + } + + LeaveCriticalSection(&m_filterInfo.csPatternLock); + return result; +} + +static void sttAppendBufRaw(StringBuf *buf, const char *str) +{ + if (!str) return; + + int length = lstrlenA(str); + if (buf->size - buf->offset < length+1) + { + buf->size += (length + STRINGBUF_INCREMENT); + buf->buf = (char *)mir_realloc(buf->buf, buf->size); + } + lstrcpyA(buf->buf + buf->offset, str); + buf->offset += length; +} + +static void sttAppendBufW(StringBuf *buf, const WCHAR *str) +{ + char tmp[32]; + + if (!str) return; + + sttAppendBufRaw(buf, "{\\uc1 "); + for (const WCHAR *p = str; *p; ++p) + { + if ((*p == '\\') || (*p == '{') || (*p == '}')) + { + tmp[0] = '\\'; + tmp[1] = (char)*p; + tmp[2] = 0; + } else + if (*p < 128) + { + tmp[0] = (char)*p; + tmp[1] = 0; + } else + { + mir_snprintf(tmp, sizeof(tmp), "\\u%d ?", (int)*p); + } + sttAppendBufRaw(buf, tmp); + } + sttAppendBufRaw(buf, "}"); +} + +static void sttEmptyBuf(StringBuf *buf) +{ + if (buf->buf) mir_free(buf->buf); + buf->buf = 0; + buf->size = 0; + buf->offset = 0; +} + +static void sttRtfAppendXml(StringBuf *buf, HXML node, DWORD flags, int indent) +{ + int i; + char *indentLevel = (char *)mir_alloc(128); + mir_snprintf(indentLevel, 128, RTF_INDENT_FMT, + (int)(indent*200) + ); + + sttAppendBufRaw(buf, RTF_BEGINTAG); + sttAppendBufRaw(buf, indentLevel); + if (flags&JCPF_IN) sttAppendBufRaw(buf, "\\highlight3 "); + if (flags&JCPF_OUT) sttAppendBufRaw(buf, "\\highlight4 "); + sttAppendBufRaw(buf, "<"); + sttAppendBufRaw(buf, RTF_BEGINTAGNAME); + sttAppendBufW(buf, (TCHAR*)xmlGetName( node )); + sttAppendBufRaw(buf, RTF_ENDTAGNAME); + + for (i = 0; i < xmlGetAttrCount( node); i++) + { + TCHAR* attr = ( TCHAR* )xmlGetAttrName( node, i ); + sttAppendBufRaw(buf, " "); + sttAppendBufRaw(buf, RTF_BEGINATTRNAME); + sttAppendBufW(buf, attr); + sttAppendBufRaw(buf, RTF_ENDATTRNAME); + sttAppendBufRaw(buf, "=\""); + sttAppendBufRaw(buf, RTF_BEGINATTRVAL); + sttAppendBufT(buf, ( TCHAR* )xmlGetAttr( node, i)); + sttAppendBufRaw(buf, "\""); + sttAppendBufRaw(buf, RTF_ENDATTRVAL); + } + + if ( xmlGetChild( node ) || xmlGetText( node )) + { + sttAppendBufRaw(buf, ">"); + if ( xmlGetChild( node )) + sttAppendBufRaw(buf, RTF_ENDTAG); + } + + if (xmlGetText( node )) + { + if ( xmlGetChildCount( node )) + { + sttAppendBufRaw(buf, RTF_BEGINTEXT); + char *indentTextLevel = (char *)mir_alloc(128); + mir_snprintf( indentTextLevel, 128, RTF_TEXTINDENT_FMT, (int)(( indent + 1) * 200 )); + sttAppendBufRaw(buf, indentTextLevel); + mir_free(indentTextLevel); + } + + sttAppendBufT(buf, xmlGetText( node )); + if ( xmlGetChild( node )) + sttAppendBufRaw(buf, RTF_ENDTEXT); + } + + for (i = 0; i < xmlGetChildCount( node ) ; ++i) + sttRtfAppendXml(buf, xmlGetChild( node ,i), flags & ~(JCPF_IN|JCPF_OUT), indent+1); + + if (xmlGetChildCount( node ) || xmlGetText( node )) + { + sttAppendBufRaw(buf, RTF_BEGINTAG); + sttAppendBufRaw(buf, indentLevel); + sttAppendBufRaw(buf, "</"); + sttAppendBufRaw(buf, RTF_BEGINTAGNAME); + sttAppendBufT(buf, xmlGetName( node )); + sttAppendBufRaw(buf, RTF_ENDTAGNAME); + sttAppendBufRaw(buf, ">"); + } else + { + sttAppendBufRaw(buf, " />"); + } + + sttAppendBufRaw(buf, RTF_ENDTAG); + mir_free(indentLevel); +} + +DWORD CALLBACK sttStreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) +{ + StringBuf *buf = (StringBuf *)dwCookie; + *pcb = 0; + + if (buf->streamOffset < buf->offset) + { + *pcb = min(cb, buf->offset - buf->streamOffset); + memcpy(pbBuff, buf->buf + buf->streamOffset, *pcb); + buf->streamOffset += *pcb; + } + + return 0; +} + +static void sttJabberConsoleRebuildStrings(CJabberProto* ppro, HWND hwndCombo) +{ + int i; + JABBER_LIST_ITEM *item = NULL; + + int len = GetWindowTextLength(hwndCombo) + 1; + TCHAR *buf = (TCHAR *)_alloca(len * sizeof(TCHAR)); + GetWindowText(hwndCombo, buf, len); + + SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); + + for (i = 0; g_JabberFeatCapPairs[i].szFeature; ++i) + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)g_JabberFeatCapPairs[i].szFeature); + for (i = 0; g_JabberFeatCapPairsExt[i].szFeature; ++i) + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)g_JabberFeatCapPairsExt[i].szFeature); + + LISTFOREACH_NODEF(i, ppro, LIST_ROSTER) + if (item = ppro->ListGetItemPtrFromIndex(i)) + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)item->jid); + LISTFOREACH_NODEF(i, ppro, LIST_CHATROOM) + if (item = ppro->ListGetItemPtrFromIndex(i)) + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)item->jid); + + SetWindowText(hwndCombo, buf); +} + +/////////////////////////////////////////////////////////////////////////////// +// CJabberDlgConsole class +static struct +{ + int type; + TCHAR *title; + char *icon; +} filter_modes[] = +{ + { TFilterInfo::T_JID, _T("JID"), "main" }, + { TFilterInfo::T_XMLNS, _T("xmlns"), "xmlconsole" }, + { TFilterInfo::T_ANY, _T("all attributes"), "sd_filter_apply" }, + { TFilterInfo::T_OFF, _T("disabled"), "sd_filter_reset" }, +}; + +class CJabberDlgConsole: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgConsole(CJabberProto *proto); + +protected: + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + void OnProtoRefresh(WPARAM wParam, LPARAM lParam); + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + int Resizer(UTILRESIZECONTROL *urc); +}; + +CJabberDlgConsole::CJabberDlgConsole(CJabberProto *proto): + CJabberDlgBase(proto, IDD_CONSOLE, NULL) +{ +} + +void CJabberDlgConsole::OnInitDialog() +{ + CSuper::OnInitDialog(); + + int i; + + WindowSetIcon( m_hwnd, m_proto, "xmlconsole" ); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXLIMITTEXT, 0, 0x80000000); + + m_proto->m_filterInfo.msg = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_msg", TRUE); + m_proto->m_filterInfo.presence = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_presence", TRUE); + m_proto->m_filterInfo.iq = DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_iq", TRUE); + m_proto->m_filterInfo.type = (TFilterInfo::Type)DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_ftype", TFilterInfo::T_OFF); + + DBVARIANT dbv; + *m_proto->m_filterInfo.pattern = 0; + if ( !m_proto->JGetStringT(NULL, "consoleWnd_fpattern", &dbv)) { + lstrcpyn(m_proto->m_filterInfo.pattern, dbv.ptszVal, SIZEOF(m_proto->m_filterInfo.pattern)); + JFreeVariant(&dbv); + } + + sttJabberConsoleRebuildStrings(m_proto, GetDlgItem(m_hwnd, IDC_CB_FILTER)); + SetWindowText(GetDlgItem(m_hwnd, IDC_CB_FILTER), m_proto->m_filterInfo.pattern); + + static struct + { + int idc; + char *title; + char *icon; + bool push; + BOOL pushed; + } buttons[] = + { + {IDC_BTN_MSG, "Messages", "pl_msg_allow", true, m_proto->m_filterInfo.msg}, + {IDC_BTN_PRESENCE, "Presences", "pl_prin_allow", true, m_proto->m_filterInfo.presence}, + {IDC_BTN_IQ, "Queries", "pl_iq_allow", true, m_proto->m_filterInfo.iq}, + {IDC_BTN_FILTER, "Filter mode", "sd_filter_apply", true, FALSE}, + {IDC_BTN_FILTER_REFRESH, "Refresh list", "sd_nav_refresh", false, FALSE}, + }; + for (i = 0; i < SIZEOF(buttons); ++i) + { + SendDlgItemMessage(m_hwnd, buttons[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(buttons[i].icon)); + SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONADDTOOLTIP, (WPARAM)buttons[i].title, 0); + if (buttons[i].push) SendDlgItemMessage(m_hwnd, buttons[i].idc, BUTTONSETASPUSHBTN, TRUE, 0); + if (buttons[i].pushed) CheckDlgButton(m_hwnd, buttons[i].idc, TRUE); + } + + for (i = 0; i < SIZEOF(filter_modes); ++i) + if (filter_modes[i].type == m_proto->m_filterInfo.type) + { + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon))); + SendDlgItemMessage(m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon)); + break; + } + EnableWindow(GetDlgItem(m_hwnd, IDC_CB_FILTER), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); + EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTER_REFRESH), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "consoleWnd_"); +} + +void CJabberDlgConsole::OnClose() +{ + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_msg", m_proto->m_filterInfo.msg); + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_presence", m_proto->m_filterInfo.presence); + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_iq", m_proto->m_filterInfo.iq); + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "consoleWnd_ftype", m_proto->m_filterInfo.type); + m_proto->JSetStringT(NULL, "consoleWnd_fpattern", m_proto->m_filterInfo.pattern); + + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "consoleWnd_"); + DestroyWindow(m_hwnd); + CSuper::OnClose(); +} + +void CJabberDlgConsole::OnDestroy() +{ + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_MSG, BM_SETIMAGE, IMAGE_ICON, 0 )); + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_PRESENCE, BM_SETIMAGE, IMAGE_ICON, 0 )); + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_IQ, BM_SETIMAGE, IMAGE_ICON, 0 )); + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, 0 )); + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER_REFRESH, BM_SETIMAGE, IMAGE_ICON, 0 )); + + m_proto->m_pDlgConsole = NULL; + CSuper::OnDestroy(); +} + +void CJabberDlgConsole::OnProtoRefresh(WPARAM, LPARAM lParam) +{ + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_SETREDRAW, FALSE, 0); + + StringBuf *buf = (StringBuf *)lParam; + buf->streamOffset = 0; + + EDITSTREAM es = {0}; + es.dwCookie = (DWORD_PTR)buf; + es.pfnCallback = sttStreamInCallback; + + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(GetDlgItem(m_hwnd, IDC_CONSOLE), SB_VERT, &si); + + CHARRANGE oldSel, sel; + POINT ptScroll; + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_GETSCROLLPOS, 0, (LPARAM)&ptScroll); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXGETSEL, 0, (LPARAM)&oldSel); + sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLE)); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&sel); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_STREAMIN, SF_RTF|SFF_SELECTION, (LPARAM)&es); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&oldSel); + + // magic expression from tabsrmm :) + if ((UINT)si.nPos >= (UINT)si.nMax-si.nPage-5 || si.nMax-si.nMin-si.nPage < 50) + { + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); + sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLE)); + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_EXSETSEL, 0, (LPARAM)&sel); + } else + { + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, EM_SETSCROLLPOS, 0, (LPARAM)&ptScroll); + } + + SendDlgItemMessage(m_hwnd, IDC_CONSOLE, WM_SETREDRAW, TRUE, 0); + InvalidateRect(GetDlgItem(m_hwnd, IDC_CONSOLE), NULL, FALSE); +} + +int CJabberDlgConsole::Resizer(UTILRESIZECONTROL *urc) +{ + switch ( urc->wId ) + { + case IDC_CONSOLE: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + case IDC_CONSOLEIN: + return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; + + case IDC_BTN_MSG: + case IDC_BTN_PRESENCE: + case IDC_BTN_IQ: + case IDC_BTN_FILTER: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + + case IDC_CB_FILTER: + { + RECT rc; + GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); + urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx); + urc->rcItem.top += (urc->dlgNewSize.cy - urc->dlgOriginalSize.cy); + urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; + return 0; + } + + case IDC_RESET: + case IDOK: + case IDC_BTN_FILTER_REFRESH: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + return CSuper::Resizer(urc); +} + +INT_PTR CJabberDlgConsole::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch ( msg ) + { + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 300; + lpmmi->ptMinTrackSize.y = 400; + return 0; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + if (!m_proto->m_bJabberOnline) + { + MessageBox(m_hwnd, TranslateT("Can't send data while you are offline."), TranslateT("Jabber Error"), MB_ICONSTOP|MB_OK); + return TRUE; + } + + int length = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_CONSOLEIN)) + 1; + TCHAR *textToSend = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); + GetWindowText(GetDlgItem(m_hwnd, IDC_CONSOLEIN), textToSend, length); + + int bytesProcessed = 0; + XmlNode xmlTmp( textToSend, &bytesProcessed, NULL); + if (xmlTmp) + { + m_proto->m_ThreadInfo->send( xmlTmp ); + } + else + { + StringBuf buf = {0}; + sttAppendBufRaw(&buf, RTF_HEADER); + sttAppendBufRaw(&buf, RTF_BEGINPLAINXML); + sttAppendBufT(&buf, TranslateT("Outgoing XML parsing error")); + sttAppendBufRaw(&buf, RTF_ENDPLAINXML); + sttAppendBufRaw(&buf, RTF_SEPARATOR); + sttAppendBufRaw(&buf, RTF_FOOTER); + SendMessage(m_hwnd, WM_JABBER_REFRESH, 0, (LPARAM)&buf); + sttEmptyBuf(&buf); + } + + mir_free(textToSend); + + SendDlgItemMessage(m_hwnd, IDC_CONSOLEIN, WM_SETTEXT, 0, (LPARAM)_T("")); + return TRUE; + } + + case IDC_RESET: + { + SetDlgItemText(m_hwnd, IDC_CONSOLE, _T("")); + break; + } + + case IDC_BTN_MSG: + case IDC_BTN_PRESENCE: + case IDC_BTN_IQ: + { + m_proto->m_filterInfo.msg = IsDlgButtonChecked(m_hwnd, IDC_BTN_MSG); + m_proto->m_filterInfo.presence = IsDlgButtonChecked(m_hwnd, IDC_BTN_PRESENCE); + m_proto->m_filterInfo.iq = IsDlgButtonChecked(m_hwnd, IDC_BTN_IQ); + break; + } + + case IDC_BTN_FILTER_REFRESH: + { + sttJabberConsoleRebuildStrings(m_proto, GetDlgItem(m_hwnd, IDC_CB_FILTER)); + break; + } + + case IDC_BTN_FILTER: + { + int i; + HMENU hMenu = CreatePopupMenu(); + for (i = 0; i < SIZEOF(filter_modes); ++i) + { + AppendMenu(hMenu, + MF_STRING | ((filter_modes[i].type == m_proto->m_filterInfo.type) ? MF_CHECKED : 0), + filter_modes[i].type+1, TranslateTS(filter_modes[i].title)); + } + RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BTN_FILTER), &rc); + CheckDlgButton(m_hwnd, IDC_BTN_FILTER, TRUE); + int res = TrackPopupMenu(hMenu, TPM_RETURNCMD|TPM_BOTTOMALIGN, rc.left, rc.top, 0, m_hwnd, NULL); + CheckDlgButton(m_hwnd, IDC_BTN_FILTER, FALSE); + DestroyMenu(hMenu); + + if (res) + { + m_proto->m_filterInfo.type = (TFilterInfo::Type)(res - 1); + for (i = 0; i < SIZEOF(filter_modes); ++i) + if (filter_modes[i].type == m_proto->m_filterInfo.type) + { + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BTN_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx(filter_modes[i].icon))); + break; + } + EnableWindow(GetDlgItem(m_hwnd, IDC_CB_FILTER), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); + EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTER_REFRESH), (m_proto->m_filterInfo.type == TFilterInfo::T_OFF) ? FALSE : TRUE); + } + + break; + } + + case IDC_CB_FILTER: + { + if (HIWORD(wParam) == CBN_SELCHANGE) + { + int idx = SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETCURSEL, 0, 0); + int len = SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXTLEN, idx, 0) + 1; + + EnterCriticalSection(&m_proto->m_filterInfo.csPatternLock); + if (len > SIZEOF(m_proto->m_filterInfo.pattern)) + { + TCHAR *buf = (TCHAR *)_alloca(len * sizeof(TCHAR)); + SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXT, idx, (LPARAM)buf); + lstrcpyn(m_proto->m_filterInfo.pattern, buf, SIZEOF(m_proto->m_filterInfo.pattern)); + } else + { + SendDlgItemMessage(m_hwnd, IDC_CB_FILTER, CB_GETLBTEXT, idx, (LPARAM)m_proto->m_filterInfo.pattern); + } + LeaveCriticalSection(&m_proto->m_filterInfo.csPatternLock); + } else + if (HIWORD(wParam) == CBN_EDITCHANGE) + { + EnterCriticalSection(&m_proto->m_filterInfo.csPatternLock); + GetWindowText(GetDlgItem(m_hwnd, IDC_CB_FILTER), m_proto->m_filterInfo.pattern, SIZEOF(m_proto->m_filterInfo.pattern)); + LeaveCriticalSection(&m_proto->m_filterInfo.csPatternLock); + } + break; + } + } + break; + } + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +void __cdecl CJabberProto::ConsoleThread( void* ) +{ + MSG msg; + while ( GetMessage(&msg, NULL, 0, 0 )) { + if ( msg.message == WM_CREATECONSOLE ) { + m_pDlgConsole = new CJabberDlgConsole( this ); + m_pDlgConsole->Show(); + continue; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + m_dwConsoleThreadId = 0; +} + +void CJabberProto::ConsoleInit() +{ + LoadLibraryA("riched20.dll"); + InitializeCriticalSection(&m_filterInfo.csPatternLock); + m_hThreadConsole = JForkThreadEx( &CJabberProto::ConsoleThread, 0, &m_dwConsoleThreadId ); +} + +void CJabberProto::ConsoleUninit() +{ + if ( m_hThreadConsole ) { + PostThreadMessage(m_dwConsoleThreadId, WM_QUIT, 0, 0); + if ( WaitForSingleObject( m_hThreadConsole, 5000 ) == WAIT_TIMEOUT) { + TerminateThread( m_hThreadConsole, 0 ); + } + CloseHandle( m_hThreadConsole ); + m_hThreadConsole = NULL; + } + + m_filterInfo.iq = m_filterInfo.msg = m_filterInfo.presence = FALSE; + m_filterInfo.type = TFilterInfo::T_OFF; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleConsole(WPARAM, LPARAM) +{ + if ( m_pDlgConsole ) + SetForegroundWindow( m_pDlgConsole->GetHwnd()); + else + if ( m_hThreadConsole ) + PostThreadMessage( m_dwConsoleThreadId, WM_CREATECONSOLE, 0, 0 ); + return 0; +} diff --git a/protocols/JabberG/src/jabber_db_utils.h b/protocols/JabberG/src/jabber_db_utils.h new file mode 100644 index 0000000000..ae9a6c9781 --- /dev/null +++ b/protocols/JabberG/src/jabber_db_utils.h @@ -0,0 +1,279 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __jabber_db_utils_h__ +#define __jabber_db_utils_h__ + +template<typename Int> struct CMIntTraits { static __forceinline bool IsSigned() { return false; } }; +template<> struct CMIntTraits<signed char> { static __forceinline bool IsSigned() { return true; } }; +template<> struct CMIntTraits<signed short> { static __forceinline bool IsSigned() { return true; } }; +template<> struct CMIntTraits<signed long> { static __forceinline bool IsSigned() { return true; } }; + +template<int Size> +struct CMDBTraits +{ +}; + +template<> +struct CMDBTraits<1> +{ + typedef BYTE DBType; + enum { DBTypeId = DBVT_BYTE }; + static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) + { + return DBGetContactSettingByte(NULL, szModule, szSetting, value); + } + static __forceinline void Set(char *szModule, char *szSetting, DBType value) + { + DBWriteContactSettingByte(NULL, szModule, szSetting, value); + } +}; + +template<> +struct CMDBTraits<2> +{ + typedef WORD DBType; + enum { DBTypeId = DBVT_WORD }; + static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) + { + return DBGetContactSettingWord(NULL, szModule, szSetting, value); + } + static __forceinline void Set(char *szModule, char *szSetting, DBType value) + { + DBWriteContactSettingWord(NULL, szModule, szSetting, value); + } +}; + +template<> +struct CMDBTraits<4> +{ + typedef DWORD DBType; + enum { DBTypeId = DBVT_DWORD }; + static __forceinline BYTE GetDBType() + { + return DBVT_DWORD; + } + static __forceinline DBType Get(char *szModule, char *szSetting, DBType value) + { + return DBGetContactSettingDword(NULL, szModule, szSetting, value); + } + static __forceinline void Set(char *szModule, char *szSetting, DBType value) + { + DBWriteContactSettingDword(NULL, szModule, szSetting, value); + } +}; + +class CMOptionBase +{ +public: + BYTE GetDBType() { return m_dbType; } + char *GetDBModuleName() { return m_proto->m_szModuleName; } + char *GetDBSettingName() { return m_szSetting; } + +protected: + CMOptionBase(PROTO_INTERFACE *proto, char *szSetting, BYTE dbType): m_proto(proto), m_szSetting(szSetting), m_dbType(dbType) {} + + PROTO_INTERFACE *m_proto; + char *m_szSetting; + BYTE m_dbType; + +private: + CMOptionBase(const CMOptionBase &) {} + void operator= (const CMOptionBase &) {} +}; + +template<class T> +class CMOption: public CMOptionBase +{ +public: + typedef T Type; + + __forceinline CMOption(PROTO_INTERFACE *proto, char *szSetting, Type defValue): + CMOptionBase(proto, szSetting, CMDBTraits<sizeof(T)>::DBTypeId), m_default(defValue) {} + + __forceinline operator Type() + { + return (Type)CMDBTraits<sizeof(Type)>::Get(m_proto->m_szModuleName, m_szSetting, m_default); + } + __forceinline Type operator= (Type value) + { + CMDBTraits<sizeof(Type)>::Set(m_proto->m_szModuleName, m_szSetting, (CMDBTraits<sizeof(Type)>::DBType)value); + return value; + } + +private: + Type m_default; + + CMOption(const CMOption &): CMOptionBase(NULL, NULL, DBVT_DELETED) {} + void operator= (const CMOption &) {} +}; + +template<> +class CMOption<CMString>: public CMOptionBase +{ +public: + typedef const TCHAR *Type; + + __forceinline CMOption(PROTO_INTERFACE *proto, char *szSetting, Type defValue, bool crypt=false): + CMOptionBase(proto, szSetting, DBVT_TCHAR), m_default(defValue), m_crypt(crypt) {} + + __forceinline operator CMString() + { + CMString result; + DBVARIANT dbv; + if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, m_szSetting, &dbv)) + { + result = dbv.ptszVal; + DBFreeVariant(&dbv); + } + return result; + } + __forceinline Type operator= (Type value) + { + DBWriteContactSettingTString(NULL, m_proto->m_szModuleName, m_szSetting, value); + return value; + } + +private: + Type m_default; + bool m_crypt; + + CMOption(const CMOption &): CMOptionBase(NULL, NULL, DBVT_DELETED) {} + void operator= (const CMOption &) {} +}; + +struct CJabberOptions +{ + CMOption<BYTE> AllowVersionRequests; + CMOption<BYTE> AcceptHttpAuth; + CMOption<BYTE> AddRoster2Bookmarks; + CMOption<BYTE> AutoAcceptAuthorization; + CMOption<BYTE> AutoAcceptMUC; + CMOption<BYTE> AutoAdd; + CMOption<BYTE> AutoJoinBookmarks; + CMOption<BYTE> AutoJoinConferences; + CMOption<BYTE> AutoJoinHidden; + CMOption<BYTE> AvatarType; + CMOption<BYTE> BsDirect; + CMOption<BYTE> BsDirectManual; + CMOption<BYTE> BsOnlyIBB; + CMOption<BYTE> BsProxyManual; + CMOption<BYTE> Disable3920auth; + CMOption<BYTE> DisableFrame; + CMOption<BYTE> EnableAvatars; + CMOption<BYTE> EnableRemoteControl; + CMOption<BYTE> EnableUserActivity; + CMOption<BYTE> EnableUserMood; + CMOption<BYTE> EnableUserTune; + CMOption<BYTE> EnableZlib; + CMOption<BYTE> ExtendedSearch; + CMOption<BYTE> FixIncorrectTimestamps; + CMOption<BYTE> GcLogAffiliations; + CMOption<BYTE> GcLogBans; + CMOption<BYTE> GcLogConfig; + CMOption<BYTE> GcLogRoles; + CMOption<BYTE> GcLogStatuses; + CMOption<BYTE> GcLogChatHistory; + CMOption<BYTE> HostNameAsResource; + CMOption<BYTE> IgnoreMUCInvites; + CMOption<BYTE> KeepAlive; + CMOption<BYTE> LogChatstates; + CMOption<BYTE> LogPresence; + CMOption<BYTE> LogPresenceErrors; + CMOption<BYTE> ManualConnect; + CMOption<BYTE> MsgAck; + CMOption<BYTE> RosterSync; + CMOption<BYTE> SavePassword; + CMOption<BYTE> UseDomainLogin; + CMOption<BYTE> ShowForeignResourceInMirVer; + CMOption<BYTE> ShowOSVersion; + CMOption<BYTE> ShowTransport; + CMOption<BYTE> UseSSL; + CMOption<BYTE> UseTLS; + CMOption<BYTE> AcceptNotes; + CMOption<BYTE> AutosaveNotes; + CMOption<BYTE> RcMarkMessagesAsRead; + CMOption<DWORD> ConnectionKeepAliveInterval; + CMOption<DWORD> ConnectionKeepAliveTimeout; + CMOption<BYTE> ProcessXMPPLinks; + CMOption<BYTE> IgnoreRosterGroups; + + CJabberOptions(PROTO_INTERFACE *proto): + BsDirect(proto, "BsDirect", TRUE), + AllowVersionRequests(proto, "AllowVersionRequests", TRUE), + AcceptHttpAuth(proto, "AcceptHttpAuth", TRUE), + AddRoster2Bookmarks(proto, "AddRoster2Bookmarks", TRUE), + AutoAcceptAuthorization(proto, "AutoAcceptAuthorization", FALSE), + AutoAcceptMUC(proto, "AutoAcceptMUC", FALSE), + AutoAdd(proto, "AutoAdd", TRUE), + AutoJoinBookmarks(proto, "AutoJoinBookmarks", TRUE), + AutoJoinConferences(proto, "AutoJoinConferences", 0), + AutoJoinHidden(proto, "AutoJoinHidden", TRUE), + AvatarType(proto, "AvatarType", PA_FORMAT_UNKNOWN), + BsDirectManual(proto, "BsDirectManual", FALSE), + BsOnlyIBB(proto, "BsOnlyIBB", FALSE), + BsProxyManual(proto, "BsProxyManual", FALSE), + Disable3920auth(proto, "Disable3920auth", FALSE), + DisableFrame(proto, "DisableFrame", TRUE), + EnableAvatars(proto, "EnableAvatars", TRUE), + EnableRemoteControl(proto, "EnableRemoteControl", FALSE), + EnableUserActivity(proto, "EnableUserActivity", TRUE), + EnableUserMood(proto, "EnableUserMood", TRUE), + EnableUserTune(proto, "EnableUserTune", FALSE), + EnableZlib(proto, "EnableZlib", TRUE), + ExtendedSearch(proto, "ExtendedSearch", TRUE), + FixIncorrectTimestamps(proto, "FixIncorrectTimestamps", TRUE), + GcLogAffiliations(proto, "GcLogAffiliations", FALSE), + GcLogBans(proto, "GcLogBans", TRUE), + GcLogConfig(proto, "GcLogConfig", FALSE), + GcLogRoles(proto, "GcLogRoles", FALSE), + GcLogStatuses(proto, "GcLogStatuses", FALSE), + GcLogChatHistory(proto, "GcLogChatHistory", FALSE), + HostNameAsResource(proto, "HostNameAsResource", FALSE), + IgnoreMUCInvites(proto, "IgnoreMUCInvites", FALSE), + KeepAlive(proto, "KeepAlive", TRUE), + LogChatstates(proto, "LogChatstates", FALSE), + LogPresence(proto, "LogPresence", TRUE), + LogPresenceErrors(proto, "LogPresenceErrors", FALSE), + ManualConnect(proto, "ManualConnect", FALSE), + MsgAck(proto, "MsgAck", FALSE), + RosterSync(proto, "RosterSync", FALSE), + SavePassword(proto, "SavePassword", TRUE), + ShowForeignResourceInMirVer(proto, "ShowForeignResourceInMirVer", FALSE), + ShowOSVersion(proto, "ShowOSVersion", TRUE), + ShowTransport(proto, "ShowTransport", TRUE), + UseSSL(proto, "UseSSL", FALSE), + UseTLS(proto, "UseTLS", TRUE), + UseDomainLogin(proto, "UseDomainLogin", FALSE), + AcceptNotes(proto, "AcceptNotes", TRUE), + AutosaveNotes(proto, "AutosaveNotes", FALSE), + RcMarkMessagesAsRead(proto, "RcMarkMessagesAsRead", 1), + ConnectionKeepAliveInterval(proto, "ConnectionKeepAliveInterval", 60000), + ConnectionKeepAliveTimeout(proto, "ConnectionKeepAliveTimeout", 50000), + ProcessXMPPLinks(proto, "ProcessXMPPLinks", FALSE), + IgnoreRosterGroups(proto, "IgnoreRosterGroups", FALSE) + {} +}; + +#endif // __jabber_db_utils_h__ diff --git a/protocols/JabberG/src/jabber_disco.cpp b/protocols/JabberG/src/jabber_disco.cpp new file mode 100644 index 0000000000..eadfd2d5d1 --- /dev/null +++ b/protocols/JabberG/src/jabber_disco.cpp @@ -0,0 +1,1529 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_disco.h" + +#define SD_FAKEJID_CONFERENCES "@@conferences" +#define SD_FAKEJID_MYAGENTS "@@my-transports" +#define SD_FAKEJID_AGENTS "@@transports" +#define SD_FAKEJID_FAVORITES "@@favorites" + +enum { + SD_BROWSE_NORMAL, + SD_BROWSE_MYAGENTS, + SD_BROWSE_AGENTS, + SD_BROWSE_CONFERENCES, + SD_BROWSE_FAVORITES +}; +static int sttBrowseMode = SD_BROWSE_NORMAL; + +#define REFRESH_TIMEOUT 500 +#define REFRESH_TIMER 1607 +static DWORD sttLastRefresh = 0; + +#define AUTODISCO_TIMEOUT 500 +#define AUTODISCO_TIMER 1608 +static DWORD sttLastAutoDisco = 0; + +enum { SD_OVERLAY_NONE, SD_OVERLAY_FAIL, SD_OVERLAY_PROGRESS, SD_OVERLAY_REGISTERED }; + +static struct +{ + TCHAR *feature; + TCHAR *category; + TCHAR *type; + char *iconName; + int iconIndex; + int listIndex; +} sttNodeIcons[] = +{ +// standard identities: http://www.xmpp.org/registrar/disco-categories.html#directory +// {NULL, _T("account"), _T("admin"), NULL, 0}, +// {NULL, _T("account"), _T("anonymous"), NULL, 0}, +// {NULL, _T("account"), _T("registered"), NULL, 0}, + {NULL, _T("account"), NULL, NULL, SKINICON_STATUS_ONLINE}, + +// {NULL, _T("auth"), _T("cert"), NULL, 0}, +// {NULL, _T("auth"), _T("generic"), NULL, 0}, +// {NULL, _T("auth"), _T("ldap"), NULL, 0}, +// {NULL, _T("auth"), _T("ntlm"), NULL, 0}, +// {NULL, _T("auth"), _T("pam"), NULL, 0}, +// {NULL, _T("auth"), _T("radius"), NULL, 0}, + {NULL, _T("auth"), NULL, "key", 0}, + +/// {NULL, _T("automation"), _T("command-list"), NULL, 0}, +/// {NULL, _T("automation"), _T("command-node"), NULL, 0}, +// {NULL, _T("automation"), _T("rpc"), NULL, 0}, +// {NULL, _T("automation"), _T("soap"), NULL, 0}, + {NULL, _T("automation"), NULL, "adhoc", 0}, + +// {NULL, _T("client"), _T("bot"), NULL, 0}, +// {NULL, _T("client"), _T("console"), NULL, 0}, +// {NULL, _T("client"), _T("handheld"), NULL, 0}, +// {NULL, _T("client"), _T("pc"), NULL, 0}, +// {NULL, _T("client"), _T("phone"), NULL, 0}, +// {NULL, _T("client"), _T("web"), NULL, 0}, + {NULL, _T("client"), NULL, NULL, SKINICON_STATUS_ONLINE}, + +// {NULL, _T("collaboration"), _T("whiteboard"), NULL, 0}, + {NULL, _T("collaboration"), NULL, "group", 0}, + +// {NULL, _T("component"), _T("archive"), NULL, 0}, +// {NULL, _T("component"), _T("c2s"), NULL, 0}, +// {NULL, _T("component"), _T("generic"), NULL, 0}, +// {NULL, _T("component"), _T("load"), NULL, 0}, +// {NULL, _T("component"), _T("log"), NULL, 0}, +// {NULL, _T("component"), _T("presence"), NULL, 0}, +// {NULL, _T("component"), _T("router"), NULL, 0}, +// {NULL, _T("component"), _T("s2s"), NULL, 0}, +// {NULL, _T("component"), _T("sm"), NULL, 0}, +// {NULL, _T("component"), _T("stats"), NULL, 0}, + +// {NULL, _T("conference"), _T("irc"), NULL, 0}, +// {NULL, _T("conference"), _T("text"), NULL, 0}, + {NULL, _T("conference"), NULL, "group", 0}, + + {NULL, _T("directory"), _T("chatroom"), "group", 0}, + {NULL, _T("directory"), _T("group"), "group", 0}, + {NULL, _T("directory"), _T("user"), NULL, SKINICON_OTHER_FINDUSER}, +// {NULL, _T("directory"), _T("waitinglist"), NULL, 0}, + {NULL, _T("directory"), NULL, NULL, SKINICON_OTHER_SEARCHALL}, + + {NULL, _T("gateway"), _T("aim"), "AIM", SKINICON_STATUS_ONLINE}, + {NULL, _T("gateway"), _T("gadu-gadu"), "GG", SKINICON_STATUS_ONLINE}, +// {NULL, _T("gateway"), _T("http-ws"), NUL, 0}, + {NULL, _T("gateway"), _T("icq"), "ICQ", SKINICON_STATUS_ONLINE}, + {NULL, _T("gateway"), _T("msn"), "MSN", SKINICON_STATUS_ONLINE}, + {NULL, _T("gateway"), _T("qq"), "QQ", SKINICON_STATUS_ONLINE}, +// {NULL, _T("gateway"), _T("sms"), NULL, 0}, +// {NULL, _T("gateway"), _T("smtp"), NULL, 0}, + {NULL, _T("gateway"), _T("tlen"), "TLEN", SKINICON_STATUS_ONLINE}, + {NULL, _T("gateway"), _T("yahoo"), "YAHOO", SKINICON_STATUS_ONLINE}, + {NULL, _T("gateway"), NULL, "Agents", 0}, + +// {NULL, _T("headline"), _T("newmail"), NULL, 0}, + {NULL, _T("headline"), _T("rss"), "node_rss", 0}, + {NULL, _T("headline"), _T("weather"), "node_weather", 0}, + +// {NULL, _T("hierarchy"), _T("branch"), NULL, 0}, +// {NULL, _T("hierarchy"), _T("leaf"), NULL, 0}, + +// {NULL, _T("proxy"), _T("bytestreams"), NULL, 0}, + {NULL, _T("proxy"), NULL, NULL, SKINICON_EVENT_FILE}, + +// {NULL, _T("pubsub"), _T("collection"), NULL, 0}, +// {NULL, _T("pubsub"), _T("leaf"), NULL, 0}, +// {NULL, _T("pubsub"), _T("pep"), NULL, 0}, +// {NULL, _T("pubsub"), _T("service"), NULL, 0}, + +// {NULL, _T("server"), _T("im"), NULL, 0}, + {NULL, _T("server"), NULL, "node_server", 0}, + +// {NULL, _T("store"), _T("berkeley"), NULL, 0}, +/// {NULL, _T("store"), _T("file"), NULL, 0}, +// {NULL, _T("store"), _T("generic"), NULL, 0}, +// {NULL, _T("store"), _T("ldap"), NULL, 0}, +// {NULL, _T("store"), _T("mysql"), NULL, 0}, +// {NULL, _T("store"), _T("oracle"), NULL, 0}, +// {NULL, _T("store"), _T("postgres"), NULL, 0}, + {NULL, _T("store"), NULL, "node_store", 0}, + +// icons for non-standard identities + {NULL, _T("x-service"), _T("x-rss"), "node_rss", 0}, + {NULL, _T("application"), _T("x-weather"), "node_weather", 0}, + {NULL, _T("user"), NULL, NULL, SKINICON_STATUS_ONLINE}, + +// icon suggestions based on supported features + {_T("jabber:iq:gateway"), NULL,NULL, "Agents", 0}, + {_T("jabber:iq:search"), NULL,NULL, NULL, SKINICON_OTHER_FINDUSER}, + {_T(JABBER_FEAT_COMMANDS), NULL,NULL, "adhoc", 0}, + {_T(JABBER_FEAT_REGISTER), NULL,NULL, "key", 0}, +}; + +static void sttApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode); + +void CJabberProto::OnIqResultServiceDiscoveryInfo( HXML iqNode, CJabberIqInfo* pInfo ) +{ + m_SDManager.Lock(); + CJabberSDNode* pNode = m_SDManager.FindByIqId( pInfo->GetIqId(), TRUE ); + if ( !pNode ) { + m_SDManager.Unlock(); + return; + } + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML query = xmlGetChild( iqNode , "query" ); + if ( !query ) + pNode->SetInfoRequestId( JABBER_DISCO_RESULT_ERROR ); + else { + HXML feature; + int i; + for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) + pNode->AddFeature( xmlGetAttrValue( feature, _T("var"))); + HXML identity; + for ( i = 1; ( identity = xmlGetNthChild( query, _T("identity"), i )) != NULL; i++ ) + pNode->AddIdentity( xmlGetAttrValue( identity, _T("category")), xmlGetAttrValue( identity, _T("type")), xmlGetAttrValue( identity, _T("name"))); + + pNode->SetInfoRequestId( JABBER_DISCO_RESULT_OK ); + pNode->SetInfoRequestErrorText( NULL ); + } + } + else { + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + pNode->SetInfoRequestErrorText( str ); + mir_free( str ); + } + else pNode->SetInfoRequestErrorText( TranslateT("request timeout.")); + + pNode->SetInfoRequestId( JABBER_DISCO_RESULT_ERROR ); + } + + m_SDManager.Unlock(); + + if ( m_pDlgServiceDiscovery ) { + ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); + PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); + } +} + +void CJabberProto::OnIqResultServiceDiscoveryItems( HXML iqNode, CJabberIqInfo* pInfo ) +{ + m_SDManager.Lock(); + CJabberSDNode* pNode = m_SDManager.FindByIqId( pInfo->GetIqId(), FALSE ); + if ( !pNode ) { + m_SDManager.Unlock(); + return; + } + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML query = xmlGetChild( iqNode , "query" ); + if ( !query ) + pNode->SetItemsRequestId( JABBER_DISCO_RESULT_ERROR ); + else { + HXML item; + for ( int i = 1; ( item = xmlGetNthChild( query, _T("item"), i )) != NULL; i++ ) { + pNode->AddChildNode( xmlGetAttrValue( item, _T("jid")), xmlGetAttrValue( item, _T("node")), xmlGetAttrValue( item, _T("name"))); + } + + pNode->SetItemsRequestId( JABBER_DISCO_RESULT_OK ); + pNode->SetItemsRequestErrorText( NULL ); + } + } + else { + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + pNode->SetItemsRequestErrorText( str ); + mir_free( str ); + } + else { + pNode->SetItemsRequestErrorText( _T("request timeout.")); + } + pNode->SetItemsRequestId( JABBER_DISCO_RESULT_ERROR ); + } + + m_SDManager.Unlock(); + + if ( m_pDlgServiceDiscovery ) { + ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); + PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); + } +} + +void CJabberProto::OnIqResultServiceDiscoveryRootInfo( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if (!pInfo->m_pUserData) return; + m_SDManager.Lock(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML query = xmlGetChild( iqNode , "query" ); + if ( query ) { + HXML feature; + int i; + for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { + if ( !lstrcmp( xmlGetAttrValue( feature, _T("var")), (TCHAR *)pInfo->m_pUserData)) { + CJabberSDNode *pNode = m_SDManager.AddPrimaryNode( pInfo->GetReceiver(), xmlGetAttrValue( iqNode, _T("node")), NULL); + SendBothRequests( pNode, NULL ); + break; + } } } } + m_SDManager.Unlock(); + + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_REFRESH); +} + +void CJabberProto::OnIqResultServiceDiscoveryRootItems( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if (!pInfo->m_pUserData) + return; + + XmlNode packet( NULL ); + m_SDManager.Lock(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML query = xmlGetChild( iqNode , "query" ); + if ( query ) { + HXML item; + for ( int i = 1; ( item = xmlGetNthChild( query, _T("item"), i )) != NULL; i++ ) { + const TCHAR *szJid = xmlGetAttrValue( item, _T("jid")); + const TCHAR *szNode = xmlGetAttrValue( item, _T("node")); + CJabberIqInfo* pNewInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootInfo, JABBER_IQ_TYPE_GET, szJid ); + pNewInfo->m_pUserData = pInfo->m_pUserData; + pNewInfo->SetTimeout( 30000 ); + + XmlNodeIq iq( pNewInfo ); + iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), szNode ); + xmlAddChild( packet, iq ); + } } } + m_SDManager.Unlock(); + + if ( xmlGetChild( packet ,0)) + m_ThreadInfo->send( packet ); +} + +BOOL CJabberProto::SendInfoRequest(CJabberSDNode* pNode, HXML parent) +{ + if ( !pNode || !m_bJabberOnline ) + return FALSE; + + // disco#info + if ( !pNode->GetInfoRequestId()) { + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryInfo, JABBER_IQ_TYPE_GET, pNode->GetJid()); + pInfo->SetTimeout( 30000 ); + pNode->SetInfoRequestId( pInfo->GetIqId()); + + XmlNodeIq iq( pInfo ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); + if ( pNode->GetNode()) + xmlAddAttr( query, _T("node"), pNode->GetNode()); + + if ( parent ) + xmlAddChild( parent, iq ); + else + m_ThreadInfo->send( iq ); + } + + if ( m_pDlgServiceDiscovery ) { + ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); + PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); + } + + return TRUE; +} + +BOOL CJabberProto::SendBothRequests(CJabberSDNode* pNode, HXML parent) +{ + if ( !pNode || !m_bJabberOnline ) + return FALSE; + + // disco#info + if ( !pNode->GetInfoRequestId()) { + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryInfo, JABBER_IQ_TYPE_GET, pNode->GetJid()); + pInfo->SetTimeout( 30000 ); + pNode->SetInfoRequestId( pInfo->GetIqId()); + + XmlNodeIq iq( pInfo ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)); + if ( pNode->GetNode()) + xmlAddAttr( query, _T("node"), pNode->GetNode()); + + if ( parent ) + xmlAddChild( parent, iq ); + else + m_ThreadInfo->send( iq ); + } + + // disco#items + if ( !pNode->GetItemsRequestId()) { + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryItems, JABBER_IQ_TYPE_GET, pNode->GetJid()); + pInfo->SetTimeout( 30000 ); + pNode->SetItemsRequestId( pInfo->GetIqId()); + + XmlNodeIq iq( pInfo ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); + if ( pNode->GetNode()) + xmlAddAttr( query, _T("node"), pNode->GetNode()); + + if ( parent ) + xmlAddChild( parent, iq ); + else + m_ThreadInfo->send( iq ); + } + + if ( m_pDlgServiceDiscovery ) { + ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); + PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_JABBER_REFRESH, 0, 0 ); + } + + return TRUE; +} + +void CJabberProto::PerformBrowse(HWND hwndDlg) +{ + TCHAR szJid[ JABBER_MAX_JID_LEN ]; + TCHAR szNode[ 512 ]; + if ( !GetDlgItemText( hwndDlg, IDC_COMBO_JID, szJid, SIZEOF( szJid ))) + szJid[ 0 ] = 0; + if ( !GetDlgItemText( hwndDlg, IDC_COMBO_NODE, szNode, SIZEOF( szNode ))) + szNode[ 0 ] = 0; + + ComboAddRecentString(hwndDlg, IDC_COMBO_JID, "discoWnd_rcJid", szJid); + ComboAddRecentString(hwndDlg, IDC_COMBO_NODE, "discoWnd_rcNode", szNode); + + if ( _tcslen( szJid )) { + HWND hwndList = GetDlgItem(hwndDlg, IDC_TREE_DISCO); + TreeList_Reset(hwndList); + + m_SDManager.Lock(); + m_SDManager.RemoveAll(); + if (!lstrcmp(szJid, _T(SD_FAKEJID_MYAGENTS))) { + sttBrowseMode = SD_BROWSE_MYAGENTS; + JABBER_LIST_ITEM *item = NULL; + LISTFOREACH(i, this, LIST_ROSTER) + { + if (( item=ListGetItemPtrFromIndex( i )) != NULL ) { + if ( _tcschr( item->jid, '@' )==NULL && _tcschr( item->jid, '/' )==NULL && item->subscription!=SUB_NONE ) { + HANDLE hContact = HContactFromJID( item->jid ); + if ( hContact != NULL ) + JSetByte( hContact, "IsTransport", TRUE ); + + if ( m_lstTransports.getIndex( item->jid ) == -1 ) + m_lstTransports.insert( mir_tstrdup( item->jid )); + + CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(item->jid, NULL, NULL); + SendBothRequests( pNode, NULL ); + } } + } } + else if (!lstrcmp(szJid, _T(SD_FAKEJID_CONFERENCES))) { + sttBrowseMode = SD_BROWSE_CONFERENCES; + TCHAR *szServerJid = mir_a2t(m_ThreadInfo->server); + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootItems, JABBER_IQ_TYPE_GET, szServerJid ); + pInfo->m_pUserData = (void *)_T(JABBER_FEAT_MUC); + pInfo->SetTimeout( 30000 ); + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); + m_ThreadInfo->send( iq ); + mir_free(szServerJid); + } + else if (!lstrcmp(szJid, _T(SD_FAKEJID_AGENTS))) { + sttBrowseMode = SD_BROWSE_AGENTS; + TCHAR *szServerJid = mir_a2t(m_ThreadInfo->server); + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultServiceDiscoveryRootItems, JABBER_IQ_TYPE_GET, szServerJid ); + pInfo->m_pUserData = (void *)_T("jabber:iq:gateway"); + pInfo->SetTimeout( 30000 ); + XmlNodeIq iq( pInfo ); + iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); + m_ThreadInfo->send( iq ); + mir_free(szServerJid); + } + else if (!lstrcmp(szJid, _T(SD_FAKEJID_FAVORITES))) { + sttBrowseMode = SD_BROWSE_FAVORITES; + int count = JGetDword(NULL, "discoWnd_favCount", 0); + for (int i = 0; i < count; ++i) + { + DBVARIANT dbv; + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); + if (!JGetStringT(NULL, setting, &dbv)) { + DBVARIANT dbvJid, dbvNode; + mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", i); + JGetStringT(NULL, setting, &dbvJid); + mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", i); + JGetStringT(NULL, setting, &dbvNode); + CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(dbvJid.ptszVal, dbvNode.ptszVal, dbv.ptszVal); + SendBothRequests( pNode, NULL ); + JFreeVariant(&dbv); + JFreeVariant(&dbvJid); + JFreeVariant(&dbvNode); + } } } + else { + sttBrowseMode = SD_BROWSE_NORMAL; + CJabberSDNode* pNode = m_SDManager.AddPrimaryNode(szJid, _tcslen( szNode ) ? szNode : NULL, NULL); + SendBothRequests( pNode, NULL ); + } + m_SDManager.Unlock(); + + PostMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 ); + } +} + +BOOL CJabberProto::IsNodeRegistered(CJabberSDNode *pNode) +{ + if (pNode->GetNode()) + return FALSE; + + JABBER_LIST_ITEM *item; + if (item = ListGetItemPtr(LIST_ROSTER, pNode->GetJid())) + return (item->subscription != SUB_NONE) ? TRUE : FALSE; + + if (item = ListGetItemPtr(LIST_BOOKMARK, pNode->GetJid())) + return TRUE; + + return FALSE; +} + +void CJabberProto::ApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode) +{ + if (!hItem || !pNode) return; + + int iIcon = -1, iOverlay = -1; + + if ((pNode->GetInfoRequestId() > 0) || (pNode->GetItemsRequestId() > 0)) + iOverlay = SD_OVERLAY_PROGRESS; + else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_ERROR) + iOverlay = SD_OVERLAY_FAIL; + else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_NOT_REQUESTED) { + if (IsNodeRegistered(pNode)) + iOverlay = SD_OVERLAY_REGISTERED; + else + iOverlay = SD_OVERLAY_NONE; + } else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_OK) { + if (IsNodeRegistered(pNode)) + iOverlay = SD_OVERLAY_REGISTERED; + else if (pNode->GetInfoRequestId() == JABBER_DISCO_RESULT_ERROR) + iOverlay = SD_OVERLAY_FAIL; + else + iOverlay = SD_OVERLAY_NONE; + } + + for (int i = 0; i < SIZEOF(sttNodeIcons); ++i) + { + if (!sttNodeIcons[i].iconIndex && !sttNodeIcons[i].iconName) continue; + + if (sttNodeIcons[i].category) + { + CJabberSDIdentity *iIdentity; + for (iIdentity = pNode->GetFirstIdentity(); iIdentity; iIdentity = iIdentity->GetNext()) + if (!lstrcmp(iIdentity->GetCategory(), sttNodeIcons[i].category) && + (!sttNodeIcons[i].type || !lstrcmp(iIdentity->GetType(), sttNodeIcons[i].type))) + { + iIcon = sttNodeIcons[i].listIndex; + break; + } + if (iIdentity) break; + } + + if (sttNodeIcons[i].feature) + { + CJabberSDFeature *iFeature; + for (iFeature = pNode->GetFirstFeature(); iFeature; iFeature = iFeature->GetNext()) + if (!lstrcmp(iFeature->GetVar(), sttNodeIcons[i].feature)) + { + iIcon = sttNodeIcons[i].listIndex; + break; + } + if (iFeature) break; + } + } + + TreeList_SetIcon(pNode->GetTreeItemHandle(), iIcon, iOverlay); +} + +BOOL CJabberProto::SyncTree(HTREELISTITEM hIndex, CJabberSDNode* pNode) +{ + if (!m_pDlgServiceDiscovery) return FALSE; + + CJabberSDNode* pTmp = pNode; + while (pTmp) { + if ( !pTmp->GetTreeItemHandle()) { + HTREELISTITEM hNewItem = TreeList_AddItem( + GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hIndex, + pTmp->GetName() ? pTmp->GetName() : pTmp->GetJid(), + (LPARAM)pTmp); + TreeList_AppendColumn(hNewItem, pTmp->GetJid()); + TreeList_AppendColumn(hNewItem, pTmp->GetNode()); + if (!pTmp->GetInfoRequestId()) + TreeList_MakeFakeParent(hNewItem, TRUE); + else + TreeList_MakeFakeParent(hNewItem, FALSE); + pTmp->SetTreeItemHandle( hNewItem ); + } + + ApplyNodeIcon(pNode->GetTreeItemHandle(), pNode); + + if ( pTmp->GetFirstChildNode()) + SyncTree( pTmp->GetTreeItemHandle(), pTmp->GetFirstChildNode()); + + pTmp = pTmp->GetNext(); + } + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// CJabberDlgDiscovery +class CJabberDlgDiscovery: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgDiscovery(CJabberProto *proto, TCHAR *jid); + +protected: + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + int Resizer(UTILRESIZECONTROL *urc); + +private: + TCHAR *m_jid; + bool m_focusEditAfterBrowse; + + CCtrlMButton m_btnViewAsTree; + CCtrlMButton m_btnViewAsList; + CCtrlMButton m_btnGoHome; + CCtrlMButton m_btnBookmarks; + CCtrlMButton m_btnRefresh; + CCtrlMButton m_btnBrowse; + CCtrlFilterListView m_lstDiscoTree; + + void btnViewAsTree_OnClick(CCtrlButton *); + void btnViewAsList_OnClick(CCtrlButton *); + void btnGoHome_OnClick(CCtrlButton *); + void btnBookmarks_OnClick(CCtrlButton *); + void btnRefresh_OnClick(CCtrlButton *); + void btnBrowse_OnClick(CCtrlButton *); + void lstDiscoTree_OnFilter(CCtrlFilterListView *); +}; + +CJabberDlgDiscovery::CJabberDlgDiscovery(CJabberProto *proto, TCHAR *jid) : + CJabberDlgBase(proto, IDD_SERVICE_DISCOVERY, NULL), + m_jid(jid), + m_btnViewAsTree(this, IDC_BTN_VIEWTREE, proto->LoadIconEx("sd_view_tree"), "View as tree"), + m_btnViewAsList(this, IDC_BTN_VIEWLIST, proto->LoadIconEx("sd_view_list"), "View as list"), + m_btnGoHome(this, IDC_BTN_NAVHOME, proto->LoadIconEx("sd_nav_home"), "Navigate home"), + m_btnBookmarks(this, IDC_BTN_FAVORITE, proto->LoadIconEx("bookmarks"), "Favorites"), + m_btnRefresh(this, IDC_BTN_REFRESH, proto->LoadIconEx("sd_nav_refresh"), "Refresh node"), + m_btnBrowse(this, IDC_BUTTON_BROWSE, proto->LoadIconEx("sd_browse"), "Browse"), + m_lstDiscoTree(this, IDC_TREE_DISCO, true, false) +{ + m_btnViewAsTree.OnClick = Callback(this, &CJabberDlgDiscovery::btnViewAsTree_OnClick); + m_btnViewAsList.OnClick = Callback(this, &CJabberDlgDiscovery::btnViewAsList_OnClick); + m_btnGoHome.OnClick = Callback(this, &CJabberDlgDiscovery::btnGoHome_OnClick); + m_btnBookmarks.OnClick = Callback(this, &CJabberDlgDiscovery::btnBookmarks_OnClick); + m_btnRefresh.OnClick = Callback(this, &CJabberDlgDiscovery::btnRefresh_OnClick); + m_btnBrowse.OnClick = Callback(this, &CJabberDlgDiscovery::btnBrowse_OnClick); + m_lstDiscoTree.OnFilterChanged = Callback(this, &CJabberDlgDiscovery::lstDiscoTree_OnFilter); +} + +void CJabberDlgDiscovery::OnInitDialog() +{ + CSuper::OnInitDialog(); + +// TranslateDialogDefault( m_hwnd ); + WindowSetIcon( m_hwnd, m_proto, "servicediscovery" ); + + int i; + + if ( m_jid ) { + SetDlgItemText( m_hwnd, IDC_COMBO_JID, m_jid ); + SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); + m_focusEditAfterBrowse = false; + } else { + SetDlgItemTextA( m_hwnd, IDC_COMBO_JID, m_proto->m_ThreadInfo->server ); + SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); + m_focusEditAfterBrowse = true; + } + + m_btnViewAsList.MakePush(); + m_btnViewAsTree.MakePush(); + m_btnBookmarks.MakePush(); + + CheckDlgButton(m_hwnd, + DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", 1) ? + IDC_BTN_VIEWTREE : IDC_BTN_VIEWLIST, + TRUE); + + EnableWindow(GetDlgItem(m_hwnd, IDC_BTN_FILTERRESET), FALSE); + + SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_CONFERENCES)); + SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_MYAGENTS)); + SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_AGENTS)); + SendDlgItemMessage(m_hwnd, IDC_COMBO_JID, CB_ADDSTRING, 0, (LPARAM)_T(SD_FAKEJID_FAVORITES)); + m_proto->ComboLoadRecentStrings(m_hwnd, IDC_COMBO_JID, "discoWnd_rcJid"); + m_proto->ComboLoadRecentStrings(m_hwnd, IDC_COMBO_NODE, "discoWnd_rcNode"); + + HWND hwndList = m_lstDiscoTree.GetHwnd();//GetDlgItem(m_hwnd, IDC_TREE_DISCO); + LVCOLUMN lvc = {0}; + lvc.mask = LVCF_SUBITEM|LVCF_WIDTH|LVCF_TEXT; + lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx0", 200); + lvc.iSubItem = 0; + lvc.pszText = TranslateT("Node hierarchy"); + ListView_InsertColumn(hwndList, 0, &lvc); + lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx1", 200); + lvc.iSubItem = 1; + lvc.pszText = _T("JID"); + ListView_InsertColumn(hwndList, 1, &lvc); + lvc.cx = DBGetContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx2", 200); + lvc.iSubItem = 2; + lvc.pszText = TranslateT("Node"); + ListView_InsertColumn(hwndList, 2, &lvc); + + TreeList_Create(hwndList); + TreeList_AddIcon(hwndList, m_proto->LoadIconEx("main"), 0); + for (i = 0; i < SIZEOF(sttNodeIcons); ++i) + { + bool needDestroy = false; + HICON hIcon; + if ((sttNodeIcons[i].iconIndex == SKINICON_STATUS_ONLINE) && sttNodeIcons[i].iconName) { + hIcon = (HICON)CallProtoService(sttNodeIcons[i].iconName, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); + needDestroy = true; + } + else if (sttNodeIcons[i].iconName) + hIcon = m_proto->LoadIconEx(sttNodeIcons[i].iconName); + else if (sttNodeIcons[i].iconIndex) + hIcon = LoadSkinnedIcon(sttNodeIcons[i].iconIndex); + else continue; + sttNodeIcons[i].listIndex = TreeList_AddIcon(hwndList, hIcon, 0); + if (needDestroy) DestroyIcon(hIcon); + } + TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_fail"), SD_OVERLAY_FAIL); + TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_progress"), SD_OVERLAY_PROGRESS); + TreeList_AddIcon(hwndList, m_proto->LoadIconEx("disco_ok"), SD_OVERLAY_REGISTERED); + + TreeList_SetMode(hwndList, DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", 1) ? TLM_TREE : TLM_REPORT); + + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "discoWnd_"); +} + +void CJabberDlgDiscovery::OnClose() +{ + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "discoWnd_useTree", IsDlgButtonChecked(m_hwnd, IDC_BTN_VIEWTREE)); + + HWND hwndList = GetDlgItem(m_hwnd, IDC_TREE_DISCO); + LVCOLUMN lvc = {0}; + lvc.mask = LVCF_WIDTH; + ListView_GetColumn(hwndList, 0, &lvc); + DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx0", lvc.cx); + ListView_GetColumn(hwndList, 1, &lvc); + DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx1", lvc.cx); + ListView_GetColumn(hwndList, 2, &lvc); + DBWriteContactSettingWord(NULL, m_proto->m_szModuleName, "discoWnd_cx2", lvc.cx); + + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "discoWnd_"); + DestroyWindow( m_hwnd ); + + CSuper::OnClose(); +} + +void CJabberDlgDiscovery::OnDestroy() +{ + m_proto->m_pDlgServiceDiscovery = NULL; + m_proto->m_SDManager.Lock(); + m_proto->m_SDManager.RemoveAll(); + m_proto->m_SDManager.Unlock(); + TreeList_Destroy(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); + + CSuper::OnDestroy(); +} + +int CJabberDlgDiscovery::Resizer(UTILRESIZECONTROL *urc) +{ + RECT rc; + + switch ( urc->wId ) { + case IDC_COMBO_JID: + { + GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); + urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; + urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; + return 0; + } + case IDC_TXT_NODELABEL: + { + urc->rcItem.left += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; + urc->rcItem.right += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; + return 0; + } + case IDC_COMBO_NODE: + { + GetWindowRect(GetDlgItem(m_hwnd, urc->wId), &rc); + urc->rcItem.left += (urc->dlgNewSize.cx - urc->dlgOriginalSize.cx) / 2; + urc->rcItem.right += urc->dlgNewSize.cx - urc->dlgOriginalSize.cx; + urc->rcItem.bottom = urc->rcItem.top + rc.bottom - rc.top; + return 0; + } + case IDC_BUTTON_BROWSE: + return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP; + + case IDC_TREE_DISCO: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + + case IDC_TXT_FILTER: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + case IDC_TXT_FILTERTEXT: + return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; + case IDC_BTN_FILTERAPPLY: + case IDC_BTN_FILTERRESET: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + return CSuper::Resizer(urc); +} + +void CJabberDlgDiscovery::btnViewAsTree_OnClick(CCtrlButton *) +{ + CheckDlgButton(m_hwnd, IDC_BTN_VIEWLIST, FALSE); + CheckDlgButton(m_hwnd, IDC_BTN_VIEWTREE, TRUE); + TreeList_SetMode(GetDlgItem(m_hwnd, IDC_TREE_DISCO), TLM_TREE); +} + +void CJabberDlgDiscovery::btnViewAsList_OnClick(CCtrlButton *) +{ + CheckDlgButton(m_hwnd, IDC_BTN_VIEWLIST, TRUE); + CheckDlgButton(m_hwnd, IDC_BTN_VIEWTREE, FALSE); + TreeList_SetMode(GetDlgItem(m_hwnd, IDC_TREE_DISCO), TLM_REPORT); +} + +void CJabberDlgDiscovery::btnGoHome_OnClick(CCtrlButton *) +{ + SetDlgItemTextA( m_hwnd, IDC_COMBO_JID, m_proto->m_ThreadInfo->server ); + SetDlgItemText( m_hwnd, IDC_COMBO_NODE, _T("")); + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); +} + +void CJabberDlgDiscovery::btnBookmarks_OnClick(CCtrlButton *) +{ + HMENU hMenu = CreatePopupMenu(); + int count = m_proto->JGetDword(NULL, "discoWnd_favCount", 0); + for (int i = 0; i < count; ++i) + { + DBVARIANT dbv; + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); + if (!m_proto->JGetStringT(NULL, setting, &dbv)) + { + HMENU hSubMenu = CreatePopupMenu(); + AppendMenu(hSubMenu, MF_STRING, 100+i*10+0, TranslateT("Navigate")); + AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hSubMenu, MF_STRING, 100+i*10+1, TranslateT("Remove")); + AppendMenu(hMenu, MF_POPUP|MF_STRING, (UINT_PTR)hSubMenu, dbv.ptszVal); + } + JFreeVariant(&dbv); + } + int res = 0; + if (GetMenuItemCount(hMenu)) { + AppendMenu(hMenu, MF_SEPARATOR, 1, NULL); + AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_FAVORITES, TranslateT("Browse all favorites")); + AppendMenu(hMenu, MF_STRING, 1, TranslateT("Remove all favorites")); + } + if (GetMenuItemCount(hMenu)) + AppendMenu(hMenu, MF_SEPARATOR, 1, NULL); + + AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_MYAGENTS, TranslateT("Registered transports")); + AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_AGENTS, TranslateT("Browse local transports")); + AppendMenu(hMenu, MF_STRING, 10+SD_BROWSE_CONFERENCES, TranslateT("Browse chatrooms")); + + RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BTN_FAVORITE), &rc); + CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, TRUE); + res = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, NULL); + CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, FALSE); + DestroyMenu(hMenu); + + if (res >= 100) + { + res -= 100; + if (res % 10) + { + res /= 10; + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", res); + m_proto->JDeleteSetting(NULL, setting); + mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", res); + m_proto->JDeleteSetting(NULL, setting); + mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", res); + m_proto->JDeleteSetting(NULL, setting); + } else + { + res /= 10; + + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T("")); + SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); + + DBVARIANT dbv; + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", res); + if (!m_proto->JGetStringT(NULL, setting, &dbv)) SetDlgItemText(m_hwnd, IDC_COMBO_JID, dbv.ptszVal); + JFreeVariant(&dbv); + mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", res); + if (!m_proto->JGetStringT(NULL, setting, &dbv)) SetDlgItemText(m_hwnd, IDC_COMBO_NODE, dbv.ptszVal); + JFreeVariant(&dbv); + + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + } + } else + if (res == 1) + { + int count = m_proto->JGetDword(NULL, "discoWnd_favCount", 0); + for (int i = 0; i < count; ++i) + { + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", i); + m_proto->JDeleteSetting(NULL, setting); + mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", i); + m_proto->JDeleteSetting(NULL, setting); + mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", i); + m_proto->JDeleteSetting(NULL, setting); + } + m_proto->JDeleteSetting(NULL, "discoWnd_favCount"); + } else + if ((res >= 10) && (res <= 20)) + { + switch (res-10) { + case SD_BROWSE_FAVORITES: + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_FAVORITES)); + break; + case SD_BROWSE_MYAGENTS: + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_MYAGENTS)); + break; + case SD_BROWSE_AGENTS: + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_AGENTS)); + break; + case SD_BROWSE_CONFERENCES: + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_CONFERENCES)); + break; + } + SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + } + + CheckDlgButton(m_hwnd, IDC_BTN_FAVORITE, FALSE); +} + +void CJabberDlgDiscovery::btnRefresh_OnClick(CCtrlButton *) +{ + HTREELISTITEM hItem = (HTREELISTITEM)TreeList_GetActiveItem(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); + if (!hItem) return; + + m_proto->m_SDManager.Lock(); + XmlNode packet( NULL ); + CJabberSDNode* pNode = (CJabberSDNode* )TreeList_GetData(hItem); + if ( pNode ) { + TreeList_ResetItem(GetDlgItem(m_hwnd, IDC_TREE_DISCO), hItem); + pNode->ResetInfo(); + m_proto->SendBothRequests( pNode, packet ); + TreeList_MakeFakeParent(hItem, FALSE); + } + m_proto->m_SDManager.Unlock(); + + if ( xmlGetChild( packet ,0)) + m_proto->m_ThreadInfo->send( packet ); +} + +void CJabberDlgDiscovery::btnBrowse_OnClick(CCtrlButton *) +{ + SetFocus(GetDlgItem(m_hwnd, m_focusEditAfterBrowse ? IDC_COMBO_JID : IDC_TREE_DISCO)); + m_focusEditAfterBrowse = false; + + m_proto->PerformBrowse(m_hwnd); +} + +void CJabberDlgDiscovery::lstDiscoTree_OnFilter(CCtrlFilterListView *) +{ + TreeList_SetFilter(GetDlgItem(m_hwnd, IDC_TREE_DISCO), m_lstDiscoTree.GetFilterText()); +} + +INT_PTR CJabberDlgDiscovery::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + BOOL result; + if (TreeList_ProcessMessage(m_hwnd, msg, wParam, lParam, IDC_TREE_DISCO, &result)) + return result; + + switch ( msg ) { + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 538; + lpmmi->ptMinTrackSize.y = 374; + return 0; + } + + case WM_JABBER_TRANSPORT_REFRESH: + if (m_proto->m_nSDBrowseMode == SD_BROWSE_MYAGENTS) { + SetDlgItemText(m_hwnd, IDC_COMBO_JID, _T(SD_FAKEJID_MYAGENTS)); + SetDlgItemText(m_hwnd, IDC_COMBO_NODE, _T("")); + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + } + break; + + case WM_JABBER_REFRESH: + KillTimer(m_hwnd, REFRESH_TIMER); + if (GetTickCount() - m_proto->m_dwSDLastRefresh < REFRESH_TIMEOUT) { + SetTimer(m_hwnd, REFRESH_TIMER, REFRESH_TIMEOUT, NULL); + return TRUE; + } + + wParam = REFRESH_TIMER; + // fall through + + case WM_TIMER: + if (wParam == REFRESH_TIMER) { + m_proto->m_SDManager.Lock(); + + CJabberSDNode* pNode = m_proto->m_SDManager.GetPrimaryNode(); + while (pNode) + { + if ( pNode->GetJid()) { + if ( !pNode->GetTreeItemHandle()) { + HTREELISTITEM hNewItem = TreeList_AddItem( + GetDlgItem( m_hwnd, IDC_TREE_DISCO), NULL, + pNode->GetName() ? pNode->GetName() : pNode->GetJid(), + (LPARAM)pNode); + TreeList_AppendColumn(hNewItem, pNode->GetJid()); + TreeList_AppendColumn(hNewItem, pNode->GetNode()); + pNode->SetTreeItemHandle( hNewItem ); + } } + m_proto->SyncTree( NULL, pNode ); + pNode = pNode->GetNext(); + } + m_proto->m_SDManager.Unlock(); + TreeList_Update(GetDlgItem(m_hwnd, IDC_TREE_DISCO)); + KillTimer(m_hwnd, REFRESH_TIMER); + m_proto->m_dwSDLastRefresh = GetTickCount(); + return TRUE; + } + else if (wParam == AUTODISCO_TIMER) { + HWND hwndList = GetDlgItem(m_hwnd, IDC_TREE_DISCO); + RECT rcCtl; GetClientRect(hwndList, &rcCtl); + RECT rcHdr; GetClientRect(ListView_GetHeader(hwndList), &rcHdr); + LVHITTESTINFO lvhti = {0}; + lvhti.pt.x = rcCtl.left + 5; + lvhti.pt.y = rcHdr.bottom + 5; + int iFirst = ListView_HitTest(hwndList, &lvhti); + ZeroMemory(&lvhti, sizeof(lvhti)); + lvhti.pt.x = rcCtl.left + 5; + lvhti.pt.y = rcCtl.bottom - 5; + int iLast = ListView_HitTest(hwndList, &lvhti); + if (iFirst < 0) return FALSE; + if (iLast < 0) iLast = ListView_GetItemCount(hwndList) - 1; + + m_proto->m_SDManager.Lock(); + XmlNode packet( NULL ); + for (int i = iFirst; i <= iLast; ++i) + { + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = i; + ListView_GetItem(hwndList, &lvi); + if (!lvi.lParam) + continue; + + CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData((HTREELISTITEM)lvi.lParam); + if (!pNode || pNode->GetInfoRequestId()) + continue; + + m_proto->SendInfoRequest(pNode, packet); + } + m_proto->m_SDManager.Unlock(); + if ( xmlGetChild( packet, 0)) + m_proto->m_ThreadInfo->send( packet ); + + KillTimer(m_hwnd, AUTODISCO_TIMER); + m_proto->m_dwSDLastRefresh = GetTickCount(); + return TRUE; + } + break; + + case WM_CONTEXTMENU: + if (GetWindowLongPtr((HWND)wParam, GWL_ID) == IDC_TREE_DISCO) + { + HWND hwndList = (HWND)wParam; + POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; + + if (( pt.x == -1 ) && ( pt.y == -1 )) { + LVITEM lvi = {0}; + lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); + if (lvi.iItem < 0) return FALSE; + + RECT rc; + ListView_GetItemRect(hwndList, lvi.iItem, &rc, LVIR_LABEL); + pt.x = rc.left; + pt.y = rc.bottom; + ClientToScreen(hwndList, &pt); + } + + HTREELISTITEM hItem = TreeList_GetActiveItem(hwndList); + if (!hItem) break; + CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData(hItem); + if (!pNode) break; + + m_proto->ServiceDiscoveryShowMenu(pNode, hItem, pt); + } + break; + + case WM_NOTIFY: + if ( wParam == IDC_TREE_DISCO ) { + NMHDR* pHeader = (NMHDR* )lParam; + if ( pHeader->code == LVN_GETINFOTIP ) { + NMLVGETINFOTIP *pInfoTip = (NMLVGETINFOTIP *)lParam; + LVITEM lvi; + lvi.mask = LVIF_PARAM; + lvi.iItem = pInfoTip->iItem; + ListView_GetItem(pHeader->hwndFrom, &lvi); + HTREELISTITEM hItem = (HTREELISTITEM)lvi.lParam; + m_proto->m_SDManager.Lock(); + CJabberSDNode* pNode = (CJabberSDNode* )TreeList_GetData(hItem); + if ( pNode ) { + pNode->GetTooltipText( pInfoTip->pszText, pInfoTip->cchTextMax ); + } + m_proto->m_SDManager.Unlock(); + } + else if ( pHeader->code == TVN_ITEMEXPANDED ) { + NMTREEVIEW *pNmTreeView = (NMTREEVIEW *)lParam; + HTREELISTITEM hItem = (HTREELISTITEM)pNmTreeView->itemNew.hItem; + + m_proto->m_SDManager.Lock(); + XmlNode packet( NULL ); + CJabberSDNode* pNode; + pNode = (CJabberSDNode* )TreeList_GetData(hItem); + if ( pNode ) + { + m_proto->SendBothRequests( pNode, packet ); + TreeList_MakeFakeParent(hItem, FALSE); + } + m_proto->m_SDManager.Unlock(); + + if ( xmlGetChild( packet )) + m_proto->m_ThreadInfo->send( packet ); + } + else if ( pHeader->code == NM_CUSTOMDRAW ) { + LPNMLVCUSTOMDRAW lpnmlvcd = (LPNMLVCUSTOMDRAW)lParam; + if (lpnmlvcd->nmcd.dwDrawStage != CDDS_PREPAINT) + return CDRF_DODEFAULT; + + KillTimer(m_hwnd, AUTODISCO_TIMER); + if (GetTickCount() - sttLastAutoDisco < AUTODISCO_TIMEOUT) { + SetTimer(m_hwnd, AUTODISCO_TIMER, AUTODISCO_TIMEOUT, NULL); + return CDRF_DODEFAULT; + } + + SendMessage(m_hwnd, WM_TIMER, AUTODISCO_TIMER, 0); + + return CDRF_DODEFAULT; + } + return TRUE; + } + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + HWND hwndFocus = GetFocus(); + if (!hwndFocus) return TRUE; + if (GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_TXT_FILTERTEXT) + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BTN_FILTERAPPLY, 0 ), 0 ); + else if (m_hwnd == (hwndFocus = GetParent(hwndFocus))) + break; + else if ((GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_COMBO_NODE) || (GetWindowLongPtr(hwndFocus, GWL_ID) == IDC_COMBO_JID)) + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + return TRUE; + } + case IDCANCEL: + { + PostMessage(m_hwnd, WM_CLOSE, 0, 0); + return TRUE; + } + } + break; + + case WM_MEASUREITEM: + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + case WM_DRAWITEM: + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +// extern references to used functions: +void SearchAddToRecent( TCHAR* szAddr, HWND hwndDialog = NULL ); + +void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM hItem, POINT pt) +{ + //ClientToScreen(GetDlgItem(hwndServiceDiscovery, IDC_TREE_DISCO), &pt); + + enum { // This values are below CLISTMENUIDMAX and won't overlap + SD_ACT_REFRESH = 1, SD_ACT_REFRESHCHILDREN, SD_ACT_FAVORITE, + SD_ACT_ROSTER, SD_ACT_COPYJID, SD_ACT_COPYNODE, SD_ACT_USERMENU, + SD_ACT_COPYINFO, + + SD_ACT_LOGON = 100, SD_ACT_LOGOFF, SD_ACT_UNREGISTER, + + SD_ACT_REGISTER = 200, SD_ACT_ADHOC, SD_ACT_ADDDIRECTORY, + SD_ACT_JOIN, SD_ACT_BOOKMARK, SD_ACT_PROXY, SD_ACT_VCARD + }; + + enum { + SD_FLG_NONODE = 0x001, + SD_FLG_NOTONROSTER = 0x002, + SD_FLG_ONROSTER = 0x004, + SD_FLG_SUBSCRIBED = 0x008, + SD_FLG_NOTSUBSCRIBED = 0x010, + SD_FLG_ONLINE = 0x020, + SD_FLG_NOTONLINE = 0x040, + SD_FLG_NORESOURCE = 0x080, + SD_FLG_HASUSER = 0x100 + }; + + static struct + { + TCHAR *feature; + TCHAR *title; + int action; + DWORD flags; + } items[] = + { + {NULL, _T("Contact Menu..."), SD_ACT_USERMENU, SD_FLG_NONODE}, + {NULL, _T("View vCard"), SD_ACT_VCARD, SD_FLG_NONODE}, + {_T(JABBER_FEAT_MUC), _T("Join chatroom"), SD_ACT_JOIN, SD_FLG_NORESOURCE}, + {0}, + {NULL, _T("Refresh Info"), SD_ACT_REFRESH}, + {NULL, _T("Refresh Children"), SD_ACT_REFRESHCHILDREN}, + {0}, + {NULL, _T("Add to favorites"), SD_ACT_FAVORITE}, + {NULL, _T("Add to roster"), SD_ACT_ROSTER, SD_FLG_NONODE|SD_FLG_NOTONROSTER}, + {_T(JABBER_FEAT_MUC), _T("Bookmark chatroom"), SD_ACT_BOOKMARK, SD_FLG_NORESOURCE|SD_FLG_HASUSER}, + {_T("jabber:iq:search"), _T("Add search directory"), SD_ACT_ADDDIRECTORY}, + {_T(JABBER_FEAT_BYTESTREAMS), _T("Use this proxy"), SD_ACT_PROXY}, + {0}, + {_T(JABBER_FEAT_REGISTER), _T("Register"), SD_ACT_REGISTER}, + {_T("jabber:iq:gateway"), _T("Unregister"), SD_ACT_UNREGISTER, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED}, + {_T(JABBER_FEAT_COMMANDS), _T("Commands..."), SD_ACT_ADHOC}, + {0}, + {_T("jabber:iq:gateway"), _T("Logon"), SD_ACT_LOGON, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED|SD_FLG_ONLINE}, + {_T("jabber:iq:gateway"), _T("Logoff"), SD_ACT_LOGOFF, SD_FLG_ONROSTER|SD_FLG_SUBSCRIBED|SD_FLG_NOTONLINE}, + {0}, + {NULL, _T("Copy JID"), SD_ACT_COPYJID}, + {NULL, _T("Copy node name"), SD_ACT_COPYNODE}, + {NULL, _T("Copy node information"),SD_ACT_COPYINFO}, + }; + + HMENU hMenu = CreatePopupMenu(); + BOOL lastSeparator = TRUE; + bool bFilterItems = !GetAsyncKeyState(VK_CONTROL); + for (int i = 0; i < SIZEOF(items); ++i) + { + JABBER_LIST_ITEM *rosterItem = NULL; + + if (bFilterItems) + { + if ((items[i].flags&SD_FLG_NONODE) && pNode->GetNode()) + continue; + if ((items[i].flags&SD_FLG_NOTONROSTER) && (rosterItem = ListGetItemPtr(LIST_ROSTER, pNode->GetJid()))) + continue; + if ((items[i].flags&SD_FLG_ONROSTER) && !(rosterItem = ListGetItemPtr(LIST_ROSTER, pNode->GetJid()))) + continue; + if ((items[i].flags&SD_FLG_SUBSCRIBED) && (!rosterItem || (rosterItem->subscription == SUB_NONE))) + continue; + if ((items[i].flags&SD_FLG_NOTSUBSCRIBED) && (rosterItem && (rosterItem->subscription != SUB_NONE))) + continue; + if ((items[i].flags&SD_FLG_ONLINE) && rosterItem && (rosterItem->itemResource.status != ID_STATUS_OFFLINE)) + continue; + if ((items[i].flags&SD_FLG_NOTONLINE) && rosterItem && (rosterItem->itemResource.status == ID_STATUS_OFFLINE)) + continue; + if ((items[i].flags&SD_FLG_NORESOURCE) && _tcschr(pNode->GetJid(), _T('/'))) + continue; + if ((items[i].flags&SD_FLG_HASUSER) && !_tcschr(pNode->GetJid(), _T('@'))) + continue; + } + + if (!items[i].feature) + { + if (items[i].title) + { + HANDLE hContact; + if ((items[i].action == SD_ACT_USERMENU) && (hContact = HContactFromJID(pNode->GetJid()))) { + HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + AppendMenu(hMenu, MF_STRING|MF_POPUP, (UINT_PTR)hContactMenu, TranslateTS(items[i].title)); + } else + AppendMenu(hMenu, MF_STRING, items[i].action, TranslateTS(items[i].title)); + lastSeparator = FALSE; + } else + if (!lastSeparator) + { + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + lastSeparator = TRUE; + } + continue; + } + + bool bFeatureOk = !bFilterItems; + if (bFilterItems) + for (CJabberSDFeature *iFeature = pNode->GetFirstFeature(); iFeature; iFeature = iFeature->GetNext()) + if (!lstrcmp(iFeature->GetVar(), items[i].feature)) + { + bFeatureOk = true; + break; + } + + if (bFeatureOk) + { + if (items[i].title) + { + AppendMenu(hMenu, MF_STRING, items[i].action, TranslateTS(items[i].title)); + lastSeparator = FALSE; + } else + if (!lastSeparator) + { + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + lastSeparator = TRUE; + } + } + } + + if (!GetMenuItemCount(hMenu)) + { + DestroyMenu(hMenu); + return; + } + + int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlgServiceDiscovery->GetHwnd(), NULL); + DestroyMenu(hMenu); + + switch (res) + { + case SD_ACT_REFRESH: + { + m_SDManager.Lock(); + XmlNode packet( NULL ); + if ( pNode ) + { + TreeList_ResetItem(GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hItem); + pNode->ResetInfo(); + SendBothRequests( pNode, packet ); + TreeList_MakeFakeParent(hItem, FALSE); + } + m_SDManager.Unlock(); + + if ( xmlGetChild( packet )) + m_ThreadInfo->send( packet ); + break; + } + + case SD_ACT_REFRESHCHILDREN: + { + m_SDManager.Lock(); + XmlNode packet( NULL ); + for (int iChild = TreeList_GetChildrenCount(hItem); iChild--; ) { + HTREELISTITEM hNode = TreeList_GetChild(hItem, iChild); + CJabberSDNode *pNode = (CJabberSDNode *)TreeList_GetData(hNode); + if ( pNode ) + { + TreeList_ResetItem(GetDlgItem(m_pDlgServiceDiscovery->GetHwnd(), IDC_TREE_DISCO), hNode); + pNode->ResetInfo(); + SendBothRequests( pNode, packet ); + TreeList_MakeFakeParent(hNode, FALSE); + } + + if ( xmlGetChildCount( packet ) > 50 ) { + m_ThreadInfo->send( packet ); + packet = XmlNode( NULL ); + } } + m_SDManager.Unlock(); + + if ( xmlGetChildCount( packet )) + m_ThreadInfo->send( packet ); + break; + } + + case SD_ACT_COPYJID: + JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); + break; + + case SD_ACT_COPYNODE: + JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetNode()); + break; + + case SD_ACT_COPYINFO: + { + TCHAR buf[8192]; + pNode->GetTooltipText(buf, SIZEOF(buf)); + JabberCopyText(m_pDlgServiceDiscovery->GetHwnd(), buf); + break; + } + + case SD_ACT_FAVORITE: + { + char setting[MAXMODULELABELLENGTH]; + int count = JGetDword(NULL, "discoWnd_favCount", 0); + mir_snprintf(setting, sizeof(setting), "discoWnd_favName_%d", count); + JSetStringT(NULL, setting, pNode->GetName() ? pNode->GetName() : pNode->GetJid()); + mir_snprintf(setting, sizeof(setting), "discoWnd_favJID_%d", count); + JSetStringT(NULL, setting, pNode->GetJid()); + mir_snprintf(setting, sizeof(setting), "discoWnd_favNode_%d", count); + JSetStringT(NULL, setting, pNode->GetNode() ? pNode->GetNode() : _T("")); + JSetDword(NULL, "discoWnd_favCount", ++count); + break; + } + + case SD_ACT_REGISTER: + RegisterAgent(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); + break; + + case SD_ACT_ADHOC: + ContactMenuAdhocCommands( new CJabberAdhocStartupParams( this, pNode->GetJid(), pNode->GetNode())); + break; + + case SD_ACT_ADDDIRECTORY: + SearchAddToRecent(pNode->GetJid()); + break; + + case SD_ACT_PROXY: + m_options.BsDirect = FALSE; + m_options.BsProxyManual = TRUE; + JSetStringT( NULL, "BsProxyServer", pNode->GetJid()); + break; + + case SD_ACT_JOIN: + if ( jabberChatDllPresent ) + GroupchatJoinRoomByJid(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid()); + else + JabberChatDllError(); + break; + + case SD_ACT_BOOKMARK: + { + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_BOOKMARK, pNode->GetJid()); + if ( item == NULL ) { + item = ListGetItemPtr( LIST_BOOKMARK, pNode->GetJid()); + if ( item == NULL ) { + item = ListAdd( LIST_ROOM, pNode->GetJid()); + item->name = mir_tstrdup( pNode->GetName()); + } + if ( item != NULL ) { + item->type = _T("conference"); + AddEditBookmark( item ); + } } + break; + } + + case SD_ACT_USERMENU: + { + HANDLE hContact = HContactFromJID( pNode->GetJid()); + if ( !hContact ) { + hContact = DBCreateContact( pNode->GetJid(), pNode->GetName(), TRUE, FALSE ); + JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); + item->bUseResource = TRUE; + } + HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + GetCursorPos(&pt); + int res = TrackPopupMenu(hContactMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlgServiceDiscovery->GetHwnd(), NULL); + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); + break; + } + + case SD_ACT_VCARD: + { + TCHAR * jid = pNode->GetJid(); + HANDLE hContact = HContactFromJID(pNode->GetJid()); + if ( !hContact ) { + JABBER_SEARCH_RESULT jsr={0}; + mir_sntprintf( jsr.jid, SIZEOF(jsr.jid), _T("%s"), jid ); + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + hContact = ( HANDLE )CallProtoService( m_szModuleName, PS_ADDTOLIST, PALF_TEMPORARY, ( LPARAM )&jsr ); + } + if ( ListGetItemPtr( LIST_VCARD_TEMP, pNode->GetJid()) == NULL ) { + JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); + item->bUseResource = TRUE; + if ( item->resource == NULL ) + ListAddResource( LIST_VCARD_TEMP, jid, ID_STATUS_OFFLINE, NULL, 0); + } + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); + break; + } + + case SD_ACT_ROSTER: + { + HANDLE hContact = DBCreateContact(pNode->GetJid(), pNode->GetName(), FALSE, FALSE); + DBDeleteContactSetting( hContact, "CList", "NotOnList" ); + JABBER_LIST_ITEM* item = ListAdd( LIST_VCARD_TEMP, pNode->GetJid()); + item->bUseResource = TRUE; + break; + } + + case SD_ACT_LOGON: + case SD_ACT_LOGOFF: + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), pNode->GetJid()) << XATTR( _T("type"), ( res != SD_ACT_LOGON ) ? _T("unavailable") : NULL )); + break; + + case SD_ACT_UNREGISTER: + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), pNode->GetJid()) << XQUERY( _T(JABBER_FEAT_REGISTER)) << XCHILD( _T("remove"))); + + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) + << XCHILD( _T("item")) << XATTR( _T("jid"), pNode->GetJid()) << XATTR( _T("subscription"), _T("remove"))); + break; + + default: + if ((res >= CLISTMENUIDMIN) && (res <= CLISTMENUIDMAX)) { + HANDLE hContact = HContactFromJID(pNode->GetJid()); + if (hContact) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); + } + break; + } +} + +void CJabberProto::LaunchServiceDiscovery(TCHAR *jid) +{ + if ( m_pDlgServiceDiscovery ) { + SetForegroundWindow( m_pDlgServiceDiscovery->GetHwnd()); + if (jid) { + SetDlgItemText( m_pDlgServiceDiscovery->GetHwnd(), IDC_COMBO_JID, jid); + SetDlgItemTextA( m_pDlgServiceDiscovery->GetHwnd(), IDC_COMBO_NODE, ""); + PostMessage( m_pDlgServiceDiscovery->GetHwnd(), WM_COMMAND, MAKEWPARAM( IDC_BUTTON_BROWSE, 0 ), 0 ); + } + } else { + m_pDlgServiceDiscovery = new CJabberDlgDiscovery(this, jid); + m_pDlgServiceDiscovery->Show(); + } +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscovery( WPARAM, LPARAM ) +{ + LaunchServiceDiscovery(NULL); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryMyTransports( WPARAM, LPARAM ) +{ + LaunchServiceDiscovery(_T(SD_FAKEJID_MYAGENTS)); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryTransports( WPARAM, LPARAM ) +{ + LaunchServiceDiscovery(_T(SD_FAKEJID_AGENTS)); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleServiceDiscoveryConferences( WPARAM, LPARAM ) +{ + LaunchServiceDiscovery(_T(SD_FAKEJID_CONFERENCES)); + return 0; +} diff --git a/protocols/JabberG/src/jabber_disco.h b/protocols/JabberG/src/jabber_disco.h new file mode 100644 index 0000000000..79df12781e --- /dev/null +++ b/protocols/JabberG/src/jabber_disco.h @@ -0,0 +1,493 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2005-07 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_DISCO_H_ +#define _JABBER_DISCO_H_ + +#define CHR_BULLET ((WCHAR)0x2022) +// #define STR_BULLET L" \u2022 " + +#define JABBER_DISCO_RESULT_NOT_REQUESTED 0 +#define JABBER_DISCO_RESULT_ERROR -1 +#define JABBER_DISCO_RESULT_OK -2 + +class CJabberSDIdentity; +class CJabberSDIdentity +{ +protected: + TCHAR *m_szCategory; + TCHAR *m_szType; + TCHAR *m_szName; + CJabberSDIdentity *m_pNext; +public: + CJabberSDIdentity(const TCHAR *szCategory, const TCHAR *szType, const TCHAR *szName) + { + m_szCategory = mir_tstrdup(szCategory); + m_szType = mir_tstrdup(szType); + m_szName = mir_tstrdup(szName); + m_pNext = NULL; + } + ~CJabberSDIdentity() + { + mir_free(m_szCategory); + mir_free(m_szType); + mir_free(m_szName); + if (m_pNext) + delete m_pNext; + } + TCHAR* GetCategory() + { + return m_szCategory; + } + TCHAR* GetType() + { + return m_szType; + } + TCHAR* GetName() + { + return m_szName; + } + CJabberSDIdentity* GetNext() + { + return m_pNext; + } + CJabberSDIdentity* SetNext(CJabberSDIdentity *pNext) + { + CJabberSDIdentity *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } +}; + +class CJabberSDFeature; +class CJabberSDFeature +{ +protected: + TCHAR *m_szVar; + CJabberSDFeature *m_pNext; +public: + CJabberSDFeature(const TCHAR *szVar) + { + m_szVar = szVar ? mir_tstrdup(szVar) : NULL; + m_pNext = NULL; + } + ~CJabberSDFeature() + { + mir_free(m_szVar); + if (m_pNext) + delete m_pNext; + } + TCHAR* GetVar() + { + return m_szVar; + } + CJabberSDFeature* GetNext() + { + return m_pNext; + } + CJabberSDFeature* SetNext(CJabberSDFeature *pNext) + { + CJabberSDFeature *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } +}; + +class CJabberSDNode; +class CJabberSDNode +{ +protected: + TCHAR *m_szJid; + TCHAR *m_szNode; + TCHAR *m_szName; + CJabberSDIdentity *m_pIdentities; + CJabberSDFeature *m_pFeatures; + CJabberSDNode *m_pNext; + CJabberSDNode *m_pChild; + DWORD m_dwInfoRequestTime; + DWORD m_dwItemsRequestTime; + int m_nInfoRequestId; + int m_nItemsRequestId; + HTREELISTITEM m_hTreeItem; + TCHAR *m_szInfoError; + TCHAR *m_szItemsError; +public: + CJabberSDNode( const TCHAR *szJid = NULL, const TCHAR *szNode = NULL, const TCHAR *szName = NULL) + { + m_szJid = mir_tstrdup(szJid); + m_szNode = mir_tstrdup(szNode); + m_szName = mir_tstrdup(szName); + m_pIdentities = NULL; + m_pFeatures = NULL; + m_pNext = NULL; + m_pChild = NULL; + m_dwInfoRequestTime = 0; + m_dwItemsRequestTime = 0; + m_nInfoRequestId = 0; + m_nItemsRequestId = 0; + m_hTreeItem = NULL; + m_szInfoError = NULL; + m_szItemsError = NULL; + } + ~CJabberSDNode() + { + RemoveAll(); + } + BOOL RemoveAll() + { + replaceStrT( m_szJid, NULL ); + replaceStrT( m_szNode, NULL ); + replaceStrT( m_szName, NULL ); + replaceStrT( m_szInfoError, NULL ); + replaceStrT( m_szItemsError, NULL ); + if ( m_pIdentities ) + delete m_pIdentities; + m_pIdentities = NULL; + if ( m_pFeatures ) + delete m_pFeatures; + m_pFeatures = NULL; + if ( m_pNext ) + delete m_pNext; + m_pNext = NULL; + if ( m_pChild ) + delete m_pChild; + m_pChild = NULL; + m_nInfoRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; + m_nItemsRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; + m_dwInfoRequestTime = 0; + m_dwItemsRequestTime = 0; + m_hTreeItem = NULL; + return TRUE; + } + BOOL ResetInfo() + { + replaceStrT( m_szInfoError, NULL ); + replaceStrT( m_szItemsError, NULL ); + if ( m_pIdentities ) + delete m_pIdentities; + m_pIdentities = NULL; + if ( m_pFeatures ) + delete m_pFeatures; + m_pFeatures = NULL; + if ( m_pChild ) + delete m_pChild; + m_pChild = NULL; + m_nInfoRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; + m_nItemsRequestId = JABBER_DISCO_RESULT_NOT_REQUESTED; + m_dwInfoRequestTime = 0; + m_dwItemsRequestTime = 0; + return TRUE; + } + BOOL SetTreeItemHandle(HTREELISTITEM hItem) + { + m_hTreeItem = hItem; + return TRUE; + } + HTREELISTITEM GetTreeItemHandle() + { + return m_hTreeItem; + } + BOOL SetInfoRequestId(int nId) + { + m_nInfoRequestId = nId; + m_dwInfoRequestTime = GetTickCount(); + return TRUE; + } + int GetInfoRequestId() + { + return m_nInfoRequestId; + } + BOOL SetItemsRequestId(int nId) + { + m_nItemsRequestId = nId; + m_dwItemsRequestTime = GetTickCount(); + return TRUE; + } + int GetItemsRequestId() + { + return m_nItemsRequestId; + } + BOOL SetJid(TCHAR *szJid) + { + replaceStrT(m_szJid, szJid); + return TRUE; + } + TCHAR* GetJid() + { + return m_szJid; + } + BOOL SetNode(TCHAR *szNode) + { + replaceStrT(m_szNode, szNode); + return TRUE; + } + TCHAR* GetNode() + { + return m_szNode; + } + TCHAR* GetName() + { + return m_szName; + } + CJabberSDIdentity* GetFirstIdentity() + { + return m_pIdentities; + } + CJabberSDFeature* GetFirstFeature() + { + return m_pFeatures; + } + CJabberSDNode* GetFirstChildNode() + { + return m_pChild; + } + CJabberSDNode* GetNext() + { + return m_pNext; + } + CJabberSDNode* SetNext(CJabberSDNode *pNext) + { + CJabberSDNode *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } + CJabberSDNode* FindByIqId(int nIqId, BOOL bInfoId = TRUE) + { + if (( m_nInfoRequestId == nIqId && bInfoId ) || ( m_nItemsRequestId == nIqId && !bInfoId )) + return this; + + CJabberSDNode *pNode = NULL; + if ( m_pChild && (pNode = m_pChild->FindByIqId( nIqId, bInfoId ))) + return pNode; + + CJabberSDNode *pTmpNode = NULL; + pNode = m_pNext; + while ( pNode ) { + if (( pNode->m_nInfoRequestId == nIqId && bInfoId ) || ( pNode->m_nItemsRequestId == nIqId && !bInfoId )) + return pNode; + if ( pNode->m_pChild && (pTmpNode = pNode->m_pChild->FindByIqId( nIqId, bInfoId ))) + return pTmpNode; + pNode = pNode->GetNext(); + } + return NULL; + } + BOOL AddFeature(const TCHAR *szFeature) + { + if ( !szFeature ) + return FALSE; + + CJabberSDFeature *pFeature = new CJabberSDFeature( szFeature ); + if ( !pFeature ) + return FALSE; + + pFeature->SetNext( m_pFeatures ); + m_pFeatures = pFeature; + + return TRUE; + } + BOOL AddIdentity(const TCHAR *szCategory, const TCHAR *szType, const TCHAR *szName) + { + if ( !szCategory || !szType ) + return FALSE; + + CJabberSDIdentity *pIdentity = new CJabberSDIdentity( szCategory, szType, szName ); + if ( !pIdentity ) + return FALSE; + + pIdentity->SetNext( m_pIdentities ); + m_pIdentities = pIdentity; + + return TRUE; + } + BOOL AddChildNode(const TCHAR *szJid, const TCHAR *szNode, const TCHAR *szName) + { + if ( !szJid ) + return FALSE; + + CJabberSDNode *pNode = new CJabberSDNode( szJid, szNode, szName ); + if ( !pNode ) + return FALSE; + + pNode->SetNext( m_pChild ); + m_pChild = pNode; + + return TRUE; + } + BOOL AppendString(TCHAR **ppBuffer, TCHAR *szString) + { + if ( !*ppBuffer ) { + *ppBuffer = mir_tstrdup( szString ); + return TRUE; + } + + *ppBuffer = (TCHAR *)mir_realloc( *ppBuffer, (_tcslen( *ppBuffer) + _tcslen(szString) + 1 ) * sizeof( TCHAR )); + _tcscat(*ppBuffer, szString); + + return TRUE; + } + BOOL SetItemsRequestErrorText(TCHAR *szError) + { + replaceStrT(m_szItemsError, szError); + return TRUE; + } + BOOL SetInfoRequestErrorText(TCHAR *szError) + { + replaceStrT(m_szInfoError, szError); + return TRUE; + } + BOOL GetTooltipText(TCHAR *szText, int nMaxLength) + { + TCHAR *szBuffer = NULL; + + TCHAR szTmp[ 8192 ]; + + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("Jid: %s\r\n"), m_szJid ); + AppendString( &szBuffer, szTmp ); + + if ( m_szNode ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("%s: %s\r\n"), TranslateT("Node"), m_szNode ); + AppendString( &szBuffer, szTmp ); + } + + if ( m_pIdentities ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s:\r\n"), TranslateT("Identities")); + AppendString( &szBuffer, szTmp ); + + CJabberSDIdentity *pIdentity = m_pIdentities; + while ( pIdentity ) { + if ( pIdentity->GetName()) + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s (%s: %s, %s: %s)\r\n"), + CHR_BULLET, pIdentity->GetName(), + TranslateT("category"), pIdentity->GetCategory(), + TranslateT("type"), pIdentity->GetType()); + else + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s: %s, %s: %s\r\n"), + CHR_BULLET, + TranslateT("Category"), pIdentity->GetCategory(), + TranslateT("Type"), pIdentity->GetType()); + + AppendString( &szBuffer, szTmp ); + + pIdentity = pIdentity->GetNext(); + } + } + + if ( m_pFeatures ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s:\r\n"), TranslateT("Supported features")); + AppendString( &szBuffer, szTmp ); + + CJabberSDFeature *pFeature = m_pFeatures; + while ( pFeature ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T(" %c %s\r\n"), CHR_BULLET, pFeature->GetVar()); + + AppendString( &szBuffer, szTmp ); + + pFeature = pFeature->GetNext(); + } + } + + if ( m_szInfoError ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s: %s\r\n"), TranslateT("Info request error"), m_szInfoError ); + AppendString( &szBuffer, szTmp ); + } + + if ( m_szItemsError ) { + mir_sntprintf( szTmp, SIZEOF( szTmp ), _T("\r\n%s: %s\r\n"), TranslateT("Items request error"), m_szItemsError ); + AppendString( &szBuffer, szTmp ); + } + + szBuffer[lstrlen(szBuffer)-2] = 0; // remove CR/LF + mir_sntprintf( szText, nMaxLength, _T("%s"), szBuffer ); + + mir_free( szBuffer ); + + return TRUE; + } +}; + +class CJabberSDManager +{ +protected: + CRITICAL_SECTION m_cs; + CJabberSDNode *m_pPrimaryNodes; +public: + CJabberSDManager() + { + m_pPrimaryNodes = NULL; + InitializeCriticalSection(&m_cs); + } + ~CJabberSDManager() + { + DeleteCriticalSection(&m_cs); + RemoveAll(); + } + void RemoveAll() + { + delete m_pPrimaryNodes; + m_pPrimaryNodes = NULL; + } + BOOL Lock() + { + EnterCriticalSection(&m_cs); + return TRUE; + } + BOOL Unlock() + { + LeaveCriticalSection(&m_cs); + return TRUE; + } + CJabberSDNode* GetPrimaryNode() + { + return m_pPrimaryNodes; + } + CJabberSDNode* AddPrimaryNode(const TCHAR *szJid, const TCHAR *szNode, const TCHAR *szName) + { + if ( !szJid ) + return FALSE; + + CJabberSDNode *pNode = new CJabberSDNode( szJid, szNode, szName ); + if ( !pNode ) + return NULL; + + pNode->SetNext( m_pPrimaryNodes ); + m_pPrimaryNodes = pNode; + + return pNode; + } + CJabberSDNode* FindByIqId(int nIqId, BOOL bInfoId = TRUE) + { + CJabberSDNode *pNode = NULL; + CJabberSDNode *pTmpNode = NULL; + pNode = m_pPrimaryNodes; + while ( pNode ) { + if ( pTmpNode = pNode->FindByIqId( nIqId, bInfoId )) + return pTmpNode; + pNode = pNode->GetNext(); + } + return NULL; + } +}; + +#undef STR_BULLET // used for formatting + +#endif // _JABBER_DISCO_H_ diff --git a/protocols/JabberG/src/jabber_events.cpp b/protocols/JabberG/src/jabber_events.cpp new file mode 100644 index 0000000000..3f416aa54b --- /dev/null +++ b/protocols/JabberG/src/jabber_events.cpp @@ -0,0 +1,234 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#include <fcntl.h> +#include <io.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "m_file.h" +#include "m_addcontact.h" +#include "jabber_disco.h" +#include "m_proto_listeningto.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// OnContactDeleted - processes a contact deletion + +int CJabberProto::OnContactDeleted( WPARAM wParam, LPARAM ) +{ + if ( !m_bJabberOnline ) // should never happen + return 0; + + DBVARIANT dbv; + if ( !JGetStringT(( HANDLE ) wParam, JGetByte( (HANDLE ) wParam, "ChatRoom", 0 )?(char*)"ChatRoomID":(char*)"jid", &dbv )) { + if ( ListExist( LIST_ROSTER, dbv.ptszVal )) { + if ( !_tcschr( dbv.ptszVal, _T( '@' ))) { + TCHAR szStrippedJid[JABBER_MAX_JID_LEN]; + JabberStripJid( m_ThreadInfo->fullJID, szStrippedJid, SIZEOF(szStrippedJid)); + TCHAR *szDog = _tcschr( szStrippedJid, _T('@')); + if ( szDog && _tcsicmp( szDog + 1, dbv.ptszVal )) + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), dbv.ptszVal ) << XQUERY( _T(JABBER_FEAT_REGISTER)) << XCHILD( _T("remove"))); + } + + // Remove from roster, server also handles the presence unsubscription process. + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) + << XCHILD( _T("item")) << XATTR( _T("jid"), dbv.ptszVal ) << XATTR( _T("subscription"), _T("remove"))); + } + + JFreeVariant( &dbv ); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberDbSettingChanged - process database changes + +static TCHAR* sttSettingToTchar( DBCONTACTWRITESETTING* cws ) +{ + switch( cws->value.type ) { + case DBVT_ASCIIZ: + return mir_a2t( cws->value.pszVal ); + + case DBVT_UTF8: + return mir_utf8decodeT( cws->value.pszVal ); + + case DBVT_WCHAR: + return mir_u2t( cws->value.pwszVal ); + } + return NULL; +} + +void __cdecl CJabberProto::OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ) +{ + DBVARIANT jid, dbv; + if ( JGetStringT( hContact, "jid", &jid )) + return; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); + JFreeVariant( &jid ); + if ( item == NULL ) + return; + + TCHAR* nick; + if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) { + nick = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else if ( !JGetStringT( hContact, "Nick", &dbv )) { + nick = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else nick = JabberNickFromJID( item->jid ); + if ( nick == NULL ) + return; + + if ( cws->value.type == DBVT_DELETED ) { + if ( item->group != NULL ) { + Log( "Group set to nothing" ); + AddContactToRoster( item->jid, nick, NULL ); + } + } + else { + TCHAR* p = sttSettingToTchar( cws ); + if ( cws->value.pszVal != NULL && lstrcmp( p, item->group )) { + Log( "Group set to " TCHAR_STR_PARAM, p ); + if ( p ) + AddContactToRoster( item->jid, nick, p ); + } + mir_free( p ); + } + mir_free( nick ); +} + +void __cdecl CJabberProto::OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ) +{ + DBVARIANT jid; + if ( JGetStringT( hContact, "jid", &jid )) + return; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); + JFreeVariant( &jid ); + if ( item == NULL ) + return; + + if ( cws->value.type == DBVT_DELETED ) { + TCHAR* nick = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, GCDNF_NOMYHANDLE | GCDNF_TCHAR ); + AddContactToRoster( item->jid, nick, item->group ); + mir_free(nick); + return; + } + + TCHAR* newNick = sttSettingToTchar( cws ); + if ( newNick ) { + if ( lstrcmp( item->nick, newNick )) { + Log( "Renaming contact " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM " -> " TCHAR_STR_PARAM, item->jid, item->nick, newNick ); + AddContactToRoster( item->jid, newNick, item->group ); + } + mir_free( newNick ); +} } + +void __cdecl CJabberProto::OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ) +{ + if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 )) + return; + + DBVARIANT jid, dbv; + if ( JGetStringT( hContact, "jid", &jid )) + return; + + TCHAR *nick; + Log( "Add " TCHAR_STR_PARAM " permanently to list", jid.pszVal ); + if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) { + nick = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else if ( !JGetStringT( hContact, "Nick", &dbv )) { + nick = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else nick = JabberNickFromJID( jid.ptszVal ); + if ( nick == NULL ) { + JFreeVariant( &jid ); + return; + } + + if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) { + AddContactToRoster( jid.ptszVal, nick, dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else AddContactToRoster( jid.ptszVal, nick, NULL ); + + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), jid.ptszVal ) << XATTR( _T("type"), _T("subscribe"))); + + SendGetVcard( jid.ptszVal ); + + mir_free( nick ); + DBDeleteContactSetting( hContact, "CList", "Hidden" ); + JFreeVariant( &jid ); +} + +int __cdecl CJabberProto::OnDbSettingChanged( WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE ) wParam; + if ( hContact == NULL || !m_bJabberOnline ) + return 0; + + DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam; + if ( strcmp( cws->szModule, "CList" )) + return 0; + + if ( !strcmp( cws->szSetting, "Group" )) + OnRenameGroup( cws, hContact ); + else if ( !strcmp( cws->szSetting, "MyHandle" )) + OnRenameContact( cws, hContact ); + else if ( !strcmp( cws->szSetting, "NotOnList" )) + OnAddContactForever( cws, hContact ); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnIdleChanged - tracks idle start time for XEP-0012 support + +int CJabberProto::OnIdleChanged( WPARAM, LPARAM lParam ) +{ + // don't report idle time, if user disabled + if (lParam & IDF_PRIVACY) { + m_tmJabberIdleStartTime = 0; + return 0; + } + + if ( lParam & IDF_ISIDLE ) { + MIRANDA_IDLE_INFO mii = { 0 }; + mii.cbSize = sizeof( mii ); + CallService( MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii ); + m_tmJabberIdleStartTime = time( 0 ) - mii.idleTime * 60; + } else + m_tmJabberIdleStartTime = 0; + return 0; +} diff --git a/protocols/JabberG/src/jabber_file.cpp b/protocols/JabberG/src/jabber_file.cpp new file mode 100644 index 0000000000..5db215d024 --- /dev/null +++ b/protocols/JabberG/src/jabber_file.cpp @@ -0,0 +1,552 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "jabber_caps.h" + +#define JABBER_NETWORK_BUFFER_SIZE 2048 + +void __cdecl CJabberProto::FileReceiveThread( filetransfer* ft ) +{ + char* buffer; + int datalen; + ThreadData info( this, JABBER_SESSION_NORMAL ); + + Log( "Thread started: type=file_receive server='%s' port='%d'", ft->httpHostName, ft->httpPort ); + + ft->type = FT_OOB; + + if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { + Log( "Cannot allocate network buffer, thread ended" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + delete ft; + return; + } + + NETLIBOPENCONNECTION nloc = { 0 }; + nloc.cbSize = sizeof( nloc ); + nloc.cbSize = sizeof( NETLIBOPENCONNECTION ); + nloc.szHost = ft->httpHostName; + nloc.wPort = ft->httpPort; + info.s = ( HANDLE ) CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); + if ( info.s == NULL ) { + Log( "Connection failed ( %d ), thread ended", WSAGetLastError()); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + mir_free( buffer ); + delete ft; + return; + } + + ft->s = info.s; + + info.send( "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", ft->httpPath, ft->httpHostName ); + ft->state = FT_CONNECTING; + + Log( "Entering file_receive recv loop" ); + datalen = 0; + + while ( ft->state != FT_DONE && ft->state != FT_ERROR ) { + int recvResult, bytesParsed; + + Log( "Waiting for data..." ); + recvResult = info.recv( buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen ); + if ( recvResult <= 0 ) + break; + datalen += recvResult; + + bytesParsed = FileReceiveParse( ft, buffer, datalen ); + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + } + + ft->s = NULL; + + if ( ft->state==FT_DONE || ( ft->state==FT_RECEIVING && ft->std.currentFileSize < 0 )) + ft->complete(); + + Log( "Thread ended: type=file_receive server='%s'", ft->httpHostName ); + + mir_free( buffer ); + delete ft; +} + +int CJabberProto::FileReceiveParse( filetransfer* ft, char* buffer, int datalen ) +{ + char* p, *q, *s, *eob; + char* str; + int num, code; + + eob = buffer + datalen; + p = buffer; + num = 0; + while ( true ) { + if ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) { + for ( q=p; q+1<eob && ( *q!='\r' || *( q+1 )!='\n' ); q++ ); + if ( q+1 < eob ) { + if (( str=( char* )mir_alloc( q-p+1 )) != NULL ) { + strncpy( str, p, q-p ); + str[q-p] = '\0'; + Log( "FT Got: %s", str ); + if ( ft->state == FT_CONNECTING ) { + // looking for "HTTP/1.1 200 OK" + if ( sscanf( str, "HTTP/%*d.%*d %d %*s", &code )==1 && code==200 ) { + ft->state = FT_INITIALIZING; + ft->std.currentFileSize = -1; + Log( "Change to FT_INITIALIZING" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0 ); + } + } + else { // FT_INITIALIZING + if ( str[0] == '\0' ) { + TCHAR* s; + if (( s = _tcsrchr( ft->httpPath, '/' )) != NULL ) + s++; + else + s = ft->httpPath; + ft->std.tszCurrentFile = mir_tstrdup( s ); + JabberHttpUrlDecode( ft->std.tszCurrentFile ); + if ( ft->create() == -1 ) { + ft->state = FT_ERROR; + break; + } + ft->state = FT_RECEIVING; + ft->std.currentFileProgress = 0; + Log( "Change to FT_RECEIVING" ); + } + else if (( s=strchr( str, ':' )) != NULL ) { + *s = '\0'; + if ( !strcmp( str, "Content-Length" )) + ft->std.totalBytes = ft->std.currentFileSize = _atoi64( s+1 ); + } } + + mir_free( str ); + q += 2; + num += ( q-p ); + p = q; + } + else { + ft->state = FT_ERROR; + break; + } + } + else { + break; + } + } + else if ( ft->state == FT_RECEIVING ) { + int bufferSize, writeSize; + __int64 remainingBytes; + + if ( ft->std.currentFileSize < 0 || ft->std.currentFileProgress < ft->std.currentFileSize ) { + bufferSize = eob - p; + remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress; + if ( remainingBytes < bufferSize ) + writeSize = remainingBytes; + else + writeSize = bufferSize; + if ( _write( ft->fileId, p, writeSize ) != writeSize ) { + Log( "_write() error" ); + ft->state = FT_ERROR; + } + else { + ft->std.currentFileProgress += writeSize; + ft->std.totalProgress += writeSize; + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); + if ( ft->std.currentFileProgress == ft->std.currentFileSize ) + ft->state = FT_DONE; + } + } + num = datalen; + break; + } + else break; + } + + return num; +} + +void JabberFileServerConnection( JABBER_SOCKET hConnection, DWORD /*dwRemoteIP*/, void* extra ) +{ + CJabberProto* ppro = ( CJabberProto* )extra; + + NETLIBCONNINFO connInfo = { sizeof(connInfo) }; + CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hConnection, (LPARAM)&connInfo); + + TCHAR szPort[10]; + mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), connInfo.wPort ); + ppro->Log( "File server incoming connection accepted: %s", connInfo.szIpPort ); + + JABBER_LIST_ITEM *item = ppro->ListGetItemPtr( LIST_FILE, szPort ); + if ( item == NULL ) { + ppro->Log( "No file is currently served, file server connection closed." ); + Netlib_CloseHandle( hConnection ); + return; + } + + filetransfer* ft = item->ft; + JABBER_SOCKET slisten = ft->s; + ft->s = hConnection; + ppro->Log( "Set ft->s to %d ( saving %d )", hConnection, slisten ); + + char* buffer = ( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE+1 ); + if ( buffer == NULL ) { + ppro->Log( "Cannot allocate network buffer, file server connection closed." ); + Netlib_CloseHandle( hConnection ); + ft->state = FT_ERROR; + if ( ft->hFileEvent != NULL ) + SetEvent( ft->hFileEvent ); + return; + } + + ppro->Log( "Entering recv loop for this file connection... ( ft->s is hConnection )" ); + int datalen = 0; + while ( ft->state!=FT_DONE && ft->state!=FT_ERROR ) { + int recvResult, bytesParsed; + + recvResult = Netlib_Recv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); + if ( recvResult <= 0 ) + break; + datalen += recvResult; + + buffer[datalen] = '\0'; + ppro->Log( "RECV:%s", buffer ); + + bytesParsed = ppro->FileSendParse( hConnection, ft, buffer, datalen ); + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + } + + ppro->Log( "Closing connection for this file transfer... ( ft->s is now hBind )" ); + Netlib_CloseHandle( hConnection ); + ft->s = slisten; + ppro->Log( "ft->s is restored to %d", ft->s ); + if ( ft->hFileEvent != NULL ) + SetEvent( ft->hFileEvent ); + mir_free( buffer ); +} + +void __cdecl CJabberProto::FileServerThread( filetransfer* ft ) +{ + Log( "Thread started: type=file_send" ); + + ThreadData info( this, JABBER_SESSION_NORMAL ); + ft->type = FT_OOB; + + NETLIBBIND nlb = {0}; + nlb.cbSize = sizeof( NETLIBBIND ); + nlb.pfnNewConnectionV2 = JabberFileServerConnection; + nlb.pExtra = this; + nlb.wPort = 0; // Use user-specified incoming port ranges, if available + info.s = ( HANDLE ) CallService( MS_NETLIB_BINDPORT, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nlb ); + if ( info.s == NULL ) { + Log( "Cannot allocate port to bind for file server thread, thread ended." ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + delete ft; + return; + } + + ft->s = info.s; + Log( "ft->s = %d", info.s ); + + HANDLE hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + ft->hFileEvent = hEvent; + + TCHAR szPort[20]; + mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort ); + JABBER_LIST_ITEM *item = ListAdd( LIST_FILE, szPort ); + item->ft = ft; + + TCHAR* ptszResource = ListGetBestClientResourceNamePtr( ft->jid ); + if ( ptszResource != NULL ) { + ft->state = FT_CONNECTING; + for ( int i=0; i < ft->std.totalFiles && ft->state != FT_ERROR && ft->state != FT_DENIED; i++ ) { + ft->std.currentFileNumber = i; + ft->state = FT_CONNECTING; + if ( ft->httpPath ) mir_free( ft->httpPath ); + ft->httpPath = NULL; + + TCHAR* p; + if (( p = _tcschr( ft->std.ptszFiles[i], '\\' )) != NULL ) + p++; + else + p = ft->std.ptszFiles[i]; + + TCHAR* pFileName = JabberHttpUrlEncode( p ); + if ( pFileName != NULL ) { + int id = SerialNext(); + if ( ft->iqId ) mir_free( ft->iqId ); + ft->iqId = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( strlen( JABBER_IQID )+20 )); + wsprintf( ft->iqId, _T(JABBER_IQID)_T("%d"), id ); + + char *myAddr = NULL; + DBVARIANT dbv; + if (m_options.BsDirect && m_options.BsDirectManual) { + if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsDirectAddr", &dbv )) + myAddr = dbv.pszVal; + } + + if ( myAddr == NULL ) + myAddr = (char*)CallService( MS_NETLIB_ADDRESSTOSTRING, 1, nlb.dwExternalIP ); + + char szAddr[ 256 ]; + mir_snprintf( szAddr, sizeof(szAddr), "http://%s:%d/%s", myAddr, nlb.wPort, pFileName ); + + mir_free( pFileName ); + mir_free( myAddr ); + + int len = lstrlen(ptszResource) + lstrlen(ft->jid) + 2; + TCHAR* fulljid = ( TCHAR* )alloca( sizeof( TCHAR )*len ); + wsprintf( fulljid, _T("%s/%s"), ft->jid, ptszResource ); + + XmlNodeIq iq( _T("set"), id, fulljid ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_OOB)); + query << XCHILD( _T("url"), _A2T(szAddr)); + query << XCHILD( _T("desc"), ft->szDescription); + m_ThreadInfo->send( iq ); + + Log( "Waiting for the file to be sent..." ); + WaitForSingleObject( hEvent, INFINITE ); + } + Log( "File sent, advancing to the next file..." ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 ); + } + CloseHandle( hEvent ); + ft->hFileEvent = NULL; + Log( "Finish all files" ); + } + + ft->s = NULL; + Log( "ft->s is NULL" ); + + ListRemove( LIST_FILE, szPort ); + + switch ( ft->state ) { + case FT_DONE: + Log( "Finish successfully" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 ); + break; + case FT_DENIED: + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0 ); + break; + default: // FT_ERROR: + Log( "Finish with errors" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + break; + } + + Log( "Thread ended: type=file_send" ); + delete ft; +} + +int CJabberProto::FileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen ) +{ + char* p, *q, *t, *eob; + char* str; + int num; + int currentFile; + int fileId; + int numRead; + + eob = buffer + datalen; + p = buffer; + num = 0; + while ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) { + for ( q=p; q+1<eob && ( *q!='\r' || *( q+1 )!='\n' ); q++ ); + if ( q+1 >= eob ) + break; + if (( str=( char* )mir_alloc( q-p+1 )) == NULL ) { + ft->state = FT_ERROR; + break; + } + strncpy( str, p, q-p ); + str[q-p] = '\0'; + Log( "FT Got: %s", str ); + if ( ft->state == FT_CONNECTING ) { + // looking for "GET filename.ext HTTP/1.1" + if ( !strncmp( str, "GET ", 4 )) { + for ( t=str+4; *t!='\0' && *t!=' '; t++ ); + *t = '\0'; + for ( t=str+4; *t!='\0' && *t=='/'; t++ ); + ft->httpPath = mir_a2t( t ); + JabberHttpUrlDecode( ft->httpPath ); + ft->state = FT_INITIALIZING; + Log( "Change to FT_INITIALIZING" ); + } + } + else { // FT_INITIALIZING + if ( str[0] == '\0' ) { + struct _stati64 statbuf; + + mir_free( str ); + num += 2; + + currentFile = ft->std.currentFileNumber; + TCHAR* t = _tcsrchr( ft->std.ptszFiles[ currentFile ], '\\' ); + if ( t != NULL ) + t++; + else + t = ft->std.ptszFiles[currentFile]; + + if ( ft->httpPath==NULL || lstrcmp( ft->httpPath, t )) { + if ( ft->httpPath == NULL ) + Log( "Requested file name does not matched ( httpPath==NULL )" ); + else + Log( "Requested file name does not matched ( '%s' vs. '%s' )", ft->httpPath, t ); + ft->state = FT_ERROR; + break; + } + Log( "Sending [%s]", ft->std.ptszFiles[ currentFile ] ); + _tstati64( ft->std.ptszFiles[ currentFile ], &statbuf ); // file size in statbuf.st_size + if (( fileId = _topen( ft->std.ptszFiles[currentFile], _O_BINARY|_O_RDONLY )) < 0 ) { + Log( "File cannot be opened" ); + ft->state = FT_ERROR; + mir_free( ft->httpPath ); + ft->httpPath = NULL; + break; + } + + char fileBuffer[ 2048 ]; + int bytes = mir_snprintf( fileBuffer, sizeof(fileBuffer), "HTTP/1.1 200 OK\r\nContent-Length: %I64u\r\n\r\n", statbuf.st_size ); + WsSend( s, fileBuffer, bytes, MSG_DUMPASTEXT ); + + ft->std.flags |= PFTS_SENDING; + ft->std.currentFileProgress = 0; + Log( "Sending file data..." ); + + while (( numRead = _read( fileId, fileBuffer, 2048 )) > 0 ) { + if ( Netlib_Send( s, fileBuffer, numRead, 0 ) != numRead ) { + ft->state = FT_ERROR; + break; + } + ft->std.currentFileProgress += numRead; + ft->std.totalProgress += numRead; + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); + } + _close( fileId ); + if ( ft->state != FT_ERROR ) + ft->state = FT_DONE; + Log( "Finishing this file..." ); + mir_free( ft->httpPath ); + ft->httpPath = NULL; + break; + } } + + mir_free( str ); + q += 2; + num += ( q-p ); + p = q; + } + + return num; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// filetransfer class members + +filetransfer::filetransfer( CJabberProto* proto ) +{ + memset( this, 0, sizeof( filetransfer )); + ppro = proto; + fileId = -1; + std.cbSize = sizeof( std ); + std.flags = PFTS_TCHAR; +} + +filetransfer::~filetransfer() +{ + ppro->Log( "Destroying file transfer session %08p", this ); + + if ( !bCompleted ) + ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0 ); + + close(); + + if ( hWaitEvent != INVALID_HANDLE_VALUE ) + CloseHandle( hWaitEvent ); + + if ( jid ) mir_free( jid ); + if ( sid ) mir_free( sid ); + if ( iqId ) mir_free( iqId ); + if ( fileSize ) mir_free( fileSize ); + if ( httpHostName ) mir_free( httpHostName ); + if ( httpPath ) mir_free( httpPath ); + if ( szDescription ) mir_free( szDescription ); + + if ( std.tszWorkingDir ) mir_free( std.tszWorkingDir ); + if ( std.tszCurrentFile ) mir_free( std.tszCurrentFile ); + + if ( std.ptszFiles ) { + for ( int i=0; i < std.totalFiles; i++ ) + if ( std.ptszFiles[i] ) mir_free( std.ptszFiles[i] ); + + mir_free( std.ptszFiles ); +} } + +void filetransfer::close() +{ + if ( fileId != -1 ) { + _close( fileId ); + fileId = -1; +} } + +void filetransfer::complete() +{ + close(); + + bCompleted = true; + ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0); +} + +int filetransfer::create() +{ + if ( fileId != -1 ) + return fileId; + + TCHAR filefull[ MAX_PATH ]; + mir_sntprintf( filefull, SIZEOF(filefull), _T("%s\\%s"), std.tszWorkingDir, std.tszCurrentFile ); + replaceStrT( std.tszCurrentFile, filefull ); + + if ( hWaitEvent != INVALID_HANDLE_VALUE ) + CloseHandle( hWaitEvent ); + hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + + if ( ppro->JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, this, ( LPARAM )&std )) + WaitForSingleObject( hWaitEvent, INFINITE ); + + if ( fileId == -1 ) { + ppro->Log( "Saving to [%s]", std.tszCurrentFile ); + fileId = _topen( std.tszCurrentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE ); + } + + if ( fileId == -1 ) + ppro->Log( "Cannot create file '%s' during a file transfer", filefull ); + else if ( std.currentFileSize != 0 ) + _chsize( fileId, std.currentFileSize ); + + return fileId; +} diff --git a/protocols/JabberG/src/jabber_form.cpp b/protocols/JabberG/src/jabber_form.cpp new file mode 100644 index 0000000000..a90dcf62fa --- /dev/null +++ b/protocols/JabberG/src/jabber_form.cpp @@ -0,0 +1,905 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_caps.h" + + +static BOOL CALLBACK JabberFormMultiLineWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch ( msg ) { + //case WM_GETDLGCODE: + // return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTALLKEYS; + case WM_KEYDOWN: + if ( wParam == VK_TAB ) { + SetFocus( GetNextDlgTabItem( GetParent( GetParent( hwnd )), hwnd, GetKeyState( VK_SHIFT )<0?TRUE:FALSE )); + return TRUE; + }; + break; + } + return CallWindowProc(( WNDPROC ) GetWindowLongPtr( hwnd, GWLP_USERDATA ), hwnd, msg, wParam, lParam ); +} + +struct TJabberFormControlInfo +{ + TJabberFormControlType type; + SIZE szBlock; + POINT ptLabel, ptCtrl; + HWND hLabel, hCtrl; +}; +typedef LIST<TJabberFormControlInfo> TJabberFormControlList; + +struct TJabberFormLayoutInfo +{ + int ctrlHeight; + int offset, width, maxLabelWidth; + int y_pos, y_spacing; + int id; + bool compact; +}; + +void JabberFormCenterContent(HWND hwndStatic) +{ + RECT rcWindow; + int minX; + GetWindowRect(hwndStatic,&rcWindow); + minX=rcWindow.right; + HWND oldChild=NULL; + HWND hWndChild=GetWindow(hwndStatic,GW_CHILD); + while (hWndChild!=oldChild && hWndChild!=NULL) + { + DWORD style=GetWindowLongPtr(hWndChild, GWL_STYLE); + RECT rc; + GetWindowRect(hWndChild,&rc); + if ((style&SS_RIGHT) && !(style&WS_TABSTOP)) + { + TCHAR * text; + RECT calcRect=rc; + int len=GetWindowTextLength(hWndChild); + text=(TCHAR*)malloc(sizeof(TCHAR)*(len+1)); + GetWindowText(hWndChild,text,len+1); + HDC hdc=GetDC(hWndChild); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hWndChild, WM_GETFONT, 0, 0)); + DrawText(hdc,text,-1,&calcRect,DT_CALCRECT|DT_WORDBREAK); + minX=min(minX, rc.right-(calcRect.right-calcRect.left)); + SelectObject(hdc, hfntSave); + ReleaseDC(hWndChild,hdc); + } + else + { + minX=min(minX,rc.left); + } + oldChild=hWndChild; + hWndChild=GetWindow(hWndChild,GW_HWNDNEXT); + } + if (minX>rcWindow.left+5) + { + int dx=(minX-rcWindow.left)/2; + oldChild=NULL; + hWndChild=GetWindow(hwndStatic,GW_CHILD); + while (hWndChild!=oldChild && hWndChild!=NULL ) + { + DWORD style=GetWindowLongPtr(hWndChild, GWL_STYLE); + RECT rc; + GetWindowRect(hWndChild,&rc); + if ((style&SS_RIGHT) && !(style&WS_TABSTOP)) + MoveWindow(hWndChild,rc.left-rcWindow.left,rc.top-rcWindow.top, rc.right-rc.left-dx, rc.bottom-rc.top, TRUE); + else + MoveWindow(hWndChild,rc.left-dx-rcWindow.left,rc.top-rcWindow.top, rc.right-rc.left, rc.bottom-rc.top, TRUE); + oldChild=hWndChild; + hWndChild=GetWindow(hWndChild,GW_HWNDNEXT); + } + } +} + +void JabberFormSetInstruction( HWND hwndForm, const TCHAR *text ) +{ + if (!text) text = _T(""); + + int len = lstrlen(text); + int fixedLen = len; + for (int i = 1; i < len; ++i) + if ((text[i - 1] == _T('\n')) && (text[i] != _T('\r'))) + ++fixedLen; + TCHAR *fixedText = NULL; + if (fixedLen != len) { + fixedText = (TCHAR *)mir_alloc(sizeof(TCHAR) * (fixedLen+1)); + TCHAR *p = fixedText; + for (int i = 0; i < len; ++i) { + *p = text[i]; + if (i && (text[i] == _T('\n')) && (text[i] != _T('\r'))) { + *p++ = _T('\r'); + *p = _T('\n'); + } + ++p; + } + *p = 0; + text = fixedText; + } + + SetDlgItemText( hwndForm, IDC_INSTRUCTION, text ); + + RECT rcText; + GetWindowRect(GetDlgItem(hwndForm, IDC_INSTRUCTION), &rcText); + int oldWidth = rcText.right-rcText.left; + int deltaHeight = -(rcText.bottom-rcText.top); + + SetRect(&rcText, 0, 0, rcText.right-rcText.left, 0); + HDC hdcEdit = GetDC(GetDlgItem(hwndForm, IDC_INSTRUCTION)); + HFONT hfntSave = (HFONT)SelectObject(hdcEdit, (HFONT)SendDlgItemMessage(hwndForm, IDC_INSTRUCTION, WM_GETFONT, 0, 0)); + DrawTextEx(hdcEdit, (TCHAR *)text, lstrlen(text), &rcText, + DT_CALCRECT|DT_EDITCONTROL|DT_TOP|DT_WORDBREAK, NULL); + SelectObject(hdcEdit, hfntSave); + ReleaseDC(GetDlgItem(hwndForm, IDC_INSTRUCTION), hdcEdit); + + RECT rcWindow; GetClientRect(hwndForm, &rcWindow); + if (rcText.bottom-rcText.top > (rcWindow.bottom-rcWindow.top)/5) { + HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); + SetWindowLongPtr(hwndEdit, GWL_STYLE, WS_VSCROLL | GetWindowLongPtr(hwndEdit, GWL_STYLE)); + rcText.bottom = rcText.top + (rcWindow.bottom-rcWindow.top)/5; + } else { + HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); + SetWindowLongPtr(hwndEdit, GWL_STYLE, ~WS_VSCROLL & GetWindowLongPtr(hwndEdit, GWL_STYLE)); + } + deltaHeight += rcText.bottom-rcText.top; + + SetWindowPos(GetDlgItem(hwndForm, IDC_INSTRUCTION), 0, 0, 0, + oldWidth, + rcText.bottom-rcText.top, + SWP_NOMOVE|SWP_NOZORDER); + + GetWindowRect(GetDlgItem(hwndForm, IDC_WHITERECT), &rcText); + MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); + rcText.bottom += deltaHeight; + SetWindowPos(GetDlgItem(hwndForm, IDC_WHITERECT), 0, 0, 0, + rcText.right-rcText.left, + rcText.bottom-rcText.top, + SWP_NOMOVE|SWP_NOZORDER); + + GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME1), &rcText); + MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); + rcText.top += deltaHeight; + SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME1), 0, + rcText.left, + rcText.top, + 0, 0, + SWP_NOSIZE|SWP_NOZORDER); + + GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME), &rcText); + MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); + rcText.top += deltaHeight; + SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME), 0, + rcText.left, + rcText.top, + rcText.right-rcText.left, + rcText.bottom-rcText.top, + SWP_NOZORDER); + + GetWindowRect(GetDlgItem(hwndForm, IDC_VSCROLL), &rcText); + MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); + rcText.top += deltaHeight; + SetWindowPos(GetDlgItem(hwndForm, IDC_VSCROLL), 0, + rcText.left, + rcText.top, + rcText.right-rcText.left, + rcText.bottom-rcText.top, + SWP_NOZORDER); + + if (fixedText) mir_free(fixedText); +} + +static TJabberFormControlType JabberFormTypeNameToId( const TCHAR *type ) +{ + if ( !_tcscmp( type, _T("text-private"))) + return JFORM_CTYPE_TEXT_PRIVATE; + if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) + return JFORM_CTYPE_TEXT_MULTI; + if ( !_tcscmp( type, _T("boolean"))) + return JFORM_CTYPE_BOOLEAN; + if ( !_tcscmp( type, _T("list-single"))) + return JFORM_CTYPE_LIST_SINGLE; + if ( !_tcscmp( type, _T("list-multi"))) + return JFORM_CTYPE_LIST_MULTI; + if ( !_tcscmp( type, _T("fixed"))) + return JFORM_CTYPE_FIXED; + if ( !_tcscmp( type, _T("hidden"))) + return JFORM_CTYPE_HIDDEN; + // else + return JFORM_CTYPE_TEXT_SINGLE; +} + +void JabberFormLayoutSingleControl(TJabberFormControlInfo *item, TJabberFormLayoutInfo *layout_info, const TCHAR *labelStr, const TCHAR *valueStr) +{ + RECT rcLabel = {0}, rcCtrl = {0}; + if (item->hLabel) + { + SetRect(&rcLabel, 0, 0, layout_info->width, 0); + HDC hdc = GetDC( item->hLabel ); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hLabel, WM_GETFONT, 0, 0)); + DrawText( hdc, labelStr, -1, &rcLabel, DT_CALCRECT|DT_WORDBREAK ); + SelectObject(hdc, hfntSave); + ReleaseDC(item->hLabel, hdc); + } + + int indent = layout_info->compact ? 10 : 20; + + if ((layout_info->compact && (item->type != JFORM_CTYPE_BOOLEAN) && (item->type != JFORM_CTYPE_FIXED))|| + (rcLabel.right >= layout_info->maxLabelWidth) || + (rcLabel.bottom > layout_info->ctrlHeight) || + (item->type == JFORM_CTYPE_LIST_MULTI) || + (item->type == JFORM_CTYPE_TEXT_MULTI)) + { + int height = layout_info->ctrlHeight; + if ((item->type == JFORM_CTYPE_LIST_MULTI) || (item->type == JFORM_CTYPE_TEXT_MULTI)) height *= 3; + SetRect(&rcCtrl, indent, rcLabel.bottom, layout_info->width, rcLabel.bottom + height); + } else + if (item->type == JFORM_CTYPE_BOOLEAN) + { + SetRect(&rcCtrl, 0, 0, layout_info->width-20, 0); + HDC hdc = GetDC( item->hCtrl ); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); + DrawText( hdc, labelStr, -1, &rcCtrl, DT_CALCRECT|DT_RIGHT|DT_WORDBREAK ); + SelectObject(hdc, hfntSave); + ReleaseDC(item->hCtrl, hdc); + rcCtrl.right += 20; + } else + if (item->type == JFORM_CTYPE_FIXED) + { + SetRect(&rcCtrl, 0, 0, layout_info->width, 0); + HDC hdc = GetDC( item->hCtrl ); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); + DrawText( hdc, valueStr, -1, &rcCtrl, DT_CALCRECT|DT_EDITCONTROL ); + rcCtrl.right += 20; + SelectObject(hdc, hfntSave); + ReleaseDC(item->hCtrl, hdc); + } else + { + SetRect(&rcCtrl, rcLabel.right+5, 0, layout_info->width, layout_info->ctrlHeight); + rcLabel.bottom = rcCtrl.bottom; + } + + if (item->hLabel) + SetWindowPos(item->hLabel, 0, + 0, 0, rcLabel.right-rcLabel.left, rcLabel.bottom-rcLabel.top, + SWP_NOZORDER|SWP_NOMOVE); + if (item->hCtrl) + SetWindowPos(item->hCtrl, 0, + 0, 0, rcCtrl.right-rcCtrl.left, rcCtrl.bottom-rcCtrl.top, + SWP_NOZORDER|SWP_NOMOVE); + + item->ptLabel.x = rcLabel.left; + item->ptLabel.y = rcLabel.top; + item->ptCtrl.x = rcCtrl.left; + item->ptCtrl.y = rcCtrl.top; + item->szBlock.cx = layout_info->width; + item->szBlock.cy = max(rcLabel.bottom, rcCtrl.bottom); +} + +#define JabberFormCreateLabel() \ + CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, \ + 0, 0, 0, 0, hwndStatic, ( HMENU )-1, hInst, NULL ) + +TJabberFormControlInfo *JabberFormAppendControl(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, TJabberFormControlType type, const TCHAR *labelStr, const TCHAR *valueStr) +{ + TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); + if (!controls) + { + controls = new TJabberFormControlList(5); + SetWindowLongPtr(hwndStatic, GWLP_USERDATA, (LONG_PTR)controls); + } + + TJabberFormControlInfo *item = (TJabberFormControlInfo *)mir_alloc(sizeof(TJabberFormControlInfo)); + item->type = type; + item->hLabel = item->hCtrl = NULL; + + switch (type) + { + case JFORM_CTYPE_TEXT_PRIVATE: + { + item->hLabel = JabberFormCreateLabel(); + item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + ++layout_info->id; + break; + } + case JFORM_CTYPE_TEXT_MULTI: + { + item->hLabel = JabberFormCreateLabel(); + item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + WNDPROC oldWndProc = ( WNDPROC ) SetWindowLongPtr( item->hCtrl, GWLP_WNDPROC, ( LONG_PTR )JabberFormMultiLineWndProc ); + SetWindowLongPtr( item->hCtrl, GWLP_USERDATA, ( LONG_PTR ) oldWndProc ); + ++layout_info->id; + break; + } + case JFORM_CTYPE_BOOLEAN: + { + item->hCtrl = CreateWindowEx( 0, _T("button"), labelStr, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + if ( valueStr && !_tcscmp( valueStr, _T("1"))) + SendMessage( item->hCtrl, BM_SETCHECK, 1, 0 ); + ++layout_info->id; + break; + } + case JFORM_CTYPE_LIST_SINGLE: + { + item->hLabel = JabberFormCreateLabel(); + item->hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "combobox", NULL, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + ++layout_info->id; + break; + } + case JFORM_CTYPE_LIST_MULTI: + { + item->hLabel = JabberFormCreateLabel(); + item->hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "listbox", + NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_MULTIPLESEL, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + ++layout_info->id; + break; + } + case JFORM_CTYPE_FIXED: + { + item->hCtrl = CreateWindow( _T("edit"), valueStr, + WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY|ES_AUTOHSCROLL, + 0, 0, 0, 0, + hwndStatic, ( HMENU )-1, hInst, NULL ); + break; + } + case JFORM_CTYPE_HIDDEN: + { + break; + } + case JFORM_CTYPE_TEXT_SINGLE: + { + item->hLabel = labelStr ? (JabberFormCreateLabel()) : NULL; + item->hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, + 0, 0, 0, 0, + hwndStatic, ( HMENU ) layout_info->id, hInst, NULL ); + ++layout_info->id; + break; + } + } + + HFONT hFont = ( HFONT ) SendMessage( GetParent(hwndStatic), WM_GETFONT, 0, 0 ); + if (item->hLabel) SendMessage( item->hLabel, WM_SETFONT, ( WPARAM ) hFont, 0 ); + if (item->hCtrl) SendMessage( item->hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 ); + + JabberFormLayoutSingleControl(item, layout_info, labelStr, valueStr); + + controls->insert(item); + return item; +} + +void JabberFormAddListItem(TJabberFormControlInfo *item, TCHAR *text, bool selected) +{ + DWORD dwIndex; + switch (item->type) + { + case JFORM_CTYPE_LIST_MULTI: + dwIndex = SendMessage(item->hCtrl, LB_ADDSTRING, 0, (LPARAM)text); + if (selected) SendMessage(item->hCtrl, LB_SETSEL, TRUE, dwIndex); + break; + case JFORM_CTYPE_LIST_SINGLE: + dwIndex = SendMessage(item->hCtrl, CB_ADDSTRING, 0, (LPARAM)text); + if (selected) SendMessage(item->hCtrl, CB_SETCURSEL, dwIndex, 0); + break; + } +} + +void JabberFormLayoutControls(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, int *formHeight) +{ + TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); + if (!controls) return; + + for (int i = 0; i < controls->getCount(); ++i) + { + if ((*controls)[i]->hLabel) + SetWindowPos((*controls)[i]->hLabel, 0, + layout_info->offset+(*controls)[i]->ptLabel.x, layout_info->y_pos+(*controls)[i]->ptLabel.y, 0, 0, + SWP_NOZORDER|SWP_NOSIZE); + if ((*controls)[i]->hCtrl) + SetWindowPos((*controls)[i]->hCtrl, 0, + layout_info->offset+(*controls)[i]->ptCtrl.x, layout_info->y_pos+(*controls)[i]->ptCtrl.y, 0, 0, + SWP_NOZORDER|SWP_NOSIZE); + + layout_info->y_pos += (*controls)[i]->szBlock.cy; + layout_info->y_pos += layout_info->y_spacing; + } + + *formHeight = layout_info->y_pos + (layout_info->compact ? 0 : 9); +} + +HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic) +{ + RECT frameRect; + GetClientRect( hwndStatic, &frameRect ); + + TJabberFormLayoutInfo *layout_info = (TJabberFormLayoutInfo *)mir_alloc(sizeof(TJabberFormLayoutInfo)); + layout_info->compact = false; + layout_info->ctrlHeight = 20; + layout_info->id = 0; + layout_info->width = frameRect.right - frameRect.left - 20 - 10; + layout_info->y_spacing = 5; + layout_info->maxLabelWidth = layout_info->width*2/5; + layout_info->offset = 10; + layout_info->y_pos = 14; + return layout_info; +} + +void JabberFormCreateUI( HWND hwndStatic, HXML xNode, int *formHeight, BOOL bCompact ) +{ + JabberFormDestroyUI(hwndStatic); + + HXML v, o, vs; + + int i, j, k; + const TCHAR* label, *typeName, *varStr, *str, *valueText; + TCHAR *labelStr, *valueStr, *p; + RECT frameRect; + + if ( xNode==NULL || xmlGetName( xNode )==NULL || lstrcmp( xmlGetName( xNode ), _T("x")) || hwndStatic==NULL ) return; + + GetClientRect( hwndStatic, &frameRect ); + + TJabberFormLayoutInfo layout_info; + layout_info.compact = bCompact ? true : false; + layout_info.ctrlHeight = 20; + layout_info.id = 0; + layout_info.width = frameRect.right - frameRect.left - 20; + if (!bCompact) layout_info.width -= 10; + layout_info.y_spacing = bCompact ? 1 : 5; + layout_info.maxLabelWidth = layout_info.width*2/5; + layout_info.offset = 10; + layout_info.y_pos = bCompact ? 0 : 14; + for ( i=0; ; i++ ) { + HXML n = xmlGetChild( xNode ,i); + if ( !n ) + break; + + if ( xmlGetName( n )) { + if ( !lstrcmp( xmlGetName( n ), _T("field"))) { + varStr = xmlGetAttrValue( n, _T("var")); + if (( typeName = xmlGetAttrValue( n, _T("type"))) != NULL ) { + if (( label = xmlGetAttrValue( n, _T("label"))) != NULL ) + labelStr = mir_tstrdup( label ); + else + labelStr = mir_tstrdup( varStr ); + + TJabberFormControlType type = JabberFormTypeNameToId(typeName); + + if (( v = xmlGetChild( n , "value" )) != NULL ) + { + valueText = xmlGetText( v ); + if (type != JFORM_CTYPE_TEXT_MULTI) + { + valueStr = mir_tstrdup( valueText ); + } else + { + size_t size = 1; + for ( j=0; ; j++ ) { + v = xmlGetChild( n ,j); + if ( !v ) + break; + if ( xmlGetName( v ) && !lstrcmp( xmlGetName( v ), _T("value")) && xmlGetText( v )) + size += _tcslen( xmlGetText( v )) + 2; + } + valueStr = ( TCHAR* )mir_alloc( sizeof(TCHAR)*size ); + valueStr[0] = '\0'; + for ( j=0; ; j++ ) { + v = xmlGetChild( n ,j); + if ( !v ) + break; + if ( xmlGetName( v ) && !lstrcmp( xmlGetName( v ), _T("value")) && xmlGetText( v )) { + if ( valueStr[0] ) + _tcscat( valueStr, _T("\r\n")); + _tcscat( valueStr, xmlGetText( v )); + } } + } + } else + { + valueText = valueStr = NULL; + } + + TJabberFormControlInfo *item = JabberFormAppendControl(hwndStatic, &layout_info, type, labelStr, valueStr); + + mir_free( labelStr ); + mir_free( valueStr ); + + if (type == JFORM_CTYPE_LIST_SINGLE) + { + for ( j=0; ; j++ ) { + o = xmlGetChild( n ,j); + if ( !o ) + break; + if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { + if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { + if (( str = xmlGetAttrValue( o, _T("label"))) == NULL ) + str = xmlGetText( v ); + if (( p = mir_tstrdup( str )) != NULL ) { + bool selected = false; + if ( valueText != NULL && !_tcscmp( valueText, xmlGetText( v ))) + selected = true; + JabberFormAddListItem(item, p, selected); + mir_free( p ); + } } } } + } else + if (type == JFORM_CTYPE_LIST_MULTI) + { + for ( j=0; ; j++ ) { + o = xmlGetChild( n ,j); + if ( !o ) + break; + if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { + if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { + if (( str = xmlGetAttrValue( o, _T("label"))) == NULL ) + str = xmlGetText( v ); + if (( p = mir_tstrdup( str )) != NULL ) { + bool selected = false; + for ( k=0; ; k++ ) { + vs = xmlGetChild( n ,k); + if ( !vs ) + break; + if ( !lstrcmp( xmlGetName( vs ), _T("value")) && xmlGetText( vs ) && !_tcscmp( xmlGetText( vs ), xmlGetText( v ))) + { + selected = true; + break; + } + } + JabberFormAddListItem( item, p, selected ); + mir_free( p ); + } } } } } } } } } + + JabberFormLayoutControls(hwndStatic, &layout_info, formHeight); +} + +void JabberFormDestroyUI(HWND hwndStatic) +{ + TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); + if (controls) + { + for ( int i = 0; i < controls->getCount(); i++ ) + mir_free((*controls)[i]); + controls->destroy(); + delete controls; + SetWindowLongPtr(hwndStatic, GWLP_USERDATA, 0); + } +} + +HXML JabberFormGetData( HWND hwndStatic, HXML xNode ) +{ + HWND hFrame, hCtrl; + HXML n, v, o; + int id, j, k, len; + const TCHAR *varName, *type, *fieldStr, *labelText, *str2; + TCHAR *p, *q, *str; + + if ( xNode == NULL || xmlGetName( xNode ) == NULL || lstrcmp( xmlGetName( xNode ), _T("x")) || hwndStatic == NULL ) + return NULL; + + hFrame = hwndStatic; + id = 0; + XmlNode x( _T("x")); + x << XATTR( _T("xmlns"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")); + + for ( int i=0; ; i++ ) { + n = xmlGetChild( xNode ,i); + if ( !n ) + break; + + fieldStr = NULL; + if ( lstrcmp( xmlGetName( n ), _T("field"))) + continue; + + if (( varName = xmlGetAttrValue( n, _T("var"))) == NULL || ( type = xmlGetAttrValue( n, _T("type"))) == NULL ) + continue; + + hCtrl = GetDlgItem( hFrame, id ); + HXML field = x << XCHILD( _T("field")) << XATTR( _T("var"), varName ); + + if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) { + len = GetWindowTextLength( GetDlgItem( hFrame, id )); + str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 )); + GetDlgItemText( hFrame, id, str, len+1 ); + p = str; + while ( p != NULL ) { + if (( q = _tcsstr( p, _T("\r\n"))) != NULL ) + *q = '\0'; + field << XCHILD( _T("value"), p ); + p = q ? q+2 : NULL; + } + mir_free( str ); + id++; + } + else if ( !_tcscmp( type, _T("boolean"))) { + TCHAR buf[ 10 ]; + _itot( IsDlgButtonChecked( hFrame, id ) == BST_CHECKED ? 1 : 0, buf, 10 ); + field << XCHILD( _T("value"), buf ); + id++; + } + else if ( !_tcscmp( type, _T("list-single"))) { + len = GetWindowTextLength( GetDlgItem( hFrame, id )); + str = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 )); + GetDlgItemText( hFrame, id, str, len+1 ); + v = NULL; + for ( j=0; ; j++ ) { + o = xmlGetChild( n ,j); + if ( !o ) + break; + + if ( !lstrcmp( xmlGetName( o ), _T("option"))) { + if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { + if (( str2 = xmlGetAttrValue( o, _T("label"))) == NULL ) + str2 = xmlGetText( v ); + if ( !lstrcmp( str2, str )) + break; + } } } + + if ( o ) + field << XCHILD( _T("value"), xmlGetText( v )); + + mir_free( str ); + id++; + } + else if ( !_tcscmp( type, _T("list-multi"))) { + int count = SendMessage( hCtrl, LB_GETCOUNT, 0, 0 ); + for ( j=0; j<count; j++ ) { + if ( SendMessage( hCtrl, LB_GETSEL, j, 0 ) > 0 ) { + // an entry is selected + len = SendMessage( hCtrl, LB_GETTEXTLEN, j, 0 ); + if (( str = ( TCHAR* )mir_alloc(( len+1 )*sizeof( TCHAR ))) != NULL ) { + SendMessage( hCtrl, LB_GETTEXT, j, ( LPARAM )str ); + for ( k=0; ; k++ ) { + o = xmlGetChild( n ,k); + if ( !o ) + break; + + if ( xmlGetName( o ) && !lstrcmp( xmlGetName( o ), _T("option"))) { + if (( v = xmlGetChild( o , "value" )) != NULL && xmlGetText( v )) { + if (( labelText = xmlGetAttrValue( o, _T("label"))) == NULL ) + labelText = xmlGetText( v ); + + if ( !lstrcmp( labelText, str )) + field << XCHILD( _T("value"), xmlGetText( v )); + } } } + mir_free( str ); + } } } + id++; + } + else if ( !_tcscmp( type, _T("fixed")) || !_tcscmp( type, _T("hidden"))) { + v = xmlGetChild( n , "value" ); + if ( v != NULL && xmlGetText( v ) != NULL ) + field << XCHILD( _T("value"), xmlGetText( v )); + } + else { // everything else is considered "text-single" or "text-private" + len = GetWindowTextLength( GetDlgItem( hFrame, id )); + str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 )); + GetDlgItemText( hFrame, id, str, len+1 ); + field << XCHILD( _T("value"), str ); + mir_free( str ); + id++; + } } + + return xi.copyNode( x ); +} + +struct JABBER_FORM_INFO +{ + ~JABBER_FORM_INFO(); + + CJabberProto* ppro; + HXML xNode; + TCHAR defTitle[128]; // Default title if no <title/> in xNode + RECT frameRect; // Clipping region of the frame to scroll + int frameHeight; // Height of the frame ( can be eliminated, redundant to frameRect ) + int formHeight; // Actual height of the form + int curPos; // Current scroll position + JABBER_FORM_SUBMIT_FUNC pfnSubmit; + void *userdata; +}; + +static INT_PTR CALLBACK JabberFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JABBER_FORM_INFO *jfi; + + switch ( msg ) { + case WM_INITDIALOG: + { + HXML n; + LONG frameExStyle; + + // lParam is ( JABBER_FORM_INFO * ) + TranslateDialogDefault( hwndDlg ); + ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE ); + jfi = ( JABBER_FORM_INFO * ) lParam; + if ( jfi != NULL ) { + // Set dialog title + if ( jfi->xNode!=NULL && ( n = xmlGetChild( jfi->xNode , "title" )) != NULL && xmlGetText( n ) != NULL ) + SetWindowText( hwndDlg, xmlGetText( n )); + else if ( jfi->defTitle != NULL ) + SetWindowText( hwndDlg, TranslateTS( jfi->defTitle )); + // Set instruction field + if ( jfi->xNode!=NULL && ( n = xmlGetChild( jfi->xNode , "instructions" )) != NULL && xmlGetText( n ) != NULL ) + JabberFormSetInstruction( hwndDlg, xmlGetText( n )); + else + { + if ( jfi->xNode != NULL && ( n = xmlGetChild( jfi->xNode , "title" )) != NULL && xmlGetText( n ) != NULL ) + JabberFormSetInstruction( hwndDlg, xmlGetText( n )); + else if ( jfi->defTitle != NULL ) + JabberFormSetInstruction( hwndDlg, TranslateTS( jfi->defTitle )); + } + + // Create form + if ( jfi->xNode != NULL ) { + RECT rect; + + GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &( jfi->frameRect )); + GetClientRect( GetDlgItem( hwndDlg, IDC_VSCROLL ), &rect ); + jfi->frameRect.right -= ( rect.right - rect.left ); + GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &rect ); + jfi->frameHeight = rect.bottom - rect.top; + JabberFormCreateUI( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode, &( jfi->formHeight )); + } + } + + if ( jfi->formHeight > jfi->frameHeight ) { + HWND hwndScroll; + + hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); + EnableWindow( hwndScroll, TRUE ); + SetScrollRange( hwndScroll, SB_CTL, 0, jfi->formHeight - jfi->frameHeight, FALSE ); + jfi->curPos = 0; + } + + // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children ) + frameExStyle = GetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE ); + frameExStyle |= WS_EX_CONTROLPARENT; + SetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle ); + + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) jfi ); + if ( jfi->pfnSubmit != NULL ) + EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE ); + } + return TRUE; + + case WM_CTLCOLORSTATIC: + if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) + { + return (INT_PTR)GetStockObject(WHITE_BRUSH); + } + + return NULL; + + case WM_MOUSEWHEEL: + { + int zDelta = GET_WHEEL_DELTA_WPARAM( wParam ); + if ( zDelta ) { + int nScrollLines=0; + SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0 ); + for (int i = 0; i < ( nScrollLines + 1 ) / 2; i++ ) + SendMessage( hwndDlg, WM_VSCROLL, ( zDelta < 0 ) ? SB_LINEDOWN : SB_LINEUP, 0 ); + } + } + break; + + case WM_VSCROLL: + jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + if ( jfi != NULL ) { + int pos = jfi->curPos; + switch ( LOWORD( wParam )) { + case SB_LINEDOWN: + pos += 15; + break; + case SB_LINEUP: + pos -= 15; + break; + case SB_PAGEDOWN: + pos += ( jfi->frameHeight - 10 ); + break; + case SB_PAGEUP: + pos -= ( jfi->frameHeight - 10 ); + break; + case SB_THUMBTRACK: + pos = HIWORD( wParam ); + break; + } + if ( pos > ( jfi->formHeight - jfi->frameHeight )) + pos = jfi->formHeight - jfi->frameHeight; + if ( pos < 0 ) + pos = 0; + if ( jfi->curPos != pos ) { + ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, jfi->curPos - pos, NULL, &( jfi->frameRect )); + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); + jfi->curPos = pos; + } + } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDC_SUBMIT: + jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + if ( jfi != NULL ) { + HXML n = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode ); + ( jfi->ppro->*(jfi->pfnSubmit))( n, jfi->userdata ); + xi.destroyNode( n ); + } + // fall through + case IDCANCEL: + case IDCLOSE: + DestroyWindow( hwndDlg ); + return TRUE; + } + break; + + case WM_CLOSE: + DestroyWindow( hwndDlg ); + break; + + case WM_DESTROY: + JabberFormDestroyUI( GetDlgItem( hwndDlg, IDC_FRAME )); + jfi = ( JABBER_FORM_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + delete jfi; + break; + } + + return FALSE; +} + +static VOID CALLBACK JabberFormCreateDialogApcProc( void* param ) +{ + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberFormDlgProc, ( LPARAM )param ); +} + +void CJabberProto::FormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ) +{ + JABBER_FORM_INFO *jfi = new JABBER_FORM_INFO; + memset( jfi, 0, sizeof( JABBER_FORM_INFO )); + jfi->ppro = this; + jfi->xNode = xi.copyNode( xNode ); + if ( defTitle ) + _tcsncpy( jfi->defTitle, defTitle, SIZEOF( jfi->defTitle )); + jfi->pfnSubmit = pfnSubmit; + jfi->userdata = userdata; + + CallFunctionAsync( JabberFormCreateDialogApcProc, jfi ); +} + +//======================================================================================= + +JABBER_FORM_INFO::~JABBER_FORM_INFO() +{ + xi.destroyNode( xNode ); + mir_free( userdata ); +} \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_form2.cpp b/protocols/JabberG/src/jabber_form2.cpp new file mode 100644 index 0000000000..f1936c9e73 --- /dev/null +++ b/protocols/JabberG/src/jabber_form2.cpp @@ -0,0 +1,1198 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_caps.h" + +#include "jabber_form2.h" + + +///////////////////////////////////////////////////////////////////////////////////////// +// FORM_TYPE Registry +namespace NSJabberRegistry +{ + // http://jabber.org/network/serverinfo + static TJabberDataFormRegisry_Field form_type_serverinfo[] = + { + { _T("abuse-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to abusive traffic") }, + { _T("feedback-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for customer feedback") }, + { _T("sales-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to sales and marketing") }, + { _T("security-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for communication related to security concerns") }, + { _T("support-addresses"), JDFT_LIST_MULTI, _T("One or more addresses for customer support") }, + }; + + // http://jabber.org/protocol/admin + static TJabberDataFormRegisry_Field form_type_admin[] = + { + { _T("accountjid"), JDFT_JID_SINGLE, _T("The Jabber ID of a single entity to which an operation applies") }, + { _T("accountjids"), JDFT_JID_MULTI, _T("The Jabber ID of one or more entities to which an operation applies") }, + { _T("activeuserjids"), JDFT_JID_MULTI, _T("The Jabber IDs associated with active sessions") }, + { _T("activeusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities that are active") }, + { _T("adminjids"), JDFT_JID_MULTI, _T("A list of entities with administrative privileges") }, + { _T("announcement"), JDFT_TEXT_MULTI, _T("The text of an announcement to be sent to active users or all users") }, + { _T("blacklistjids"), JDFT_JID_MULTI, _T("A list of entities with whom communication is blocked") }, + { _T("delay"), JDFT_LIST_MULTI, _T("The number of seconds to delay before applying a change") }, + { _T("disableduserjids"), JDFT_JID_MULTI, _T("The Jabber IDs that have been disabled") }, + { _T("disabledusersnum"), JDFT_TEXT_SINGLE, _T("The number of disabled entities") }, + { _T("email"), JDFT_TEXT_SINGLE, _T("The email address for a user") }, + { _T("given_name"), JDFT_TEXT_SINGLE, _T("The given (first) name of a user") }, + { _T("idleusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities that are idle") }, + { _T("ipaddresses"), JDFT_LIST_MULTI, _T("The IP addresses of an account's online sessions") }, + { _T("lastlogin"), JDFT_TEXT_SINGLE, _T("The last login time (per XEP-0082) of a user") }, + { _T("loginsperminute"), JDFT_TEXT_SINGLE, _T("The number of logins per minute for an account") }, + { _T("max_items"), JDFT_LIST_SINGLE, _T("The maximum number of items associated with a search or list") }, + { _T("motd"), JDFT_TEXT_MULTI, _T("The text of a message of the day") }, + { _T("onlineresources"), JDFT_TEXT_SINGLE, _T("The names of an account's online sessions") }, + { _T("onlineuserjids"), JDFT_JID_MULTI, _T("The Jabber IDs associated with online users") }, + { _T("onlineusersnum"), JDFT_TEXT_SINGLE, _T("The number of online entities") }, + { _T("password"), JDFT_TEXT_PRIVATE, _T("The password for an account") }, + { _T("password-verify"), JDFT_TEXT_PRIVATE, _T("Password verification") }, + { _T("registereduserjids"), JDFT_JID_MULTI, _T("A list of registered entities") }, + { _T("registeredusersnum"), JDFT_TEXT_SINGLE, _T("The number of registered entities") }, + { _T("rostersize"), JDFT_TEXT_SINGLE, _T("Number of roster items for an account") }, + { _T("stanzaspersecond"), JDFT_TEXT_SINGLE, _T("The number of stanzas being sent per second by an account") }, + { _T("surname"), JDFT_TEXT_SINGLE, _T("The family (last) name of a user") }, + { _T("welcome"), JDFT_TEXT_MULTI, _T("The text of a welcome message") }, + { _T("whitelistjids"), JDFT_JID_MULTI, _T("A list of entities with whom communication is allowed") }, + }; + + // http://jabber.org/protocol/muc#register + static TJabberDataFormRegisry_Field form_type_muc_register[] = + { + { _T("muc#register_first"), JDFT_TEXT_SINGLE, _T("First Name") }, + { _T("muc#register_last"), JDFT_TEXT_SINGLE, _T("Last Name") }, + { _T("muc#register_roomnick"), JDFT_TEXT_SINGLE, _T("Desired Nickname") }, + { _T("muc#register_url"), JDFT_TEXT_SINGLE, _T("Your URL") }, + { _T("muc#register_email"), JDFT_TEXT_SINGLE, _T("Email Address") }, + { _T("muc#register_faqentry"), JDFT_TEXT_MULTI, _T("FAQ Entry") }, + }; + + // http://jabber.org/protocol/muc#roomconfig + static TJabberDataFormRegisry_Field form_type_muc_roomconfig[] = + { + { _T("muc#roomconfig_allowinvites"), JDFT_BOOLEAN, _T("Whether to Allow Occupants to Invite Others") }, + { _T("muc#roomconfig_changesubject"), JDFT_BOOLEAN, _T("Whether to Allow Occupants to Change Subject") }, + { _T("muc#roomconfig_enablelogging"), JDFT_BOOLEAN, _T("Whether to Enable Logging of Room Conversations") }, + { _T("muc#roomconfig_lang"), JDFT_TEXT_SINGLE, _T("Natural Language for Room Discussions") }, + { _T("muc#roomconfig_maxusers"), JDFT_LIST_SINGLE, _T("Maximum Number of Room Occupants") }, + { _T("muc#roomconfig_membersonly"), JDFT_BOOLEAN, _T("Whether an Make Room Members-Only") }, + { _T("muc#roomconfig_moderatedroom"), JDFT_BOOLEAN, _T("Whether to Make Room Moderated") }, + { _T("muc#roomconfig_passwordprotectedroom"), JDFT_BOOLEAN, _T("Whether a Password is Required to Enter") }, + { _T("muc#roomconfig_persistentroom"), JDFT_BOOLEAN, _T("Whether to Make Room Persistent") }, + { _T("muc#roomconfig_presencebroadcast"), JDFT_LIST_MULTI, _T("Roles for which Presence is Broadcast") }, + { _T("muc#roomconfig_publicroom"), JDFT_BOOLEAN, _T("Whether to Allow Public Searching for Room") }, + { _T("muc#roomconfig_roomadmins"), JDFT_JID_MULTI, _T("Full List of Room Admins") }, + { _T("muc#roomconfig_roomdesc"), JDFT_TEXT_SINGLE, _T("Short Description of Room") }, + { _T("muc#roomconfig_roomname"), JDFT_TEXT_SINGLE, _T("Natural-Language Room Name") }, + { _T("muc#roomconfig_roomowners"), JDFT_JID_MULTI, _T("Full List of Room Owners") }, + { _T("muc#roomconfig_roomsecret"), JDFT_TEXT_PRIVATE, _T("The Room Password") }, + { _T("muc#roomconfig_whois"), JDFT_LIST_SINGLE, _T("Affiliations that May Discover Real JIDs of Occupants") }, + }; + + // http://jabber.org/protocol/pubsub#publish-options + static TJabberDataFormRegisry_Field form_type_publish_options[] = + { + { _T("pubsub#access_model"), JDFT_LIST_SINGLE, _T("Precondition: node configuration with the specified access model") }, + }; + + // http://jabber.org/protocol/pubsub#subscribe_authorization + static TJabberDataFormRegisry_Field form_type_subscribe_auth[] = + { + { _T("pubsub#allow"), JDFT_BOOLEAN, _T("Whether to allow the subscription") }, + { _T("pubsub#subid"), JDFT_TEXT_SINGLE, _T("The SubID of the subscription") }, + { _T("pubsub#node"), JDFT_TEXT_SINGLE, _T("The NodeID of the relevant node") }, + { _T("pubsub#subscriber_jid"), JDFT_JID_SINGLE, _T("The address (JID) of the subscriber") }, + }; + + // http://jabber.org/protocol/pubsub#subscribe_options + static TJabberDataFormRegisry_Field form_type_subscribe_options[] = + { + { _T("pubsub#deliver"), JDFT_BOOLEAN, _T("Whether an entity wants to receive or disable notifications") }, + { _T("pubsub#digest"), JDFT_BOOLEAN, _T("Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually") }, + { _T("pubsub#digest_frequency"), JDFT_TEXT_SINGLE, _T("The minimum number of milliseconds between sending any two notification digests") }, + { _T("pubsub#expire"), JDFT_TEXT_SINGLE, _T("The DateTime at which a leased subscription will end or has ended") }, + { _T("pubsub#include_body"), JDFT_BOOLEAN, _T("Whether an entity wants to receive an XMPP message body in addition to the payload format") }, + { _T("pubsub#show-values"), JDFT_LIST_MULTI, _T("The presence states for which an entity wants to receive notifications") }, + { _T("pubsub#subscription_type"), JDFT_LIST_SINGLE, _T("") }, + { _T("pubsub#subscription_depth"), JDFT_LIST_SINGLE, _T("") }, + }; + + // http://jabber.org/protocol/pubsub#node_config + static TJabberDataFormRegisry_Field form_type_node_config[] = + { + { _T("pubsub#access_model"), JDFT_LIST_SINGLE, _T("Who may subscribe and retrieve items") }, + { _T("pubsub#body_xslt"), JDFT_TEXT_SINGLE, _T("The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.") }, + { _T("pubsub#collection"), JDFT_TEXT_SINGLE, _T("The collection with which a node is affiliated") }, + { _T("pubsub#dataform_xslt"), JDFT_TEXT_SINGLE, _T("The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine") }, + { _T("pubsub#deliver_payloads"), JDFT_BOOLEAN, _T("Whether to deliver payloads with event notifications") }, + { _T("pubsub#itemreply"), JDFT_LIST_SINGLE, _T("Whether owners or publisher should receive replies to items") }, + { _T("pubsub#children_association_policy"), JDFT_LIST_SINGLE, _T("Who may associate leaf nodes with a collection") }, + { _T("pubsub#children_association_whitelist"), JDFT_JID_MULTI, _T("The list of JIDs that may associated leaf nodes with a collection") }, + { _T("pubsub#children"), JDFT_TEXT_MULTI, _T("The child nodes (leaf or collection) associated with a collection") }, + { _T("pubsub#children_max"), JDFT_TEXT_SINGLE, _T("The maximum number of child nodes that can be associated with a collection") }, + { _T("pubsub#max_items"), JDFT_TEXT_SINGLE, _T("The maximum number of items to persist") }, + { _T("pubsub#max_payload_size"), JDFT_TEXT_SINGLE, _T("The maximum payload size in bytes") }, + { _T("pubsub#node_type"), JDFT_LIST_SINGLE, _T("Whether the node is a leaf (default) or a collection") }, + { _T("pubsub#notify_config"), JDFT_BOOLEAN, _T("Whether to notify subscribers when the node configuration changes") }, + { _T("pubsub#notify_delete"), JDFT_BOOLEAN, _T("Whether to notify subscribers when the node is deleted") }, + { _T("pubsub#notify_retract"), JDFT_BOOLEAN, _T("Whether to notify subscribers when items are removed from the node") }, + { _T("pubsub#persist_items"), JDFT_BOOLEAN, _T("Whether to persist items to storage") }, + { _T("pubsub#presence_based_delivery"), JDFT_BOOLEAN, _T("Whether to deliver notifications to available users only") }, + { _T("pubsub#publish_model"), JDFT_LIST_SINGLE, _T("The publisher model") }, + { _T("pubsub#replyroom"), JDFT_JID_MULTI, _T("The specific multi-user chat rooms to specify for replyroom") }, + { _T("pubsub#replyto"), JDFT_JID_MULTI, _T("The specific JID(s) to specify for replyto") }, + { _T("pubsub#roster_groups_allowed"), JDFT_LIST_MULTI, _T("The roster group(s) allowed to subscribe and retrieve items") }, + { _T("pubsub#send_item_subscribe"), JDFT_BOOLEAN, _T("Whether to send items to new subscribers") }, + { _T("pubsub#subscribe"), JDFT_BOOLEAN, _T("Whether to allow subscriptions") }, + { _T("pubsub#title"), JDFT_TEXT_SINGLE, _T("A friendly name for the node") }, + { _T("pubsub#type"), JDFT_TEXT_SINGLE, _T("The type of node data, usually specified by the namespace of the payload (if any); MAY be list-single rather than text-single") }, + }; + + // http://jabber.org/protocol/pubsub#meta-data + static TJabberDataFormRegisry_Field form_type_metadata[] = + { + { _T("pubsub#contact"), JDFT_JID_MULTI, _T("The JIDs of those to contact with questions") }, + { _T("pubsub#creation_date"), JDFT_TEXT_SINGLE, _T("The datetime when the node was created") }, + { _T("pubsub#creator"), JDFT_JID_SINGLE, _T("The JID of the node creator") }, + { _T("pubsub#description"), JDFT_TEXT_SINGLE, _T("A description of the node") }, + { _T("pubsub#language"), JDFT_TEXT_SINGLE, _T("The default language of the node") }, + { _T("pubsub#num_subscribers"), JDFT_TEXT_SINGLE, _T("The number of subscribers to the node") }, + { _T("pubsub#owner"), JDFT_JID_MULTI, _T("The JIDs of those with an affiliation of owner") }, + { _T("pubsub#publisher"), JDFT_JID_MULTI, _T("The JIDs of those with an affiliation of publisher") }, + { _T("pubsub#title"), JDFT_TEXT_SINGLE, _T("The name of the node") }, + { _T("pubsub#type"), JDFT_TEXT_SINGLE, _T("Payload type") }, + }; + + // http://jabber.org/protocol/rc + static TJabberDataFormRegisry_Field form_type_rc[] = + { + { _T("auto-auth"), JDFT_BOOLEAN, _T("Whether to automatically authorize subscription requests") }, + { _T("auto-files"), JDFT_BOOLEAN, _T("Whether to automatically accept file transfers") }, + { _T("auto-msg"), JDFT_BOOLEAN, _T("Whether to automatically open new messages") }, + { _T("auto-offline"), JDFT_BOOLEAN, _T("Whether to automatically go offline when idle") }, + { _T("sounds"), JDFT_BOOLEAN, _T("Whether to play sounds") }, + { _T("files"), JDFT_LIST_MULTI, _T("A list of pending file transfers") }, + { _T("groupchats"), JDFT_LIST_MULTI, _T("A list of joined groupchat rooms") }, + { _T("status"), JDFT_LIST_SINGLE, _T("A presence or availability status") }, + { _T("status-message"), JDFT_TEXT_MULTI, _T("The status message text") }, + { _T("status-priority"), JDFT_TEXT_SINGLE, _T("The new priority for the client") }, + }; + + // jabber:iq:register + static TJabberDataFormRegisry_Field form_type_register[] = + { + { _T("username"), JDFT_TEXT_SINGLE, _T("Account name associated with the user") }, + { _T("nick"), JDFT_TEXT_SINGLE, _T("Familiar name of the user") }, + { _T("password"), JDFT_TEXT_PRIVATE, _T("Password or secret for the user") }, + { _T("name"), JDFT_TEXT_SINGLE, _T("Full name of the user") }, + { _T("first"), JDFT_TEXT_SINGLE, _T("First name or given name of the user") }, + { _T("last"), JDFT_TEXT_SINGLE, _T("Last name, surname, or family name of the user") }, + { _T("email"), JDFT_TEXT_SINGLE, _T("Email address of the user") }, + { _T("address"), JDFT_TEXT_SINGLE, _T("Street portion of a physical or mailing address") }, + { _T("city"), JDFT_TEXT_SINGLE, _T("Locality portion of a physical or mailing address") }, + { _T("state"), JDFT_TEXT_SINGLE, _T("Region portion of a physical or mailing address") }, + { _T("zip"), JDFT_TEXT_SINGLE, _T("Postal code portion of a physical or mailing address") }, + }; + + // jabber:iq:search + static TJabberDataFormRegisry_Field form_type_search[] = + { + { _T("first"), JDFT_TEXT_SINGLE, _T("First Name") }, + { _T("last"), JDFT_TEXT_SINGLE, _T("Family Name") }, + { _T("nick"), JDFT_TEXT_SINGLE, _T("Nickname") }, + { _T("email"), JDFT_TEXT_SINGLE, _T("Email Address") }, + }; + + // urn:xmpp:ssn + static TJabberDataFormRegisry_Field form_type_ssn[] = + { + { _T("accept"), JDFT_BOOLEAN, _T("Whether to accept the invitation") }, + { _T("continue"), JDFT_TEXT_SINGLE, _T("Another resource with which to continue the session") }, + { _T("disclosure"), JDFT_LIST_SINGLE, _T("Disclosure of content, decryption keys or identities") }, + { _T("http://jabber.org/protocol/chatstates"), JDFT_LIST_SINGLE, _T("Whether may send Chat State Notifications per XEP-0085") }, + { _T("http://jabber.org/protocol/xhtml-im"), JDFT_LIST_SINGLE, _T("Whether allowed to use XHTML-IM formatting per XEP-0071") }, + { _T("language"), JDFT_LIST_SINGLE, _T("Primary written language of the chat (each value appears in order of preference and conforms to RFC 4646 and the IANA registry)") }, + { _T("logging"), JDFT_LIST_SINGLE, _T("Whether allowed to log messages (i.e., whether Off-The-Record mode is required)") }, + { _T("renegotiate"), JDFT_BOOLEAN, _T("Whether to renegotiate the session") }, + { _T("security"), JDFT_LIST_SINGLE, _T("Minimum security level") }, + { _T("terminate"), JDFT_BOOLEAN, _T("Whether to terminate the session") }, + { _T("urn:xmpp:receipts"), JDFT_BOOLEAN, _T("Whether to enable Message Receipts per XEP-0184") }, + }; + + TJabberDataFormRegisry_Form form_types[] = + { + /*0157*/ { _T("http://jabber.org/network/serverinfo"), form_type_serverinfo, SIZEOF(form_type_serverinfo) }, + /*0133*/ { _T("http://jabber.org/protocol/admin"), form_type_admin, SIZEOF(form_type_admin) }, + /*0045*/ { _T("http://jabber.org/protocol/muc#register"), form_type_muc_register, SIZEOF(form_type_muc_register) }, + /*0045*/ { _T("http://jabber.org/protocol/muc#roomconfig"), form_type_muc_roomconfig, SIZEOF(form_type_muc_roomconfig) }, + /*0060*/ { _T("http://jabber.org/protocol/pubsub#publish-options"), form_type_publish_options, SIZEOF(form_type_publish_options) }, + /*0060*/ { _T("http://jabber.org/protocol/pubsub#subscribe_authorization"), form_type_subscribe_auth, SIZEOF(form_type_subscribe_auth) }, + /*0060*/ { _T("http://jabber.org/protocol/pubsub#subscribe_options"), form_type_subscribe_options, SIZEOF(form_type_subscribe_options) }, + /*0060*/ { _T("http://jabber.org/protocol/pubsub#node_config"), form_type_node_config, SIZEOF(form_type_node_config) }, + /*0060*/ { _T("http://jabber.org/protocol/pubsub#meta-data"), form_type_metadata, SIZEOF(form_type_metadata) }, + /*0146*/ { _T("http://jabber.org/protocol/rc"), form_type_rc, SIZEOF(form_type_rc) }, + /*0077*/ { _T("jabber:iq:register"), form_type_register, SIZEOF(form_type_register) }, + /*0055*/ { _T("jabber:iq:search"), form_type_search, SIZEOF(form_type_search) }, + /*0155*/ { _T("urn:xmpp:ssn"), form_type_ssn, SIZEOF(form_type_ssn) }, + }; +}; + +CJabberDataField::CJabberDataField(CJabberDataForm *form, XmlNode *node): + m_node(node), m_options(5), m_values(1), m_descriptions(1) +{ + m_typeName = JabberXmlGetAttrValue(m_node, "type"); + m_var = JabberXmlGetAttrValue(m_node, "var"); + m_label = JabberXmlGetAttrValue(m_node, "label"); + m_required = JabberXmlGetChild(m_node, "required") ? true : false; + + if (m_typeName) + { + if (!lstrcmp(m_typeName, _T("text-private"))) + m_type = JDFT_TEXT_PRIVATE; + else if (!lstrcmp(m_typeName, _T("text-multi")) || !lstrcmp(m_typeName, _T("jid-multi"))) + m_type = JDFT_TEXT_MULTI; + else if (!lstrcmp(m_typeName, _T("boolean"))) + m_type = JDFT_BOOLEAN; + else if (!lstrcmp(m_typeName, _T("list-single"))) + m_type = JDFT_LIST_SINGLE; + else if (!lstrcmp(m_typeName, _T("list-multi"))) + m_type = JDFT_LIST_MULTI; + else if (!lstrcmp(m_typeName, _T("fixed"))) + m_type = JDFT_FIXED; + else if (!lstrcmp(m_typeName, _T("hidden"))) + m_type = JDFT_HIDDEN; + else + m_type = JDFT_TEXT_SINGLE; + } else + { + m_typeName = _T("text-single"); + m_type = JDFT_TEXT_SINGLE; + } + + for (int i = 0; i < m_node->numChild; ++i) + { + if (!lstrcmpA(m_node->child[i]->name, "value")) + { + m_values.insert(m_node->child[i]->text, m_values.getCount()); + } else + if (!lstrcmpA(m_node->child[i]->name, "option")) + { + TOption *opt = new TOption; + opt->label = JabberXmlGetAttrValue(m_node->child[i], "label"); + opt->value = NULL; + if (XmlNode *p = JabberXmlGetChild(m_node->child[i], "value")) + opt->value = p->text; + m_options.insert(opt, m_options.getCount()); + } else + if (!lstrcmpA(m_node->child[i]->name, "desc")) + { + m_descriptions.insert(m_node->child[i]->text, m_descriptions.getCount()); + } + } +} + +CJabberDataField::~CJabberDataField() +{ + m_values.destroy(); + m_descriptions.destroy(); +} + +CJabberDataFieldSet::CJabberDataFieldSet(): + m_fields(5) +{ +} + +CJabberDataField *CJabberDataFieldSet::GetField(TCHAR *var) +{ + for (int i = 0; i < m_fields.getCount(); ++i) + if (!lstrcmp(m_fields[i].GetVar(), var)) + return &(m_fields[i]); + return NULL; +} + +CJabberDataForm::CJabberDataForm(XmlNode *node): + m_node(node), + m_form_type(0), + m_form_type_info(0), + m_title(0), + m_instructions(1), + m_items(1) +{ + m_typename = JabberXmlGetAttrValue(m_node, "type"); + + for (int i = 0; i < m_node->numChild; ++i) + { + XmlNode *child = m_node->child[i]; + if (!lstrcmpA(child->name, "field")) + { + CJabberDataField *field = new CJabberDataField(this, child); + m_fields.AddField(field); + + if ((field->GetType() == JDFT_HIDDEN) && !lstrcmp(field->GetVar(), _T("FORM_TYPE"))) + { + using NSJabberRegistry::form_types; + + m_form_type = field->GetValue(); + for (int j = 0; j < SIZEOF(form_types); ++j) + if (!lstrcmp(m_form_type, form_types[j].form_type)) + { + m_form_type_info = form_types + j; + break; + } + } + } else + if (!lstrcmpA(child->name, "title")) + { + m_title = child->text; + } else + if (!lstrcmpA(child->name, "instructions")) + { + m_instructions.insert(child->text, m_instructions.getCount()); + } else + if (!lstrcmpA(child->name, "reported")) + { + if (m_reported.GetCount()) + continue; // ignore second <reported/> -> error!!!!!!!!!!! + + for (int j = 0; j < child->numChild; ++j) + { + XmlNode *child2 = child->child[i]; + if (!lstrcmpA(child2->name, "field")) + { + CJabberDataField *field = new CJabberDataField(this, child2); + m_reported.AddField(field); + } + } + } else + if (!lstrcmpA(child->name, "item")) + { + CJabberDataFieldSet *item = new CJabberDataFieldSet; + m_items.insert(item); + + for (int j = 0; j < child->numChild; ++j) + { + XmlNode *child2 = child->child[i]; + if (!lstrcmpA(child2->name, "field")) + { + CJabberDataField *field = new CJabberDataField(this, child2); + item->AddField(field); + } + } + } + } +} + +CJabberDataForm::~CJabberDataForm() +{ +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// UI classes + +#define FORM_CONTROL_MINWIDTH 100 +#define FORM_CONTROL_HEIGHT 20 + +class CFormCtrlBase; + +class CJabberDlgDataPage +{ +public: + CJabberDlgDataPage(HWND hwndParent); + ~CJabberDlgDataPage(); + + void AddField(CJabberDataField *field); + XmlNode *FetchData(); + + HWND GetHwnd() { return m_hwnd; } + void Layout(); + + // internal usage + int AddControl(CFormCtrlBase *ctrl) + { + m_controls.insert(ctrl, m_controls.getCount()); + return m_controls.getCount(); + } + +private: + HWND m_hwnd; + OBJLIST<CFormCtrlBase> m_controls; + int m_scrollPos, m_height, m_dataHeight; + + BOOL DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + static BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +}; + +class CFormCtrlBase +{ +public: + CFormCtrlBase(CJabberDlgDataPage *parent, CJabberDataField *field): + m_field(field), m_parent(parent), + m_hwnd(NULL), m_hwndLabel(NULL) + { + } + + HWND GetHwnd() { return m_hwnd; } + void Init(); + + int Layout(HDWP hdwp, int x, int y, int w); + virtual XmlNode *FetchData() = 0; + +protected: + int m_id; + HWND m_hwnd, m_hwndLabel; + CJabberDataField *m_field; + CJabberDlgDataPage *m_parent; + + virtual void CreateControl() = 0; + virtual int GetHeight(int width) = 0; + SIZE GetControlTextSize(HWND hwnd, int w); + + void CreateLabel(); + void SetupFont(); + XmlNode *CreateNode(); +}; + +void CFormCtrlBase::Init() +{ + m_id = m_parent->AddControl(this); + CreateControl(); + SetupFont(); +} + +SIZE CFormCtrlBase::GetControlTextSize(HWND hwnd, int w) +{ + int length = GetWindowTextLength(hwnd) + 1; + TCHAR *text = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); + GetWindowText(hwnd, text, length); + + RECT rc; + SetRect(&rc, 0, 0, w, 0); + HDC hdc = GetDC(hwnd); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0)); + DrawText(hdc, text, -1, &rc, DT_CALCRECT|DT_WORDBREAK); + SelectObject(hdc, hfntSave); + ReleaseDC(hwnd, hdc); + + mir_free(text); + + SIZE res = { rc.right, rc.bottom }; + return res; +} + +int CFormCtrlBase::Layout(HDWP hdwp, int x, int y, int w) +{ + SIZE szLabel = {0}, szCtrl = {0}; + int h = 0; + + if (m_hwndLabel) + { + SIZE szLabel = GetControlTextSize(m_hwndLabel, w); + + szCtrl.cx = w - szLabel.cx - 5; + szCtrl.cy = GetHeight(szCtrl.cx); + if ((szCtrl.cx >= FORM_CONTROL_MINWIDTH) && (szCtrl.cy <= FORM_CONTROL_HEIGHT)) + { + DeferWindowPos(hdwp, m_hwndLabel, NULL, x, y + (szCtrl.cy - szLabel.cy) / 2, szLabel.cx, szLabel.cy, SWP_NOZORDER|SWP_SHOWWINDOW); + DeferWindowPos(hdwp, m_hwnd, NULL, x + szLabel.cx + 5, y, szCtrl.cx, szCtrl.cy, SWP_NOZORDER|SWP_SHOWWINDOW); + + h = szCtrl.cy; + } else + { + szCtrl.cx = w - 10; + szCtrl.cy = GetHeight(szCtrl.cx); + + DeferWindowPos(hdwp, m_hwndLabel, NULL, x, y, szLabel.cx, szLabel.cy, SWP_NOZORDER|SWP_SHOWWINDOW); + DeferWindowPos(hdwp, m_hwnd, NULL, x + 10, y + szLabel.cy + 2, szCtrl.cx, szCtrl.cy, SWP_NOZORDER|SWP_SHOWWINDOW); + + h = szLabel.cy + 2 + szCtrl.cy; + } + + } else + { + h = GetHeight(w); + DeferWindowPos(hdwp, m_hwnd, NULL, x, y, w, h, SWP_NOZORDER|SWP_SHOWWINDOW); + } + + return h; +} + +void CFormCtrlBase::CreateLabel() +{ + if (m_field->GetLabel()) + { + m_hwndLabel = CreateWindow(_T("static"), m_field->GetLabel(), + WS_CHILD|WS_VISIBLE/*|SS_CENTERIMAGE*/, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)-1, hInst, NULL); + } +} + +void CFormCtrlBase::SetupFont() +{ + if (m_hwnd) + { + HFONT hFont = (HFONT)SendMessage(GetParent(m_hwnd), WM_GETFONT, 0, 0); + if (m_hwnd) SendMessage(m_hwnd, WM_SETFONT, (WPARAM)hFont, 0); + if (m_hwndLabel) SendMessage(m_hwndLabel, WM_SETFONT, (WPARAM) hFont, 0); + } +} + +XmlNode *CFormCtrlBase::CreateNode() +{ + XmlNode* field = new XmlNode("field"); + field->addAttr("var", m_field->GetVar()); + field->addAttr("type", m_field->GetTypeName()); + return field; +} + +class CFormCtrlBoolean: public CFormCtrlBase +{ +public: + CFormCtrlBoolean(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + m_hwnd = CreateWindowEx(0, _T("button"), m_field->GetLabel(), + WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + if (m_field->GetValue() && !_tcscmp(m_field->GetValue(), _T("1"))) + SendMessage(m_hwnd, BM_SETCHECK, 1, 0); + } + + int GetHeight(int width) + { + return GetControlTextSize(m_hwnd, width - 20).cy; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + field->addChild("value", (SendMessage(m_hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) ? _T("1") : _T("0")); + return field; + } +}; + +class CFormCtrlFixed: public CFormCtrlBase +{ +public: + CFormCtrlFixed(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + m_hwnd = CreateWindow(_T("edit"), m_field->GetValue(), + WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)-1, hInst, NULL); + } + + int GetHeight(int width) + { + return GetControlTextSize(m_hwnd, width - 2).cy; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + for (int i = 0; i < m_field->GetValueCount(); ++i) + field->addChild("value", m_field->GetValue(i)); + return field; + } +}; + +class CFormCtrlHidden: public CFormCtrlBase +{ +public: + CFormCtrlHidden(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + } + + int GetHeight(int width) + { + return 0; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + for (int i = 0; i < m_field->GetValueCount(); ++i) + field->addChild("value", m_field->GetValue(i)); + return field; + } +}; +/* +class CFormCtrlJidMulti: public CFormCtrlBase +{ +public: + CFormCtrlJidMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + } + + int GetHeight(int width) + { + return 20; + } + + XmlNode *FetchData() + { + return NULL; + } +}; + +class CFormCtrlJidSingle: public CFormCtrlBase +{ +public: + CFormCtrlJidSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + } + + int GetHeight(int width) + { + return 20; + } + + XmlNode *FetchData() + { + return NULL; + } +}; +*/ +class CFormCtrlListMulti: public CFormCtrlBase +{ +public: + CFormCtrlListMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("listbox"), + NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_MULTIPLESEL, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + + for (int i = 0; i < m_field->GetOptionCount(); ++i) + { + DWORD dwIndex = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)m_field->GetOption(i)->label); + SendMessage(m_hwnd, LB_SETITEMDATA, dwIndex, (LPARAM)m_field->GetOption(i)->value); + for (int j = 0; j < m_field->GetValueCount(); ++j) + if (!lstrcmp_null(m_field->GetValue(j), m_field->GetOption(i)->value)) + { + SendMessage(m_hwnd, LB_SETSEL, TRUE, dwIndex); + break; + } + } + } + + int GetHeight(int width) + { + return 20 * 3; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + int count = SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); + for (int i = 0; i < count; ++i) + if (SendMessage(m_hwnd, LB_GETSEL, i, 0) > 0) + field->addChild("value", (TCHAR *)SendMessage(m_hwnd, LB_GETITEMDATA, i, 0)); + return field; + } +}; + +class CFormCtrlListSingle: public CFormCtrlBase +{ +public: + CFormCtrlListSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("combobox"), NULL, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + + for (int i = 0; i < m_field->GetOptionCount(); ++i) + { + DWORD dwIndex = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)m_field->GetOption(i)->label); + SendMessage(m_hwnd, CB_SETITEMDATA, dwIndex, (LPARAM)m_field->GetOption(i)->value); + if (!lstrcmp_null(m_field->GetValue(), m_field->GetOption(i)->value)) + SendMessage(m_hwnd, CB_SETCURSEL, dwIndex, 0); + } + } + + int GetHeight(int width) + { + return 20; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + int sel = SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + field->addChild("value", (TCHAR *)SendMessage(m_hwnd, CB_GETITEMDATA, sel, 0)); + return field; + } +}; + +class CFormCtrlTextMulti: public CFormCtrlBase +{ +public: + CFormCtrlTextMulti(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + int i, length = 1; + for (i = 0; i < m_field->GetValueCount(); ++i) + length += lstrlen(m_field->GetValue(i)) + 2; + + TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); + *str = 0; + for (i = 0; i < m_field->GetValueCount(); ++i) + { + if (i) lstrcat(str, _T("\r\n")); + lstrcat(str, m_field->GetValue(i)); + } + + m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), str, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + // WNDPROC oldWndProc = (WNDPROC)SetWindowLongPtr(item->hCtrl, GWL_WNDPROC, (LPARAM)JabberFormMultiLineWndProc); + // SetWindowLongPtr(item->hCtrl, GWL_USERDATA, (LONG) oldWndProc); + + mir_free(str); + } + + int GetHeight(int width) + { + return 20 * 3; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + int len = GetWindowTextLength(m_hwnd); + TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); + GetWindowText(m_hwnd, str, len+1); + TCHAR *p = str; + while (p != NULL) + { + TCHAR *q = _tcsstr( p, _T("\r\n")); + if (q) *q = '\0'; + field->addChild("value", p); + p = q ? q+2 : NULL; + } + mir_free(str); + return field; + } +}; + +class CFormCtrlTextSingle: public CFormCtrlBase +{ +public: + CFormCtrlTextSingle(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), m_field->GetValue(), + WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + } + + int GetHeight(int width) + { + return 20; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + int len = GetWindowTextLength(m_hwnd); + TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); + GetWindowText(m_hwnd, str, len+1); + field->addChild("value", str); + mir_free(str); + return field; + } +}; + +class CFormCtrlTextPrivate: public CFormCtrlBase +{ +public: + CFormCtrlTextPrivate(CJabberDlgDataPage *parent, CJabberDataField *field): CFormCtrlBase(parent, field) {} + + void CreateControl() + { + CreateLabel(); + m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), m_field->GetValue(), + WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, + 0, 0, 0, 0, + m_parent->GetHwnd(), (HMENU)m_id, hInst, NULL); + } + + int GetHeight(int width) + { + return 20; + } + + XmlNode *FetchData() + { + XmlNode *field = CreateNode(); + int len = GetWindowTextLength(m_hwnd); + TCHAR *str = (TCHAR *)mir_alloc(sizeof(TCHAR) * (len+1)); + GetWindowText(m_hwnd, str, len+1); + field->addChild("value", str); + mir_free(str); + return field; + } +}; + +CJabberDlgDataPage::CJabberDlgDataPage(HWND hwndParent): + m_controls(5) +{ + m_hwnd = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DATAFORM_PAGE), hwndParent, DlgProc, (LPARAM)this); + ShowWindow(m_hwnd, SW_SHOW); +} + +CJabberDlgDataPage::~CJabberDlgDataPage() +{ + DestroyWindow(m_hwnd); +} + +void CJabberDlgDataPage::AddField(CJabberDataField *field) +{ + CFormCtrlBase *ctrl = NULL; + + switch (field->GetType()) + { + case JDFT_BOOLEAN: ctrl = new CFormCtrlBoolean(this, field); break; + case JDFT_FIXED: ctrl = new CFormCtrlFixed(this, field); break; + case JDFT_HIDDEN: ctrl = new CFormCtrlHidden(this, field); break; + case JDFT_JID_MULTI: ctrl = new CFormCtrlTextMulti(this, field); break; + case JDFT_JID_SINGLE: ctrl = new CFormCtrlTextSingle(this, field); break; + case JDFT_LIST_MULTI: ctrl = new CFormCtrlListMulti(this, field); break; + case JDFT_LIST_SINGLE: ctrl = new CFormCtrlListSingle(this, field); break; + case JDFT_TEXT_MULTI: ctrl = new CFormCtrlTextMulti(this, field); break; + case JDFT_TEXT_PRIVATE: ctrl = new CFormCtrlTextPrivate(this, field); break; + case JDFT_TEXT_SINGLE: ctrl = new CFormCtrlTextSingle(this, field); break; + } + + if (ctrl) ctrl->Init(); +} + +XmlNode *CJabberDlgDataPage::FetchData() +{ + XmlNode *result = new XmlNode("x"); + result->addAttr("xmlns", JABBER_FEAT_DATA_FORMS); + result->addAttr("type", "submit"); + + for (int i = 0; i < m_controls.getCount(); ++i) + if (XmlNode *field = m_controls[i].FetchData()) + result->addChild(field); + + return result; +} + +void CJabberDlgDataPage::Layout() +{ + RECT rc; GetClientRect(m_hwnd, &rc); + int w = rc.right - 20; + int x = 10; + int y = 10; + + m_height = rc.bottom; + m_scrollPos = GetScrollPos(m_hwnd, SB_VERT); + + HDWP hdwp = BeginDeferWindowPos(m_controls.getCount()); + for (int i = 0; i < m_controls.getCount(); ++i) + if (int h = m_controls[i].Layout(hdwp, x, y - m_scrollPos, w)) + y += h + 5; + EndDeferWindowPos(hdwp); + + m_dataHeight = y + 5; + + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_DISABLENOSCROLL|SIF_PAGE|SIF_RANGE; + si.nPage = m_height; + si.nMin = 0; + si.nMax = m_dataHeight; + SetScrollInfo(m_hwnd, SB_VERT, &si, TRUE); +} + +BOOL CJabberDlgDataPage::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_DISABLENOSCROLL; + SetScrollInfo(m_hwnd, SB_VERT, &si, TRUE); + m_scrollPos = 0; + + break; + } + + case WM_MOUSEWHEEL: + { + int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); + if (zDelta) + { + int i, nScrollLines = 0; + SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0); + for (i = 0; i < (nScrollLines + 1) / 2; i++ ) + SendMessage(m_hwnd, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0); + } + + SetWindowLongPtr(m_hwnd, DWL_MSGRESULT, 0); + return TRUE; + } + + case WM_VSCROLL: + { + int pos = m_scrollPos; + switch (LOWORD(wParam)) + { + case SB_LINEDOWN: + pos += 15; + break; + case SB_LINEUP: + pos -= 15; + break; + case SB_PAGEDOWN: + pos += m_height - 10; + break; + case SB_PAGEUP: + pos -= m_height - 10; + break; + case SB_THUMBTRACK: + pos = HIWORD(wParam); + break; + } + + if (pos > m_dataHeight - m_height) pos = m_dataHeight - m_height; + if (pos < 0) pos = 0; + + if (m_scrollPos != pos) + { + ScrollWindow(m_hwnd, 0, m_scrollPos - pos, NULL, NULL); + SetScrollPos(m_hwnd, SB_VERT, pos, TRUE); + m_scrollPos = pos; + } + break; + } + + case WM_SIZE: + Layout(); + break; + } + + return FALSE; +} + +BOOL CJabberDlgDataPage::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CJabberDlgDataPage *pThis = NULL; + + if (msg == WM_INITDIALOG) + { + if (pThis = (CJabberDlgDataPage *)lParam) + pThis->m_hwnd = hwnd; + SetWindowLongPtr(hwnd, GWL_USERDATA, lParam); + } else + { + pThis = (CJabberDlgDataPage *)GetWindowLongPtr(hwnd, GWL_USERDATA); + } + + if (pThis) + { + BOOL result = pThis->DlgProc(msg, wParam, lParam); + if (msg == WM_DESTROY) + { + pThis->m_hwnd = NULL; + SetWindowLongPtr(hwnd, GWL_USERDATA, 0); + } + return result; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////// +// Data form control -- Window class support +const TCHAR *CCtrlJabberForm::ClassName = _T("JabberDataFormControl"); +bool CCtrlJabberForm::ClassRegistered = false; + +bool CCtrlJabberForm::RegisterClass() +{ + if (ClassRegistered) return true; + + WNDCLASSEX wcx = {0}; + wcx.cbSize = sizeof(wcx); + wcx.lpszClassName = ClassName; + wcx.lpfnWndProc = DefWindowProc; + wcx.hCursor = LoadCursor(NULL, IDC_ARROW); + wcx.hbrBackground = 0; + wcx.style = CS_GLOBALCLASS; + + if (::RegisterClassEx(&wcx)) + ClassRegistered = true; + + return ClassRegistered; +} + +bool CCtrlJabberForm::UnregisterClass() +{ + if (!ClassRegistered) return true; + + if (::UnregisterClass(ClassName, hInst) == 0) + ClassRegistered = false; + + return !ClassRegistered; +} + +///////////////////////////////////////////////////////////////////////////////// +// Data form control +CCtrlJabberForm::CCtrlJabberForm(CDlgBase* dlg, int ctrlId): + CCtrlBase(dlg, ctrlId), m_pForm(NULL), m_pDlgPage(NULL) +{ +} + +CCtrlJabberForm::~CCtrlJabberForm() +{ + if (m_pDlgPage) delete m_pDlgPage; +} + +void CCtrlJabberForm::OnInit() +{ + CSuper::OnInit(); + Subclass(); + SetupForm(); +} + +void CCtrlJabberForm::SetDataForm(CJabberDataForm *pForm) +{ + if (m_pDlgPage) + { + delete m_pDlgPage; + m_pDlgPage = NULL; + } + + m_pForm = pForm; + SetupForm(); +} + +XmlNode *CCtrlJabberForm::FetchData() +{ + return m_pDlgPage ? m_pDlgPage->FetchData() : NULL; +} + +void CCtrlJabberForm::SetupForm() +{ + if (!m_pForm || !m_hwnd) return; + + m_pDlgPage = new CJabberDlgDataPage(m_hwnd); + for (int i = 0; i < m_pForm->GetFields()->GetCount(); ++i) + m_pDlgPage->AddField(m_pForm->GetFields()->GetField(i)); + + Layout(); +} + +void CCtrlJabberForm::Layout() +{ + if (!m_pDlgPage) return; + + RECT rc; + GetClientRect(m_hwnd, &rc); + SetWindowPos(m_pDlgPage->GetHwnd(), NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER); +} + +LRESULT CCtrlJabberForm::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_SIZE: + { + Layout(); + break; + } + } + + return CSuper::CustomWndProc(msg, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////// +// testing +class CJabberDlgFormTest: public CDlgBase +{ +public: + CJabberDlgFormTest(CJabberDataForm *pForm): + CDlgBase(IDD_DATAFORM_TEST, NULL), + m_frm(this, IDC_DATAFORM) + { + m_frm.SetDataForm(pForm); + } + + int Resizer(UTILRESIZECONTROL *urc) + { + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + } + +private: + CCtrlJabberForm m_frm; +}; + +static VOID CALLBACK CreateDialogApcProc(void* param) +{ + XmlNode *node = (XmlNode *)param; + + CJabberDataForm form(node); + + CCtrlJabberForm::RegisterClass(); + CJabberDlgFormTest dlg(&form); + dlg.DoModal(); + + delete node; +} + +void LaunchForm(XmlNode *node) +{ + node = JabberXmlCopyNode(node); + CallFunctionAsync(CreateDialogApcProc, node); +} diff --git a/protocols/JabberG/src/jabber_form2.h b/protocols/JabberG/src/jabber_form2.h new file mode 100644 index 0000000000..051eb8571f --- /dev/null +++ b/protocols/JabberG/src/jabber_form2.h @@ -0,0 +1,190 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +enum TJabberDataFormType +{ + JDFT_BOOLEAN, + JDFT_FIXED, + JDFT_HIDDEN, + JDFT_JID_MULTI, + JDFT_JID_SINGLE, + JDFT_LIST_MULTI, + JDFT_LIST_SINGLE, + JDFT_TEXT_MULTI, + JDFT_TEXT_PRIVATE, + JDFT_TEXT_SINGLE, +}; + +struct TJabberDataFormRegisry_Field +{ + TCHAR *field; + TJabberDataFormType type; + TCHAR *description_en; + TCHAR *description_tr; +}; + +struct TJabberDataFormRegisry_Form +{ + TCHAR *form_type; + TJabberDataFormRegisry_Field *fields; + int count; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Forwards +class CJabberDlgDataForm; +class CJabberDataField; +class CJabberDataFieldSet; +class CJabberDataForm; +class CJabberDlgDataPage; + +///////////////////////////////////////////////////////////////////////////////////////// +// Data form classes +class CJabberDataField +{ +public: + struct TOption + { + TCHAR *label; + TCHAR *value; + }; + + CJabberDataField(CJabberDataForm *form, XmlNode *node); + ~CJabberDataField(); + + XmlNode *GetNode() { return m_node; } + + TCHAR *GetTypeName() { return m_typeName; } + TJabberDataFormType GetType() { return m_type; } + + TCHAR *GetVar() { return m_var; } + + bool IsRequired() { return m_required; } + TCHAR *GetDescription(int i) { return m_descriptions[i]; } + TCHAR *GetLabel() { return m_label; } + + int GetValueCount() { return m_values.getCount(); } + TCHAR *GetValue(int i = 0) { return m_values[i]; } + + int GetOptionCount() { return m_options.getCount(); } + TOption *GetOption(int i) { return &(m_options[i]); } + +private: + XmlNode *m_node; + CJabberDataFieldSet *m_fieldset; + + bool m_required; + TCHAR *m_var; + TCHAR *m_label; + TCHAR *m_typeName; + TJabberDataFormType m_type; + + OBJLIST<TOption> m_options; + LIST<TCHAR> m_values; + LIST<TCHAR> m_descriptions; +}; + +class CJabberDataFieldSet +{ +public: + CJabberDataFieldSet(); + + int GetCount() { return m_fields.getCount(); } + CJabberDataField *GetField(int i) { return &(m_fields[i]); } + CJabberDataField *GetField(TCHAR *var); + + void AddField(CJabberDataField *field) { m_fields.insert(field, m_fields.getCount()); } + +private: + OBJLIST<CJabberDataField> m_fields; +}; + +class CJabberDataForm +{ +public: + enum TFormType { TYPE_NONE, TYPE_FORM, TYPE_SUBMIT, TYPE_CANCEL, TYPE_RESULT }; + + CJabberDataForm(XmlNode *node); + ~CJabberDataForm(); + + TCHAR *GetTypeName() const { return m_typename; } + TFormType GetType() const { return m_type; } + TCHAR *GetFormType() const { return m_form_type; } + TCHAR *GetTitle() const { return m_title; } + int GetInstructionsCount() const { return m_instructions.getCount(); } + TCHAR *GetInstructions(int idx=0) const { return m_instructions[idx]; } + + CJabberDataFieldSet *GetFields() { return &m_fields; } + + CJabberDataFieldSet *GetReported() { return &m_reported; } + int GetItemCount() { return m_items.getCount(); } + CJabberDataFieldSet *GetItem(int i) { return &(m_items[i]); } + +private: + XmlNode *m_node; + + TCHAR *m_typename; + TFormType m_type; + + TCHAR *m_form_type; + TJabberDataFormRegisry_Form *m_form_type_info; + + TCHAR *m_title; + LIST<TCHAR> m_instructions; + + CJabberDataFieldSet m_fields; + CJabberDataFieldSet m_reported; + OBJLIST<CJabberDataFieldSet> m_items; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// UI Control +class CCtrlJabberForm: public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + static const TCHAR *ClassName; + static bool RegisterClass(); + static bool UnregisterClass(); + + CCtrlJabberForm(CDlgBase* dlg, int ctrlId); + ~CCtrlJabberForm(); + + void OnInit(); + void SetDataForm(CJabberDataForm *pForm); + XmlNode *FetchData(); + +protected: + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + +private: + static bool ClassRegistered; + + CJabberDataForm *m_pForm; + CJabberDlgDataPage *m_pDlgPage; + + void SetupForm(); + void Layout(); +}; diff --git a/protocols/JabberG/src/jabber_ft.cpp b/protocols/JabberG/src/jabber_ft.cpp new file mode 100644 index 0000000000..4ded28d84d --- /dev/null +++ b/protocols/JabberG/src/jabber_ft.cpp @@ -0,0 +1,551 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "jabber_iq.h" +#include "jabber_byte.h" +#include "jabber_ibb.h" +#include "jabber_caps.h" + +void CJabberProto::FtCancel( filetransfer* ft ) +{ + JABBER_LIST_ITEM *item; + JABBER_BYTE_TRANSFER *jbt; + JABBER_IBB_TRANSFER *jibb; + + Log( "Invoking JabberFtCancel()" ); + + // For file sending session that is still in si negotiation phase + if ( m_iqManager.ExpireByUserData( ft )) + return; + // For file receiving session that is still in si negotiation phase + LISTFOREACH(i, this, LIST_FTRECV) + { + item = ListGetItemPtrFromIndex( i ); + if ( item->ft == ft ) { + Log( "Canceling file receiving session while in si negotiation" ); + ListRemoveByIndex( i ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + delete ft; + return; + } + } + // For file transfer through bytestream + if (( jbt=ft->jbt ) != NULL ) { + Log( "Canceling bytestream session" ); + jbt->state = JBT_ERROR; + if ( jbt->hConn ) { + Log( "Force closing bytestream session" ); + Netlib_CloseHandle( jbt->hConn ); + jbt->hConn = NULL; + } + if ( jbt->hSendEvent ) SetEvent( jbt->hSendEvent ); + if ( jbt->hEvent ) SetEvent( jbt->hEvent ); + if ( jbt->hProxyEvent ) SetEvent( jbt->hProxyEvent ); + } + // For file transfer through IBB + if (( jibb=ft->jibb ) != NULL ) { + Log( "Canceling IBB session" ); + jibb->state = JIBB_ERROR; + m_iqManager.ExpireByUserData( jibb ); + } +} + +///////////////// File sending using stream initiation ///////////////////////// + +void CJabberProto::FtInitiate( TCHAR* jid, filetransfer* ft ) +{ + TCHAR *rs; + TCHAR *filename, *p; + int i; + TCHAR sid[9]; + + if ( jid==NULL || ft==NULL || !m_bJabberOnline || ( rs=ListGetBestClientResourceNamePtr( jid ))==NULL ) { + if ( ft ) { + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 ); + delete ft; + } + return; + } + ft->type = FT_SI; + for ( i=0; i<8; i++ ) + sid[i] = ( rand()%10 ) + '0'; + sid[8] = '\0'; + if ( ft->sid != NULL ) mir_free( ft->sid ); + ft->sid = mir_tstrdup( sid ); + filename = ft->std.ptszFiles[ ft->std.currentFileNumber ]; + if (( p = _tcsrchr( filename, '\\' )) != NULL ) + filename = p+1; + + TCHAR tszJid[ 512 ]; + mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), jid, rs ); + + XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnFtSiResult, JABBER_IQ_TYPE_SET, tszJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO, -1, ft )); + HXML si = iq << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) << XATTR( _T("id"), sid ) + << XATTR( _T("mime-type"), _T("binary/octet-stream")) << XATTR( _T("profile"), _T(JABBER_FEAT_SI_FT)); + si << XCHILDNS( _T("file"), _T(JABBER_FEAT_SI_FT)) << XATTR( _T("name"), filename) + << XATTRI64( _T("size"), ft->fileSize[ ft->std.currentFileNumber ] ) << XCHILD( _T("desc"), ft->szDescription); + + HXML field = si << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")) + << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) << XATTR( _T("type"), _T("list-single")); + + BOOL bDirect = m_options.BsDirect; + BOOL bProxy = m_options.BsProxyManual; + + // bytestreams support? + if ( bDirect || bProxy ) + field << XCHILD( _T("option")) << XCHILD( _T("value"), _T(JABBER_FEAT_BYTESTREAMS)); + + field << XCHILD( _T("option")) << XCHILD( _T("value"), _T(JABBER_FEAT_IBB)); + m_ThreadInfo->send( iq ); +} + +void CJabberProto::OnFtSiResult( HXML iqNode, CJabberIqInfo* pInfo ) +{ + HXML siNode, featureNode, xNode, fieldNode, valueNode; + filetransfer *ft = (filetransfer *)pInfo->GetUserData(); + if ( !ft ) return; + + if (( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) && pInfo->m_szFrom && pInfo->m_szTo ) { + if (( siNode = xmlGetChild( iqNode , "si" )) != NULL ) { + + // fix for very smart clients, like gajim + BOOL bDirect = m_options.BsDirect; + BOOL bProxy = m_options.BsProxyManual; + + if (( featureNode = xmlGetChild( siNode , "feature" )) != NULL ) { + if (( xNode = xmlGetChildByTag( featureNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS))) != NULL ) { + if (( fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("stream-method"))) != NULL ) { + if (( valueNode = xmlGetChild( fieldNode , "value" ))!=NULL && xmlGetText( valueNode )!=NULL ) { + if (( bDirect || bProxy ) && !_tcscmp( xmlGetText( valueNode ), _T(JABBER_FEAT_BYTESTREAMS))) { + // Start Bytestream session + JABBER_BYTE_TRANSFER *jbt = new JABBER_BYTE_TRANSFER; + ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER )); + jbt->srcJID = mir_tstrdup( pInfo->m_szTo ); + jbt->dstJID = mir_tstrdup( pInfo->m_szFrom ); + jbt->sid = mir_tstrdup( ft->sid ); + jbt->pfnSend = &CJabberProto::FtSend; + jbt->pfnFinal = &CJabberProto::FtSendFinal; + jbt->ft = ft; + ft->type = FT_BYTESTREAM; + ft->jbt = jbt; + JForkThread(( JThreadFunc )&CJabberProto::ByteSendThread, jbt ); + } else if ( !_tcscmp( xmlGetText( valueNode ), _T(JABBER_FEAT_IBB))) { + JABBER_IBB_TRANSFER *jibb = (JABBER_IBB_TRANSFER *) mir_alloc( sizeof ( JABBER_IBB_TRANSFER )); + ZeroMemory( jibb, sizeof( JABBER_IBB_TRANSFER )); + jibb->srcJID = mir_tstrdup( pInfo->m_szTo ); + jibb->dstJID = mir_tstrdup( pInfo->m_szFrom ); + jibb->sid = mir_tstrdup( ft->sid ); + jibb->pfnSend = &CJabberProto::FtIbbSend; + jibb->pfnFinal = &CJabberProto::FtSendFinal; + jibb->ft = ft; + ft->type = FT_IBB; + ft->jibb = jibb; + JForkThread(( JThreadFunc )&CJabberProto::IbbSendThread, jibb ); + } } } } } } } + else { + Log( "File transfer stream initiation request denied or failed" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ? ACKRESULT_DENIED : ACKRESULT_FAILED, ft, 0 ); + delete ft; + } +} + +BOOL CJabberProto::FtSend( HANDLE hConn, filetransfer* ft ) +{ + struct _stati64 statbuf; + int fd; + char* buffer; + int numRead; + + Log( "Sending [%s]", ft->std.ptszFiles[ ft->std.currentFileNumber ] ); + _tstati64( ft->std.ptszFiles[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size + if (( fd = _topen( ft->std.ptszFiles[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) { + Log( "File cannot be opened" ); + return FALSE; + } + + ft->std.flags |= PFTS_SENDING; + ft->std.currentFileSize = statbuf.st_size; + ft->std.currentFileProgress = 0; + + if (( buffer=( char* )mir_alloc( 2048 )) != NULL ) { + while (( numRead=_read( fd, buffer, 2048 )) > 0 ) { + if ( Netlib_Send( hConn, buffer, numRead, 0 ) != numRead ) { + mir_free( buffer ); + _close( fd ); + return FALSE; + } + ft->std.currentFileProgress += numRead; + ft->std.totalProgress += numRead; + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); + } + mir_free( buffer ); + } + _close( fd ); + return TRUE; +} + +BOOL CJabberProto::FtIbbSend( int blocksize, filetransfer* ft ) +{ + struct _stati64 statbuf; + int fd; + char* buffer; + int numRead; + + Log( "Sending [%s]", ft->std.ptszFiles[ ft->std.currentFileNumber ] ); + _tstati64( ft->std.ptszFiles[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size + if (( fd = _topen( ft->std.ptszFiles[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) { + Log( "File cannot be opened" ); + return FALSE; + } + + ft->std.flags |= PFTS_SENDING; + ft->std.currentFileSize = statbuf.st_size; + ft->std.currentFileProgress = 0; + + if (( buffer=( char* )mir_alloc( blocksize )) != NULL ) { + while (( numRead=_read( fd, buffer, blocksize )) > 0 ) { + int iqId = SerialNext(); + XmlNode msg( _T("message")); + xmlAddAttr( msg, _T("to"), ft->jibb->dstJID ); + msg << XATTRID( iqId ); + + // let others send data too + Sleep(2); + + char *encoded = JabberBase64Encode(buffer, numRead); + + msg << XCHILD( _T("data"), _A2T(encoded)) << XATTR( _T("xmlns"), _T(JABBER_FEAT_IBB)) + << XATTR( _T("sid"), ft->jibb->sid ) << XATTRI( _T("seq"), ft->jibb->wPacketId ); + + HXML ampNode = msg << XCHILDNS( _T("amp"), _T(JABBER_FEAT_AMP)); + ampNode << XCHILD( _T("rule")) << XATTR( _T("condition"), _T("deliver-at")) + << XATTR( _T("value"), _T("stored")) << XATTR( _T("action"), _T("error")); + ampNode << XCHILD( _T("rule")) << XATTR( _T("condition"), _T("match-resource")) + << XATTR( _T("value"), _T("exact")) << XATTR( _T("action"), _T("error")); + ft->jibb->wPacketId++; + + mir_free( encoded ); + + if ( ft->jibb->state == JIBB_ERROR || ft->jibb->bStreamClosed || m_ThreadInfo->send( msg ) == SOCKET_ERROR ) { + Log( "JabberFtIbbSend unsuccessful exit" ); + mir_free( buffer ); + _close( fd ); + return FALSE; + } + + ft->jibb->dwTransferredSize += (DWORD)numRead; + + ft->std.currentFileProgress += numRead; + ft->std.totalProgress += numRead; + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); + } + mir_free( buffer ); + } + _close( fd ); + return TRUE; +} + +void CJabberProto::FtSendFinal( BOOL success, filetransfer* ft ) +{ + if ( !success ) { + Log( "File transfer complete with error" ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ft->state == FT_DENIED ? ACKRESULT_DENIED : ACKRESULT_FAILED, ft, 0 ); + } + else { + if ( ft->std.currentFileNumber < ft->std.totalFiles-1 ) { + ft->std.currentFileNumber++; + replaceStrT( ft->std.tszCurrentFile, ft->std.ptszFiles[ ft->std.currentFileNumber ] ); + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 ); + FtInitiate( ft->jid, ft ); + return; + } + + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 ); + } + + delete ft; +} + +///////////////// File receiving through stream initiation ///////////////////////// + +void CJabberProto::FtHandleSiRequest( HXML iqNode ) +{ + const TCHAR* from, *sid, *str, *szId, *filename; + HXML siNode, fileNode, featureNode, xNode, fieldNode, n; + int i; + unsigned __int64 filesize; + + if ( !iqNode || + ( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL || + ( str = xmlGetAttrValue( iqNode, _T("type"))) == NULL || _tcscmp( str, _T("set")) || + ( siNode = xmlGetChildByTag( iqNode, "si", "xmlns", _T(JABBER_FEAT_SI))) == NULL ) + return; + + szId = xmlGetAttrValue( iqNode, _T("id")); + if (( sid = xmlGetAttrValue( siNode, _T("id"))) != NULL && + ( fileNode = xmlGetChildByTag( siNode, "file", "xmlns", _T(JABBER_FEAT_SI_FT))) != NULL && + ( filename = xmlGetAttrValue( fileNode, _T("name"))) != NULL && + ( str = xmlGetAttrValue( fileNode, _T("size"))) != NULL ) { + + filesize = _ttoi64( str ); + if (( featureNode = xmlGetChildByTag( siNode, "feature", "xmlns", _T(JABBER_FEAT_FEATURE_NEG))) != NULL && + ( xNode = xmlGetChildByTag( featureNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)))!=NULL && + ( fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("stream-method")))!=NULL ) { + + BOOL bIbbOnly = m_options.BsOnlyIBB; + HXML optionNode = NULL; + JABBER_FT_TYPE ftType = FT_OOB; + + if ( !bIbbOnly ) { + for ( i=0; ; i++ ) { + optionNode = xmlGetChild( fieldNode ,i); + if ( !optionNode ) + break; + + if ( !lstrcmp( xmlGetName( optionNode ), _T("option"))) { + if (( n = xmlGetChild( optionNode , "value" )) != NULL && xmlGetText( n )) { + if ( !_tcscmp( xmlGetText( n ), _T(JABBER_FEAT_BYTESTREAMS))) { + ftType = FT_BYTESTREAM; + break; + } } } } } + + // try IBB only if bytestreams support not found or BsOnlyIBB flag exists + if ( bIbbOnly || !optionNode ) { + for ( i=0; ; i++ ) { + optionNode = xmlGetChild( fieldNode ,i); + if ( !optionNode ) + break; + + if ( !lstrcmp( xmlGetName( optionNode ), _T("option"))) { + if (( n = xmlGetChild( optionNode , "value" )) != NULL && xmlGetText( n )) { + if ( !_tcscmp( xmlGetText( n ), _T(JABBER_FEAT_IBB))) { + ftType = FT_IBB; + break; + } } } } } + + if ( optionNode != NULL ) { + // Found known stream mechanism + filetransfer* ft = new filetransfer( this ); + ft->dwExpectedRecvFileSize = filesize; + ft->jid = mir_tstrdup( from ); + ft->std.hContact = HContactFromJID( from ); + ft->sid = mir_tstrdup( sid ); + ft->iqId = mir_tstrdup( szId ); + ft->type = ftType; + ft->std.totalFiles = 1; + ft->std.tszCurrentFile = mir_tstrdup( filename ); + ft->std.totalBytes = ft->std.currentFileSize = filesize; + + PROTORECVFILET pre = { 0 }; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time( NULL ); + pre.ptszFiles = ( TCHAR** )&filename; + pre.lParam = ( LPARAM )ft; + if (( n = xmlGetChild( fileNode , "desc" )) != NULL ) + pre.tszDescription = ( TCHAR* )xmlGetText( n ); + + CCSDATA ccs = { ft->std.hContact, PSR_FILE, 0, ( LPARAM )&pre }; + CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); + return; + } + else { + // Unknown stream mechanism + XmlNodeIq iq( _T("error"), szId, from ); + HXML e = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); + e << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + e << XCHILDNS( _T("no-valid-streams"), _T(JABBER_FEAT_SI)); + m_ThreadInfo->send( iq ); + return; + } } } + + // Bad stream initiation, reply with bad-profile + XmlNodeIq iq( _T("error"), szId, from ); + HXML e = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); + e << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + e << XCHILDNS( _T("bad-profile"), _T(JABBER_FEAT_SI)); + m_ThreadInfo->send( iq ); +} + +void CJabberProto::FtAcceptSiRequest( filetransfer* ft ) +{ + if ( !m_bJabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return; + + JABBER_LIST_ITEM *item; + if (( item=ListAdd( LIST_FTRECV, ft->sid )) != NULL ) { + item->ft = ft; + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), ft->iqId, ft->jid ) + << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) + << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")) + << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) + << XCHILD( _T("value"), _T(JABBER_FEAT_BYTESTREAMS))); +} } + +void CJabberProto::FtAcceptIbbRequest( filetransfer* ft ) +{ + if ( !m_bJabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return; + + JABBER_LIST_ITEM *item; + if (( item=ListAdd( LIST_FTRECV, ft->sid )) != NULL ) { + item->ft = ft; + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), ft->iqId, ft->jid ) + << XCHILDNS( _T("si"), _T(JABBER_FEAT_SI)) + << XCHILDNS( _T("feature"), _T(JABBER_FEAT_FEATURE_NEG)) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")) + << XCHILD( _T("field")) << XATTR( _T("var"), _T("stream-method")) + << XCHILD( _T("value"), _T(JABBER_FEAT_IBB))); +} } + +BOOL CJabberProto::FtHandleBytestreamRequest( HXML iqNode, CJabberIqInfo* pInfo ) +{ + HXML queryNode = pInfo->GetChildNode(); + + const TCHAR* sid; + JABBER_LIST_ITEM *item; + + if (( sid = xmlGetAttrValue( queryNode, _T("sid"))) != NULL && ( item = ListGetItemPtr( LIST_FTRECV, sid )) != NULL ) { + // Start Bytestream session + JABBER_BYTE_TRANSFER *jbt = new JABBER_BYTE_TRANSFER; + ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER )); + jbt->iqNode = xi.copyNode( iqNode ); + jbt->pfnRecv = &CJabberProto::FtReceive; + jbt->pfnFinal = &CJabberProto::FtReceiveFinal; + jbt->ft = item->ft; + item->ft->jbt = jbt; + JForkThread(( JThreadFunc )&CJabberProto::ByteReceiveThread, jbt ); + ListRemove( LIST_FTRECV, sid ); + return TRUE; + } + + Log( "File transfer invalid bytestream initiation request received" ); + return TRUE; +} + +BOOL CJabberProto::FtHandleIbbRequest( HXML iqNode, BOOL bOpen ) +{ + if ( !iqNode ) return FALSE; + + const TCHAR *id = xmlGetAttrValue( iqNode, _T("id")); + const TCHAR *from = xmlGetAttrValue( iqNode, _T("from")); + const TCHAR *to = xmlGetAttrValue( iqNode, _T("to")); + if ( !id || !from || !to ) return FALSE; + + HXML ibbNode = xmlGetChildByTag( iqNode, bOpen ? "open" : "close", "xmlns", _T(JABBER_FEAT_IBB)); + if ( !ibbNode ) return FALSE; + + const TCHAR *sid = xmlGetAttrValue( ibbNode, _T("sid")); + if ( !sid ) return FALSE; + + // already closed? + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTRECV, sid ); + if ( !item ) { + m_ThreadInfo->send( + XmlNodeIq( _T("error"), id, from ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + return FALSE; + } + + // open event + if ( bOpen ) { + if ( !item->jibb ) { + JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * ) mir_alloc( sizeof( JABBER_IBB_TRANSFER )); + ZeroMemory( jibb, sizeof( JABBER_IBB_TRANSFER )); + jibb->srcJID = mir_tstrdup( from ); + jibb->dstJID = mir_tstrdup( to ); + jibb->sid = mir_tstrdup( sid ); + jibb->pfnRecv = &CJabberProto::FtReceive; + jibb->pfnFinal = &CJabberProto::FtReceiveFinal; + jibb->ft = item->ft; + item->ft->jibb = jibb; + item->jibb = jibb; + JForkThread(( JThreadFunc )&CJabberProto::IbbReceiveThread, jibb ); + + m_ThreadInfo->send( XmlNodeIq( _T("result"), id, from )); + return TRUE; + } + // stream already open + m_ThreadInfo->send( + XmlNodeIq( _T("error"), id, from ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + return FALSE; + } + + // close event && stream already open + if ( item->jibb && item->jibb->hEvent ) { + item->jibb->bStreamClosed = TRUE; + SetEvent( item->jibb->hEvent ); + + m_ThreadInfo->send( XmlNodeIq( _T("result"), id, from )); + return TRUE; + } + + ListRemove( LIST_FTRECV, sid ); + + return FALSE; +} + +int CJabberProto::FtReceive( HANDLE, filetransfer* ft, char* buffer, int datalen ) +{ + if ( ft->create() == -1 ) + return -1; + + __int64 remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress; + if ( remainingBytes > 0 ) { + int writeSize = ( remainingBytes<datalen ) ? remainingBytes : datalen; + if ( _write( ft->fileId, buffer, writeSize ) != writeSize ) { + Log( "_write() error" ); + return -1; + } + + ft->std.currentFileProgress += writeSize; + ft->std.totalProgress += writeSize; + JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std ); + return ( ft->std.currentFileSize == ft->std.currentFileProgress ) ? 0 : writeSize; + } + + return 0; +} + +void CJabberProto::FtReceiveFinal( BOOL success, filetransfer* ft ) +{ + if ( success ) { + Log( "File transfer complete successfully" ); + ft->complete(); + } + else Log( "File transfer complete with error" ); + + delete ft; +} diff --git a/protocols/JabberG/src/jabber_groupchat.cpp b/protocols/JabberG/src/jabber_groupchat.cpp new file mode 100644 index 0000000000..b442588fc0 --- /dev/null +++ b/protocols/JabberG/src/jabber_groupchat.cpp @@ -0,0 +1,1374 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" + +#define GC_SERVER_LIST_SIZE 5 + +int JabberGcGetStatus(JABBER_GC_AFFILIATION a, JABBER_GC_ROLE r); +int JabberGcGetStatus(JABBER_RESOURCE_STATUS *r); + +struct JabberGcRecentInfo +{ + TCHAR *room, *server, *nick, *password; + CJabberProto* ppro; + + JabberGcRecentInfo( CJabberProto* proto ) + { + ppro = proto; + room = server = nick = password = NULL; + } + JabberGcRecentInfo( CJabberProto* proto, const TCHAR *_room, const TCHAR *_server, const TCHAR *_nick = NULL, const TCHAR *_password = NULL) + { + ppro = proto; + room = server = nick = password = NULL; + fillData(_room, _server, _nick, _password); + } + JabberGcRecentInfo( CJabberProto* proto, const TCHAR *jid) + { + ppro = proto; + room = server = nick = password = NULL; + fillData(jid); + } + JabberGcRecentInfo( CJabberProto* proto, int iRecent) + { + ppro = proto; + room = server = nick = password = NULL; + loadRecent(iRecent); + } + + ~JabberGcRecentInfo() + { + cleanup(); + } + + void cleanup() + { + mir_free(room); + mir_free(server); + mir_free(nick); + mir_free(password); + room = server = nick = password = NULL; + } + + BOOL equals(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL, const TCHAR *password = NULL) + { + return + null_strequals(this->room, room) && + null_strequals(this->server, server) && + null_strequals(this->nick, nick) && + null_strequals(this->password, password); + } + + BOOL equalsnp(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL) + { + return + null_strequals(this->room, room) && + null_strequals(this->server, server) && + null_strequals(this->nick, nick); + } + + void fillForm(HWND hwndDlg) + { + SetDlgItemText(hwndDlg, IDC_SERVER, server ? server : _T("")); + SetDlgItemText(hwndDlg, IDC_ROOM, room ? room : _T("")); + SetDlgItemText(hwndDlg, IDC_NICK, nick ? nick : _T("")); + SetDlgItemText(hwndDlg, IDC_PASSWORD, password ? password : _T("")); + } + + void fillData(const TCHAR *room, const TCHAR *server, const TCHAR *nick = NULL, const TCHAR *password = NULL) + { + cleanup(); + this->room = room ? mir_tstrdup(room) : NULL; + this->server = server ? mir_tstrdup(server) : NULL; + this->nick = nick ? mir_tstrdup(nick) : NULL; + this->password = password ? mir_tstrdup(password) : NULL; + } + + void fillData(const TCHAR *jid) + { + TCHAR *room, *server, *nick=NULL; + room = NEWTSTR_ALLOCA(jid); + server = _tcschr(room, _T('@')); + if (server) + { + *server++ = 0; + nick = _tcschr(server, _T('/')); + if (nick) *nick++ = 0; + } else + { + server = room; + room = NULL; + } + + fillData(room, server, nick); + } + + BOOL loadRecent(int iRecent) + { + DBVARIANT dbv; + char setting[MAXMODULELABELLENGTH]; + + cleanup(); + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_server", iRecent); + if ( !ppro->JGetStringT( NULL, setting, &dbv )) { + server = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_room", iRecent); + if ( !ppro->JGetStringT( NULL, setting, &dbv )) { + room = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_nick", iRecent); + if ( !ppro->JGetStringT( NULL, setting, &dbv )) { + nick = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_passwordW", iRecent); + password = ppro->JGetStringCrypt(NULL, setting); + + return room || server || nick || password; + } + + void saveRecent(int iRecent) + { + char setting[MAXMODULELABELLENGTH]; + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_server", iRecent); + if (server) + ppro->JSetStringT(NULL, setting, server); + else + ppro->JDeleteSetting(NULL, setting); + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_room", iRecent); + if (room) + ppro->JSetStringT(NULL, setting, room); + else + ppro->JDeleteSetting(NULL, setting); + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_nick", iRecent); + if (nick) + ppro->JSetStringT(NULL, setting, nick); + else + ppro->JDeleteSetting(NULL, setting); + + mir_snprintf(setting, sizeof(setting), "rcMuc_%d_passwordW", iRecent); + if (password) + ppro->JSetStringCrypt(NULL, setting, password); + else + ppro->JDeleteSetting(NULL, setting); + } + +private: + BOOL null_strequals(const TCHAR *str1, const TCHAR *str2) + { + if (!str1 && !str2) return TRUE; + if (!str1 && str2 && !*str2) return TRUE; + if (!str2 && str1 && !*str1) return TRUE; + + if (!str1 && str2) return FALSE; + if (!str2 && str1) return FALSE; + + return !lstrcmp(str1, str2); + } +}; + +JABBER_RESOURCE_STATUS* CJabberProto::GcFindResource(JABBER_LIST_ITEM *item, const TCHAR *resource) +{ + JABBER_RESOURCE_STATUS *res = NULL; + + EnterCriticalSection( &m_csLists ); + JABBER_RESOURCE_STATUS *r = item->resource; + for ( int i=0; i<item->resourceCount; i++ ) { + if ( !_tcscmp( r[i].resourceName, resource )) { + res = &r[i]; + break; + } + } + LeaveCriticalSection( &m_csLists ); + + return res; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleJoinGroupchat( WPARAM, LPARAM ) +{ + if ( jabberChatDllPresent ) + GroupchatJoinRoomByJid( NULL, NULL ); + else + JabberChatDllError(); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnJoinChat( WPARAM wParam, LPARAM ) +{ + DBVARIANT nick, jid; + HANDLE hContact = ( HANDLE )wParam; + if ( JGetStringT( hContact, "ChatRoomID", &jid )) + return 0; + + if ( JGetStringT( hContact, "MyNick", &nick )) + if ( JGetStringT( NULL, "Nick", &nick )) { + JFreeVariant( &jid ); + return 0; + } + + TCHAR *password = JGetStringCrypt( hContact, "LoginPassword" ); + + if ( JGetWord( hContact, "Status", 0 ) != ID_STATUS_ONLINE ) { + if ( !jabberChatDllPresent ) + JabberChatDllError(); + else { + TCHAR* p = _tcschr( jid.ptszVal, '@' ); + if ( p != NULL ) { + *p++ = 0; + GroupchatJoinRoom( p, jid.ptszVal, nick.ptszVal, password ); + } } } + + mir_free( password ); + JFreeVariant( &nick ); + JFreeVariant( &jid ); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnLeaveChat( WPARAM wParam, LPARAM ) +{ + DBVARIANT jid; + HANDLE hContact = ( HANDLE )wParam; + if ( JGetStringT( hContact, "ChatRoomID", &jid )) + return 0; + + if ( JGetWord( hContact, "Status", 0 ) != ID_STATUS_OFFLINE ) { + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, jid.ptszVal ); + if ( item != NULL ) + GcQuit( item, 0, NULL ); + } + + JFreeVariant( &jid ); + return 0; +} + +void CJabberProto::GroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password, bool autojoin ) +{ + JabberGcRecentInfo info( this ); + + int i = 0; + bool found = false; + for (i = 0 ; i < 5; ++i) + { + if (!info.loadRecent(i)) + continue; + + if (info.equals(room, server, nick, password)) + { + found = true; + break; + } + } + + if (!found) + { + for (int i = 4; i--; ) + { + if (info.loadRecent(i)) + info.saveRecent(i + 1); + } + + info.fillData(room, server, nick, password); + info.saveRecent(0); + } + + TCHAR text[512]; + mir_sntprintf( text, SIZEOF(text), _T("%s@%s/%s"), room, server, nick ); + + JABBER_LIST_ITEM* item = ListAdd( LIST_CHATROOM, text ); + item->bAutoJoin = autojoin; + replaceStrT( item->nick, nick ); + replaceStrT( item->password, info.password ); + + int status = ( m_iStatus == ID_STATUS_INVISIBLE ) ? ID_STATUS_ONLINE : m_iStatus; + XmlNode x( _T("x")); x << XATTR( _T("xmlns"), _T(JABBER_FEAT_MUC)); + if ( info.password && info.password[0] ) + x << XCHILD( _T("password"), info.password ); + + if (m_options.GcLogChatHistory) { + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, SIZEOF(setting), "muc_%s@%s_lastevent", _T2A(room), _T2A(server)); + time_t lasteventtime = this->JGetDword( NULL, setting, 0 ); + if ( lasteventtime > 0 ) { + _tzset(); + lasteventtime += _timezone + 1; + struct tm* time = localtime(&lasteventtime); + TCHAR lasteventdate[40]; + mir_sntprintf(lasteventdate, SIZEOF(lasteventdate), _T("%04d-%02d-%02dT%02d:%02d:%02dZ"), + time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); + x << XCHILD( _T("history")) << XATTR( _T("since"), lasteventdate); + } + } + + SendPresenceTo( status, text, x ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Join Dialog + +static int sttTextLineHeight = 16; + +struct RoomInfo +{ + enum Overlay { ROOM_WAIT, ROOM_FAIL, ROOM_BOOKMARK, ROOM_DEFAULT }; + Overlay overlay; + TCHAR *line1, *line2; +}; + +static int sttRoomListAppend(HWND hwndList, RoomInfo::Overlay overlay, const TCHAR *line1, const TCHAR *line2, const TCHAR *name) +{ + RoomInfo *info = (RoomInfo *)mir_alloc(sizeof(RoomInfo)); + info->overlay = overlay; + info->line1 = line1 ? mir_tstrdup(line1) : 0; + info->line2 = line2 ? mir_tstrdup(line2) : 0; + + int id = SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM)name); + SendMessage(hwndList, CB_SETITEMDATA, id, (LPARAM)info); + SendMessage(hwndList, CB_SETITEMHEIGHT, id, sttTextLineHeight * 2); + return id; +} + +void CJabberProto::OnIqResultDiscovery(HXML iqNode, CJabberIqInfo *pInfo) +{ + if (!iqNode || !pInfo) + return; + + HWND hwndList = (HWND)pInfo->GetUserData(); + SendMessage(hwndList, CB_SHOWDROPDOWN, FALSE, 0); + SendMessage(hwndList, CB_RESETCONTENT, 0, 0); + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) + { + HXML query = xmlGetChild( iqNode , "query" ); + if ( !query ) + { + sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, + TranslateT("Jabber Error"), + TranslateT("Failed to retrieve room list from server."), + _T("")); + } else + { + bool found = false; + HXML item; + for ( int i = 1; item = xmlGetNthChild( query, _T("item"), i ); i++ ) + { + const TCHAR *jid = xmlGetAttrValue( item, _T("jid")); + TCHAR *name = NEWTSTR_ALLOCA(jid); + if (name) + { + if (TCHAR *p = _tcschr(name, _T('@'))) + *p = 0; + } else + { + name = _T(""); + } + + sttRoomListAppend(hwndList, + ListGetItemPtr(LIST_BOOKMARK, jid) ? RoomInfo::ROOM_BOOKMARK : RoomInfo::ROOM_DEFAULT, + xmlGetAttrValue( item, _T("name")), + jid, name); + + found = true; + } + + if (!found) + { + sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, + TranslateT("Jabber Error"), + TranslateT("No rooms available on server."), + _T("")); + } + } + } else + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ) + { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, + TranslateT("Jabber Error"), + str, + _T("")); + mir_free( str ); + } else + { + sttRoomListAppend(hwndList, RoomInfo::ROOM_FAIL, + TranslateT("Jabber Error"), + TranslateT("Room list request timed out."), + _T("")); + } + + SendMessage(hwndList, CB_SHOWDROPDOWN, TRUE, 0); +} + +static void sttJoinDlgShowRecentItems(HWND hwndDlg, int newCount) +{ + RECT rcTitle, rcLastItem; + GetWindowRect(GetDlgItem(hwndDlg, IDC_TXT_RECENT), &rcTitle); + GetWindowRect(GetDlgItem(hwndDlg, IDC_RECENT5), &rcLastItem); + + ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_RECENT), newCount ? SW_SHOW : SW_HIDE); + + int oldCount = 5; + for (int idc = IDC_RECENT1; idc <= IDC_RECENT5; ++idc) + ShowWindow(GetDlgItem(hwndDlg, idc), (idc - IDC_RECENT1 < newCount) ? SW_SHOW : SW_HIDE); + + int curRecentHeight = rcLastItem.bottom - rcTitle.top - (5 - oldCount) * (rcLastItem.bottom - rcLastItem.top); + int newRecentHeight = rcLastItem.bottom - rcTitle.top - (5 - newCount) * (rcLastItem.bottom - rcLastItem.top); + if (!newCount) newRecentHeight = 0; + int offset = newRecentHeight - curRecentHeight; + + RECT rc; + int ctrls[] = { IDC_BOOKMARKS, IDOK, IDCANCEL }; + for (int i = 0; i < SIZEOF(ctrls); ++i) + { + GetWindowRect(GetDlgItem(hwndDlg, ctrls[i]), &rc); + MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2); + SetWindowPos(GetDlgItem(hwndDlg, ctrls[i]), NULL, rc.left, rc.top + offset, 0, 0, SWP_NOSIZE|SWP_NOZORDER); + } + + GetWindowRect(hwndDlg, &rc); + SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top+offset, SWP_NOMOVE|SWP_NOZORDER); +} + +class CJabberDlgGcJoin: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgGcJoin(CJabberProto *proto, TCHAR *jid); + +protected: + TCHAR *m_jid; + + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); +}; + +CJabberDlgGcJoin::CJabberDlgGcJoin(CJabberProto *proto, TCHAR *jid) : + CSuper(proto, IDD_GROUPCHAT_JOIN, NULL), + m_jid(mir_tstrdup(jid)) +{ + m_autoClose = 0; +} + +void CJabberDlgGcJoin::OnInitDialog() +{ + CSuper::OnInitDialog(); + + WindowSetIcon( m_hwnd, m_proto, "group" ); + + JabberGcRecentInfo *info = NULL; + if ( m_jid ) + info = new JabberGcRecentInfo( m_proto, m_jid ); + else + { + OpenClipboard(m_hwnd); + HANDLE hData = GetClipboardData(CF_UNICODETEXT); + + if (hData) + { + TCHAR *buf = (TCHAR *)GlobalLock(hData); + if (buf && _tcschr(buf, _T('@')) && !_tcschr(buf, _T(' '))) + info = new JabberGcRecentInfo( m_proto, buf ); + GlobalUnlock(hData); + } + CloseClipboard(); + } + + if (info) + { + info->fillForm(m_hwnd); + delete info; + } + + DBVARIANT dbv; + if ( !m_proto->JGetStringT( NULL, "Nick", &dbv )) { + SetDlgItemText( m_hwnd, IDC_NICK, dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else { + TCHAR* nick = JabberNickFromJID( m_proto->m_szJabberJID ); + SetDlgItemText( m_hwnd, IDC_NICK, nick ); + mir_free( nick ); + } + + { + TEXTMETRIC tm = {0}; + HDC hdc = GetDC(m_hwnd); + GetTextMetrics(hdc, &tm); + ReleaseDC(m_hwnd, hdc); + sttTextLineHeight = tm.tmHeight; + SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_SETITEMHEIGHT, -1, sttTextLineHeight-1); + } + + { + LOGFONT lf = {0}; + HFONT hfnt = (HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_GETFONT, 0, 0); + GetObject(hfnt, sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), TRUE); + } + + SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_proto->LoadIconEx("bookmarks")); + SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONADDTOOLTIP, (WPARAM)"Bookmarks", 0); + SendDlgItemMessage(m_hwnd, IDC_BOOKMARKS, BUTTONSETASPUSHBTN, TRUE, 0); + + m_proto->ComboLoadRecentStrings(m_hwnd, IDC_SERVER, "joinWnd_rcSvr"); + + int i = 0; + for ( ; i < 5; ++i) + { + TCHAR jid[JABBER_MAX_JID_LEN]; + JabberGcRecentInfo info( m_proto ); + if (info.loadRecent(i)) + { + mir_sntprintf(jid, SIZEOF(jid), _T("%s@%s (%s)"), + info.room, info.server, + info.nick ? info.nick : TranslateT("<no nick>")); + SetDlgItemText(m_hwnd, IDC_RECENT1+i, jid); + } else + { + break; + } + } + sttJoinDlgShowRecentItems(m_hwnd, i); +} + +void CJabberDlgGcJoin::OnClose() +{ + CSuper::OnClose(); +} + +void CJabberDlgGcJoin::OnDestroy() +{ + g_ReleaseIcon(( HICON )SendDlgItemMessage( m_hwnd, IDC_BOOKMARKS, BM_SETIMAGE, IMAGE_ICON, 0 )); + m_proto->m_pDlgJabberJoinGroupchat = NULL; + DeleteObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_RECENT, WM_GETFONT, 0, 0)); + + CSuper::OnDestroy(); + + mir_free( m_jid ); m_jid = NULL; +} + +INT_PTR CJabberDlgGcJoin::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + TCHAR text[128]; + + switch ( msg ) { + case WM_DELETEITEM: + { + LPDELETEITEMSTRUCT lpdis = (LPDELETEITEMSTRUCT)lParam; + if (lpdis->CtlID != IDC_ROOM) + break; + + RoomInfo *info = (RoomInfo *)lpdis->itemData; + if (info->line1) mir_free(info->line1); + if (info->line2) mir_free(info->line2); + mir_free(info); + + break; + } + + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; + if (lpmis->CtlID != IDC_ROOM) + break; + + lpmis->itemHeight = 2*sttTextLineHeight; + if (lpmis->itemID == -1) + lpmis->itemHeight = sttTextLineHeight-1; + + break; + } + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + if (lpdis->CtlID != IDC_ROOM) + break; + + if (lpdis->itemID < 0) + break; + + RoomInfo *info = (RoomInfo *)SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_GETITEMDATA, lpdis->itemID, 0); + COLORREF clLine1, clLine2, clBack; + + if (lpdis->itemState & ODS_SELECTED) + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + clBack = GetSysColor(COLOR_HIGHLIGHT); + clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); + } else + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); + clBack = GetSysColor(COLOR_WINDOW); + clLine1 = GetSysColor(COLOR_WINDOWTEXT); + } + clLine2 = RGB( + GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, + GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, + GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 + ); + + SetBkMode(lpdis->hDC, TRANSPARENT); + + RECT rc; + + rc = lpdis->rcItem; + rc.bottom -= (rc.bottom - rc.top) / 2; + rc.left += 20; + SetTextColor(lpdis->hDC, clLine1); + DrawText(lpdis->hDC, info->line1, lstrlen(info->line1), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); + + rc = lpdis->rcItem; + rc.top += (rc.bottom - rc.top) / 2; + rc.left += 20; + SetTextColor(lpdis->hDC, clLine2); + DrawText(lpdis->hDC, info->line2, lstrlen(info->line2), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); + + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("group"), 16, 16, 0, NULL, DI_NORMAL); + switch (info->overlay) { + case RoomInfo::ROOM_WAIT: + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_progress"), 16, 16, 0, NULL, DI_NORMAL); + break; + case RoomInfo::ROOM_FAIL: + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_fail"), 16, 16, 0, NULL, DI_NORMAL); + break; + case RoomInfo::ROOM_BOOKMARK: + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, m_proto->LoadIconEx("disco_ok"), 16, 16, 0, NULL, DI_NORMAL); + break; + } + } + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDC_SERVER: + switch (HIWORD(wParam)) { + case CBN_EDITCHANGE: + case CBN_SELCHANGE: + { + int iqid = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA); + if (iqid) + { + m_proto->m_iqManager.ExpireIq(iqid); + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, 0); + } + SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_RESETCONTENT, 0, 0); + } + break; + } + break; + + case IDC_ROOM: + switch (HIWORD(wParam)) { + case CBN_DROPDOWN: + if (!SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_GETCOUNT, 0, 0)) + { + int iqid = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA); + if (iqid) + { + m_proto->m_iqManager.ExpireIq(iqid); + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, 0); + } + + SendDlgItemMessage(m_hwnd, IDC_ROOM, CB_RESETCONTENT, 0, 0); + + int len = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_SERVER)) + 1; + TCHAR *server = (TCHAR *)_alloca(len * sizeof(TCHAR)); + GetWindowText(GetDlgItem(m_hwnd, IDC_SERVER), server, len); + + if (*server) + { + sttRoomListAppend(GetDlgItem(m_hwnd, IDC_ROOM), RoomInfo::ROOM_WAIT, TranslateT("Loading..."), TranslateT("Please wait for room list to download."), _T("")); + + CJabberIqInfo *pInfo = m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultDiscovery, JABBER_IQ_TYPE_GET, server, 0, -1, (void *)GetDlgItem(m_hwnd, IDC_ROOM)); + pInfo->SetTimeout(30000); + XmlNodeIq iq(pInfo); + iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); + m_proto->m_ThreadInfo->send(iq); + + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_ROOM), GWLP_USERDATA, pInfo->GetIqId()); + } else + { + sttRoomListAppend(GetDlgItem(m_hwnd, IDC_ROOM), RoomInfo::ROOM_FAIL, + TranslateT("Jabber Error"), + TranslateT("Please specify groupchat directory first."), + _T("")); + } + } + break; + } + break; + + case IDC_BOOKMARKS: + { + HMENU hMenu = CreatePopupMenu(); + + LISTFOREACH(i, m_proto, LIST_BOOKMARK) + { + JABBER_LIST_ITEM *item = 0; + if (item = m_proto->ListGetItemPtrFromIndex(i)) + if (!lstrcmp(item->type, _T("conference"))) + AppendMenu(hMenu, MF_STRING, (UINT_PTR)item, item->name); + } + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)-1, TranslateT("Bookmarks...")); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); + + RECT rc; GetWindowRect(GetDlgItem(m_hwnd, IDC_BOOKMARKS), &rc); + CheckDlgButton(m_hwnd, IDC_BOOKMARKS, TRUE); + int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, NULL); + CheckDlgButton(m_hwnd, IDC_BOOKMARKS, FALSE); + DestroyMenu(hMenu); + + if ( res == -1 ) + m_proto->OnMenuHandleBookmarks( 0, 0 ); + else if (res) { + JABBER_LIST_ITEM *item = (JABBER_LIST_ITEM *)res; + TCHAR *room = NEWTSTR_ALLOCA(item->jid); + if (room) { + TCHAR *server = _tcschr(room, _T('@')); + if (server) { + *server++ = 0; + + SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_SERVER, CBN_EDITCHANGE), (LPARAM)GetDlgItem(m_hwnd, IDC_SERVER)); + + SetDlgItemText(m_hwnd, IDC_SERVER, server); + SetDlgItemText(m_hwnd, IDC_ROOM, room); + SetDlgItemText(m_hwnd, IDC_NICK, item->nick); + SetDlgItemText(m_hwnd, IDC_PASSWORD, item->password); + } } } } + break; + + case IDC_RECENT1: + case IDC_RECENT2: + case IDC_RECENT3: + case IDC_RECENT4: + case IDC_RECENT5: + { + JabberGcRecentInfo info( m_proto, LOWORD( wParam ) - IDC_RECENT1); + info.fillForm(m_hwnd); + if (GetAsyncKeyState(VK_CONTROL)) + break; + } + // fall through + + case IDOK: + { + GetDlgItemText( m_hwnd, IDC_SERVER, text, SIZEOF( text )); + TCHAR* server = NEWTSTR_ALLOCA( text ), *room; + + m_proto->ComboAddRecentString(m_hwnd, IDC_SERVER, "joinWnd_rcSvr", server); + + GetDlgItemText( m_hwnd, IDC_ROOM, text, SIZEOF( text )); + room = NEWTSTR_ALLOCA( text ); + + GetDlgItemText( m_hwnd, IDC_NICK, text, SIZEOF( text )); + TCHAR* nick = NEWTSTR_ALLOCA( text ); + + GetDlgItemText( m_hwnd, IDC_PASSWORD, text, SIZEOF( text )); + TCHAR* password = NEWTSTR_ALLOCA( text ); + m_proto->GroupchatJoinRoom( server, room, nick, password ); + } + // fall through + case IDCANCEL: + Close(); + break; + } + break; + case WM_JABBER_CHECK_ONLINE: + if ( !m_proto->m_bJabberOnline ) + EndDialog( m_hwnd, 0 ); + break; + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +void CJabberProto::GroupchatJoinRoomByJid( HWND, TCHAR *jid ) +{ + if (m_pDlgJabberJoinGroupchat) + SetForegroundWindow(m_pDlgJabberJoinGroupchat->GetHwnd()); + else { + m_pDlgJabberJoinGroupchat = new CJabberDlgGcJoin(this, jid); + m_pDlgJabberJoinGroupchat->Show(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGroupchatProcessPresence - handles the group chat presence packet + +struct JabberGroupchatChangeNicknameParam +{ + JabberGroupchatChangeNicknameParam( CJabberProto* ppro_, const TCHAR* jid_ ) : + ppro( ppro_ ), + jid( mir_tstrdup( jid_ )) + {} + + ~JabberGroupchatChangeNicknameParam() + { mir_free( jid ); + } + + CJabberProto* ppro; + TCHAR* jid; +}; + +static VOID CALLBACK JabberGroupchatChangeNickname( void* arg ) +{ + JabberGroupchatChangeNicknameParam* param = ( JabberGroupchatChangeNicknameParam* )arg; + if ( param == NULL ) + return; + + JABBER_LIST_ITEM* item = param->ppro->ListGetItemPtr( LIST_CHATROOM, param->jid ); + if ( item != NULL ) { + TCHAR szBuffer[ 1024 ]; + TCHAR szCaption[ 1024 ]; + szBuffer[ 0 ] = _T('\0'); + + TCHAR* roomName = item->name ? item->name : item->jid; + mir_sntprintf( szCaption, SIZEOF(szCaption), _T("%s <%s>"), TranslateT( "Change nickname in" ), roomName ); + if ( item->nick ) + mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s"), item->nick ); + + if ( param->ppro->EnterString( szBuffer, SIZEOF(szBuffer), szCaption, JES_COMBO, "gcNick_" )) { + TCHAR text[ 1024 ]; + replaceStrT( item->nick, szBuffer ); + mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, szBuffer ); + param->ppro->SendPresenceTo( param->ppro->m_iStatus, text, NULL ); + } } + + delete param; +} + +static int sttGetStatusCode( HXML node ) +{ + HXML statusNode = xmlGetChild( node , "status" ); + if ( statusNode == NULL ) + return -1; + + const TCHAR* statusCode = xmlGetAttrValue( statusNode, _T("code")); + if ( statusCode == NULL ) + return -1; + + return _ttol( statusCode ); +} + +void CJabberProto::RenameParticipantNick( JABBER_LIST_ITEM* item, const TCHAR* oldNick, HXML itemNode ) +{ + const TCHAR* newNick = xmlGetAttrValue( itemNode, _T("nick")); + const TCHAR* jid = xmlGetAttrValue( itemNode, _T("jid")); + if ( newNick == NULL ) + return; + + for ( int i=0; i < item->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& RS = item->resource[i]; + if ( !lstrcmp( RS.resourceName, oldNick )) { + replaceStrT( RS.resourceName, newNick ); + + if ( !lstrcmp( item->nick, oldNick )) { + replaceStrT( item->nick, newNick ); + + HANDLE hContact = HContactFromJID( item->jid ); + if ( hContact != NULL ) + JSetStringT( hContact, "MyNick", newNick ); + } + + GCDEST gcd = { m_szModuleName, NULL, GC_EVENT_CHUID }; + gcd.ptszID = item->jid; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.ptszNick = oldNick; + gce.ptszText = newNick; + if (jid != NULL) + gce.ptszUserInfo = jid; + gce.time = time(0); + gce.dwFlags = GC_TCHAR; + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + + gcd.iType = GC_EVENT_NICK; + gce.ptszNick = oldNick; + gce.ptszUID = newNick; + gce.ptszText = newNick; + CallServiceSync( MS_GC_EVENT, NULL, ( LPARAM )&gce ); + break; +} } } + +void CJabberProto::GroupchatProcessPresence( HXML node ) +{ + HXML showNode, statusNode, itemNode, n, priorityNode; + const TCHAR* from; + int status, newRes = 0; + bool bStatusChanged = false; + BOOL roomCreated; + + if ( !node || !xmlGetName( node ) || lstrcmp( xmlGetName( node ), _T("presence"))) return; + if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; + + const TCHAR* resource = _tcschr( from, '/' ); + if ( resource == NULL || *++resource == '\0' ) + return; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, from ); + if ( item == NULL ) + return; + + JABBER_RESOURCE_STATUS* r = GcFindResource(item, resource); + + HXML nNode = xmlGetChildByTag( node, "nick", "xmlns", _T(JABBER_FEAT_NICK)); + if ( nNode == NULL ) + nNode = xmlGetChildByTag( node, "nick:nick", "xmlns:nick", _T(JABBER_FEAT_NICK)); + + const TCHAR* cnick = nNode ? xmlGetText( nNode ) : NULL; + const TCHAR* nick = cnick ? cnick : (r && r->nick ? r->nick : resource); + + // process custom nick change + if ( cnick && r && r->nick && _tcscmp( cnick, r->nick )) + replaceStrT( r->nick, cnick ); + + HXML xNode = xmlGetChildByTag( node, "x", "xmlns", _T(JABBER_FEAT_MUC_USER)); + HXML xUserNode = xmlGetChildByTag( node, "user:x", "xmlns:user", _T(JABBER_FEAT_MUC_USER)); + + itemNode = xmlGetChild( xNode , "item" ); + if ( itemNode == NULL ) + itemNode = xmlGetChild( xUserNode , "user:item" ); + + const TCHAR* type = xmlGetAttrValue( node, _T("type")); + + // entering room or a usual room presence + if ( type == NULL || !_tcscmp( type, _T("available"))) { + TCHAR* room = JabberNickFromJID( from ); + if ( room == NULL ) + return; + + GcLogCreate( item ); + item->iChatState = 0; + + // Update status of room participant + status = ID_STATUS_ONLINE; + if (( showNode = xmlGetChild( node , "show" )) != NULL ) { + if ( xmlGetText( showNode ) != NULL ) { + if ( !_tcscmp( xmlGetText( showNode ) , _T("away"))) status = ID_STATUS_AWAY; + else if ( !_tcscmp( xmlGetText( showNode ) , _T("xa"))) status = ID_STATUS_NA; + else if ( !_tcscmp( xmlGetText( showNode ) , _T("dnd"))) status = ID_STATUS_DND; + else if ( !_tcscmp( xmlGetText( showNode ) , _T("chat"))) status = ID_STATUS_FREECHAT; + } } + + statusNode = xmlGetChild( node , "status" ); + if ( statusNode == NULL ) + statusNode = xmlGetChild( node , "user:status" ); + + const TCHAR* str = statusNode ? xmlGetText( statusNode ) : NULL; + + char priority = 0; + if (( priorityNode = xmlGetChild( node , "priority" )) != NULL && xmlGetText( priorityNode ) != NULL ) + priority = (char)_ttoi( xmlGetText( priorityNode )); + + if (JABBER_RESOURCE_STATUS *oldRes = ListFindResource(LIST_CHATROOM, from)) + if ((oldRes->status != status) || lstrcmp_null(oldRes->statusMessage, str)) + bStatusChanged = true; + + newRes = ( ListAddResource( LIST_CHATROOM, from, status, str, priority, cnick ) == 0 ) ? 0 : GC_EVENT_JOIN; + + roomCreated = FALSE; + + bool bAffiliationChanged = false; + bool bRoleChanged = false; + + // Check additional MUC info for this user + if ( itemNode != NULL ) { + if ( r == NULL ) + r = GcFindResource(item, resource); + if ( r != NULL ) { + JABBER_GC_AFFILIATION affiliation = r->affiliation; + JABBER_GC_ROLE role = r->role; + + if (( str = xmlGetAttrValue( itemNode, _T("affiliation"))) != NULL ) { + if ( !_tcscmp( str, _T("owner"))) affiliation = AFFILIATION_OWNER; + else if ( !_tcscmp( str, _T("admin"))) affiliation = AFFILIATION_ADMIN; + else if ( !_tcscmp( str, _T("member"))) affiliation = AFFILIATION_MEMBER; + else if ( !_tcscmp( str, _T("none"))) affiliation = AFFILIATION_NONE; + else if ( !_tcscmp( str, _T("outcast"))) affiliation = AFFILIATION_OUTCAST; + } + if (( str = xmlGetAttrValue( itemNode, _T("role"))) != NULL ) { + if ( !_tcscmp( str, _T("moderator"))) role = ROLE_MODERATOR; + else if ( !_tcscmp( str, _T("participant"))) role = ROLE_PARTICIPANT; + else if ( !_tcscmp( str, _T("visitor"))) role = ROLE_VISITOR; + else role = ROLE_NONE; + } + + if ( (role != ROLE_NONE) && (JabberGcGetStatus(r) != JabberGcGetStatus(affiliation, role))) { + GcLogUpdateMemberStatus( item, resource, nick, NULL, GC_EVENT_REMOVESTATUS, NULL ); + if (!newRes) newRes = GC_EVENT_ADDSTATUS; + } + + if (affiliation != r->affiliation) { + r->affiliation = affiliation; + bAffiliationChanged = true; + } + + if (role != r->role) { + r->role = role; + if (r->role != ROLE_NONE) + bRoleChanged = true; + } + + if ( str = xmlGetAttrValue( itemNode, _T("jid"))) + replaceStrT( r->szRealJid, str ); + } + } + + if ( sttGetStatusCode( xNode ) == 201 ) + roomCreated = TRUE; + + // show status change if needed + if (bStatusChanged) + if (JABBER_RESOURCE_STATUS *res = ListFindResource(LIST_CHATROOM, from)) + GcLogShowInformation(item, res, INFO_STATUS); + + // Update groupchat log window + GcLogUpdateMemberStatus( item, resource, nick, str, newRes, NULL ); + if (r && bAffiliationChanged) GcLogShowInformation(item, r, INFO_AFFILIATION); + if (r && bRoleChanged) GcLogShowInformation(item, r, INFO_ROLE); + + // update clist status + HANDLE hContact = HContactFromJID( from ); + if ( hContact != NULL ) + JSetWord( hContact, "Status", status ); + + // Update room status + //if ( item->status != ID_STATUS_ONLINE ) { + // item->status = ID_STATUS_ONLINE; + // JSetWord( hContact, "Status", ( WORD )ID_STATUS_ONLINE ); + // JabberLog( "Room %s online", from ); + //} + + // Check <created/> + if ( roomCreated || + (( n = xmlGetChild( node , "created" ))!=NULL && + ( str = xmlGetAttrValue( n, _T("xmlns")))!=NULL && + !_tcscmp( str, _T("http://jabber.org/protocol/muc#owner")))) { + // A new room just created by me + // Request room config + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, item->jid ) << XQUERY( xmlnsOwner )); + } + + mir_free( room ); + } + + // leaving room + else if ( !_tcscmp( type, _T("unavailable"))) { + const TCHAR* str = 0; + if ( xNode != NULL && item->nick != NULL ) { + HXML reasonNode = xmlGetChild( itemNode , "reason" ); + str = xmlGetAttrValue( itemNode, _T( "jid" )); + + int iStatus = sttGetStatusCode( xNode ); + if (iStatus == 301 && r != NULL) + GcLogShowInformation(item, r, INFO_BAN); + + if ( !lstrcmp( resource, item->nick )) { + switch( iStatus ) { + case 301: + case 307: + GcQuit( item, iStatus, reasonNode ); + return; + + case 303: + RenameParticipantNick( item, resource, itemNode ); + return; + } } + else { + switch( iStatus ) { + case 303: + RenameParticipantNick( item, resource, itemNode ); + return; + + case 301: + case 307: + case 322: + ListRemoveResource( LIST_CHATROOM, from ); + GcLogUpdateMemberStatus( item, resource, nick, str, GC_EVENT_KICK, reasonNode, iStatus ); + return; + } } } + + statusNode = xmlGetChild( node , "status" ); + GcLogUpdateMemberStatus( item, resource, nick, str, GC_EVENT_PART, statusNode ); + ListRemoveResource( LIST_CHATROOM, from ); + + HANDLE hContact = HContactFromJID( from ); + if ( hContact != NULL ) + JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); + } + + // processing room errors + else if ( !_tcscmp( type, _T("error"))) { + int errorCode = 0; + HXML errorNode = xmlGetChild( node , "error" ); + TCHAR* str = JabberErrorMsg( errorNode, &errorCode ); + + if ( errorCode == JABBER_ERROR_CONFLICT ) { + TCHAR newNick[256] = { 0 }; + if (++item->iChatState == 1 && + JGetStringT(NULL, "GcAltNick", newNick, SIZEOF(newNick)) != NULL && + newNick[0] != _T('\0')) + { + replaceStrT(item->nick, newNick); + TCHAR text[1024] = { 0 }; + mir_sntprintf(text, SIZEOF(text), _T("%s/%s"), item->jid, newNick); + SendPresenceTo(m_iStatus, text, NULL); + } + else { + CallFunctionAsync( JabberGroupchatChangeNickname, new JabberGroupchatChangeNicknameParam( this, from )); + item->iChatState = 0; + } + mir_free( str ); + return; + } + + MsgPopup( NULL, str, TranslateT( "Jabber Error" )); + + if ( item != NULL) + if ( !item->bChatActive ) ListRemove( LIST_CHATROOM, from ); + mir_free( str ); +} } + +void CJabberProto::GroupchatProcessMessage( HXML node ) +{ + HXML n, xNode, m; + const TCHAR* from, *type, *p, *nick, *resource; + JABBER_LIST_ITEM *item; + + if ( !xmlGetName( node ) || lstrcmp( xmlGetName( node ), _T("message"))) return; + if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; + if (( item = ListGetItemPtr( LIST_CHATROOM, from )) == NULL ) return; + + if (( type = xmlGetAttrValue( node, _T("type"))) == NULL ) return; + if ( !lstrcmp( type, _T("error"))) + return; + + GCDEST gcd = { m_szModuleName, NULL, 0 }; + gcd.ptszID = item->jid; + + const TCHAR* msgText = NULL; + + resource = _tcschr( from, '/' ); + if ( resource != NULL && *++resource == '\0' ) + resource = NULL; + + if (( n = xmlGetChild( node , "subject" )) != NULL ) { + msgText = xmlGetText( n ); + + if ( msgText == NULL || msgText[0] == '\0' ) + return; + + gcd.iType = GC_EVENT_TOPIC; + + if ( resource == NULL && ( m = xmlGetChild( node, "body" )) != NULL ) { + const TCHAR* tmpnick = xmlGetText( m ); + if ( tmpnick == NULL || *tmpnick == 0 ) + return; + + const TCHAR* tmptr = _tcsstr( tmpnick, _T("has set the subject to:")); //ejabberd + if ( tmptr == NULL ) + tmptr = _tcsstr( tmpnick, TranslateT("has set the subject to:")); //ejabberd + if ( tmptr != NULL && *tmptr != 0 ) { + *(TCHAR*)(--tmptr) = 0; + resource = tmpnick; + } } + replaceStrT( item->itemResource.statusMessage, msgText ); + } + else { + if (( n = xmlGetChildByTag( node , "body", "xml:lang", m_tszSelectedLang )) == NULL ) + if (( n = xmlGetChild( node , "body" )) == NULL ) + return; + + msgText = xmlGetText( n ); + + if ( msgText == NULL ) + return; + + if ( resource == NULL) + gcd.iType = GC_EVENT_INFORMATION; + else if ( _tcsncmp( msgText, _T("/me "), 4 ) == 0 && _tcslen( msgText ) > 4 ) { + msgText += 4; + gcd.iType = GC_EVENT_ACTION; + } + else gcd.iType = GC_EVENT_MESSAGE; + } + + GcLogCreate( item ); + + time_t msgTime = 0; + for ( int i = 1; ( xNode = xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) + if (( p = xmlGetAttrValue( xNode, _T("xmlns"))) != NULL ) + if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime==0 ) + if (( p = xmlGetAttrValue( xNode, _T("stamp"))) != NULL ) { + msgTime = JabberIsoToUnixTime( p ); + if (m_options.GcLogChatHistory && msgTime > 0 ) { + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "muc_%s_lastevent", _T2A(gcd.ptszID)); + this->JSetDword(NULL, setting, msgTime); + } } + + time_t now = time( NULL ); + if ( msgTime == 0 || msgTime > now ) + msgTime = now; + + if ( resource != NULL ) { + JABBER_RESOURCE_STATUS* r = GcFindResource(item, resource); + nick = r && r->nick ? r->nick : resource; + } + else + nick = NULL; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.ptszUID = resource; + gce.ptszNick = nick; + gce.time = msgTime; + gce.ptszText = EscapeChatTags( (TCHAR*)msgText ); + gce.bIsMe = nick == NULL ? FALSE : (lstrcmp( resource, item->nick ) == 0); + gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; + CallServiceSync( MS_GC_EVENT, NULL, (LPARAM)&gce ); + + item->bChatActive = 2; + + if ( gcd.iType == GC_EVENT_TOPIC ) { + gce.dwFlags &= ~GCEF_ADDTOLOG; + gcd.iType = GC_EVENT_SETSBTEXT; + CallServiceSync( MS_GC_EVENT, NULL, (LPARAM)&gce ); + } + + mir_free( (void*)gce.pszText ); // Since we processed msgText and created a new string +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Accepting groupchat invitations + +class CGroupchatInviteAcceptDlg : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + CCtrlButton m_accept; + JABBER_GROUPCHAT_INVITE_INFO* m_info; + +public: + CGroupchatInviteAcceptDlg( CJabberProto* ppro, JABBER_GROUPCHAT_INVITE_INFO* pInfo ) : + CSuper( ppro, IDD_GROUPCHAT_INVITE_ACCEPT, NULL ), + m_info( pInfo ), + m_accept( this, IDC_ACCEPT ) + { + m_accept.OnClick = Callback( this, &CGroupchatInviteAcceptDlg::OnCommand_Accept ); + } + + void OnInitDialog() + { + CSuper::OnInitDialog(); + + TCHAR buf[256]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s\n%s"), m_info->roomJid, TranslateT("Incoming groupchat invitation.")); + SetDlgItemText( m_hwnd, IDC_HEADERBAR, buf ); + + SetDlgItemText( m_hwnd, IDC_FROM, m_info->from ); + + if ( m_info->reason != NULL ) + SetDlgItemText( m_hwnd, IDC_REASON, m_info->reason ); + + TCHAR* myNick = JabberNickFromJID( m_proto->m_szJabberJID ); + SetDlgItemText( m_hwnd, IDC_NICK, myNick ); + mir_free( myNick ); + + WindowSetIcon( m_hwnd, m_proto, "group" ); + + SetFocus(GetDlgItem(m_hwnd, IDC_NICK)); + } + + void OnCommand_Accept( CCtrlButton* ) + { + TCHAR text[128]; + GetDlgItemText( m_hwnd, IDC_NICK, text, SIZEOF( text )); + m_proto->AcceptGroupchatInvite( m_info->roomJid, text, m_info->password ); + EndDialog( m_hwnd, 0 ); + } +}; + +void __cdecl CJabberProto::GroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo ) +{ + CGroupchatInviteAcceptDlg( this, inviteInfo ).DoModal(); + + mir_free( inviteInfo->roomJid ); + mir_free( inviteInfo->from ); + mir_free( inviteInfo->reason ); + mir_free( inviteInfo->password ); + mir_free( inviteInfo ); +} + +void CJabberProto::GroupchatProcessInvite( const TCHAR* roomJid, const TCHAR* from, const TCHAR* reason, const TCHAR* password ) +{ + if ( roomJid == NULL ) + return; + + if (ListGetItemPtr( LIST_CHATROOM, roomJid )) + return; + + if ( m_options.AutoAcceptMUC == FALSE ) { + JABBER_GROUPCHAT_INVITE_INFO* inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) mir_alloc( sizeof( JABBER_GROUPCHAT_INVITE_INFO )); + inviteInfo->roomJid = mir_tstrdup( roomJid ); + inviteInfo->from = mir_tstrdup( from ); + inviteInfo->reason = mir_tstrdup( reason ); + inviteInfo->password = mir_tstrdup( password ); + JForkThread(( JThreadFunc )&CJabberProto::GroupchatInviteAcceptThread, inviteInfo ); + } + else { + TCHAR* myNick = JabberNickFromJID( m_szJabberJID ); + AcceptGroupchatInvite( roomJid, myNick, password ); + mir_free( myNick ); +} } + +void CJabberProto::AcceptGroupchatInvite( const TCHAR* roomJid, const TCHAR* reason, const TCHAR* password ) +{ + TCHAR room[256], *server, *p; + _tcsncpy( room, roomJid, SIZEOF( room )); + p = _tcstok( room, _T( "@" )); + server = _tcstok( NULL, _T( "@" )); + GroupchatJoinRoom( server, p, reason, password ); +} diff --git a/protocols/JabberG/src/jabber_ibb.cpp b/protocols/JabberG/src/jabber_ibb.cpp new file mode 100644 index 0000000000..51719a696b --- /dev/null +++ b/protocols/JabberG/src/jabber_ibb.cpp @@ -0,0 +1,193 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_ibb.h" +#include "jabber_caps.h" + +#define JABBER_IBB_BLOCK_SIZE 2048 + +void JabberIbbFreeJibb( JABBER_IBB_TRANSFER *jibb ) +{ + if ( jibb ) { + filetransfer* pft = jibb->ft; + if ( pft ) + pft->jibb = NULL; + + mir_free( jibb->srcJID ); + mir_free( jibb->dstJID ); + mir_free( jibb->sid ); + + mir_free( jibb ); +} } + +BOOL CJabberProto::OnFtHandleIbbIq( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( !_tcscmp( pInfo->GetChildNodeName(), _T("open"))) + FtHandleIbbRequest( iqNode, TRUE ); + else if ( !_tcscmp( pInfo->GetChildNodeName(), _T("close"))) + FtHandleIbbRequest( iqNode, FALSE ); + else if ( !_tcscmp( pInfo->GetChildNodeName(), _T("data"))) { + BOOL bOk = FALSE; + const TCHAR *sid = xmlGetAttrValue( pInfo->GetChildNode(), _T("sid")); + const TCHAR *seq = xmlGetAttrValue( pInfo->GetChildNode(), _T("seq")); + if ( sid && seq && xmlGetText( pInfo->GetChildNode())) + bOk = OnIbbRecvdData( xmlGetText( pInfo->GetChildNode()), sid, seq ); + + if ( bOk ) + m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo )); + else + m_ThreadInfo->send( + XmlNodeIq( _T("error"), pInfo ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + } + return TRUE; +} + +void CJabberProto::OnIbbInitiateResult( HXML, CJabberIqInfo* pInfo ) +{ + JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * )pInfo->GetUserData(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) + jibb->bStreamInitialized = TRUE; + if ( jibb->hEvent ) + SetEvent( jibb->hEvent ); +} + +void CJabberProto::OnIbbCloseResult( HXML, CJabberIqInfo* pInfo ) +{ + JABBER_IBB_TRANSFER *jibb = ( JABBER_IBB_TRANSFER * )pInfo->GetUserData(); + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) + jibb->bStreamClosed = TRUE; + if ( jibb->hEvent ) + SetEvent( jibb->hEvent ); +} + +void CJabberProto::IbbSendThread( JABBER_IBB_TRANSFER *jibb ) +{ + Log( "Thread started: type=ibb_send" ); + + jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + jibb->bStreamInitialized = FALSE; + jibb->bStreamClosed = FALSE; + jibb->state = JIBB_SENDING; + + m_ThreadInfo->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbInitiateResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) + << XCHILDNS( _T("open"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid ) << XATTRI( _T("block-size"), JABBER_IBB_BLOCK_SIZE ) + << XATTR( _T("stanza"), _T("message"))); + + WaitForSingleObject( jibb->hEvent, INFINITE ); + CloseHandle( jibb->hEvent ); + jibb->hEvent = NULL; + + if ( jibb->bStreamInitialized ) { + + jibb->wPacketId = 0; + + BOOL bSent = (this->*jibb->pfnSend)( JABBER_IBB_BLOCK_SIZE, jibb->ft ); + + if ( !jibb->bStreamClosed ) + { + jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + + m_ThreadInfo->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbCloseResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) + << XCHILDNS( _T("close"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid )); + + WaitForSingleObject( jibb->hEvent, INFINITE ); + CloseHandle( jibb->hEvent ); + jibb->hEvent = NULL; + + if ( jibb->bStreamClosed && bSent ) + jibb->state = JIBB_DONE; + + } else { + jibb->state = JIBB_ERROR; + } + } + + (this->*jibb->pfnFinal)(( jibb->state==JIBB_DONE )?TRUE:FALSE, jibb->ft ); + jibb->ft = NULL; + JabberIbbFreeJibb( jibb ); +} + +void __cdecl CJabberProto::IbbReceiveThread( JABBER_IBB_TRANSFER *jibb ) +{ + Log( "Thread started: type=ibb_recv" ); + + filetransfer *ft = jibb->ft; + + jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + jibb->bStreamClosed = FALSE; + jibb->wPacketId = 0; + jibb->dwTransferredSize = 0; + jibb->state = JIBB_RECVING; + + WaitForSingleObject( jibb->hEvent, INFINITE ); + + CloseHandle( jibb->hEvent ); + jibb->hEvent = NULL; + + if ( jibb->state == JIBB_ERROR ) + m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), jibb->dstJID ) << XCHILDNS( _T("close"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid )); + + if ( jibb->bStreamClosed && jibb->dwTransferredSize == ft->dwExpectedRecvFileSize ) + jibb->state = JIBB_DONE; + + (this->*jibb->pfnFinal)(( jibb->state==JIBB_DONE )?TRUE:FALSE, jibb->ft ); + jibb->ft = NULL; + + ListRemove( LIST_FTRECV, jibb->sid ); + + JabberIbbFreeJibb( jibb ); +} + +BOOL CJabberProto::OnIbbRecvdData( const TCHAR *data, const TCHAR *sid, const TCHAR *seq ) +{ + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_FTRECV, sid ); + if ( !item ) return FALSE; + + WORD wSeq = (WORD)_ttoi(seq); + if ( wSeq != item->jibb->wPacketId ) { + if ( item->jibb->hEvent ) + SetEvent( item->jibb->hEvent ); + return FALSE; + } + + item->jibb->wPacketId++; + + int length = 0; + char *decodedData = JabberBase64DecodeT( data, &length ); + if ( !decodedData ) + return FALSE; + + (this->*item->jibb->pfnRecv)( NULL, item->ft, decodedData, length ); + + item->jibb->dwTransferredSize += (DWORD)length; + + mir_free( decodedData ); + + return TRUE; +} diff --git a/protocols/JabberG/src/jabber_ibb.h b/protocols/JabberG/src/jabber_ibb.h new file mode 100644 index 0000000000..37ecfd1a2e --- /dev/null +++ b/protocols/JabberG/src/jabber_ibb.h @@ -0,0 +1,46 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_IBB_H_ +#define _JABBER_IBB_H_ + +typedef enum { JIBB_INIT, JIBB_CONNECT, JIBB_SENDING, JIBB_RECVING, JIBB_DONE, JIBB_ERROR } JABBER_IBB_STATE; + +typedef struct { + TCHAR* sid; + TCHAR* srcJID; + TCHAR* dstJID; + unsigned __int64 dwTransferredSize; + JABBER_IBB_STATE state; + HANDLE hEvent; + BOOL bStreamInitialized; + BOOL bStreamClosed; + WORD wPacketId; + BOOL ( CJabberProto::*pfnSend )( int blocksize, filetransfer* ft ); + int ( CJabberProto::*pfnRecv )( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); + void ( CJabberProto::*pfnFinal )( BOOL success, filetransfer* ft ); + filetransfer* ft; +} + JABBER_IBB_TRANSFER; + +#endif diff --git a/protocols/JabberG/src/jabber_icolib.cpp b/protocols/JabberG/src/jabber_icolib.cpp new file mode 100644 index 0000000000..f29a827313 --- /dev/null +++ b/protocols/JabberG/src/jabber_icolib.cpp @@ -0,0 +1,733 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +Idea & portions of code by Artem Shpynov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" + +#include <m_icolib.h> + +#include <m_cluiframes.h> + +#define IDI_ONLINE 104 +#define IDI_OFFLINE 105 +#define IDI_AWAY 128 +#define IDI_FREE4CHAT 129 +#define IDI_INVISIBLE 130 +#define IDI_NA 131 +#define IDI_DND 158 +#define IDI_OCCUPIED 159 +#define IDI_ONTHEPHONE 1002 +#define IDI_OUTTOLUNCH 1003 + +HIMAGELIST hAdvancedStatusIcon = NULL; + +struct CTransportProtoTableItem +{ + TCHAR* mask; + char* proto; +}; + +static CTransportProtoTableItem TransportProtoTable[] = +{ + { _T("|*icq*|jit*"), "ICQ" }, + { _T("msn*"), "MSN" }, + { _T("yahoo*"), "YAHOO" }, + { _T("mrim*"), "MRA" }, + { _T("aim*"), "AIM" }, + //request #3094 + { _T("|gg*|gadu*"), "GaduGadu" }, + { _T("tv*"), "TV" }, + { _T("dict*"), "Dictionary" }, + { _T("weather*"), "Weather" }, + { _T("skype*"), "Skype" }, + { _T("sms*"), "SMS" }, + { _T("smtp*"), "SMTP" }, + //j2j + { _T("gtalk.*.*"), "GTalk" }, + { _T("|xmpp.*.*|j2j.*.*"),"Jabber2Jabber" }, + //jabbim.cz - services + { _T("disk*"), "Jabber Disk" }, + { _T("irc*"), "IRC" }, + { _T("rss*"), "RSS" }, + { _T("tlen*"), "Tlen" }, + + // German social networks + { _T("studivz*"), "StudiVZ" }, + { _T("schuelervz*"), "SchuelerVZ" }, + { _T("meinvz*"), "MeinVZ" }, + { _T("|fb*|facebook*"), "Facebook" }, +}; + +static int skinIconStatusToResourceId[] = {IDI_OFFLINE,IDI_ONLINE,IDI_AWAY,IDI_DND,IDI_NA,IDI_NA,/*IDI_OCCUPIED,*/IDI_FREE4CHAT,IDI_INVISIBLE,IDI_ONTHEPHONE,IDI_OUTTOLUNCH}; +static int skinStatusToJabberStatus[] = {0,1,2,3,4,4,6,7,2,2}; + +/////////////////////////////////////////////////////////////////////////////// +// CIconPool class +int CIconPool::CPoolItem::cmp(const CPoolItem *p1, const CPoolItem *p2) +{ + return lstrcmpA(p1->m_name, p2->m_name); +} + +CIconPool::CPoolItem::CPoolItem(): + m_name(NULL), m_szIcolibName(NULL), m_hIcolibItem(NULL), m_hClistItem(NULL) +{ +} + +CIconPool::CPoolItem::~CPoolItem() +{ + if (m_hIcolibItem && m_szIcolibName) + { + CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)m_szIcolibName); + mir_free(m_szIcolibName); + } + + if (m_name) mir_free(m_name); +} + +CIconPool::CIconPool(CJabberProto *proto): + m_proto(proto), + m_items(10, CIconPool::CPoolItem::cmp), + m_hOnExtraIconsRebuild(NULL) +{ +} + +CIconPool::~CIconPool() +{ + if (m_hOnExtraIconsRebuild) + { + UnhookEvent(m_hOnExtraIconsRebuild); + m_hOnExtraIconsRebuild = NULL; + } +} + +void CIconPool::RegisterIcon(const char *name, const char *filename, int iconid, TCHAR *szSection, TCHAR *szDescription) +{ + char szSettingName[128]; + mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", m_proto->m_szModuleName, name); + + CPoolItem *item = new CPoolItem; + item->m_name = mir_strdup(name); + item->m_szIcolibName = mir_strdup(szSettingName); + item->m_hClistItem = NULL; + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.pszDefaultFile = (char *)filename; // kill const flag for compiler to shut up + sid.pszName = szSettingName; + sid.ptszSection = szSection; + sid.ptszDescription = szDescription; + sid.flags = SIDF_TCHAR; + sid.iDefaultIndex = iconid; + item->m_hIcolibItem = Skin_AddIcon(&sid); + + m_items.insert(item); +} + +HANDLE CIconPool::GetIcolibHandle(const char *name) +{ + if (CPoolItem *item = FindItemByName(name)) + return item->m_hIcolibItem; + + return NULL; +} + +char *CIconPool::GetIcolibName(const char *name) +{ + if (CPoolItem *item = FindItemByName(name)) + return item->m_szIcolibName; + + return NULL; +} + +HICON CIconPool::GetIcon(const char *name, bool big) +{ + if (CPoolItem *item = FindItemByName(name)) + return (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)item->m_hIcolibItem); + + return NULL; +} + +HANDLE CIconPool::GetClistHandle(const char *name) +{ + if (!name) + return (HANDLE)-1; + + if (!ExtraIconsSupported()) + return (HANDLE)-1; + + if (!m_hOnExtraIconsRebuild) + { + int (__cdecl CIconPool::*hookProc)(WPARAM, LPARAM); + hookProc = &CIconPool::OnExtraIconsRebuild; + m_hOnExtraIconsRebuild = HookEventObj(ME_CLIST_EXTRA_LIST_REBUILD, (MIRANDAHOOKOBJ)*(void **)&hookProc, this); + } + + if (CPoolItem *item = FindItemByName(name)) + { + if (item->m_hClistItem) + return item->m_hClistItem; + + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item->m_hIcolibItem); + item->m_hClistItem = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)hIcon, 0); + g_ReleaseIcon(hIcon); + return item->m_hClistItem; + } + + return (HANDLE)-1; +} + +CIconPool::CPoolItem *CIconPool::FindItemByName(const char *name) +{ + CPoolItem item; + item.m_name = mir_strdup(name); + return m_items.find(&item); +} + +int CIconPool::OnExtraIconsRebuild(WPARAM, LPARAM) +{ + for (int i = 0; i < m_items.getCount(); ++i) + m_items[i].m_hClistItem = NULL; + + return 0; +} + +bool CIconPool::ExtraIconsSupported() +{ + static int res = -1; + if (res < 0) res = ServiceExists(MS_CLIST_EXTRA_ADD_ICON) ? 1 : 0; + return res ? true : false; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Icons init + +struct TIconListItem +{ + char* szDescr; + char* szName; + int defIconID; + char* szSection; + HANDLE hIcon; +}; + +static TIconListItem iconList[] = +{ + { LPGEN("%s"), "main", IDI_JABBER, NULL }, +}; + +void CJabberProto::IconsInit( void ) +{ + int i; + + m_transportProtoTableStartIndex = (int *)mir_alloc(sizeof(int) * SIZEOF(TransportProtoTable)); + for (i = 0; i < SIZEOF(TransportProtoTable); ++i) + m_transportProtoTableStartIndex[i] = -1; + + SKINICONDESC sid = {0}; + char szFile[MAX_PATH]; + GetModuleFileNameA(hInst, szFile, MAX_PATH); + + sid.cbSize = sizeof(SKINICONDESC); + sid.pszDefaultFile = szFile; + sid.flags = SIDF_TCHAR; + + char szSettingName[100]; + TCHAR szSectionName[100]; + TCHAR szDescription[100]; + TCHAR szRootSection[100]; + + sid.pszName = szSettingName; + sid.ptszSection = szSectionName; + sid.ptszDescription = szDescription; + + m_phIconLibItems = ( HANDLE* )mir_alloc( sizeof( HANDLE )*SIZEOF(iconList)); + + mir_sntprintf( szRootSection, SIZEOF(szRootSection), _T("%s/%s/%s"), LPGENT("Protocols"), LPGENT("Jabber"), LPGENT("Accounts")); + + for (i = 0; i < SIZEOF(iconList); i++ ) { + TCHAR tmp[100]; + + if ( iconList[i].szSection ) { + mir_sntprintf( szSectionName, SIZEOF(szSectionName), _T("%s/") _T(TCHAR_STR_PARAM), szRootSection, iconList[i].szSection ); + if (_tcsstr(szSectionName, _T("%s"))) { + mir_sntprintf(tmp, SIZEOF(tmp), szSectionName, m_tszUserName); + lstrcpy(szSectionName, tmp); + } + } + else { + mir_sntprintf( szSectionName, SIZEOF(szSectionName), _T("%s"), szRootSection ); + } + + if (strstr(iconList[i].szDescr, "%s")) { + mir_sntprintf( tmp, SIZEOF(tmp), _T(TCHAR_STR_PARAM), iconList[i].szDescr ); + mir_sntprintf( szDescription, SIZEOF(szDescription), tmp, m_tszUserName ); + } + else mir_sntprintf( szDescription, SIZEOF(szDescription), _T(TCHAR_STR_PARAM), iconList[i].szDescr ); + + mir_snprintf( szSettingName, SIZEOF(szSettingName), "%s_%s", m_szModuleName, iconList[i].szName ); + + sid.iDefaultIndex = -iconList[i].defIconID; + m_phIconLibItems[i] = Skin_AddIcon(&sid); +} } + +HANDLE CJabberProto::GetIconHandle( int iconId ) +{ + if (HANDLE result = g_GetIconHandle(iconId)) + return result; + + for ( int i=0; i < SIZEOF(iconList); i++ ) + if ( iconList[i].defIconID == iconId ) + return m_phIconLibItems[i]; + + return NULL; +} + +HICON CJabberProto::LoadIconEx( const char* name, bool big ) +{ + if (HICON result = g_LoadIconEx(name, big)) + return result; + + char szSettingName[100]; + mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", m_szModuleName, name ); + return ( HICON )CallService( MS_SKIN2_GETICON, big, (LPARAM)szSettingName ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// internal functions + +static inline TCHAR qtoupper( TCHAR c ) +{ + return ( c >= 'a' && c <= 'z' ) ? c - 'a' + 'A' : c; +} + +static BOOL WildComparei( const TCHAR* name, const TCHAR* mask ) +{ + const TCHAR* last='\0'; + for ( ;; mask++, name++) { + if ( *mask != '?' && qtoupper( *mask ) != qtoupper( *name )) + break; + if ( *name == '\0' ) + return ((BOOL)!*mask); + } + + if ( *mask != '*' ) + return FALSE; + + for (;; mask++, name++ ) { + while( *mask == '*' ) { + last = mask++; + if ( *mask == '\0' ) + return ((BOOL)!*mask); /* true */ + } + + if ( *name == '\0' ) + return ((BOOL)!*mask); /* *mask == EOS */ + if ( *mask != '?' && qtoupper( *mask ) != qtoupper( *name )) + name -= (size_t)(mask - last) - 1, mask = last; +} } + +static BOOL MatchMask( const TCHAR* name, const TCHAR* mask) +{ + if ( !mask || !name ) + return mask == name; + + if ( *mask != '|' ) + return WildComparei( name, mask ); + + TCHAR* temp = NEWTSTR_ALLOCA(mask); + for ( int e=1; mask[e] != '\0'; e++ ) { + int s = e; + while ( mask[e] != '\0' && mask[e] != '|') + e++; + + temp[e]= _T('\0'); + if ( WildComparei( name, temp+s )) + return TRUE; + + if ( mask[e] == 0 ) + return FALSE; + } + + return FALSE; +} + +static HICON ExtractIconFromPath(const char *path, BOOL * needFree) +{ + char *comma; + char file[MAX_PATH],fileFull[MAX_PATH]; + int n; + HICON hIcon; + lstrcpynA(file,path,sizeof(file)); + comma=strrchr(file,','); + if(comma==NULL) n=0; + else {n=atoi(comma+1); *comma=0;} + CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)file, (LPARAM)fileFull); + hIcon=NULL; + ExtractIconExA(fileFull,n,NULL,&hIcon,1); + if (needFree) + *needFree=(hIcon!=NULL); + + return hIcon; +} + +static HICON LoadTransportIcon(char *filename,int i,char *IconName,TCHAR *SectName,TCHAR *Description,int internalidx, BOOL * needFree) +{ + char szPath[MAX_PATH],szMyPath[MAX_PATH], szFullPath[MAX_PATH],*str; + BOOL has_proto_icon=FALSE; + SKINICONDESC sid={0}; + if (needFree) *needFree=FALSE; + GetModuleFileNameA(NULL, szPath, MAX_PATH); + str=strrchr(szPath,'\\'); + if(str!=NULL) *str=0; + _snprintf(szMyPath, sizeof(szMyPath), "%s\\Icons\\%s", szPath, filename); + _snprintf(szFullPath, sizeof(szFullPath), "%s\\Icons\\%s,%d", szPath, filename, i); + BOOL nf; + HICON hi=ExtractIconFromPath(szFullPath,&nf); + if (hi) has_proto_icon=TRUE; + if (hi && nf) DestroyIcon(hi); + if ( IconName != NULL && SectName != NULL) { + sid.cbSize = sizeof(sid); + sid.hDefaultIcon = (has_proto_icon)?NULL:(HICON)CallService(MS_SKIN_LOADPROTOICON,(WPARAM)NULL,(LPARAM)(-internalidx)); + sid.ptszSection = SectName; + sid.pszName = IconName; + sid.ptszDescription = Description; + sid.pszDefaultFile = szMyPath; + sid.iDefaultIndex = i; + sid.flags = SIDF_TCHAR; + Skin_AddIcon(&sid); + } + return ((HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)IconName)); +} + +static HICON LoadSmallIcon(HINSTANCE hInstance, LPCTSTR lpIconName) +{ + HICON hIcon=NULL; // icon handle + int index=-(int)lpIconName; + TCHAR filename[MAX_PATH]={0}; + GetModuleFileName(hInstance,filename,MAX_PATH); + ExtractIconEx(filename,index,NULL,&hIcon,1); + return hIcon; +} + +int CJabberProto::LoadAdvancedIcons(int iID) +{ + int i; + char *proto = TransportProtoTable[iID].proto; + char defFile[MAX_PATH] = {0}; + TCHAR Group[255]; + char Uname[255]; + int first=-1; + HICON empty=LoadSmallIcon(NULL,MAKEINTRESOURCE(102)); + + mir_sntprintf(Group, SIZEOF(Group), _T("Status Icons/%s/") _T(TCHAR_STR_PARAM) _T(" %s"), m_tszUserName, proto, TranslateT("transport")); + mir_snprintf(defFile, SIZEOF(defFile), "proto_%s.dll",proto); + if (!hAdvancedStatusIcon) + hAdvancedStatusIcon=(HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0); + + EnterCriticalSection( &m_csModeMsgMutex ); + for (i=0; i<ID_STATUS_ONTHEPHONE-ID_STATUS_OFFLINE; i++) { + HICON hicon; + BOOL needFree; + int n=skinStatusToJabberStatus[i]; + TCHAR *descr = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, n+ID_STATUS_OFFLINE, GSMDF_TCHAR); + mir_snprintf(Uname, SIZEOF(Uname), "%s_Transport_%s_%d", m_szModuleName, proto, n); + hicon=(HICON)LoadTransportIcon(defFile,-skinIconStatusToResourceId[i],Uname,Group,descr,-(n+ID_STATUS_OFFLINE),&needFree); + int index=(m_transportProtoTableStartIndex[iID] == -1)?-1:m_transportProtoTableStartIndex[iID]+n; + int added=ImageList_ReplaceIcon(hAdvancedStatusIcon,index,hicon?hicon:empty); + if (first == -1) first=added; + if (hicon && needFree) DestroyIcon(hicon); + } + + if ( m_transportProtoTableStartIndex[iID] == -1 ) + m_transportProtoTableStartIndex[iID] = first; + LeaveCriticalSection( &m_csModeMsgMutex ); + return 0; +} + +int CJabberProto::GetTransportProtoID( TCHAR* TransportDomain ) +{ + for ( int i=0; i<SIZEOF(TransportProtoTable); i++ ) + if ( MatchMask( TransportDomain, TransportProtoTable[i].mask )) + return i; + + return -1; +} + +int CJabberProto::GetTransportStatusIconIndex(int iID, int Status) +{ + if ( iID < 0 || iID >= SIZEOF( TransportProtoTable )) + return -1; + + //icons not loaded - loading icons + if ( m_transportProtoTableStartIndex[iID] == -1 ) + LoadAdvancedIcons( iID ); + + //some fault on loading icons + if ( m_transportProtoTableStartIndex[iID] == -1 ) + return -1; + + if ( Status < ID_STATUS_OFFLINE ) + Status = ID_STATUS_OFFLINE; + + return m_transportProtoTableStartIndex[iID] + skinStatusToJabberStatus[ Status - ID_STATUS_OFFLINE ]; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// a hook for the IcoLib plugin + +int CJabberProto::OnReloadIcons(WPARAM, LPARAM) +{ + for ( int i=0; i < SIZEOF(TransportProtoTable); i++ ) + if ( m_transportProtoTableStartIndex[i] != -1 ) + LoadAdvancedIcons(i); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Prototype for Jabber and other protocols to return index of Advanced status +// wParam - HCONTACT of called protocol +// lParam - should be 0 (reserverd for futher usage) +// return value: -1 - no Advanced status +// : other - index of icons in clcimagelist. +// if imagelist require advanced painting status overlay(like xStatus) +// index should be shifted to HIWORD, LOWORD should be 0 + +INT_PTR __cdecl CJabberProto::JGetAdvancedStatusIcon(WPARAM wParam, LPARAM) +{ + HANDLE hContact=(HANDLE) wParam; + if ( !hContact ) + return -1; + + if ( !JGetByte( hContact, "IsTransported", 0 )) + return -1; + + DBVARIANT dbv; + if ( JGetStringT( hContact, "Transport", &dbv )) + return -1; + + int iID = GetTransportProtoID( dbv.ptszVal ); + DBFreeVariant(&dbv); + if ( iID >= 0 ) { + WORD Status = ID_STATUS_OFFLINE; + Status = JGetWord( hContact, "Status", ID_STATUS_OFFLINE ); + if ( Status < ID_STATUS_OFFLINE ) + Status = ID_STATUS_OFFLINE; + else if (Status > ID_STATUS_INVISIBLE ) + Status = ID_STATUS_ONLINE; + return GetTransportStatusIconIndex( iID, Status ); + } + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Transport check functions + +BOOL CJabberProto::DBCheckIsTransportedContact(const TCHAR* jid, HANDLE hContact) +{ + // check if transport is already set + if ( !jid || !hContact ) + return FALSE; + + // strip domain part from jid + TCHAR* domain = _tcschr(( TCHAR* )jid, '@' ); + BOOL isAgent = (domain == NULL) ? TRUE : FALSE; + BOOL isTransported = FALSE; + if ( domain!=NULL ) + domain = NEWTSTR_ALLOCA(domain+1); + else + domain = NEWTSTR_ALLOCA(jid); + + TCHAR* resourcepos = _tcschr( domain, '/' ); + if ( resourcepos != NULL ) + *resourcepos = '\0'; + + for ( int i=0; i < SIZEOF(TransportProtoTable); i++ ) { + if ( MatchMask( domain, TransportProtoTable[i].mask )) { + GetTransportStatusIconIndex( GetTransportProtoID( domain ), ID_STATUS_OFFLINE ); + isTransported = TRUE; + break; + } } + + if ( m_lstTransports.getIndex( domain ) == -1 ) { + if ( isAgent ) { + m_lstTransports.insert( mir_tstrdup(domain)); + JSetByte( hContact, "IsTransport", 1 ); + } } + + if ( isTransported ) { + JSetStringT( hContact, "Transport", domain ); + JSetByte( hContact, "IsTransported", 1 ); + } + return isTransported; +} + +void CJabberProto::CheckAllContactsAreTransported() +{ + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( !lstrcmpA( m_szModuleName, szProto )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + DBCheckIsTransportedContact( dbv.ptszVal, hContact ); + JFreeVariant( &dbv ); + } } + + hContact = db_find_next(hContact); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// Cross-instance shared icons + +static TIconListItem sharedIconList[] = +{ + { LPGEN("Privacy Lists"), "privacylists", IDI_PRIVACY_LISTS, NULL }, + { LPGEN("Bookmarks"), "bookmarks", IDI_BOOKMARKS, NULL }, + { LPGEN("Notes"), "notes", IDI_NOTES, NULL }, + { LPGEN("Multi-User Conference"), "group", IDI_GROUP, NULL }, + { LPGEN("Agents list"), "Agents", IDI_AGENTS, NULL }, + + { LPGEN("Transports"), "transport", IDI_TRANSPORT, NULL }, + { LPGEN("Registered transports"), "transport_loc", IDI_TRANSPORTL, NULL }, + { LPGEN("Change password"), "key", IDI_KEYS, NULL }, + { LPGEN("Personal vCard"), "vcard", IDI_VCARD, NULL }, + { LPGEN("Request authorization"), "Request", IDI_REQUEST, NULL }, + { LPGEN("Grant authorization"), "Grant", IDI_GRANT, NULL }, + { LPGEN("Revoke authorization"), "Revoke", IDI_AUTHREVOKE, NULL }, + { LPGEN("Convert to room"), "convert", IDI_USER2ROOM, NULL }, + { LPGEN("Add to roster"), "addroster", IDI_ADDROSTER, NULL }, + { LPGEN("Login/logout"), "trlogonoff", IDI_LOGIN, NULL }, + { LPGEN("Resolve nicks"), "trresolve", IDI_REFRESH, NULL }, + { LPGEN("Send note"), "sendnote", IDI_SEND_NOTE, NULL }, + { LPGEN("Service Discovery"), "servicediscovery", IDI_SERVICE_DISCOVERY, NULL }, + { LPGEN("AdHoc Command"), "adhoc", IDI_COMMAND, NULL }, + { LPGEN("XML Console"), "xmlconsole", IDI_CONSOLE, NULL }, + { LPGEN("OpenID Request"), "openid", IDI_HTTP_AUTH, NULL }, + + { LPGEN("Discovery succeeded"), "disco_ok", IDI_DISCO_OK, LPGEN("Dialogs") }, + { LPGEN("Discovery failed"), "disco_fail", IDI_DISCO_FAIL, LPGEN("Dialogs") }, + { LPGEN("Discovery in progress"), "disco_progress", IDI_DISCO_PROGRESS, LPGEN("Dialogs") }, + { LPGEN("View as tree"), "sd_view_tree", IDI_VIEW_TREE, LPGEN("Dialogs") }, + { LPGEN("View as list"), "sd_view_list", IDI_VIEW_LIST, LPGEN("Dialogs") }, + { LPGEN("Apply filter"), "sd_filter_apply", IDI_FILTER_APPLY, LPGEN("Dialogs") }, + { LPGEN("Reset filter"), "sd_filter_reset", IDI_FILTER_RESET, LPGEN("Dialogs") }, + + { LPGEN("Navigate home"), "sd_nav_home", IDI_NAV_HOME, LPGEN("Dialogs/Discovery") }, + { LPGEN("Refresh node"), "sd_nav_refresh", IDI_NAV_REFRESH, LPGEN("Dialogs/Discovery") }, + { LPGEN("Browse node"), "sd_browse", IDI_BROWSE, LPGEN("Dialogs/Discovery") }, + { LPGEN("RSS service"), "node_rss", IDI_NODE_RSS, LPGEN("Dialogs/Discovery") }, + { LPGEN("Server"), "node_server", IDI_NODE_SERVER, LPGEN("Dialogs/Discovery") }, + { LPGEN("Storage service"), "node_store", IDI_NODE_STORE, LPGEN("Dialogs/Discovery") }, + { LPGEN("Weather service"), "node_weather", IDI_NODE_WEATHER, LPGEN("Dialogs/Discovery") }, + + { LPGEN("Generic privacy list"), "pl_list_any", IDI_PL_LIST_ANY, LPGEN("Dialogs/Privacy") }, + { LPGEN("Active privacy list"), "pl_list_active", IDI_PL_LIST_ACTIVE, LPGEN("Dialogs/Privacy") }, + { LPGEN("Default privacy list"), "pl_list_default", IDI_PL_LIST_DEFAULT, LPGEN("Dialogs/Privacy") }, + { LPGEN("Move up"), "arrow_up", IDI_ARROW_UP, LPGEN("Dialogs/Privacy") }, + { LPGEN("Move down"), "arrow_down", IDI_ARROW_DOWN, LPGEN("Dialogs/Privacy") }, + { LPGEN("Allow Messages"), "pl_msg_allow", IDI_PL_MSG_ALLOW, LPGEN("Dialogs/Privacy") }, + { LPGEN("Allow Presences (in)"), "pl_prin_allow", IDI_PL_PRIN_ALLOW, LPGEN("Dialogs/Privacy") }, + { LPGEN("Allow Presences (out)"), "pl_prout_allow", IDI_PL_PROUT_ALLOW, LPGEN("Dialogs/Privacy") }, + { LPGEN("Allow Queries"), "pl_iq_allow", IDI_PL_QUERY_ALLOW, LPGEN("Dialogs/Privacy") }, + { LPGEN("Deny Messages"), "pl_msg_deny", IDI_PL_MSG_DENY, LPGEN("Dialogs/Privacy") }, + { LPGEN("Deny Presences (in)"), "pl_prin_deny", IDI_PL_PRIN_DENY, LPGEN("Dialogs/Privacy") }, + { LPGEN("Deny Presences (out)"), "pl_prout_deny", IDI_PL_PROUT_DENY, LPGEN("Dialogs/Privacy") }, + { LPGEN("Deny Queries"), "pl_iq_deny", IDI_PL_QUERY_DENY, LPGEN("Dialogs/Privacy") }, +}; + +static void sttProcessIcons( int iAmount ) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(hInst, szFile, MAX_PATH); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszDefaultFile = szFile; + sid.flags = SIDF_PATH_TCHAR; + + char szRootSection[100]; + mir_snprintf( szRootSection, SIZEOF(szRootSection), "%s/%s", LPGEN("Protocols"), LPGEN("Jabber")); + + for ( int i = 0; i < iAmount; i++ ) { + char szSettingName[100], szSectionName[100]; + + mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", + GLOBAL_SETTING_PREFIX, sharedIconList[i].szName); + + if ( sharedIconList[i].szSection ) { + mir_snprintf( szSectionName, sizeof( szSectionName ), "%s/%s", szRootSection, sharedIconList[i].szSection ); + sid.pszSection = szSectionName; + } + else sid.pszSection = szRootSection; + + sid.pszName = szSettingName; + sid.pszDescription = sharedIconList[i].szDescr; + sid.iDefaultIndex = -sharedIconList[i].defIconID; + sharedIconList[i].hIcon = Skin_AddIcon(&sid); +} } + +void g_IconsInit() +{ + sttProcessIcons( SIZEOF( sharedIconList )); +} + +HANDLE g_GetIconHandle( int iconId ) +{ + for ( int i=0; i < SIZEOF(sharedIconList); i++ ) + if ( sharedIconList[i].defIconID == iconId ) + return sharedIconList[i].hIcon; + + return NULL; +} + +HICON g_LoadIconEx( const char* name, bool big ) +{ + char szSettingName[100]; + mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", GLOBAL_SETTING_PREFIX, name ); + return ( HICON )CallService( MS_SKIN2_GETICON, big, (LPARAM)szSettingName ); +} + +void g_ReleaseIcon( HICON hIcon ) +{ + if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +void ImageList_AddIcon_Icolib( HIMAGELIST hIml, HICON hIcon ) +{ + ImageList_AddIcon( hIml, hIcon ); + g_ReleaseIcon( hIcon ); +} + +void WindowSetIcon(HWND hWnd, CJabberProto *proto, const char* name) +{ + SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )proto->LoadIconEx( name, true )); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )proto->LoadIconEx( name )); +} + +void WindowFreeIcon(HWND hWnd) +{ + g_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0)); + g_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0)); +} diff --git a/protocols/JabberG/src/jabber_icolib.h b/protocols/JabberG/src/jabber_icolib.h new file mode 100644 index 0000000000..4b5f7d8e12 --- /dev/null +++ b/protocols/JabberG/src/jabber_icolib.h @@ -0,0 +1,67 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_ICOLIB_H_ +#define _JABBER_ICOLIB_H_ + +struct CJabberProto; + +class CIconPool +{ +public: + CIconPool(CJabberProto *proto); + ~CIconPool(); + + void RegisterIcon(const char *name, const char *filename, int iconid, TCHAR *szSection, TCHAR *szDescription); + + HANDLE GetIcolibHandle(const char *name); + char *GetIcolibName(const char *name); + HICON GetIcon(const char *name, bool big = false); + HANDLE GetClistHandle(const char *name); + +private: + struct CPoolItem + { + char *m_name; + char *m_szIcolibName; + HANDLE m_hIcolibItem; + HANDLE m_hClistItem; + + static int cmp(const CPoolItem *p1, const CPoolItem *p2); + + CPoolItem(); + ~CPoolItem(); + }; + + CJabberProto *m_proto; + OBJLIST<CPoolItem> m_items; + HANDLE m_hOnExtraIconsRebuild; + + CPoolItem *FindItemByName(const char *name); + + int __cdecl OnExtraIconsRebuild(WPARAM, LPARAM); + static bool ExtraIconsSupported(); +}; + +#endif // _JABBER_ICOLIB_H_ diff --git a/protocols/JabberG/src/jabber_iq.cpp b/protocols/JabberG/src/jabber_iq.cpp new file mode 100644 index 0000000000..43084114c2 --- /dev/null +++ b/protocols/JabberG/src/jabber_iq.cpp @@ -0,0 +1,375 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "jabber_privacy.h" +#include "jabber_ibb.h" +#include "jabber_rc.h" + +void CJabberProto::IqInit() +{ + InitializeCriticalSection( &m_csIqList ); + m_ppIqList = NULL; + m_nIqCount = 0; + m_nIqAlloced = 0; +} + +void CJabberProto::IqUninit() +{ + if ( m_ppIqList ) mir_free( m_ppIqList ); + m_ppIqList = NULL; + m_nIqCount = 0; + m_nIqAlloced = 0; + DeleteCriticalSection( &m_csIqList ); +} + +void CJabberProto::IqRemove( int index ) +{ + EnterCriticalSection( &m_csIqList ); + if ( index>=0 && index<m_nIqCount ) { + memmove( m_ppIqList+index, m_ppIqList+index+1, sizeof( JABBER_IQ_FUNC )*( m_nIqCount-index-1 )); + m_nIqCount--; + } + LeaveCriticalSection( &m_csIqList ); +} + +void CJabberProto::IqExpire() +{ + int i; + time_t expire; + + EnterCriticalSection( &m_csIqList ); + expire = time( NULL ) - 120; // 2 minute + i = 0; + while ( i < m_nIqCount ) { + if ( m_ppIqList[i].requestTime < expire ) + IqRemove( i ); + else + i++; + } + LeaveCriticalSection( &m_csIqList ); +} + +JABBER_IQ_PFUNC CJabberProto::JabberIqFetchFunc( int iqId ) +{ + int i; + JABBER_IQ_PFUNC res; + + EnterCriticalSection( &m_csIqList ); + IqExpire(); +#ifdef _DEBUG + for ( i=0; i<m_nIqCount; i++ ) + Log( " %04d : %02d : 0x%x", m_ppIqList[i].iqId, m_ppIqList[i].procId, m_ppIqList[i].func ); +#endif + for ( i=0; i<m_nIqCount && m_ppIqList[i].iqId!=iqId; i++ ); + if ( i < m_nIqCount ) { + res = m_ppIqList[i].func; + IqRemove( i ); + } + else { + res = ( JABBER_IQ_PFUNC ) NULL; + } + LeaveCriticalSection( &m_csIqList ); + return res; +} + +void CJabberProto::IqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func ) +{ + int i; + + EnterCriticalSection( &m_csIqList ); + Log( "IqAdd id=%d, proc=%d, func=0x%x", iqId, procId, func ); + if ( procId == IQ_PROC_NONE ) + i = m_nIqCount; + else + for ( i=0; i<m_nIqCount && m_ppIqList[i].procId!=procId; i++ ); + + if ( i>=m_nIqCount && m_nIqCount>=m_nIqAlloced ) { + m_nIqAlloced = m_nIqCount + 8; + m_ppIqList = ( JABBER_IQ_FUNC * )mir_realloc( m_ppIqList, sizeof( JABBER_IQ_FUNC )*m_nIqAlloced ); + } + + if ( m_ppIqList != NULL ) { + m_ppIqList[i].iqId = iqId; + m_ppIqList[i].procId = procId; + m_ppIqList[i].func = func; + m_ppIqList[i].requestTime = time( NULL ); + if ( i == m_nIqCount ) m_nIqCount++; + } + LeaveCriticalSection( &m_csIqList ); +} + +BOOL CJabberIqManager::FillPermanentHandlers() +{ + // Google Shared Status (http://code.google.com/apis/talk/jep_extensions/shared_status.html) + AddPermanentHandler( &CJabberProto::OnIqSetGoogleSharedStatus, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR, _T("google:shared-status"), FALSE, _T("query")); + + // version requests (XEP-0092) + AddPermanentHandler( &CJabberProto::OnIqRequestVersion, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_VERSION), FALSE, _T("query")); + + // last activity (XEP-0012) + AddPermanentHandler( &CJabberProto::OnIqRequestLastActivity, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_LAST_ACTIVITY), FALSE, _T("query")); + + // ping requests (XEP-0199) + AddPermanentHandler( &CJabberProto::OnIqRequestPing, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_PING), FALSE, _T("ping")); + + // entity time (XEP-0202) + AddPermanentHandler( &CJabberProto::OnIqRequestTime, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_ENTITY_TIME), FALSE, _T("time")); + + // entity time (XEP-0090) + AddPermanentHandler( &CJabberProto::OnIqProcessIqOldTime, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_ENTITY_TIME_OLD), FALSE, _T("query")); + + // old avatars support (deprecated XEP-0008) + AddPermanentHandler( &CJabberProto::OnIqRequestAvatar, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_AVATAR), FALSE, _T("query")); + + // privacy lists (XEP-0016) + AddPermanentHandler( &CJabberProto::OnIqRequestPrivacyLists, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR, _T(JABBER_FEAT_PRIVACY_LISTS), FALSE, _T("query")); + + // in band bytestreams (XEP-0047) + AddPermanentHandler( &CJabberProto::OnFtHandleIbbIq, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE | JABBER_IQ_PARSE_CHILD_TAG_NAME | JABBER_IQ_PARSE_CHILD_TAG_XMLNS, _T(JABBER_FEAT_IBB), FALSE, NULL); + + // socks5-bytestreams (XEP-0065) + AddPermanentHandler( &CJabberProto::FtHandleBytestreamRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_BYTESTREAMS), FALSE, _T("query")); + + // session initiation (XEP-0095) + AddPermanentHandler( &CJabberProto::OnSiRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_SI), FALSE, _T("si")); + + // roster push requests + AddPermanentHandler( &CJabberProto::OnRosterPushRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_IQ_ROSTER), FALSE, _T("query")); + + // OOB file transfers + AddPermanentHandler( &CJabberProto::OnIqRequestOOB, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_OOB), FALSE, _T("query")); + + // disco#items requests (XEP-0030, XEP-0050) + AddPermanentHandler( &CJabberProto::OnHandleDiscoItemsRequest, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_DISCO_ITEMS), FALSE, _T("query")); + + // disco#info requests (XEP-0030, XEP-0050, XEP-0115) + AddPermanentHandler( &CJabberProto::OnHandleDiscoInfoRequest, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_DISCO_INFO), FALSE, _T("query")); + + // ad-hoc commands (XEP-0050) for remote controlling (XEP-0146) + AddPermanentHandler( &CJabberProto::HandleAdhocCommandRequest, JABBER_IQ_TYPE_SET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_COMMANDS), FALSE, _T("command")); + + // http auth (XEP-0070) + AddPermanentHandler( &CJabberProto::OnIqHttpAuth, JABBER_IQ_TYPE_GET, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_ID_STR | JABBER_IQ_PARSE_CHILD_TAG_NODE, _T(JABBER_FEAT_HTTP_AUTH), FALSE, _T("confirm")); + + return TRUE; +} + +BOOL CJabberIqManager::Start() +{ + if ( m_hExpirerThread || m_bExpirerThreadShutdownRequest ) + return FALSE; + + m_hExpirerThread = ppro->JForkThreadEx( &CJabberProto::ExpirerThread, this ); + if ( !m_hExpirerThread ) + return FALSE; + + return TRUE; +} + +void __cdecl CJabberProto::ExpirerThread( void* pParam ) +{ + CJabberIqManager *pManager = ( CJabberIqManager * )pParam; + pManager->ExpirerThread(); +} + +void CJabberIqManager::ExpirerThread() +{ + while (!m_bExpirerThreadShutdownRequest) + { + Lock(); + CJabberIqInfo* pInfo = DetachExpired(); + Unlock(); + if (!pInfo) + { + for (int i = 0; !m_bExpirerThreadShutdownRequest && (i < 10); i++) + Sleep(50); + + // -1 thread :) + ppro->m_adhocManager.ExpireSessions(); + continue; + } + ExpireInfo( pInfo ); + delete pInfo; + } + + if ( !m_bExpirerThreadShutdownRequest ) { + CloseHandle( m_hExpirerThread ); + m_hExpirerThread = NULL; + } +} + +void CJabberIqManager::ExpireInfo( CJabberIqInfo* pInfo, void*) +{ + if ( !pInfo ) + return; + + if ( pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM ) + pInfo->m_szFrom = pInfo->m_szReceiver; + if (( pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT ) && ( pInfo->m_szFrom )) + pInfo->m_hContact = ppro->HContactFromJID( pInfo->m_szFrom , 3); + + ppro->Log( "Expiring iq id %d, sent to " TCHAR_STR_PARAM, pInfo->m_nIqId, pInfo->m_szReceiver ? pInfo->m_szReceiver : _T("server")); + + pInfo->m_nIqType = JABBER_IQ_TYPE_FAIL; + (ppro->*(pInfo->m_pHandler))( NULL, pInfo ); +} + +CJabberIqInfo* CJabberIqManager::AddHandler(JABBER_IQ_HANDLER pHandler, int nIqType, const TCHAR *szReceiver, DWORD dwParamsToParse, int nIqId, void *pUserData, int iPriority) +{ + CJabberIqInfo* pInfo = new CJabberIqInfo(); + if (!pInfo) + return NULL; + + pInfo->m_pHandler = pHandler; + if (nIqId == -1) + nIqId = ppro->SerialNext(); + pInfo->m_nIqId = nIqId; + pInfo->m_nIqType = nIqType; + pInfo->m_dwParamsToParse = dwParamsToParse; + pInfo->m_pUserData = pUserData; + pInfo->m_dwRequestTime = GetTickCount(); + pInfo->m_dwTimeout = JABBER_DEFAULT_IQ_REQUEST_TIMEOUT; + pInfo->m_iPriority = iPriority; + pInfo->SetReceiver(szReceiver); + + InsertIq(pInfo); + + return pInfo; +} + +BOOL CJabberIqManager::HandleIq(int nIqId, HXML pNode ) +{ + if (nIqId == -1 || pNode == NULL) + return FALSE; + + const TCHAR *szType = xmlGetAttrValue( pNode, _T("type")); + if ( !szType ) + return FALSE; + + int nIqType = JABBER_IQ_TYPE_FAIL; + if (!_tcsicmp(szType, _T("result"))) + nIqType = JABBER_IQ_TYPE_RESULT; + else if (!_tcsicmp(szType, _T("error"))) + nIqType = JABBER_IQ_TYPE_ERROR; + else + return FALSE; + + Lock(); + CJabberIqInfo* pInfo = DetachInfo(nIqId); + Unlock(); + if (pInfo) + { + pInfo->m_nIqType = nIqType; + if (nIqType == JABBER_IQ_TYPE_RESULT) { + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_NODE) + pInfo->m_pChildNode = xmlGetChild( pNode , 0 ); + + if (pInfo->m_pChildNode && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_NAME)) + pInfo->m_szChildTagName = ( TCHAR* )xmlGetName( pInfo->m_pChildNode ); + if (pInfo->m_pChildNode && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_CHILD_TAG_XMLNS)) + pInfo->m_szChildTagXmlns = ( TCHAR* )xmlGetAttrValue( pNode, _T("xmlns")); + } + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) + pInfo->m_szTo = ( TCHAR* )xmlGetAttrValue( pNode, _T("to")); + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM) + pInfo->m_szFrom = ( TCHAR* )xmlGetAttrValue( pNode, _T("from")); + if (pInfo->m_szFrom && (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT)) + pInfo->m_hContact = ppro->HContactFromJID( pInfo->m_szFrom, 3 ); + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_ID_STR) + pInfo->m_szId = ( TCHAR* )xmlGetAttrValue( pNode, _T("id")); + + (ppro->*(pInfo->m_pHandler))(pNode, pInfo); + delete pInfo; + return TRUE; + } + return FALSE; +} + +BOOL CJabberIqManager::HandleIqPermanent( HXML pNode ) +{ + BOOL bStopHandling = FALSE; + Lock(); + CJabberIqPermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo ) { + // have to get all data here, in the loop, because there's always possibility that previous handler modified it + const TCHAR *szType = xmlGetAttrValue( pNode, _T("type")); + if ( !szType ) + break; + + CJabberIqInfo iqInfo; + + iqInfo.m_nIqType = JABBER_IQ_TYPE_FAIL; + if ( !_tcsicmp( szType, _T("get"))) + iqInfo.m_nIqType = JABBER_IQ_TYPE_GET; + else if ( !_tcsicmp( szType, _T("set"))) + iqInfo.m_nIqType = JABBER_IQ_TYPE_SET; + else + break; + + if ( pInfo->m_nIqTypes & iqInfo.m_nIqType ) + { + HXML pFirstChild = xmlGetChild( pNode , 0 ); + if ( !pFirstChild || !xmlGetName( pFirstChild )) + break; + + const TCHAR *szTagName = xmlGetName( pFirstChild ); + const TCHAR *szXmlns = xmlGetAttrValue( pFirstChild, _T("xmlns")); + + if ( (!pInfo->m_szXmlns || ( szXmlns && !_tcscmp( pInfo->m_szXmlns, szXmlns ))) && + ( !pInfo->m_szTag || !_tcscmp( pInfo->m_szTag, szTagName ))) { + // node suits handler criteria, call the handler + iqInfo.m_pChildNode = pFirstChild; + iqInfo.m_szChildTagName = ( TCHAR* )szTagName; + iqInfo.m_szChildTagXmlns = ( TCHAR* )szXmlns; + iqInfo.m_szId = ( TCHAR* )xmlGetAttrValue( pNode, _T("id")); + iqInfo.m_pUserData = pInfo->m_pUserData; + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) + iqInfo.m_szTo = ( TCHAR* )xmlGetAttrValue( pNode, _T("to")); + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_FROM) + iqInfo.m_szFrom = ( TCHAR* )xmlGetAttrValue( pNode, _T("from")); + + if ((pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_HCONTACT) && (iqInfo.m_szFrom)) + iqInfo.m_hContact = ppro->HContactFromJID( iqInfo.m_szFrom, 3 ); + + ppro->Log( "Handling iq id " TCHAR_STR_PARAM ", type " TCHAR_STR_PARAM ", from " TCHAR_STR_PARAM, iqInfo.m_szId, szType, iqInfo.m_szFrom ); + if ((ppro->*(pInfo->m_pHandler))(pNode, &iqInfo)) { + bStopHandling = TRUE; + break; + } + } + } + + pInfo = pInfo->m_pNext; + } + Unlock(); + + return bStopHandling; +} diff --git a/protocols/JabberG/src/jabber_iq.h b/protocols/JabberG/src/jabber_iq.h new file mode 100644 index 0000000000..6e145e7db0 --- /dev/null +++ b/protocols/JabberG/src/jabber_iq.h @@ -0,0 +1,526 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_IQ_H_ +#define _JABBER_IQ_H_ + +#include "jabber_xml.h" + +class CJabberIqInfo; + +typedef enum { + IQ_PROC_NONE, + IQ_PROC_GETAGENTS, + IQ_PROC_GETREGISTER, + IQ_PROC_SETREGISTER, + IQ_PROC_GETVCARD, + IQ_PROC_SETVCARD, + IQ_PROC_GETSEARCH, + IQ_PROC_GETSEARCHFIELDS, + IQ_PROC_BROWSEROOMS, + IQ_PROC_DISCOROOMSERVER, + IQ_PROC_DISCOAGENTS, + IQ_PROC_DISCOBOOKMARKS, + IQ_PROC_SETBOOKMARKS, + IQ_PROC_DISCOCOMMANDS, + IQ_PROC_EXECCOMMANDS, +} JABBER_IQ_PROCID; + +struct CJabberProto; +typedef void ( CJabberProto::*JABBER_IQ_PFUNC )( HXML iqNode ); +typedef void ( *IQ_USER_DATA_FREE_FUNC )( void *pUserData ); + +typedef struct { + TCHAR* xmlns; + JABBER_IQ_PFUNC func; + BOOL allowSubNs; // e.g. #info in disco#info +} JABBER_IQ_XMLNS_FUNC; + +// 2 minutes, milliseconds +#define JABBER_DEFAULT_IQ_REQUEST_TIMEOUT 120000 + +typedef void ( CJabberProto::*JABBER_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); +typedef BOOL ( CJabberProto::*JABBER_PERMANENT_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); + +#define JABBER_IQ_PARSE_CHILD_TAG_NODE (1) +#define JABBER_IQ_PARSE_CHILD_TAG_NAME ((1<<1)|JABBER_IQ_PARSE_CHILD_TAG_NODE) +#define JABBER_IQ_PARSE_CHILD_TAG_XMLNS ((1<<2)|JABBER_IQ_PARSE_CHILD_TAG_NODE) +#define JABBER_IQ_PARSE_FROM (1<<3) +#define JABBER_IQ_PARSE_HCONTACT ((1<<4)|JABBER_IQ_PARSE_FROM) +#define JABBER_IQ_PARSE_TO (1<<5) +#define JABBER_IQ_PARSE_ID_STR (1<<6) + +#define JABBER_IQ_PARSE_DEFAULT (JABBER_IQ_PARSE_CHILD_TAG_NODE|JABBER_IQ_PARSE_CHILD_TAG_NAME|JABBER_IQ_PARSE_CHILD_TAG_XMLNS) + +class CJabberIqInfo +{ +protected: + friend class CJabberIqManager; + JABBER_IQ_HANDLER m_pHandler; + CJabberIqInfo* m_pNext; + + int m_nIqId; + DWORD m_dwParamsToParse; + DWORD m_dwRequestTime; + DWORD m_dwTimeout; + TCHAR *m_szReceiver; + int m_iPriority; +public: + void *m_pUserData; +public:// parsed data + int m_nIqType; + TCHAR *m_szFrom; + TCHAR *m_szChildTagXmlns; + TCHAR *m_szChildTagName; + HXML m_pChildNode; + HANDLE m_hContact; + TCHAR *m_szTo; + TCHAR *m_szId; +public: + CJabberIqInfo() + { + ZeroMemory(this, sizeof(CJabberIqInfo)); + } + ~CJabberIqInfo() + { + if (m_szReceiver) + mir_free(m_szReceiver); + } + void SetReceiver(const TCHAR *szReceiver) + { + replaceStrT(m_szReceiver, szReceiver); + } + TCHAR* GetReceiver() + { + return m_szReceiver; + } + void SetParamsToParse(DWORD dwParamsToParse) + { + m_dwParamsToParse = dwParamsToParse; + } + void SetTimeout(DWORD dwTimeout) + { + m_dwTimeout = dwTimeout; + } + int GetIqId() + { + return m_nIqId; + } + DWORD GetRequestTime() + { + return m_dwRequestTime; + } + int GetIqType() + { + return m_nIqType; + } + void* GetUserData() + { + return m_pUserData; + } + TCHAR* GetFrom() + { + return m_szFrom; + } + TCHAR* GetTo() + { + return m_szTo; + } + TCHAR* GetIdStr() + { + return m_szId; + } + HANDLE GetHContact() + { + return m_hContact; + } + HXML GetChildNode() + { + return m_pChildNode; + } + TCHAR* GetChildNodeName() + { + return m_szChildTagName; + } + char* GetCharIqType() + { + switch (m_nIqType) + { + case JABBER_IQ_TYPE_SET: return "set"; + case JABBER_IQ_TYPE_GET: return "get"; + case JABBER_IQ_TYPE_ERROR: return "error"; + case JABBER_IQ_TYPE_RESULT: return "result"; + } + return NULL; + } +}; + +class CJabberIqPermanentInfo +{ + friend class CJabberIqManager; + + CJabberIqPermanentInfo* m_pNext; + + JABBER_PERMANENT_IQ_HANDLER m_pHandler; + DWORD m_dwParamsToParse; + int m_nIqTypes; + TCHAR* m_szXmlns; + TCHAR* m_szTag; + BOOL m_bAllowPartialNs; + void *m_pUserData; + IQ_USER_DATA_FREE_FUNC m_pUserDataFree; + int m_iPriority; +public: + CJabberIqPermanentInfo() + { + ZeroMemory(this, sizeof(CJabberIqPermanentInfo)); + } + ~CJabberIqPermanentInfo() + { + if ( m_pUserDataFree ) + m_pUserDataFree(m_pUserData); + mir_free(m_szXmlns); + mir_free(m_szTag); + } +}; + +class CJabberIqManager +{ +protected: + CJabberProto* ppro; + CRITICAL_SECTION m_cs; + DWORD m_dwLastUsedHandle; + CJabberIqInfo* m_pIqs; // list of iqs ordered by priority + HANDLE m_hExpirerThread; + BOOL m_bExpirerThreadShutdownRequest; + + CJabberIqPermanentInfo* m_pPermanentHandlers; + + CJabberIqInfo* DetachInfo(int nIqId) + { + if (!m_pIqs) + return NULL; + + CJabberIqInfo* pInfo = m_pIqs; + if (m_pIqs->m_nIqId == nIqId) + { + m_pIqs = pInfo->m_pNext; + pInfo->m_pNext = NULL; + return pInfo; + } + + while (pInfo->m_pNext) + { + if (pInfo->m_pNext->m_nIqId == nIqId) + { + CJabberIqInfo* pRetVal = pInfo->m_pNext; + pInfo->m_pNext = pInfo->m_pNext->m_pNext; + pRetVal->m_pNext = NULL; + return pRetVal; + } + pInfo = pInfo->m_pNext; + } + return NULL; + } + CJabberIqInfo* DetachInfo(void *pUserData) + { + if (!m_pIqs) + return NULL; + + CJabberIqInfo* pInfo = m_pIqs; + if (m_pIqs->m_pUserData == pUserData) + { + m_pIqs = pInfo->m_pNext; + pInfo->m_pNext = NULL; + return pInfo; + } + + while (pInfo->m_pNext) + { + if (pInfo->m_pNext->m_pUserData == pUserData) + { + CJabberIqInfo* pRetVal = pInfo->m_pNext; + pInfo->m_pNext = pInfo->m_pNext->m_pNext; + pRetVal->m_pNext = NULL; + return pRetVal; + } + pInfo = pInfo->m_pNext; + } + return NULL; + } + CJabberIqInfo* DetachExpired() + { + if (!m_pIqs) + return NULL; + + DWORD dwCurrentTime = GetTickCount(); + + CJabberIqInfo* pInfo = m_pIqs; + if (dwCurrentTime - pInfo->m_dwRequestTime > pInfo->m_dwTimeout ) + { + m_pIqs = pInfo->m_pNext; + pInfo->m_pNext = NULL; + return pInfo; + } + + while (pInfo->m_pNext) + { + if (dwCurrentTime - pInfo->m_pNext->m_dwRequestTime > pInfo->m_pNext->m_dwTimeout ) + { + CJabberIqInfo* pRetVal = pInfo->m_pNext; + pInfo->m_pNext = pInfo->m_pNext->m_pNext; + pRetVal->m_pNext = NULL; + return pRetVal; + } + pInfo = pInfo->m_pNext; + } + return NULL; + } + void ExpireInfo( CJabberIqInfo* pInfo, void *pUserData = NULL ); + BOOL InsertIq(CJabberIqInfo* pInfo) + { // inserts pInfo at a place determined by pInfo->m_iPriority + Lock(); + if (!m_pIqs) + m_pIqs = pInfo; + else + { + if (m_pIqs->m_iPriority > pInfo->m_iPriority) { + pInfo->m_pNext = m_pIqs; + m_pIqs = pInfo; + } else + { + CJabberIqInfo* pTmp = m_pIqs; + while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) + pTmp = pTmp->m_pNext; + pInfo->m_pNext = pTmp->m_pNext; + pTmp->m_pNext = pInfo; + } + } + Unlock(); + return TRUE; + } +public: + CJabberIqManager( CJabberProto* proto ) + { + InitializeCriticalSection(&m_cs); + m_dwLastUsedHandle = 0; + m_pIqs = NULL; + m_hExpirerThread = NULL; + m_pPermanentHandlers = NULL; + ppro = proto; + } + ~CJabberIqManager() + { + ExpireAll(); + Lock(); + CJabberIqPermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo ) + { + CJabberIqPermanentInfo *pTmp = pInfo->m_pNext; + delete pInfo; + pInfo = pTmp; + } + m_pPermanentHandlers = NULL; + Unlock(); + DeleteCriticalSection(&m_cs); + } + BOOL Start(); + BOOL Shutdown() + { + if ( m_bExpirerThreadShutdownRequest || !m_hExpirerThread ) + return TRUE; + + m_bExpirerThreadShutdownRequest = TRUE; + + WaitForSingleObject( m_hExpirerThread, INFINITE ); + CloseHandle( m_hExpirerThread ); + m_hExpirerThread = NULL; + + return TRUE; + } + void Lock() + { + EnterCriticalSection(&m_cs); + } + void Unlock() + { + LeaveCriticalSection(&m_cs); + } + // fucking params, maybe just return CJabberIqRequestInfo pointer ? + CJabberIqInfo* AddHandler(JABBER_IQ_HANDLER pHandler, int nIqType = JABBER_IQ_TYPE_GET, const TCHAR *szReceiver = NULL, DWORD dwParamsToParse = 0, int nIqId = -1, void *pUserData = NULL, int iPriority = JH_PRIORITY_DEFAULT); + CJabberIqPermanentInfo* AddPermanentHandler(JABBER_PERMANENT_IQ_HANDLER pHandler, int nIqTypes, DWORD dwParamsToParse, const TCHAR* szXmlns, BOOL bAllowPartialNs, const TCHAR* szTag, void *pUserData = NULL, IQ_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) + { + CJabberIqPermanentInfo* pInfo = new CJabberIqPermanentInfo(); + if (!pInfo) + return NULL; + + pInfo->m_pHandler = pHandler; + pInfo->m_nIqTypes = nIqTypes ? nIqTypes : JABBER_IQ_TYPE_ANY; + replaceStrT( pInfo->m_szXmlns, szXmlns ); + pInfo->m_bAllowPartialNs = bAllowPartialNs; + replaceStrT( pInfo->m_szTag, szTag ); + pInfo->m_dwParamsToParse = dwParamsToParse; + pInfo->m_pUserData = pUserData; + pInfo->m_pUserDataFree = pUserDataFree; + pInfo->m_iPriority = iPriority; + + Lock(); + if (!m_pPermanentHandlers) + m_pPermanentHandlers = pInfo; + else + { + if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { + pInfo->m_pNext = m_pPermanentHandlers; + m_pPermanentHandlers = pInfo; + } else + { + CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) + pTmp = pTmp->m_pNext; + pInfo->m_pNext = pTmp->m_pNext; + pTmp->m_pNext = pInfo; + } + } + Unlock(); + + return pInfo; + } + BOOL DeletePermanentHandler(CJabberIqPermanentInfo *pInfo) + { // returns TRUE when pInfo found, or FALSE otherwise + Lock(); + if (!m_pPermanentHandlers) + { + Unlock(); + return FALSE; + } + if (m_pPermanentHandlers == pInfo) // check first item + { + m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } else + { + CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext) + { + if (pTmp->m_pNext == pInfo) + { + pTmp->m_pNext = pTmp->m_pNext->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } + pTmp = pTmp->m_pNext; + } + } + Unlock(); + return FALSE; + } + BOOL DeleteHandler(CJabberIqInfo *pInfo) + { // returns TRUE when pInfo found, or FALSE otherwise + Lock(); + if (!m_pIqs) + { + Unlock(); + return FALSE; + } + if (m_pIqs == pInfo) // check first item + { + m_pIqs = m_pIqs->m_pNext; + Unlock(); + ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary + delete pInfo; + return TRUE; + } else + { + CJabberIqInfo* pTmp = m_pIqs; + while (pTmp->m_pNext) + { + if (pTmp->m_pNext == pInfo) + { + pTmp->m_pNext = pTmp->m_pNext->m_pNext; + Unlock(); + ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary + delete pInfo; + return TRUE; + } + pTmp = pTmp->m_pNext; + } + } + Unlock(); + return FALSE; + } + BOOL HandleIq(int nIqId, HXML pNode); + BOOL HandleIqPermanent(HXML pNode); + BOOL ExpireIq(int nIqId) + { + Lock(); + CJabberIqInfo* pInfo = DetachInfo(nIqId); + Unlock(); + if (pInfo) + { + ExpireInfo(pInfo); + delete pInfo; + return TRUE; + } + return FALSE; + } + void ExpirerThread( void ); + BOOL ExpireByUserData(void *pUserData) + { + BOOL bRetVal = FALSE; + while (1) + { + Lock(); + CJabberIqInfo* pInfo = DetachInfo(pUserData); + Unlock(); + if (!pInfo) + break; + ExpireInfo(pInfo, NULL); + delete pInfo; + bRetVal = TRUE; + } + return bRetVal; + } + BOOL ExpireAll(void *pUserData = NULL) + { + while (1) + { + Lock(); + CJabberIqInfo* pInfo = m_pIqs; + if (pInfo) + m_pIqs = m_pIqs->m_pNext; + Unlock(); + if (!pInfo) + break; + pInfo->m_pNext = NULL; + ExpireInfo(pInfo, pUserData); + delete pInfo; + } + return TRUE; + } + BOOL FillPermanentHandlers(); +}; + +#endif diff --git a/protocols/JabberG/src/jabber_iq_handlers.cpp b/protocols/JabberG/src/jabber_iq_handlers.cpp new file mode 100644 index 0000000000..7f3385ff6e --- /dev/null +++ b/protocols/JabberG/src/jabber_iq_handlers.cpp @@ -0,0 +1,775 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#include <io.h> +#include "version.h" +#include "jabber_iq.h" +#include "jabber_rc.h" + +extern int bSecureIM; + +#ifndef VER_SUITE_WH_SERVER + #define VER_SUITE_WH_SERVER 0x00008000 +#endif + +#ifndef PRODUCT_ULTIMATE + #define PRODUCT_UNDEFINED 0x00000000 + #define PRODUCT_ULTIMATE 0x00000001 + #define PRODUCT_HOME_BASIC 0x00000002 + #define PRODUCT_HOME_PREMIUM 0x00000003 + #define PRODUCT_ENTERPRISE 0x00000004 + #define PRODUCT_HOME_BASIC_N 0x00000005 + #define PRODUCT_BUSINESS 0x00000006 + #define PRODUCT_STANDARD_SERVER 0x00000007 + #define PRODUCT_DATACENTER_SERVER 0x00000008 + #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009 + #define PRODUCT_ENTERPRISE_SERVER 0x0000000A + #define PRODUCT_STARTER 0x0000000B + #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C + #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D + #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E + #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F + #define PRODUCT_BUSINESS_N 0x00000010 + #define PRODUCT_WEB_SERVER 0x00000011 + #define PRODUCT_CLUSTER_SERVER 0x00000012 + #define PRODUCT_HOME_SERVER 0x00000013 + #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014 + #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015 + #define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016 + #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017 + #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018 + #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x00000019 + #define PRODUCT_UNLICENSED 0xABCDABCD +#endif + +typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); +typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); + +#define StringCchCopy(x,y,z) lstrcpyn((x),(z),(y)) +#define StringCchCat(x,y,z) lstrcat((x),(z)) +#define StringCchPrintf mir_sntprintf + +// slightly modified sample from MSDN +BOOL GetOSDisplayString(LPTSTR pszOS, int BUFSIZE) +{ + OSVERSIONINFOEX osvi; + SYSTEM_INFO si; + PGNSI pGNSI; + PGPI pGPI; + + DWORD dwType; + + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + BOOL bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi); + if ( !bOsVersionInfoEx ) + { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (!GetVersionEx((OSVERSIONINFO*)&osvi)) + return FALSE; + } + + // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. + HMODULE hKernel = GetModuleHandle(TEXT("kernel32.dll")); + pGNSI = (PGNSI) GetProcAddress(hKernel,"GetNativeSystemInfo"); + if(NULL != pGNSI) + pGNSI(&si); + else GetSystemInfo(&si); + + //Some code from Crash Dumper Plugin :-) + if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion > 4 ) + { + StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft ")); + + // Test for the specific product. + if (osvi.dwMajorVersion == 6) + { + switch (osvi.dwMinorVersion) + { + case 0: + if (osvi.wProductType == VER_NT_WORKSTATION) + StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista ")); + else + StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 ")); + break; + + case 1: + if (osvi.wProductType == VER_NT_WORKSTATION) + StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 ")); + else + StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 ")); + break; + + default: + if (osvi.wProductType == VER_NT_WORKSTATION) + StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8 ")); + else + StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 ")); + break; + } + + pGPI = (PGPI) GetProcAddress(hKernel, "GetProductInfo"); + if(pGPI != NULL) pGPI( 6, 0, 0, 0, &dwType); + + switch( dwType ) + { + case PRODUCT_ULTIMATE: + StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" )); + break; + case PRODUCT_HOME_PREMIUM: + StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" )); + break; + case PRODUCT_HOME_BASIC: + StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" )); + break; + case PRODUCT_ENTERPRISE: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); + break; + case PRODUCT_BUSINESS: + StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" )); + break; + case PRODUCT_STARTER: + StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" )); + break; + case PRODUCT_CLUSTER_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" )); + break; + case PRODUCT_DATACENTER_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" )); + break; + case PRODUCT_DATACENTER_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" )); + break; + case PRODUCT_ENTERPRISE_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); + break; + case PRODUCT_ENTERPRISE_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" )); + break; + case PRODUCT_ENTERPRISE_SERVER_IA64: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" )); + break; + case PRODUCT_SMALLBUSINESS_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" )); + break; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" )); + break; + case PRODUCT_STANDARD_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" )); + break; + case PRODUCT_STANDARD_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" )); + break; + case PRODUCT_WEB_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" )); + break; + } + if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) + StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" )); + else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) + StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit")); + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) + { + if ( GetSystemMetrics(SM_SERVERR2)) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, ")); + else if ( osvi.wSuiteMask==VER_SUITE_STORAGE_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003")); + else if ( osvi.wSuiteMask==VER_SUITE_WH_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server")); + else if ( osvi.wProductType == VER_NT_WORKSTATION && + si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) + { + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition")); + } + else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, ")); + + // Test for the server type. + if ( osvi.wProductType != VER_NT_WORKSTATION ) + { + if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) + { + if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" )); + else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" )); + } + + else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) + { + if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" )); + else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" )); + } + + else + { + if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" )); + else if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" )); + else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" )); + else if ( osvi.wSuiteMask & VER_SUITE_BLADE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" )); + } + } + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP ")); + if ( osvi.wSuiteMask & VER_SUITE_PERSONAL ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 ")); + + if ( osvi.wProductType == VER_NT_WORKSTATION ) + { + StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); + } + else + { + if ( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" )); + else if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" )); + } + } + + // Include service pack (if any) and build number. + + if ( _tcslen(osvi.szCSDVersion) > 0 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT(" ")); + StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion); + } + + TCHAR buf[80]; + + StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber); + StringCchCat(pszOS, BUFSIZE, buf); + + return TRUE; + } + else + { + return FALSE; + } +} + + +BOOL CJabberProto::OnIqRequestVersion( HXML, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->GetFrom()) + return TRUE; + + if ( !m_options.AllowVersionRequests ) + return FALSE; + + XmlNodeIq iq( _T("result"), pInfo ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_VERSION)); + query << XCHILD( _T("name"), _T("Miranda NG Jabber")); + query << XCHILD( _T("version"), szCoreVersion); + + if ( m_options.ShowOSVersion ) + { + TCHAR os[256] = {0}; + if (!GetOSDisplayString(os, SIZEOF(os))) + lstrcpyn(os, _T("Microsoft Windows"), SIZEOF(os)); + query << XCHILD( _T("os"), os ); + } + + m_ThreadInfo->send( iq ); + return TRUE; +} + +// last activity (XEP-0012) support +BOOL CJabberProto::OnIqRequestLastActivity( HXML, CJabberIqInfo *pInfo ) +{ + m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)) + << XATTRI( _T("seconds"), m_tmJabberIdleStartTime ? time( 0 ) - m_tmJabberIdleStartTime : 0 )); + return TRUE; +} + +// XEP-0199: XMPP Ping support +BOOL CJabberProto::OnIqRequestPing( HXML, CJabberIqInfo *pInfo ) +{ + m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo ) << XATTR( _T("from"), m_ThreadInfo->fullJID )); + return TRUE; +} + +// Returns the current GMT offset in seconds +int GetGMTOffset(void) +{ + TIME_ZONE_INFORMATION tzinfo; + int nOffset = 0; + + DWORD dwResult= GetTimeZoneInformation(&tzinfo); + + switch(dwResult) { + case TIME_ZONE_ID_STANDARD: + nOffset = tzinfo.Bias + tzinfo.StandardBias; + break; + case TIME_ZONE_ID_DAYLIGHT: + nOffset = tzinfo.Bias + tzinfo.DaylightBias; + break; + case TIME_ZONE_ID_UNKNOWN: + nOffset = tzinfo.Bias; + break; + case TIME_ZONE_ID_INVALID: + default: + nOffset = 0; + break; + } + + return -nOffset; +} + +// entity time (XEP-0202) support +BOOL CJabberProto::OnIqRequestTime( HXML, CJabberIqInfo *pInfo ) +{ + TCHAR stime[100]; + TCHAR szTZ[10]; + + tmi.printDateTime(UTC_TIME_HANDLE, _T("I"), stime, SIZEOF(stime), 0); + + int nGmtOffset = GetGMTOffset(); + mir_sntprintf(szTZ, SIZEOF(szTZ), _T("%+03d:%02d"), nGmtOffset / 60, nGmtOffset % 60 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML timeNode = iq << XCHILDNS( _T("time"), _T(JABBER_FEAT_ENTITY_TIME)); + timeNode << XCHILD( _T("utc"), stime); timeNode << XCHILD( _T("tzo"), szTZ ); + LPCTSTR szTZName = tmi.getTzName( NULL ); + if ( szTZName ) + timeNode << XCHILD( _T("tz"), szTZName ); + m_ThreadInfo->send( iq ); + return TRUE; +} + +BOOL CJabberProto::OnIqProcessIqOldTime( HXML, CJabberIqInfo *pInfo ) +{ + struct tm *gmt; + time_t ltime; + TCHAR stime[ 100 ], *dtime; + + _tzset(); + time( <ime ); + gmt = gmtime( <ime ); + mir_sntprintf( stime, SIZEOF(stime), _T("%.4i%.2i%.2iT%.2i:%.2i:%.2i"), + gmt->tm_year + 1900, gmt->tm_mon + 1, + gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec ); + dtime = _tctime( <ime ); + dtime[ 24 ] = 0; + + XmlNodeIq iq( _T("result"), pInfo ); + HXML queryNode = iq << XQUERY( _T(JABBER_FEAT_ENTITY_TIME_OLD)); + queryNode << XCHILD( _T("utc"), stime ); + LPCTSTR szTZName = tmi.getTzName( NULL ); + if ( szTZName ) + queryNode << XCHILD( _T("tz"), szTZName ); + queryNode << XCHILD( _T("display"), dtime ); + m_ThreadInfo->send( iq ); + return TRUE; +} + +BOOL CJabberProto::OnIqRequestAvatar( HXML, CJabberIqInfo *pInfo ) +{ + if ( !m_options.EnableAvatars ) + return TRUE; + + int pictureType = m_options.AvatarType; + if ( pictureType == PA_FORMAT_UNKNOWN ) + return TRUE; + + TCHAR* szMimeType; + switch( pictureType ) { + case PA_FORMAT_JPEG: szMimeType = _T("image/jpeg"); break; + case PA_FORMAT_GIF: szMimeType = _T("image/gif"); break; + case PA_FORMAT_PNG: szMimeType = _T("image/png"); break; + case PA_FORMAT_BMP: szMimeType = _T("image/bmp"); break; + default: return TRUE; + } + + TCHAR szFileName[ MAX_PATH ]; + GetAvatarFileName( NULL, szFileName, SIZEOF(szFileName)); + + FILE* in = _tfopen( szFileName, _T("rb")); + if ( in == NULL ) + return TRUE; + + long bytes = _filelength( _fileno( in )); + char* buffer = ( char* )mir_alloc( bytes*4/3 + bytes + 1000 ); + if ( buffer == NULL ) { + fclose( in ); + return TRUE; + } + + fread( buffer, bytes, 1, in ); + fclose( in ); + + char* str = JabberBase64Encode( buffer, bytes ); + m_ThreadInfo->send( XmlNodeIq( _T("result"), pInfo ) << XQUERY( _T(JABBER_FEAT_AVATAR)) << XCHILD( _T("query"), _A2T(str)) << XATTR( _T("mimetype"), szMimeType )); + mir_free( str ); + mir_free( buffer ); + return TRUE; +} + +BOOL CJabberProto::OnSiRequest( HXML node, CJabberIqInfo *pInfo ) +{ + const TCHAR* szProfile = xmlGetAttrValue( pInfo->GetChildNode(), _T("profile")); + + if ( szProfile && !_tcscmp( szProfile, _T(JABBER_FEAT_SI_FT))) + FtHandleSiRequest( node ); + else { + XmlNodeIq iq( _T("error"), pInfo ); + HXML error = iq << XCHILD( _T("error")) << XATTRI( _T("code"), 400 ) << XATTR( _T("type"), _T("cancel")); + error << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + error << XCHILD( _T("bad-profile")); + m_ThreadInfo->send( iq ); + } + return TRUE; +} + +BOOL CJabberProto::OnRosterPushRequest( HXML, CJabberIqInfo *pInfo ) +{ + HXML queryNode = pInfo->GetChildNode(); + + // RFC 3921 #7.2 Business Rules + if ( pInfo->GetFrom()) { + TCHAR* szFrom = JabberPrepareJid( pInfo->GetFrom()); + if ( !szFrom ) + return TRUE; + + TCHAR* szTo = JabberPrepareJid( m_ThreadInfo->fullJID ); + if ( !szTo ) { + mir_free( szFrom ); + return TRUE; + } + + TCHAR* pDelimiter = _tcschr( szFrom, _T('/')); + if ( pDelimiter ) *pDelimiter = _T('\0'); + + pDelimiter = _tcschr( szTo, _T('/')); + if ( pDelimiter ) *pDelimiter = _T('\0'); + + BOOL bRetVal = _tcscmp( szFrom, szTo ) == 0; + + mir_free( szFrom ); + mir_free( szTo ); + + // invalid JID + if ( !bRetVal ) { + Log( "<iq/> attempt to hack via roster push from " TCHAR_STR_PARAM, pInfo->GetFrom()); + return TRUE; + } + } + + JABBER_LIST_ITEM *item; + HANDLE hContact = NULL; + const TCHAR *jid, *str, *name; + TCHAR* nick; + + Log( "<iq/> Got roster push, query has %d children", xmlGetChildCount( queryNode )); + for ( int i=0; ; i++ ) { + HXML itemNode = xmlGetChild( queryNode ,i); + if ( !itemNode ) + break; + + if ( _tcscmp( xmlGetName( itemNode ), _T("item")) != 0 ) + continue; + if (( jid = xmlGetAttrValue( itemNode, _T("jid"))) == NULL ) + continue; + if (( str = xmlGetAttrValue( itemNode, _T("subscription"))) == NULL ) + continue; + + // we will not add new account when subscription=remove + if ( !_tcscmp( str, _T("to")) || !_tcscmp( str, _T("both")) || !_tcscmp( str, _T("from")) || !_tcscmp( str, _T("none"))) { + if (( name = xmlGetAttrValue( itemNode, _T("name"))) != NULL ) + nick = mir_tstrdup( name ); + else + nick = JabberNickFromJID( jid ); + + if ( nick != NULL ) { + if (( item=ListAdd( LIST_ROSTER, jid )) != NULL ) { + replaceStrT( item->nick, nick ); + + HXML groupNode = xmlGetChild( itemNode , "group" ); + replaceStrT( item->group, ( groupNode ) ? xmlGetText( groupNode ) : NULL ); + + if (( hContact=HContactFromJID( jid, 0 )) == NULL ) { + // Received roster has a new JID. + // Add the jid ( with empty resource ) to Miranda contact list. + hContact = DBCreateContact( jid, nick, FALSE, FALSE ); + } + else JSetStringT( hContact, "jid", jid ); + + if ( name != NULL ) { + DBVARIANT dbnick; + if ( !JGetStringT( hContact, "Nick", &dbnick )) { + if ( _tcscmp( nick, dbnick.ptszVal ) != 0 ) + DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); + else + DBDeleteContactSetting( hContact, "CList", "MyHandle" ); + + JFreeVariant( &dbnick ); + } + else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); + } + else DBDeleteContactSetting( hContact, "CList", "MyHandle" ); + + if (!m_options.IgnoreRosterGroups) + { + if ( item->group != NULL ) { + JabberContactListCreateGroup( item->group ); + DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); + } + else + DBDeleteContactSetting( hContact, "CList", "Group" ); + } + } + mir_free( nick ); + } } + + if (( item=ListGetItemPtr( LIST_ROSTER, jid )) != NULL ) { + if ( !_tcscmp( str, _T("both"))) item->subscription = SUB_BOTH; + else if ( !_tcscmp( str, _T("to"))) item->subscription = SUB_TO; + else if ( !_tcscmp( str, _T("from"))) item->subscription = SUB_FROM; + else item->subscription = SUB_NONE; + Log( "Roster push for jid=" TCHAR_STR_PARAM ", set subscription to " TCHAR_STR_PARAM, jid, str ); + // subscription = remove is to remove from roster list + // but we will just set the contact to offline and not actually + // remove, so that history will be retained. + if ( !_tcscmp( str, _T("remove"))) { + if (( hContact=HContactFromJID( jid )) != NULL ) { + SetContactOfflineStatus( hContact ); + ListRemove( LIST_ROSTER, jid ); + } } + else if ( JGetByte( hContact, "ChatRoom", 0 )) + DBDeleteContactSetting( hContact, "CList", "Hidden" ); + else + UpdateSubscriptionInfo( hContact, item ); + } } + + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); + RebuildInfoFrame(); + return TRUE; +} + +BOOL CJabberProto::OnIqRequestOOB( HXML, CJabberIqInfo *pInfo ) +{ + if ( !pInfo->GetFrom() || !pInfo->GetHContact()) + return TRUE; + + HXML n = xmlGetChild( pInfo->GetChildNode(), "url" ); + if ( !n || !xmlGetText( n )) + return TRUE; + + if ( m_options.BsOnlyIBB ) { + // reject + XmlNodeIq iq( _T("error"), pInfo ); + HXML e = xmlAddChild( iq, _T("error"), _T("File transfer refused")); xmlAddAttr( e, _T("code"), 406 ); + m_ThreadInfo->send( iq ); + return TRUE; + } + + TCHAR text[ 1024 ]; + TCHAR *str, *p, *q; + + str = ( TCHAR* )xmlGetText( n ); // URL of the file to get + filetransfer* ft = new filetransfer( this ); + ft->std.totalFiles = 1; + ft->jid = mir_tstrdup( pInfo->GetFrom()); + ft->std.hContact = pInfo->GetHContact(); + ft->type = FT_OOB; + ft->httpHostName = NULL; + ft->httpPort = 80; + ft->httpPath = NULL; + + // Parse the URL + if ( !_tcsnicmp( str, _T("http://"), 7 )) { + p = str + 7; + if (( q = _tcschr( p, '/' )) != NULL ) { + if ( q-p < SIZEOF( text )) { + _tcsncpy( text, p, q-p ); + text[q-p] = '\0'; + if (( p = _tcschr( text, ':' )) != NULL ) { + ft->httpPort = ( WORD )_ttoi( p+1 ); + *p = '\0'; + } + ft->httpHostName = mir_t2a( text ); + } } } + + if ( pInfo->GetIdStr()) + ft->iqId = mir_tstrdup( pInfo->GetIdStr()); + + if ( ft->httpHostName && ft->httpPath ) { + TCHAR* desc = NULL; + + Log( "Host=%s Port=%d Path=%s", ft->httpHostName, ft->httpPort, ft->httpPath ); + if (( n = xmlGetChild( pInfo->GetChildNode(), "desc" )) != NULL ) + desc = ( TCHAR* )xmlGetText( n ); + + TCHAR* str2; + Log( "description = %s", desc ); + if (( str2 = _tcsrchr( ft->httpPath, '/' )) != NULL ) + str2++; + else + str2 = ft->httpPath; + str2 = mir_tstrdup( str2 ); + JabberHttpUrlDecode( str2 ); + + PROTORECVFILET pre; + pre.flags = PREF_TCHAR; + pre.timestamp = time( NULL ); + pre.tszDescription = desc; + pre.ptszFiles = &str2; + pre.fileCount = 1; + pre.lParam = ( LPARAM )ft; + + CCSDATA ccs = { ft->std.hContact, PSR_FILE, 0, ( LPARAM )&pre }; + CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); + mir_free( str2 ); + } + else { + // reject + XmlNodeIq iq( _T("error"), pInfo ); + HXML e = xmlAddChild( iq, _T("error"), _T("File transfer refused")); xmlAddAttr( e, _T("code"), 406 ); + m_ThreadInfo->send( iq ); + delete ft; + } + return TRUE; +} + +BOOL CJabberProto::OnHandleDiscoInfoRequest( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->GetChildNode()) + return TRUE; + + const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); + // caps hack + if ( m_clientCapsManager.HandleInfoRequest( iqNode, pInfo, szNode )) + return TRUE; + + // ad-hoc hack: + if ( szNode && m_adhocManager.HandleInfoRequest( iqNode, pInfo, szNode )) + return TRUE; + + // another request, send empty result + m_ThreadInfo->send( + XmlNodeIq( _T("error"), pInfo ) + << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + return TRUE; +} + +BOOL CJabberProto::OnHandleDiscoItemsRequest( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->GetChildNode()) + return TRUE; + + // ad-hoc commands check: + const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); + if ( szNode && m_adhocManager.HandleItemsRequest( iqNode, pInfo, szNode )) + return TRUE; + + // another request, send empty result + XmlNodeIq iq( _T("result"), pInfo ); + HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)); + if ( szNode ) + xmlAddAttr( resultQuery, _T("node"), szNode ); + + if ( !szNode && m_options.EnableRemoteControl ) + resultQuery << XCHILD( _T("item")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) + << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("name"), _T("Ad-hoc commands")); + + m_ThreadInfo->send( iq ); + return TRUE; +} + +BOOL CJabberProto::AddClistHttpAuthEvent( CJabberHttpAuthParams *pParams ) +{ + CLISTEVENT cle = {0}; + char szService[256]; + mir_snprintf( szService, sizeof(szService),"%s%s", m_szModuleName, JS_HTTP_AUTH ); + cle.cbSize = sizeof(CLISTEVENT); + cle.hIcon = (HICON) LoadIconEx("openid"); + cle.flags = CLEF_PROTOCOLGLOBAL | CLEF_TCHAR; + cle.hDbEvent = (HANDLE)("test"); + cle.lParam = (LPARAM) pParams; + cle.pszService = szService; + cle.ptszTooltip = TranslateT("Http authentication request received"); + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + + return TRUE; +} + +BOOL CJabberProto::OnIqHttpAuth( HXML node, CJabberIqInfo* pInfo ) +{ + if ( !m_options.AcceptHttpAuth ) + return TRUE; + + if ( !node || !pInfo->GetChildNode() || !pInfo->GetFrom() || !pInfo->GetIdStr()) + return TRUE; + + HXML pConfirm = xmlGetChild( node , "confirm" ); + if ( !pConfirm ) + return TRUE; + + const TCHAR *szId = xmlGetAttrValue( pConfirm, _T("id")); + const TCHAR *szMethod = xmlGetAttrValue( pConfirm, _T("method")); + const TCHAR *szUrl = xmlGetAttrValue( pConfirm, _T("url")); + + if ( !szId || !szMethod || !szUrl ) + return TRUE; + + CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)mir_alloc( sizeof( CJabberHttpAuthParams )); + if ( !pParams ) + return TRUE; + ZeroMemory( pParams, sizeof( CJabberHttpAuthParams )); + pParams->m_nType = CJabberHttpAuthParams::IQ; + pParams->m_szFrom = mir_tstrdup( pInfo->GetFrom()); + pParams->m_szId = mir_tstrdup( szId ); + pParams->m_szMethod = mir_tstrdup( szMethod ); + pParams->m_szUrl = mir_tstrdup( szUrl ); + + AddClistHttpAuthEvent( pParams ); + + return TRUE; +} diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp new file mode 100644 index 0000000000..7679450d59 --- /dev/null +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -0,0 +1,1742 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "jabber_privacy.h" + +#include "m_genmenu.h" +#include "m_clistint.h" + +void CJabberProto::OnIqResultServerDiscoInfo( HXML iqNode ) +{ + if ( !iqNode ) + return; + + const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); + int i; + + if ( !_tcscmp( type, _T("result"))) { + HXML query = xmlGetChildByTag( iqNode, "query", "xmlns", _T(JABBER_FEAT_DISCO_INFO)); + if ( !query ) + return; + + HXML identity; + for ( i = 1; ( identity = xmlGetNthChild( query, _T("identity"), i )) != NULL; i++ ) { + const TCHAR *identityCategory = xmlGetAttrValue( identity, _T("category")); + const TCHAR *identityType = xmlGetAttrValue( identity, _T("type")); + const TCHAR *identityName = xmlGetAttrValue( identity, _T("name")); + if ( identityCategory && identityType && !_tcscmp( identityCategory, _T("pubsub")) && !_tcscmp( identityType, _T("pep"))) { + m_bPepSupported = TRUE; + + EnableMenuItems( TRUE ); + RebuildInfoFrame(); + } + else if ( identityCategory && identityType && identityName && + !_tcscmp( identityCategory, _T("server")) && + !_tcscmp( identityType, _T("im")) && + !_tcscmp( identityName, _T("Google Talk"))) { + m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PING; + m_bGoogleTalk = true; + + // Google Shared Status + m_ThreadInfo->send( + XmlNodeIq(m_iqManager.AddHandler(&CJabberProto::OnIqResultGoogleSharedStatus, JABBER_IQ_TYPE_GET)) + << XQUERY(_T(JABBER_FEAT_GTALK_SHARED_STATUS)) << XATTR(_T("version"), _T("2"))); + } + } + if ( m_ThreadInfo ) { + HXML feature; + for ( i = 1; ( feature = xmlGetNthChild( query, _T("feature"), i )) != NULL; i++ ) { + const TCHAR *featureName = xmlGetAttrValue( feature, _T("var")); + if ( featureName ) { + for ( int j = 0; g_JabberFeatCapPairs[j].szFeature; j++ ) { + if ( !_tcscmp( g_JabberFeatCapPairs[j].szFeature, featureName )) { + m_ThreadInfo->jabberServerCaps |= g_JabberFeatCapPairs[j].jcbCap; + break; + } } } } } + + OnProcessLoginRq( m_ThreadInfo, JABBER_LOGIN_SERVERINFO); +} } + +void CJabberProto::OnIqResultNestedRosterGroups( HXML iqNode, CJabberIqInfo* pInfo ) +{ + const TCHAR *szGroupDelimeter = NULL; + BOOL bPrivateStorageSupport = FALSE; + + if ( iqNode && pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + bPrivateStorageSupport = TRUE; + szGroupDelimeter = XPathFmt( iqNode, _T("query[@xmlns='%s']/roster[@xmlns='%s']"), _T(JABBER_FEAT_PRIVATE_STORAGE), _T( JABBER_FEAT_NESTED_ROSTER_GROUPS )); + if ( szGroupDelimeter && !szGroupDelimeter[0] ) + szGroupDelimeter = NULL; // "" as roster delimeter is not supported :) + } + + // global fuckup + if ( !m_ThreadInfo ) + return; + + // is our default delimiter? + if (( !szGroupDelimeter && bPrivateStorageSupport ) || ( szGroupDelimeter && _tcscmp( szGroupDelimeter, _T("\\")))) + m_ThreadInfo->send( + XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) + << XCHILD( _T("roster"), _T("\\")) << XATTR( _T("xmlns"), _T(JABBER_FEAT_NESTED_ROSTER_GROUPS))); + + // roster request + TCHAR *szUserData = mir_tstrdup( szGroupDelimeter ? szGroupDelimeter : _T("\\")); + m_ThreadInfo->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultGetRoster, JABBER_IQ_TYPE_GET, NULL, 0, -1, (void *)szUserData )) + << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER))); +} + +void CJabberProto::OnIqResultNotes( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( iqNode && pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT ) { + HXML hXmlData = XPathFmt( iqNode, _T("query[@xmlns='%s']/storage[@xmlns='%s']"), + _T(JABBER_FEAT_PRIVATE_STORAGE), _T(JABBER_FEAT_MIRANDA_NOTES)); + if (hXmlData) m_notes.LoadXml(hXmlData); + } +} + +void CJabberProto::OnProcessLoginRq( ThreadData* info, DWORD rq ) +{ + if ( info == NULL ) + return; + + info->dwLoginRqs |= rq; + + if ((info->dwLoginRqs & JABBER_LOGIN_ROSTER) && (info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS) && + (info->dwLoginRqs & JABBER_LOGIN_SERVERINFO) && !(info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS_AJ)) + { + if ( jabberChatDllPresent && m_options.AutoJoinBookmarks) { + LIST<JABBER_LIST_ITEM> ll( 10 ); + LISTFOREACH(i, this, LIST_BOOKMARK) + { + JABBER_LIST_ITEM* item = ListGetItemPtrFromIndex( i ); + if ( item != NULL && !lstrcmp( item->type, _T("conference")) && item->bAutoJoin ) + ll.insert( item ); + } + + for ( int j=0; j < ll.getCount(); j++ ) { + JABBER_LIST_ITEM* item = ll[j]; + + TCHAR room[256], *server, *p; + TCHAR text[128]; + _tcsncpy( text, item->jid, SIZEOF( text )); + _tcsncpy( room, text, SIZEOF( room )); + p = _tcstok( room, _T( "@" )); + server = _tcstok( NULL, _T( "@" )); + if ( item->nick && item->nick[0] != 0 ) + GroupchatJoinRoom( server, p, item->nick, item->password, true ); + else { + TCHAR* nick = JabberNickFromJID( m_szJabberJID ); + GroupchatJoinRoom( server, p, nick, item->password, true ); + mir_free( nick ); + } } + + ll.destroy(); + } + + OnProcessLoginRq( info, JABBER_LOGIN_BOOKMARKS_AJ ); +} } + +void CJabberProto::OnLoggedIn() +{ + m_bJabberOnline = TRUE; + m_tmJabberLoggedInTime = time(0); + + m_ThreadInfo->dwLoginRqs = 0; + + // XEP-0083 support + { + CJabberIqInfo* pIqInfo = m_iqManager.AddHandler( &CJabberProto::OnIqResultNestedRosterGroups, JABBER_IQ_TYPE_GET ); + // ugly hack to prevent hangup during login process + pIqInfo->SetTimeout( 30000 ); + m_ThreadInfo->send( + XmlNodeIq( pIqInfo ) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) + << XCHILDNS( _T("roster"), _T(JABBER_FEAT_NESTED_ROSTER_GROUPS))); + } + + // Server-side notes + { + m_ThreadInfo->send( + XmlNodeIq(m_iqManager.AddHandler(&CJabberProto::OnIqResultNotes, JABBER_IQ_TYPE_GET)) + << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) + << XCHILDNS( _T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES))); + } + + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_DISCOBOOKMARKS, &CJabberProto::OnIqResultDiscoBookmarks); + m_ThreadInfo->send( + XmlNodeIq( _T("get"), iqId) << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)) + << XCHILDNS( _T("storage"), _T("storage:bookmarks"))); + + m_bPepSupported = FALSE; + m_ThreadInfo->jabberServerCaps = JABBER_RESOURCE_CAPS_NONE; + iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultServerDiscoInfo ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, _A2T(m_ThreadInfo->server)) << XQUERY( _T(JABBER_FEAT_DISCO_INFO))); + + QueryPrivacyLists( m_ThreadInfo ); + + char szServerName[ sizeof(m_ThreadInfo->server) ]; + if ( JGetStaticString( "LastLoggedServer", NULL, szServerName, sizeof(szServerName))) + SendGetVcard( m_szJabberJID ); + else if ( strcmp( m_ThreadInfo->server, szServerName )) + SendGetVcard( m_szJabberJID ); + JSetString( NULL, "LastLoggedServer", m_ThreadInfo->server ); + + m_pepServices.ResetPublishAll(); +} + +void CJabberProto::OnIqResultGetAuth( HXML iqNode ) +{ + // RECVED: result of the request for authentication method + // ACTION: send account authentication information to log in + Log( "<iq/> iqIdGetAuth" ); + + HXML queryNode; + const TCHAR* type; + if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; + + if ( !lstrcmp( type, _T("result"))) { + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultSetAuth ); + + XmlNodeIq iq( _T("set"), iqId ); + HXML query = iq << XQUERY( _T("jabber:iq:auth")); + query << XCHILD( _T("username"), m_ThreadInfo->username ); + if ( xmlGetChild( queryNode, "digest" ) != NULL && m_szStreamId ) { + char* str = mir_utf8encodeT( m_ThreadInfo->password ); + char text[200]; + mir_snprintf( text, SIZEOF(text), "%s%s", m_szStreamId, str ); + mir_free( str ); + if (( str=JabberSha1( text )) != NULL ) { + query << XCHILD( _T("digest"), _A2T(str)); + mir_free( str ); + } + } + else if ( xmlGetChild( queryNode, "password" ) != NULL ) + query << XCHILD( _T("password"), m_ThreadInfo->password ); + else { + Log( "No known authentication mechanism accepted by the server." ); + + m_ThreadInfo->send( "</stream:stream>" ); + return; + } + + if ( xmlGetChild( queryNode , "resource" ) != NULL ) + query << XCHILD( _T("resource"), m_ThreadInfo->resource ); + + m_ThreadInfo->send( iq ); + } + else if ( !lstrcmp( type, _T("error"))) { + m_ThreadInfo->send( "</stream:stream>" ); + + TCHAR text[128]; + mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), m_ThreadInfo->username ); + MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); + m_ThreadInfo = NULL; // To disallow auto reconnect +} } + +void CJabberProto::OnIqResultSetAuth( HXML iqNode ) +{ + const TCHAR* type; + + // RECVED: authentication result + // ACTION: if successfully logged in, continue by requesting roster list and set my initial status + Log( "<iq/> iqIdSetAuth" ); + if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + + if ( !lstrcmp( type, _T("result"))) { + DBVARIANT dbv; + if ( JGetStringT( NULL, "Nick", &dbv )) + JSetStringT( NULL, "Nick", m_ThreadInfo->username ); + else + JFreeVariant( &dbv ); + + OnLoggedIn(); + } + // What to do if password error? etc... + else if ( !lstrcmp( type, _T("error"))) { + TCHAR text[128]; + + m_ThreadInfo->send( "</stream:stream>" ); + mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), m_ThreadInfo->username ); + MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); + m_ThreadInfo = NULL; // To disallow auto reconnect +} } + +void CJabberProto::OnIqResultBind( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( !m_ThreadInfo || !iqNode ) + return; + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) { + LPCTSTR szJid = XPathT( iqNode, "bind[@xmlns='urn:ietf:params:xml:ns:xmpp-bind']/jid" ); + if ( szJid ) { + if ( !_tcsncmp( m_ThreadInfo->fullJID, szJid, SIZEOF( m_ThreadInfo->fullJID ))) + Log( "Result Bind: " TCHAR_STR_PARAM " confirmed ", m_ThreadInfo->fullJID ); + else { + Log( "Result Bind: " TCHAR_STR_PARAM " changed to " TCHAR_STR_PARAM, m_ThreadInfo->fullJID, szJid); + _tcsncpy( m_ThreadInfo->fullJID, szJid, SIZEOF( m_ThreadInfo->fullJID )); + } + } + if ( m_ThreadInfo->bIsSessionAvailable ) + m_ThreadInfo->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultSession, JABBER_IQ_TYPE_SET )) + << XCHILDNS( _T("session"), _T("urn:ietf:params:xml:ns:xmpp-session" ))); + else + OnLoggedIn(); + } + else { + //rfc3920 page 39 + m_ThreadInfo->send( "</stream:stream>" ); + m_ThreadInfo = NULL; // To disallow auto reconnect + } +} + +void CJabberProto::OnIqResultSession( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) + OnLoggedIn(); +} + +void CJabberProto::GroupchatJoinByHContact( HANDLE hContact, bool autojoin ) +{ + TCHAR* roomjid = JGetStringT( hContact, "ChatRoomID" ); + if ( !roomjid ) return; + + TCHAR* room = roomjid; + TCHAR* server = _tcschr( roomjid, '@' ); + if ( !server ) { + mir_free( roomjid ); + return; + } + server[0] = 0; server++; + + TCHAR *nick = JGetStringT( hContact, "MyNick" ); + if ( !nick ) { + nick = JabberNickFromJID( m_szJabberJID ); + if ( !nick ) { + mir_free( roomjid ); + return; + } + } + + TCHAR *password = JGetStringCrypt( hContact, "LoginPassword" ); + + GroupchatJoinRoom( server, room, nick, password, autojoin ); + + mir_free( password ); + mir_free( nick ); + mir_free( roomjid ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberIqResultGetRoster - populates LIST_ROSTER and creates contact for any new rosters + +void CJabberProto::OnIqResultGetRoster( HXML iqNode, CJabberIqInfo* pInfo ) +{ + Log( "<iq/> iqIdGetRoster" ); + TCHAR *szGroupDelimeter = (TCHAR *)pInfo->GetUserData(); + if ( pInfo->GetIqType() != JABBER_IQ_TYPE_RESULT ) { + mir_free( szGroupDelimeter ); + return; + } + + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode == NULL ) { + mir_free( szGroupDelimeter ); + return; + } + + if ( lstrcmp( xmlGetAttrValue( queryNode, _T("xmlns")), _T(JABBER_FEAT_IQ_ROSTER))) { + mir_free( szGroupDelimeter ); + return; + } + + if ( !_tcscmp( szGroupDelimeter, _T("\\"))) { + mir_free( szGroupDelimeter ); + szGroupDelimeter = NULL; + } + + TCHAR* nick; + int i; + LIST<void> chatRooms(10); + OBJLIST<JABBER_HTTP_AVATARS> *httpavatars = new OBJLIST<JABBER_HTTP_AVATARS>(20, JABBER_HTTP_AVATARS::compare); + + for ( i=0; ; i++ ) { + BOOL bIsTransport=FALSE; + + HXML itemNode = xmlGetChild( queryNode ,i); + if ( !itemNode ) + break; + + if ( _tcscmp( xmlGetName( itemNode ), _T("item"))) + continue; + + const TCHAR* str = xmlGetAttrValue( itemNode, _T("subscription")), *name; + + JABBER_SUBSCRIPTION sub; + if ( str == NULL ) sub = SUB_NONE; + else if ( !_tcscmp( str, _T("both"))) sub = SUB_BOTH; + else if ( !_tcscmp( str, _T("to"))) sub = SUB_TO; + else if ( !_tcscmp( str, _T("from"))) sub = SUB_FROM; + else sub = SUB_NONE; + + const TCHAR* jid = xmlGetAttrValue( itemNode, _T("jid")); + if ( jid == NULL ) + continue; + if ( _tcschr( jid, '@' ) == NULL ) + bIsTransport = TRUE; + + if (( name = xmlGetAttrValue( itemNode, _T("name"))) != NULL ) + nick = mir_tstrdup( name ); + else + nick = JabberNickFromJID( jid ); + + if ( nick == NULL ) + continue; + + JABBER_LIST_ITEM* item = ListAdd( LIST_ROSTER, jid ); + item->subscription = sub; + + mir_free( item->nick ); item->nick = nick; + + HXML groupNode = xmlGetChild( itemNode , "group" ); + replaceStrT( item->group, ( groupNode ) ? xmlGetText( groupNode ) : NULL ); + + // check group delimiters: + if ( item->group && szGroupDelimeter ) { + TCHAR *szPos = NULL; + while ( szPos = _tcsstr( item->group, szGroupDelimeter )) { + *szPos = 0; + szPos += _tcslen( szGroupDelimeter ); + TCHAR *szNewGroup = (TCHAR *)mir_alloc( sizeof(TCHAR) * ( _tcslen( item->group ) + _tcslen( szPos ) + 2)); + _tcscpy( szNewGroup, item->group ); + _tcscat( szNewGroup, _T("\\")); + _tcscat( szNewGroup, szPos ); + mir_free( item->group ); + item->group = szNewGroup; + } + } + + HANDLE hContact = HContactFromJID( jid ); + if ( hContact == NULL ) { + // Received roster has a new JID. + // Add the jid ( with empty resource ) to Miranda contact list. + hContact = DBCreateContact( jid, nick, FALSE, FALSE ); + } + + if ( name != NULL ) { + DBVARIANT dbNick; + if ( !JGetStringT( hContact, "Nick", &dbNick )) { + if ( lstrcmp( nick, dbNick.ptszVal ) != 0 ) + DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); + else + DBDeleteContactSetting( hContact, "CList", "MyHandle" ); + + JFreeVariant( &dbNick ); + } + else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); + } + else DBDeleteContactSetting( hContact, "CList", "MyHandle" ); + + if ( JGetByte( hContact, "ChatRoom", 0 )) { + GCSESSION gcw = {0}; + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.dwFlags = GC_TCHAR; + gcw.ptszID = jid; + gcw.ptszName = NEWTSTR_ALLOCA( jid ); + + TCHAR* p = (TCHAR*)_tcschr( gcw.ptszName, '@' ); + if ( p ) + *p = 0; + + CallServiceSync( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw ); + + DBDeleteContactSetting( hContact, "CList", "Hidden" ); + chatRooms.insert( hContact ); + } else + { + UpdateSubscriptionInfo(hContact, item); + } + + if (!m_options.IgnoreRosterGroups) { + if ( item->group != NULL ) { + JabberContactListCreateGroup( item->group ); + + // Don't set group again if already correct, or Miranda may show wrong group count in some case + DBVARIANT dbv; + if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) { + if ( lstrcmp( dbv.ptszVal, item->group )) + DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); + JFreeVariant( &dbv ); + } + else DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); + } + else + DBDeleteContactSetting( hContact, "CList", "Group" ); + } + + if ( hContact != NULL ) { + if ( bIsTransport) + JSetByte( hContact, "IsTransport", TRUE ); + else + JSetByte( hContact, "IsTransport", FALSE ); + } + + const TCHAR* imagepath = xmlGetAttrValue(itemNode, _T("vz:img")); + if (imagepath) + httpavatars->insert(new JABBER_HTTP_AVATARS(imagepath, hContact)); + } + + if (httpavatars->getCount()) + JForkThread(&CJabberProto::LoadHttpAvatars, httpavatars); + else + delete httpavatars; + + // Delete orphaned contacts ( if roster sync is enabled ) + if ( m_options.RosterSync == TRUE ) { + int listSize = 0, listAllocSize = 0; + HANDLE* list = NULL; + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* str = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( str != NULL && !strcmp( str, m_szModuleName )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + if ( !ListExist( LIST_ROSTER, dbv.ptszVal )) { + Log( "Syncing roster: preparing to delete " TCHAR_STR_PARAM " ( hContact=0x%x )", dbv.ptszVal, hContact ); + if ( listSize >= listAllocSize ) { + listAllocSize = listSize + 100; + if (( list=( HANDLE * ) mir_realloc( list, listAllocSize * sizeof( HANDLE ))) == NULL ) { + listSize = 0; + break; + } } + + list[listSize++] = hContact; + } + JFreeVariant( &dbv ); + } } + + hContact = db_find_next(hContact); + } + + for ( i=0; i < listSize; i++ ) { + Log( "Syncing roster: deleting 0x%x", list[i] ); + CallService( MS_DB_CONTACT_DELETE, ( WPARAM ) list[i], 0 ); + } + if ( list != NULL ) + mir_free( list ); + } + + EnableMenuItems( TRUE ); + + Log( "Status changed via THREADSTART" ); + m_bModeMsgStatusChangePending = FALSE; + SetServerStatus( m_iDesiredStatus ); + + if ( m_options.AutoJoinConferences ) { + for ( i=0; i < chatRooms.getCount(); i++ ) + GroupchatJoinByHContact(( HANDLE )chatRooms[i], true); + } + chatRooms.destroy(); + + //UI_SAFE_NOTIFY(m_pDlgJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE); + //UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_CHECK_ONLINE); + UI_SAFE_NOTIFY_HWND(m_hwndJabberAddBookmark, WM_JABBER_CHECK_ONLINE); + WindowNotify(WM_JABBER_CHECK_ONLINE); + + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); + + if ( szGroupDelimeter ) + mir_free( szGroupDelimeter ); + + OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_ROSTER); + RebuildInfoFrame(); +} + +void CJabberProto::OnIqResultGetRegister( HXML iqNode ) +{ + // RECVED: result of the request for ( agent ) registration mechanism + // ACTION: activate ( agent ) registration input dialog + Log( "<iq/> iqIdGetRegister" ); + + HXML queryNode; + const TCHAR *type; + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( queryNode = xmlGetChild( iqNode , "query" )) == NULL ) return; + + if ( !lstrcmp( type, _T("result"))) { + if ( m_hwndAgentRegInput ) + SendMessage( m_hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 1 /*success*/, ( LPARAM )xi.copyNode( iqNode )); + } + else if ( !lstrcmp( type, _T("error"))) { + if ( m_hwndAgentRegInput ) { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + SendMessage( m_hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 0 /*error*/, ( LPARAM )str ); + mir_free( str ); +} } } + +void CJabberProto::OnIqResultSetRegister( HXML iqNode ) +{ + // RECVED: result of registration process + // ACTION: notify of successful agent registration + Log( "<iq/> iqIdSetRegister" ); + + const TCHAR *type, *from; + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; + + if ( !lstrcmp( type, _T("result"))) { + HANDLE hContact = HContactFromJID( from ); + if ( hContact != NULL ) + JSetByte( hContact, "IsTransport", TRUE ); + + if ( m_hwndRegProgress ) + SendMessage( m_hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" )); + } + else if ( !lstrcmp( type, _T("error"))) { + if ( m_hwndRegProgress ) { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + SendMessage( m_hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str ); + mir_free( str ); +} } } + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberIqResultGetVcard - processes the server-side v-card + +void CJabberProto::OnIqResultGetVcardPhoto( const TCHAR* jid, HXML n, HANDLE hContact, BOOL& hasPhoto ) +{ + Log( "JabberIqResultGetVcardPhoto: %d", hasPhoto ); + if ( hasPhoto ) + return; + + HXML o = xmlGetChild( n , "BINVAL" ); + if ( o == NULL || xmlGetText( o ) == NULL ) + return; + + int bufferLen; + char* buffer = JabberBase64DecodeT( xmlGetText( o ), &bufferLen ); + if ( buffer == NULL ) + return; + + const TCHAR* szPicType; + HXML m = xmlGetChild( n , "TYPE" ); + if ( m == NULL || xmlGetText( m ) == NULL ) { +LBL_NoTypeSpecified: + switch( JabberGetPictureType( buffer )) { + case PA_FORMAT_GIF: szPicType = _T("image/gif"); break; + case PA_FORMAT_BMP: szPicType = _T("image/bmp"); break; + case PA_FORMAT_PNG: szPicType = _T("image/png"); break; + case PA_FORMAT_JPEG: szPicType = _T("image/jpeg"); break; + default: +LBL_Ret: + mir_free( buffer ); + return; + } + } + else { + const TCHAR* tszType = xmlGetText( m ); + if ( !_tcscmp( tszType, _T("image/jpeg")) || + !_tcscmp( tszType, _T("image/png")) || + !_tcscmp( tszType, _T("image/gif")) || + !_tcscmp( tszType, _T("image/bmp"))) + szPicType = tszType; + else + goto LBL_NoTypeSpecified; + } + + TCHAR szAvatarFileName[MAX_PATH]; + GetAvatarFileName( hContact, szAvatarFileName, SIZEOF( szAvatarFileName )); + + Log( "Picture file name set to " TCHAR_STR_PARAM, szAvatarFileName ); + HANDLE hFile = CreateFile( szAvatarFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile == INVALID_HANDLE_VALUE ) + goto LBL_Ret; + + Log( "Writing %d bytes", bufferLen ); + DWORD nWritten; + if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL )) + goto LBL_Ret; + + CloseHandle( hFile ); + + Log( "%d bytes written", nWritten ); + if ( hContact == NULL ) { + hasPhoto = TRUE; + CallService( MS_AV_SETMYAVATART, ( WPARAM )m_szModuleName, ( LPARAM )szAvatarFileName ); + + Log( "My picture saved to " TCHAR_STR_PARAM, szAvatarFileName ); + } + else { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, jid ); + if ( item == NULL ) { + item = ListAdd( LIST_VCARD_TEMP, jid ); // adding to the temp list to store information about photo + item->bUseResource = TRUE; + } + if ( item != NULL ) { + hasPhoto = TRUE; + if ( item->photoFileName ) + DeleteFile( item->photoFileName ); + replaceStrT( item->photoFileName, szAvatarFileName ); + Log( "Contact's picture saved to " TCHAR_STR_PARAM, szAvatarFileName ); + + if (JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE) { + char szHashValue[ MAX_PATH ]; + if ( JGetStaticString( "AvatarHash", hContact, szHashValue, sizeof( szHashValue ))) + OnIqResultGotAvatar( hContact, o, xmlGetText( m )); + } } + + JFreeVariant( &dbv ); + } } + + if ( !hasPhoto ) + DeleteFile( szAvatarFileName ); + + goto LBL_Ret; +} + +static TCHAR* sttGetText( HXML node, char* tag ) +{ + HXML n = xmlGetChild( node , tag ); + if ( n == NULL ) + return NULL; + + return ( TCHAR* )xmlGetText( n ); +} + +void CJabberProto::OnIqResultGetVcard( HXML iqNode ) +{ + HXML vCardNode, m, n, o; + const TCHAR* type, *jid; + HANDLE hContact; + TCHAR text[128]; + DBVARIANT dbv; + + Log( "<iq/> iqIdGetVcard" ); + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( jid = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; + int id = JabberGetPacketID( iqNode ); + + if ( id == m_nJabberSearchID ) { + m_nJabberSearchID = -1; + + if (( vCardNode = xmlGetChild( iqNode , "vCard" )) != NULL ) { + if ( !lstrcmp( type, _T("result"))) { + JABBER_SEARCH_RESULT jsr = { 0 }; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + jsr.hdr.flags = PSR_TCHAR; + jsr.hdr.nick = sttGetText( vCardNode, "NICKNAME" ); + jsr.hdr.firstName = sttGetText( vCardNode, "FN" ); + jsr.hdr.lastName = _T(""); + jsr.hdr.email = sttGetText( vCardNode, "EMAIL" ); + _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid )); + jsr.jid[ SIZEOF( jsr.jid )-1 ] = '\0'; + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE )id, ( LPARAM )&jsr ); + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); + } + else if ( !lstrcmp( type, _T("error"))) + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); + } + else JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )id, 0 ); + return; + } + + size_t len = _tcslen( m_szJabberJID ); + if ( !_tcsnicmp( jid, m_szJabberJID, len ) && ( jid[len]=='/' || jid[len]=='\0' )) { + hContact = NULL; + Log( "Vcard for myself" ); + } + else { + if (( hContact = HContactFromJID( jid )) == NULL ) + return; + Log( "Other user's vcard" ); + } + + if ( !lstrcmp( type, _T("result"))) { + BOOL hasFn, hasNick, hasGiven, hasFamily, hasMiddle, hasBday, hasGender; + BOOL hasPhone, hasFax, hasCell, hasUrl; + BOOL hasHome, hasHomeStreet, hasHomeStreet2, hasHomeLocality, hasHomeRegion, hasHomePcode, hasHomeCtry; + BOOL hasWork, hasWorkStreet, hasWorkStreet2, hasWorkLocality, hasWorkRegion, hasWorkPcode, hasWorkCtry; + BOOL hasOrgname, hasOrgunit, hasRole, hasTitle; + BOOL hasDesc, hasPhoto; + int nEmail, nPhone, nYear, nMonth, nDay; + + hasFn = hasNick = hasGiven = hasFamily = hasMiddle = hasBday = hasGender = FALSE; + hasPhone = hasFax = hasCell = hasUrl = FALSE; + hasHome = hasHomeStreet = hasHomeStreet2 = hasHomeLocality = hasHomeRegion = hasHomePcode = hasHomeCtry = FALSE; + hasWork = hasWorkStreet = hasWorkStreet2 = hasWorkLocality = hasWorkRegion = hasWorkPcode = hasWorkCtry = FALSE; + hasOrgname = hasOrgunit = hasRole = hasTitle = FALSE; + hasDesc = hasPhoto = FALSE; + nEmail = nPhone = 0; + + if (( vCardNode = xmlGetChild( iqNode , "vCard" )) != NULL ) { + for ( int i=0; ; i++ ) { + n = xmlGetChild( vCardNode ,i); + if ( !n ) + break; + if ( xmlGetName( n ) == NULL ) continue; + if ( !_tcscmp( xmlGetName( n ), _T("FN"))) { + if ( xmlGetText( n ) != NULL ) { + hasFn = TRUE; + JSetStringT( hContact, "FullName", xmlGetText( n )); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("NICKNAME"))) { + if ( xmlGetText( n ) != NULL ) { + hasNick = TRUE; + JSetStringT( hContact, "Nick", xmlGetText( n )); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("N"))) { + // First/Last name + if ( !hasGiven && !hasFamily && !hasMiddle ) { + if (( m=xmlGetChild( n , "GIVEN" )) != NULL && xmlGetText( m )!=NULL ) { + hasGiven = TRUE; + JSetStringT( hContact, "FirstName", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "FAMILY" )) != NULL && xmlGetText( m )!=NULL ) { + hasFamily = TRUE; + JSetStringT( hContact, "LastName", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "MIDDLE" )) != NULL && xmlGetText( m ) != NULL ) { + hasMiddle = TRUE; + JSetStringT( hContact, "MiddleName", xmlGetText( m )); + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("EMAIL"))) { + // E-mail address( es ) + if (( m=xmlGetChild( n , "USERID" )) == NULL ) // Some bad client put e-mail directly in <EMAIL/> instead of <USERID/> + m = n; + if ( xmlGetText( m ) != NULL ) { + char text[100]; + if ( hContact != NULL ) { + if ( nEmail == 0 ) + strcpy( text, "e-mail" ); + else + sprintf( text, "e-mail%d", nEmail-1 ); + } + else sprintf( text, "e-mail%d", nEmail ); + JSetStringT( hContact, text, xmlGetText( m )); + + if ( hContact == NULL ) { + sprintf( text, "e-mailFlag%d", nEmail ); + int nFlag = 0; + if ( xmlGetChild( n , "HOME" ) != NULL ) nFlag |= JABBER_VCEMAIL_HOME; + if ( xmlGetChild( n , "WORK" ) != NULL ) nFlag |= JABBER_VCEMAIL_WORK; + if ( xmlGetChild( n , "INTERNET" ) != NULL ) nFlag |= JABBER_VCEMAIL_INTERNET; + if ( xmlGetChild( n , "X400" ) != NULL ) nFlag |= JABBER_VCEMAIL_X400; + JSetWord( NULL, text, nFlag ); + } + nEmail++; + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("BDAY"))) { + // Birthday + if ( !hasBday && xmlGetText( n )!=NULL ) { + if ( hContact != NULL ) { + if ( _stscanf( xmlGetText( n ), _T("%d-%d-%d"), &nYear, &nMonth, &nDay ) == 3 ) { + hasBday = TRUE; + JSetWord( hContact, "BirthYear", ( WORD )nYear ); + JSetByte( hContact, "BirthMonth", ( BYTE ) nMonth ); + JSetByte( hContact, "BirthDay", ( BYTE ) nDay ); + + SYSTEMTIME sToday = {0}; + GetLocalTime(&sToday); + int nAge = sToday.wYear - nYear; + if (sToday.wMonth < nMonth || (sToday.wMonth == nMonth && sToday.wDay < nDay)) + nAge--; + if (nAge) + JSetWord( hContact, "Age", ( WORD )nAge ); + } + } + else { + hasBday = TRUE; + JSetStringT( NULL, "BirthDate", xmlGetText( n )); + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("GENDER"))) { + // Gender + if ( !hasGender && xmlGetText( n )!=NULL ) { + if ( hContact != NULL ) { + if ( xmlGetText( n )[0] && strchr( "mMfF", xmlGetText( n )[0] )!=NULL ) { + hasGender = TRUE; + JSetByte( hContact, "Gender", ( BYTE ) toupper( xmlGetText( n )[0] )); + } + } + else { + hasGender = TRUE; + JSetStringT( NULL, "GenderString", xmlGetText( n )); + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("ADR"))) { + if ( !hasHome && xmlGetChild( n , "HOME" )!=NULL ) { + // Home address + hasHome = TRUE; + if (( m=xmlGetChild( n , "STREET" )) != NULL && xmlGetText( m ) != NULL ) { + hasHomeStreet = TRUE; + if ( hContact != NULL ) { + if (( o=xmlGetChild( n , "EXTADR" )) != NULL && xmlGetText( o ) != NULL ) + mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); + else if (( o=xmlGetChild( n , "EXTADD" ))!=NULL && xmlGetText( o )!=NULL ) + mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); + else + _tcsncpy( text, xmlGetText( m ), SIZEOF( text )); + text[SIZEOF(text)-1] = '\0'; + JSetStringT( hContact, "Street", text ); + } + else { + JSetStringT( hContact, "Street", xmlGetText( m )); + if (( m=xmlGetChild( n , "EXTADR" )) == NULL ) + m = xmlGetChild( n , "EXTADD" ); + if ( m!=NULL && xmlGetText( m )!=NULL ) { + hasHomeStreet2 = TRUE; + JSetStringT( hContact, "Street2", xmlGetText( m )); + } } } + + if (( m=xmlGetChild( n , "LOCALITY" ))!=NULL && xmlGetText( m )!=NULL ) { + hasHomeLocality = TRUE; + JSetStringT( hContact, "City", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "REGION" ))!=NULL && xmlGetText( m )!=NULL ) { + hasHomeRegion = TRUE; + JSetStringT( hContact, "State", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "PCODE" ))!=NULL && xmlGetText( m )!=NULL ) { + hasHomePcode = TRUE; + JSetStringT( hContact, "ZIP", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "CTRY" ))==NULL || xmlGetText( m )==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/> + m = xmlGetChild( n , "COUNTRY" ); + if ( m!=NULL && xmlGetText( m )!=NULL ) { + hasHomeCtry = TRUE; + JSetStringT( hContact, "Country", xmlGetText( m )); + } } + + if ( !hasWork && xmlGetChild( n , "WORK" )!=NULL ) { + // Work address + hasWork = TRUE; + if (( m=xmlGetChild( n , "STREET" ))!=NULL && xmlGetText( m )!=NULL ) { + hasWorkStreet = TRUE; + if ( hContact != NULL ) { + if (( o=xmlGetChild( n , "EXTADR" ))!=NULL && xmlGetText( o )!=NULL ) + mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); + else if (( o=xmlGetChild( n , "EXTADD" ))!=NULL && xmlGetText( o )!=NULL ) + mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), xmlGetText( m ), xmlGetText( o )); + else + _tcsncpy( text, xmlGetText( m ), SIZEOF( text )); + text[SIZEOF( text )-1] = '\0'; + JSetStringT( hContact, "CompanyStreet", text ); + } + else { + JSetStringT( hContact, "CompanyStreet", xmlGetText( m )); + if (( m=xmlGetChild( n , "EXTADR" )) == NULL ) + m = xmlGetChild( n , "EXTADD" ); + if ( m!=NULL && xmlGetText( m )!=NULL ) { + hasWorkStreet2 = TRUE; + JSetStringT( hContact, "CompanyStreet2", xmlGetText( m )); + } } } + + if (( m=xmlGetChild( n , "LOCALITY" ))!=NULL && xmlGetText( m )!=NULL ) { + hasWorkLocality = TRUE; + JSetStringT( hContact, "CompanyCity", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "REGION" ))!=NULL && xmlGetText( m )!=NULL ) { + hasWorkRegion = TRUE; + JSetStringT( hContact, "CompanyState", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "PCODE" ))!=NULL && xmlGetText( m )!=NULL ) { + hasWorkPcode = TRUE; + JSetStringT( hContact, "CompanyZIP", xmlGetText( m )); + } + if (( m=xmlGetChild( n , "CTRY" ))==NULL || xmlGetText( m )==NULL ) // Some bad client use <COUNTRY/> instead of <CTRY/> + m = xmlGetChild( n , "COUNTRY" ); + if ( m!=NULL && xmlGetText( m )!=NULL ) { + hasWorkCtry = TRUE; + JSetStringT( hContact, "CompanyCountry", xmlGetText( m )); + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("TEL"))) { + // Telephone/Fax/Cellular + if (( m=xmlGetChild( n , "NUMBER" ))!=NULL && xmlGetText( m )!=NULL ) { + if ( hContact != NULL ) { + if ( !hasFax && xmlGetChild( n , "FAX" )!=NULL ) { + hasFax = TRUE; + JSetStringT( hContact, "Fax", xmlGetText( m )); + } + else if ( !hasCell && xmlGetChild( n , "CELL" )!=NULL ) { + hasCell = TRUE; + JSetStringT( hContact, "Cellular", xmlGetText( m )); + } + else if ( !hasPhone && + ( xmlGetChild( n , "HOME" )!=NULL || + xmlGetChild( n , "WORK" )!=NULL || + xmlGetChild( n , "VOICE" )!=NULL || + ( xmlGetChild( n , "FAX" )==NULL && + xmlGetChild( n , "PAGER" )==NULL && + xmlGetChild( n , "MSG" )==NULL && + xmlGetChild( n , "CELL" )==NULL && + xmlGetChild( n , "VIDEO" )==NULL && + xmlGetChild( n , "BBS" )==NULL && + xmlGetChild( n , "MODEM" )==NULL && + xmlGetChild( n , "ISDN" )==NULL && + xmlGetChild( n , "PCS" )==NULL ))) { + hasPhone = TRUE; + JSetStringT( hContact, "Phone", xmlGetText( m )); + } + } + else { + char text[ 100 ]; + sprintf( text, "Phone%d", nPhone ); + JSetStringT( NULL, text, xmlGetText( m )); + + sprintf( text, "PhoneFlag%d", nPhone ); + int nFlag = 0; + if ( xmlGetChild( n ,"HOME" ) != NULL ) nFlag |= JABBER_VCTEL_HOME; + if ( xmlGetChild( n ,"WORK" ) != NULL ) nFlag |= JABBER_VCTEL_WORK; + if ( xmlGetChild( n ,"VOICE" ) != NULL ) nFlag |= JABBER_VCTEL_VOICE; + if ( xmlGetChild( n ,"FAX" ) != NULL ) nFlag |= JABBER_VCTEL_FAX; + if ( xmlGetChild( n ,"PAGER" ) != NULL ) nFlag |= JABBER_VCTEL_PAGER; + if ( xmlGetChild( n ,"MSG" ) != NULL ) nFlag |= JABBER_VCTEL_MSG; + if ( xmlGetChild( n ,"CELL" ) != NULL ) nFlag |= JABBER_VCTEL_CELL; + if ( xmlGetChild( n ,"VIDEO" ) != NULL ) nFlag |= JABBER_VCTEL_VIDEO; + if ( xmlGetChild( n ,"BBS" ) != NULL ) nFlag |= JABBER_VCTEL_BBS; + if ( xmlGetChild( n ,"MODEM" ) != NULL ) nFlag |= JABBER_VCTEL_MODEM; + if ( xmlGetChild( n ,"ISDN" ) != NULL ) nFlag |= JABBER_VCTEL_ISDN; + if ( xmlGetChild( n ,"PCS" ) != NULL ) nFlag |= JABBER_VCTEL_PCS; + JSetWord( NULL, text, nFlag ); + nPhone++; + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("URL"))) { + // Homepage + if ( !hasUrl && xmlGetText( n )!=NULL ) { + hasUrl = TRUE; + JSetStringT( hContact, "Homepage", xmlGetText( n )); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("ORG"))) { + if ( !hasOrgname && !hasOrgunit ) { + if (( m=xmlGetChild( n ,"ORGNAME" ))!=NULL && xmlGetText( m )!=NULL ) { + hasOrgname = TRUE; + JSetStringT( hContact, "Company", xmlGetText( m )); + } + if (( m=xmlGetChild( n ,"ORGUNIT" ))!=NULL && xmlGetText( m )!=NULL ) { // The real vCard can have multiple <ORGUNIT/> but we will only display the first one + hasOrgunit = TRUE; + JSetStringT( hContact, "CompanyDepartment", xmlGetText( m )); + } } + } + else if ( !lstrcmp( xmlGetName( n ), _T("ROLE"))) { + if ( !hasRole && xmlGetText( n )!=NULL ) { + hasRole = TRUE; + JSetStringT( hContact, "Role", xmlGetText( n )); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("TITLE"))) { + if ( !hasTitle && xmlGetText( n )!=NULL ) { + hasTitle = TRUE; + JSetStringT( hContact, "CompanyPosition", xmlGetText( n )); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("DESC"))) { + if ( !hasDesc && xmlGetText( n )!=NULL ) { + hasDesc = TRUE; + TCHAR* szMemo = JabberUnixToDosT( xmlGetText( n )); + JSetStringT( hContact, "About", szMemo ); + mir_free( szMemo ); + } + } + else if ( !lstrcmp( xmlGetName( n ), _T("PHOTO"))) + OnIqResultGetVcardPhoto( jid, n, hContact, hasPhoto ); + } } + + if ( hasFn && !hasNick ) { + TCHAR *name = JGetStringT( hContact, "FullName" ); + TCHAR *nick = JGetStringT( hContact, "Nick" ); + TCHAR *jidNick = JabberNickFromJID(jid); + if ( !nick || ( jidNick && !_tcsicmp( nick, jidNick ))) + JSetStringT( hContact, "Nick", name ); + + mir_free( jidNick ); + mir_free( nick ); + mir_free( name ); + } + if ( !hasFn ) + JDeleteSetting( hContact, "FullName" ); + // We are not deleting "Nick" +// if ( !hasNick ) +// JDeleteSetting( hContact, "Nick" ); + if ( !hasGiven ) + JDeleteSetting( hContact, "FirstName" ); + if ( !hasFamily ) + JDeleteSetting( hContact, "LastName" ); + if ( !hasMiddle ) + JDeleteSetting( hContact, "MiddleName" ); + if ( hContact != NULL ) { + while ( true ) { + if ( nEmail <= 0 ) + JDeleteSetting( hContact, "e-mail" ); + else { + char text[ 100 ]; + sprintf( text, "e-mail%d", nEmail-1 ); + if ( DBGetContactSettingString( hContact, m_szModuleName, text, &dbv )) break; + JFreeVariant( &dbv ); + JDeleteSetting( hContact, text ); + } + nEmail++; + } + } + else { + while ( true ) { + char text[ 100 ]; + sprintf( text, "e-mail%d", nEmail ); + if ( DBGetContactSettingString( NULL, m_szModuleName, text, &dbv )) break; + JFreeVariant( &dbv ); + JDeleteSetting( NULL, text ); + sprintf( text, "e-mailFlag%d", nEmail ); + JDeleteSetting( NULL, text ); + nEmail++; + } } + + if ( !hasBday ) { + JDeleteSetting( hContact, "BirthYear" ); + JDeleteSetting( hContact, "BirthMonth" ); + JDeleteSetting( hContact, "BirthDay" ); + JDeleteSetting( hContact, "BirthDate" ); + JDeleteSetting( hContact, "Age" ); + } + if ( !hasGender ) { + if ( hContact != NULL ) + JDeleteSetting( hContact, "Gender" ); + else + JDeleteSetting( NULL, "GenderString" ); + } + if ( hContact != NULL ) { + if ( !hasPhone ) + JDeleteSetting( hContact, "Phone" ); + if ( !hasFax ) + JDeleteSetting( hContact, "Fax" ); + if ( !hasCell ) + JDeleteSetting( hContact, "Cellular" ); + } + else { + while ( true ) { + char text[ 100 ]; + sprintf( text, "Phone%d", nPhone ); + if ( DBGetContactSettingString( NULL, m_szModuleName, text, &dbv )) break; + JFreeVariant( &dbv ); + JDeleteSetting( NULL, text ); + sprintf( text, "PhoneFlag%d", nPhone ); + JDeleteSetting( NULL, text ); + nPhone++; + } } + + if ( !hasHomeStreet ) + JDeleteSetting( hContact, "Street" ); + if ( !hasHomeStreet2 && hContact==NULL ) + JDeleteSetting( hContact, "Street2" ); + if ( !hasHomeLocality ) + JDeleteSetting( hContact, "City" ); + if ( !hasHomeRegion ) + JDeleteSetting( hContact, "State" ); + if ( !hasHomePcode ) + JDeleteSetting( hContact, "ZIP" ); + if ( !hasHomeCtry ) + JDeleteSetting( hContact, "Country" ); + if ( !hasWorkStreet ) + JDeleteSetting( hContact, "CompanyStreet" ); + if ( !hasWorkStreet2 && hContact==NULL ) + JDeleteSetting( hContact, "CompanyStreet2" ); + if ( !hasWorkLocality ) + JDeleteSetting( hContact, "CompanyCity" ); + if ( !hasWorkRegion ) + JDeleteSetting( hContact, "CompanyState" ); + if ( !hasWorkPcode ) + JDeleteSetting( hContact, "CompanyZIP" ); + if ( !hasWorkCtry ) + JDeleteSetting( hContact, "CompanyCountry" ); + if ( !hasUrl ) + JDeleteSetting( hContact, "Homepage" ); + if ( !hasOrgname ) + JDeleteSetting( hContact, "Company" ); + if ( !hasOrgunit ) + JDeleteSetting( hContact, "CompanyDepartment" ); + if ( !hasRole ) + JDeleteSetting( hContact, "Role" ); + if ( !hasTitle ) + JDeleteSetting( hContact, "CompanyPosition" ); + if ( !hasDesc ) + JDeleteSetting( hContact, "About" ); + + if ( id == m_ThreadInfo->resolveID ) { + const TCHAR* p = _tcschr( jid, '@' ); + ResolveTransportNicks(( p != NULL ) ? p+1 : jid ); + } + else { + if (( hContact = HContactFromJID( jid )) != NULL ) + JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 ); + WindowNotify(WM_JABBER_REFRESH_VCARD); + } + } + else if ( !lstrcmp( type, _T("error"))) { + if (( hContact = HContactFromJID( jid )) != NULL ) + JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, ( HANDLE ) 1, 0 ); + } +} + +void CJabberProto::OnIqResultSetVcard( HXML iqNode ) +{ + Log( "<iq/> iqIdSetVcard" ); + if ( !xmlGetAttrValue( iqNode, _T("type"))) + return; + + WindowNotify(WM_JABBER_REFRESH_VCARD); +} + +void CJabberProto::OnIqResultSetSearch( HXML iqNode ) +{ + HXML queryNode, n; + const TCHAR* type, *jid; + int i, id; + JABBER_SEARCH_RESULT jsr; + + Log( "<iq/> iqIdGetSearch" ); + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( id = JabberGetPacketID( iqNode )) == -1 ) return; + + if ( !lstrcmp( type, _T("result"))) { + if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + for ( i=0; ; i++ ) { + HXML itemNode = xmlGetChild( queryNode ,i); + if ( !itemNode ) + break; + + if ( !lstrcmp( xmlGetName( itemNode ), _T("item"))) { + if (( jid=xmlGetAttrValue( itemNode, _T("jid"))) != NULL ) { + _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid )); + jsr.jid[ SIZEOF( jsr.jid )-1] = '\0'; + jsr.hdr.id = (TCHAR*)jid; + Log( "Result jid = " TCHAR_STR_PARAM, jid ); + if (( n=xmlGetChild( itemNode , "nick" ))!=NULL && xmlGetText( n )!=NULL ) + jsr.hdr.nick = ( TCHAR* )xmlGetText( n ); + else + jsr.hdr.nick = _T( "" ); + if (( n=xmlGetChild( itemNode , "first" ))!=NULL && xmlGetText( n )!=NULL ) + jsr.hdr.firstName = ( TCHAR* )xmlGetText( n ); + else + jsr.hdr.firstName = _T( "" ); + if (( n=xmlGetChild( itemNode , "last" ))!=NULL && xmlGetText( n )!=NULL ) + jsr.hdr.lastName = ( TCHAR* )xmlGetText( n ); + else + jsr.hdr.lastName = _T( "" ); + if (( n=xmlGetChild( itemNode , "email" ))!=NULL && xmlGetText( n )!=NULL ) + jsr.hdr.email = ( TCHAR* )xmlGetText( n ); + else + jsr.hdr.email = _T( "" ); + jsr.hdr.flags = PSR_TCHAR; + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); + } } } + + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); + } + else if ( !lstrcmp( type, _T("error"))) + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); +} + +void CJabberProto::OnIqResultExtSearch( HXML iqNode ) +{ + HXML queryNode; + const TCHAR* type; + int id; + + Log( "<iq/> iqIdGetExtSearch" ); + if (( type=xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( id = JabberGetPacketID( iqNode )) == -1 ) return; + + if ( !lstrcmp( type, _T("result"))) { + if (( queryNode=xmlGetChild( iqNode , "query" )) == NULL ) return; + if (( queryNode=xmlGetChild( queryNode , "x" )) == NULL ) return; + for ( int i=0; ; i++ ) { + HXML itemNode = xmlGetChild( queryNode ,i); + if ( !itemNode ) + break; + if ( lstrcmp( xmlGetName( itemNode ), _T("item"))) + continue; + + JABBER_SEARCH_RESULT jsr = { 0 }; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + jsr.hdr.flags = PSR_TCHAR; +// jsr.hdr.firstName = ""; + + for ( int j=0; ; j++ ) { + HXML fieldNode = xmlGetChild( itemNode ,j); + if ( !fieldNode ) + break; + + if ( lstrcmp( xmlGetName( fieldNode ), _T("field"))) + continue; + + const TCHAR* fieldName = xmlGetAttrValue( fieldNode, _T("var")); + if ( fieldName == NULL ) + continue; + + HXML n = xmlGetChild( fieldNode , "value" ); + if ( n == NULL ) + continue; + + if ( !lstrcmp( fieldName, _T("jid"))) { + _tcsncpy( jsr.jid, xmlGetText( n ), SIZEOF( jsr.jid )); + jsr.jid[SIZEOF( jsr.jid )-1] = '\0'; + Log( "Result jid = " TCHAR_STR_PARAM, jsr.jid ); + } + else if ( !lstrcmp( fieldName, _T("nickname"))) + jsr.hdr.nick = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); + else if ( !lstrcmp( fieldName, _T("fn"))) + jsr.hdr.firstName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); + else if ( !lstrcmp( fieldName, _T("given"))) + jsr.hdr.firstName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); + else if ( !lstrcmp( fieldName, _T("family"))) + jsr.hdr.lastName = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); + else if ( !lstrcmp( fieldName, _T("email"))) + jsr.hdr.email = ( xmlGetText( n ) != NULL ) ? ( TCHAR* )xmlGetText( n ) : _T( "" ); + } + + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); + } + + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); + } + else if ( !lstrcmp( type, _T("error"))) + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); +} + +void CJabberProto::OnIqResultSetPassword( HXML iqNode ) +{ + Log( "<iq/> iqIdSetPassword" ); + + const TCHAR* type = xmlGetAttrValue( iqNode, _T("type")); + if ( type == NULL ) + return; + + if ( !lstrcmp( type, _T("result"))) { + _tcsncpy( m_ThreadInfo->password, m_ThreadInfo->newPassword, SIZEOF( m_ThreadInfo->password )); + MessageBox( NULL, TranslateT( "Password is successfully changed. Don't forget to update your password in the Jabber protocol option." ), TranslateT( "Change Password" ), MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND ); + } + else if ( !lstrcmp( type, _T("error"))) + MessageBox( NULL, TranslateT( "Password cannot be changed." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); +} +/* +void CJabberProto::OnIqResultDiscoAgentItems( HXML iqNode, void *userdata ) +{ + if ( !m_options.EnableAvatars ) + return; +} +*/ +void CJabberProto::OnIqResultGetVCardAvatar( HXML iqNode ) +{ + const TCHAR* type; + + Log( "<iq/> OnIqResultGetVCardAvatar" ); + + const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); + if ( from == NULL ) + return; + HANDLE hContact = HContactFromJID( from ); + if ( hContact == NULL ) + return; + + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if ( _tcscmp( type, _T("result"))) return; + + HXML vCard = xmlGetChild( iqNode , "vCard" ); + if (vCard == NULL) return; + vCard = xmlGetChild( vCard , "PHOTO" ); + if (vCard == NULL) return; + + if ( xmlGetChildCount( vCard ) == 0 ) { + JDeleteSetting( hContact, "AvatarHash" ); + DBVARIANT dbv = {0}; + if ( !JGetStringT( hContact, "AvatarSaved", &dbv )) { + JFreeVariant( &dbv ); + JDeleteSetting( hContact, "AvatarSaved" ); + JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, NULL, NULL ); + } + + return; + } + + HXML typeNode = xmlGetChild( vCard , "TYPE" ); + const TCHAR* mimeType = NULL; + if (typeNode != NULL) mimeType = xmlGetText( typeNode ); + HXML n = xmlGetChild( vCard , "BINVAL" ); + if ( n == NULL ) + return; + + JSetByte( hContact, "AvatarXVcard", 1 ); + OnIqResultGotAvatar( hContact, n, mimeType); +} + +void CJabberProto::OnIqResultGetClientAvatar( HXML iqNode ) +{ + const TCHAR* type; + + Log( "<iq/> iqIdResultGetClientAvatar" ); + + const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); + if ( from == NULL ) + return; + HANDLE hContact = HContactFromJID( from ); + if ( hContact == NULL ) + return; + + HXML n = NULL; + if (( type = xmlGetAttrValue( iqNode, _T("type"))) != NULL && !_tcscmp( type, _T("result"))) { + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode != NULL ) { + const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); + if ( !lstrcmp( xmlns, _T(JABBER_FEAT_AVATAR))) { + n = xmlGetChild( queryNode , "data" ); + } + } + } + + if ( n == NULL ) { + TCHAR szJid[ JABBER_MAX_JID_LEN ]; + lstrcpyn(szJid, from, SIZEOF(szJid)); + TCHAR *res = _tcschr(szJid, _T('/')); + if ( res != NULL ) + *res = 0; + + // Try server stored avatar + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetServerAvatar ); + + XmlNodeIq iq( _T("get"), iqId, szJid ); + iq << XQUERY( _T(JABBER_FEAT_SERVER_AVATAR)); + m_ThreadInfo->send( iq ); + + return; + } + + const TCHAR* mimeType = mimeType = xmlGetAttrValue( n, _T("mimetype")); + + OnIqResultGotAvatar( hContact, n, mimeType); +} + + +void CJabberProto::OnIqResultGetServerAvatar( HXML iqNode ) +{ + const TCHAR* type; + + Log( "<iq/> iqIdResultGetServerAvatar" ); + + const TCHAR* from = xmlGetAttrValue( iqNode, _T("from")); + if ( from == NULL ) + return; + HANDLE hContact = HContactFromJID( from ); + if ( hContact == NULL ) + return; + + HXML n = NULL; + if (( type = xmlGetAttrValue( iqNode, _T("type"))) != NULL && !_tcscmp( type, _T("result"))) { + HXML queryNode = xmlGetChild( iqNode , "query" ); + if ( queryNode != NULL ) { + const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); + if ( !lstrcmp( xmlns, _T(JABBER_FEAT_SERVER_AVATAR))) { + n = xmlGetChild( queryNode , "data" ); + } + } + } + + if ( n == NULL ) { + TCHAR szJid[ JABBER_MAX_JID_LEN ]; + lstrcpyn(szJid, from, SIZEOF(szJid)); + TCHAR *res = _tcschr(szJid, _T('/')); + if ( res != NULL ) + *res = 0; + + // Try VCard photo + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetVCardAvatar ); + + XmlNodeIq iq( _T("get"), iqId, szJid ); + iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); + m_ThreadInfo->send( iq ); + + return; + } + + const TCHAR* mimeType = xmlGetAttrValue( n, _T("mimetype")); + + OnIqResultGotAvatar( hContact, n, mimeType); +} + + +void CJabberProto::OnIqResultGotAvatar( HANDLE hContact, HXML n, const TCHAR* mimeType ) +{ + int resultLen = 0; + char* body = JabberBase64DecodeT( xmlGetText( n ), &resultLen ); + + int pictureType; + if ( mimeType != NULL ) { + if ( !lstrcmp( mimeType, _T("image/jpeg"))) pictureType = PA_FORMAT_JPEG; + else if ( !lstrcmp( mimeType, _T("image/png"))) pictureType = PA_FORMAT_PNG; + else if ( !lstrcmp( mimeType, _T("image/gif"))) pictureType = PA_FORMAT_GIF; + else if ( !lstrcmp( mimeType, _T("image/bmp"))) pictureType = PA_FORMAT_BMP; + else { +LBL_ErrFormat: + Log( "Invalid mime type specified for picture: " TCHAR_STR_PARAM, mimeType ); + mir_free( body ); + return; + } } + else if (( pictureType = JabberGetPictureType( body )) == PA_FORMAT_UNKNOWN ) + goto LBL_ErrFormat; + + TCHAR tszFileName[ MAX_PATH ]; + + PROTO_AVATAR_INFORMATIONT AI; + AI.cbSize = sizeof AI; + AI.format = pictureType; + AI.hContact = hContact; + + if ( JGetByte( hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) { + GetAvatarFileName( hContact, tszFileName, SIZEOF(tszFileName)); + DeleteFile( tszFileName ); + } + + JSetByte( hContact, "AvatarType", pictureType ); + + char buffer[ 41 ]; + mir_sha1_byte_t digest[20]; + mir_sha1_ctx sha; + mir_sha1_init( &sha ); + mir_sha1_append( &sha, ( mir_sha1_byte_t* )body, resultLen ); + mir_sha1_finish( &sha, digest ); + for ( int i=0; i<20; i++ ) + sprintf( buffer+( i<<1 ), "%02x", digest[i] ); + + GetAvatarFileName( hContact, tszFileName, SIZEOF(tszFileName)); + _tcsncpy( AI.filename, tszFileName, SIZEOF(AI.filename)); + + FILE* out = _tfopen( tszFileName, _T("wb")); + if ( out != NULL ) { + fwrite( body, resultLen, 1, out ); + fclose( out ); + JSetString( hContact, "AvatarSaved", buffer ); + JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL ); + Log("Broadcast new avatar: %s",AI.filename); + } + else JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL ); + + mir_free( body ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Bookmarks + +void CJabberProto::OnIqResultDiscoBookmarks( HXML iqNode ) +{ + HXML storageNode;//, nickNode, passNode; + const TCHAR* type, *jid, *name; + + // RECVED: list of bookmarks + // ACTION: refresh bookmarks dialog + Log( "<iq/> iqIdGetBookmarks" ); + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + + if ( !lstrcmp( type, _T("result"))) { + if ( m_ThreadInfo && !( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE )) { + m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PRIVATE_STORAGE; + EnableMenuItems( TRUE ); + } + + if ( storageNode = XPathT( iqNode, "query/storage[@xmlns='storage:bookmarks']" )) { + ListRemoveList( LIST_BOOKMARK ); + + HXML itemNode; + for ( int i = 0; itemNode = xmlGetChild( storageNode, i ); i++ ) { + if ( name = xmlGetName( itemNode)) { + if ( !_tcscmp( name, _T("conference")) && (jid = xmlGetAttrValue( itemNode, _T("jid")))) { + JABBER_LIST_ITEM* item = ListAdd( LIST_BOOKMARK, jid ); + item->name = mir_tstrdup( xmlGetAttrValue( itemNode, _T("name"))); + item->type = mir_tstrdup( _T( "conference" )); + item->bUseResource = TRUE; + item->nick = mir_tstrdup( XPathT( itemNode, "nick" )); + item->password = mir_tstrdup( XPathT( itemNode, "password" )); + + const TCHAR* autoJ = xmlGetAttrValue( itemNode, _T("autojoin")); + if ( autoJ != NULL ) + item->bAutoJoin = ( !lstrcmp( autoJ, _T("true")) || !lstrcmp( autoJ, _T("1"))) ? true : false; + } + else if ( !_tcscmp( name, _T("url")) && (jid = xmlGetAttrValue( itemNode, _T("url") ))) { + JABBER_LIST_ITEM* item = ListAdd( LIST_BOOKMARK, jid ); + item->bUseResource = TRUE; + item->name = mir_tstrdup( xmlGetAttrValue( itemNode, _T("name"))); + item->type = mir_tstrdup( _T("url")); + } + } + } + + UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_REFRESH); + m_ThreadInfo->bBookmarksLoaded = TRUE; + OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_BOOKMARKS); + } + } + else if ( !lstrcmp( type, _T("error"))) { + if ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE ) { + m_ThreadInfo->jabberServerCaps &= ~JABBER_CAPS_PRIVATE_STORAGE; + EnableMenuItems( TRUE ); + UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_ACTIVATE); + return; + } +} } + +void CJabberProto::SetBookmarkRequest (XmlNodeIq& iq) +{ + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); + HXML storage = query << XCHILDNS( _T("storage"), _T("storage:bookmarks")); + + LISTFOREACH(i, this, LIST_BOOKMARK) + { + JABBER_LIST_ITEM* item = ListGetItemPtrFromIndex( i ); + if ( item == NULL ) + continue; + + if ( item->jid == NULL ) + continue; + if ( !lstrcmp( item->type, _T("conference"))) { + HXML itemNode = storage << XCHILD( _T("conference")) << XATTR( _T("jid"), item->jid ); + if ( item->name ) + itemNode << XATTR( _T("name"), item->name ); + if ( item->bAutoJoin ) + itemNode << XATTRI( _T("autojoin"), 1 ); + if ( item->nick ) + itemNode << XCHILD( _T("nick"), item->nick ); + if ( item->password ) + itemNode << XCHILD( _T("password"), item->password ); + } + if ( !lstrcmp( item->type, _T("url"))) { + HXML itemNode = storage << XCHILD( _T("url")) << XATTR( _T("url"), item->jid ); + if ( item->name ) + itemNode << XATTR( _T("name"), item->name ); + } + } +} + +void CJabberProto::OnIqResultSetBookmarks( HXML iqNode ) +{ + // RECVED: server's response + // ACTION: refresh bookmarks list dialog + + Log( "<iq/> iqIdSetBookmarks" ); + + const TCHAR* type = xmlGetAttrValue( iqNode, _T("type")); + if ( type == NULL ) + return; + + if ( !lstrcmp( type, _T("result"))) { + UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_REFRESH); + } + else if ( !lstrcmp( type, _T("error"))) { + HXML errorNode = xmlGetChild( iqNode , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + MessageBox( NULL, str, TranslateT( "Jabber Bookmarks Error" ), MB_OK|MB_SETFOREGROUND ); + mir_free( str ); + UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_ACTIVATE); +} } + +// last activity (XEP-0012) support +void CJabberProto::OnIqResultLastActivity( HXML iqNode, CJabberIqInfo* pInfo ) +{ + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->m_szFrom ); + if ( !r ) + return; + + time_t lastActivity = -1; + if ( pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT ) { + LPCTSTR szSeconds = XPathT( iqNode, "query[@xmlns='jabber:iq:last']/@seconds" ); + if ( szSeconds ) { + int nSeconds = _ttoi( szSeconds ); + if ( nSeconds > 0 ) + lastActivity = time( 0 ) - nSeconds; + } + + LPCTSTR szLastStatusMessage = XPathT( iqNode, "query[@xmlns='jabber:iq:last']" ); + if ( szLastStatusMessage ) // replace only if it exists + replaceStrT( r->statusMessage, szLastStatusMessage ); + } + + r->idleStartTime = lastActivity; + + JabberUserInfoUpdate(pInfo->GetHContact()); +} + +// entity time (XEP-0202) support +void CJabberProto::OnIqResultEntityTime( HXML pIqNode, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->m_hContact ) + return; + + if ( pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT ) { + LPCTSTR szTzo = XPathFmt( pIqNode, _T("time[@xmlns='%s']/tzo"), _T( JABBER_FEAT_ENTITY_TIME )); + if ( szTzo && szTzo[0] ) { + LPCTSTR szMin = _tcschr( szTzo, ':' ); + int nTz = _ttoi( szTzo ) * -2; + nTz += ( nTz < 0 ? -1 : 1 ) * ( szMin ? _ttoi( szMin + 1 ) / 30 : 0 ); + + TIME_ZONE_INFORMATION tzinfo; + if ( GetTimeZoneInformation( &tzinfo ) == TIME_ZONE_ID_DAYLIGHT ) + nTz -= tzinfo.DaylightBias / 30; + + JSetByte( pInfo->m_hContact, "Timezone", (signed char)nTz ); + + LPCTSTR szTz = XPathFmt( pIqNode, _T("time[@xmlns='%s']/tz"), _T( JABBER_FEAT_ENTITY_TIME )); + if (szTz) + JSetStringT( pInfo->m_hContact, "TzName", szTz ); + else + JDeleteSetting( pInfo->m_hContact, "TzName" ); + return; + } + } + else if ( pInfo->m_nIqType == JABBER_IQ_TYPE_ERROR ) + { + if ( JGetWord( pInfo->m_hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE ) + return; + } + + JDeleteSetting( pInfo->m_hContact, "Timezone" ); + JDeleteSetting( pInfo->m_hContact, "TzName" ); +} diff --git a/protocols/JabberG/src/jabber_iqid_muc.cpp b/protocols/JabberG/src/jabber_iqid_muc.cpp new file mode 100644 index 0000000000..3621506d29 --- /dev/null +++ b/protocols/JabberG/src/jabber_iqid_muc.cpp @@ -0,0 +1,560 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" + +void CJabberProto::SetMucConfig( HXML node, void *from ) +{ + if ( m_ThreadInfo && from ) { + XmlNodeIq iq( _T("set"), SerialNext(), ( TCHAR* )from ); + HXML query = iq << XQUERY( xmlnsOwner ); + xmlAddChild( query, node ); + m_ThreadInfo->send( iq ); +} } + +void LaunchForm(HXML node); + +void CJabberProto::OnIqResultGetMuc( HXML iqNode ) +{ + HXML queryNode, xNode; + const TCHAR *type, *from, *str; + + // RECVED: room config form + // ACTION: show the form + Log( "<iq/> iqIdGetMuc" ); + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; + + if ( !_tcscmp( type, _T("result"))) { + if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { + str = xmlGetAttrValue( queryNode, _T("xmlns")); + if ( !lstrcmp( str, _T("http://jabber.org/protocol/muc#owner" ))) { + if (( xNode = xmlGetChild( queryNode , "x" )) != NULL ) { + str = xmlGetAttrValue( xNode, _T("xmlns")); + if ( !lstrcmp( str, _T(JABBER_FEAT_DATA_FORMS))) + //LaunchForm(xNode); + FormCreateDialog( xNode, _T("Jabber Conference Room Configuration"), &CJabberProto::SetMucConfig, mir_tstrdup( from )); +} } } } } + +static void sttFillJidList(HWND hwndDlg) +{ + JABBER_MUC_JIDLIST_INFO *jidListInfo; + HXML iqNode, queryNode; + const TCHAR* from, *jid, *reason, *nick; + LVITEM lvi; + HWND hwndList; + int count, i; + + TCHAR *filter = NULL; + if (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA)) + { + int filterLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_FILTER)) + 1; + filter = (TCHAR *)_alloca(filterLength * sizeof(TCHAR)); + GetDlgItemText(hwndDlg, IDC_FILTER, filter, filterLength); + } + + jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + if ( !jidListInfo ) + return; + + hwndList = GetDlgItem( hwndDlg, IDC_LIST ); + SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); + + count = ListView_GetItemCount( hwndList ); + lvi.mask = LVIF_PARAM; + lvi.iSubItem = 0; + for ( i=0; i<count; i++ ) { + lvi.iItem = i; + if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) { + if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) { + mir_free(( void * ) lvi.lParam ); + } + } + } + ListView_DeleteAllItems( hwndList ); + + // Populate displayed list from iqNode + if (( iqNode = jidListInfo->iqNode ) != NULL ) { + if (( from = xmlGetAttrValue( iqNode, _T("from"))) != NULL ) { + if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.iSubItem = 0; + lvi.iItem = 0; + for ( i=0; ; i++ ) { + HXML itemNode = xmlGetChild( queryNode ,i); + if ( !itemNode ) + break; + + if (( jid = xmlGetAttrValue( itemNode, _T("jid"))) != NULL ) { + lvi.pszText = ( TCHAR* )jid; + if ( jidListInfo->type == MUC_BANLIST ) { + if (( reason = xmlGetText(xmlGetChild( itemNode , "reason" ))) != NULL ) { + TCHAR jidreason[ JABBER_MAX_JID_LEN + 256 ]; + mir_sntprintf( jidreason, SIZEOF( jidreason ), _T("%s (%s)") , jid, reason ); + lvi.pszText = jidreason; + } } + + if ( jidListInfo->type == MUC_VOICELIST || jidListInfo->type == MUC_MODERATORLIST ) { + if (( nick = xmlGetAttrValue( itemNode, _T("nick"))) != NULL ) { + TCHAR nickjid[ JABBER_MAX_JID_LEN + 256 ]; + mir_sntprintf( nickjid, SIZEOF( nickjid ), _T("%s (%s)") , nick, jid ); + lvi.pszText = nickjid; + } } + + if (filter && *filter && !JabberStrIStr(lvi.pszText, filter)) + continue; + + lvi.lParam = ( LPARAM )mir_tstrdup( jid ); + + ListView_InsertItem( hwndList, &lvi ); + lvi.iItem++; + } } } } } + + lvi.mask = LVIF_PARAM; + lvi.lParam = ( LPARAM )( -1 ); + ListView_InsertItem( hwndList, &lvi ); + + SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE); +} + +static int sttJidListResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_LIST: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + case IDC_FILTER: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM|RD_ANCHORX_WIDTH; + case IDC_BTN_FILTERRESET: + case IDC_BTN_FILTERAPPLY: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +static INT_PTR CALLBACK JabberMucJidListDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JABBER_MUC_JIDLIST_INFO* dat = (JABBER_MUC_JIDLIST_INFO*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch( msg ) { + case WM_INITDIALOG: + { + LVCOLUMN lvc; + RECT rc; + HWND hwndList; + + TranslateDialogDefault( hwndDlg ); + + hwndList = GetDlgItem( hwndDlg, IDC_LIST ); + ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); + GetClientRect( hwndList, &rc ); + //rc.right -= GetSystemMetrics( SM_CXVSCROLL ); + lvc.mask = LVCF_WIDTH; + lvc.cx = rc.right - 20; + ListView_InsertColumn( hwndList, 0, &lvc ); + lvc.cx = 20; + ListView_InsertColumn( hwndList, 1, &lvc ); + SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, lParam ); + dat = (JABBER_MUC_JIDLIST_INFO*)lParam; + + static struct + { + int idc; + char *title; + char *icon; + bool push; + } buttons[] = + { + {IDC_BTN_FILTERAPPLY, "Apply filter", "sd_filter_apply", false}, + {IDC_BTN_FILTERRESET, "Reset filter", "sd_filter_reset", false}, + }; + for (int i = 0; i < SIZEOF(buttons); ++i) + { + SendDlgItemMessage(hwndDlg, buttons[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->ppro->LoadIconEx(buttons[i].icon)); + SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONADDTOOLTIP, (WPARAM)buttons[i].title, 0); + if (buttons[i].push) + SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASPUSHBTN, TRUE, 0); + } + + Utils_RestoreWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); + } + return TRUE; + case WM_SIZE: + { + UTILRESIZEDIALOG urd = {0}; + urd.cbSize = sizeof(urd); + urd.hInstance = hInst; + urd.hwndDlg = hwndDlg; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_JIDLIST); + urd.pfnResizer = sttJidListResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + + RECT listrc; + LVCOLUMN lvc; + HWND hwndList = GetDlgItem( hwndDlg, IDC_LIST ); + GetClientRect( hwndList, &listrc ); + lvc.mask = LVCF_WIDTH; + //listrc.right -= GetSystemMetrics( SM_CXVSCROLL ); + lvc.cx = listrc.right - 20; + SendMessage(hwndList, LVM_SETCOLUMN, 0, (LPARAM)&lvc); + break; + } + break; + + case WM_JABBER_REFRESH: + { + // lParam is ( JABBER_MUC_JIDLIST_INFO * ) + HXML iqNode, queryNode; + const TCHAR* from; + TCHAR title[256]; + + // Clear current GWL_USERDATA, if any + if ( dat != NULL ) + delete dat; + + // Set new GWL_USERDATA + dat = ( JABBER_MUC_JIDLIST_INFO * ) lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) dat ); + + // Populate displayed list from iqNode + lstrcpyn( title, TranslateT( "JID List" ), SIZEOF( title )); + if (( dat=( JABBER_MUC_JIDLIST_INFO * ) lParam ) != NULL ) { + if (( iqNode = dat->iqNode ) != NULL ) { + if (( from = xmlGetAttrValue( iqNode, _T("from"))) != NULL ) { + dat->roomJid = mir_tstrdup( from ); + + if (( queryNode = xmlGetChild( iqNode , "query" )) != NULL ) { + TCHAR* localFrom = mir_tstrdup( from ); + mir_sntprintf( title, SIZEOF( title ), TranslateT("%s, %d items (%s)"), + ( dat->type == MUC_VOICELIST ) ? TranslateT( "Voice List" ) : + ( dat->type == MUC_MEMBERLIST ) ? TranslateT( "Member List" ) : + ( dat->type == MUC_MODERATORLIST ) ? TranslateT( "Moderator List" ) : + ( dat->type == MUC_BANLIST ) ? TranslateT( "Ban List" ) : + ( dat->type == MUC_ADMINLIST ) ? TranslateT( "Admin List" ) : + ( dat->type == MUC_OWNERLIST ) ? TranslateT( "Owner List" ) : + TranslateT( "JID List" ), xmlGetChildCount(queryNode), localFrom ); + mir_free( localFrom ); + } } } } + SetWindowText( hwndDlg, title ); + + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); + sttFillJidList(hwndDlg); + } + break; + case WM_NOTIFY: + if (( ( LPNMHDR )lParam )->idFrom == IDC_LIST ) { + switch (( ( LPNMHDR )lParam )->code ) { + case NM_CUSTOMDRAW: + { + NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam; + + switch ( nm->nmcd.dwDrawStage ) { + case CDDS_PREPAINT: + case CDDS_ITEMPREPAINT: + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW ); + return TRUE; + case CDDS_SUBITEM|CDDS_ITEMPREPAINT: + { + RECT rc; + HICON hIcon; + + ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc ); + if ( nm->iSubItem == 1 ) { + if ( nm->nmcd.lItemlParam == ( LPARAM )( -1 )) + hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); + else + hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); + DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL ); + DestroyIcon( hIcon ); + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT ); + return TRUE; + } } } } + break; + case NM_CLICK: + { + NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam; + LVITEM lvi; + LVHITTESTINFO hti; + TCHAR text[128]; + + if ( nm->iSubItem < 1 ) + break; + + hti.pt.x = ( short ) LOWORD( GetMessagePos()); + hti.pt.y = ( short ) HIWORD( GetMessagePos()); + ScreenToClient( nm->hdr.hwndFrom, &hti.pt ); + if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 ) + break; + + if ( hti.iSubItem != 1 ) + break; + + lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.iItem = hti.iItem; + lvi.iSubItem = 0; + lvi.pszText = text; + lvi.cchTextMax = sizeof( text ); + ListView_GetItem( nm->hdr.hwndFrom, &lvi ); + if ( lvi.lParam == ( LPARAM )( -1 )) { + TCHAR szBuffer[ 1024 ]; + _tcscpy( szBuffer, dat->type2str()); + if ( !dat->ppro->EnterString(szBuffer, SIZEOF(szBuffer), NULL, JES_COMBO, "gcAddNick_")) + break; + + // Trim leading and trailing whitespaces + TCHAR *p = szBuffer, *q; + for ( p = szBuffer; *p!='\0' && isspace( BYTE( *p )); p++); + for ( q = p; *q!='\0' && !isspace( BYTE( *q )); q++); + if (*q != '\0') *q = '\0'; + if (*p == '\0') + break; + TCHAR rsn[ 1024 ]; + _tcscpy( rsn, dat->type2str()); + if ( dat->type == MUC_BANLIST ) { + dat->ppro->EnterString(rsn, SIZEOF(rsn), TranslateT("Reason to ban") , JES_COMBO, "gcAddReason_"); + if ( szBuffer ) + dat->ppro->AddMucListItem( dat, p , rsn); + else + dat->ppro->AddMucListItem( dat, p ); + } + else dat->ppro->AddMucListItem( dat, p ); + } + else { + //delete + TCHAR msgText[128]; + + mir_sntprintf( msgText, SIZEOF( msgText ), _T("%s %s?"), TranslateT( "Removing" ), text ); + if ( MessageBox( hwndDlg, msgText, dat->type2str(), MB_YESNO|MB_SETFOREGROUND ) == IDYES ) { + dat->ppro->DeleteMucListItem( dat, ( TCHAR* )lvi.lParam ); + mir_free(( void * )lvi.lParam ); + ListView_DeleteItem( nm->hdr.hwndFrom, hti.iItem ); + } } } + break; + } + break; + } + break; + case WM_COMMAND: + if ((LOWORD(wParam) == IDC_BTN_FILTERAPPLY) || + ((LOWORD(wParam) == IDOK) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) + { + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 1); + sttFillJidList(hwndDlg); + } else + if ((LOWORD(wParam) == IDC_BTN_FILTERRESET) || + ((LOWORD(wParam) == IDCANCEL) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) + { + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); + sttFillJidList(hwndDlg); + } + break; +/* case WM_SETCURSOR: + if ( LOWORD( LPARAM )!= HTCLIENT ) break; + if ( GetForegroundWindow() == GetParent( hwndDlg )) { + POINT pt; + GetCursorPos( &pt ); + ScreenToClient( hwndDlg,&pt ); + SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click + } + break; +*/ case WM_CLOSE: + { + HWND hwndList; + int count, i; + LVITEM lvi; + + // Free lParam of the displayed list items + hwndList = GetDlgItem( hwndDlg, IDC_LIST ); + count = ListView_GetItemCount( hwndList ); + lvi.mask = LVIF_PARAM; + lvi.iSubItem = 0; + for ( i=0; i<count; i++ ) { + lvi.iItem = i; + if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) { + if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) { + mir_free(( void * ) lvi.lParam ); + } + } + } + ListView_DeleteAllItems( hwndList ); + + CJabberProto* ppro = dat->ppro; + switch ( dat->type ) { + case MUC_VOICELIST: + ppro->m_hwndMucVoiceList = NULL; + break; + case MUC_MEMBERLIST: + ppro->m_hwndMucMemberList = NULL; + break; + case MUC_MODERATORLIST: + ppro->m_hwndMucModeratorList = NULL; + break; + case MUC_BANLIST: + ppro->m_hwndMucBanList = NULL; + break; + case MUC_ADMINLIST: + ppro->m_hwndMucAdminList = NULL; + break; + case MUC_OWNERLIST: + ppro->m_hwndMucOwnerList = NULL; + break; + } + + DestroyWindow( hwndDlg ); + } + break; + + case WM_DESTROY: + // Clear GWL_USERDATA + if ( dat != NULL ) { + Utils_SaveWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); + delete dat; + } + break; + } + return FALSE; +} + +static void CALLBACK JabberMucJidListCreateDialogApcProc( void* param ) +{ + HXML iqNode, queryNode; + const TCHAR* from; + HWND *pHwndJidList; + JABBER_MUC_JIDLIST_INFO *jidListInfo = (JABBER_MUC_JIDLIST_INFO *)param; + + if ( jidListInfo == NULL ) return; + if (( iqNode = jidListInfo->iqNode ) == NULL ) return; + if (( from = xmlGetAttrValue( iqNode, _T("from"))) == NULL ) return; + if (( queryNode = xmlGetChild( iqNode , "query" )) == NULL ) return; + + CJabberProto* ppro = jidListInfo->ppro; + switch ( jidListInfo->type ) { + case MUC_VOICELIST: + pHwndJidList = &ppro->m_hwndMucVoiceList; + break; + case MUC_MEMBERLIST: + pHwndJidList = &ppro->m_hwndMucMemberList; + break; + case MUC_MODERATORLIST: + pHwndJidList = &ppro->m_hwndMucModeratorList; + break; + case MUC_BANLIST: + pHwndJidList = &ppro->m_hwndMucBanList; + break; + case MUC_ADMINLIST: + pHwndJidList = &ppro->m_hwndMucAdminList; + break; + case MUC_OWNERLIST: + pHwndJidList = &ppro->m_hwndMucOwnerList; + break; + default: + mir_free( jidListInfo ); + return; + } + + if ( *pHwndJidList!=NULL && IsWindow( *pHwndJidList )) { + SetForegroundWindow( *pHwndJidList ); + SendMessage( *pHwndJidList, WM_JABBER_REFRESH, 0, ( LPARAM )jidListInfo ); + } + else *pHwndJidList = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_JIDLIST ), GetForegroundWindow(), JabberMucJidListDlgProc, ( LPARAM )jidListInfo ); +} + +void CJabberProto::OnIqResultMucGetJidList( HXML iqNode, JABBER_MUC_JIDLIST_TYPE listType ) +{ + const TCHAR* type; + JABBER_MUC_JIDLIST_INFO *jidListInfo; + + if (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL ) return; + + if ( !lstrcmp( type, _T("result" ))) { + if (( jidListInfo = new JABBER_MUC_JIDLIST_INFO ) != NULL ) { + jidListInfo->type = listType; + jidListInfo->ppro = this; + jidListInfo->roomJid = NULL; // Set in the dialog procedure + if (( jidListInfo->iqNode = xi.copyNode( iqNode )) != NULL ) + CallFunctionAsync( JabberMucJidListCreateDialogApcProc, jidListInfo ); + else + mir_free( jidListInfo ); +} } } + +void CJabberProto::OnIqResultMucGetVoiceList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetVoiceList" ); + OnIqResultMucGetJidList( iqNode, MUC_VOICELIST ); +} + +void CJabberProto::OnIqResultMucGetMemberList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetMemberList" ); + OnIqResultMucGetJidList( iqNode, MUC_MEMBERLIST ); +} + +void CJabberProto::OnIqResultMucGetModeratorList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetModeratorList" ); + OnIqResultMucGetJidList( iqNode, MUC_MODERATORLIST ); +} + +void CJabberProto::OnIqResultMucGetBanList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetBanList" ); + OnIqResultMucGetJidList( iqNode, MUC_BANLIST ); +} + +void CJabberProto::OnIqResultMucGetAdminList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetAdminList" ); + OnIqResultMucGetJidList( iqNode, MUC_ADMINLIST ); +} + +void CJabberProto::OnIqResultMucGetOwnerList( HXML iqNode ) +{ + Log( "<iq/> iqResultMucGetOwnerList" ); + OnIqResultMucGetJidList( iqNode, MUC_OWNERLIST ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +JABBER_MUC_JIDLIST_INFO::~JABBER_MUC_JIDLIST_INFO() +{ + xi.destroyNode( iqNode ); + mir_free( roomJid ); +} + +TCHAR* JABBER_MUC_JIDLIST_INFO::type2str() const +{ + switch( type ) { + case MUC_VOICELIST: return TranslateT( "Voice List" ); + case MUC_MEMBERLIST: return TranslateT( "Member List" ); + case MUC_MODERATORLIST: return TranslateT( "Moderator List" ); + case MUC_BANLIST: return TranslateT( "Ban List" ); + case MUC_ADMINLIST: return TranslateT( "Admin List" ); + case MUC_OWNERLIST: return TranslateT( "Owner List" ); + } + + return TranslateT( "JID List" ); +} diff --git a/protocols/JabberG/src/jabber_libstr.cpp b/protocols/JabberG/src/jabber_libstr.cpp new file mode 100644 index 0000000000..4517d77272 --- /dev/null +++ b/protocols/JabberG/src/jabber_libstr.cpp @@ -0,0 +1,31 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +int lstrcmp_null(const TCHAR *s1, const TCHAR *s2) +{ + if (!s1 && !s2) return 0; + if (!s1) return -1; + if (!s2) return 1; + return lstrcmp(s1, s2); +} diff --git a/protocols/JabberG/src/jabber_list.cpp b/protocols/JabberG/src/jabber_list.cpp new file mode 100644 index 0000000000..8a956ebc47 --- /dev/null +++ b/protocols/JabberG/src/jabber_list.cpp @@ -0,0 +1,474 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" + +void MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item); + +///////////////////////////////////////////////////////////////////////////////////////// +// List item freeing + +static void JabberListFreeResourceInternal( JABBER_RESOURCE_STATUS *r) +{ + if ( r->resourceName ) mir_free( r->resourceName ); + if ( r->nick ) mir_free( r->nick ); + if ( r->statusMessage ) mir_free( r->statusMessage ); + if ( r->software ) mir_free( r->software ); + if ( r->version ) mir_free( r->version ); + if ( r->system ) mir_free( r->system ); + if ( r->szCapsNode ) mir_free( r->szCapsNode ); + if ( r->szCapsVer ) mir_free( r->szCapsVer ); + if ( r->szCapsExt ) mir_free( r->szCapsExt ); + if ( r->szRealJid ) mir_free( r->szRealJid ); + if ( r->pSoftwareInfo) delete r->pSoftwareInfo; +} + +static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item ) +{ + if ( item == NULL ) + return; + + if ( item->jid ) mir_free( item->jid ); + if ( item->nick ) mir_free( item->nick ); + + JABBER_RESOURCE_STATUS* r = item->resource; + for ( int i=0; i < item->resourceCount; i++, r++ ) + JabberListFreeResourceInternal( r ); + if ( item->resource ) mir_free( item->resource ); + + JabberListFreeResourceInternal( &item->itemResource ); + + if ( item->group ) mir_free( item->group ); + if ( item->photoFileName ) { + DeleteFile( item->photoFileName ); + mir_free( item->photoFileName ); + } + if ( item->messageEventIdStr ) mir_free( item->messageEventIdStr ); + if ( item->name ) mir_free( item->name ); + if ( item->type ) mir_free( item->type ); + if ( item->service ) mir_free( item->service ); + if ( item->password ) mir_free( item->password ); + if ( item->list==LIST_ROSTER && item->ft ) delete item->ft; + mir_free( item ); +} + +void CJabberProto::ListWipe( void ) +{ + int i; + + EnterCriticalSection( &m_csLists ); + for ( i=0; i < m_lstRoster.getCount(); i++ ) + JabberListFreeItemInternal( m_lstRoster[i] ); + + m_lstRoster.destroy(); + LeaveCriticalSection( &m_csLists ); +} + +int CJabberProto::ListExist( JABBER_LIST list, const TCHAR* jid ) +{ + JABBER_LIST_ITEM tmp; + tmp.list = list; + tmp.jid = (TCHAR*)jid; + tmp.bUseResource = FALSE; + + EnterCriticalSection( &m_csLists ); + + //fyr + if ( list == LIST_ROSTER ) + { + tmp.list = LIST_CHATROOM; + int id = m_lstRoster.getIndex( &tmp ); + if ( id != -1) + tmp.bUseResource = TRUE; + tmp.list = list; + } + + int idx = m_lstRoster.getIndex( &tmp ); + + if ( idx == -1 ) { + LeaveCriticalSection( &m_csLists ); + return 0; + } + + LeaveCriticalSection( &m_csLists ); + return idx+1; +} + +JABBER_LIST_ITEM *CJabberProto::ListAdd( JABBER_LIST list, const TCHAR* jid ) +{ + JABBER_LIST_ITEM* item; + BOOL bUseResource=FALSE; + EnterCriticalSection( &m_csLists ); + if (( item = ListGetItemPtr( list, jid )) != NULL ) { + LeaveCriticalSection( &m_csLists ); + return item; + } + + TCHAR *s = mir_tstrdup( jid ); + TCHAR *q = NULL; + // strip resource name if any + //fyr + if ( !((list== LIST_ROSTER ) && ListExist(LIST_CHATROOM, jid))) { // but only if it is not chat room contact + if ( list != LIST_VCARD_TEMP ) { + TCHAR *p; + if (( p = _tcschr( s, '@' )) != NULL ) + if (( q = _tcschr( p, '/' )) != NULL ) + *q = '\0'; + } + } else { + bUseResource=TRUE; + } + + if ( !bUseResource && list== LIST_ROSTER ) + { + //if it is a chat room keep resource and made it resource sensitive + if ( ChatRoomHContactFromJID( s )) + { + if (q != NULL) *q='/'; + bUseResource=TRUE; + } + } + item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); + ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); + item->list = list; + item->jid = s; + item->itemResource.status = ID_STATUS_OFFLINE; + item->resource = NULL; + item->resourceMode = RSMODE_LASTSEEN; + item->lastSeenResource = -1; + item->manualResource = -1; + item->bUseResource = bUseResource; + + m_lstRoster.insert( item ); + LeaveCriticalSection( &m_csLists ); + + MenuUpdateSrmmIcon(item); + return item; +} + +void CJabberProto::ListRemove( JABBER_LIST list, const TCHAR* jid ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( list, jid ); + if ( i != 0 ) { + JabberListFreeItemInternal( m_lstRoster[ --i ] ); + m_lstRoster.remove( i ); + } + LeaveCriticalSection( &m_csLists ); +} + +void CJabberProto::ListRemoveList( JABBER_LIST list ) +{ + int i = 0; + while (( i=ListFindNext( list, i )) >= 0 ) + ListRemoveByIndex( i ); +} + +void CJabberProto::ListRemoveByIndex( int index ) +{ + EnterCriticalSection( &m_csLists ); + if ( index >= 0 && index < m_lstRoster.getCount()) { + JabberListFreeItemInternal( m_lstRoster[index] ); + m_lstRoster.remove( index ); + } + LeaveCriticalSection( &m_csLists ); +} + +JABBER_RESOURCE_STATUS *CJabberProto::ListFindResource( JABBER_LIST list, const TCHAR* jid ) +{ + JABBER_RESOURCE_STATUS *result = NULL; + + EnterCriticalSection( &m_csLists ); + int i = ListExist( list, jid ); + if ( !i ) { + LeaveCriticalSection( &m_csLists ); + return 0; + } + + JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; + + const TCHAR* p = _tcschr( jid, '@' ); + const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); + if (q) + { + const TCHAR *resource = q+1; + if (*resource) + for ( int j=0; j < LI->resourceCount; j++ ) + if ( !_tcscmp( LI->resource[j].resourceName, resource )) + { + result = LI->resource + j; + break; + } + } + + LeaveCriticalSection( &m_csLists ); + + return result; +} + +int CJabberProto::ListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage, char priority, const TCHAR* nick ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( list, jid ); + if ( !i ) { + LeaveCriticalSection( &m_csLists ); + return 0; + } + + JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; + int bIsNewResource = false, j; + + const TCHAR* p = _tcschr( jid, '@' ); + const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); + if ( q ) { + const TCHAR* resource = q+1; + if ( resource[0] ) { + JABBER_RESOURCE_STATUS* r = LI->resource; + for ( j=0; j < LI->resourceCount; j++, r++ ) { + if ( !_tcscmp( r->resourceName, resource )) { + // Already exist, update status and statusMessage + r->status = status; + replaceStrT( r->statusMessage, statusMessage ); + r->priority = priority; + break; + } } + + if ( j >= LI->resourceCount ) { + // Not already exist, add new resource + LI->resource = ( JABBER_RESOURCE_STATUS * ) mir_realloc( LI->resource, ( LI->resourceCount+1 )*sizeof( JABBER_RESOURCE_STATUS )); + bIsNewResource = true; + r = LI->resource + LI->resourceCount++; + memset( r, 0, sizeof( JABBER_RESOURCE_STATUS )); + r->status = status; + r->affiliation = AFFILIATION_NONE; + r->role = ROLE_NONE; + r->resourceName = mir_tstrdup( resource ); + r->nick = mir_tstrdup( nick ); + if ( statusMessage ) + r->statusMessage = mir_tstrdup( statusMessage ); + r->priority = priority; + } } + } + // No resource, update the main statusMessage + else { + LI->itemResource.status = status; + replaceStrT( LI->itemResource.statusMessage, statusMessage ); + } + + LeaveCriticalSection( &m_csLists ); + + MenuUpdateSrmmIcon(LI); + return bIsNewResource; +} + +void CJabberProto::ListRemoveResource( JABBER_LIST list, const TCHAR* jid ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( list, jid ); + JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; + if ( !i || LI == NULL ) { + LeaveCriticalSection( &m_csLists ); + return; + } + + const TCHAR* p = _tcschr( jid, '@' ); + const TCHAR* q = _tcschr(( p == NULL ) ? jid : p, '/' ); + if ( q ) { + const TCHAR* resource = q+1; + if ( resource[0] ) { + JABBER_RESOURCE_STATUS* r = LI->resource; + int j; + for ( j=0; j < LI->resourceCount; j++, r++ ) { + if ( !_tcsicmp( r->resourceName, resource )) + break; + } + if ( j < LI->resourceCount ) { + // Found last seen resource ID to be removed + if ( LI->lastSeenResource == j ) + LI->lastSeenResource = -1; + else if ( LI->lastSeenResource > j ) + LI->lastSeenResource--; + // update manually selected resource ID + if (LI->resourceMode == RSMODE_MANUAL) + { + if ( LI->manualResource == j ) + { + LI->resourceMode = RSMODE_LASTSEEN; + LI->manualResource = -1; + } else if ( LI->manualResource > j ) + LI->manualResource--; + } + + // Update MirVer due to possible resource changes + UpdateMirVer(LI); + + JabberListFreeResourceInternal( r ); + + if ( LI->resourceCount-- == 1 ) { + mir_free( r ); + LI->resource = NULL; + } + else { + memmove( r, r+1, ( LI->resourceCount-j )*sizeof( JABBER_RESOURCE_STATUS )); + LI->resource = ( JABBER_RESOURCE_STATUS* )mir_realloc( LI->resource, LI->resourceCount*sizeof( JABBER_RESOURCE_STATUS )); + } } } } + + LeaveCriticalSection( &m_csLists ); + + MenuUpdateSrmmIcon(LI); +} + +TCHAR* CJabberProto::ListGetBestResourceNamePtr( const TCHAR* jid ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( LIST_ROSTER, jid ); + if ( !i ) { + LeaveCriticalSection( &m_csLists ); + return NULL; + } + + TCHAR* res = NULL; + + JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; + if ( LI->resourceCount > 1 ) { + if ( LI->resourceMode == RSMODE_LASTSEEN && LI->lastSeenResource>=0 && LI->lastSeenResource < LI->resourceCount ) + res = LI->resource[ LI->lastSeenResource ].resourceName; + else if (LI->resourceMode == RSMODE_MANUAL && LI->manualResource>=0 && LI->manualResource < LI->resourceCount ) + res = LI->resource[ LI->manualResource ].resourceName; + else { + int nBestPos = -1, nBestPri = -200, j; + for ( j = 0; j < LI->resourceCount; j++ ) { + if ( LI->resource[ j ].priority > nBestPri ) { + nBestPri = LI->resource[ j ].priority; + nBestPos = j; + } + } + if ( nBestPos != -1 ) + res = LI->resource[ nBestPos ].resourceName; + } + } + + if ( !res && LI->resource) + res = LI->resource[0].resourceName; + + LeaveCriticalSection( &m_csLists ); + return res; +} + +TCHAR* CJabberProto::ListGetBestClientResourceNamePtr( const TCHAR* jid ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( LIST_ROSTER, jid ); + if ( !i ) { + LeaveCriticalSection( &m_csLists ); + return NULL; + } + + JABBER_LIST_ITEM* LI = m_lstRoster[i-1]; + TCHAR* res = ListGetBestResourceNamePtr( jid ); + if ( res == NULL ) { + JABBER_RESOURCE_STATUS* r = LI->resource; + int status = ID_STATUS_OFFLINE; + res = NULL; + for ( i=0; i < LI->resourceCount; i++ ) { + int s = r[i].status; + BOOL foundBetter = FALSE; + switch ( s ) { + case ID_STATUS_FREECHAT: + foundBetter = TRUE; + break; + case ID_STATUS_ONLINE: + if ( status != ID_STATUS_FREECHAT ) + foundBetter = TRUE; + break; + case ID_STATUS_DND: + if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE ) + foundBetter = TRUE; + break; + case ID_STATUS_AWAY: + if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND ) + foundBetter = TRUE; + break; + case ID_STATUS_NA: + if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND && status != ID_STATUS_AWAY ) + foundBetter = TRUE; + break; + } + if ( foundBetter ) { + res = r[i].resourceName; + status = s; + } } } + + LeaveCriticalSection( &m_csLists ); + return res; +} + +int CJabberProto::ListFindNext( JABBER_LIST list, int fromOffset ) +{ + EnterCriticalSection( &m_csLists ); + int i = ( fromOffset >= 0 ) ? fromOffset : 0; + for ( ; i<m_lstRoster.getCount(); i++ ) + if ( m_lstRoster[i]->list == list ) { + LeaveCriticalSection( &m_csLists ); + return i; + } + LeaveCriticalSection( &m_csLists ); + return -1; +} + +JABBER_LIST_ITEM *CJabberProto::ListGetItemPtr( JABBER_LIST list, const TCHAR* jid ) +{ + EnterCriticalSection( &m_csLists ); + int i = ListExist( list, jid ); + if ( !i ) { + LeaveCriticalSection( &m_csLists ); + return NULL; + } + i--; + LeaveCriticalSection( &m_csLists ); + return m_lstRoster[i]; +} + +JABBER_LIST_ITEM *CJabberProto::ListGetItemPtrFromIndex( int index ) +{ + EnterCriticalSection( &m_csLists ); + if ( index >= 0 && index < m_lstRoster.getCount()) { + LeaveCriticalSection( &m_csLists ); + return m_lstRoster[index]; + } + LeaveCriticalSection( &m_csLists ); + return NULL; +} + +BOOL CJabberProto::ListLock() +{ + EnterCriticalSection( &m_csLists ); + return TRUE; +} + +BOOL CJabberProto::ListUnlock() +{ + LeaveCriticalSection( &m_csLists ); + return TRUE; +} diff --git a/protocols/JabberG/src/jabber_list.h b/protocols/JabberG/src/jabber_list.h new file mode 100644 index 0000000000..503a479ece --- /dev/null +++ b/protocols/JabberG/src/jabber_list.h @@ -0,0 +1,202 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_LIST_H_ +#define _JABBER_LIST_H_ + +#include "jabber_caps.h" + +typedef enum { + LIST_ROSTER, // Roster list + LIST_CHATROOM, // Groupchat room currently joined + LIST_ROOM, // Groupchat room list to show on the Jabber groupchat dialog + LIST_FILE, // Current file transfer session + LIST_BYTE, // Bytestream sending connection + LIST_FTRECV, + LIST_BOOKMARK, + LIST_VCARD_TEMP, + LIST_FTIQID +} JABBER_LIST; + +typedef enum { + SUB_NONE, + SUB_TO, + SUB_FROM, + SUB_BOTH +} JABBER_SUBSCRIPTION; + +typedef enum { + AFFILIATION_NONE, + AFFILIATION_OUTCAST, + AFFILIATION_MEMBER, + AFFILIATION_ADMIN, + AFFILIATION_OWNER +} JABBER_GC_AFFILIATION; + +typedef enum { + ROLE_NONE, + ROLE_VISITOR, + ROLE_PARTICIPANT, + ROLE_MODERATOR +} JABBER_GC_ROLE; + +typedef enum { // initial default to RSMODE_LASTSEEN + RSMODE_SERVER, // always let server decide ( always send correspondence without resouce name ) + RSMODE_LASTSEEN, // use the last seen resource ( or let server decide if haven't seen anything yet ) + RSMODE_MANUAL // specify resource manually ( see the defaultResource field - must not be NULL ) +} JABBER_RESOURCE_MODE; + + +struct JABBER_XEP0232_SOFTWARE_INFO +{ + TCHAR* szOs; + TCHAR* szOsVersion; + TCHAR* szSoftware; + TCHAR* szSoftwareVersion; + TCHAR* szXMirandaCoreVersion; + BOOL bXMirandaIsUnicode; + BOOL bXMirandaIsAlpha; + BOOL bXMirandaIsDebug; + JABBER_XEP0232_SOFTWARE_INFO() { + ZeroMemory( this, sizeof( JABBER_XEP0232_SOFTWARE_INFO )); + } + ~JABBER_XEP0232_SOFTWARE_INFO() { + mir_free(szOs); + mir_free(szOsVersion); + mir_free(szSoftware); + mir_free(szSoftwareVersion); + mir_free(szXMirandaCoreVersion); + } +}; + +struct JABBER_RESOURCE_STATUS +{ + int status; + TCHAR* resourceName; + TCHAR* nick; + TCHAR* statusMessage; + TCHAR* software; + TCHAR* version; + TCHAR* system; + signed char priority; // resource priority, -128..+127 + time_t idleStartTime;// XEP-0012 support + JABBER_GC_AFFILIATION affiliation; + JABBER_GC_ROLE role; + TCHAR* szRealJid; // real jid for jabber conferences + + // XEP-0115 support + TCHAR* szCapsNode; + TCHAR* szCapsVer; + TCHAR* szCapsExt; + DWORD dwVersionRequestTime; + DWORD dwDiscoInfoRequestTime; + JabberCapsBits jcbCachedCaps; + JabberCapsBits jcbManualDiscoveredCaps; + + // XEP-0085 gone event support + BOOL bMessageSessionActive; + JABBER_XEP0232_SOFTWARE_INFO* pSoftwareInfo; +}; + +struct JABBER_LIST_ITEM +{ + JABBER_LIST list; + TCHAR* jid; + + // LIST_ROSTER + // jid = jid of the contact + TCHAR* nick; + int resourceCount; + JABBER_RESOURCE_STATUS *resource; + JABBER_RESOURCE_STATUS itemResource; // resource for jids without /resource node + int lastSeenResource; // index to resource[x] which was last seen active + int manualResource; // manually set index to resource[x] +// int defaultResource; // index to resource[x] which is the default, negative ( -1 ) means no resource is chosen yet + JABBER_RESOURCE_MODE resourceMode; + JABBER_SUBSCRIPTION subscription; + TCHAR* group; + TCHAR* photoFileName; + TCHAR* messageEventIdStr; + + // LIST_AGENT + // jid = jid of the agent + TCHAR* name; + TCHAR* service; + + // LIST_ROOM + // jid = room JID + // char* name; // room name + TCHAR* type; // room type + + // LIST_CHATROOM + // jid = room JID + // char* nick; // my nick in this chat room ( SPECIAL: in TXT ) + // JABBER_RESOURCE_STATUS *resource; // participant nicks in this room + BOOL bChatActive; + HWND hwndGcListBan; + HWND hwndGcListAdmin; + HWND hwndGcListOwner; + int iChatState; + // BOOL bAutoJoin; // chat sessio was started via auto-join + + // LIST_FILE + // jid = string representation of port number + filetransfer* ft; + WORD port; + + // LIST_BYTE + // jid = string representation of port number + JABBER_BYTE_TRANSFER *jbt; + + JABBER_IBB_TRANSFER *jibb; + + // LIST_FTRECV + // jid = string representation of stream id ( sid ) + // ft = file transfer data + + //LIST_BOOKMARK + // jid = room JID + // TCHAR* nick; // my nick in this chat room + // TCHAR* name; // name of the bookmark + // TCHAR* type; // type of bookmark ("url" or "conference") + TCHAR* password; // password for room + BOOL bAutoJoin; + + BOOL bUseResource; +}; + +struct JABBER_HTTP_AVATARS +{ + char * Url; + HANDLE hContact; + + JABBER_HTTP_AVATARS(const TCHAR* tUrl, HANDLE thContact) + : Url(mir_t2a(tUrl)), hContact(thContact) {} + + ~JABBER_HTTP_AVATARS() { mir_free(Url); } + + static int compare(const JABBER_HTTP_AVATARS *p1, const JABBER_HTTP_AVATARS *p2) + { return strcmp(p1->Url, p2->Url); } +}; + +#endif diff --git a/protocols/JabberG/src/jabber_menu.cpp b/protocols/JabberG/src/jabber_menu.cpp new file mode 100644 index 0000000000..6bc4c1f8c8 --- /dev/null +++ b/protocols/JabberG/src/jabber_menu.cpp @@ -0,0 +1,1324 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" +#include "jabber_caps.h" +#include "jabber_privacy.h" +#include "jabber_disco.h" + +#include <m_genmenu.h> +#include <m_contacts.h> +#include <m_hotkeys.h> +#include <m_icolib.h> + +#include "m_toptoolbar.h" + +#define MENUITEM_LASTSEEN 1 +#define MENUITEM_SERVER 2 +#define MENUITEM_RESOURCES 10 + +static HANDLE hChooserMenu; +static int iChooserMenuPos = 30000; + +static HANDLE hPrebuildMenuHook; +SortedList arServices; + +static HGENMENU g_hMenuRequestAuth; +static HGENMENU g_hMenuGrantAuth; +static HGENMENU g_hMenuRevokeAuth; +static HGENMENU g_hMenuConvert; +static HGENMENU g_hMenuRosterAdd; +static HGENMENU g_hMenuAddBookmark; +static HGENMENU g_hMenuLogin; +static HGENMENU g_hMenuRefresh; +static HGENMENU g_hMenuCommands; +static HGENMENU g_hMenuSendNote; +static HGENMENU g_hMenuResourcesRoot; +static HGENMENU g_hMenuResourcesActive; +static HGENMENU g_hMenuResourcesServer; + +static struct +{ + int icon; + int mode; +} PresenceModeArray[] = +{ + { SKINICON_STATUS_ONLINE, ID_STATUS_ONLINE }, + { SKINICON_STATUS_AWAY, ID_STATUS_AWAY }, + { SKINICON_STATUS_NA, ID_STATUS_NA }, + { SKINICON_STATUS_DND, ID_STATUS_DND }, + { SKINICON_STATUS_FREE4CHAT, ID_STATUS_FREECHAT }, +}; +static HGENMENU g_hMenuDirectPresence[SIZEOF(PresenceModeArray) + 1]; + +static INT_PTR JabberMenuChooseService( WPARAM wParam, LPARAM lParam ) +{ + if ( lParam ) + *( void** )lParam = ( void* )wParam; + return 0; +} + +static CJabberProto* JabberGetInstanceByHContact( HANDLE hContact ) +{ + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto == NULL ) + return NULL; + + for ( int i=0; i < g_Instances.getCount(); i++ ) + if ( !strcmp( szProto, g_Instances[i]->m_szModuleName )) + return g_Instances[i]; + + return NULL; +} + +static INT_PTR JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuHandleRequestAuth( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuHandleGrantAuth( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuRevokeAuth( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuRevokeAuth( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuConvertChatContact( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuConvertChatContact( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuRosterAdd( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuRosterAdd( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuBookmarkAdd( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuBookmarkAdd( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuTransportLogin( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuTransportLogin( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuTransportResolve( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuTransportResolve( wParam, lParam ) : 0; +} + +static INT_PTR JabberContactMenuRunCommands( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->ContactMenuRunCommands( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuSendNote( WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuSendNote( wParam, lParam ) : 0; +} + +static INT_PTR JabberMenuHandleResource( WPARAM wParam, LPARAM lParam, LPARAM lRes ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuHandleResource( wParam, lParam, lRes ) : 0; +} + +static INT_PTR JabberMenuHandleDirectPresence( WPARAM wParam, LPARAM lParam, LPARAM lRes ) +{ + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnMenuHandleDirectPresence( wParam, lParam, lRes ) : 0; +} + +static void sttEnableMenuItem( HANDLE hMenuItem, BOOL bEnable ) +{ + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS; + if ( !bEnable ) + clmi.flags |= CMIF_HIDDEN; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi ); +} + +static int JabberPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) +{ + sttEnableMenuItem( g_hMenuRequestAuth, FALSE ); + sttEnableMenuItem( g_hMenuGrantAuth, FALSE ); + sttEnableMenuItem( g_hMenuRevokeAuth, FALSE ); + sttEnableMenuItem( g_hMenuCommands, FALSE ); + sttEnableMenuItem( g_hMenuSendNote, FALSE ); + sttEnableMenuItem( g_hMenuConvert, FALSE ); + sttEnableMenuItem( g_hMenuRosterAdd, FALSE ); + sttEnableMenuItem( g_hMenuLogin, FALSE ); + sttEnableMenuItem( g_hMenuRefresh, FALSE ); + sttEnableMenuItem( g_hMenuAddBookmark, FALSE ); + sttEnableMenuItem( g_hMenuResourcesRoot, FALSE ); + sttEnableMenuItem( g_hMenuDirectPresence[0], FALSE ); + + CJabberProto* ppro = JabberGetInstanceByHContact(( HANDLE )wParam ); + return( ppro ) ? ppro->OnPrebuildContactMenu( wParam, lParam ) : 0; +} + +void g_MenuInit( void ) +{ + arServices.increment = 10; + + hPrebuildMenuHook = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, JabberPrebuildContactMenu ); + + List_InsertPtr( &arServices, CreateServiceFunction( "Jabber/MenuChoose", JabberMenuChooseService )); + + TMenuParam mnu = {0}; + mnu.cbSize = sizeof(mnu); + mnu.name = "JabberAccountChooser"; + mnu.ExecService = "Jabber/MenuChoose"; + hChooserMenu = (HANDLE)CallService( MO_CREATENEWMENUOBJECT, 0, (LPARAM)&mnu ); + + TMO_MenuItem tmi = { 0 }; + tmi.cbSize = sizeof( tmi ); + tmi.flags = CMIF_ICONFROMICOLIB; + tmi.pszName = "Cancel"; + tmi.position = 9999999; + tmi.hIcolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_DELETE); + CallService( MO_ADDNEWMENUITEM, (WPARAM)hChooserMenu, ( LPARAM )&tmi ); + + ////////////////////////////////////////////////////////////////////////////////////// + // Contact menu initialization + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(CLISTMENUITEM); + + // "Request authorization" + mi.pszName = LPGEN("Request authorization"); + mi.flags = CMIF_ICONFROMICOLIB; + mi.position = -2000001000; + mi.icolibItem = g_GetIconHandle( IDI_REQUEST ); + mi.pszService = "Jabber/ReqAuth"; + g_hMenuRequestAuth = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuHandleRequestAuth )); + + // "Grant authorization" + mi.pszService = "Jabber/GrantAuth"; + mi.pszName = LPGEN("Grant authorization"); + mi.position = -2000001001; + mi.icolibItem = g_GetIconHandle( IDI_GRANT ); + g_hMenuGrantAuth = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuHandleGrantAuth )); + + // Revoke auth + mi.pszService = "Jabber/RevokeAuth"; + mi.pszName = LPGEN("Revoke authorization"); + mi.position = -2000001002; + mi.icolibItem = g_GetIconHandle( IDI_AUTHREVOKE ); + g_hMenuRevokeAuth = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuRevokeAuth )); + + // "Convert Chat/Contact" + mi.pszService = "Jabber/ConvertChatContact"; + mi.pszName = LPGEN("Convert"); + mi.position = -1999901004; + mi.icolibItem = g_GetIconHandle( IDI_USER2ROOM ); + g_hMenuConvert = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuConvertChatContact )); + + // "Add to roster" + mi.pszService = "Jabber/AddToRoster"; + mi.pszName = LPGEN("Add to roster"); + mi.position = -1999901005; + mi.icolibItem = g_GetIconHandle( IDI_ADDROSTER ); + g_hMenuRosterAdd = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuRosterAdd )); + + // "Add to Bookmarks" + mi.pszService = "Jabber/AddToBookmarks"; + mi.pszName = LPGEN("Add to Bookmarks"); + mi.position = -1999901006; + mi.icolibItem = g_GetIconHandle( IDI_BOOKMARKS); + g_hMenuAddBookmark = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuBookmarkAdd )); + + // Login/logout + mi.pszService = "Jabber/TransportLogin"; + mi.pszName = LPGEN("Login/logout"); + mi.position = -1999901007; + mi.icolibItem = g_GetIconHandle( IDI_LOGIN ); + g_hMenuLogin = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuTransportLogin )); + + // Retrieve nicks + mi.pszService = "Jabber/TransportGetNicks"; + mi.pszName = LPGEN("Resolve nicks"); + mi.position = -1999901008; + mi.icolibItem = g_GetIconHandle( IDI_REFRESH ); + g_hMenuRefresh = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuTransportResolve )); + + // Run Commands + mi.pszService = "Jabber/RunCommands"; + mi.pszName = LPGEN("Commands"); + mi.position = -1999901009; + mi.icolibItem = g_GetIconHandle( IDI_COMMAND ); + g_hMenuCommands = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberContactMenuRunCommands )); + + // Send Note + mi.pszService = "Jabber/SendNote"; + mi.pszName = LPGEN("Send Note"); + mi.position = -1999901010; + mi.icolibItem = g_GetIconHandle( IDI_SEND_NOTE); + g_hMenuSendNote = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunction( mi.pszService, JabberMenuSendNote )); + + // Direct Presence + mi.pszService = "Jabber/DirectPresenceDummySvc"; + mi.pszName = LPGEN("Send Presence"); + mi.position = -1999901011; + mi.pszPopupName = (char *)-1; + mi.icolibItem = g_GetIconHandle( IDI_NOTES ); + g_hMenuDirectPresence[0] = Menu_AddContactMenuItem(&mi); + + mi.flags |= CMIF_ROOTHANDLE; + mi.flags &= ~CMIF_ICONFROMICOLIB; + + for (int i = 0; i < SIZEOF(PresenceModeArray); ++i) + { + char buf[] = "Jabber/DirectPresenceX"; + buf[SIZEOF(buf)-2] = '0' + i; + mi.pszService = buf; + mi.pszName = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, PresenceModeArray[i].mode, 0); + mi.position = -1999901000; + mi.hParentMenu = g_hMenuDirectPresence[0]; + mi.icolibItem = LoadSkinnedIcon(PresenceModeArray[i].icon); + g_hMenuDirectPresence[i+1] = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleDirectPresence, PresenceModeArray[i].mode )); + } + + mi.flags &= ~CMIF_ROOTHANDLE; + mi.flags |= CMIF_ICONFROMICOLIB; + + // Resource selector + mi.pszService = "Jabber/ResourceSelectorDummySvc"; + mi.pszName = LPGEN("Jabber Resource"); + mi.position = -1999901011; + mi.pszPopupName = (char *)-1; + mi.icolibItem = g_GetIconHandle( IDI_JABBER ); + g_hMenuResourcesRoot = Menu_AddContactMenuItem(&mi); + + mi.pszService = "Jabber/UseResource_last"; + mi.pszName = LPGEN("Last Active"); + mi.position = -1999901000; + mi.hParentMenu = g_hMenuResourcesRoot; + mi.icolibItem = g_GetIconHandle( IDI_JABBER ); + mi.flags |= CMIF_ROOTHANDLE; + g_hMenuResourcesActive = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleResource, MENUITEM_LASTSEEN )); + + mi.pszService = "Jabber/UseResource_server"; + mi.pszName = LPGEN("Server's Choice"); + mi.position = -1999901000; + mi.pszPopupName = (char *)g_hMenuResourcesRoot; + mi.icolibItem = g_GetIconHandle( IDI_NODE_SERVER ); + g_hMenuResourcesServer = Menu_AddContactMenuItem(&mi); + List_InsertPtr( &arServices, CreateServiceFunctionParam( mi.pszService, JabberMenuHandleResource, MENUITEM_SERVER )); +} + +void g_MenuUninit( void ) +{ + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRequestAuth, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuGrantAuth, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRevokeAuth, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuConvert, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRosterAdd, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuLogin, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuRefresh, 0 ); + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )g_hMenuAddBookmark, 0 ); + + UnhookEvent( hPrebuildMenuHook ); + for (int i = 0; i < arServices.realCount; i++) + DestroyServiceFunction( arServices.items[i] ); + List_Destroy( &arServices ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// contact menu services + +int CJabberProto::OnPrebuildContactMenu( WPARAM wParam, LPARAM ) +{ + HANDLE hContact; + if (( hContact=( HANDLE )wParam ) == NULL ) + return 0; + + BYTE bIsChatRoom = (BYTE)JGetByte( hContact, "ChatRoom", 0 ); + BYTE bIsTransport = (BYTE)JGetByte( hContact, "IsTransport", 0 ); + + if ((bIsChatRoom == GCW_CHATROOM) || bIsChatRoom == 0 ) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, bIsChatRoom?(char*)"ChatRoomID":(char*)"jid", &dbv )) { + JFreeVariant( &dbv ); + CLISTMENUITEM clmi = { 0 }; + sttEnableMenuItem( g_hMenuConvert, TRUE ); + clmi.cbSize = sizeof( clmi ); + clmi.pszName = bIsChatRoom ? (char *)LPGEN("&Convert to Contact") : (char *)LPGEN("&Convert to Chat Room"); + clmi.flags = CMIM_NAME | CMIM_FLAGS; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuConvert, ( LPARAM )&clmi ); + } } + + if (!m_bJabberOnline) + return 0; + + sttEnableMenuItem( g_hMenuDirectPresence[0], TRUE ); + for (int i = 0; i < SIZEOF(PresenceModeArray); ++i) + { + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_ICON|CMIM_FLAGS; + clmi.hIcon = (HICON)LoadSkinnedProtoIcon(m_szModuleName, PresenceModeArray[i].mode); + CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuDirectPresence[i+1], ( LPARAM )&clmi ); + } + + if ( bIsChatRoom ) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "ChatRoomID", &dbv )) { + sttEnableMenuItem( g_hMenuRosterAdd, FALSE ); + + if ( ListGetItemPtr( LIST_BOOKMARK, dbv.ptszVal ) == NULL ) + if ( m_ThreadInfo && m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE ) + sttEnableMenuItem( g_hMenuAddBookmark, TRUE ); + + JFreeVariant( &dbv ); + } } + + if ( bIsChatRoom == GCW_CHATROOM ) + return 0; + + if ( bIsTransport ) { + sttEnableMenuItem( g_hMenuLogin, TRUE ); + sttEnableMenuItem( g_hMenuRefresh, TRUE ); + } + + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + JabberCapsBits jcb = GetTotalJidCapabilites(dbv.ptszVal ); + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); + JFreeVariant( &dbv ); + if ( item != NULL ) { + BOOL bCtrlPressed = ( GetKeyState( VK_CONTROL)&0x8000 ) != 0; + sttEnableMenuItem( g_hMenuRequestAuth, item->subscription == SUB_FROM || item->subscription == SUB_NONE || bCtrlPressed ); + sttEnableMenuItem( g_hMenuGrantAuth, bCtrlPressed ); + sttEnableMenuItem( g_hMenuRevokeAuth, item->subscription == SUB_FROM || item->subscription == SUB_BOTH || bCtrlPressed ); + sttEnableMenuItem( g_hMenuCommands, (( jcb & JABBER_CAPS_COMMANDS ) != 0) || bCtrlPressed); + sttEnableMenuItem( g_hMenuSendNote, TRUE ); + + if ( item->resourceCount >= 1 ) { + sttEnableMenuItem( g_hMenuResourcesRoot, TRUE ); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(CLISTMENUITEM); + mi.flags = CMIM_ICON|CMIM_FLAGS; + mi.icolibItem = GetIconHandle( IDI_JABBER ); + CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesRoot, ( LPARAM )&mi ); + CallService(MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesActive, ( LPARAM )&mi ); + + int nMenuResourceItemsNew = m_nMenuResourceItems; + if ( m_nMenuResourceItems < item->resourceCount ) { + m_phMenuResourceItems = (HANDLE *)mir_realloc( m_phMenuResourceItems, item->resourceCount * sizeof(HANDLE)); + nMenuResourceItemsNew = item->resourceCount; + } + + char text[ 256 ]; + strcpy( text, m_szModuleName ); + size_t nModuleNameLength = strlen( text ); + char* tDest = text + nModuleNameLength; + + mi.cbSize = sizeof(CLISTMENUITEM); + mi.flags = CMIF_CHILDPOPUP; + mi.position = 0; + mi.icolibItem = GetIconHandle( IDI_REQUEST ); + mi.pszService = text; + mi.pszContactOwner = m_szModuleName; + + TCHAR szTmp[512]; + for (int i = 0; i < nMenuResourceItemsNew; ++i) { + mir_snprintf( tDest, SIZEOF(text) - nModuleNameLength, "/UseResource_%d", i ); + if ( i >= m_nMenuResourceItems ) { + JCreateServiceParam( tDest, &CJabberProto::OnMenuHandleResource, MENUITEM_RESOURCES+i ); + mi.pszName = ""; + mi.position = i; + mi.pszPopupName = (char *)g_hMenuResourcesRoot; + m_phMenuResourceItems[i] = Menu_AddContactMenuItem(&mi); + } + if ( i < item->resourceCount ) { + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_NAME|CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_TCHAR; + if ((item->resourceMode == RSMODE_MANUAL) && (item->manualResource == i)) + clmi.flags |= CMIF_CHECKED; + if (ServiceExists(MS_FP_GETCLIENTICONT)) { + clmi.flags |= CMIM_ICON; + FormatMirVer(&item->resource[i], szTmp, SIZEOF(szTmp)); + clmi.hIcon = (HICON)CallService( MS_FP_GETCLIENTICONT, (WPARAM)szTmp, 0 ); + } + mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s [%s, %d]"), + item->resource[i].resourceName, + (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, item->resource[i].status, GSMDF_TCHAR), + item->resource[i].priority); + clmi.ptszName = szTmp; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_phMenuResourceItems[i], ( LPARAM )&clmi ); + DestroyIcon(clmi.hIcon); + } + else sttEnableMenuItem( m_phMenuResourceItems[i], FALSE ); + } + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(CLISTMENUITEM); + + mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_ICONFROMICOLIB | + ((item->resourceMode == RSMODE_LASTSEEN) ? CMIF_CHECKED : 0); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesActive, ( LPARAM )&mi ); + + mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP|CMIF_ICONFROMICOLIB | + ((item->resourceMode == RSMODE_SERVER) ? CMIF_CHECKED : 0); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )g_hMenuResourcesServer, ( LPARAM )&mi ); + + m_nMenuResourceItems = nMenuResourceItemsNew; + } + + return 0; + } } + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuConvertChatContact( WPARAM wParam, LPARAM ) +{ + BYTE bIsChatRoom = (BYTE)JGetByte( (HANDLE ) wParam, "ChatRoom", 0 ); + if ((bIsChatRoom == GCW_CHATROOM) || bIsChatRoom == 0 ) { + DBVARIANT dbv; + if ( !JGetStringT( (HANDLE ) wParam, (bIsChatRoom == GCW_CHATROOM)?(char*)"ChatRoomID":(char*)"jid", &dbv )) { + JDeleteSetting( (HANDLE ) wParam, (bIsChatRoom == GCW_CHATROOM)?"ChatRoomID":"jid"); + JSetStringT( (HANDLE ) wParam, (bIsChatRoom != GCW_CHATROOM)?"ChatRoomID":"jid", dbv.ptszVal); + JFreeVariant( &dbv ); + JSetByte((HANDLE ) wParam, "ChatRoom", (bIsChatRoom == GCW_CHATROOM)?0:GCW_CHATROOM); + } } + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuRosterAdd( WPARAM wParam, LPARAM ) +{ + DBVARIANT dbv; + if ( !wParam ) return 0; // we do not add ourself to the roster. (buggy situation - should not happen) + if ( !JGetStringT( ( HANDLE ) wParam, "ChatRoomID", &dbv )) { + TCHAR *roomID = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + if ( ListGetItemPtr( LIST_ROSTER, roomID ) == NULL ) { + TCHAR *nick = 0; + TCHAR *group = 0; + if ( !DBGetContactSettingTString( ( HANDLE ) wParam, "CList", "Group", &dbv )) { + group = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + if ( !JGetStringT( ( HANDLE ) wParam, "Nick", &dbv )) { + nick = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + AddContactToRoster( roomID, nick, group ); + if ( m_options.AddRoster2Bookmarks == TRUE ) { + + JABBER_LIST_ITEM* item = NULL; + + item = ListGetItemPtr(LIST_BOOKMARK, roomID); + if (!item) { + item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); + ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); + item->jid = mir_tstrdup(roomID); + item->name = mir_tstrdup(nick); + if ( !JGetStringT( ( HANDLE ) wParam, "MyNick", &dbv )) { + item->nick = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + AddEditBookmark( item ); + mir_free(item); + } + } + if (nick) mir_free(nick); + if (nick) mir_free(group); + } + mir_free(roomID); + } + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleRequestAuth( WPARAM wParam, LPARAM ) +{ + HANDLE hContact; + DBVARIANT dbv; + + if (( hContact=( HANDLE ) wParam )!=NULL && m_bJabberOnline ) { + if ( !JGetStringT( hContact, "jid", &dbv )) { + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("subscribe"))); + JFreeVariant( &dbv ); + } } + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleGrantAuth( WPARAM wParam, LPARAM ) +{ + HANDLE hContact; + DBVARIANT dbv; + + if (( hContact=( HANDLE ) wParam )!=NULL && m_bJabberOnline ) { + if ( !JGetStringT( hContact, "jid", &dbv )) { + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("subscribed"))); + JFreeVariant( &dbv ); + } } + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuRevokeAuth( WPARAM wParam, LPARAM ) +{ + HANDLE hContact; + DBVARIANT dbv; + + if (( hContact=( HANDLE ) wParam ) != NULL && m_bJabberOnline ) { + if ( !JGetStringT( hContact, "jid", &dbv )) { + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), dbv.ptszVal ) << XATTR( _T("type"), _T("unsubscribed"))); + JFreeVariant( &dbv ); + } } + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuTransportLogin( WPARAM wParam, LPARAM ) +{ + HANDLE hContact = ( HANDLE )wParam; + if ( !JGetByte( hContact, "IsTransport", 0 )) + return 0; + + DBVARIANT jid; + if ( JGetStringT( hContact, "jid", &jid )) + return 0; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, jid.ptszVal ); + if ( item != NULL ) { + XmlNode p( _T("presence")); xmlAddAttr( p, _T("to"), item->jid ); + if ( item->itemResource.status == ID_STATUS_ONLINE ) + xmlAddAttr( p, _T("type"), _T("unavailable")); + m_ThreadInfo->send( p ); + } + + JFreeVariant( &jid ); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuTransportResolve( WPARAM wParam, LPARAM ) +{ + HANDLE hContact = ( HANDLE )wParam; + if ( !JGetByte( hContact, "IsTransport", 0 )) + return 0; + + DBVARIANT jid; + if ( !JGetStringT( hContact, "jid", &jid )) { + ResolveTransportNicks( jid.ptszVal ); + JFreeVariant( &jid ); + } + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuBookmarkAdd( WPARAM wParam, LPARAM ) +{ + DBVARIANT dbv; + if ( !wParam ) return 0; // we do not add ourself to the roster. (buggy situation - should not happen) + if ( !JGetStringT( ( HANDLE ) wParam, "ChatRoomID", &dbv )) { + TCHAR *roomID = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + if ( ListGetItemPtr( LIST_BOOKMARK, roomID ) == NULL ) { + TCHAR *nick = 0; + if ( !JGetStringT( ( HANDLE ) wParam, "Nick", &dbv )) { + nick = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + JABBER_LIST_ITEM* item = NULL; + + item = ( JABBER_LIST_ITEM* )mir_alloc( sizeof( JABBER_LIST_ITEM )); + ZeroMemory( item, sizeof( JABBER_LIST_ITEM )); + item->jid = mir_tstrdup(roomID); + item->name = ( TCHAR* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GCDNF_TCHAR ); + item->type = _T("conference"); + if ( !JGetStringT(( HANDLE ) wParam, "MyNick", &dbv )) { + item->nick = mir_tstrdup(dbv.ptszVal); + JFreeVariant( &dbv ); + } + AddEditBookmark( item ); + mir_free(item); + + if (nick) mir_free(nick); + } + mir_free(roomID); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// status menu + +void CJabberProto::MenuInit() +{ + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(CLISTMENUITEM); + + char text[ 200 ]; + strcpy( text, m_szModuleName ); + char* tDest = text + strlen( text ); + mi.pszService = text; + + HGENMENU hJabberRoot = MO_GetProtoRootMenu( m_szModuleName ); + if ( hJabberRoot == NULL ) { + mi.ptszName = m_tszUserName; + mi.position = -1999901006; + mi.hParentMenu = HGENMENU_ROOT; + mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.icolibItem = GetIconHandle( IDI_JABBER ); + hJabberRoot = m_hMenuRoot = Menu_AddProtoMenuItem(&mi); + } + else { + if ( m_hMenuRoot ) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )m_hMenuRoot, 0 ); + m_hMenuRoot = NULL; + } + + // "Bookmarks..." + JCreateService( "/Bookmarks", &CJabberProto::OnMenuHandleBookmarks ); + strcpy( tDest, "/Bookmarks" ); + mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; + mi.hParentMenu = hJabberRoot; + mi.pszName = LPGEN("Bookmarks"); + mi.position = 200001; + mi.icolibItem = GetIconHandle( IDI_BOOKMARKS ); + m_hMenuBookmarks = Menu_AddProtoMenuItem(&mi); + + // "Options..." + JCreateService( "/Options", &CJabberProto::OnMenuOptions ); + strcpy( tDest, "/Options" ); + mi.pszName = LPGEN("Options..."); + mi.position = 200002; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_OPTIONS); + Menu_AddProtoMenuItem(&mi); + + // "Services..." + mi.pszName = LPGEN("Services..."); + strcpy( tDest, "/Services" ); + mi.position = 200003; + mi.icolibItem = GetIconHandle( IDI_SERVICE_DISCOVERY ); + HGENMENU hMenuServicesRoot = Menu_AddProtoMenuItem(&mi); + + // "Service Discovery..." + JCreateService( "/ServiceDiscovery", &CJabberProto::OnMenuHandleServiceDiscovery ); + strcpy( tDest, "/ServiceDiscovery" ); + mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTHANDLE; + mi.pszName = LPGEN("Service Discovery"); + mi.position = 2000050001; + mi.icolibItem = GetIconHandle( IDI_SERVICE_DISCOVERY ); + mi.hParentMenu = hMenuServicesRoot; + m_hMenuServiceDiscovery = Menu_AddProtoMenuItem(&mi); + + JCreateService( "/SD/MyTransports", &CJabberProto::OnMenuHandleServiceDiscoveryMyTransports ); + strcpy( tDest, "/SD/MyTransports" ); + mi.pszName = LPGEN("Registered Transports"); + mi.position = 2000050003; + mi.icolibItem = GetIconHandle( IDI_TRANSPORTL ); + m_hMenuSDMyTransports = Menu_AddProtoMenuItem(&mi); + + JCreateService( "/SD/Transports", &CJabberProto::OnMenuHandleServiceDiscoveryTransports ); + strcpy( tDest, "/SD/Transports" ); + mi.pszName = LPGEN("Local Server Transports"); + mi.position = 2000050004; + mi.icolibItem = GetIconHandle( IDI_TRANSPORT ); + m_hMenuSDTransports = Menu_AddProtoMenuItem(&mi); + + JCreateService( "/SD/Conferences", &CJabberProto::OnMenuHandleServiceDiscoveryConferences ); + strcpy( tDest, "/SD/Conferences" ); + mi.pszName = LPGEN("Browse Chatrooms"); + mi.position = 2000050005; + mi.icolibItem = GetIconHandle( IDI_GROUP ); + m_hMenuSDConferences = Menu_AddProtoMenuItem(&mi); + + JCreateService( "/Groupchat", &CJabberProto::OnMenuHandleJoinGroupchat ); + strcpy( tDest, "/Groupchat" ); + mi.pszName = LPGEN("Create/Join groupchat"); + mi.position = 2000050006; + mi.icolibItem = GetIconHandle( IDI_GROUP ); + m_hMenuGroupchat = Menu_AddProtoMenuItem(&mi); + + // "Change Password..." + JCreateService( "/ChangePassword", &CJabberProto::OnMenuHandleChangePassword ); + strcpy( tDest, "/ChangePassword" ); + mi.pszName = LPGEN("Change Password"); + mi.position = 2000050007; + mi.icolibItem = GetIconHandle( IDI_KEYS ); + m_hMenuChangePassword = Menu_AddProtoMenuItem(&mi); + + // "Roster editor" + JCreateService( "/RosterEditor", &CJabberProto::OnMenuHandleRosterControl ); + strcpy( tDest, "/RosterEditor" ); + mi.pszName = LPGEN("Roster editor"); + mi.position = 2000050009; + mi.icolibItem = GetIconHandle( IDI_AGENTS ); + m_hMenuRosterControl = Menu_AddProtoMenuItem(&mi); + + // "XML Console" + JCreateService( "/XMLConsole", &CJabberProto::OnMenuHandleConsole ); + strcpy( tDest, "/XMLConsole" ); + mi.pszName = LPGEN("XML Console"); + mi.position = 2000050010; + mi.icolibItem = GetIconHandle( IDI_CONSOLE ); + Menu_AddProtoMenuItem(&mi); + + JCreateService( "/Notes", &CJabberProto::OnMenuHandleNotes ); + strcpy( tDest, "/Notes" ); + mi.pszName = LPGEN("Notes"); + mi.position = 2000050011; + mi.icolibItem = GetIconHandle( IDI_NOTES); + m_hMenuNotes = Menu_AddProtoMenuItem(&mi); + + BuildPrivacyMenu(); + if ( m_menuItemsStatus ) + BuildPrivacyListsMenu( false ); + + ////////////////////////////////////////////////////////////////////////////////////// + // build priority menu + + m_priorityMenuVal = 0; + m_priorityMenuValSet = false; + + mi.position = 200006; + mi.pszContactOwner = m_szModuleName; + mi.hParentMenu = hJabberRoot; + mi.pszName = LPGEN("Resource priority"); + mi.flags = CMIF_ROOTPOPUP | CMIF_HIDDEN; + m_hMenuPriorityRoot = Menu_AddProtoMenuItem(&mi); + + char szName[128], srvFce[MAX_PATH + 64], *svcName = srvFce+strlen( m_szModuleName ); + mi.pszService = srvFce; + mi.pszName = szName; + mi.position = 2000040000; + mi.flags = CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB; + mi.hParentMenu = m_hMenuPriorityRoot; + + mir_snprintf(srvFce, sizeof(srvFce), "%s/menuSetPriority/0", m_szModuleName); + bool needServices = !ServiceExists(srvFce); + if ( needServices ) + JCreateServiceParam(svcName, &CJabberProto::OnMenuSetPriority, (LPARAM)0); + + int steps[] = { 10, 5, 1, 0, -1, -5, -10 }; + for (int i = 0; i < SIZEOF(steps); ++i) { + if ( !steps[i] ) { + mi.position += 100000; + continue; + } + + mi.icolibItem = (steps[i] > 0) ? GetIconHandle(IDI_ARROW_UP) : GetIconHandle(IDI_ARROW_DOWN); + + mir_snprintf(srvFce, sizeof(srvFce), "%s/menuSetPriority/%d", m_szModuleName, steps[i]); + mir_snprintf(szName, sizeof(szName), (steps[i] > 0) ? "Increase priority by %d" : "Decrease priority by %d", abs(steps[i])); + + if ( needServices ) + JCreateServiceParam(svcName, &CJabberProto::OnMenuSetPriority, (LPARAM)steps[i]); + + mi.position++; + Menu_AddProtoMenuItem(&mi); + } + + UpdatePriorityMenu((short)JGetWord(NULL, "Priority", 0)); + + ////////////////////////////////////////////////////////////////////////////////////// + // finalize status menu + + m_pepServices.RebuildMenu(); + CheckMenuItems(); +} + +////////////////////////////////////////////////////////////////////////// +// priority popup in status menu + +INT_PTR CJabberProto::OnMenuSetPriority(WPARAM, LPARAM, LPARAM dwDelta) +{ + int iDelta = (int)dwDelta; + short priority = 0; + priority = (short)JGetWord(NULL, "Priority", 0) + iDelta; + if (priority > 127) priority = 127; + else if (priority < -128) priority = -128; + JSetWord(NULL, "Priority", priority); + SendPresence(m_iStatus, true); + return 0; +} + +void CJabberProto::UpdatePriorityMenu(short priority) +{ + if (!m_hMenuPriorityRoot || m_priorityMenuValSet && (priority == m_priorityMenuVal)) + return; + + TCHAR szName[128]; + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_TCHAR | CMIM_NAME; + mi.ptszName = szName; + mir_sntprintf(szName, SIZEOF(szName), TranslateT("Resource priority [%d]"), (int)priority); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)m_hMenuPriorityRoot, (LPARAM)&mi); + + m_priorityMenuVal = priority; + m_priorityMenuValSet = true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CJabberProto::GlobalMenuInit() +{ + ////////////////////////////////////////////////////////////////////////////////////// + // Account chooser menu + + TMO_MenuItem tmi = { 0 }; + tmi.cbSize = sizeof(tmi); + tmi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + tmi.ownerdata = this; + tmi.position = iChooserMenuPos++; + tmi.ptszName = m_tszUserName; + m_hChooseMenuItem = (HANDLE)CallService( MO_ADDNEWMENUITEM, (WPARAM)hChooserMenu, ( LPARAM )&tmi ); + + ////////////////////////////////////////////////////////////////////////////////////// + // Hotkeys + + char text[ 200 ]; + strcpy( text, m_szModuleName ); + char* tDest = text + strlen( text ); + + HOTKEYDESC hkd = {0}; + hkd.cbSize = sizeof(hkd); + hkd.pszName = text; + hkd.pszService = text; + hkd.ptszSection = m_tszUserName; + hkd.dwFlags = HKD_TCHAR; + + strcpy(tDest, "/Groupchat"); + hkd.ptszDescription = _T("Join conference"); + Hotkey_Register(&hkd); + + strcpy(tDest, "/Bookmarks"); + hkd.ptszDescription = _T("Open bookmarks"); + Hotkey_Register(&hkd); + + strcpy(tDest, "/PrivacyLists"); + hkd.ptszDescription = _T("Privacy lists"); + Hotkey_Register(&hkd); + + strcpy(tDest, "/ServiceDiscovery"); + hkd.ptszDescription = _T("Service discovery"); + Hotkey_Register(&hkd); +} + +static INT_PTR g_ToolbarHandleJoinGroupchat(WPARAM w, LPARAM l) +{ + if (CJabberProto *ppro = JabberChooseInstance()) + return ppro->OnMenuHandleJoinGroupchat(w, l); + return 0; +} + +static INT_PTR g_ToolbarHandleBookmarks(WPARAM w, LPARAM l) +{ + if (CJabberProto *ppro = JabberChooseInstance()) + return ppro->OnMenuHandleBookmarks(w, l); + return 0; +} + +static INT_PTR g_ToolbarHandleServiceDiscovery(WPARAM w, LPARAM l) +{ + if (CJabberProto *ppro = JabberChooseInstance()) + return ppro->OnMenuHandleServiceDiscovery(w, l); + return 0; +} + +int g_OnToolbarInit(WPARAM, LPARAM) +{ + if ( g_Instances.getCount() == 0 ) + return 0; + + TTBButton button = {0}; + button.cbSize = sizeof(button); + button.dwFlags = TTBBF_SHOWTOOLTIP | TTBBF_VISIBLE; + + List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/Groupchat", g_ToolbarHandleJoinGroupchat )); + button.pszService = "JABBER/*/Groupchat"; + button.pszTooltipUp = button.name = LPGEN("Join conference"); + button.hIconHandleUp = g_GetIconHandle(IDI_GROUP); + TopToolbar_AddButton(&button); + + List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/Bookmarks", g_ToolbarHandleBookmarks )); + button.pszService = "JABBER/*/Bookmarks"; + button.pszTooltipUp = button.name = LPGEN("Open bookmarks"); + button.hIconHandleUp = g_GetIconHandle(IDI_BOOKMARKS); + TopToolbar_AddButton(&button); + + List_InsertPtr( &arServices, CreateServiceFunction("JABBER/*/ServiceDiscovery", g_ToolbarHandleServiceDiscovery )); + button.pszService = "JABBER/*/ServiceDiscovery"; + button.pszTooltipUp = button.name = LPGEN("Service discovery"); + button.hIconHandleUp = g_GetIconHandle(IDI_SERVICE_DISCOVERY); + TopToolbar_AddButton(&button); + return 0; +} + +void CJabberProto::GlobalMenuUninit() +{ + if ( m_phMenuResourceItems ) { + for ( int i=0; i < m_nMenuResourceItems; i++ ) + CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )m_phMenuResourceItems[i], 0 ); + mir_free(m_phMenuResourceItems); + m_phMenuResourceItems = NULL; + } + m_nMenuResourceItems = 0; + + if ( m_hMenuRoot ) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )m_hMenuRoot, 0 ); + m_hMenuRoot = NULL; +} + +void CJabberProto::EnableMenuItems( BOOL bEnable ) +{ + m_menuItemsStatus = bEnable; + CheckMenuItems(); +} + +void CJabberProto::CheckMenuItems() +{ + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS; + if ( !m_menuItemsStatus ) + clmi.flags |= CMIF_GRAYED; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuChangePassword, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuGroupchat, ( LPARAM )&clmi ); + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuPrivacyLists, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuRosterControl, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuServiceDiscovery, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDMyTransports, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDTransports, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuSDConferences, ( LPARAM )&clmi ); + + clmi.flags = CMIM_FLAGS | (( m_ThreadInfo && ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVATE_STORAGE)) ? 0 : CMIF_HIDDEN ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuBookmarks, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuNotes, ( LPARAM )&clmi ); + + clmi.flags = CMIM_FLAGS | (( m_ThreadInfo && ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PRIVACY_LISTS)) ? 0 : CMIF_HIDDEN ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hPrivacyMenuRoot, ( LPARAM )&clmi ); + + clmi.flags = CMIM_FLAGS | ( m_menuItemsStatus ? 0 : CMIF_HIDDEN); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuPriorityRoot, ( LPARAM )&clmi ); + + if ( !m_bPepSupported ) + clmi.flags |= CMIF_HIDDEN; + for ( int i=0; i < m_pepServices.getCount(); i++ ) + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_pepServices[i].GetMenu(), ( LPARAM )&clmi ); + + JabberUpdateDialogs( m_menuItemsStatus ); +} + +////////////////////////////////////////////////////////////////////////// +// resource menu + +static HANDLE hDialogsList = NULL; + +void CJabberProto::MenuHideSrmmIcon(HANDLE hContact) +{ + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = m_szModuleName; + sid.flags = MBF_HIDDEN; + CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid); +} + +void CJabberProto::MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item) +{ + if ( item->list != LIST_ROSTER || !ServiceExists( MS_MSG_MODIFYICON )) + return; + + HANDLE hContact = HContactFromJID(item->jid); + if ( !hContact ) + return; + + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = m_szModuleName; + sid.flags = item->resourceCount ? 0 : MBF_HIDDEN; + CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid); +} + +int CJabberProto::OnProcessSrmmEvent( WPARAM, LPARAM lParam ) +{ + MessageWindowEventData *event = (MessageWindowEventData *)lParam; + + if ( event->uType == MSG_WINDOW_EVT_OPEN ) { + if ( !hDialogsList ) + hDialogsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + WindowList_Add(hDialogsList, event->hwndWindow, event->hContact); + } + else if ( event->uType == MSG_WINDOW_EVT_CLOSING ) { + if (hDialogsList) + WindowList_Remove(hDialogsList, event->hwndWindow); + + DBVARIANT dbv; + BOOL bSupportTyping = FALSE; + if ( !DBGetContactSetting( event->hContact, "SRMsg", "SupportTyping", &dbv )) { + bSupportTyping = dbv.bVal == 1; + JFreeVariant( &dbv ); + } else if ( !DBGetContactSetting( NULL, "SRMsg", "DefaultTyping", &dbv )) { + bSupportTyping = dbv.bVal == 1; + JFreeVariant( &dbv ); + } + if ( bSupportTyping && !JGetStringT( event->hContact, "jid", &dbv )) { + TCHAR jid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, jid, SIZEOF( jid )); + JFreeVariant( &dbv ); + + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( jid ); + + if ( r && r->bMessageSessionActive ) { + r->bMessageSessionActive = FALSE; + JabberCapsBits jcb = GetResourceCapabilites( jid, TRUE ); + + if ( jcb & JABBER_CAPS_CHATSTATES ) { + int iqId = SerialNext(); + m_ThreadInfo->send( + XmlNode( _T("message")) << XATTR( _T("to"), jid ) << XATTR( _T("type"), _T("chat")) << XATTRID( iqId ) + << XCHILDNS( _T("gone"), _T(JABBER_FEAT_CHATSTATES))); + } } } } + + return 0; +} + +int CJabberProto::OnProcessSrmmIconClick( WPARAM wParam, LPARAM lParam ) +{ + StatusIconClickData *sicd = (StatusIconClickData *)lParam; + if (lstrcmpA(sicd->szModule, m_szModuleName)) + return 0; + + HANDLE hContact = (HANDLE)wParam; + if (!hContact) + return 0; + + DBVARIANT dbv; + if (JGetStringT(hContact, "jid", &dbv)) + return 0; + + JABBER_LIST_ITEM *LI = ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); + JFreeVariant( &dbv ); + + if ( !LI ) + return 0; + + HMENU hMenu = CreatePopupMenu(); + TCHAR buf[256]; + + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%s)"), TranslateT("Last active"), + ((LI->lastSeenResource>=0) && (LI->lastSeenResource < LI->resourceCount)) ? + LI->resource[LI->lastSeenResource].resourceName : TranslateT("No activity yet, use server's choice")); + AppendMenu(hMenu, MF_STRING, MENUITEM_LASTSEEN, buf); + + AppendMenu(hMenu, MF_STRING, MENUITEM_SERVER, TranslateT("Highest priority (server's choice)")); + + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + for (int i = 0; i < LI->resourceCount; ++i) + AppendMenu(hMenu, MF_STRING, MENUITEM_RESOURCES+i, LI->resource[i].resourceName); + + if (LI->resourceMode == RSMODE_LASTSEEN) + CheckMenuItem(hMenu, MENUITEM_LASTSEEN, MF_BYCOMMAND|MF_CHECKED); + else if (LI->resourceMode == RSMODE_SERVER) + CheckMenuItem(hMenu, MENUITEM_SERVER, MF_BYCOMMAND|MF_CHECKED); + else + CheckMenuItem(hMenu, MENUITEM_RESOURCES+LI->manualResource, MF_BYCOMMAND|MF_CHECKED); + + int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, sicd->clickLocation.x, sicd->clickLocation.y, 0, WindowList_Find(hDialogsList, hContact), NULL); + + if ( res == MENUITEM_LASTSEEN ) { + LI->manualResource = -1; + LI->resourceMode = RSMODE_LASTSEEN; + } + else if (res == MENUITEM_SERVER) { + LI->manualResource = -1; + LI->resourceMode = RSMODE_SERVER; + } + else if (res >= MENUITEM_RESOURCES) { + LI->manualResource = res - MENUITEM_RESOURCES; + LI->resourceMode = RSMODE_MANUAL; + } + + UpdateMirVer(LI); + MenuUpdateSrmmIcon(LI); + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleResource(WPARAM wParam, LPARAM, LPARAM res) +{ + if ( !m_bJabberOnline || !wParam ) + return 0; + + HANDLE hContact = (HANDLE)wParam; + + DBVARIANT dbv; + if (JGetStringT(hContact, "jid", &dbv)) + return 0; + + JABBER_LIST_ITEM *LI = ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); + JFreeVariant( &dbv ); + + if ( !LI ) + return 0; + + if ( res == MENUITEM_LASTSEEN ) { + LI->manualResource = -1; + LI->resourceMode = RSMODE_LASTSEEN; + } + else if (res == MENUITEM_SERVER) { + LI->manualResource = -1; + LI->resourceMode = RSMODE_SERVER; + } + else if (res >= MENUITEM_RESOURCES) { + LI->manualResource = res - MENUITEM_RESOURCES; + LI->resourceMode = RSMODE_MANUAL; + } + + UpdateMirVer(LI); + MenuUpdateSrmmIcon(LI); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleDirectPresence(WPARAM wParam, LPARAM lParam, LPARAM res) +{ + if ( !m_bJabberOnline || !wParam ) + return 0; + + HANDLE hContact = (HANDLE)wParam; + + TCHAR *jid, text[ 1024 ]; + + DBVARIANT dbv; + int result = JGetStringT( hContact, "jid", &dbv ); + if (result) + { + result = JGetStringT( hContact, "ChatRoomID", &dbv ); + if ( result ) return 0; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, dbv.ptszVal ); + if ( !item ) return 0; + + mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, item->nick ); + jid = text; + } + else + jid = dbv.ptszVal; + + TCHAR buf[1024] = _T(""); + EnterString(buf, SIZEOF(buf), TranslateT("Status Message"), JES_MULTINE); + + SendPresenceTo(res, jid, NULL, buf); + JFreeVariant(&dbv); + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Choose protocol instance +CJabberProto *JabberChooseInstance(bool bIsLink) +{ + if ( g_Instances.getCount() == 0 ) + return NULL; + + if ( g_Instances.getCount() == 1 ) { + if ( g_Instances[0]->m_iStatus != ID_STATUS_OFFLINE && g_Instances[0]->m_iStatus != ID_STATUS_CONNECTING ) + return g_Instances[0]; + return NULL; + } + + if ( bIsLink ) { + for ( int i = 0; i < g_Instances.getCount(); i++ ) + if ( g_Instances[i]->m_options.ProcessXMPPLinks ) + return g_Instances[i]; + } + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + + int nItems = 0, lastItemId = 0; + for (int i = 0; i < g_Instances.getCount(); ++i) { + clmi.flags = CMIM_FLAGS; + + CJabberProto* ppro = g_Instances[i]; + if ( ppro->m_iStatus != ID_STATUS_OFFLINE && ppro->m_iStatus != ID_STATUS_CONNECTING ) { + ++nItems; + lastItemId = i+1; + clmi.flags |= CMIM_ICON; + clmi.hIcon = LoadSkinnedProtoIcon(ppro->m_szModuleName, ppro->m_iStatus); + } + else clmi.flags |= CMIF_HIDDEN; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )ppro->m_hChooseMenuItem, ( LPARAM )&clmi ); + } + + if ( nItems > 1 ) { + ListParam param = { 0 }; + param.MenuObjectHandle = hChooserMenu; + HMENU hMenu = CreatePopupMenu(); + CallService( MO_BUILDMENU, ( WPARAM )hMenu, ( LPARAM )¶m ); + + POINT pt; + GetCursorPos(&pt); + + int res = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, pcli->hwndContactList, NULL ); + DestroyMenu( hMenu ); + + if ( res ) { + CJabberProto* pro = NULL; + CallService( MO_PROCESSCOMMANDBYMENUIDENT, res, ( LPARAM )&pro ); + return pro; + } + + return NULL; + } + + return lastItemId ? g_Instances[lastItemId-1] : NULL; +} diff --git a/protocols/JabberG/src/jabber_message_handlers.cpp b/protocols/JabberG/src/jabber_message_handlers.cpp new file mode 100644 index 0000000000..a3801f274f --- /dev/null +++ b/protocols/JabberG/src/jabber_message_handlers.cpp @@ -0,0 +1,87 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_message_manager.h" + +BOOL CJabberProto::OnMessageError( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) +{ + // we check if is message delivery failure + int id = JabberGetPacketID( node ); + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, pInfo->GetFrom()); + if ( item == NULL ) + item = ListGetItemPtr( LIST_CHATROOM, pInfo->GetFrom()); + if ( item != NULL ) { // yes, it is + TCHAR *szErrText = JabberErrorMsg( pInfo->GetChildNode()); + if ( id != -1 ) { + char *errText = mir_t2a(szErrText); + JSendBroadcast( pInfo->GetHContact(), ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) id, (LPARAM)errText ); + mir_free(errText); + } else { + TCHAR buf[512]; + HXML bodyNode = xmlGetChild( node, "body" ); + if (bodyNode) + mir_sntprintf( buf, SIZEOF( buf ), _T( "%s:\n%s\n%s" ), pInfo->GetFrom(), xmlGetText( bodyNode ), szErrText ); + else + mir_sntprintf( buf, SIZEOF( buf ), _T( "%s:\n%s" ), pInfo->GetFrom(), szErrText ); + + MsgPopup( NULL, buf, TranslateT( "Jabber Error" )); + } + mir_free(szErrText); + } + return TRUE; +} + +BOOL CJabberProto::OnMessageIbb( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) +{ + BOOL bOk = FALSE; + const TCHAR *sid = xmlGetAttrValue( pInfo->GetChildNode(), _T("sid")); + const TCHAR *seq = xmlGetAttrValue( pInfo->GetChildNode(), _T("seq")); + if ( sid && seq && xmlGetText( pInfo->GetChildNode()) ) { + bOk = OnIbbRecvdData( xmlGetText( pInfo->GetChildNode()), sid, seq ); + } + return TRUE; +} + +BOOL CJabberProto::OnMessagePubsubEvent( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) +{ + OnProcessPubsubEvent( node ); + return TRUE; +} + +BOOL CJabberProto::OnMessageGroupchat( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) +{ + JABBER_LIST_ITEM *chatItem = ListGetItemPtr( LIST_CHATROOM, pInfo->GetFrom()); + if ( chatItem ) + { // process GC message + GroupchatProcessMessage( node ); + } else + { // got message from unknown conference... let's leave it :) +// TCHAR *conference = NEWTSTR_ALLOCA(from); +// if (TCHAR *s = _tcschr(conference, _T('/'))) *s = 0; +// XmlNode p( "presence" ); xmlAddAttr( p, "to", conference ); xmlAddAttr( p, "type", "unavailable" ); +// info->send( p ); + } + return TRUE; +} diff --git a/protocols/JabberG/src/jabber_message_manager.cpp b/protocols/JabberG/src/jabber_message_manager.cpp new file mode 100644 index 0000000000..67e9982eb3 --- /dev/null +++ b/protocols/JabberG/src/jabber_message_manager.cpp @@ -0,0 +1,107 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_message_manager.h" + +BOOL CJabberMessageManager::FillPermanentHandlers() +{ + AddPermanentHandler( &CJabberProto::OnMessageError, JABBER_MESSAGE_TYPE_ERROR, JABBER_MESSAGE_PARSE_FROM | JABBER_MESSAGE_PARSE_HCONTACT, NULL, FALSE, _T("error")); + AddPermanentHandler( &CJabberProto::OnMessageIbb, 0, 0, _T(JABBER_FEAT_IBB), FALSE, _T("data")); + AddPermanentHandler( &CJabberProto::OnMessagePubsubEvent, 0, 0, _T(JABBER_FEAT_PUBSUB_EVENT), FALSE, _T("event")); + AddPermanentHandler( &CJabberProto::OnMessageGroupchat, JABBER_MESSAGE_TYPE_GROUPCHAT, JABBER_MESSAGE_PARSE_FROM, NULL, FALSE, NULL ); + return TRUE; +} + +BOOL CJabberMessageManager::HandleMessagePermanent(HXML node, ThreadData *pThreadData) +{ + BOOL bStopHandling = FALSE; + Lock(); + CJabberMessagePermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo && !bStopHandling ) { + // have to get all data here, in the loop, because there's always possibility that previous handler modified it + CJabberMessageInfo messageInfo; + + LPCTSTR szType = xmlGetAttrValue(node, _T("type")); + if ( szType ) + { + if ( !_tcsicmp( szType, _T("normal"))) + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_NORMAL; + else if ( !_tcsicmp( szType, _T("error"))) + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_ERROR; + else if ( !_tcsicmp( szType, _T("chat"))) + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_CHAT; + else if ( !_tcsicmp( szType, _T("groupchat"))) + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_GROUPCHAT; + else if ( !_tcsicmp( szType, _T("headline"))) + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_HEADLINE; + else + break; // m_nMessageType = JABBER_MESSAGE_TYPE_FAIL; + } + else { + messageInfo.m_nMessageType = JABBER_MESSAGE_TYPE_NORMAL; + } + + if ( (pInfo->m_nMessageTypes & messageInfo.m_nMessageType )) { + int i; + for ( i = xmlGetChildCount( node ) - 1; i >= 0; i-- ) { + // enumerate all children and see whether this node suits handler criteria + HXML child = xmlGetChild( node, i ); + + LPCTSTR szTagName = xmlGetName(child); + LPCTSTR szXmlns = xmlGetAttrValue( child, _T("xmlns")); + + if ( (!pInfo->m_szXmlns || ( szXmlns && !_tcscmp( pInfo->m_szXmlns, szXmlns ))) && + ( !pInfo->m_szTag || !_tcscmp( pInfo->m_szTag, szTagName ))) { + // node suits handler criteria, call the handler + messageInfo.m_hChildNode = child; + messageInfo.m_szChildTagName = szTagName; + messageInfo.m_szChildTagXmlns = szXmlns; + messageInfo.m_pUserData = pInfo->m_pUserData; + messageInfo.m_szFrom = xmlGetAttrValue( node, _T("from")); // is necessary for ppro->Log() below, that's why we must parse it even if JABBER_MESSAGE_PARSE_FROM flag is not set + + if (pInfo->m_dwParamsToParse & JABBER_MESSAGE_PARSE_ID_STR) + messageInfo.m_szId = xmlGetAttrValue( node, _T("id")); + + if (pInfo->m_dwParamsToParse & JABBER_IQ_PARSE_TO) + messageInfo.m_szTo = xmlGetAttrValue( node, _T("to")); + + if (pInfo->m_dwParamsToParse & JABBER_MESSAGE_PARSE_HCONTACT) + messageInfo.m_hContact = ppro->HContactFromJID( messageInfo.m_szFrom, 3 ); + + if (messageInfo.m_szFrom) + ppro->Log( "Handling message from " TCHAR_STR_PARAM, messageInfo.m_szFrom ); + if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &messageInfo)) { + bStopHandling = TRUE; + break; + } + } + } + } + pInfo = pInfo->m_pNext; + } + Unlock(); + + return bStopHandling; +} diff --git a/protocols/JabberG/src/jabber_message_manager.h b/protocols/JabberG/src/jabber_message_manager.h new file mode 100644 index 0000000000..dd52b50683 --- /dev/null +++ b/protocols/JabberG/src/jabber_message_manager.h @@ -0,0 +1,250 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_MESSAGE_MANAGER_H_ +#define _JABBER_MESSAGE_MANAGER_H_ + +#include "jabber_xml.h" + +struct CJabberProto; +typedef void ( CJabberProto::*JABBER_MESSAGE_PFUNC )( HXML messageNode, void *usedata ); +typedef void ( *MESSAGE_USER_DATA_FREE_FUNC )( void *pUserData ); + +class CJabberMessageInfo; + +typedef BOOL ( CJabberProto::*JABBER_PERMANENT_MESSAGE_HANDLER )( HXML messageNode, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + +#define JABBER_MESSAGE_PARSE_FROM (1<<3) +#define JABBER_MESSAGE_PARSE_HCONTACT ((1<<4)|JABBER_MESSAGE_PARSE_FROM) +#define JABBER_MESSAGE_PARSE_TO (1<<5) +#define JABBER_MESSAGE_PARSE_ID_STR (1<<6) + +class CJabberMessageInfo +{ +protected: + friend class CJabberMessageManager; + JABBER_PERMANENT_MESSAGE_HANDLER m_pHandler; + CJabberMessageInfo* m_pNext; + +public: + void *m_pUserData; +// parsed data + int m_nMessageType; + LPCTSTR m_szFrom; + LPCTSTR m_szChildTagXmlns; + LPCTSTR m_szChildTagName; + HXML m_hChildNode; + HANDLE m_hContact; + LPCTSTR m_szTo; + LPCTSTR m_szId; + +public: + CJabberMessageInfo() + { + ZeroMemory(this, sizeof(*this)); + } + ~CJabberMessageInfo() + { + } + int GetMessageType() + { + return m_nMessageType; + } + void* GetUserData() + { + return m_pUserData; + } + LPCTSTR GetFrom() + { + return m_szFrom; + } + LPCTSTR GetTo() + { + return m_szTo; + } + LPCTSTR GetIdStr() + { + return m_szId; + } + HANDLE GetHContact() + { + return m_hContact; + } + HXML GetChildNode() + { + return m_hChildNode; + } + LPCTSTR GetChildNodeName() + { + return m_szChildTagName; + } +}; + +class CJabberMessagePermanentInfo +{ + friend class CJabberMessageManager; + + CJabberMessagePermanentInfo* m_pNext; + + JABBER_PERMANENT_MESSAGE_HANDLER m_pHandler; + DWORD m_dwParamsToParse; + int m_nMessageTypes; + LPTSTR m_szXmlns; + LPTSTR m_szTag; + BOOL m_bAllowPartialNs; + void *m_pUserData; + MESSAGE_USER_DATA_FREE_FUNC m_pUserDataFree; + int m_iPriority; +public: + CJabberMessagePermanentInfo() + { + ZeroMemory(this, sizeof(CJabberMessagePermanentInfo)); + } + ~CJabberMessagePermanentInfo() + { + if ( m_pUserDataFree ) + m_pUserDataFree(m_pUserData); + mir_free(m_szXmlns); + mir_free(m_szTag); + } +}; + +class CJabberMessageManager +{ +protected: + CJabberProto* ppro; + CRITICAL_SECTION m_cs; + CJabberMessagePermanentInfo* m_pPermanentHandlers; + +public: + CJabberMessageManager( CJabberProto* proto ) + { + InitializeCriticalSection(&m_cs); + m_pPermanentHandlers = NULL; + ppro = proto; + } + ~CJabberMessageManager() + { + Lock(); + CJabberMessagePermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo ) + { + CJabberMessagePermanentInfo *pTmp = pInfo->m_pNext; + delete pInfo; + pInfo = pTmp; + } + m_pPermanentHandlers = NULL; + Unlock(); + DeleteCriticalSection(&m_cs); + } + BOOL Start() + { + return TRUE; + } + BOOL Shutdown() + { + return TRUE; + } + void Lock() + { + EnterCriticalSection(&m_cs); + } + void Unlock() + { + LeaveCriticalSection(&m_cs); + } + CJabberMessagePermanentInfo* AddPermanentHandler(JABBER_PERMANENT_MESSAGE_HANDLER pHandler, int nMessageTypes, DWORD dwParamsToParse, const TCHAR* szXmlns, BOOL bAllowPartialNs, const TCHAR* szTag, void *pUserData = NULL, MESSAGE_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) + { + CJabberMessagePermanentInfo* pInfo = new CJabberMessagePermanentInfo(); + if (!pInfo) + return NULL; + + pInfo->m_pHandler = pHandler; + pInfo->m_nMessageTypes = nMessageTypes ? nMessageTypes : JABBER_MESSAGE_TYPE_ANY; + replaceStrT( pInfo->m_szXmlns, szXmlns ); + pInfo->m_bAllowPartialNs = bAllowPartialNs; + replaceStrT( pInfo->m_szTag, szTag ); + pInfo->m_dwParamsToParse = dwParamsToParse; + pInfo->m_pUserData = pUserData; + pInfo->m_pUserDataFree = pUserDataFree; + pInfo->m_iPriority = iPriority; + + Lock(); + if (!m_pPermanentHandlers) + m_pPermanentHandlers = pInfo; + else + { + if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { + pInfo->m_pNext = m_pPermanentHandlers; + m_pPermanentHandlers = pInfo; + } else + { + CJabberMessagePermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) + pTmp = pTmp->m_pNext; + pInfo->m_pNext = pTmp->m_pNext; + pTmp->m_pNext = pInfo; + } + } + Unlock(); + + return pInfo; + } + BOOL DeletePermanentHandler(CJabberMessagePermanentInfo *pInfo) + { // returns TRUE when pInfo found, or FALSE otherwise + Lock(); + if (!m_pPermanentHandlers) + { + Unlock(); + return FALSE; + } + if (m_pPermanentHandlers == pInfo) // check first item + { + m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } else + { + CJabberMessagePermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext) + { + if (pTmp->m_pNext == pInfo) + { + pTmp->m_pNext = pTmp->m_pNext->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } + pTmp = pTmp->m_pNext; + } + } + Unlock(); + return FALSE; + } + BOOL HandleMessagePermanent(HXML node, ThreadData *pThreadData); + BOOL FillPermanentHandlers(); +}; + +#endif diff --git a/protocols/JabberG/src/jabber_misc.cpp b/protocols/JabberG/src/jabber_misc.cpp new file mode 100644 index 0000000000..e13c0d450d --- /dev/null +++ b/protocols/JabberG/src/jabber_misc.cpp @@ -0,0 +1,642 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" +#include "jabber_caps.h" + +#include <m_popup.h> +#include "m_folders.h" + +/////////////////////////////////////////////////////////////////////////////// +// JabberAddContactToRoster() - adds a contact to the roster + +void CJabberProto::AddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName ) +{ + XmlNodeIq iq( _T("set"), SerialNext()); + HXML query = iq << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) + << XCHILD( _T("item")) << XATTR( _T("jid"), jid ) << XATTR( _T("name"), nick ); + if ( grpName ) + query << XCHILD( _T("group"), grpName ); + m_ThreadInfo->send( iq ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberChatDllError() - missing CHAT.DLL + +void JabberChatDllError() +{ + MessageBox( NULL, + TranslateT( "CHAT plugin is required for conferences. Install it before chatting" ), + TranslateT( "Jabber Error" ), MB_OK|MB_SETFOREGROUND ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberCompareJids + +int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 ) +{ + if ( !lstrcmpi( jid1, jid2 )) + return 0; + + // match only node@domain part + TCHAR szTempJid1[ JABBER_MAX_JID_LEN ], szTempJid2[ JABBER_MAX_JID_LEN ]; + return lstrcmpi( + JabberStripJid( jid1, szTempJid1, SIZEOF(szTempJid1)), + JabberStripJid( jid2, szTempJid2, SIZEOF(szTempJid2))); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberContactListCreateGroup() + +static void JabberContactListCreateClistGroup( TCHAR* groupName ) +{ + char str[33]; + int i; + DBVARIANT dbv; + + for ( i=0;;i++ ) { + _itoa( i, str, 10 ); + if ( DBGetContactSettingTString( NULL, "CListGroups", str, &dbv )) + break; + TCHAR* name = dbv.ptszVal; + if ( name[0]!='\0' && !_tcscmp( name+1, groupName )) { + // Already exists, no need to create + JFreeVariant( &dbv ); + return; + } + JFreeVariant( &dbv ); + } + + // Create new group with id = i ( str is the text representation of i ) + TCHAR newName[128]; + newName[0] = 1 | GROUPF_EXPANDED; + _tcsncpy( newName+1, groupName, SIZEOF( newName )-1 ); + newName[ SIZEOF( newName )-1] = '\0'; + DBWriteContactSettingTString( NULL, "CListGroups", str, newName ); + CallService( MS_CLUI_GROUPADDED, i+1, 0 ); +} + +void JabberContactListCreateGroup( TCHAR* groupName ) +{ + TCHAR name[128], *p; + + if ( groupName==NULL || groupName[0]=='\0' || groupName[0]=='\\' ) return; + + _tcsncpy( name, groupName, SIZEOF( name )); + name[ SIZEOF( name )-1] = '\0'; + for ( p=name; *p!='\0'; p++ ) { + if ( *p == '\\' ) { + *p = '\0'; + JabberContactListCreateClistGroup( name ); + *p = '\\'; + } + } + JabberContactListCreateClistGroup( name ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberDBAddAuthRequest() + +void CJabberProto::DBAddAuthRequest( const TCHAR* jid, const TCHAR* nick ) +{ + HANDLE hContact = DBCreateContact( jid, NULL, TRUE, TRUE ); + JDeleteSetting( hContact, "Hidden" ); + //JSetStringT( hContact, "Nick", nick ); + + char* szJid = mir_utf8encodeT( jid ); + char* szNick = mir_utf8encodeT( nick ); + + //blob is: uin(DWORD), hContact(DWORD), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ) + //blob is: 0( DWORD ), hContact(DWORD), nick( ASCIIZ ), ""( ASCIIZ ), ""( ASCIIZ ), email( ASCIIZ ), ""( ASCIIZ ) + DBEVENTINFO dbei = { sizeof(DBEVENTINFO) }; + dbei.szModule = m_szModuleName; + dbei.timestamp = ( DWORD )time( NULL ); + dbei.flags = DBEF_UTF; + dbei.eventType = EVENTTYPE_AUTHREQUEST; + dbei.cbBlob = (DWORD)(sizeof(DWORD)*2 + strlen( szNick ) + strlen( szJid ) + 5); + PBYTE pCurBlob = dbei.pBlob = (PBYTE)mir_alloc(dbei.cbBlob); + *((PDWORD)pCurBlob) = 0; pCurBlob += sizeof(DWORD); + *((PDWORD)pCurBlob) = (DWORD)hContact; pCurBlob += sizeof(DWORD); + strcpy(( char* )pCurBlob, szNick ); pCurBlob += strlen( szNick )+1; + *pCurBlob = '\0'; pCurBlob++; //firstName + *pCurBlob = '\0'; pCurBlob++; //lastName + strcpy(( char* )pCurBlob, szJid ); pCurBlob += strlen( szJid )+1; + *pCurBlob = '\0'; //reason + + CallService( MS_DB_EVENT_ADD, ( WPARAM ) ( HANDLE ) NULL, ( LPARAM )&dbei ); + Log( "Setup DBAUTHREQUEST with nick='%s' jid='%s'", szNick, szJid ); + + mir_free( szJid ); + mir_free( szNick ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberDBCreateContact() + +HANDLE CJabberProto::DBCreateContact( const TCHAR* jid, const TCHAR* nick, BOOL temporary, BOOL stripResource ) +{ + TCHAR* s, *p, *q; + size_t len; + char* szProto; + + if ( jid==NULL || jid[0]=='\0' ) + return NULL; + + s = mir_tstrdup( jid ); + q = NULL; + // strip resource if present + if (( p = _tcschr( s, '@' )) != NULL ) + if (( q = _tcschr( p, '/' )) != NULL ) + *q = '\0'; + + if ( !stripResource && q!=NULL ) // so that resource is not stripped + *q = '/'; + len = _tcslen( s ); + + // We can't use JabberHContactFromJID() here because of the stripResource option + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto!=NULL && !strcmp( m_szModuleName, szProto )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + p = dbv.ptszVal; + if ( p && _tcslen( p )>=len && ( p[len]=='\0'||p[len]=='/' ) && !_tcsnicmp( p, s, len )) { + JFreeVariant( &dbv ); + break; + } + JFreeVariant( &dbv ); + } } + hContact = db_find_next(hContact); + } + + if ( hContact == NULL ) { + hContact = ( HANDLE ) CallService( MS_DB_CONTACT_ADD, 0, 0 ); + CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )m_szModuleName ); + JSetStringT( hContact, "jid", s ); + if ( nick != NULL && *nick != '\0' ) + JSetStringT( hContact, "Nick", nick ); + if ( temporary ) + DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); + else + SendGetVcard( s ); + Log( "Create Jabber contact jid=" TCHAR_STR_PARAM ", nick=" TCHAR_STR_PARAM, s, nick ); + DBCheckIsTransportedContact(s,hContact); + } + + mir_free( s ); + return hContact; +} + +BOOL CJabberProto::AddDbPresenceEvent(HANDLE hContact, BYTE btEventType) +{ + if ( !hContact ) + return FALSE; + + switch ( btEventType ) { + case JABBER_DB_EVENT_PRESENCE_SUBSCRIBE: + case JABBER_DB_EVENT_PRESENCE_SUBSCRIBED: + case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE: + case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED: + if ( !m_options.LogPresence ) + return FALSE; + break; + + case JABBER_DB_EVENT_PRESENCE_ERROR: + if ( !m_options.LogPresenceErrors ) + return FALSE; + break; + } + + DBEVENTINFO dbei; + dbei.cbSize = sizeof( dbei ); + dbei.pBlob = &btEventType; + dbei.cbBlob = sizeof( btEventType ); + dbei.eventType = JABBER_DB_EVENT_TYPE_PRESENCE; + dbei.flags = DBEF_READ; + dbei.timestamp = time( NULL ); + dbei.szModule = m_szModuleName; + CallService( MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei ); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberGetAvatarFileName() - gets a file name for the avatar image + +static HANDLE hJabberAvatarsFolder = NULL; +static bool bInitDone = false; + +void CJabberProto::InitCustomFolders( void ) +{ + if ( bInitDone ) + return; + + bInitDone = true; + if ( ServiceExists( MS_FOLDERS_REGISTER_PATH )) { + TCHAR AvatarsFolder[MAX_PATH]; + mir_sntprintf( AvatarsFolder, SIZEOF( AvatarsFolder ), _T("%%miranda_avatarcache%%\\Jabber")); + hJabberAvatarsFolder = FoldersRegisterCustomPathT( m_szModuleName, "Avatars", AvatarsFolder ); // title!!!!!!!!!!! +} } + +void CJabberProto::GetAvatarFileName( HANDLE hContact, TCHAR* pszDest, size_t cbLen ) +{ + size_t tPathLen; + TCHAR* path = ( TCHAR* )alloca( cbLen * sizeof( TCHAR )); + + InitCustomFolders(); + + if ( hJabberAvatarsFolder == NULL || FoldersGetCustomPathT( hJabberAvatarsFolder, path, (int)cbLen, _T(""))) { + TCHAR *tmpPath = Utils_ReplaceVarsT( _T("%miranda_avatarcache%")); + tPathLen = mir_sntprintf( pszDest, cbLen, _T("%s\\Jabber"), tmpPath ); + mir_free(tmpPath); + } + else tPathLen = mir_sntprintf( pszDest, cbLen, _T("%s"), path ); + + DWORD dwAttributes = GetFileAttributes( pszDest ); + if ( dwAttributes == 0xffffffff || ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) + CallService( MS_UTILS_CREATEDIRTREET, 0, ( LPARAM )pszDest ); + + pszDest[ tPathLen++ ] = '\\'; + + char* szFileType = NULL; + switch( JGetByte( hContact, "AvatarType", PA_FORMAT_PNG )) { + case PA_FORMAT_JPEG: szFileType = "jpg"; break; + case PA_FORMAT_PNG: szFileType = "png"; break; + case PA_FORMAT_GIF: szFileType = "gif"; break; + case PA_FORMAT_BMP: szFileType = "bmp"; break; + } + + if ( hContact != NULL ) { + char str[ 256 ]; + DBVARIANT dbv; + if ( !JGetStringUtf( hContact, "jid", &dbv )) { + strncpy( str, dbv.pszVal, sizeof str ); + str[ sizeof(str)-1 ] = 0; + JFreeVariant( &dbv ); + } + else _i64toa(( LONG_PTR )hContact, str, 10 ); + + char* hash = JabberSha1( str ); + mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T(TCHAR_STR_PARAM) _T(".") _T(TCHAR_STR_PARAM), hash, szFileType ); + mir_free( hash ); + } + else if ( m_ThreadInfo != NULL ) { + mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T("%s@") _T(TCHAR_STR_PARAM) _T(" avatar.") _T(TCHAR_STR_PARAM), + m_ThreadInfo->username, m_ThreadInfo->server, szFileType ); + } + else { + DBVARIANT dbv1, dbv2; + BOOL res1 = DBGetContactSettingString( NULL, m_szModuleName, "LoginName", &dbv1 ); + BOOL res2 = DBGetContactSettingString( NULL, m_szModuleName, "LoginServer", &dbv2 ); + mir_sntprintf( pszDest + tPathLen, MAX_PATH - tPathLen, _T(TCHAR_STR_PARAM) _T("@") _T(TCHAR_STR_PARAM) _T(" avatar.") _T(TCHAR_STR_PARAM), + res1 ? "noname" : dbv1.pszVal, + res2 ? m_szModuleName : dbv2.pszVal, + szFileType ); + if (!res1) JFreeVariant( &dbv1 ); + if (!res2) JFreeVariant( &dbv2 ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberResolveTransportNicks - massive vcard update + +void CJabberProto::ResolveTransportNicks( const TCHAR* jid ) +{ + // Set all contacts to offline + HANDLE hContact = m_ThreadInfo->resolveContact; + if ( hContact == NULL ) + hContact = ( HANDLE ) db_find_first(); + + for ( ; hContact != NULL; hContact = db_find_next(hContact)) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( lstrcmpA( szProto, m_szModuleName )) + continue; + + if ( !JGetByte( hContact, "IsTransported", 0 )) + continue; + + DBVARIANT dbv, nick; + if ( JGetStringT( hContact, "jid", &dbv )) + continue; + if ( JGetStringT( hContact, "Nick", &nick )) { + JFreeVariant( &dbv ); + continue; + } + + TCHAR* p = _tcschr( dbv.ptszVal, '@' ); + if ( p ) { + *p = 0; + if ( !lstrcmp( jid, p+1 ) && !lstrcmp( dbv.ptszVal, nick.ptszVal )) { + *p = '@'; + m_ThreadInfo->resolveID = SendGetVcard( dbv.ptszVal ); + m_ThreadInfo->resolveContact = hContact; + JFreeVariant( &dbv ); + JFreeVariant( &nick ); + return; + } } + + JFreeVariant( &dbv ); + JFreeVariant( &nick ); + } + + m_ThreadInfo->resolveID = -1; + m_ThreadInfo->resolveContact = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberSetServerStatus() + +void CJabberProto::SetServerStatus( int iNewStatus ) +{ + if ( !m_bJabberOnline ) + return; + + // change status + int oldStatus = m_iStatus; + switch ( iNewStatus ) { + case ID_STATUS_ONLINE: + case ID_STATUS_NA: + case ID_STATUS_FREECHAT: + case ID_STATUS_INVISIBLE: + m_iStatus = iNewStatus; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + m_iStatus = ID_STATUS_AWAY; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + m_iStatus = ID_STATUS_DND; + break; + default: + return; + } + + if ( m_iStatus == oldStatus ) + return; + + // send presence update + SendPresence( m_iStatus, true ); + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); +} + +// Process a string, and double all % characters, according to chat.dll's restrictions +// Returns a pointer to the new string (old one is not freed) +TCHAR* EscapeChatTags(TCHAR* pszText) +{ + int nChars = 0; + for ( TCHAR* p = pszText; ( p = _tcschr( p, '%' )) != NULL; p++ ) + nChars++; + + if ( nChars == 0 ) + return mir_tstrdup( pszText ); + + TCHAR* pszNewText = (TCHAR*)mir_alloc( sizeof(TCHAR)*(_tcslen( pszText ) + 1 + nChars )), *s, *d; + if ( pszNewText == NULL ) + return mir_tstrdup( pszText ); + + for ( s = pszText, d = pszNewText; *s; s++ ) { + if ( *s == '%' ) + *d++ = '%'; + *d++ = *s; + } + *d = 0; + return pszNewText; +} + +TCHAR* UnEscapeChatTags(TCHAR* str_in) +{ + TCHAR* s = str_in, *d = str_in; + while ( *s ) { + if ( *s == '%' && s[1] == '%' ) + s++; + *d++ = *s++; + } + *d = 0; + return str_in; +} + +////////////////////////////////////////////////////////////////////////// +// update MirVer with data for active resource + +struct +{ + TCHAR *node; + TCHAR *name; +} +static sttCapsNodeToName_Map[] = +{ + { _T("http://miranda-im.org"), _T("Miranda IM Jabber") }, + { _T("http://miranda-ng.org"), _T("Miranda NG Jabber") }, + { _T("http://www.google.com"), _T("GTalk") }, + { _T("http://mail.google.com"), _T("GMail") }, + { _T("http://talk.google.com/xmpp/bot"), _T("GTalk Bot") }, + { _T("http://www.android.com"), _T("Android") }, +}; + +void CJabberProto::UpdateMirVer(JABBER_LIST_ITEM *item) +{ + HANDLE hContact = HContactFromJID(item->jid); + if (!hContact) + return; + + Log("JabberUpdateMirVer: for jid " TCHAR_STR_PARAM, item->jid); + + int resource = -1; + if (item->resourceMode == RSMODE_LASTSEEN) + resource = item->lastSeenResource; + else if (item->resourceMode == RSMODE_MANUAL) + resource = item->manualResource; + if ((resource < 0) || (resource >= item->resourceCount)) + return; + + UpdateMirVer( hContact, &item->resource[resource] ); +} + +void CJabberProto::FormatMirVer(JABBER_RESOURCE_STATUS *resource, TCHAR *buf, int bufSize) +{ + if ( !buf || !bufSize ) return; + buf[ 0 ] = _T('\0'); + if ( !resource ) return; + + // jabber:iq:version info requested and exists? + if ( resource->dwVersionRequestTime && resource->software ) { + Log("JabberUpdateMirVer: for iq:version rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM, resource->resourceName, resource->software); + if ( !resource->version || _tcsstr(resource->software, resource->version)) + lstrcpyn(buf, resource->software, bufSize); + else + mir_sntprintf(buf, bufSize, _T("%s %s"), resource->software, resource->version); + } + // no version info and no caps info? set MirVer = resource name + else if ( !resource->szCapsNode || !resource->szCapsVer ) { + Log("JabberUpdateMirVer: for rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM, resource->resourceName, resource->resourceName); + if ( resource->resourceName ) + lstrcpyn(buf, resource->resourceName, bufSize); + } + // XEP-0115 caps mode + else { + Log("JabberUpdateMirVer: for rc " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM "#" TCHAR_STR_PARAM, resource->resourceName, resource->szCapsNode, resource->szCapsVer); + + int i; + + // search through known software list + for (i = 0; i < SIZEOF(sttCapsNodeToName_Map); ++i) + if ( _tcsstr( resource->szCapsNode, sttCapsNodeToName_Map[i].node )) + { + mir_sntprintf( buf, bufSize, _T("%s %s"), sttCapsNodeToName_Map[i].name, resource->szCapsVer ); + break; + } + + // unknown software + if (i == SIZEOF(sttCapsNodeToName_Map)) + mir_sntprintf( buf, bufSize, _T("%s %s"), resource->szCapsNode, resource->szCapsVer ); + } + + // attach additional info for fingerprint plguin + if (resource->resourceName && !_tcsstr(buf, resource->resourceName)) + { + if (_tcsstr(buf, _T("Miranda IM")) || _tcsstr(buf, _T("Miranda NG")) || m_options.ShowForeignResourceInMirVer ) + { + int offset = lstrlen(buf); + mir_sntprintf(buf + offset, bufSize - offset, _T(" [%s]"), resource->resourceName); + } + } + + if (resource->szCapsExt && _tcsstr(resource->szCapsExt, _T(JABBER_EXT_SECUREIM)) && !_tcsstr(buf, _T("(SecureIM)"))) + { + int offset = lstrlen(buf); + mir_sntprintf(buf + offset, bufSize - offset, _T(" (SecureIM)")); + } +} + + +void CJabberProto::UpdateMirVer(HANDLE hContact, JABBER_RESOURCE_STATUS *resource) +{ + TCHAR szMirVer[ 512 ]; + FormatMirVer(resource, szMirVer, SIZEOF(szMirVer)); + if ( szMirVer[0] ) + JSetStringT( hContact, "MirVer", szMirVer ); +// else +// JDeleteSetting( hContact, "MirVer" ); + + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + TCHAR szFullJid[ JABBER_MAX_JID_LEN ]; + if ( resource->resourceName ) + mir_sntprintf( szFullJid, SIZEOF( szFullJid ), _T("%s/%s"), dbv.ptszVal, resource->resourceName ); + else + lstrcpyn( szFullJid, dbv.ptszVal, SIZEOF(szFullJid)); + JSetStringT( hContact, DBSETTING_DISPLAY_UID, szFullJid ); + JFreeVariant( &dbv ); + } +} + +void CJabberProto::UpdateSubscriptionInfo(HANDLE hContact, JABBER_LIST_ITEM *item) +{ + switch (item->subscription) + { + case SUB_TO: + JSetStringT(hContact, "SubscriptionText", TranslateT("To")); + JSetString(hContact, "Subscription", "to"); + JSetByte(hContact, "Auth", 0); + JSetByte(hContact, "Grant", 1); + break; + case SUB_FROM: + JSetStringT(hContact, "SubscriptionText", TranslateT("From")); + JSetString(hContact, "Subscription", "from"); + JSetByte(hContact, "Auth", 1); + JSetByte(hContact, "Grant", 0); + break; + case SUB_BOTH: + JSetStringT(hContact, "SubscriptionText", TranslateT("Both")); + JSetString(hContact, "Subscription", "both"); + JSetByte(hContact, "Auth", 0); + JSetByte(hContact, "Grant", 0); + break; + case SUB_NONE: + JSetStringT(hContact, "SubscriptionText", TranslateT("None")); + JSetString(hContact, "Subscription", "none"); + JSetByte(hContact, "Auth", 1); + JSetByte(hContact, "Grant", 1); + break; + } +} + +void CJabberProto::SetContactOfflineStatus( HANDLE hContact ) +{ + if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) + JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); + + JDeleteSetting( hContact, DBSETTING_XSTATUSID ); + JDeleteSetting( hContact, DBSETTING_XSTATUSNAME ); + JDeleteSetting( hContact, DBSETTING_XSTATUSMSG ); + JDeleteSetting( hContact, DBSETTING_DISPLAY_UID ); + + ResetAdvStatus( hContact, ADVSTATUS_MOOD ); + ResetAdvStatus( hContact, ADVSTATUS_TUNE ); + + //JabberUpdateContactExtraIcon(hContact); +} + +void CJabberProto::InitPopups(void) +{ + TCHAR desc[256]; + char name[256]; + + POPUPCLASS ppc = {0}; + ppc.cbSize = sizeof(ppc); + ppc.flags = PCF_TCHAR; + + ppc.ptszDescription = desc; + ppc.pszName = name; + ppc.hIcon = LoadIconEx("main"); + ppc.colorBack = RGB(191, 0, 0); //Red + ppc.colorText = RGB(255, 245, 225); //Yellow + ppc.iSeconds = 60; + mir_sntprintf(desc, SIZEOF(desc), _T("%s %s"), m_tszUserName, TranslateT("Errors")); + mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Error"); + + CallService(MS_POPUP_REGISTERCLASS, 0, (WPARAM)&ppc); +} + +void CJabberProto::MsgPopup(HANDLE hContact, const TCHAR *szMsg, const TCHAR *szTitle) +{ + if (ServiceExists(MS_POPUP_ADDPOPUPCLASS)) { + char name[256]; + + POPUPDATACLASS ppd = { sizeof(ppd) }; + ppd.ptszTitle = szTitle; + ppd.ptszText = szMsg; + ppd.pszClassName = name; + ppd.hContact = hContact; + mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Error"); + + CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd); + } else { + DWORD mtype = MB_OK | MB_SETFOREGROUND | MB_ICONSTOP; + MessageBox(NULL, szMsg, szTitle, mtype); + } +} diff --git a/protocols/JabberG/src/jabber_notes.cpp b/protocols/JabberG/src/jabber_notes.cpp new file mode 100644 index 0000000000..d684541f0a --- /dev/null +++ b/protocols/JabberG/src/jabber_notes.cpp @@ -0,0 +1,865 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "jabber_privacy.h" +#include "jabber_notes.h" + +static TCHAR *StrTrimCopy(TCHAR *str) +{ + if (!str) return 0; + while (*str && _istspace(*str)) ++str; + if (!*str) return mir_tstrdup(str); + + TCHAR *res = mir_tstrdup(str); + for (TCHAR *p = res + lstrlen(res) - 1; p >= res; --p) + { + if (_istspace(*p)) + *p = 0; + else + break; + } + + return res; +} + +CNoteItem::CNoteItem() +{ + m_szTitle = + m_szFrom = + m_szText = + m_szTags = + m_szTagsStr = NULL; +} + +CNoteItem::CNoteItem(HXML hXml, TCHAR *szFrom) +{ + m_szTitle = + m_szFrom = + m_szText = + m_szTags = + m_szTagsStr = NULL; + + SetData( + XPathT(hXml, "title"), + szFrom ? szFrom : XPathT(hXml, "@from"), + XPathT(hXml, "text"), + XPathT(hXml, "@tags")); +} + +CNoteItem::~CNoteItem() +{ + mir_free(m_szTitle); + mir_free(m_szFrom); + mir_free(m_szText); + mir_free(m_szTags); + mir_free(m_szTagsStr); +} + +void CNoteItem::SetData(TCHAR *title, TCHAR *from, TCHAR *text, TCHAR *tags) +{ + mir_free(m_szTitle); + mir_free(m_szFrom); + mir_free(m_szText); + mir_free(m_szTags); + mir_free(m_szTagsStr); + + m_szTitle = StrTrimCopy(title); + m_szText = JabberStrFixLines(text); + m_szFrom = StrTrimCopy(from); + + const TCHAR *szTags = tags; + TCHAR *p = m_szTags = (TCHAR *)mir_alloc((lstrlen(szTags) + 2 /*for double zero*/) * sizeof(TCHAR)); + TCHAR *q = m_szTagsStr = (TCHAR *)mir_alloc((lstrlen(szTags) + 1) * sizeof(TCHAR)); + for ( ; szTags && *szTags; ++szTags) + { + if (_istspace(*szTags)) + continue; + + if (*szTags == _T(',')) + { + *q++ = _T(','); + *p++ = 0; + continue; + } + + *q++ = *p++ = *szTags; + } + + q[0] = p[0] = p[1] = 0; +} + +bool CNoteItem::HasTag(const TCHAR *szTag) +{ + if (!szTag || !*szTag) + return true; + + for (TCHAR *p = m_szTags; p && *p; p = p + lstrlen(p) + 1) + if (!lstrcmp(p, szTag)) + return true; + + return false; +} + +int CNoteItem::cmp(const CNoteItem *p1, const CNoteItem *p2) +{ + int ret = 0; + if (ret = lstrcmp(p1->m_szTitle, p2->m_szTitle)) return ret; + if (ret = lstrcmp(p1->m_szText, p2->m_szText)) return ret; + if (ret = lstrcmp(p1->m_szTagsStr, p2->m_szTagsStr)) return ret; + if (p1 < p2) return -1; + if (p1 > p2) return 1; + return 0; +} + +void CNoteList::AddNote(HXML hXml, TCHAR *szFrom) +{ + m_bIsModified = true; + insert(new CNoteItem(hXml, szFrom)); +} + +void CNoteList::LoadXml(HXML hXml) +{ + destroy(); + m_bIsModified = false; + + int count = xmlGetChildCount(hXml); + for (int i = 0; i < count; ++i) + { + CNoteItem *pNote = new CNoteItem(xi.getChild(hXml, i)); + if (pNote->IsNotEmpty()) + insert(pNote); + else + delete pNote; + } +} + +void CNoteList::SaveXml(HXML hXmlParent) +{ + m_bIsModified = false; + CNoteList &me = *this; + + for (int i = 0; i < getCount(); ++i) + { + HXML hXmlItem = hXmlParent << XCHILD(_T("note")); + hXmlItem << XATTR(_T("from"), me[i].GetFrom()) << XATTR(_T("tags"), me[i].GetTagsStr()); + hXmlItem << XCHILD(_T("title"), me[i].GetTitle()); + hXmlItem << XCHILD(_T("text"), me[i].GetText()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Single note editor + +class CJabberDlgNoteItem : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + typedef void (CJabberProto::*TFnProcessNote)(CNoteItem *, bool ok); + +public: + CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote); + CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess); + +protected: + void OnInitDialog(); + int Resizer(UTILRESIZECONTROL *urc); + +private: + CNoteItem *m_pNote; + TFnProcessNote m_fnProcess; + + CCtrlEdit m_txtTitle; + CCtrlEdit m_txtText; + CCtrlEdit m_txtTags; + CCtrlButton m_btnOk; + + void btnOk_OnClick(CCtrlButton *) + { + TCHAR *szTitle = m_txtTitle.GetText(); + TCHAR *szText = m_txtText.GetText(); + TCHAR *szTags = m_txtTags.GetText(); + TCHAR *szFrom = mir_tstrdup(m_pNote->GetFrom()); + m_pNote->SetData(szTitle, szFrom, szText, szTags); + mir_free(szTitle); + mir_free(szText); + mir_free(szTags); + mir_free(szFrom); + + m_autoClose = false; + if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, true); + EndDialog(m_hwnd, TRUE); + } + + void OnClose() + { + if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, false); + CSuper::OnClose(); + } +}; + +CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote): + CSuper(parent->GetProto(), IDD_NOTE_EDIT, parent->GetHwnd()), + m_pNote(pNote), + m_fnProcess(NULL), + m_txtTitle(this, IDC_TXT_TITLE), + m_txtText(this, IDC_TXT_TEXT), + m_txtTags(this, IDC_TXT_TAGS), + m_btnOk(this, IDOK) +{ + m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); +} + +CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess): + CSuper(proto, IDD_NOTE_EDIT, NULL), + m_pNote(pNote), + m_fnProcess(fnProcess), + m_txtTitle(this, IDC_TXT_TITLE), + m_txtText(this, IDC_TXT_TEXT), + m_txtTags(this, IDC_TXT_TAGS), + m_btnOk(this, IDOK) +{ + m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); +} + +void CJabberDlgNoteItem::OnInitDialog() +{ + CSuper::OnInitDialog(); + WindowSetIcon( m_hwnd, m_proto, "notes" ); + + if (m_fnProcess) + { + TCHAR buf[256]; + if (m_fnProcess == &CJabberProto::ProcessIncomingNote) + mir_sntprintf(buf, SIZEOF(buf), TranslateT("Incoming note from %s"), m_pNote->GetFrom()); + else + mir_sntprintf(buf, SIZEOF(buf), TranslateT("Send note to %s"), m_pNote->GetFrom()); + + SetWindowText(m_hwnd, buf); + } + + m_txtTitle.SetText(m_pNote->GetTitle()); + m_txtText.SetText(m_pNote->GetText()); + m_txtTags.SetText(m_pNote->GetTagsStr()); +} + +int CJabberDlgNoteItem::Resizer(UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_TXT_TITLE: + return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; + case IDC_TXT_TEXT: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + case IDC_ST_TAGS: + case IDC_TXT_TAGS: + return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; + + case IDOK: + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + + return CSuper::Resizer(urc); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Notebook window + +class CCtrlNotebookList: public CCtrlListBox +{ + typedef CCtrlListBox CSuper; + bool m_adding; + HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; + +public: + CCtrlNotebookList( CDlgBase* dlg, int ctrlId ): CCtrlListBox( dlg, ctrlId ) {} + void SetFonts(HFONT hfntNormal, HFONT hfntSmall, HFONT hfntBold) + { + m_hfntNormal = hfntNormal; + m_hfntSmall = hfntSmall; + m_hfntBold = hfntBold; + } + + int AddString(TCHAR *text, LPARAM data=0) + { + m_adding = true; + int idx = CCtrlListBox::AddString(text, data); + m_adding = false; + if (idx == LB_ERR) return idx; + + MEASUREITEMSTRUCT mis = {0}; + mis.CtlType = ODT_LISTBOX; + mis.CtlID = m_idCtrl; + mis.itemID = idx; + mis.itemData = data; + OnMeasureItem(&mis); + if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); + return idx; + } + + void OnInit() + { + CSuper::OnInit(); + Subclass(); + } + + LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + if (msg == WM_SIZE) + { + SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0); + int cnt = GetCount(); + for (int idx = 0; idx < cnt; ++idx) + { + MEASUREITEMSTRUCT mis = {0}; + mis.CtlType = ODT_LISTBOX; + mis.CtlID = m_idCtrl; + mis.itemID = idx; + mis.itemData = GetItemData(idx); + OnMeasureItem(&mis); + if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); + } + SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); + } + + return CSuper::CustomWndProc(msg, wParam, lParam); + } + + BOOL OnDrawItem(DRAWITEMSTRUCT *lps) + { + if (m_adding) return FALSE; + if (lps->itemID == -1) return TRUE; + if (!lps->itemData) return TRUE; + + HDC hdc = lps->hDC; + CNoteItem *pNote = (CNoteItem *)lps->itemData; + + SetBkMode(hdc, TRANSPARENT); + if (lps->itemState & ODS_SELECTED) + { + FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } else + { + FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_WINDOW)); + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + } + + if (lps->itemID) + { + RECT rcTmp = lps->rcItem; rcTmp.bottom = rcTmp.top+1; + FillRect(hdc, &rcTmp, GetSysColorBrush(COLOR_BTNSHADOW)); + } + + RECT rc = lps->rcItem; + rc.left += 5; + rc.right -= 5; + rc.top += 2; + + SelectObject(hdc, m_hfntBold); + rc.top += DrawText(hdc, pNote->GetTitle(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); + SelectObject(hdc, m_hfntNormal); + if (pNote->GetFrom()) + { + TCHAR buf[256]; + mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); + rc.top += DrawText(hdc, buf, -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); + } + rc.top += DrawText(hdc, pNote->GetText(), -1, &rc, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS); + SelectObject(hdc, m_hfntSmall); + rc.top += DrawText(hdc, pNote->GetTagsStr(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); + rc.top += 5; + + int h = min(255, max(0, rc.bottom - rc.top)); + if (SendMessage(m_hwnd, LB_GETITEMHEIGHT, lps->itemID, 0) != h) + SendMessage(m_hwnd, LB_SETITEMHEIGHT, lps->itemID, h); + + return TRUE; + } + + BOOL OnMeasureItem(MEASUREITEMSTRUCT *lps) + { + if (m_adding) return FALSE; + if (lps->itemID == -1) return TRUE; + if (!lps->itemData) return TRUE; + + HDC hdc = GetDC(m_hwnd); + CNoteItem *pNote = (CNoteItem *)lps->itemData; + + RECT rcTmp, rc; + GetClientRect(m_hwnd, &rc); + int maxHeight = rc.bottom - 10; + rc.bottom = 0; + + SelectObject(hdc, m_hfntBold); + rcTmp = rc; + DrawText(hdc, pNote->GetTitle(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); + lps->itemHeight += rcTmp.bottom; + SelectObject(hdc, m_hfntNormal); + if (pNote->GetFrom()) + { + TCHAR buf[256]; + mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); + rcTmp = rc; + DrawText(hdc, buf, -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); + lps->itemHeight += rcTmp.bottom; + } + rcTmp = rc; + DrawText(hdc, pNote->GetText(), -1, &rcTmp, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS|DT_CALCRECT); + lps->itemHeight += rcTmp.bottom; + SelectObject(hdc, m_hfntSmall); + rcTmp = rc; + DrawText(hdc, pNote->GetTagsStr(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); + lps->itemHeight += rcTmp.bottom; + lps->itemHeight += 5; + + ReleaseDC(m_hwnd, hdc); + + lps->itemWidth = rc.right; + lps->itemHeight = min(255, lps->itemHeight); // listbox can't make items taller then 255px + return TRUE; + } +}; + +class CJabberDlgNotes : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgNotes(CJabberProto *proto); + void UpdateData(); + +protected: + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + int Resizer(UTILRESIZECONTROL *urc); + + void OnProtoCheckOnline(WPARAM wParam, LPARAM lParam); + void OnProtoRefresh(WPARAM wParam, LPARAM lParam); + +private: + CCtrlMButton m_btnAdd; + CCtrlMButton m_btnEdit; + CCtrlMButton m_btnRemove; + CCtrlNotebookList m_lstNotes; + CCtrlTreeView m_tvFilter; + CCtrlButton m_btnSave; + + HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; + + void EnableControls() + { + m_btnSave.Enable(m_proto->m_bJabberOnline && m_proto->m_notes.IsModified()); + m_btnEdit.Enable(m_lstNotes.GetCurSel() != LB_ERR); + m_btnRemove.Enable(m_lstNotes.GetCurSel() != LB_ERR); + } + + void InsertTag(HTREEITEM htiRoot, const TCHAR *tag, bool bSelect) + { + TVINSERTSTRUCT tvi = {0}; + tvi.hParent = htiRoot; + tvi.hInsertAfter = TVI_LAST; + tvi.itemex.mask = TVIF_TEXT|TVIF_PARAM; + tvi.itemex.pszText = (TCHAR *)tag; + tvi.itemex.lParam = (LPARAM)mir_tstrdup(tag); + HTREEITEM hti = m_tvFilter.InsertItem(&tvi); + if (bSelect) m_tvFilter.SelectItem(hti); + } + + void PopulateTags(HTREEITEM htiRoot, TCHAR *szActiveTag) + { + LIST<TCHAR> tagSet(5, _tcscmp); + for (int i = 0; i < m_proto->m_notes.getCount(); ++i) + { + TCHAR *tags = m_proto->m_notes[i].GetTags(); + for (TCHAR *tag = tags; tag && *tag; tag = tag + lstrlen(tag) + 1) + if (!tagSet.find(tag)) + tagSet.insert(tag); + } + + bool selected = false; + for (int j = 0; j < tagSet.getCount(); ++j) + { + bool select = !lstrcmp(szActiveTag, tagSet[j]); + selected |= select; + InsertTag(htiRoot, tagSet[j], select); + } + + if (!selected) + m_tvFilter.SelectItem(htiRoot); + + tagSet.destroy(); + } + + void RebuildTree() + { + TVITEMEX tvi = {0}; + tvi.mask = TVIF_HANDLE|TVIF_PARAM; + tvi.hItem = m_tvFilter.GetSelection(); + m_tvFilter.GetItem(&tvi); + TCHAR *szActiveTag = mir_tstrdup((TCHAR *)tvi.lParam); + + m_tvFilter.DeleteAllItems(); + + TVINSERTSTRUCT tvis = {0}; + tvis.hParent = NULL; + tvis.hInsertAfter = TVI_LAST; + tvis.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE; + tvis.itemex.stateMask = + tvis.itemex.state = TVIS_BOLD|TVIS_EXPANDED; + tvis.itemex.pszText = TranslateT("All tags"); + tvis.itemex.lParam = NULL; + + + PopulateTags(m_tvFilter.InsertItem(&tvis), szActiveTag); + mir_free(szActiveTag); + } + + void InsertItem(CNoteItem &item) + { + m_lstNotes.AddString((TCHAR *)item.GetTitle(), (LPARAM)&item); + EnableControls(); + } + + void ListItems(const TCHAR *tag) + { + m_lstNotes.ResetContent(); + for (int i = 0; i < m_proto->m_notes.getCount(); ++i) + if (m_proto->m_notes[i].HasTag(tag)) + InsertItem(m_proto->m_notes[i]); + EnableControls(); + } + + void btnAdd_OnClick(CCtrlFilterListView *) + { + CNoteItem *pNote = new CNoteItem(); + CJabberDlgNoteItem dlg(this, pNote); + dlg.DoModal(); + + if (pNote->IsNotEmpty()) + { + m_proto->m_notes.insert(pNote); + m_proto->m_notes.Modify(); + UpdateData(); + } else + { + delete pNote; + return; + } + EnableControls(); + } + + void btnEdit_OnClick(CCtrlFilterListView *) + { + int idx = m_lstNotes.GetCurSel(); + if (idx != LB_ERR) + { + if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) + { + CJabberDlgNoteItem dlg(this, pItem); + if (dlg.DoModal()) + { + m_proto->m_notes.Modify(); + RebuildTree(); + } + } + } + EnableControls(); + } + + void btnRemove_OnClick(CCtrlFilterListView *) + { + int idx = m_lstNotes.GetCurSel(); + if (idx != LB_ERR) + { + if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) + { + m_lstNotes.DeleteString(idx); + m_proto->m_notes.remove(pItem); + } + RebuildTree(); + } + EnableControls(); + } + + void lstNotes_OnSelChange(CCtrlListBox *) + { + EnableControls(); + } + + void tvFilter_OnDeleteItem(CCtrlTreeView::TEventInfo *e) + { + TCHAR *szText = (TCHAR *)e->nmtv->itemOld.lParam; + mir_free(szText); + EnableControls(); + } + + void tvFilter_OnSelChanged(CCtrlTreeView::TEventInfo *e) + { + TCHAR *szText = (TCHAR *)e->nmtv->itemNew.lParam; + ListItems(szText); + EnableControls(); + } + + void btnSave_OnClick(CCtrlButton *) + { + XmlNodeIq iq(_T("set")); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); + HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); + m_proto->m_notes.SaveXml(storage); + m_proto->m_ThreadInfo->send(iq); + EnableControls(); + } +}; + +CJabberDlgNotes::CJabberDlgNotes(CJabberProto *proto) : + CSuper(proto, IDD_NOTEBOOK, NULL), + m_btnAdd(this, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add")), + m_btnEdit(this, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit")), + m_btnRemove(this, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove")), + m_lstNotes(this, IDC_LST_NOTES), + m_tvFilter(this, IDC_TV_FILTER), + m_btnSave(this, IDC_APPLY) +{ + m_btnAdd.OnClick = Callback(this, &CJabberDlgNotes::btnAdd_OnClick); + m_btnEdit.OnClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); + m_btnRemove.OnClick = Callback(this, &CJabberDlgNotes::btnRemove_OnClick); + m_lstNotes.OnDblClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); + m_lstNotes.OnSelChange = Callback(this, &CJabberDlgNotes::lstNotes_OnSelChange); + m_btnSave.OnClick = Callback(this, &CJabberDlgNotes::btnSave_OnClick); + + m_tvFilter.OnSelChanged = Callback(this, &CJabberDlgNotes::tvFilter_OnSelChanged); + m_tvFilter.OnDeleteItem = Callback(this, &CJabberDlgNotes::tvFilter_OnDeleteItem); +} + +void CJabberDlgNotes::UpdateData() +{ + RebuildTree(); + //ListItems(NULL); + EnableControls(); +} + +void CJabberDlgNotes::OnInitDialog() +{ + CSuper::OnInitDialog(); + WindowSetIcon( m_hwnd, m_proto, "notes" ); + + LOGFONT lf, lfTmp; + m_hfntNormal = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + GetObject(m_hfntNormal, sizeof(lf), &lf); + lfTmp = lf; lfTmp.lfWeight = FW_BOLD; + m_hfntBold = CreateFontIndirect(&lfTmp); + lfTmp = lf; lfTmp.lfHeight *= 0.8; + m_hfntSmall = CreateFontIndirect(&lfTmp); + m_lstNotes.SetFonts(m_hfntNormal, m_hfntSmall, m_hfntBold); + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); +} + +void CJabberDlgNotes::OnClose() +{ + if (m_proto->m_notes.IsModified()) + { + if (IDYES != MessageBox(m_hwnd, TranslateT("Notes are not saved, close this window without uploading data to server?"), TranslateT("Are you sure?"), MB_ICONWARNING|MB_YESNO|MB_DEFBUTTON2)) + { + m_lresult = TRUE; + return; + } + } + + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); + DeleteObject(m_hfntSmall); + DeleteObject(m_hfntBold); + CSuper::OnClose(); +} + +void CJabberDlgNotes::OnDestroy() +{ + m_tvFilter.DeleteAllItems(); + m_proto->m_pDlgNotes = NULL; + CSuper::OnDestroy(); +} + +void CJabberDlgNotes::OnProtoCheckOnline(WPARAM, LPARAM) +{ + EnableControls(); +} + +void CJabberDlgNotes::OnProtoRefresh(WPARAM, LPARAM) +{ +} + +int CJabberDlgNotes::Resizer(UTILRESIZECONTROL *urc) +{ + switch ( urc->wId ) { + case IDC_TV_FILTER: + return RD_ANCHORX_LEFT|RD_ANCHORY_HEIGHT; + case IDC_LST_NOTES: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + case IDC_APPLY: + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + case IDC_ADD: + case IDC_EDIT: + case IDC_REMOVE: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + } + return CSuper::Resizer(urc); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Launches the incoming note window + +void CJabberProto::ProcessIncomingNote(CNoteItem *pNote, bool ok) +{ + if (ok && pNote->IsNotEmpty()) + { + m_notes.insert(pNote); + + XmlNodeIq iq(_T("set")); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); + HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); + m_notes.SaveXml(storage); + m_ThreadInfo->send(iq); + } else + { + delete pNote; + } +} + +void CJabberProto::ProcessOutgoingNote(CNoteItem *pNote, bool ok) +{ + if (!ok || !pNote->IsNotEmpty()) + { + delete pNote; + return; + } + + TCHAR buf[1024]; + mir_sntprintf(buf, SIZEOF(buf), _T("Incoming note: %s\n\n%s\nTags: %s"), + pNote->GetTitle(), pNote->GetText(), pNote->GetTagsStr()); + + JabberCapsBits jcb = GetResourceCapabilites( pNote->GetFrom(), TRUE ); + + if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) + jcb = JABBER_RESOURCE_CAPS_NONE; + + int nMsgId = SerialNext(); + + XmlNode m(_T("message")); + m << XATTR(_T("type"), _T("chat")) << XATTR( _T("to"), pNote->GetFrom()) << XATTRID( nMsgId ); + m << XCHILD(_T("body"), buf); + HXML hXmlItem = m << XCHILDNS(_T("x"), _T(JABBER_FEAT_MIRANDA_NOTES)) << XCHILD(_T("note")); + hXmlItem << XATTR(_T("tags"), pNote->GetTagsStr()); + hXmlItem << XCHILD(_T("title"), pNote->GetTitle()); + hXmlItem << XCHILD(_T("text"), pNote->GetText()); + + // message receipts XEP priority + if ( jcb & JABBER_CAPS_MESSAGE_RECEIPTS ) + m << XCHILDNS( _T("request"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)); + else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { + HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); + x << XCHILD( _T("delivered")); x << XCHILD( _T("offline")); + } + else + nMsgId = -1; + + m_ThreadInfo->send(m); + delete pNote; +} + +bool CJabberProto::OnIncomingNote(const TCHAR *szFrom, HXML hXml) +{ + if (!m_options.AcceptNotes) + return false; + + if (!szFrom || !hXml) return true; + CNoteItem *pItem = new CNoteItem(hXml, (TCHAR *)szFrom); + if (!pItem->IsNotEmpty()) + { + delete pItem; + return true; + } + + if (m_options.AutosaveNotes && HContactFromJID(szFrom)) + { + ProcessIncomingNote(pItem, true); + return false; + } + + CLISTEVENT cle = {0}; + char szService[256]; + mir_snprintf( szService, sizeof(szService),"%s%s", m_szModuleName, JS_INCOMING_NOTE_EVENT ); + cle.cbSize = sizeof(CLISTEVENT); + cle.hIcon = (HICON)LoadIconEx("notes"); + cle.flags = CLEF_PROTOCOLGLOBAL|CLEF_TCHAR; + cle.hDbEvent = (HANDLE)("test"); + cle.lParam = (LPARAM)pItem; + cle.pszService = szService; + cle.ptszTooltip = TranslateT("Incoming note"); + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + + return true; +} + +INT_PTR __cdecl CJabberProto::OnIncomingNoteEvent(WPARAM, LPARAM lParam) +{ + CLISTEVENT *pCle = (CLISTEVENT *)lParam; + CNoteItem *pNote = (CNoteItem *)pCle->lParam; + if ( !pNote ) + return 0; + + CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pNote, &CJabberProto::ProcessIncomingNote); + pDlg->Show(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Menu handling + +INT_PTR __cdecl CJabberProto::OnMenuHandleNotes( WPARAM, LPARAM) +{ + UI_SAFE_OPEN_EX(CJabberDlgNotes, m_pDlgNotes, pDlg); + pDlg->UpdateData(); + return 0; +} + +INT_PTR __cdecl CJabberProto::OnMenuSendNote(WPARAM wParam, LPARAM) +{ + if (!wParam) return 0; + + TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; + GetClientJID( JGetStringT( (HANDLE)wParam, "jid"), szClientJid, SIZEOF( szClientJid )); + + CNoteItem *pItem = new CNoteItem( NULL, szClientJid ); + CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pItem, &CJabberProto::ProcessOutgoingNote); + pDlg->Show(); + + return 0; +} diff --git a/protocols/JabberG/src/jabber_notes.h b/protocols/JabberG/src/jabber_notes.h new file mode 100644 index 0000000000..de096943c2 --- /dev/null +++ b/protocols/JabberG/src/jabber_notes.h @@ -0,0 +1,82 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __jabber_notes_h__ +#define __jabber_notes_h__ + +class CNoteItem +{ +private: + TCHAR *m_szTitle; + TCHAR *m_szFrom; + TCHAR *m_szText; + TCHAR *m_szTags; + TCHAR *m_szTagsStr; + +public: + CNoteItem(); + CNoteItem(HXML hXml, TCHAR *szFrom = 0); + ~CNoteItem(); + + void SetData(TCHAR *title, TCHAR *from, TCHAR *text, TCHAR *tags); + + TCHAR *GetTitle() const { return m_szTitle; } + TCHAR *GetFrom() const { return m_szFrom; } + TCHAR *GetText() const { return m_szText; } + TCHAR *GetTags() const { return m_szTags; } + TCHAR *GetTagsStr() const { return m_szTagsStr; } + + bool HasTag(const TCHAR *szTag); + + bool IsNotEmpty() + { + return (m_szTitle && *m_szTitle) || (m_szText && *m_szText); + } + + static int cmp(const CNoteItem *p1, const CNoteItem *p2); +}; + +class CNoteList: public OBJLIST<CNoteItem> +{ +private: + bool m_bIsModified; + +public: + CNoteList(): OBJLIST<CNoteItem>(10, CNoteItem::cmp) {} + + void remove(CNoteItem *p) + { + m_bIsModified = true; + OBJLIST<CNoteItem>::remove(p); + } + + void AddNote(HXML hXml, TCHAR *szFrom = 0); + void LoadXml(HXML hXml); + void SaveXml(HXML hXmlParent); + + bool IsModified() { return m_bIsModified; } + void Modify() { m_bIsModified = true; } +}; + +#endif // __jabber_notes_h__ diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp new file mode 100644 index 0000000000..1f1270a8a1 --- /dev/null +++ b/protocols/JabberG/src/jabber_opt.cpp @@ -0,0 +1,2331 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_list.h" + +#include "jabber_caps.h" +#include "jabber_opttree.h" +#include "m_modernopt.h" + +static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberRegisterDlgProc - the dialog proc for registering new account + +#define STR_FORMAT _T("%s %s@%S:%d?") + +struct { TCHAR *szCode; TCHAR *szDescription; } g_LanguageCodes[] = { + { _T("aa"), _T("Afar") }, + { _T("ab"), _T("Abkhazian") }, + { _T("af"), _T("Afrikaans") }, + { _T("ak"), _T("Akan") }, + { _T("sq"), _T("Albanian") }, + { _T("am"), _T("Amharic") }, + { _T("ar"), _T("Arabic") }, + { _T("an"), _T("Aragonese") }, + { _T("hy"), _T("Armenian") }, + { _T("as"), _T("Assamese") }, + { _T("av"), _T("Avaric") }, + { _T("ae"), _T("Avestan") }, + { _T("ay"), _T("Aymara") }, + { _T("az"), _T("Azerbaijani") }, + { _T("ba"), _T("Bashkir") }, + { _T("bm"), _T("Bambara") }, + { _T("eu"), _T("Basque") }, + { _T("be"), _T("Belarusian") }, + { _T("bn"), _T("Bengali") }, + { _T("bh"), _T("Bihari") }, + { _T("bi"), _T("Bislama") }, + { _T("bs"), _T("Bosnian") }, + { _T("br"), _T("Breton") }, + { _T("bg"), _T("Bulgarian") }, + { _T("my"), _T("Burmese") }, + { _T("ca"), _T("Catalan; Valencian") }, + { _T("ch"), _T("Chamorro") }, + { _T("ce"), _T("Chechen") }, + { _T("zh"), _T("Chinese") }, + { _T("cu"), _T("Church Slavic; Old Slavonic") }, + { _T("cv"), _T("Chuvash") }, + { _T("kw"), _T("Cornish") }, + { _T("co"), _T("Corsican") }, + { _T("cr"), _T("Cree") }, + { _T("cs"), _T("Czech") }, + { _T("da"), _T("Danish") }, + { _T("dv"), _T("Divehi; Dhivehi; Maldivian") }, + { _T("nl"), _T("Dutch; Flemish") }, + { _T("dz"), _T("Dzongkha") }, + { _T("en"), _T("English") }, + { _T("eo"), _T("Esperanto") }, + { _T("et"), _T("Estonian") }, + { _T("ee"), _T("Ewe") }, + { _T("fo"), _T("Faroese") }, + { _T("fj"), _T("Fijian") }, + { _T("fi"), _T("Finnish") }, + { _T("fr"), _T("French") }, + { _T("fy"), _T("Western Frisian") }, + { _T("ff"), _T("Fulah") }, + { _T("ka"), _T("Georgian") }, + { _T("de"), _T("German") }, + { _T("gd"), _T("Gaelic; Scottish Gaelic") }, + { _T("ga"), _T("Irish") }, + { _T("gl"), _T("Galician") }, + { _T("gv"), _T("Manx") }, + { _T("el"), _T("Greek, Modern (1453-)") }, + { _T("gn"), _T("Guarani") }, + { _T("gu"), _T("Gujarati") }, + { _T("ht"), _T("Haitian; Haitian Creole") }, + { _T("ha"), _T("Hausa") }, + { _T("he"), _T("Hebrew") }, + { _T("hz"), _T("Herero") }, + { _T("hi"), _T("Hindi") }, + { _T("ho"), _T("Hiri Motu") }, + { _T("hu"), _T("Hungarian") }, + { _T("ig"), _T("Igbo") }, + { _T("is"), _T("Icelandic") }, + { _T("io"), _T("Ido") }, + { _T("ii"), _T("Sichuan Yi") }, + { _T("iu"), _T("Inuktitut") }, + { _T("ie"), _T("Interlingue") }, + { _T("ia"), _T("Interlingua (International Auxiliary Language Association)") }, + { _T("id"), _T("Indonesian") }, + { _T("ik"), _T("Inupiaq") }, + { _T("it"), _T("Italian") }, + { _T("jv"), _T("Javanese") }, + { _T("ja"), _T("Japanese") }, + { _T("kl"), _T("Kalaallisut; Greenlandic") }, + { _T("kn"), _T("Kannada") }, + { _T("ks"), _T("Kashmiri") }, + { _T("kr"), _T("Kanuri") }, + { _T("kk"), _T("Kazakh") }, + { _T("km"), _T("Central Khmer") }, + { _T("ki"), _T("Kikuyu; Gikuyu") }, + { _T("rw"), _T("Kinyarwanda") }, + { _T("ky"), _T("Kirghiz; Kyrgyz") }, + { _T("kv"), _T("Komi") }, + { _T("kg"), _T("Kongo") }, + { _T("ko"), _T("Korean") }, + { _T("kj"), _T("Kuanyama; Kwanyama") }, + { _T("ku"), _T("Kurdish") }, + { _T("lo"), _T("Lao") }, + { _T("la"), _T("Latin") }, + { _T("lv"), _T("Latvian") }, + { _T("li"), _T("Limburgan; Limburger; Limburgish") }, + { _T("ln"), _T("Lingala") }, + { _T("lt"), _T("Lithuanian") }, + { _T("lb"), _T("Luxembourgish; Letzeburgesch") }, + { _T("lu"), _T("Luba-Katanga") }, + { _T("lg"), _T("Ganda") }, + { _T("mk"), _T("Macedonian") }, + { _T("mh"), _T("Marshallese") }, + { _T("ml"), _T("Malayalam") }, + { _T("mi"), _T("Maori") }, + { _T("mr"), _T("Marathi") }, + { _T("ms"), _T("Malay") }, + { _T("mg"), _T("Malagasy") }, + { _T("mt"), _T("Maltese") }, + { _T("mo"), _T("Moldavian") }, + { _T("mn"), _T("Mongolian") }, + { _T("na"), _T("Nauru") }, + { _T("nv"), _T("Navajo; Navaho") }, + { _T("nr"), _T("Ndebele, South; South Ndebele") }, + { _T("nd"), _T("Ndebele, North; North Ndebele") }, + { _T("ng"), _T("Ndonga") }, + { _T("ne"), _T("Nepali") }, + { _T("nn"), _T("Norwegian Nynorsk; Nynorsk, Norwegian") }, + { _T("nb"), _T("Bokmaal, Norwegian; Norwegian Bokmaal") }, + { _T("no"), _T("Norwegian") }, + { _T("ny"), _T("Chichewa; Chewa; Nyanja") }, + { _T("oc"), _T("Occitan (post 1500); Provencal") }, + { _T("oj"), _T("Ojibwa") }, + { _T("or"), _T("Oriya") }, + { _T("om"), _T("Oromo") }, + { _T("os"), _T("Ossetian; Ossetic") }, + { _T("pa"), _T("Panjabi; Punjabi") }, + { _T("fa"), _T("Persian") }, + { _T("pi"), _T("Pali") }, + { _T("pl"), _T("Polish") }, + { _T("pt"), _T("Portuguese") }, + { _T("ps"), _T("Pushto") }, + { _T("qu"), _T("Quechua") }, + { _T("rm"), _T("Romansh") }, + { _T("ro"), _T("Romanian") }, + { _T("rn"), _T("Rundi") }, + { _T("ru"), _T("Russian") }, + { _T("sg"), _T("Sango") }, + { _T("sa"), _T("Sanskrit") }, + { _T("sr"), _T("Serbian") }, + { _T("hr"), _T("Croatian") }, + { _T("si"), _T("Sinhala; Sinhalese") }, + { _T("sk"), _T("Slovak") }, + { _T("sl"), _T("Slovenian") }, + { _T("se"), _T("Northern Sami") }, + { _T("sm"), _T("Samoan") }, + { _T("sn"), _T("Shona") }, + { _T("sd"), _T("Sindhi") }, + { _T("so"), _T("Somali") }, + { _T("st"), _T("Sotho, Southern") }, + { _T("es"), _T("Spanish; Castilian") }, + { _T("sc"), _T("Sardinian") }, + { _T("ss"), _T("Swati") }, + { _T("su"), _T("Sundanese") }, + { _T("sw"), _T("Swahili") }, + { _T("sv"), _T("Swedish") }, + { _T("ty"), _T("Tahitian") }, + { _T("ta"), _T("Tamil") }, + { _T("tt"), _T("Tatar") }, + { _T("te"), _T("Telugu") }, + { _T("tg"), _T("Tajik") }, + { _T("tl"), _T("Tagalog") }, + { _T("th"), _T("Thai") }, + { _T("bo"), _T("Tibetan") }, + { _T("ti"), _T("Tigrinya") }, + { _T("to"), _T("Tonga (Tonga Islands)") }, + { _T("tn"), _T("Tswana") }, + { _T("ts"), _T("Tsonga") }, + { _T("tk"), _T("Turkmen") }, + { _T("tr"), _T("Turkish") }, + { _T("tw"), _T("Twi") }, + { _T("ug"), _T("Uighur; Uyghur") }, + { _T("uk"), _T("Ukrainian") }, + { _T("ur"), _T("Urdu") }, + { _T("uz"), _T("Uzbek") }, + { _T("ve"), _T("Venda") }, + { _T("vi"), _T("Vietnamese") }, + { _T("vo"), _T("Volapuk") }, + { _T("cy"), _T("Welsh") }, + { _T("wa"), _T("Walloon") }, + { _T("wo"), _T("Wolof") }, + { _T("xh"), _T("Xhosa") }, + { _T("yi"), _T("Yiddish") }, + { _T("yo"), _T("Yoruba") }, + { _T("za"), _T("Zhuang; Chuang") }, + { _T("zu"), _T("Zulu") }, + { NULL, NULL } +}; + +class CJabberDlgRegister: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; +public: + CJabberDlgRegister(CJabberProto *proto, HWND hwndParent, ThreadData *regInfo): + CJabberDlgBase(proto, IDD_OPT_REGISTER, hwndParent, false), + m_bProcessStarted(false), + m_regInfo(regInfo), + m_btnOk(this, IDOK) + { + m_autoClose = CLOSE_ON_CANCEL; + m_btnOk.OnClick = Callback(this, &CJabberDlgRegister::btnOk_OnClick); + } + +protected: + void OnInitDialog() + { + TCHAR text[256]; + mir_sntprintf( text, SIZEOF(text), STR_FORMAT, TranslateT( "Register" ), m_regInfo->username, m_regInfo->server, m_regInfo->port ); + SetDlgItemText( m_hwnd, IDC_REG_STATUS, text ); + } + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + switch ( msg ) { + case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string + if (( TCHAR* )lParam == NULL ) + SetDlgItemText( m_hwnd, IDC_REG_STATUS, TranslateT( "No message" )); + else + SetDlgItemText( m_hwnd, IDC_REG_STATUS, ( TCHAR* )lParam ); + + if ( wParam >= 0 ) + SendMessage( GetDlgItem( m_hwnd, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 ); + if ( wParam >= 100 ) + m_btnOk.SetText(TranslateT("Close")); + else + SetFocus( GetDlgItem( m_hwnd, IDC_PROGRESS_REG )); + + return TRUE; + } + + return CSuper::DlgProc(msg, wParam, lParam); + } + +private: + bool m_bProcessStarted; + ThreadData *m_regInfo; + + CCtrlButton m_btnOk; + + void btnOk_OnClick(CCtrlButton *) + { + if ( m_bProcessStarted ) { + Close(); + return; + } + + ShowWindow(GetDlgItem(m_hwnd, IDC_PROGRESS_REG), SW_SHOW); + + ThreadData *thread = new ThreadData( m_regInfo->proto, JABBER_SESSION_REGISTER ); + _tcsncpy( thread->username, m_regInfo->username, SIZEOF( thread->username )); + _tcsncpy( thread->password, m_regInfo->password, SIZEOF( thread->password )); + strncpy( thread->server, m_regInfo->server, SIZEOF( thread->server )); + strncpy( thread->manualHost, m_regInfo->manualHost, SIZEOF( thread->manualHost )); + thread->port = m_regInfo->port; + thread->useSSL = m_regInfo->useSSL; + thread->reg_hwndDlg= m_hwnd; + m_proto->JForkThread(( JThreadFunc )&CJabberProto::ServerThread, thread ); + + m_btnOk.SetText(TranslateT("Cancel")); + m_bProcessStarted = true; + + m_lresult = TRUE; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberOptDlgProc - main options dialog procedure + +class CCtrlEditJid: public CCtrlEdit +{ + typedef CCtrlEdit CSuper; + +public: + CCtrlEditJid( CDlgBase* dlg, int ctrlId ); + + void OnInit() + { + CCtrlEdit::OnInit(); + Subclass(); + } + +protected: + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + if ( msg == WM_CHAR ) + { + switch( wParam ) + { + case '\"': case '&': case '\'': case '/': + case ':': case '<': case '>': case '@': + MessageBeep(MB_ICONASTERISK); + return 0; + } + } + return CCtrlEdit::CustomWndProc(msg, wParam, lParam); + } +}; + +CCtrlEditJid::CCtrlEditJid( CDlgBase* dlg, int ctrlId ): + CCtrlEdit( dlg, ctrlId ) +{ +} + +static void sttStoreJidFromUI(CJabberProto *ppro, CCtrlEdit &txtUsername, CCtrlCombo &cbServer) +{ + TCHAR *user = txtUsername.GetText(); + TCHAR *server = cbServer.GetText(); + int len = lstrlen(user) + lstrlen(server) + 2; + TCHAR *jid = (TCHAR *)mir_alloc(len * sizeof(TCHAR)); + mir_sntprintf(jid, len, _T("%s@%s"), user, server); + ppro->JSetStringT(NULL, "jid", jid); + mir_free(jid); + mir_free(server); + mir_free(user); +} + +class CDlgOptAccount: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + CCtrlEditJid m_txtUsername; + CCtrlEdit m_txtPassword; + CCtrlEdit m_txtPriority; + CCtrlCheck m_chkSavePassword; + CCtrlCombo m_cbResource; + CCtrlCheck m_chkUseHostnameAsResource; + CCtrlCheck m_chkUseDomainLogin; + CCtrlCombo m_cbServer; + CCtrlEdit m_txtPort; + CCtrlCheck m_chkUseSsl; + CCtrlCheck m_chkUseTls; + CCtrlCheck m_chkManualHost; + CCtrlEdit m_txtManualHost; + CCtrlEdit m_txtManualPort; + CCtrlCheck m_chkKeepAlive; + CCtrlCheck m_chkAutoDeleteContacts; + CCtrlEdit m_txtUserDirectory; + CCtrlCombo m_cbLocale; + CCtrlButton m_btnRegister; + CCtrlButton m_btnUnregister; + CCtrlButton m_btnChangePassword; + CCtrlHyperlink m_lnkServers; + +public: + CDlgOptAccount(CJabberProto *proto): + CJabberDlgBase(proto, IDD_OPT_JABBER, NULL, false ), + m_txtUsername(this, IDC_EDIT_USERNAME), + m_txtPassword(this, IDC_EDIT_PASSWORD), + m_txtPriority(this, IDC_PRIORITY), + m_chkSavePassword(this, IDC_SAVEPASSWORD), + m_cbResource(this, IDC_COMBO_RESOURCE), + m_chkUseHostnameAsResource(this,IDC_HOSTNAME_AS_RESOURCE), + m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), + m_cbServer(this, IDC_EDIT_LOGIN_SERVER), + m_txtPort(this, IDC_PORT), + m_chkUseSsl(this, IDC_USE_SSL), + m_chkUseTls(this, IDC_USE_TLS), + m_chkManualHost(this, IDC_MANUAL), + m_txtManualHost(this, IDC_HOST), + m_txtManualPort(this, IDC_HOSTPORT), + m_chkKeepAlive(this, IDC_KEEPALIVE), + m_chkAutoDeleteContacts(this, IDC_ROSTER_SYNC), + m_txtUserDirectory(this, IDC_JUD), + m_cbLocale(this, IDC_MSGLANG), + m_btnRegister(this, IDC_BUTTON_REGISTER), + m_btnUnregister(this, IDC_UNREGISTER), + m_btnChangePassword(this, IDC_BUTTON_CHANGE_PASSWORD), + m_lnkServers(this, IDC_LINK_PUBLIC_SERVER, "http://xmpp.org/services/") + + { + CreateLink(m_txtUsername, "LoginName", _T("")); + CreateLink(m_txtPriority, "Priority", DBVT_WORD, 0, true); + CreateLink(m_chkSavePassword, proto->m_options.SavePassword); + CreateLink(m_cbResource, "Resource", _T("Miranda")); + CreateLink(m_chkUseHostnameAsResource, proto->m_options.HostNameAsResource); + CreateLink(m_chkUseDomainLogin, proto->m_options.UseDomainLogin); + CreateLink(m_cbServer, "LoginServer", _T("jabber.org")); + CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); + CreateLink(m_chkUseSsl, proto->m_options.UseSSL); + CreateLink(m_chkUseTls, proto->m_options.UseTLS); + CreateLink(m_chkManualHost, proto->m_options.ManualConnect); + CreateLink(m_txtManualHost, "ManualHost", _T("")); + CreateLink(m_txtManualPort, "ManualPort", DBVT_WORD, 0); + CreateLink(m_chkKeepAlive, proto->m_options.KeepAlive); + CreateLink(m_chkAutoDeleteContacts, proto->m_options.RosterSync); + CreateLink(m_txtUserDirectory, "Jud", _T("")); + + // Bind events + m_cbServer.OnDropdown = Callback(this, &CDlgOptAccount::cbServer_OnDropdown); + m_chkManualHost.OnChange = Callback(this, &CDlgOptAccount::chkManualHost_OnChange); + m_chkUseHostnameAsResource.OnChange = Callback(this, &CDlgOptAccount::chkUseHostnameAsResource_OnChange); + m_chkUseDomainLogin.OnChange = Callback(this, &CDlgOptAccount::chkUseDomainLogin_OnChange); + m_chkUseSsl.OnChange = Callback(this, &CDlgOptAccount::chkUseSsl_OnChange); + m_chkUseTls.OnChange = Callback(this, &CDlgOptAccount::chkUseTls_OnChange); + + m_btnRegister.OnClick = Callback(this, &CDlgOptAccount::btnRegister_OnClick); + m_btnUnregister.OnClick = Callback(this, &CDlgOptAccount::btnUnregister_OnClick); + m_btnChangePassword.OnClick = Callback(this, &CDlgOptAccount::btnChangePassword_OnClick); + } + + static CDlgBase *Create(void *param) { return new CDlgOptAccount((CJabberProto *)param); } + +protected: + void OnInitDialog() + { + CSuper::OnInitDialog(); + + int i; + DBVARIANT dbv; + + m_gotservers = false; + + SendDlgItemMessage(m_hwnd, IDC_PRIORITY_SPIN, UDM_SETRANGE, 0, (LPARAM)MAKELONG(127, -128)); + + TCHAR *passw = m_proto->JGetStringCrypt(NULL, "LoginPassword"); + if (passw) + { + m_txtPassword.SetText(passw); + mir_free(passw); + } + + m_cbServer.AddString(TranslateT("Loading...")); + + // fill predefined resources + TCHAR* szResources[] = { _T("Home"), _T("Work"), _T("Office"), _T("Miranda") }; + for (i = 0; i < SIZEOF(szResources); ++i) + m_cbResource.AddString(szResources[i]); + + // append computer name to the resource list + TCHAR szCompName[ MAX_COMPUTERNAME_LENGTH + 1]; + DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; + if (GetComputerName(szCompName, &dwCompNameLength)) + m_cbResource.AddString(szCompName); + + if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "Resource", &dbv)) + { + if (CB_ERR == m_cbResource.FindString(dbv.ptszVal, -1, true)) + m_cbResource.AddString(dbv.ptszVal); + + m_cbResource.SetText(dbv.ptszVal); + JFreeVariant(&dbv); + } + else m_cbResource.SetText(_T("Miranda")); + + for (i = 0; g_LanguageCodes[i].szCode; ++i) + { + int iItem = m_cbLocale.AddString(TranslateTS(g_LanguageCodes[i].szDescription), (LPARAM)g_LanguageCodes[i].szCode); + if (!_tcscmp(m_proto->m_tszSelectedLang, g_LanguageCodes[i].szCode)) + m_cbLocale.SetCurSel(iItem); + } + + EnableWindow(GetDlgItem(m_hwnd, IDC_COMBO_RESOURCE ), m_chkUseHostnameAsResource.GetState() != BST_CHECKED); + EnableWindow(GetDlgItem(m_hwnd, IDC_UNREGISTER), m_proto->m_bJabberOnline); + + m_chkUseTls.Enable(!m_proto->m_options.Disable3920auth && (m_proto->m_options.UseSSL ? false : true)); + if (m_proto->m_options.Disable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); + m_chkUseSsl.Enable(m_proto->m_options.Disable3920auth || (m_proto->m_options.UseTLS ? false : true)); + + if (m_proto->m_options.ManualConnect) + { + m_txtManualHost.Enable(); + m_txtManualPort.Enable(); + m_txtPort.Disable(); + } + + if (m_proto->m_options.UseDomainLogin) + chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); + + CheckRegistration(); + + } + + void OnApply() + { + // clear saved password + *m_proto->m_savedPassword = 0; + + if (m_chkSavePassword.GetState() == BST_CHECKED) + { + TCHAR *text = m_txtPassword.GetText(); + m_proto->JSetStringCrypt(NULL, "LoginPassword", text); + mir_free(text); + } + else m_proto->JDeleteSetting(NULL, "LoginPassword"); + + int index = m_cbLocale.GetCurSel(); + if ( index >= 0 ) + { + TCHAR *szLanguageCode = (TCHAR *)m_cbLocale.GetItemData(index); + if ( szLanguageCode ) { + m_proto->JSetStringT(NULL, "XmlLang", szLanguageCode); + + mir_free( m_proto->m_tszSelectedLang ); + m_proto->m_tszSelectedLang = mir_tstrdup( szLanguageCode ); + } } + + sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); + + if (m_proto->m_bJabberOnline) + { + if (m_txtUsername.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || + m_cbServer.IsChanged() || m_chkUseHostnameAsResource.IsChanged() || m_txtPort.IsChanged() || + m_txtManualHost.IsChanged() || m_txtManualPort.IsChanged() || m_cbLocale.IsChanged()) + { + MessageBox(m_hwnd, + TranslateT("These changes will take effect the next time you connect to the Jabber network."), + TranslateT( "Jabber Protocol Option" ), MB_OK|MB_SETFOREGROUND ); + } + + m_proto->SendPresence(m_proto->m_iStatus, true); + } + } + + void OnChange(CCtrlBase*) + { + if (m_initialized) + CheckRegistration(); + } + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) + { + case WM_ACTIVATE: + m_chkUseTls.Enable(!m_proto->m_options.Disable3920auth && (m_proto->m_options.UseSSL ? false : true)); + if (m_proto->m_options.Disable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); + break; + + case WM_JABBER_REFRESH: + RefreshServers(( HXML )lParam ); + break; + } + return CSuper::DlgProc(msg, wParam, lParam); + } + +private: + bool m_gotservers; + + void btnRegister_OnClick(CCtrlButton *) + { + TCHAR buf[512] = _T(""), pass[512]; + if (!m_proto->EnterString(buf, SIZEOF(buf), TranslateT("Confirm password"), JES_PASSWORD)) + return; + + m_txtPassword.GetText(pass, SIZEOF(pass)); + if (lstrcmp(buf, pass)) + { + MessageBox(m_hwnd, TranslateT("Passwords do not match."), _T("Miranda NG"), MB_ICONSTOP|MB_OK); + return; + } + + ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); + m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); + m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); + m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); + if (m_chkManualHost.GetState() == BST_CHECKED) + { + regInfo.port = (WORD)m_txtManualPort.GetInt(); + m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); + } else + { + regInfo.port = (WORD)m_txtPort.GetInt(); + regInfo.manualHost[0] = '\0'; + } + + if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) + { + CJabberDlgRegister dlg(m_proto, m_hwnd, ®Info); + dlg.DoModal(); +// DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_OPT_REGISTER), m_hwnd, JabberRegisterDlgProc, (LPARAM)®Info); + } + } + + void btnUnregister_OnClick(CCtrlButton *) + { + int res = MessageBox(NULL, + TranslateT("This operation will kill your account, roster and all another information stored at the server. Are you ready to do that?"), + TranslateT("Account removal warning"), MB_YESNOCANCEL); + + if ( res == IDYES ) + m_proto->m_ThreadInfo->send( + XmlNodeIq( _T("set"), m_proto->SerialNext(), m_proto->m_szJabberJID ) << XQUERY( _T(JABBER_FEAT_REGISTER)) + << XCHILD( _T("remove"))); + } + + void btnChangePassword_OnClick(CCtrlButton *) + { + if ( !m_proto->m_bJabberOnline ) { + MessageBox( NULL, + TranslateT("You can change your password only when you are online"), + TranslateT("You must be online"), MB_OK | MB_ICONSTOP ); + return; + } + + m_proto->OnMenuHandleChangePassword(0, 0); + } + + void cbServer_OnDropdown(CCtrlCombo*) + { + if ( !m_gotservers ) + mir_forkthread(QueryServerListThread, this); + } + + void chkManualHost_OnChange(CCtrlData *sender) + { + CCtrlCheck *chk = (CCtrlCheck *)sender; + + if (chk->GetState() == BST_CHECKED) + { + m_txtManualHost.Enable(); + m_txtManualPort.Enable(); + m_txtPort.Disable(); + } else + { + m_txtManualHost.Disable(); + m_txtManualPort.Disable(); + m_txtPort.Enable(); + } + } + + void chkUseHostnameAsResource_OnChange(CCtrlData *sender) + { + CCtrlCheck *chk = (CCtrlCheck *)sender; + + m_cbResource.Enable(chk->GetState() != BST_CHECKED); + if (chk->GetState() == BST_CHECKED) + { + TCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; + if (GetComputerName(szCompName, &dwCompNameLength)) + m_cbResource.SetText(szCompName); + } + } + + void chkUseDomainLogin_OnChange(CCtrlData *sender) + { + CCtrlCheck *chk = (CCtrlCheck *)sender; + BOOL checked = chk->GetState() == BST_CHECKED; + + m_txtPassword.Enable(!checked); + m_txtUsername.Enable(!checked); + m_chkSavePassword.Enable(!checked); + if (checked) { + m_txtPassword.SetText(_T("")); + m_txtUsername.SetText(_T("")); + m_chkSavePassword.SetState(BST_CHECKED); + } + } + + void chkUseSsl_OnChange(CCtrlData*) + { + BOOL bManualHost = m_chkManualHost.GetState() == BST_CHECKED; + if (m_chkUseSsl.GetState() == BST_CHECKED) + { + m_chkUseTls.Disable(); + if (!bManualHost) + m_txtPort.SetInt(5223); + } else + { + if (!m_proto->m_options.Disable3920auth) m_chkUseTls.Enable(); + if (!bManualHost) + m_txtPort.SetInt(5222); + } + } + + void chkUseTls_OnChange(CCtrlData*) + { + if (m_chkUseTls.GetState() == BST_CHECKED) + m_chkUseSsl.Disable(); + else + m_chkUseSsl.Enable(); + } + + void CheckRegistration() + { + ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); + m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); + m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); + m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); + if (m_chkManualHost.GetState() == BST_CHECKED) + { + regInfo.port = (WORD)m_txtManualPort.GetInt(); + m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); + } else + { + regInfo.port = (WORD)m_txtPort.GetInt(); + regInfo.manualHost[0] = '\0'; + } + + if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) + EnableWindow( GetDlgItem( m_hwnd, IDC_BUTTON_REGISTER ), TRUE ); + else + EnableWindow( GetDlgItem( m_hwnd, IDC_BUTTON_REGISTER ), FALSE ); + } + + void RefreshServers( HXML node ) + { + m_gotservers = node != NULL; + + TCHAR *server = m_cbServer.GetText(); + bool bDropdown = m_cbServer.GetDroppedState(); + if (bDropdown) m_cbServer.ShowDropdown(false); + + m_cbServer.ResetContent(); + if ( node ) { + for (int i = 0; ; ++i) { + HXML n = xmlGetChild(node, i); + if ( !n ) + break; + + if ( !lstrcmp( xmlGetName( n ), _T("item"))) + if ( const TCHAR *jid = xmlGetAttrValue( n, _T("jid"))) + if ( m_cbServer.FindString(jid, -1, true) == CB_ERR) + m_cbServer.AddString(jid); + } + } + + m_cbServer.SetText(server); + + if (bDropdown) m_cbServer.ShowDropdown(); + mir_free(server); + } + + static void QueryServerListThread(void *arg) + { + CDlgOptAccount *wnd = (CDlgOptAccount *)arg; + HWND hwnd = wnd->GetHwnd(); + bool bIsError = true; + + if (!IsWindow(hwnd)) return; + + NETLIBHTTPREQUEST request = {0}; + request.cbSize = sizeof(request); + request.requestType = REQUEST_GET; + request.flags = NLHRF_REDIRECT | NLHRF_HTTP11; + request.szUrl = "http://xmpp.org/services/services.xml"; + + NETLIBHTTPREQUEST *result = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)wnd->GetProto()->m_hNetlibUser, (LPARAM)&request); + if ( result ) { + if ( result->resultCode == 200 && result->dataLength && result->pData ) { + TCHAR* buf = mir_a2t( result->pData ); + XmlNode node( buf, NULL, NULL ); + if ( node ) { + HXML queryNode = xmlGetChild( node, _T("query")); + SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); + bIsError = false; + } + mir_free( buf ); + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)result); + } + + if ( bIsError ) + SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)NULL); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberAdvOptDlgProc - advanced options dialog procedure + +class CDlgOptAdvanced: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + CCtrlCheck m_chkDirect; + CCtrlCheck m_chkDirectManual; + CCtrlCheck m_chkProxy; + CCtrlEdit m_txtDirect; + CCtrlEdit m_txtProxy; + CCtrlTreeOpts m_otvOptions; + +public: + CDlgOptAdvanced(CJabberProto *proto): + CJabberDlgBase(proto, IDD_OPT_JABBER2, NULL, false), + m_chkDirect(this, IDC_DIRECT), + m_chkDirectManual(this, IDC_DIRECT_MANUAL), + m_chkProxy(this, IDC_PROXY_MANUAL), + m_txtDirect(this, IDC_DIRECT_ADDR), + m_txtProxy(this, IDC_PROXY_ADDR), + m_otvOptions(this, IDC_OPTTREE) + { + CreateLink(m_chkDirect, proto->m_options.BsDirect); + CreateLink(m_chkDirectManual, proto->m_options.BsDirectManual); + CreateLink(m_chkProxy, proto->m_options.BsProxyManual); + CreateLink(m_txtDirect, "BsDirectAddr", _T("")); + CreateLink(m_txtProxy, "BsProxyServer", _T("")); + + m_chkDirect.OnChange = + m_chkDirectManual.OnChange = Callback(this, &CDlgOptAdvanced::chkDirect_OnChange); + m_chkProxy.OnChange = Callback(this, &CDlgOptAdvanced::chkProxy_OnChange); + + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Send messages slower, but with full acknowledgement"), m_proto->m_options.MsgAck); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable avatars"), m_proto->m_options.EnableAvatars); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log chat state changes"), m_proto->m_options.LogChatstates); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log presence subscription state changes"), m_proto->m_options.LogPresence); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Log presence errors"), m_proto->m_options.LogPresenceErrors); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user moods receiving"), m_proto->m_options.EnableUserMood); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user tunes receiving"), m_proto->m_options.EnableUserTune); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user activity receiving"), m_proto->m_options.EnableUserActivity); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Receive notes"), m_proto->m_options.AcceptNotes); + m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Automatically save received notes"), m_proto->m_options.AutosaveNotes); + + m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Disable SASL authentication (for old servers)"), m_proto->m_options.Disable3920auth); + m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Enable stream compression (if possible)"), m_proto->m_options.EnableZlib); + + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Enable remote controlling (from another resource of same JID only)"), m_proto->m_options.EnableRemoteControl); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Show transport agents on contact list"), m_proto->m_options.ShowTransport); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Automatically add contact when accept authorization"), m_proto->m_options.AutoAdd); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Automatically accept authorization requests"), m_proto->m_options.AutoAcceptAuthorization); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Fix incorrect timestamps in incoming messages"), m_proto->m_options.FixIncorrectTimestamps); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Disable frame"), m_proto->m_options.DisableFrame); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Enable XMPP link processing (requires Association Manager)"), m_proto->m_options.ProcessXMPPLinks); + m_otvOptions.AddOption(LPGENT("Other") _T("/") LPGENT("Keep contacts assigned to local groups (ignore roster group)"), m_proto->m_options.IgnoreRosterGroups); + + m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Allow servers to request version (XEP-0092)"), m_proto->m_options.AllowVersionRequests); + m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Show information about operating system in version replies"), m_proto->m_options.ShowOSVersion); + m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Accept only in band incoming filetransfers (don't disclose own IP)"), m_proto->m_options.BsOnlyIBB); + m_otvOptions.AddOption(LPGENT("Security") _T("/") LPGENT("Accept HTTP Authentication requests (XEP-0070)"), m_proto->m_options.AcceptHttpAuth); + } + + void OnInitDialog() + { + CSuper::OnInitDialog(); + + chkDirect_OnChange(&m_chkDirect); + chkProxy_OnChange(&m_chkProxy); + } + + void OnApply() + { + BOOL bChecked = m_proto->m_options.ShowTransport; + LISTFOREACH(index, m_proto, LIST_ROSTER) + { + JABBER_LIST_ITEM* item = m_proto->ListGetItemPtrFromIndex( index ); + if ( item != NULL ) { + if ( _tcschr( item->jid, '@' ) == NULL ) { + HANDLE hContact = m_proto->HContactFromJID( item->jid ); + if ( hContact != NULL ) { + if ( bChecked ) { + if ( item->itemResource.status != m_proto->JGetWord( hContact, "Status", ID_STATUS_OFFLINE )) { + m_proto->JSetWord( hContact, "Status", ( WORD )item->itemResource.status ); + } } + else if ( m_proto->JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) + m_proto->JSetWord( hContact, "Status", ID_STATUS_OFFLINE ); + } } } + } + + m_proto->SendPresence( m_proto->m_iStatus, true ); + } + + void chkDirect_OnChange(CCtrlData *) + { + if (m_chkDirect.GetState() == BST_CHECKED) + { + if (m_chkDirectManual.GetState() == BST_CHECKED) + m_txtDirect.Enable(); + else + m_txtDirect.Disable(); + + m_chkDirectManual.Enable(); + } else + { + m_txtDirect.Disable(); + m_chkDirectManual.Disable(); + } + } + + void chkProxy_OnChange(CCtrlData *) + { + if (m_chkProxy.GetState() == BST_CHECKED) + m_txtProxy.Enable(); + else + m_txtProxy.Disable(); + } + + static CDlgBase *Create(void *param) { return new CDlgOptAdvanced((CJabberProto *)param); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGcOptDlgProc - chat options dialog procedure + +class CDlgOptGc: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + CCtrlEdit m_txtAltNick; + CCtrlEdit m_txtSlap; + CCtrlEdit m_txtQuit; + CCtrlTreeOpts m_otvOptions; + +public: + CDlgOptGc(CJabberProto *proto): + CJabberDlgBase(proto, IDD_OPT_JABBER4, NULL, false), + m_txtAltNick(this, IDC_TXT_ALTNICK), + m_txtSlap(this, IDC_TXT_SLAP), + m_txtQuit(this, IDC_TXT_QUIT), + m_otvOptions(this, IDC_OPTTREE) + { + CreateLink(m_txtAltNick, "GcAltNick", _T("")); + CreateLink(m_txtSlap, "GcMsgSlap", TranslateTS(JABBER_GC_MSG_SLAP)); + CreateLink(m_txtQuit, "GcMsgQuit", TranslateTS(JABBER_GC_MSG_QUIT)); + + m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Autoaccept multiuser chat invitations"), m_proto->m_options.AutoAcceptMUC); + m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Automatically join bookmarks on login"), m_proto->m_options.AutoJoinBookmarks); + m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Automatically join conferences on login"), m_proto->m_options.AutoJoinConferences); + m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Hide conference windows at startup"), m_proto->m_options.AutoJoinHidden); + m_otvOptions.AddOption(LPGENT("General") _T("/") LPGENT("Do not show multiuser chat invitations"), m_proto->m_options.IgnoreMUCInvites); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Ban notifications"), m_proto->m_options.GcLogBans); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Room configuration changes"), m_proto->m_options.GcLogConfig); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Affiliation changes"), m_proto->m_options.GcLogAffiliations); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Role changes"), m_proto->m_options.GcLogRoles); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Status changes"), m_proto->m_options.GcLogStatuses); + m_otvOptions.AddOption(LPGENT("Log events") _T("/") LPGENT("Filter history messages"), m_proto->m_options.GcLogChatHistory); + } + + static CDlgBase *Create(void *param) { return new CDlgOptGc((CJabberProto *)param); } +}; + +////////////////////////////////////////////////////////////////////////// +// roster editor +// + +#include <io.h> +#define JM_STATUSCHANGED WM_USER+0x0001 +#define fopent(name, mode) _wfopen(name, mode) + +enum { + RRA_FILLLIST = 0, + RRA_SYNCROSTER, + RRA_SYNCDONE +}; + +typedef struct _tag_RosterhEditDat{ + WNDPROC OldEditProc; + HWND hList; + int index; + int subindex; +} ROSTEREDITDAT; + +static WNDPROC _RosterOldListProc=NULL; + +static int _RosterInsertListItem(HWND hList, const TCHAR * jid, const TCHAR * nick, const TCHAR * group, const TCHAR * subscr, BOOL bChecked) +{ + LVITEM item={0}; + int index; + item.mask=LVIF_TEXT|LVIF_STATE; + + item.iItem = ListView_GetItemCount(hList); + item.iSubItem = 0; + item.pszText = ( TCHAR* )jid; + + index=ListView_InsertItem(hList, &item); + + if ( index<0 ) + return index; + + ListView_SetCheckState(hList, index, bChecked); + + ListView_SetItemText(hList, index, 0, ( TCHAR* )jid); + ListView_SetItemText(hList, index, 1, ( TCHAR* )nick); + ListView_SetItemText(hList, index, 2, ( TCHAR* )group); + ListView_SetItemText(hList, index, 3, TranslateTS( subscr )); + + return index; +} + +static void _RosterListClear(HWND hwndDlg) +{ + HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); + if (!hList) return; + ListView_DeleteAllItems(hList); + while ( ListView_DeleteColumn( hList, 0)); + + LV_COLUMN column={0}; + column.mask=LVCF_TEXT; + column.cx=500; + + column.pszText=TranslateT("JID"); + ListView_InsertColumn(hList, 1, &column); + + column.pszText=TranslateT("Nick Name"); + ListView_InsertColumn(hList, 2, &column); + + column.pszText=TranslateT("Group"); + ListView_InsertColumn(hList, 3, &column); + + column.pszText=TranslateT("Subscription"); + ListView_InsertColumn(hList, 4, &column); + + RECT rc; + GetClientRect(hList, &rc); + int width=rc.right-rc.left; + + ListView_SetColumnWidth(hList,0,width*40/100); + ListView_SetColumnWidth(hList,1,width*25/100); + ListView_SetColumnWidth(hList,2,width*20/100); + ListView_SetColumnWidth(hList,3,width*10/100); +} + +void CJabberProto::_RosterHandleGetRequest( HXML node ) +{ + HWND hList=GetDlgItem(rrud.hwndDlg, IDC_ROSTER); + if (rrud.bRRAction==RRA_FILLLIST) + { + _RosterListClear(rrud.hwndDlg); + HXML query = xmlGetChild( node , "query"); + if (!query) return; + int i = 1; + while (TRUE) { + HXML item = xmlGetNthChild( query, _T("item"), i++); + if (!item) + break; + + const TCHAR *jid = xmlGetAttrValue( item, _T("jid")); + if (!jid) + continue; + + const TCHAR *name = xmlGetAttrValue( item, _T("name")); + const TCHAR *subscription = xmlGetAttrValue( item, _T("subscription")); + const TCHAR *group = NULL; + HXML groupNode = xmlGetChild( item , "group" ); + if ( groupNode ) + group = xmlGetText( groupNode ); + _RosterInsertListItem( hList, jid, name, group, subscription, TRUE ); + } + // now it is require to process whole contact list to add not in roster contacts + { + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) + { + char* str = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( str != NULL && !strcmp( str, m_szModuleName )) + { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) + { + LVFINDINFO lvfi={0}; + lvfi.flags = LVFI_STRING; + lvfi.psz = dbv.ptszVal; + TCHAR *p = _tcschr(dbv.ptszVal,_T('@')); + if ( p ) { + p = _tcschr( dbv.ptszVal, _T('/')); + if ( p ) *p = _T('\0'); + } + if ( ListView_FindItem(hList, -1, &lvfi) == -1) { + TCHAR *jid = mir_tstrdup( dbv.ptszVal ); + TCHAR *name = NULL; + TCHAR *group = NULL; + DBVARIANT dbvtemp; + if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbvtemp )) { + name = mir_tstrdup( dbvtemp.ptszVal ); + DBFreeVariant( &dbvtemp ); + } + if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbvtemp )) { + group = mir_tstrdup( dbvtemp.ptszVal ); + DBFreeVariant( &dbvtemp ); + } + _RosterInsertListItem( hList, jid, name, group, NULL, FALSE ); + if ( jid ) mir_free( jid ); + if ( name ) mir_free( name ); + if ( group ) mir_free( group ); + } + DBFreeVariant( &dbv ); + } + } + hContact = db_find_next(hContact); + } + } + rrud.bReadyToDownload = FALSE; + rrud.bReadyToUpload = TRUE; + SetDlgItemText( rrud.hwndDlg, IDC_DOWNLOAD, TranslateT( "Download" )); + SetDlgItemText( rrud.hwndDlg, IDC_UPLOAD, TranslateT( "Upload" )); + SendMessage( rrud.hwndDlg, JM_STATUSCHANGED, 0, 0 ); + return; + } + else if ( rrud.bRRAction == RRA_SYNCROSTER ) + { + SetDlgItemText(rrud.hwndDlg, IDC_UPLOAD, TranslateT("Uploading...")); + HXML queryRoster = xmlGetChild( node , "query"); + if (!queryRoster) + return; + + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::_RosterHandleGetRequest ); + + XmlNode iq( _T("iq")); + xmlAddAttr( iq, _T("type"), _T("set")); + iq << XATTRID( iqId ); + + HXML query = iq << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER)); + + int itemCount=0; + int ListItemCount=ListView_GetItemCount(hList); + for (int index=0; index<ListItemCount; index++) + { + TCHAR jid[JABBER_MAX_JID_LEN]=_T(""); + TCHAR name[260]=_T(""); + TCHAR group[260]=_T(""); + TCHAR subscr[260]=_T(""); + ListView_GetItemText(hList, index, 0, jid, SIZEOF(jid)); + ListView_GetItemText(hList, index, 1, name, SIZEOF(name)); + ListView_GetItemText(hList, index, 2, group, SIZEOF(group)); + ListView_GetItemText(hList, index, 3, subscr, SIZEOF(subscr)); + HXML itemRoster = xmlGetChildByTag( queryRoster, "item", "jid", jid); + BOOL bRemove = !ListView_GetCheckState(hList,index); + if (itemRoster && bRemove) + { + //delete item + query << XCHILD( _T("item")) << XATTR( _T("jid"), jid ) << XATTR( _T("subscription") ,_T("remove")); + itemCount++; + } + else if ( !bRemove ) + { + BOOL bPushed = itemRoster ? TRUE : FALSE; + if ( !bPushed ) { + const TCHAR *rosterName = xmlGetAttrValue( itemRoster, _T("name")); + if ( (rosterName!=NULL || name[0]!=_T('\0')) && lstrcmpi(rosterName,name)) + bPushed=TRUE; + if ( !bPushed ) { + rosterName = xmlGetAttrValue( itemRoster, _T("subscription")); + if ((rosterName!=NULL || subscr[0]!=_T('\0')) && lstrcmpi(rosterName,subscr)) + bPushed=TRUE; + } + if ( !bPushed ) { + HXML groupNode = xmlGetChild( itemRoster , "group" ); + const TCHAR* rosterGroup=NULL; + if (groupNode != NULL) + rosterGroup = xmlGetText( groupNode ); + if ((rosterGroup!=NULL || group[0]!=_T('\0')) && lstrcmpi(rosterGroup,group)) + bPushed=TRUE; + } + } + if ( bPushed ) { + HXML item = query << XCHILD( _T("item")); + if ( group && _tcslen( group )) + item << XCHILD( _T("group"), group ); + if ( name && _tcslen( name )) + item << XATTR( _T("name"), name ); + item << XATTR( _T("jid"), jid ) << XATTR( _T("subscription"), subscr[0] ? subscr : _T("none")); + itemCount++; + } + } + } + rrud.bRRAction=RRA_SYNCDONE; + if (itemCount) + m_ThreadInfo->send( iq ); + else + _RosterSendRequest(rrud.hwndDlg,RRA_FILLLIST); + } + else + { + SetDlgItemText(rrud.hwndDlg,IDC_UPLOAD,TranslateT("Upload")); + rrud.bReadyToUpload=FALSE; + rrud.bReadyToDownload=FALSE; + SendMessage(rrud.hwndDlg, JM_STATUSCHANGED,0,0); + SetDlgItemText(rrud.hwndDlg,IDC_DOWNLOAD,TranslateT("Downloading...")); + _RosterSendRequest(rrud.hwndDlg,RRA_FILLLIST); + + } +} + +void CJabberProto::_RosterSendRequest(HWND hwndDlg, BYTE rrAction) +{ + rrud.bRRAction=rrAction; + rrud.hwndDlg=hwndDlg; + + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::_RosterHandleGetRequest ); + m_ThreadInfo->send( XmlNode( _T("iq")) << XATTR( _T("type"), _T("get")) << XATTRID( iqId ) << XCHILDNS( _T("query"), _T(JABBER_FEAT_IQ_ROSTER ))); +} + +static void _RosterItemEditEnd( HWND hEditor, ROSTEREDITDAT * edat, BOOL bCancel ) +{ + if (!bCancel) + { + int len = GetWindowTextLength(hEditor) + 1; + TCHAR *buff=(TCHAR*)mir_alloc(len*sizeof(TCHAR)); + if ( buff ) { + GetWindowText(hEditor,buff,len); + ListView_SetItemText(edat->hList,edat->index, edat->subindex,buff); + } + mir_free(buff); + } + DestroyWindow(hEditor); +} + +static BOOL CALLBACK _RosterItemNewEditProc( HWND hEditor, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + ROSTEREDITDAT * edat = (ROSTEREDITDAT *) GetWindowLongPtr(hEditor,GWLP_USERDATA); + if (!edat) return 0; + switch(msg) + { + + case WM_KEYDOWN: + switch(wParam) + { + case VK_RETURN: + _RosterItemEditEnd(hEditor, edat, FALSE); + return 0; + case VK_ESCAPE: + _RosterItemEditEnd(hEditor, edat, TRUE); + return 0; + } + break; + case WM_GETDLGCODE: + if ( lParam ) { + MSG *msg2 = (MSG*)lParam; + if (msg2->message==WM_KEYDOWN && msg2->wParam==VK_TAB) return 0; + if (msg2->message==WM_CHAR && msg2->wParam=='\t') return 0; + } + return DLGC_WANTMESSAGE; + case WM_KILLFOCUS: + _RosterItemEditEnd(hEditor, edat, FALSE); + return 0; + } + + if (msg==WM_DESTROY) + { + SetWindowLongPtr(hEditor, GWLP_WNDPROC, (LONG_PTR) edat->OldEditProc); + SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR) 0); + free(edat); + return 0; + } + else return CallWindowProc( edat->OldEditProc, hEditor, msg, wParam, lParam); +} + + + +void CJabberProto::_RosterExportToFile(HWND hwndDlg) +{ + TCHAR filename[MAX_PATH]={0}; + + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.xml)%c*.xml%c%c"), TranslateT("XML for MS Excel (UTF-8 encoded)"), 0, 0, 0); + OPENFILENAME ofn={0}; + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + ofn.lpstrFilter = filter; + ofn.lpstrFile = filename; + ofn.Flags = OFN_HIDEREADONLY; + ofn.nMaxFile = SIZEOF(filename); + ofn.nMaxFileTitle = MAX_PATH; + ofn.lpstrDefExt = _T("xml"); + if (!GetSaveFileName(&ofn)) return; + + FILE * fp = fopent(filename,_T("w")); + if (!fp) return; + HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); + int ListItemCount=ListView_GetItemCount(hList); + + XmlNode root(_T("Workbook")); + root << XATTR(_T("xmlns"), _T("urn:schemas-microsoft-com:office:spreadsheet")) + << XATTR(_T("xmlns:o"), _T("urn:schemas-microsoft-com:office:office")) + << XATTR(_T("xmlns:x"), _T("urn:schemas-microsoft-com:office:excel")) + << XATTR(_T("xmlns:ss"), _T("urn:schemas-microsoft-com:office:spreadsheet")) + << XATTR(_T("xmlns:html"), _T("http://www.w3.org/TR/REC-html40")); + root << XCHILD(_T("ExcelWorkbook")) + << XATTR(_T("xmlns"), _T("urn:schemas-microsoft-com:office:excel")); + HXML table = root << XCHILD(_T("Worksheet")) << XATTR(_T("ss:Name"), _T("Exported roster")) + << XCHILD(_T("Table")); + + for (int index=0; index<ListItemCount; index++) + { + TCHAR jid[JABBER_MAX_JID_LEN]=_T(""); + TCHAR name[260]=_T(""); + TCHAR group[260]=_T(""); + TCHAR subscr[260]=_T(""); + ListView_GetItemText(hList, index, 0, jid, SIZEOF(jid)); + ListView_GetItemText(hList, index, 1, name, SIZEOF(name)); + ListView_GetItemText(hList, index, 2, group, SIZEOF(group)); + ListView_GetItemText(hList, index, 3, subscr, SIZEOF(subscr)); + + HXML node = table << XCHILD(_T("Row")); + node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), _T("+")) << XATTR(_T("ss:Type"), _T("String")); + node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), jid) << XATTR(_T("ss:Type"), _T("String")); + node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), name) << XATTR(_T("ss:Type"), _T("String")); + node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), group) << XATTR(_T("ss:Type"), _T("String")); + node << XCHILD(_T("Cell")) << XCHILD(_T("Data"), subscr) << XATTR(_T("ss:Type"), _T("String")); + + } + + char header[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n"; + fwrite(header, 1, sizeof(header) - 1 /* for zero terminator */, fp); + + TCHAR *xtmp = xi.toString(root, NULL); + char *tmp = mir_utf8encodeT(xtmp); + xi.freeMem(xtmp); + + fwrite(tmp, 1, strlen(tmp), fp); + mir_free(tmp); + fclose(fp); +} + +void CJabberProto::_RosterImportFromFile(HWND hwndDlg) +{ + char filename[MAX_PATH]={0}; + char *filter="XML for MS Excel (UTF-8 encoded)(*.xml)\0*.xml\0\0"; + OPENFILENAMEA ofn={0}; + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + ofn.lpstrFilter = filter; + ofn.lpstrFile = filename; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.nMaxFile = sizeof(filename); + ofn.nMaxFileTitle = MAX_PATH; + ofn.lpstrDefExt = "xml"; + if ( !GetOpenFileNameA( &ofn )) + return; + + FILE * fp=fopen(filename,"r"); + if (!fp) + return; + + DWORD bufsize = _filelength(_fileno(fp)); + if (bufsize <= 0) { + fclose(fp); + return; + } + + char* buffer=(char*)mir_calloc(bufsize+1); // zero-terminate it + fread(buffer,1,bufsize,fp); + fclose(fp); + _RosterListClear(hwndDlg); + + TCHAR* newBuf = mir_utf8decodeT( buffer ); + mir_free( buffer ); + + int nBytesProcessed = 0; + XmlNode node( newBuf, &nBytesProcessed, NULL ); + if ( node ) { + HXML Workbook = xmlGetChild( node, _T("Workbook")); + if ( Workbook ) { + HXML Worksheet = xmlGetChild( Workbook , "Worksheet"); + if ( Worksheet ) { + HXML Table = xmlGetChild( Worksheet , "Table" ); + if ( Table ) { + int index=1; + HWND hList=GetDlgItem(hwndDlg, IDC_ROSTER); + while (TRUE) + { + HXML Row = xmlGetNthChild( Table, _T("Row"), index++ ); + if (!Row) + break; + + BOOL bAdd=FALSE; + const TCHAR* jid=NULL; + const TCHAR* name=NULL; + const TCHAR* group=NULL; + const TCHAR* subscr=NULL; + HXML Cell = xmlGetNthChild( Row, _T("Cell"), 1 ); + HXML Data = (Cell) ? xmlGetChild( Cell , "Data") : XmlNode(); + if ( Data ) + { + if (!lstrcmpi(xmlGetText( Data ),_T("+"))) bAdd=TRUE; + else if (lstrcmpi(xmlGetText( Data ),_T("-"))) continue; + + Cell = xmlGetNthChild( Row, _T("Cell"),2); + if (Cell) Data=xmlGetChild( Cell , "Data"); + else Data = NULL; + if (Data) + { + jid=xmlGetText( Data ); + if (!jid || lstrlen(jid)==0) continue; + } + + Cell=xmlGetNthChild( Row,_T("Cell"),3); + if (Cell) Data=xmlGetChild( Cell , "Data"); + else Data = NULL; + if (Data) name=xmlGetText( Data ); + + Cell=xmlGetNthChild( Row,_T("Cell"),4); + if (Cell) Data=xmlGetChild( Cell , "Data"); + else Data = NULL; + if (Data) group=xmlGetText( Data ); + + Cell=xmlGetNthChild( Row,_T("Cell"),5); + if (Cell) Data=xmlGetChild( Cell , "Data"); + else Data = NULL; + if (Data) subscr=xmlGetText( Data ); + } + _RosterInsertListItem(hList,jid,name,group,subscr,bAdd); + } } } } } + + mir_free( newBuf ); + SendMessage(hwndDlg, JM_STATUSCHANGED, 0, 0); +} + +static BOOL CALLBACK _RosterNewListProc( HWND hList, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if (msg==WM_MOUSEWHEEL || msg==WM_NCLBUTTONDOWN || msg==WM_NCRBUTTONDOWN) + { + SetFocus(hList); + } + + if (msg==WM_LBUTTONDOWN) + { + POINT pt; + GetCursorPos(&pt); + ScreenToClient(hList, &pt); + + LVHITTESTINFO lvhti={0}; + lvhti.pt=pt; + ListView_SubItemHitTest(hList,&lvhti); + if (lvhti.flags&LVHT_ONITEM && lvhti.iSubItem !=0) + { + RECT rc; + TCHAR buff[260]; + ListView_GetSubItemRect(hList, lvhti.iItem, lvhti.iSubItem, LVIR_BOUNDS,&rc); + ListView_GetItemText(hList, lvhti.iItem, lvhti.iSubItem, buff, SIZEOF(buff)); + HWND hEditor=CreateWindow(TEXT("EDIT"),buff,WS_CHILD|ES_AUTOHSCROLL,rc.left+3, rc.top+2, rc.right-rc.left-3, rc.bottom - rc.top-3,hList, NULL, hInst, NULL); + SendMessage(hEditor,WM_SETFONT,(WPARAM)SendMessage(hList,WM_GETFONT,0,0),0); + ShowWindow(hEditor,SW_SHOW); + SetWindowText(hEditor, buff); + ClientToScreen(hList, &pt); + ScreenToClient(hEditor, &pt); + mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + + ROSTEREDITDAT * edat=(ROSTEREDITDAT *)malloc(sizeof(ROSTEREDITDAT)); + edat->OldEditProc=(WNDPROC)GetWindowLongPtr(hEditor, GWLP_WNDPROC); + SetWindowLongPtr(hEditor,GWLP_WNDPROC,(LONG_PTR)_RosterItemNewEditProc); + edat->hList=hList; + edat->index=lvhti.iItem; + edat->subindex=lvhti.iSubItem; + SetWindowLongPtr(hEditor,GWLP_USERDATA,(LONG_PTR)edat); + } + } + return CallWindowProc(_RosterOldListProc, hList, msg, wParam, lParam ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberRosterOptDlgProc - advanced options dialog procedure + +static int sttRosterEditorResizer(HWND /*hwndDlg*/, LPARAM, UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_HEADERBAR: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH; + case IDC_ROSTER: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT|RD_ANCHORX_WIDTH; + case IDC_DOWNLOAD: + case IDC_UPLOAD: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + case IDC_EXPORT: + case IDC_IMPORT: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; +// case IDC_STATUSBAR: +// return RD_ANCHORX_LEFT|RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +static INT_PTR CALLBACK JabberRosterOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case JM_STATUSCHANGED: + { + int count = ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_ROSTER)); + EnableWindow( GetDlgItem( hwndDlg, IDC_DOWNLOAD ), ppro->m_bJabberOnline ); + EnableWindow( GetDlgItem( hwndDlg, IDC_UPLOAD ), count && ppro->m_bJabberOnline ); + EnableWindow( GetDlgItem( hwndDlg, IDC_EXPORT ), count > 0); + break; + } + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + break; + } + case WM_DESTROY: + { + Utils_SaveWindowPosition(hwndDlg, NULL, ppro->m_szModuleName, "rosterCtrlWnd_"); + ppro->rrud.hwndDlg = NULL; + WindowFreeIcon(hwndDlg); + break; + } + case WM_INITDIALOG: + { + ppro = ( CJabberProto* )lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + TranslateDialogDefault( hwndDlg ); + WindowSetIcon( hwndDlg, ppro, "Agents" ); + + Utils_RestoreWindowPosition(hwndDlg, NULL, ppro->m_szModuleName, "rosterCtrlWnd_"); + + ListView_SetExtendedListViewStyle(GetDlgItem(hwndDlg,IDC_ROSTER), LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT /*| LVS_EX_FULLROWSELECT*/ | LVS_EX_GRIDLINES /*| LVS_EX_HEADERDRAGDROP*/ ); + _RosterOldListProc=(WNDPROC) GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_ROSTER), GWLP_WNDPROC); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_ROSTER), GWLP_WNDPROC, (LONG_PTR) _RosterNewListProc); + _RosterListClear(hwndDlg); + ppro->rrud.hwndDlg = hwndDlg; + ppro->rrud.bReadyToDownload = TRUE; + ppro->rrud.bReadyToUpload = FALSE; + SendMessage( hwndDlg, JM_STATUSCHANGED, 0, 0 ); + + return TRUE; + } + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 550; + lpmmi->ptMinTrackSize.y = 390; + return 0; + } + case WM_SIZE: + { + UTILRESIZEDIALOG urd = {0}; + urd.cbSize = sizeof(urd); + urd.hInstance = hInst; + urd.hwndDlg = hwndDlg; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER3); + urd.pfnResizer = sttRosterEditorResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + break; + } + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDC_DOWNLOAD: + ppro->rrud.bReadyToUpload = FALSE; + ppro->rrud.bReadyToDownload = FALSE; + SendMessage( ppro->rrud.hwndDlg, JM_STATUSCHANGED,0,0); + SetDlgItemText( ppro->rrud.hwndDlg, IDC_DOWNLOAD, TranslateT("Downloading...")); + ppro->_RosterSendRequest(hwndDlg, RRA_FILLLIST); + break; + + case IDC_UPLOAD: + ppro->rrud.bReadyToUpload = FALSE; + SendMessage( ppro->rrud.hwndDlg, JM_STATUSCHANGED, 0, 0 ); + SetDlgItemText( ppro->rrud.hwndDlg, IDC_UPLOAD, TranslateT("Connecting...")); + ppro->_RosterSendRequest( hwndDlg, RRA_SYNCROSTER ); + break; + + case IDC_EXPORT: + ppro->_RosterExportToFile( hwndDlg ); + break; + + case IDC_IMPORT: + ppro->_RosterImportFromFile( hwndDlg ); + break; + } + break; + } + return FALSE; +} + +INT_PTR __cdecl CJabberProto::OnMenuHandleRosterControl( WPARAM, LPARAM ) +{ + if ( rrud.hwndDlg && IsWindow( rrud.hwndDlg )) + SetForegroundWindow( rrud.hwndDlg ); + else + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_OPT_JABBER3 ), NULL, JabberRosterOptDlgProc, ( LPARAM )this ); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberOptInit - initializes all options dialogs + +int CJabberProto::OnOptionsInit( WPARAM wParam, LPARAM ) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof( odp ); + odp.hInstance = hInst; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTitle = m_tszUserName; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; + + odp.ptszTab = LPGENT("Account"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER); + odp.pfnDlgProc = CDlgBase::DynamicDlgProc; + odp.dwInitParam = (LPARAM)&OptCreateAccount; + OptCreateAccount.create = CDlgOptAccount::Create; + OptCreateAccount.param = this; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Conferences"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_JABBER4); + odp.pfnDlgProc = CDlgBase::DynamicDlgProc; + odp.dwInitParam = (LPARAM)&OptCreateGc; + OptCreateGc.create = CDlgOptGc::Create; + OptCreateGc.param = this; + Options_AddPage(wParam, &odp); + + odp.flags |= ODPF_EXPERTONLY; + + odp.ptszTab = LPGENT("Advanced"); + odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_JABBER2 ); + odp.pfnDlgProc = CDlgBase::DynamicDlgProc; + odp.dwInitParam = (LPARAM)&OptCreateAdvanced; + OptCreateAdvanced.create = CDlgOptAdvanced::Create; + OptCreateAdvanced.param = this; + Options_AddPage(wParam, &odp); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// Account manager UI + +class CJabberDlgAccMgrUI: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + CCtrlCombo m_cbType; + CCtrlEditJid m_txtUsername; + CCtrlCombo m_cbServer; + CCtrlEdit m_txtPassword; + CCtrlCheck m_chkSavePassword; + CCtrlCheck m_chkUseDomainLogin; + CCtrlCombo m_cbResource; + CCtrlCheck m_chkManualHost; + CCtrlEdit m_txtManualHost; + CCtrlEdit m_txtPort; + CCtrlButton m_btnRegister; + +public: + CJabberDlgAccMgrUI(CJabberProto *proto, HWND hwndParent): + CJabberDlgBase(proto, IDD_ACCMGRUI, hwndParent, false), + m_cbType(this, IDC_CB_TYPE), + m_txtUsername(this, IDC_EDIT_USERNAME), + m_txtPassword(this, IDC_EDIT_PASSWORD), + m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), + m_chkSavePassword(this, IDC_SAVEPASSWORD), + m_cbResource(this, IDC_COMBO_RESOURCE), + m_cbServer(this, IDC_EDIT_LOGIN_SERVER), + m_txtPort(this, IDC_PORT), + m_chkManualHost(this, IDC_MANUAL), + m_txtManualHost(this, IDC_HOST), + m_btnRegister(this, IDC_BUTTON_REGISTER) + { + CreateLink(m_txtUsername, "LoginName", _T("")); + CreateLink(m_chkSavePassword, proto->m_options.SavePassword); + CreateLink(m_cbResource, "Resource", _T("Miranda")); + CreateLink(m_cbServer, "LoginServer", _T("jabber.org")); + CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); + CreateLink(m_chkUseDomainLogin, proto->m_options.UseDomainLogin); + + // Bind events + m_cbType.OnChange = Callback(this, &CJabberDlgAccMgrUI::cbType_OnChange); + m_cbServer.OnDropdown = Callback(this, &CJabberDlgAccMgrUI::cbServer_OnDropdown); + m_chkManualHost.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkManualHost_OnChange); + m_chkUseDomainLogin.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkUseDomainLogin_OnChange); + + m_btnRegister.OnClick = Callback(this, &CJabberDlgAccMgrUI::btnRegister_OnClick); + } + +protected: + enum { ACC_PUBLIC, ACC_TLS, ACC_SSL, ACC_GTALK, ACC_LJTALK, ACC_FBOOK, ACC_VK, ACC_SMS }; + + void OnInitDialog() + { + CSuper::OnInitDialog(); + + int i; + DBVARIANT dbv; + char server[256], manualServer[256]={0}; + + m_gotservers = false; + + TCHAR *passw = m_proto->JGetStringCrypt(NULL, "LoginPassword"); + if (passw) + { + m_txtPassword.SetText(passw); + mir_free(passw); + } + + m_cbServer.AddString(TranslateT("Loading...")); + + // fill predefined resources + TCHAR* szResources[] = { _T("Home"), _T("Work"), _T("Office"), _T("Miranda") }; + for (i = 0; i < SIZEOF(szResources); ++i) + m_cbResource.AddString(szResources[i]); + + // append computer name to the resource list + TCHAR szCompName[ MAX_COMPUTERNAME_LENGTH + 1]; + DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; + if (GetComputerName(szCompName, &dwCompNameLength)) + m_cbResource.AddString(szCompName); + + if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "Resource", &dbv)) + { + if(CB_ERR == m_cbResource.FindString(dbv.ptszVal, -1, true)) + m_cbResource.AddString(dbv.ptszVal); + + m_cbResource.SetText(dbv.ptszVal); + JFreeVariant(&dbv); + } else + { + m_cbResource.SetText(_T("Miranda")); + } + + m_cbType.AddString(TranslateT("Public XMPP Network"), ACC_PUBLIC); + m_cbType.AddString(TranslateT("Secure XMPP Network"), ACC_TLS); + m_cbType.AddString(TranslateT("Secure XMPP Network (old style)"), ACC_SSL); + m_cbType.AddString(TranslateT("Google Talk!"), ACC_GTALK); + m_cbType.AddString(TranslateT("LiveJournal Talk"), ACC_LJTALK); + m_cbType.AddString(TranslateT("Facebook Chat"), ACC_FBOOK); + m_cbType.AddString(TranslateT("Vkontakte"), ACC_VK); + m_cbType.AddString(TranslateT("S.ms"), ACC_SMS); + + m_cbServer.GetTextA(server, SIZEOF(server)); + if (!DBGetContactSettingString(NULL, m_proto->m_szModuleName, "ManualHost", &dbv)) + { + lstrcpynA(manualServer, dbv.pszVal, SIZEOF(manualServer)); + JFreeVariant(&dbv); + } + + m_canregister = true; + if (!lstrcmpA(manualServer, "talk.google.com")) + { + m_cbType.SetCurSel(ACC_GTALK); + m_canregister = false; + } + else if (!lstrcmpA(server, "livejournal.com")) + { + m_cbType.SetCurSel(ACC_LJTALK); + m_canregister = false; + } + else if (!lstrcmpA(server, "chat.facebook.com")) + { + m_cbType.SetCurSel(ACC_FBOOK); + m_canregister = false; + } + else if (!lstrcmpA(server, "vk.com")) + { + m_cbType.SetCurSel(ACC_VK); + m_canregister = false; + } + else if (!lstrcmpA(server, "S.ms")) + { + m_cbType.SetCurSel(ACC_SMS); + m_canregister = false; + } + else if (m_proto->m_options.UseSSL) + m_cbType.SetCurSel(ACC_SSL); + else if (m_proto->m_options.UseTLS) { + m_cbType.SetCurSel(ACC_TLS); + m_txtPort.SetInt(5222); + } + else + m_cbType.SetCurSel(ACC_PUBLIC); + //cbType_OnChange(&m_cbType); + + if (m_chkManualHost.Enabled()) + { + if (m_proto->m_options.ManualConnect) + { + m_chkManualHost.SetState(BST_CHECKED); + m_txtManualHost.Enable(); + m_txtPort.Enable(); + + if (!DBGetContactSettingTString(NULL, m_proto->m_szModuleName, "ManualHost", &dbv)) + { + m_txtManualHost.SetText(dbv.ptszVal); + JFreeVariant(&dbv); + } + + m_txtPort.SetInt(m_proto->JGetWord(NULL, "ManualPort", m_txtPort.GetInt())); + } else + { + int defPort = m_txtPort.GetInt(); + int port = m_proto->JGetWord(NULL, "Port", defPort); + + if (port != defPort) + { + m_chkManualHost.SetState(BST_CHECKED); + m_txtManualHost.Enable(); + m_txtPort.Enable(); + + m_txtManualHost.SetTextA(server); + m_txtPort.SetInt(port); + } else + { + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + } + } + } + + if (m_proto->m_options.UseDomainLogin) + chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); + + CheckRegistration(); + } + + void OnApply() + { + // clear saved password + *m_proto->m_savedPassword = 0; + + BOOL bUseHostnameAsResource = FALSE; + TCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1], szResource[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; + if (GetComputerName(szCompName, &dwCompNameLength)) + { + m_cbResource.GetText(szResource, SIZEOF(szResource)); + if (!lstrcmp(szCompName, szResource)) + bUseHostnameAsResource = TRUE; + } + m_proto->m_options.HostNameAsResource = bUseHostnameAsResource; + + if (m_chkSavePassword.GetState() == BST_CHECKED) + { + TCHAR *text = m_txtPassword.GetText(); + m_proto->JSetStringCrypt(NULL, "LoginPassword", text); + mir_free(text); + } else + { + m_proto->JDeleteSetting(NULL, "LoginPassword"); + } + + switch (m_cbType.GetItemData(m_cbType.GetCurSel())) + { + case ACC_FBOOK: + m_proto->m_options.IgnoreRosterGroups = TRUE; + + case ACC_VK: + case ACC_PUBLIC: + m_proto->m_options.UseSSL = m_proto->m_options.UseTLS = FALSE; + break; + + case ACC_GTALK: + m_proto->JSetWord(NULL, "Priority", 24); + { + int port = m_txtPort.GetInt(); + if (port == 443 || port == 5223) + { + m_proto->m_options.UseSSL = TRUE; + m_proto->m_options.UseTLS = FALSE; + } + else if (port == 5222) + { + m_proto->m_options.UseSSL = FALSE; + m_proto->m_options.UseTLS = TRUE; + } + } + break; + + case ACC_TLS: + case ACC_LJTALK: + case ACC_SMS: + m_proto->m_options.UseSSL = FALSE; + m_proto->m_options.UseTLS = TRUE; + break; + + case ACC_SSL: + m_proto->m_options.UseSSL = TRUE; + m_proto->m_options.UseTLS = FALSE; + break; + } + + char server[256]; + char manualServer[256]; + + m_cbServer.GetTextA(server, SIZEOF(server)); + m_txtManualHost.GetTextA(manualServer, SIZEOF(manualServer)); + + if ((m_chkManualHost.GetState() == BST_CHECKED) && lstrcmpA(server, manualServer)) + { + m_proto->m_options.ManualConnect = TRUE; + m_proto->JSetString(NULL, "ManualHost", manualServer); + m_proto->JSetWord(NULL, "ManualPort", m_txtPort.GetInt()); + m_proto->JSetWord(NULL, "Port", m_txtPort.GetInt()); + } else + { + m_proto->m_options.ManualConnect = FALSE; + m_proto->JDeleteSetting(NULL, "ManualHost"); + m_proto->JDeleteSetting(NULL, "ManualPort"); + m_proto->JSetWord(NULL, "Port", m_txtPort.GetInt()); + } + + sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); + + if (m_proto->m_bJabberOnline) + { + if (m_cbType.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || + m_cbServer.IsChanged() || m_txtPort.IsChanged() || m_txtManualHost.IsChanged()) + { + MessageBox(m_hwnd, + TranslateT("Some changes will take effect the next time you connect to the Jabber network."), + TranslateT("Jabber Protocol Option"), MB_OK|MB_SETFOREGROUND); + } + + m_proto->SendPresence(m_proto->m_iStatus, true); + } + } + + void OnChange(CCtrlBase*) + { + if (m_initialized) + CheckRegistration(); + } + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) { + case WM_JABBER_REFRESH: + RefreshServers(( HXML )lParam); + break; + } + return CSuper::DlgProc(msg, wParam, lParam); + } + +private: + bool m_gotservers; + bool m_canregister; + + void btnRegister_OnClick(CCtrlButton *) + { + TCHAR buf[512] = _T(""), pass[512]; + if (!m_proto->EnterString(buf, SIZEOF(buf), TranslateT("Confirm password"), JES_PASSWORD)) + return; + + m_txtPassword.GetText(pass, SIZEOF(pass)); + if (lstrcmp(buf, pass)) + { + MessageBox(m_hwnd, TranslateT("Passwords do not match."), _T("Miranda NG"), MB_ICONSTOP|MB_OK); + return; + } + + ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); + m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); + m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); + m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); + regInfo.port = (WORD)m_txtPort.GetInt(); + if (m_chkManualHost.GetState() == BST_CHECKED) + { + m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); + } else + { + regInfo.manualHost[0] = '\0'; + } + + if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) + { + CJabberDlgRegister dlg(m_proto, m_hwnd, ®Info); + dlg.DoModal(); +// DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_OPT_REGISTER), m_hwnd, JabberRegisterDlgProc, (LPARAM)®Info); + } + } + + void cbServer_OnDropdown(CCtrlCombo* ) + { + if ( !m_gotservers ) + mir_forkthread(QueryServerListThread, this); + } + + void cbType_OnChange(CCtrlData *sender) + { + CCtrlCombo *chk = (CCtrlCombo *)sender; + setupConnection(chk->GetItemData(chk->GetCurSel())); + CheckRegistration(); + } + + void chkUseDomainLogin_OnChange(CCtrlData *sender) + { + CCtrlCheck *chk = (CCtrlCheck *)sender; + BOOL checked = chk->GetState() == BST_CHECKED; + + m_txtPassword.Enable(!checked); + m_txtUsername.Enable(!checked); + m_chkSavePassword.Enable(!checked); + if (checked) { + m_txtPassword.SetText(_T("")); + m_txtUsername.SetText(_T("")); + m_chkSavePassword.SetState(BST_CHECKED); + } + } + + void chkManualHost_OnChange(CCtrlData *sender) + { + CCtrlCheck *chk = (CCtrlCheck *)sender; + + if (chk->GetState() == BST_CHECKED) + { + char buf[256]; + m_cbServer.GetTextA(buf, SIZEOF(buf)); + m_txtManualHost.SetTextA(buf); + m_txtPort.SetInt(5222); + + m_txtManualHost.Enable(); + m_txtPort.Enable(); + } else + { + m_txtManualHost.Disable(); + m_txtPort.Disable(); + } + } + + void CheckRegistration(); + void setupConnection(int type); + void setupPublic(); + void setupSecure(); + void setupSecureSSL(); + void setupGoogle(); + void setupLJ(); + void setupFB(); + void setupVK(); + void setupSMS(); + void RefreshServers( HXML node); + static void QueryServerListThread(void *arg); +}; + +void CJabberDlgAccMgrUI::CheckRegistration() +{ + if ( !m_canregister ) { + m_btnRegister.Disable(); + return; + } + + ThreadData regInfo(m_proto, JABBER_SESSION_NORMAL); + m_txtUsername.GetText(regInfo.username, SIZEOF(regInfo.username)); + m_txtPassword.GetText(regInfo.password, SIZEOF(regInfo.password)); + m_cbServer.GetTextA(regInfo.server, SIZEOF(regInfo.server)); + regInfo.port = (WORD)m_txtPort.GetInt(); + if (m_chkManualHost.GetState() == BST_CHECKED) + m_txtManualHost.GetTextA(regInfo.manualHost, SIZEOF(regInfo.manualHost)); + else + regInfo.manualHost[0] = '\0'; + + if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ( (m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0] )) + m_btnRegister.Enable(); + else + m_btnRegister.Disable(); +} + +void CJabberDlgAccMgrUI::setupConnection(int type) +{ + switch (type) { + case ACC_PUBLIC: setupPublic(); break; + case ACC_TLS: setupSecure(); break; + case ACC_SSL: setupSecureSSL(); break; + case ACC_GTALK: setupGoogle(); break; + case ACC_LJTALK: setupLJ(); break; + case ACC_FBOOK: setupFB(); break; + case ACC_VK: setupVK(); break; + case ACC_SMS: setupSMS(); break; + } +} + +void CJabberDlgAccMgrUI::setupPublic() +{ + m_canregister = true; + m_gotservers = false; + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5222); + + m_cbServer.Enable(); + m_chkManualHost.Enable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Enable(); +} + +void CJabberDlgAccMgrUI::setupSecure() +{ + m_canregister = true; + m_gotservers = false; + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5222); + + m_cbServer.Enable(); + m_chkManualHost.Enable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Enable(); +} + +void CJabberDlgAccMgrUI::setupSecureSSL() +{ + m_canregister = true; + m_gotservers = false; + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5223); + + m_cbServer.Enable(); + m_chkManualHost.Enable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Enable(); +} + +void CJabberDlgAccMgrUI::setupGoogle() +{ + m_canregister = false; + m_gotservers = true; + m_cbServer.ResetContent(); + m_cbServer.AddStringA("gmail.com"); + m_cbServer.AddStringA("googlemail.com"); + m_cbServer.SetTextA("gmail.com"); + m_chkManualHost.SetState(BST_CHECKED); + m_txtManualHost.SetTextA("talk.google.com"); + m_txtPort.SetInt(443); + + m_cbServer.Enable(); + m_chkManualHost.Disable(); + m_txtManualHost.Disable(); + //m_txtPort.Disable(); + m_btnRegister.Disable(); +} + +void CJabberDlgAccMgrUI::setupLJ() +{ + m_canregister = false; + m_gotservers = true; + m_cbServer.ResetContent(); + m_cbServer.SetTextA("livejournal.com"); + m_cbServer.AddStringA("livejournal.com"); + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5222); + + m_cbServer.Disable(); + m_chkManualHost.Disable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Disable(); +} + +void CJabberDlgAccMgrUI::setupFB() +{ + m_canregister = false; + m_gotservers = true; + m_cbServer.ResetContent(); + m_cbServer.SetTextA("chat.facebook.com"); + m_cbServer.AddStringA("chat.facebook.com"); + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(443); + + m_cbServer.Disable(); + m_chkManualHost.Disable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Disable(); +} + +void CJabberDlgAccMgrUI::setupVK() +{ + m_canregister = false; + m_gotservers = true; + m_cbServer.ResetContent(); + m_cbServer.SetTextA("VK.com"); + m_cbServer.AddStringA("VK.com"); + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5222); + + m_cbServer.Disable(); + m_chkManualHost.Disable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Disable(); +} + +void CJabberDlgAccMgrUI::setupSMS() +{ + m_canregister = false; + m_gotservers = true; + m_cbServer.ResetContent(); + m_cbServer.SetTextA("S.ms"); + m_cbServer.AddStringA("S.ms"); + m_chkManualHost.SetState(BST_UNCHECKED); + m_txtManualHost.SetTextA(""); + m_txtPort.SetInt(5222); + + m_cbServer.Disable(); + m_chkManualHost.Disable(); + m_txtManualHost.Disable(); + m_txtPort.Disable(); + m_btnRegister.Disable(); + // m_cbResource.Disable(); +} + +void CJabberDlgAccMgrUI::RefreshServers( HXML node ) +{ + m_gotservers = node != NULL; + + TCHAR *server = m_cbServer.GetText(); + bool bDropdown = m_cbServer.GetDroppedState(); + if (bDropdown) m_cbServer.ShowDropdown(false); + + m_cbServer.ResetContent(); + if ( node ) + { + for (int i = 0; ; ++i) { + HXML n = xmlGetChild(node, i); + if ( !n ) + break; + + if ( !lstrcmp( xmlGetName( n ), _T("item"))) + if ( const TCHAR *jid = xmlGetAttrValue( n, _T("jid"))) + if (m_cbServer.FindString(jid, -1, true) == CB_ERR) + m_cbServer.AddString(jid); + } + } + + m_cbServer.SetText(server); + + if (bDropdown) m_cbServer.ShowDropdown(); + mir_free(server); +} + +void CJabberDlgAccMgrUI::QueryServerListThread(void *arg) +{ + CDlgOptAccount *wnd = (CDlgOptAccount *)arg; + HWND hwnd = wnd->GetHwnd(); + bool bIsError = true; + + NETLIBHTTPREQUEST request = {0}; + request.cbSize = sizeof(request); + request.requestType = REQUEST_GET; + request.flags = NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11; + request.szUrl = "http://xmpp.org/services/services.xml"; + + NETLIBHTTPREQUEST *result = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)wnd->GetProto()->m_hNetlibUser, (LPARAM)&request); + if ( result && IsWindow( hwnd )) { + if ((result->resultCode == 200) && result->dataLength && result->pData) { + TCHAR* ptszText = mir_a2t( result->pData ); + XmlNode node( ptszText, NULL, NULL ); + if ( node ) { + HXML queryNode = xmlGetChild( node, _T("query")); + if ( queryNode && IsWindow(hwnd)) { + SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); + bIsError = false; + } } + mir_free( ptszText ); + } } + + if ( result ) + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)result); + if ( bIsError ) + SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)NULL); +} + +INT_PTR CJabberProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) +{ + CJabberDlgAccMgrUI *dlg = new CJabberDlgAccMgrUI(this, (HWND)lParam); + dlg->Show(); + return (INT_PTR)dlg->GetHwnd(); +} + +void CJabberProto::JabberUpdateDialogs( BOOL ) +{ + if ( rrud.hwndDlg ) + SendMessage(rrud.hwndDlg, JM_STATUSCHANGED, 0,0); +} + +INT_PTR __cdecl CJabberProto::OnMenuOptions( WPARAM, LPARAM ) +{ + OPENOPTIONSDIALOG ood = {0}; + ood.cbSize = sizeof(ood); + ood.pszGroup = "Network"; + ood.pszPage = mir_t2a(m_tszUserName); + ood.pszTab = "Account"; + Options_Open(&ood); + + mir_free((void *)ood.pszPage); + return 0; +} + +int CJabberProto::OnModernOptInit( WPARAM, LPARAM ) +{/* + static int iBoldControls[] = + { + IDC_TITLE1, MODERNOPT_CTRL_LAST + }; + + MODERNOPTOBJECT obj = {0}; + obj.cbSize = sizeof(obj); + obj.dwFlags = MODEROPT_FLG_TCHAR; + obj.hIcon = LoadIconEx("main"); + obj.hInstance = hInst; + obj.iSection = MODERNOPT_PAGE_ACCOUNTS; + obj.iType = MODERNOPT_TYPE_SUBSECTIONPAGE; + obj.lptzSubsection = mir_a2t(m_szModuleName); // title!!!!!!!!!!! + obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT); + obj.iBoldControls = iBoldControls; + obj.pfnDlgProc = JabberWizardDlgProc; + obj.lpszClassicGroup = "Network"; + obj.lpszClassicPage = m_szModuleName; // title!!!!!!!!!!! + obj.lpszHelpUrl = "http://forums.miranda-im.org/showthread.php?t=14294"; + CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj); + mir_free(obj.lptzSubsection); */ + return 0; +} diff --git a/protocols/JabberG/src/jabber_opttree.cpp b/protocols/JabberG/src/jabber_opttree.cpp new file mode 100644 index 0000000000..bd43b55a08 --- /dev/null +++ b/protocols/JabberG/src/jabber_opttree.cpp @@ -0,0 +1,263 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2007 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_opttree.h" + +enum { IMG_GROUP, IMG_CHECK, IMG_NOCHECK, IMG_RCHECK, IMG_NORCHECK, IMG_GRPOPEN, IMG_GRPCLOSED }; + +CCtrlTreeOpts::CCtrlTreeOpts(CDlgBase* dlg, int ctrlId): + CCtrlTreeView(dlg, ctrlId), + m_options(5) +{ +} + +CCtrlTreeOpts::~CCtrlTreeOpts() +{ + for (int i = 0; i < m_options.getCount(); ++i) + delete m_options[i]; + m_options.destroy(); +} + +void CCtrlTreeOpts::AddOption(TCHAR *szOption, CMOption<BYTE> &option) +{ + m_options.insert(new COptionsItem(szOption, option), m_options.getCount()); +} + +BOOL CCtrlTreeOpts::OnNotify(int idCtrl, NMHDR *pnmh) +{ + switch (pnmh->code) + { + case TVN_KEYDOWN: + { + LPNMTVKEYDOWN lpnmtvkd = (LPNMTVKEYDOWN)pnmh; + HTREEITEM hti; + if ((lpnmtvkd->wVKey == VK_SPACE) && (hti = GetSelection())) + ProcessItemClick(hti); + break; + } + + case NM_CLICK: + { + TVHITTESTINFO hti; + hti.pt.x=(short)LOWORD(GetMessagePos()); + hti.pt.y=(short)HIWORD(GetMessagePos()); + ScreenToClient(pnmh->hwndFrom,&hti.pt); + if(HitTest(&hti)) + if(hti.flags&TVHT_ONITEMICON) + ProcessItemClick(hti.hItem); + break; + } + + case TVN_ITEMEXPANDEDW: + { + LPNMTREEVIEWW lpnmtv = (LPNMTREEVIEWW)pnmh; + TVITEM tvi; + tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvi.hItem = lpnmtv->itemNew.hItem; + tvi.iImage = tvi.iSelectedImage = + (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; + SendMessageW(pnmh->hwndFrom, TVM_SETITEMW, 0, (LPARAM)&tvi); + break; + } + + case TVN_ITEMEXPANDEDA: + { + LPNMTREEVIEWA lpnmtv = (LPNMTREEVIEWA)pnmh; + TVITEM tvi; + tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvi.hItem = lpnmtv->itemNew.hItem; + tvi.iImage = tvi.iSelectedImage = + (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; + SendMessageA(pnmh->hwndFrom, TVM_SETITEMA, 0, (LPARAM)&tvi); + break; + } + } + + return CCtrlTreeView::OnNotify(idCtrl, pnmh); +} + +void CCtrlTreeOpts::OnInit() +{ + CCtrlTreeView::OnInit(); + + TCHAR itemName[1024]; + HIMAGELIST hImgLst; + + SelectItem(NULL); + DeleteAllItems(); + + hImgLst = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR|ILC_COLOR32|ILC_MASK, 5, 1); + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_TICK)); // check on + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); // check off + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_TICK)); // radio on + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); // radio on + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN)); + ImageList_AddIcon_Icolib(hImgLst, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT)); + SetImageList(hImgLst, TVSIL_NORMAL); + + /* build options tree. based on code from IcoLib */ + for (int i = 0; i < m_options.getCount(); i++) + { + TCHAR* sectionName; + int sectionLevel = 0; + + HTREEITEM hSection = NULL; + lstrcpy(itemName, m_options[i]->m_szOptionName); + sectionName = itemName; + + while (sectionName) + { + // allow multi-level tree + TCHAR* pItemName = sectionName; + HTREEITEM hItem; + + if (sectionName = _tcschr(sectionName, '/')) + { + // one level deeper + *sectionName = 0; + sectionName++; + } + + hItem = FindNamedItem(hSection, pItemName); + if (!sectionName || !hItem) + { + if (!hItem) + { + TVINSERTSTRUCT tvis = {0}; + + tvis.hParent = hSection; + tvis.hInsertAfter = TVI_LAST;//TVI_SORT; + tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvis.item.pszText = pItemName; + tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED; + if (sectionName) + { + tvis.item.lParam = -1; + tvis.item.state |= TVIS_BOLD; + tvis.item.stateMask |= TVIS_BOLD; + tvis.item.iImage = tvis.item.iSelectedImage = IMG_GRPOPEN; + } else + { + tvis.item.lParam = i; + + BYTE val = *m_options[i]->m_option; + + if (m_options[i]->m_groupId == OPTTREE_CHECK) + { + tvis.item.iImage = tvis.item.iSelectedImage = val ? IMG_CHECK : IMG_NOCHECK; + } else + { + tvis.item.iImage = tvis.item.iSelectedImage = val ? IMG_RCHECK : IMG_NORCHECK; + } + } + hItem = InsertItem(&tvis); + if (!sectionName) + m_options[i]->m_hItem = hItem; + } + } + sectionLevel++; + hSection = hItem; + } + } + + TranslateTree(); + ShowWindow(m_hwnd, SW_SHOW); + SelectItem(FindNamedItem(0, NULL)); +} + +void CCtrlTreeOpts::OnDestroy() +{ + ImageList_Destroy(GetImageList(TVSIL_NORMAL)); +} + +void CCtrlTreeOpts::OnApply() +{ + CCtrlTreeView::OnApply(); + + for (int i = 0; i < m_options.getCount(); ++i) + { + TVITEMEX tvi; + GetItem(m_options[i]->m_hItem, &tvi); + *m_options[i]->m_option = ((tvi.iImage == IMG_CHECK) || (tvi.iImage == IMG_RCHECK)) ? 1 : 0; + } +} + +void CCtrlTreeOpts::ProcessItemClick(HTREEITEM hti) +{ + TVITEMEX tvi; + GetItem(hti, &tvi); + switch (tvi.iImage) + { + case IMG_GRPOPEN: + tvi.iImage = tvi.iSelectedImage = IMG_GRPCLOSED; + Expand(tvi.hItem, TVE_COLLAPSE); + break; + case IMG_GRPCLOSED: + tvi.iImage = tvi.iSelectedImage = IMG_GRPOPEN; + Expand(tvi.hItem, TVE_EXPAND); + break; + + case IMG_CHECK: + tvi.iImage = tvi.iSelectedImage = IMG_NOCHECK; + SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); + break; + case IMG_NOCHECK: + tvi.iImage = tvi.iSelectedImage = IMG_CHECK; + SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); + break; + case IMG_NORCHECK: + { + int i; + for (i = 0; i < m_options.getCount(); ++i) + { + if (m_options[i]->m_groupId == m_options[tvi.lParam]->m_groupId) + { + TVITEMEX tvi_tmp; + tvi_tmp.mask = TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvi_tmp.hItem = m_options[i]->m_hItem; + tvi_tmp.iImage = tvi_tmp.iSelectedImage = IMG_NORCHECK; + SetItem(&tvi_tmp); + } + } + tvi.iImage = tvi.iSelectedImage = IMG_RCHECK; + SendMessage(::GetParent(::GetParent(m_hwnd)), PSM_CHANGED, 0, 0); + break; + } + } + + SetItem(&tvi); +} + +CCtrlTreeOpts::COptionsItem::COptionsItem(TCHAR *szOption, CMOption<BYTE> &option): + m_option(&option), m_groupId(OPTTREE_CHECK), m_hItem(NULL) +{ + m_szOptionName = mir_tstrdup(szOption); +} + +CCtrlTreeOpts::COptionsItem::~COptionsItem() +{ + mir_free(m_szOptionName); +} diff --git a/protocols/JabberG/src/jabber_opttree.h b/protocols/JabberG/src/jabber_opttree.h new file mode 100644 index 0000000000..3246ad74a3 --- /dev/null +++ b/protocols/JabberG/src/jabber_opttree.h @@ -0,0 +1,64 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2007 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __jabber_opttree_h__ +#define __jabber_opttree_h__ + +#define OPTTREE_CHECK 0 + +class CCtrlTreeOpts : public CCtrlTreeView +{ + typedef CCtrlTreeView CSuper; + +public: + CCtrlTreeOpts( CDlgBase* dlg, int ctrlId ); + ~CCtrlTreeOpts(); + + void AddOption(TCHAR *szOption, CMOption<BYTE> &option); + + BOOL OnNotify(int idCtrl, NMHDR *pnmh); + void OnDestroy(); + void OnInit(); + void OnApply(); + +protected: + struct COptionsItem + { + TCHAR *m_szOptionName; + int m_groupId; + + CMOption<BYTE> *m_option; + + HTREEITEM m_hItem; + + COptionsItem(TCHAR *szOption, CMOption<BYTE> &option); + ~COptionsItem(); + }; + + LIST<COptionsItem> m_options; + + void ProcessItemClick(HTREEITEM hti); +}; + +#endif // __opttree_h__ diff --git a/protocols/JabberG/src/jabber_password.cpp b/protocols/JabberG/src/jabber_password.cpp new file mode 100644 index 0000000000..2ce5128b78 --- /dev/null +++ b/protocols/JabberG/src/jabber_password.cpp @@ -0,0 +1,99 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_caps.h" + +static INT_PTR CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ); + +INT_PTR __cdecl CJabberProto::OnMenuHandleChangePassword( WPARAM, LPARAM ) +{ + if ( IsWindow( m_hwndJabberChangePassword )) + SetForegroundWindow( m_hwndJabberChangePassword ); + else + m_hwndJabberChangePassword = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_CHANGEPASSWORD ), NULL, JabberChangePasswordDlgProc, ( LPARAM )this ); + + return 0; +} + +static INT_PTR CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + CJabberProto* ppro = (CJabberProto*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + switch ( msg ) { + case WM_INITDIALOG: + ppro = (CJabberProto*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )lParam ); + + WindowSetIcon( hwndDlg, ppro, "key" ); + TranslateDialogDefault( hwndDlg ); + if ( ppro->m_bJabberOnline && ppro->m_ThreadInfo!=NULL ) { + TCHAR text[1024]; + mir_sntprintf( text, SIZEOF( text ), _T("%s %s@") _T(TCHAR_STR_PARAM), TranslateT( "Set New Password for" ), ppro->m_ThreadInfo->username, ppro->m_ThreadInfo->server ); + SetWindowText( hwndDlg, text ); + } + return TRUE; + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + if ( ppro->m_bJabberOnline && ppro->m_ThreadInfo!=NULL ) { + TCHAR newPasswd[512], text[512]; + GetDlgItemText( hwndDlg, IDC_NEWPASSWD, newPasswd, SIZEOF( newPasswd )); + GetDlgItemText( hwndDlg, IDC_NEWPASSWD2, text, SIZEOF( text )); + if ( _tcscmp( newPasswd, text )) { + MessageBox( hwndDlg, TranslateT( "New password does not match." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); + break; + } + GetDlgItemText( hwndDlg, IDC_OLDPASSWD, text, SIZEOF( text )); + if ( _tcscmp( text, ppro->m_ThreadInfo->password )) { + MessageBox( hwndDlg, TranslateT( "Current password is incorrect." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); + break; + } + _tcsncpy( ppro->m_ThreadInfo->newPassword, newPasswd, SIZEOF( ppro->m_ThreadInfo->newPassword )); + + int iqId = ppro->SerialNext(); + ppro->IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultSetPassword ); + + XmlNodeIq iq( _T("set"), iqId, _A2T(ppro->m_ThreadInfo->server)); + HXML q = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); + q << XCHILD( _T("username"), ppro->m_ThreadInfo->username ); + q << XCHILD( _T("password"), newPasswd ); + ppro->m_ThreadInfo->send( iq ); + } + DestroyWindow( hwndDlg ); + break; + case IDCANCEL: + DestroyWindow( hwndDlg ); + break; + } + break; + case WM_CLOSE: + DestroyWindow( hwndDlg ); + break; + case WM_DESTROY: + ppro->m_hwndJabberChangePassword = NULL; + WindowFreeIcon( hwndDlg ); + break; + } + + return FALSE; +} diff --git a/protocols/JabberG/src/jabber_presence_manager.cpp b/protocols/JabberG/src/jabber_presence_manager.cpp new file mode 100644 index 0000000000..8a8ece811d --- /dev/null +++ b/protocols/JabberG/src/jabber_presence_manager.cpp @@ -0,0 +1,51 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_presence_manager.h" + +BOOL CJabberPresenceManager::FillPermanentHandlers() +{ + return TRUE; +} + +BOOL CJabberPresenceManager::HandlePresencePermanent(HXML node, ThreadData *pThreadData) +{ + BOOL bStopHandling = FALSE; + Lock(); + CJabberPresencePermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo && !bStopHandling ) { + CJabberPresenceInfo presenceInfo; + presenceInfo.m_pUserData = pInfo->m_pUserData; + + if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &presenceInfo)) { + bStopHandling = TRUE; + break; + } + pInfo = pInfo->m_pNext; + } + Unlock(); + + return bStopHandling; +} diff --git a/protocols/JabberG/src/jabber_presence_manager.h b/protocols/JabberG/src/jabber_presence_manager.h new file mode 100644 index 0000000000..be138d3b93 --- /dev/null +++ b/protocols/JabberG/src/jabber_presence_manager.h @@ -0,0 +1,195 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_PRESENCE_MANAGER_H_ +#define _JABBER_PRESENCE_MANAGER_H_ + +#include "jabber_xml.h" + +struct CJabberProto; +typedef void ( CJabberProto::*JABBER_PRESENCE_PFUNC )( HXML node, void *usedata ); +typedef void ( *PRESENCE_USER_DATA_FREE_FUNC )( void *pUserData ); + +class CJabberPresenceInfo; + +typedef BOOL ( CJabberProto::*JABBER_PRESENCE_HANDLER )( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ); + +class CJabberPresenceInfo +{ +protected: + friend class CJabberPresenceManager; + JABBER_PRESENCE_HANDLER m_pHandler; + CJabberPresenceInfo* m_pNext; + +public: + void *m_pUserData; + + CJabberPresenceInfo() + { + ZeroMemory(this, sizeof(*this)); + } + ~CJabberPresenceInfo() + { + } + void* GetUserData() + { + return m_pUserData; + } +}; + +class CJabberPresencePermanentInfo +{ + friend class CJabberPresenceManager; + + CJabberPresencePermanentInfo* m_pNext; + + JABBER_PRESENCE_HANDLER m_pHandler; + void *m_pUserData; + PRESENCE_USER_DATA_FREE_FUNC m_pUserDataFree; + int m_iPriority; +public: + CJabberPresencePermanentInfo() + { + ZeroMemory(this, sizeof(CJabberPresencePermanentInfo)); + } + ~CJabberPresencePermanentInfo() + { + if ( m_pUserDataFree ) + m_pUserDataFree(m_pUserData); + } +}; + +class CJabberPresenceManager +{ +protected: + CJabberProto* ppro; + CRITICAL_SECTION m_cs; + CJabberPresencePermanentInfo* m_pPermanentHandlers; + +public: + CJabberPresenceManager( CJabberProto* proto ) + { + InitializeCriticalSection(&m_cs); + m_pPermanentHandlers = NULL; + ppro = proto; + } + ~CJabberPresenceManager() + { + Lock(); + CJabberPresencePermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo ) + { + CJabberPresencePermanentInfo *pTmp = pInfo->m_pNext; + delete pInfo; + pInfo = pTmp; + } + m_pPermanentHandlers = NULL; + Unlock(); + DeleteCriticalSection(&m_cs); + } + BOOL Start() + { + return TRUE; + } + BOOL Shutdown() + { + return TRUE; + } + void Lock() + { + EnterCriticalSection(&m_cs); + } + void Unlock() + { + LeaveCriticalSection(&m_cs); + } + CJabberPresencePermanentInfo* AddPermanentHandler(JABBER_PRESENCE_HANDLER pHandler, void *pUserData = NULL, PRESENCE_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) + { + CJabberPresencePermanentInfo* pInfo = new CJabberPresencePermanentInfo(); + if (!pInfo) + return NULL; + + pInfo->m_pHandler = pHandler; + pInfo->m_pUserData = pUserData; + pInfo->m_pUserDataFree = pUserDataFree; + pInfo->m_iPriority = iPriority; + + Lock(); + if (!m_pPermanentHandlers) + m_pPermanentHandlers = pInfo; + else + { + if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { + pInfo->m_pNext = m_pPermanentHandlers; + m_pPermanentHandlers = pInfo; + } else + { + CJabberPresencePermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) + pTmp = pTmp->m_pNext; + pInfo->m_pNext = pTmp->m_pNext; + pTmp->m_pNext = pInfo; + } + } + Unlock(); + + return pInfo; + } + BOOL DeletePermanentHandler(CJabberPresencePermanentInfo *pInfo) + { // returns TRUE when pInfo found, or FALSE otherwise + Lock(); + if (!m_pPermanentHandlers) + { + Unlock(); + return FALSE; + } + if (m_pPermanentHandlers == pInfo) // check first item + { + m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } else + { + CJabberPresencePermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext) + { + if (pTmp->m_pNext == pInfo) + { + pTmp->m_pNext = pTmp->m_pNext->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } + pTmp = pTmp->m_pNext; + } + } + Unlock(); + return FALSE; + } + BOOL HandlePresencePermanent(HXML node, ThreadData *pThreadData); + BOOL FillPermanentHandlers(); +}; + +#endif diff --git a/protocols/JabberG/src/jabber_privacy.cpp b/protocols/JabberG/src/jabber_privacy.cpp new file mode 100644 index 0000000000..636cf50bf6 --- /dev/null +++ b/protocols/JabberG/src/jabber_privacy.cpp @@ -0,0 +1,2328 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_privacy.h" + +#include <m_icolib.h> +#include <m_genmenu.h> +#include <m_clistint.h> + +#define JABBER_PL_BUSY_MSG "Sending request, please wait..." + +BOOL CJabberProto::OnIqRequestPrivacyLists( HXML, CJabberIqInfo* pInfo ) +{ + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_SET ) { + if ( !m_pDlgPrivacyLists ) + { + m_privacyListManager.RemoveAllLists(); + QueryPrivacyLists(); + } + else m_pDlgPrivacyLists->SetStatusText(TranslateT("Warning: privacy lists were changed on server.")); + + XmlNodeIq iq( _T("result"), pInfo ); + m_ThreadInfo->send( iq ); + } + return TRUE; +} + +void CJabberProto::OnIqResultPrivacyListModify( HXML, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->m_pUserData ) + return; + + CPrivacyListModifyUserParam *pParam = ( CPrivacyListModifyUserParam * )pInfo->m_pUserData; + + if ( pInfo->m_nIqType != JABBER_IQ_TYPE_RESULT ) + pParam->m_bAllOk = FALSE; + + InterlockedDecrement( &pParam->m_dwCount ); + if ( !pParam->m_dwCount ) { + TCHAR szText[ 512 ]; + if ( !pParam->m_bAllOk ) + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while applying changes")); + else + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy lists successfully saved")); + if (m_pDlgPrivacyLists) + m_pDlgPrivacyLists->SetStatusText( szText ); + // FIXME: enable apply button + delete pParam; + } +} + +void CJabberProto::OnIqResultPrivacyList( HXML iqNode ) +{ + if ( !iqNode ) + return; + + const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); + if ( !type ) + return; + + if ( !_tcscmp( type, _T("result"))) { + HXML query = xmlGetChild( iqNode , "query" ); + if ( !query ) + return; + HXML list = xmlGetChild( query , "list" ); + if ( !list ) + return; + TCHAR *szListName = ( TCHAR* )xmlGetAttrValue( list, _T("name")); + if ( !szListName ) + return; + m_privacyListManager.Lock(); + CPrivacyList* pList = m_privacyListManager.FindList( szListName ); + if ( !pList ) { + m_privacyListManager.AddList( szListName ); + pList = m_privacyListManager.FindList( szListName ); + if ( !pList ) { + m_privacyListManager.Unlock(); + return; + } } + + HXML item; + for ( int i = 1; ( item = xmlGetNthChild( list, _T("item"), i )) != NULL; i++ ) { + const TCHAR *itemType = xmlGetAttrValue( item, _T("type")); + PrivacyListRuleType nItemType = Else; + if ( itemType ) { + if ( !_tcsicmp( itemType, _T( "jid" ))) + nItemType = Jid; + else if ( !_tcsicmp( itemType, _T( "group" ))) + nItemType = Group; + else if ( !_tcsicmp( itemType, _T( "subscription" ))) + nItemType = Subscription; + } + + const TCHAR *itemValue = xmlGetAttrValue( item, _T("value")); + + const TCHAR *itemAction = xmlGetAttrValue( item, _T("action")); + BOOL bAllow = TRUE; + if ( itemAction && !_tcsicmp( itemAction, _T( "deny" ))) + bAllow = FALSE; + + const TCHAR *itemOrder = xmlGetAttrValue( item, _T("order")); + DWORD dwOrder = 0; + if ( itemOrder ) + dwOrder = _ttoi( itemOrder ); + + DWORD dwPackets = 0; + if ( xmlGetChild( item , "message" )) + dwPackets |= JABBER_PL_RULE_TYPE_MESSAGE; + if ( xmlGetChild( item , "presence-in" )) + dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_IN; + if ( xmlGetChild( item , "presence-out" )) + dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; + if ( xmlGetChild( item , "iq" )) + dwPackets |= JABBER_PL_RULE_TYPE_IQ; + + pList->AddRule( nItemType, itemValue, bAllow, dwOrder, dwPackets ); + } + pList->Reorder(); + pList->SetLoaded(); + pList->SetModified(FALSE); + m_privacyListManager.Unlock(); + + UI_SAFE_NOTIFY(m_pDlgPrivacyLists, WM_JABBER_REFRESH); +} } + +CPrivacyList* GetSelectedList(HWND hDlg) +{ + LRESULT nCurSel = SendDlgItemMessage( hDlg, IDC_LB_LISTS, LB_GETCURSEL, 0, 0 ); + if ( nCurSel == LB_ERR ) + return NULL; + + LRESULT nItemData = SendDlgItemMessage( hDlg, IDC_LB_LISTS, LB_GETITEMDATA, nCurSel, 0 ); + if ( nItemData == LB_ERR || nItemData == 0 ) + return NULL; + + return ( CPrivacyList* )nItemData; +} + +CPrivacyListRule* GetSelectedRule(HWND hDlg) +{ + LRESULT nCurSel = SendDlgItemMessage( hDlg, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); + if ( nCurSel == LB_ERR) + return NULL; + + LRESULT nItemData = SendDlgItemMessage( hDlg, IDC_PL_RULES_LIST, LB_GETITEMDATA, nCurSel, 0 ); + if ( nItemData == LB_ERR || nItemData == 0 ) + return NULL; + + return (CPrivacyListRule* )nItemData; +} + +void CJabberProto::OnIqResultPrivacyListActive( HXML iqNode, CJabberIqInfo* pInfo ) +{ + CPrivacyList *pList = (CPrivacyList *)pInfo->GetUserData(); + + if ( m_pDlgPrivacyLists ) + EnableWindow( GetDlgItem( m_pDlgPrivacyLists->GetHwnd(), IDC_ACTIVATE ), TRUE ); + + if ( !iqNode ) + return; + + const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); + if ( !type ) + return; + + TCHAR szText[ 512 ]; + szText[0] = _T('\0'); + m_privacyListManager.Lock(); + if ( !_tcscmp( type, _T("result"))) { + if ( pList ) { + m_privacyListManager.SetActiveListName( pList->GetListName()); + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy list %s set as active"), pList->GetListName()); + } + else { + m_privacyListManager.SetActiveListName( NULL ); + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Active privacy list successfully declined")); + } + } + else mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while setting active list")); + + m_privacyListManager.Unlock(); + + if ( m_pDlgPrivacyLists ) + { + m_pDlgPrivacyLists->SetStatusText( szText ); + RedrawWindow(GetDlgItem(m_pDlgPrivacyLists->GetHwnd(), IDC_LB_LISTS), NULL, NULL, RDW_INVALIDATE); + } + + BuildPrivacyListsMenu( true ); +} + +void CJabberProto::OnIqResultPrivacyListDefault( HXML iqNode, CJabberIqInfo* pInfo ) +{ + CPrivacyList *pList = (CPrivacyList *)pInfo->GetUserData(); + + if ( m_pDlgPrivacyLists ) + EnableWindow( GetDlgItem( m_pDlgPrivacyLists->GetHwnd(), IDC_SET_DEFAULT ), TRUE ); + + if ( !iqNode ) + return; + + const TCHAR *type = xmlGetAttrValue( iqNode, _T("type")); + if ( !type ) + return; + + TCHAR szText[ 512 ]; + szText[0] = _T('\0'); + m_privacyListManager.Lock(); + if ( !_tcscmp( type, _T("result"))) { + if ( pList ) { + m_privacyListManager.SetDefaultListName( pList->GetListName()); + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Privacy list %s set as default"), pList->GetListName()); + } + else { + m_privacyListManager.SetDefaultListName( NULL ); + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Default privacy list successfully declined")); + } + } + else { + mir_sntprintf( szText, SIZEOF( szText ), TranslateT("Error occurred while setting default list")); + } + m_privacyListManager.Unlock(); + + if ( m_pDlgPrivacyLists ) + { + m_pDlgPrivacyLists->SetStatusText( szText ); + RedrawWindow(GetDlgItem(m_pDlgPrivacyLists->GetHwnd(), IDC_LB_LISTS), NULL, NULL, RDW_INVALIDATE); + } +} + +void CJabberProto::OnIqResultPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( pInfo->m_nIqType != JABBER_IQ_TYPE_RESULT ) + return; + + HXML query = xmlGetChild( iqNode, "query" ); + if ( !query ) + return; + + if ( m_ThreadInfo ) + m_ThreadInfo->jabberServerCaps |= JABBER_CAPS_PRIVACY_LISTS; + + m_privacyListManager.Lock(); + m_privacyListManager.RemoveAllLists(); + + for ( int i = 1; ; i++ ) { + HXML list = xmlGetNthChild( query, _T("list"), i ); + if ( !list ) + break; + + const TCHAR *listName = xmlGetAttrValue( list, _T("name")); + if ( listName ) { + m_privacyListManager.AddList(( TCHAR* )listName); + + // Query contents only if list editior is visible! + if ( m_pDlgPrivacyLists ) { + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultPrivacyList); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)) << XCHILD( _T("list")) << XATTR( _T("name"), listName )); + } } } + + const TCHAR *szName = NULL; + HXML node = xmlGetChild( query , "active" ); + if ( node ) + szName = xmlGetAttrValue( node, _T("name")); + m_privacyListManager.SetActiveListName( szName ); + + szName = NULL; + node = xmlGetChild( query , "default" ); + if ( node ) + szName = xmlGetAttrValue( node, _T("name")); + m_privacyListManager.SetDefaultListName( szName ); + + m_privacyListManager.Unlock(); + + UI_SAFE_NOTIFY(m_pDlgPrivacyLists, WM_JABBER_REFRESH); + + BuildPrivacyListsMenu( true ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Add privacy list box +class CJabberDlgPrivacyAddList: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + TCHAR szLine[512]; + + CJabberDlgPrivacyAddList(CJabberProto *proto, HWND hwndParent): + CJabberDlgBase(proto, IDD_PRIVACY_ADD_LIST, hwndParent, false), + m_txtName(this, IDC_EDIT_NAME), + m_btnOk(this, IDOK), + m_btnCancel(this, IDCANCEL) + { + m_btnOk.OnClick = Callback( this, &CJabberDlgPrivacyAddList::btnOk_OnClick ); + m_btnCancel.OnClick = Callback( this, &CJabberDlgPrivacyAddList::btnCancel_OnClick); + } + + void btnOk_OnClick(CCtrlButton*) + { + GetDlgItemText(m_hwnd, IDC_EDIT_NAME, szLine, SIZEOF(szLine)); + EndDialog(m_hwnd, 1); + } + void btnCancel_OnClick(CCtrlButton*) + { + *szLine = 0; + EndDialog(m_hwnd, 0); + } + +private: + CCtrlEdit m_txtName; + CCtrlButton m_btnOk; + CCtrlButton m_btnCancel; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Privacy rule editor +class CJabberDlgPrivacyRule: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + CCtrlButton m_btnOk; + CCtrlButton m_btnCancel; + CCtrlCombo m_cbType; + +public: + CPrivacyListRule *m_pRule; + + CJabberDlgPrivacyRule(CJabberProto *proto, HWND hwndParent, CPrivacyListRule *pRule): + CJabberDlgBase(proto, IDD_PRIVACY_RULE, hwndParent, false), + m_btnOk(this, IDOK), + m_btnCancel(this, IDCANCEL), + m_cbType(this, IDC_COMBO_TYPE) + { + m_pRule = pRule; + m_cbType.OnChange = Callback(this, &CJabberDlgPrivacyRule::cbType_OnChange); + m_btnOk.OnClick = Callback(this, &CJabberDlgPrivacyRule::btnOk_OnClick); + m_btnCancel.OnClick = Callback(this, &CJabberDlgPrivacyRule::btnCancel_OnClick); + } + + virtual void OnInitDialog() + { + CSuper::OnInitDialog(); + + m_proto->m_hwndPrivacyRule = m_hwnd; + + SendDlgItemMessage(m_hwnd, IDC_ICO_MESSAGE, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_msg_allow"), 0); + SendDlgItemMessage(m_hwnd, IDC_ICO_QUERY, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_iq_allow"), 0); + SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEIN, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_prin_allow"), 0); + SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEOUT, STM_SETICON, (WPARAM)m_proto->LoadIconEx("pl_prout_allow"), 0); + + TCHAR* szTypes[] = { _T("JID"), _T("Group"), _T("Subscription"), _T("Any") }; + int i, nTypes[] = { Jid, Group, Subscription, Else }; + for ( i = 0; i < SIZEOF(szTypes); i++ ) + { + LRESULT nItem = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateTS( szTypes[i] )); + SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_SETITEMDATA, nItem, nTypes[i] ); + if ( m_pRule->GetType() == nTypes[i] ) + SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_SETCURSEL, nItem, 0 ); + } + + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_RESETCONTENT, 0, 0 ); + TCHAR* szSubscriptions[] = { _T("none"), _T("from"), _T("to"), _T("both") }; + for ( i = 0; i < SIZEOF(szSubscriptions); i++ ) + { + LRESULT nItem = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_ADDSTRING, 0, (LPARAM)TranslateTS( szSubscriptions[i] )); + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETITEMDATA, nItem, (LPARAM)szSubscriptions[i] ); + } + + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_COMBO_TYPE, CBN_SELCHANGE ), 0 ); + + SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateTS( _T("Deny" ))); + SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateTS( _T("Allow" ))); + + SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_SETCURSEL, m_pRule->GetAction() ? 1 : 0, 0 ); + + DWORD dwPackets = m_pRule->GetPackets(); + if ( !dwPackets ) + dwPackets = JABBER_PL_RULE_TYPE_ALL; + if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) + SendDlgItemMessage( m_hwnd, IDC_CHECK_QUERIES, BM_SETCHECK, BST_CHECKED, 0 ); + if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) + SendDlgItemMessage( m_hwnd, IDC_CHECK_MESSAGES, BM_SETCHECK, BST_CHECKED, 0 ); + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) + SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_IN, BM_SETCHECK, BST_CHECKED, 0 ); + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) + SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_OUT, BM_SETCHECK, BST_CHECKED, 0 ); + + if ( m_pRule->GetValue() && ( m_pRule->GetType() == Jid || m_pRule->GetType() == Group )) + SetDlgItemText( m_hwnd, IDC_EDIT_VALUE, m_pRule->GetValue()); + } + + void cbType_OnChange(CCtrlData*) + { + if ( !m_pRule ) return; + + LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0 ); + if ( nCurSel == CB_ERR ) + return; + + LRESULT nItemData = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETITEMDATA, nCurSel, 0 ); + switch (nItemData) + { + case Jid: + { + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_SHOW ); + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); + + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_RESETCONTENT, 0, 0 ); + + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) + { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_proto->m_szModuleName )) + { + DBVARIANT dbv; + if ( !m_proto->JGetStringT( hContact, "jid", &dbv )) + { + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)dbv.ptszVal ); + JFreeVariant( &dbv ); + } + } + hContact = db_find_next(hContact); + } + + // append known chatroom jids from bookmarks + LISTFOREACH(i, m_proto, LIST_BOOKMARK) + { + JABBER_LIST_ITEM *item = 0; + if ( item = m_proto->ListGetItemPtrFromIndex( i )) + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)item->jid ); + } + + // FIXME: ugly code :) + if ( m_pRule->GetValue()) + { + SetDlgItemText( m_hwnd, IDC_COMBO_VALUES, m_pRule->GetValue()); + LRESULT nSelPos = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_FINDSTRINGEXACT , -1, (LPARAM)m_pRule->GetValue()); + if ( nSelPos != CB_ERR ) + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_SETCURSEL, nSelPos, 0 ); + } + break; + } + + case Group: + { + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_SHOW ); + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); + + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_RESETCONTENT, 0, 0 ); + + char buf[ 20 ]; + DBVARIANT dbv; + for ( int i = 0; ; i++ ) + { + mir_snprintf(buf, 20, "%d", i); + if ( DBGetContactSettingTString(NULL, "CListGroups", buf, &dbv)) + break; + + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_ADDSTRING, 0, (LPARAM)&dbv.ptszVal[1] ); + DBFreeVariant(&dbv); + } + + // FIXME: ugly code :) + if ( m_pRule->GetValue()) + { + SetDlgItemText( m_hwnd, IDC_COMBO_VALUES, m_pRule->GetValue()); + LRESULT nSelPos = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_FINDSTRINGEXACT , -1, (LPARAM)m_pRule->GetValue()); + if ( nSelPos != CB_ERR ) + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUES, CB_SETCURSEL, nSelPos, 0 ); + } + break; + } + + case Subscription: + { + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_HIDE ); + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_SHOW ); + + if ( m_pRule->GetValue()) + { + LRESULT nSelected = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SELECTSTRING, -1, (LPARAM)TranslateTS(m_pRule->GetValue())); + if ( nSelected == CB_ERR ) + SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETCURSEL, 0, 0 ); + } + else SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_SETCURSEL, 0, 0 ); + break; + } + + case Else: + { + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUES ), SW_HIDE ); + ShowWindow( GetDlgItem( m_hwnd, IDC_COMBO_VALUE ), SW_HIDE ); + break; + } + } + + return; + } + + void btnOk_OnClick(CCtrlButton *) + { + LRESULT nItemData = -1; + LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0 ); + if ( nCurSel != CB_ERR ) + nItemData = SendDlgItemMessage( m_hwnd, IDC_COMBO_TYPE, CB_GETITEMDATA, nCurSel, 0 ); + + switch ( nItemData ) + { + case Jid: + case Group: + { + TCHAR szText[ 512 ]; + GetDlgItemText( m_hwnd, IDC_COMBO_VALUES, szText, SIZEOF(szText)); + m_pRule->SetValue( szText ); + break; + } + case Subscription: + { + nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_GETCURSEL, 0, 0 ); + if ( nCurSel != CB_ERR ) + m_pRule->SetValue(( TCHAR* )SendDlgItemMessage( m_hwnd, IDC_COMBO_VALUE, CB_GETITEMDATA, nCurSel, 0 )); + else + m_pRule->SetValue( _T( "none" )); + break; + } + + default: + m_pRule->SetValue( NULL ); + break; + } + + m_pRule->SetType( ( PrivacyListRuleType )nItemData ); + nCurSel = SendDlgItemMessage( m_hwnd, IDC_COMBO_ACTION, CB_GETCURSEL, 0, 0 ); + if ( nCurSel == CB_ERR ) + nCurSel = 1; + m_pRule->SetAction( nCurSel ? TRUE : FALSE ); + + DWORD dwPackets = 0; + if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_MESSAGES, BM_GETCHECK, 0, 0 )) + dwPackets |= JABBER_PL_RULE_TYPE_MESSAGE; + if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_IN, BM_GETCHECK, 0, 0 )) + dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_IN; + if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_PRESENCE_OUT, BM_GETCHECK, 0, 0 )) + dwPackets |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; + if ( BST_CHECKED == SendDlgItemMessage( m_hwnd, IDC_CHECK_QUERIES, BM_GETCHECK, 0, 0 )) + dwPackets |= JABBER_PL_RULE_TYPE_IQ; + if ( !dwPackets ) + dwPackets = JABBER_PL_RULE_TYPE_ALL; + + m_pRule->SetPackets( dwPackets ); + + EndDialog( m_hwnd, 1 ); + } + + void btnCancel_OnClick(CCtrlButton *) + { + EndDialog(m_hwnd, 0); + } + + void OnDestroy() + { + g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_MESSAGE, STM_SETICON, 0, 0)); + g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_QUERY, STM_SETICON, 0, 0)); + g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEIN, STM_SETICON, 0, 0)); + g_ReleaseIcon(( HICON )SendDlgItemMessage(m_hwnd, IDC_ICO_PRESENCEOUT, STM_SETICON, 0, 0)); + m_proto->m_hwndPrivacyRule = NULL; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Main privacy list dialog +class CJabberDlgPrivacyLists: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgPrivacyLists(CJabberProto *proto); + +protected: + static int idSimpleControls[]; + static int idAdvancedControls[]; + + void OnInitDialog(); + void OnClose(); + void OnDestroy(); + void OnProtoRefresh(WPARAM, LPARAM); + int Resizer(UTILRESIZECONTROL *urc); + + UI_MESSAGE_MAP(CJabberDlgPrivacyLists, CSuper); + UI_MESSAGE(WM_MEASUREITEM, OnWmMeasureItem); + UI_MESSAGE(WM_DRAWITEM, OnWmDrawItem); + UI_MESSAGE(WM_GETMINMAXINFO, OnWmGetMinMaxInfo); + UI_MESSAGE_MAP_END(); + + BOOL OnWmMeasureItem(UINT msg, WPARAM wParam, LPARAM lParam); + BOOL OnWmDrawItem(UINT msg, WPARAM wParam, LPARAM lParam); + BOOL OnWmGetMinMaxInfo(UINT msg, WPARAM wParam, LPARAM lParam); + + void btnSimple_OnClick(CCtrlButton *); + void btnAdvanced_OnClick(CCtrlButton *); + void btnAddJid_OnClick(CCtrlButton *); + void btnActivate_OnClick(CCtrlButton *); + void btnSetDefault_OnClick(CCtrlButton *); + void lbLists_OnSelChange(CCtrlListBox *); + void lbLists_OnDblClick(CCtrlListBox *); + void lbRules_OnSelChange(CCtrlListBox *); + void lbRules_OnDblClick(CCtrlListBox *); + void btnEditRule_OnClick(CCtrlButton *); + void btnAddRule_OnClick(CCtrlButton *); + void btnRemoveRule_OnClick(CCtrlButton *); + void btnUpRule_OnClick(CCtrlButton *); + void btnDownRule_OnClick(CCtrlButton *); + void btnAddList_OnClick(CCtrlButton *); + void btnRemoveList_OnClick(CCtrlButton *); + void btnApply_OnClick(CCtrlButton *); + void clcClist_OnUpdate(CCtrlClc::TEventInfo *evt); + void clcClist_OnOptionsChanged(CCtrlClc::TEventInfo *evt); + void clcClist_OnClick(CCtrlClc::TEventInfo *evt); + + void OnCommand_Close(HWND hwndCtrl, WORD idCtrl, WORD idCode); + + void ShowAdvancedList(CPrivacyList *pList); + void DrawNextRulePart(HDC hdc, COLORREF color, const TCHAR *text, RECT *rc); + void DrawRuleAction(HDC hdc, COLORREF clLine1, COLORREF clLine2, CPrivacyListRule *pRule, RECT *rc); + void DrawRulesList(LPDRAWITEMSTRUCT lpdis); + void DrawLists(LPDRAWITEMSTRUCT lpdis); + + void CListResetOptions(HWND hwndList); + void CListFilter(HWND hwndList); + bool CListIsGroup(HANDLE hGroup); + HANDLE CListFindGroupByName(TCHAR *name); + void CListResetIcons(HWND hwndList, HANDLE hItem, bool hide=false); + void CListSetupIcons(HWND hwndList, HANDLE hItem, int iSlot, DWORD dwProcess, BOOL bAction); + HANDLE CListAddContact(HWND hwndList, TCHAR *jid); + void CListApplyList(HWND hwndList, CPrivacyList *pList = NULL); + DWORD CListGetPackets(HWND hwndList, HANDLE hItem, bool bAction); + void CListBuildList(HWND hwndList, CPrivacyList *pList); + + void EnableEditorControls(); + BOOL CanExit(); + + static LRESULT CALLBACK LstListsSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK LstRulesSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + struct TCLCInfo + { + struct TJidData + { + HANDLE hItem; + TCHAR *jid; + + static int cmp(const TJidData *p1, const TJidData *p2) { return lstrcmp(p1->jid, p2->jid); } + }; + + HANDLE hItemDefault; + HANDLE hItemSubNone; + HANDLE hItemSubTo; + HANDLE hItemSubFrom; + HANDLE hItemSubBoth; + + LIST<TJidData> newJids; + + bool bChanged; + + CPrivacyList *pList; + + TCLCInfo(): newJids(1, TJidData::cmp), bChanged(false), pList(0) {} + ~TCLCInfo() + { + for (int i = 0; i < newJids.getCount(); ++i) + { + mir_free(newJids[i]->jid); + mir_free(newJids[i]); + } + newJids.destroy(); + } + + void addJid(HANDLE hItem, TCHAR *jid) + { + TJidData *data = (TJidData *)mir_alloc(sizeof(TJidData)); + data->hItem = hItem; + data->jid = mir_tstrdup(jid); + newJids.insert(data); + } + + HANDLE findJid(TCHAR *jid) + { + TJidData data = {0}; + data.jid = jid; + TJidData *found = newJids.find(&data); + return found ? found->hItem : 0; + } + }; + + TCLCInfo clc_info; + +private: + CCtrlMButton m_btnSimple; + CCtrlMButton m_btnAdvanced; + CCtrlMButton m_btnAddJid; + CCtrlMButton m_btnActivate; + CCtrlMButton m_btnSetDefault; + CCtrlMButton m_btnEditRule; + CCtrlMButton m_btnAddRule; + CCtrlMButton m_btnRemoveRule; + CCtrlMButton m_btnUpRule; + CCtrlMButton m_btnDownRule; + CCtrlMButton m_btnAddList; + CCtrlMButton m_btnRemoveList; + CCtrlButton m_btnApply; + CCtrlListBox m_lbLists; + CCtrlListBox m_lbRules; + CCtrlClc m_clcClist; +}; + +int CJabberDlgPrivacyLists::idSimpleControls[] = +{ + IDC_CLIST, IDC_CANVAS, + IDC_TXT_OTHERJID, IDC_NEWJID, IDC_ADDJID, + IDC_ICO_MESSAGE, IDC_ICO_QUERY, IDC_ICO_INPRESENCE, IDC_ICO_OUTPRESENCE, + IDC_TXT_MESSAGE, IDC_TXT_QUERY, IDC_TXT_INPRESENCE, IDC_TXT_OUTPRESENCE, + 0 +}; + +int CJabberDlgPrivacyLists::idAdvancedControls[] = +{ + IDC_PL_RULES_LIST, + IDC_ADD_RULE, IDC_EDIT_RULE, IDC_REMOVE_RULE, + IDC_UP_RULE, IDC_DOWN_RULE, + 0 +}; + +CJabberDlgPrivacyLists::CJabberDlgPrivacyLists(CJabberProto *proto): + CSuper(proto, IDD_PRIVACY_LISTS, NULL), + m_btnSimple(this, IDC_BTN_SIMPLE, proto->LoadIconEx("group"), LPGEN("Simple mode")), + m_btnAdvanced(this, IDC_BTN_ADVANCED, proto->LoadIconEx("sd_view_list"), LPGEN("Advanced mode")), + m_btnAddJid(this, IDC_ADDJID, proto->LoadIconEx("addroster"), LPGEN("Add JID")), + m_btnActivate(this, IDC_ACTIVATE, proto->LoadIconEx("pl_list_active"), LPGEN("Activate")), + m_btnSetDefault(this, IDC_SET_DEFAULT, proto->LoadIconEx("pl_list_default"), LPGEN("Set default")), + m_btnEditRule(this, IDC_EDIT_RULE, SKINICON_OTHER_RENAME, LPGEN("Edit rule")), + m_btnAddRule(this, IDC_ADD_RULE, SKINICON_OTHER_ADDCONTACT, LPGEN("Add rule")), + m_btnRemoveRule(this, IDC_REMOVE_RULE, SKINICON_OTHER_DELETE, LPGEN("Delete rule")), + m_btnUpRule(this, IDC_UP_RULE, proto->LoadIconEx("arrow_up"), LPGEN("Move rule up")), + m_btnDownRule(this, IDC_DOWN_RULE, proto->LoadIconEx("arrow_down"), LPGEN("Move rule down")), + m_btnAddList(this, IDC_ADD_LIST, SKINICON_OTHER_ADDCONTACT, LPGEN("Add list...")), + m_btnRemoveList(this, IDC_REMOVE_LIST, SKINICON_OTHER_DELETE, LPGEN("Remove list")), + m_btnApply(this, IDC_APPLY), + m_lbLists(this, IDC_LB_LISTS), + m_lbRules(this, IDC_PL_RULES_LIST), + m_clcClist(this, IDC_CLIST) +{ + m_btnSimple.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnSimple_OnClick); + m_btnAdvanced.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAdvanced_OnClick); + m_btnAddJid.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddJid_OnClick); + m_btnActivate.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnActivate_OnClick); + m_btnSetDefault.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnSetDefault_OnClick); + m_btnEditRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnEditRule_OnClick); + m_btnAddRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddRule_OnClick); + m_btnRemoveRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnRemoveRule_OnClick); + m_btnUpRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnUpRule_OnClick); + m_btnDownRule.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnDownRule_OnClick); + m_btnAddList.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnAddList_OnClick); + m_btnRemoveList.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnRemoveList_OnClick); + m_btnApply.OnClick = Callback( this, &CJabberDlgPrivacyLists::btnApply_OnClick); + + m_lbLists.OnSelChange = Callback(this, &CJabberDlgPrivacyLists::lbLists_OnSelChange); + m_lbLists.OnDblClick = Callback(this, &CJabberDlgPrivacyLists::lbLists_OnDblClick); + m_lbRules.OnSelChange = Callback(this, &CJabberDlgPrivacyLists::lbRules_OnSelChange); + m_lbRules.OnDblClick = Callback(this, &CJabberDlgPrivacyLists::lbRules_OnDblClick); + + m_clcClist.OnNewContact = + m_clcClist.OnListRebuilt = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnUpdate); + m_clcClist.OnOptionsChanged = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnOptionsChanged); + m_clcClist.OnClick = Callback(this, &CJabberDlgPrivacyLists::clcClist_OnClick); +} + +void CJabberDlgPrivacyLists::OnInitDialog() +{ + CSuper::OnInitDialog(); + + WindowSetIcon( m_hwnd, m_proto, "privacylists" ); + + EnableWindow( GetDlgItem( m_hwnd, IDC_ADD_RULE ), FALSE ); + EnableWindow( GetDlgItem( m_hwnd, IDC_EDIT_RULE ), FALSE ); + EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_RULE ), FALSE ); + EnableWindow( GetDlgItem( m_hwnd, IDC_UP_RULE ), FALSE ); + EnableWindow( GetDlgItem( m_hwnd, IDC_DOWN_RULE ), FALSE ); + + m_proto->QueryPrivacyLists(); + + LOGFONT lf; + GetObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_GETFONT, 0, 0), sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + HFONT hfnt = CreateFontIndirect(&lf); + SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_SETFONT, (WPARAM)hfnt, TRUE); + SendDlgItemMessage(m_hwnd, IDC_TXT_RULES, WM_SETFONT, (WPARAM)hfnt, TRUE); + + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE, + GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_CLIST), GWL_STYLE)|CLS_HIDEEMPTYGROUPS|CLS_USEGROUPS|CLS_GREYALTERNATE); + m_clcClist.SetExStyle(CLS_EX_DISABLEDRAGDROP|CLS_EX_TRACKSELECT); + + HIMAGELIST hIml = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,9,9); + ImageList_AddIcon_Icolib(hIml, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT)); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_msg_allow")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_msg_deny")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prin_allow")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prin_deny")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prout_allow")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_prout_deny")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_iq_allow")); + ImageList_AddIcon_Icolib(hIml, m_proto->LoadIconEx("pl_iq_deny")); + m_clcClist.SetExtraImageList(hIml); + m_clcClist.SetExtraColumns(4); + + m_btnSimple.MakePush(); + m_btnAdvanced.MakePush(); + + CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + + cii.flags = CLCIIF_GROUPFONT; + cii.pszText = TranslateT("** Default **"); + clc_info.hItemDefault = m_clcClist.AddInfoItem(&cii); + cii.pszText = TranslateT("** Subsription: both **"); + clc_info.hItemSubBoth = m_clcClist.AddInfoItem(&cii); + cii.pszText = TranslateT("** Subsription: to **"); + clc_info.hItemSubTo = m_clcClist.AddInfoItem(&cii); + cii.pszText = TranslateT("** Subsription: from **"); + clc_info.hItemSubFrom = m_clcClist.AddInfoItem(&cii); + cii.pszText = TranslateT("** Subsription: none **"); + clc_info.hItemSubNone = m_clcClist.AddInfoItem(&cii); + + CListResetOptions(GetDlgItem(m_hwnd, IDC_CLIST)); + CListFilter(GetDlgItem(m_hwnd, IDC_CLIST)); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST)); + + if ( DBGetContactSettingByte(NULL, m_proto->m_szModuleName, "plistsWnd_simpleMode", 1)) + { + UIShowControls(m_hwnd, idSimpleControls, SW_SHOW); + UIShowControls(m_hwnd, idAdvancedControls, SW_HIDE); + CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, TRUE); + } else + { + UIShowControls(m_hwnd, idSimpleControls, SW_HIDE); + UIShowControls(m_hwnd, idAdvancedControls, SW_SHOW); + CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, TRUE); + } + + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LB_LISTS), GWLP_USERDATA, + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LB_LISTS), GWLP_WNDPROC, (LONG_PTR)LstListsSubclassProc)); + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PL_RULES_LIST), GWLP_USERDATA, + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PL_RULES_LIST), GWLP_WNDPROC, (LONG_PTR)LstRulesSubclassProc)); + + SetStatusText(TranslateT("Loading...")); + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "plistsWnd_sz"); +} + +void CJabberDlgPrivacyLists::OnClose() +{ + if (CanExit()) { + DestroyWindow(m_hwnd); + CSuper::OnClose(); + } + else + m_lresult = TRUE; +} + +void CJabberDlgPrivacyLists::OnDestroy() +{ + m_proto->m_pDlgPrivacyLists = NULL; + + // Wipe all data and query lists without contents + m_proto->m_privacyListManager.RemoveAllLists(); + m_proto->QueryPrivacyLists(); + m_proto->m_privacyListManager.SetModified( FALSE ); + + // Delete custom bold font + DeleteObject((HFONT)SendDlgItemMessage(m_hwnd, IDC_TXT_LISTS, WM_GETFONT, 0, 0)); + + DBWriteContactSettingByte(NULL, m_proto->m_szModuleName, "plistsWnd_simpleMode", IsDlgButtonChecked(m_hwnd, IDC_BTN_SIMPLE)); + + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "plistsWnd_sz"); + + CSuper::OnDestroy(); +} + +void CJabberDlgPrivacyLists::OnProtoRefresh(WPARAM, LPARAM) +{ + LRESULT sel = SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0); + TCHAR *szCurrentSelectedList = NULL; + if ( sel != LB_ERR ) { + LRESULT len = SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETTEXTLEN, sel, 0) + 1; + szCurrentSelectedList = (TCHAR *)mir_alloc(len * sizeof(TCHAR)); + SendDlgItemMessage(m_hwnd, IDC_LB_LISTS, LB_GETTEXT, sel, (LPARAM)szCurrentSelectedList); + } + + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_RESETCONTENT, 0, 0 ); + + LRESULT nItemId = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)TranslateT( "<none>" )); + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nItemId, (LPARAM)NULL ); + + m_proto->m_privacyListManager.Lock(); + CPrivacyList* pList = m_proto->m_privacyListManager.GetFirstList(); + while ( pList ) { + if ( !pList->IsDeleted()) { + nItemId = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)pList->GetListName()); + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nItemId, (LPARAM)pList ); + } + pList = pList->GetNext(); + } + + if ( !szCurrentSelectedList || ( SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SELECTSTRING, -1, (LPARAM)szCurrentSelectedList ) == LB_ERR )) + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETCURSEL, 0, 0 ); + if ( szCurrentSelectedList ) + mir_free( szCurrentSelectedList ); + + m_proto->m_privacyListManager.Unlock(); + + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_LB_LISTS, LBN_SELCHANGE ), 0 ); + EnableEditorControls(); +} + +BOOL CJabberDlgPrivacyLists::OnWmMeasureItem(UINT, WPARAM, LPARAM lParam) +{ + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; + if ((lpmis->CtlID != IDC_PL_RULES_LIST) && (lpmis->CtlID != IDC_LB_LISTS)) + return FALSE; + + TEXTMETRIC tm = {0}; + HDC hdc = GetDC(GetDlgItem(m_hwnd, lpmis->CtlID)); + GetTextMetrics(hdc, &tm); + ReleaseDC(GetDlgItem(m_hwnd, lpmis->CtlID), hdc); + + if (lpmis->CtlID == IDC_PL_RULES_LIST) + lpmis->itemHeight = tm.tmHeight * 2; + else if (lpmis->CtlID == IDC_LB_LISTS) + lpmis->itemHeight = tm.tmHeight; + + if (lpmis->itemHeight < 18) lpmis->itemHeight = 18; + + return TRUE; +} + +BOOL CJabberDlgPrivacyLists::OnWmDrawItem(UINT, WPARAM, LPARAM lParam) +{ + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + + if (lpdis->CtlID == IDC_PL_RULES_LIST) + DrawRulesList(lpdis); + else if (lpdis->CtlID == IDC_LB_LISTS) + DrawLists(lpdis); + else if (lpdis->CtlID == IDC_CANVAS) + { + static struct + { + TCHAR *textEng; + char *icon; + TCHAR *text; + } items[] = + { + { _T("Message"), "pl_msg_allow" }, + { _T("Presence (in)"), "pl_prin_allow" }, + { _T("Presence (out)"), "pl_prout_allow" }, + { _T("Query"), "pl_iq_allow" }, + }; + + int i, totalWidth = -5; // spacing for last item + for (i = 0; i < SIZEOF(items); ++i) + { + SIZE sz = {0}; + if (!items[i].text) items[i].text = TranslateTS(items[i].textEng); + GetTextExtentPoint32(lpdis->hDC, items[i].text, lstrlen(items[i].text), &sz); + totalWidth += sz.cx + 18 + 5; // 18 pixels for icon, 5 pixel spacing + } + + COLORREF clText = GetSysColor(COLOR_BTNTEXT); + RECT rc = lpdis->rcItem; + rc.left = (rc.left + rc.right - totalWidth)/2; + + for (i = 0; i < SIZEOF(items); ++i) + { + DrawIconEx(lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, m_proto->LoadIconEx(items[i].icon), + 16, 16, 0, NULL, DI_NORMAL); + rc.left += 18; + DrawNextRulePart(lpdis->hDC, clText, items[i].text, &rc); + rc.left += 5; + } + } + else return FALSE; + + return TRUE; +} + +BOOL CJabberDlgPrivacyLists::OnWmGetMinMaxInfo(UINT, WPARAM, LPARAM lParam) +{ + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 550; + lpmmi->ptMinTrackSize.y = 390; + return 0; +} + +void CJabberDlgPrivacyLists::ShowAdvancedList(CPrivacyList *pList) +{ + int nLbSel = SendDlgItemMessage(m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_RESETCONTENT, 0, 0 ); + + BOOL bListEmpty = TRUE; + + CPrivacyListRule* pRule = pList->GetFirstRule(); + + while ( pRule ) { + bListEmpty = FALSE; + TCHAR szTypeValue[ 512 ]; + switch ( pRule->GetType()) { + case Jid: + mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If jabber id is '%s' then" ), pRule->GetValue()); + break; + case Group: + mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If group is '%s' then" ), pRule->GetValue()); + break; + case Subscription: + mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "If subscription is '%s' then" ), pRule->GetValue()); + break; + case Else: + mir_sntprintf( szTypeValue, SIZEOF( szTypeValue ), _T( "Else")); + break; + } + + TCHAR szPackets[ 512 ]; + szPackets[ 0 ] = '\0'; + + DWORD dwPackets = pRule->GetPackets(); + if ( !dwPackets ) + dwPackets = JABBER_PL_RULE_TYPE_ALL; + if ( dwPackets == JABBER_PL_RULE_TYPE_ALL ) + _tcscpy( szPackets, _T("all")); + else { + if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) + _tcscat( szPackets, _T("messages")); + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) { + if ( _tcslen( szPackets )) + _tcscat( szPackets, _T(", ")); + _tcscat( szPackets, _T("presence-in")); + } + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) { + if ( _tcslen( szPackets )) + _tcscat( szPackets, _T(", ")); + _tcscat( szPackets, _T("presence-out")); + } + if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) { + if ( _tcslen( szPackets )) + _tcscat( szPackets, _T(", ")); + _tcscat( szPackets, _T("queries")); + } } + + TCHAR szListItem[ 512 ]; + mir_sntprintf( szListItem, SIZEOF( szListItem ), _T("%s %s %s"), szTypeValue, pRule->GetAction() ? _T("allow") : _T("deny"), szPackets ); + + LRESULT nItemId = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)szListItem ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETITEMDATA, nItemId, (LPARAM)pRule ); + + pRule = pRule->GetNext(); + } + + EnableWindow( GetDlgItem( m_hwnd, IDC_PL_RULES_LIST ), !bListEmpty ); + if ( bListEmpty ) + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)TranslateTS(_T("List has no rules, empty lists will be deleted then changes applied"))); + else + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nLbSel, 0 ); + + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_PL_RULES_LIST, LBN_SELCHANGE ), 0 ); +} + +void CJabberDlgPrivacyLists::DrawNextRulePart(HDC hdc, COLORREF color, const TCHAR *text, RECT *rc) +{ + SetTextColor(hdc, color); + DrawText(hdc, text, lstrlen(text), rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS); + + SIZE sz; + GetTextExtentPoint32(hdc, text, lstrlen(text), &sz); + rc->left += sz.cx; +} + +void CJabberDlgPrivacyLists::DrawRuleAction(HDC hdc, COLORREF clLine1, COLORREF, CPrivacyListRule *pRule, RECT *rc) +{ + DrawNextRulePart(hdc, clLine1, pRule->GetAction() ? TranslateT("allow ") : TranslateT("deny "), rc); + if (!pRule->GetPackets() || (pRule->GetPackets() == JABBER_PL_RULE_TYPE_ALL)) + { + DrawNextRulePart(hdc, clLine1, TranslateT("all."), rc); + } else + { + bool needComma = false; + int itemCount = + ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_MESSAGE) ? 1 : 0) + + ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_IN) ? 1 : 0) + + ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_OUT) ? 1 : 0) + + ((pRule->GetPackets() & JABBER_PL_RULE_TYPE_IQ) ? 1 : 0); + + if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_MESSAGE) + { + --itemCount; + needComma = true; + DrawNextRulePart(hdc, clLine1, TranslateT("messages"), rc); + } + if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_IN) + { + --itemCount; + if (needComma) + DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); + needComma = true; + DrawNextRulePart(hdc, clLine1, TranslateT("incoming presences"), rc); + } + if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_PRESENCE_OUT) + { + --itemCount; + if (needComma) + DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); + needComma = true; + DrawNextRulePart(hdc, clLine1, TranslateT("outgoing presences"), rc); + } + if (pRule->GetPackets() & JABBER_PL_RULE_TYPE_IQ) + { + --itemCount; + if (needComma) + DrawNextRulePart(hdc, clLine1, itemCount ? _T(", ") : TranslateT(" and "), rc); + needComma = true; + DrawNextRulePart(hdc, clLine1, TranslateT("queries"), rc); + } + DrawNextRulePart(hdc, clLine1, _T("."), rc); + } +} + +void CJabberDlgPrivacyLists::DrawRulesList(LPDRAWITEMSTRUCT lpdis) +{ + if (lpdis->itemID == -1) + return; + + CPrivacyListRule *pRule = (CPrivacyListRule *)lpdis->itemData; + + COLORREF clLine1, clLine2, clBack; + if (lpdis->itemState & ODS_SELECTED) + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + clBack = GetSysColor(COLOR_HIGHLIGHT); + clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); + } else + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); + clBack = GetSysColor(COLOR_WINDOW); + clLine1 = GetSysColor(COLOR_WINDOWTEXT); + } + clLine2 = RGB( + GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, + GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, + GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 + ); + + SetBkMode(lpdis->hDC, TRANSPARENT); + + RECT rc; + + if ( !pRule ) { + rc = lpdis->rcItem; + rc.left += 25; + + int len = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETTEXTLEN, lpdis->itemID, 0) + 1; + TCHAR *str = (TCHAR *)_alloca(len * sizeof(TCHAR)); + SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETTEXT, lpdis->itemID, (LPARAM)str); + DrawNextRulePart(lpdis->hDC, clLine1, str, &rc); + } + else if (pRule->GetType() == Else) { + rc = lpdis->rcItem; + rc.left += 25; + + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("Else "), &rc); + DrawRuleAction(lpdis->hDC, clLine1, clLine2, pRule, &rc); + } + else { + rc = lpdis->rcItem; + rc.bottom -= (rc.bottom - rc.top) / 2; + rc.left += 25; + + switch ( pRule->GetType()) + { + case Jid: + { + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If jabber id is '"), &rc); + DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); + + if (HANDLE hContact = m_proto->HContactFromJID(pRule->GetValue())) { + TCHAR *szName = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + if ( szName ) { + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (nickname: "), &rc); + DrawNextRulePart(lpdis->hDC, clLine1, szName, &rc); + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(")"), &rc); + } } + break; + } + + case Group: + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If group is '"), &rc); + DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); + break; + case Subscription: + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("If subscription is '"), &rc); + DrawNextRulePart(lpdis->hDC, clLine1, pRule->GetValue(), &rc); + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("'"), &rc); + break; + } + + rc = lpdis->rcItem; + rc.top += (rc.bottom - rc.top) / 2; + rc.left += 25; + + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT("then "), &rc); + DrawRuleAction(lpdis->hDC, clLine1, clLine2, pRule, &rc); + } + + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, + m_proto->LoadIconEx("main"), 16, 16, 0, NULL, DI_NORMAL); + + if (pRule) + { + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, + m_proto->LoadIconEx(pRule->GetAction() ? "disco_ok" : "disco_fail"), + 16, 16, 0, NULL, DI_NORMAL); + } + + if (lpdis->itemState & ODS_FOCUS) + { + LRESULT sel = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETCURSEL, 0, 0); + if ((sel == LB_ERR) || (sel == (LRESULT)lpdis->itemID)) + DrawFocusRect(lpdis->hDC, &lpdis->rcItem); + } +} + +void CJabberDlgPrivacyLists::DrawLists(LPDRAWITEMSTRUCT lpdis) +{ + if (lpdis->itemID == -1) + return; + + CPrivacyList *pList = (CPrivacyList *)lpdis->itemData; + + COLORREF clLine1, clLine2, clBack; + if (lpdis->itemState & ODS_SELECTED) + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + clBack = GetSysColor(COLOR_HIGHLIGHT); + clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); + } else + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); + clBack = GetSysColor(COLOR_WINDOW); + clLine1 = GetSysColor(COLOR_WINDOWTEXT); + } + clLine2 = RGB( + GetRValue(clLine1) * 0.66 + GetRValue(clBack) * 0.34, + GetGValue(clLine1) * 0.66 + GetGValue(clBack) * 0.34, + GetBValue(clLine1) * 0.66 + GetBValue(clBack) * 0.34 + ); + + SetBkMode(lpdis->hDC, TRANSPARENT); + + RECT rc; + m_proto->m_privacyListManager.Lock(); + TCHAR *szDefault = NEWTSTR_ALLOCA(m_proto->m_privacyListManager.GetDefaultListName()); + TCHAR *szActive = NEWTSTR_ALLOCA(m_proto->m_privacyListManager.GetActiveListName()); + m_proto->m_privacyListManager.Unlock(); + + rc = lpdis->rcItem; + rc.left +=3; + + bool bActive = false; + bool bDefault = false; + TCHAR *szName; + + if (!pList) + { + if (!szActive) bActive = true; + if (!szDefault) bDefault = true; + szName = TranslateT("<none>"); + } else + { + if (!lstrcmp(pList->GetListName(), szActive)) bActive = true; + if (!lstrcmp(pList->GetListName(), szDefault)) bDefault = true; + szName = pList->GetListName(); + } + + HFONT hfnt = NULL; + if (bActive) + { + LOGFONT lf; + GetObject(GetCurrentObject(lpdis->hDC, OBJ_FONT), sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + hfnt = (HFONT)SelectObject(lpdis->hDC, CreateFontIndirect(&lf)); + } + + DrawNextRulePart(lpdis->hDC, clLine1, szName, &rc); + + if (bActive && bDefault) + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (act., def.)"), &rc); + else if (bActive) + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (active)"), &rc); + else if (bDefault) + DrawNextRulePart(lpdis->hDC, clLine2, TranslateT(" (default)"), &rc); + + DrawIconEx(lpdis->hDC, lpdis->rcItem.right-16-4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, + m_proto->LoadIconEx(bActive ? "pl_list_active" : "pl_list_any"), + 16, 16, 0, NULL, DI_NORMAL); + + if (bDefault) + DrawIconEx(lpdis->hDC, lpdis->rcItem.right-16-4, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, + m_proto->LoadIconEx("disco_ok"), + 16, 16, 0, NULL, DI_NORMAL); + + if (hfnt) + DeleteObject(SelectObject(lpdis->hDC, hfnt)); + + if (lpdis->itemState & ODS_FOCUS) + { + int sel = SendDlgItemMessage(m_hwnd, lpdis->CtlID, LB_GETCURSEL, 0, 0); + if ((sel == LB_ERR) || (sel == (int)lpdis->itemID)) + DrawFocusRect(lpdis->hDC, &lpdis->rcItem); + } +} + +void CJabberDlgPrivacyLists::CListResetOptions(HWND) +{ + m_clcClist.SetBkBitmap(0, NULL); + m_clcClist.SetBkColor(GetSysColor(COLOR_WINDOW)); + m_clcClist.SetGreyoutFlags(0); + m_clcClist.SetLeftMargin(4); + m_clcClist.SetIndent(10); + m_clcClist.SetHideEmptyGroups(false); + m_clcClist.SetHideOfflineRoot(false); + for (int i = 0; i <= FONTID_MAX; i++) + m_clcClist.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT)); +} + +void CJabberDlgPrivacyLists::CListFilter(HWND) +{ + for (HANDLE hContact = db_find_first(); + hContact; + hContact = db_find_next(hContact)) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (!proto || lstrcmpA(proto, m_proto->m_szModuleName)) + if (HANDLE hItem = m_clcClist.FindContact(hContact)) + m_clcClist.DeleteItem(hItem); + } +} + +bool CJabberDlgPrivacyLists::CListIsGroup(HANDLE hGroup) +{ + char idstr[33]; + _i64toa((INT_PTR)hGroup-1, idstr, 10); + + DBVARIANT dbv; + bool result = DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv) == 0; + if ( result ) + DBFreeVariant(&dbv); + + return result; +} + +HANDLE CJabberDlgPrivacyLists::CListFindGroupByName(TCHAR *name) +{ + char idstr[33]; + DBVARIANT dbv; + + HANDLE hGroup = 0; + + for (int i= 0; !hGroup; ++i) + { + _itoa(i, idstr, 10); + + if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv)) + break; + + if (!_tcscmp(dbv.ptszVal + 1, name)) + hGroup = (HANDLE)(i+1); + + DBFreeVariant(&dbv); + } + + return hGroup; +} + +void CJabberDlgPrivacyLists::CListResetIcons(HWND, HANDLE hItem, bool hide) +{ + for (int i = 0; i < 4; ++i) + m_clcClist.SetExtraImage(hItem, i, hide ? 0xFF : 0); +} + +void CJabberDlgPrivacyLists::CListSetupIcons(HWND, HANDLE hItem, int iSlot, DWORD dwProcess, BOOL bAction) +{ + if (dwProcess && !m_clcClist.GetExtraImage(hItem, iSlot)) + m_clcClist.SetExtraImage(hItem, iSlot, iSlot*2 + (bAction?1:2)); +} + +HANDLE CJabberDlgPrivacyLists::CListAddContact(HWND hwndList, TCHAR *jid) +{ + HANDLE hItem = 0; + + HANDLE hContact = m_proto->HContactFromJID(jid); + if ( !hContact ) { + hItem = clc_info.findJid(jid); + if (!hItem) + { + CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + cii.pszText = jid; + hItem = m_clcClist.AddInfoItem(&cii); + CListResetIcons(hwndList, hItem); + clc_info.addJid(hItem, jid); + } + } else + { + hItem = m_clcClist.FindContact(hContact); + } + + return hItem; +} + +void CJabberDlgPrivacyLists::CListApplyList(HWND hwndList, CPrivacyList *pList) +{ + clc_info.pList = pList; + + bool bHideIcons = pList ? false : true; + + CListResetIcons(hwndList, clc_info.hItemDefault, bHideIcons); + CListResetIcons(hwndList, clc_info.hItemSubBoth, bHideIcons); + CListResetIcons(hwndList, clc_info.hItemSubFrom, bHideIcons); + CListResetIcons(hwndList, clc_info.hItemSubNone, bHideIcons); + CListResetIcons(hwndList, clc_info.hItemSubTo, bHideIcons); + + // group handles start with 1 (0 is "root") + for (int iGroup = 1; CListIsGroup((HANDLE)iGroup); ++iGroup) + { + HANDLE hItem = m_clcClist.FindGroup((HANDLE)iGroup); + if (!hItem) continue; + CListResetIcons(hwndList, hItem, bHideIcons); + } + + for (HANDLE hContact=db_find_first(); hContact; + hContact=db_find_next(hContact)) + { + HANDLE hItem = m_clcClist.FindContact(hContact); + if (!hItem) continue; + CListResetIcons(hwndList, hItem, bHideIcons); + } + + for (int iJid = 0; iJid < clc_info.newJids.getCount(); ++iJid) + CListResetIcons(hwndList, clc_info.newJids[iJid]->hItem, bHideIcons); + + if (!pList) + goto lbl_return; + + CPrivacyListRule *pRule; + for (pRule = pList->GetFirstRule(); pRule; pRule = pRule->GetNext()) + { + HANDLE hItem = 0; + switch (pRule->GetType()) + { + case Jid: + { + hItem = CListAddContact(hwndList, pRule->GetValue()); + break; + } + case Group: + { + HANDLE hGroup = CListFindGroupByName(pRule->GetValue()); + hItem = m_clcClist.FindGroup(hGroup); + break; + } + case Subscription: + { + if (!lstrcmp(pRule->GetValue(), _T("none"))) hItem = clc_info.hItemSubNone; + else if (!lstrcmp(pRule->GetValue(), _T("from"))) hItem = clc_info.hItemSubFrom; + else if (!lstrcmp(pRule->GetValue(), _T("to"))) hItem = clc_info.hItemSubTo; + else if (!lstrcmp(pRule->GetValue(), _T("both"))) hItem = clc_info.hItemSubBoth; + break; + } + case Else: + { + hItem = clc_info.hItemDefault; + break; + } + } + + if (!hItem) continue; + + DWORD dwPackets = pRule->GetPackets(); + if (!dwPackets) dwPackets = JABBER_PL_RULE_TYPE_ALL; + CListSetupIcons(hwndList, hItem, 0, dwPackets & JABBER_PL_RULE_TYPE_MESSAGE, pRule->GetAction()); + CListSetupIcons(hwndList, hItem, 1, dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN, pRule->GetAction()); + CListSetupIcons(hwndList, hItem, 2, dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT, pRule->GetAction()); + CListSetupIcons(hwndList, hItem, 3, dwPackets & JABBER_PL_RULE_TYPE_IQ, pRule->GetAction()); + } + +lbl_return: + clc_info.bChanged = false; +} + +DWORD CJabberDlgPrivacyLists::CListGetPackets(HWND, HANDLE hItem, bool bAction) +{ + DWORD result = 0; + + int iIcon = 0; + + iIcon = m_clcClist.GetExtraImage(hItem, 0); + if ( bAction && (iIcon == 1)) result |= JABBER_PL_RULE_TYPE_MESSAGE; + else if (!bAction && (iIcon == 2)) result |= JABBER_PL_RULE_TYPE_MESSAGE; + + iIcon = m_clcClist.GetExtraImage(hItem, 1); + if ( bAction && (iIcon == 3)) result |= JABBER_PL_RULE_TYPE_PRESENCE_IN; + else if (!bAction && (iIcon == 4)) result |= JABBER_PL_RULE_TYPE_PRESENCE_IN; + + iIcon = m_clcClist.GetExtraImage(hItem, 2); + if ( bAction && (iIcon == 5)) result |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; + else if (!bAction && (iIcon == 6)) result |= JABBER_PL_RULE_TYPE_PRESENCE_OUT; + + iIcon = m_clcClist.GetExtraImage(hItem, 3); + if ( bAction && (iIcon == 7)) result |= JABBER_PL_RULE_TYPE_IQ; + else if (!bAction && (iIcon == 8)) result |= JABBER_PL_RULE_TYPE_IQ; + + return result; +} + +void CJabberDlgPrivacyLists::CListBuildList(HWND hwndList, CPrivacyList *pList) +{ + if (!pList) return; + + if (!clc_info.bChanged) return; + + clc_info.bChanged = false; + + DWORD dwOrder = 0; + DWORD dwPackets = 0; + + HANDLE hItem; + TCHAR *szJid; + + pList->RemoveAllRules(); + + for (int iJid = 0; iJid < clc_info.newJids.getCount(); ++iJid) + { + hItem = clc_info.newJids[iJid]->hItem; + szJid = clc_info.newJids[iJid]->jid; + + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Jid, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Jid, szJid, FALSE, dwOrder++, dwPackets); + } + + for (HANDLE hContact=db_find_first(); hContact; + hContact=db_find_next(hContact)) + { + hItem = m_clcClist.FindContact(hContact); + + DBVARIANT dbv = {0}; + if ( m_proto->JGetStringT(hContact, "jid", &dbv)) { + if ( m_proto->JGetStringT(hContact, "ChatRoomID", &dbv)) + continue; + } + + szJid = dbv.ptszVal; + + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Jid, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Jid, szJid, FALSE, dwOrder++, dwPackets); + + JFreeVariant(&dbv); + } + + // group handles start with 1 (0 is "root") + for (int iGroup = 1; ; ++iGroup) + { + char idstr[33]; + _itoa(iGroup-1, idstr, 10); + DBVARIANT dbv = {0}; + if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv)) + break; + + hItem = m_clcClist.FindGroup((HANDLE)iGroup); + szJid = dbv.ptszVal+1; + + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Group, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Group, szJid, FALSE, dwOrder++, dwPackets); + + DBFreeVariant(&dbv); + } + + hItem = clc_info.hItemSubBoth; + szJid = _T("both"); + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); + + hItem = clc_info.hItemSubFrom; + szJid = _T("from"); + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); + + hItem = clc_info.hItemSubNone; + szJid = _T("none"); + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); + + hItem = clc_info.hItemSubTo; + szJid = _T("to"); + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Subscription, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Subscription, szJid, FALSE, dwOrder++, dwPackets); + + hItem = clc_info.hItemDefault; + szJid = NULL; + if (dwPackets = CListGetPackets(hwndList, hItem, true)) + pList->AddRule(Else, szJid, TRUE, dwOrder++, dwPackets); + if (dwPackets = CListGetPackets(hwndList, hItem, false)) + pList->AddRule(Else, szJid, FALSE, dwOrder++, dwPackets); + + pList->Reorder(); + pList->SetModified(); +} + +void CJabberDlgPrivacyLists::EnableEditorControls() +{ + m_proto->m_privacyListManager.Lock(); + BOOL bListsLoaded = m_proto->m_privacyListManager.IsAllListsLoaded(); + BOOL bListsModified = m_proto->m_privacyListManager.IsModified() || clc_info.bChanged; + m_proto->m_privacyListManager.Unlock(); + + int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); + int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); + BOOL bSelected = nCurSel != CB_ERR; + BOOL bListSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCOUNT, 0, 0); + bListSelected = bListSelected && (SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0) != LB_ERR); + bListSelected = bListSelected && SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETITEMDATA, SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0), 0); + + EnableWindow( GetDlgItem( m_hwnd, IDC_TXT_OTHERJID ), bListsLoaded && bListSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_NEWJID ), bListsLoaded && bListSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_ADDJID ), bListsLoaded && bListSelected ); + + EnableWindow( GetDlgItem( m_hwnd, IDC_ADD_RULE ), bListsLoaded && bListSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_EDIT_RULE ), bListsLoaded && bSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_RULE ), bListsLoaded && bSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_UP_RULE ), bListsLoaded && bSelected && nCurSel != 0 ); + EnableWindow( GetDlgItem( m_hwnd, IDC_DOWN_RULE ), bListsLoaded && bSelected && nCurSel != ( nItemCount - 1 )); + EnableWindow( GetDlgItem( m_hwnd, IDC_REMOVE_LIST ), bListsLoaded && bListSelected ); + EnableWindow( GetDlgItem( m_hwnd, IDC_APPLY ), bListsLoaded && bListsModified ); + + if (bListsLoaded) + SetStatusText( TranslateT("Ready.")); +} + +LRESULT CALLBACK CJabberDlgPrivacyLists::LstListsSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC sttOldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + switch (msg) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + if (wParam == VK_INSERT) + return UIEmulateBtnClick(GetParent(hwnd), IDC_ADD_LIST); + if (wParam == VK_DELETE) + return UIEmulateBtnClick(GetParent(hwnd), IDC_REMOVE_LIST); + if (wParam == VK_SPACE) + { + if (GetAsyncKeyState(VK_CONTROL)) + return UIEmulateBtnClick(GetParent(hwnd), IDC_SET_DEFAULT); + return UIEmulateBtnClick(GetParent(hwnd), IDC_ACTIVATE); + } + + break; + } + } + return CallWindowProc(sttOldWndProc, hwnd, msg, wParam, lParam); +} + +LRESULT CALLBACK CJabberDlgPrivacyLists::LstRulesSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC sttOldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + switch (msg) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + if (wParam == VK_INSERT) + return UIEmulateBtnClick(GetParent(hwnd), IDC_ADD_RULE); + if (wParam == VK_DELETE) + return UIEmulateBtnClick(GetParent(hwnd), IDC_REMOVE_RULE); + if ((wParam == VK_UP) && (lParam & (1UL << 29))) + return UIEmulateBtnClick(GetParent(hwnd), IDC_UP_RULE); + if ((wParam == VK_DOWN) && (lParam & (1UL << 29))) + return UIEmulateBtnClick(GetParent(hwnd), IDC_DOWN_RULE); + if (wParam == VK_F2) + return UIEmulateBtnClick(GetParent(hwnd), IDC_EDIT_RULE); + + break; + } + } + return CallWindowProc(sttOldWndProc, hwnd, msg, wParam, lParam); +} + +BOOL CJabberDlgPrivacyLists::CanExit() +{ + m_proto->m_privacyListManager.Lock(); + BOOL bModified = m_proto->m_privacyListManager.IsModified(); + m_proto->m_privacyListManager.Unlock(); + + if (clc_info.bChanged) + bModified = TRUE; + + if ( !bModified ) + return TRUE; + + if ( IDYES == MessageBox( m_hwnd, TranslateT("Privacy lists are not saved, discard any changes and exit?"), TranslateT("Are you sure?"), MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 )) + return TRUE; + + return FALSE; +} + +void CJabberDlgPrivacyLists::btnSimple_OnClick(CCtrlButton *) +{ + CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, TRUE); + CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, FALSE); + UIShowControls(m_hwnd, idSimpleControls, SW_SHOW); + UIShowControls(m_hwnd, idAdvancedControls, SW_HIDE); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); +} + +void CJabberDlgPrivacyLists::btnAdvanced_OnClick(CCtrlButton *) +{ + CheckDlgButton(m_hwnd, IDC_BTN_SIMPLE, FALSE); + CheckDlgButton(m_hwnd, IDC_BTN_ADVANCED, TRUE); + UIShowControls(m_hwnd, idSimpleControls, SW_HIDE); + UIShowControls(m_hwnd, idAdvancedControls, SW_SHOW); + CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); + PostMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_LB_LISTS, LBN_SELCHANGE), 0); +} + +void CJabberDlgPrivacyLists::btnAddJid_OnClick(CCtrlButton *) +{ + int len = GetWindowTextLength(GetDlgItem(m_hwnd, IDC_NEWJID))+1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(GetDlgItem(m_hwnd, IDC_NEWJID), buf, len); + SetWindowText(GetDlgItem(m_hwnd, IDC_NEWJID), _T("")); + CListAddContact(GetDlgItem(m_hwnd, IDC_CLIST), buf); +} + +void CJabberDlgPrivacyLists::btnActivate_OnClick(CCtrlButton *) +{ + if ( m_proto->m_bJabberOnline ) + { + m_proto->m_privacyListManager.Lock(); + CPrivacyList* pList = GetSelectedList(m_hwnd); + if ( pList && pList->IsModified()) { + m_proto->m_privacyListManager.Unlock(); + MessageBox( m_hwnd, TranslateT("Please save list before activating"), TranslateT("First, save the list"), MB_OK | MB_ICONSTOP ); + return; + } + EnableWindow( GetDlgItem( m_hwnd, IDC_ACTIVATE ), FALSE ); + SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_ACTIVATE ), GWLP_USERDATA, (LONG_PTR)pList ); + XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListActive, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); + HXML active = query << XCHILD( _T("active")); + if ( pList ) + active << XATTR( _T("name"), pList->GetListName()); + m_proto->m_privacyListManager.Unlock(); + + SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); + + m_proto->m_ThreadInfo->send( iq ); + } +} + +void CJabberDlgPrivacyLists::btnSetDefault_OnClick(CCtrlButton *) +{ + if ( m_proto->m_bJabberOnline ) + { + m_proto->m_privacyListManager.Lock(); + CPrivacyList* pList = GetSelectedList(m_hwnd); + if ( pList && pList->IsModified()) { + m_proto->m_privacyListManager.Unlock(); + MessageBox( m_hwnd, TranslateT("Please save list before you make it the default list"), TranslateT("First, save the list"), MB_OK | MB_ICONSTOP ); + return; + } + EnableWindow( GetDlgItem( m_hwnd, IDC_SET_DEFAULT ), FALSE ); + SetWindowLongPtr( GetDlgItem( m_hwnd, IDC_SET_DEFAULT ), GWLP_USERDATA, (LONG_PTR)pList ); + + XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListDefault, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS )); + HXML defaultTag = query << XCHILD( _T("default")); + if ( pList ) + xmlAddAttr( defaultTag, _T("name"), pList->GetListName()); + m_proto->m_privacyListManager.Unlock(); + + SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); + + m_proto->m_ThreadInfo->send( iq ); + } +} + +void CJabberDlgPrivacyLists::lbLists_OnSelChange(CCtrlListBox *) +{ + LRESULT nCurSel = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETCURSEL, 0, 0 ); + if ( nCurSel == LB_ERR ) + return; + + LRESULT nErr = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_GETITEMDATA, nCurSel, 0 ); + if ( nErr == LB_ERR ) + return; + if ( nErr == 0 ) + { + if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) + { + CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), NULL); + } else + { + EnableWindow( GetDlgItem( m_hwnd, IDC_PL_RULES_LIST ), FALSE ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_RESETCONTENT, 0, 0 ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_ADDSTRING, 0, (LPARAM)TranslateTS(_T("No list selected"))); + } + EnableEditorControls(); + return; + } + + m_proto->m_privacyListManager.Lock(); + if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) + { + CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), (CPrivacyList* )nErr); + } + else ShowAdvancedList((CPrivacyList* )nErr); + + m_proto->m_privacyListManager.Unlock(); + + EnableEditorControls(); +} + +void CJabberDlgPrivacyLists::lbLists_OnDblClick(CCtrlListBox *) +{ + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_ACTIVATE, 0 ), 0 ); +} + +void CJabberDlgPrivacyLists::lbRules_OnSelChange(CCtrlListBox *) +{ + EnableEditorControls(); +} + +void CJabberDlgPrivacyLists::lbRules_OnDblClick(CCtrlListBox *) +{ + PostMessage( m_hwnd, WM_COMMAND, MAKEWPARAM( IDC_EDIT_RULE, 0 ), 0 ); +} + +void CJabberDlgPrivacyLists::btnEditRule_OnClick(CCtrlButton *) +{ + // FIXME: potential deadlock due to PLM lock while editing rule + m_proto->m_privacyListManager.Lock(); + { + CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); + CPrivacyList* pList = GetSelectedList(m_hwnd); + if ( pList && pRule ) { + CJabberDlgPrivacyRule dlgPrivacyRule(m_proto, m_hwnd, pRule); + int nResult = dlgPrivacyRule.DoModal(); + if ( nResult ) { + pList->SetModified(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } } } + m_proto->m_privacyListManager.Unlock(); +} + +void CJabberDlgPrivacyLists::btnAddRule_OnClick(CCtrlButton *) +{ + // FIXME: potential deadlock due to PLM lock while editing rule + m_proto->m_privacyListManager.Lock(); + { + CPrivacyList* pList = GetSelectedList(m_hwnd); + if ( pList ) { + CPrivacyListRule* pRule = new CPrivacyListRule( m_proto, Jid, _T(""), FALSE ); + CJabberDlgPrivacyRule dlgPrivacyRule(m_proto, m_hwnd, pRule); + int nResult = dlgPrivacyRule.DoModal(); + if ( nResult ) { + pList->AddRule(pRule); + pList->Reorder(); + pList->SetModified(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } + else delete pRule; + } } + m_proto->m_privacyListManager.Unlock(); +} + +void CJabberDlgPrivacyLists::btnRemoveRule_OnClick(CCtrlButton *) +{ + m_proto->m_privacyListManager.Lock(); + { + CPrivacyList* pList = GetSelectedList(m_hwnd); + CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); + + if ( pList && pRule ) { + pList->RemoveRule( pRule ); + int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); + int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel != nItemCount - 1 ? nCurSel : nCurSel - 1, 0 ); + pList->Reorder(); + pList->SetModified(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } } + + m_proto->m_privacyListManager.Unlock(); +} + +void CJabberDlgPrivacyLists::btnUpRule_OnClick(CCtrlButton *) +{ + m_proto->m_privacyListManager.Lock(); + { + CPrivacyList* pList = GetSelectedList(m_hwnd); + CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); + int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); + + if ( pList && pRule && nCurSel ) { + pRule->SetOrder( pRule->GetOrder() - 11 ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel - 1, 0 ); + pList->Reorder(); + pList->SetModified(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } } + + m_proto->m_privacyListManager.Unlock(); +} + +void CJabberDlgPrivacyLists::btnDownRule_OnClick(CCtrlButton *) +{ + m_proto->m_privacyListManager.Lock(); + { + CPrivacyList* pList = GetSelectedList(m_hwnd); + CPrivacyListRule* pRule = GetSelectedRule( m_hwnd ); + int nCurSel = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCURSEL, 0, 0 ); + int nItemCount = SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_GETCOUNT, 0, 0 ); + + if ( pList && pRule && ( nCurSel != ( nItemCount - 1 ))) { + pRule->SetOrder( pRule->GetOrder() + 11 ); + SendDlgItemMessage( m_hwnd, IDC_PL_RULES_LIST, LB_SETCURSEL, nCurSel + 1, 0 ); + pList->Reorder(); + pList->SetModified(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } } + + m_proto->m_privacyListManager.Unlock(); +} + +void CJabberDlgPrivacyLists::btnAddList_OnClick(CCtrlButton *) +{ + // FIXME: line length is hard coded in dialog procedure + CJabberDlgPrivacyAddList dlgPrivacyAddList(m_proto, m_hwnd); + int nRetVal = dlgPrivacyAddList.DoModal(); + if ( nRetVal && _tcslen( dlgPrivacyAddList.szLine )) { + m_proto->m_privacyListManager.Lock(); + CPrivacyList* pList = m_proto->m_privacyListManager.FindList( dlgPrivacyAddList.szLine ); + if ( !pList ) { + m_proto->m_privacyListManager.AddList( dlgPrivacyAddList.szLine ); + pList = m_proto->m_privacyListManager.FindList( dlgPrivacyAddList.szLine ); + if ( pList ) { + pList->SetModified( TRUE ); + pList->SetLoaded( TRUE ); + } + } + if ( pList ) + pList->SetDeleted( FALSE ); + int nSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SELECTSTRING, -1, (LPARAM)dlgPrivacyAddList.szLine ); + if ( nSelected == CB_ERR ) { + nSelected = SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_ADDSTRING, 0, (LPARAM)dlgPrivacyAddList.szLine ); + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETITEMDATA, nSelected, (LPARAM)pList ); + SendDlgItemMessage( m_hwnd, IDC_LB_LISTS, LB_SETCURSEL, nSelected, 0 ); + } + m_proto->m_privacyListManager.Unlock(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); + } +} + +void CJabberDlgPrivacyLists::btnRemoveList_OnClick(CCtrlButton *) +{ + m_proto->m_privacyListManager.Lock(); + { + CPrivacyList* pList = GetSelectedList(m_hwnd); + if ( pList ) { + TCHAR *szListName = pList->GetListName(); + if ( ( m_proto->m_privacyListManager.GetActiveListName() && !_tcscmp( szListName, m_proto->m_privacyListManager.GetActiveListName())) + || ( m_proto->m_privacyListManager.GetDefaultListName() && !_tcscmp( szListName, m_proto->m_privacyListManager.GetDefaultListName()))) { + m_proto->m_privacyListManager.Unlock(); + MessageBox( m_hwnd, TranslateTS(_T("Can't remove active or default list")), TranslateTS(_T("Sorry")), MB_OK | MB_ICONSTOP ); + return; + } + pList->SetDeleted(); + pList->SetModified(); + } } + + m_proto->m_privacyListManager.Unlock(); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); +} + +void CJabberDlgPrivacyLists::btnApply_OnClick(CCtrlButton *) +{ + if ( !m_proto->m_bJabberOnline ) { + SetStatusText(TranslateT("Unable to save list because you are currently offline.")); + return; + } + + m_proto->m_privacyListManager.Lock(); + { + if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) + CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); + + CPrivacyListModifyUserParam *pUserData = NULL; + CPrivacyList* pList = m_proto->m_privacyListManager.GetFirstList(); + while ( pList ) { + if ( pList->IsModified()) { + CPrivacyListRule* pRule = pList->GetFirstRule(); + if ( !pRule ) + pList->SetDeleted(); + if ( pList->IsDeleted()) { + pList->RemoveAllRules(); + pRule = NULL; + } + pList->SetModified( FALSE ); + + if ( !pUserData ) + pUserData = new CPrivacyListModifyUserParam(); + + pUserData->m_dwCount++; + + XmlNodeIq iq( m_proto->m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListModify, JABBER_IQ_TYPE_SET, NULL, 0, -1, pUserData )); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS )); + HXML listTag = query << XCHILD( _T("list")) << XATTR( _T("name"), pList->GetListName()); + + while ( pRule ) { + HXML itemTag = listTag << XCHILD( _T("item")); + switch ( pRule->GetType()) { + case Jid: + itemTag << XATTR( _T("type"), _T("jid")); + break; + case Group: + itemTag << XATTR( _T("type"), _T("group")); + break; + case Subscription: + itemTag << XATTR( _T("type"), _T("subscription")); + break; + } + if ( pRule->GetType() != Else ) + itemTag << XATTR( _T("value"), pRule->GetValue()); + if ( pRule->GetAction()) + itemTag << XATTR( _T("action"), _T("allow")); + else + itemTag << XATTR( _T("action"), _T("deny")); + itemTag << XATTRI( _T("order"), pRule->GetOrder()); + DWORD dwPackets = pRule->GetPackets(); + if ( dwPackets != JABBER_PL_RULE_TYPE_ALL ) { + if ( dwPackets & JABBER_PL_RULE_TYPE_IQ ) + itemTag << XCHILD( _T("iq")); + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_IN ) + itemTag << XCHILD( _T("presence-in")); + if ( dwPackets & JABBER_PL_RULE_TYPE_PRESENCE_OUT ) + itemTag << XCHILD( _T("presence-out")); + if ( dwPackets & JABBER_PL_RULE_TYPE_MESSAGE ) + itemTag << XCHILD( _T("message")); + } + pRule = pRule->GetNext(); + } + + m_proto->m_ThreadInfo->send( iq ); + } + pList = pList->GetNext(); + } } + m_proto->m_privacyListManager.Unlock(); + SetStatusText(TranslateT( JABBER_PL_BUSY_MSG )); + PostMessage( m_hwnd, WM_JABBER_REFRESH, 0, 0 ); +} + +void CJabberDlgPrivacyLists::OnCommand_Close(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) +{ + if (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CLIST))) + CListBuildList(GetDlgItem(m_hwnd, IDC_CLIST), clc_info.pList); + + if (CanExit()) + DestroyWindow(m_hwnd); +} + +void CJabberDlgPrivacyLists::clcClist_OnUpdate(CCtrlClc::TEventInfo*) +{ + CListFilter(GetDlgItem(m_hwnd, IDC_CLIST)); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); +} + +void CJabberDlgPrivacyLists::clcClist_OnOptionsChanged(CCtrlClc::TEventInfo*) +{ + CListResetOptions(GetDlgItem(m_hwnd, IDC_CLIST)); + CListApplyList(GetDlgItem(m_hwnd, IDC_CLIST), GetSelectedList(m_hwnd)); +} + +void CJabberDlgPrivacyLists::clcClist_OnClick(CCtrlClc::TEventInfo *evt) +{ + HANDLE hItem; + DWORD hitFlags; + int iImage; + + if(evt->info->iColumn==-1) return; + hItem = m_clcClist.HitTest(evt->info->pt.x, evt->info->pt.y, &hitFlags); + if(hItem==NULL) return; + if (!(hitFlags&CLCHT_ONITEMEXTRA)) return; + + iImage = m_clcClist.GetExtraImage(hItem, evt->info->iColumn); + if (iImage != 0xFF) + { + if (iImage == 0) + iImage = evt->info->iColumn * 2 + 2; + else if (iImage == evt->info->iColumn * 2 + 2) + iImage = evt->info->iColumn * 2 + 1; + else + iImage = 0; + + m_clcClist.SetExtraImage(hItem, evt->info->iColumn, iImage); + + clc_info.bChanged = true; + + EnableEditorControls(); + } +} + +int CJabberDlgPrivacyLists::Resizer(UTILRESIZECONTROL *urc) +{ + switch (urc->wId) { + case IDC_HEADERBAR: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH; + case IDC_BTN_SIMPLE: + case IDC_BTN_ADVANCED: + return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP; + case IDC_LB_LISTS: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT; + case IDC_PL_RULES_LIST: + case IDC_CLIST: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORY_HEIGHT|RD_ANCHORX_WIDTH; + case IDC_NEWJID: + case IDC_CANVAS: + return RD_ANCHORX_LEFT|RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; + case IDC_ADD_LIST: + case IDC_ACTIVATE: + case IDC_REMOVE_LIST: + case IDC_SET_DEFAULT: + case IDC_TXT_OTHERJID: + case IDC_ADD_RULE: + case IDC_UP_RULE: + case IDC_EDIT_RULE: + case IDC_DOWN_RULE: + case IDC_REMOVE_RULE: + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + case IDC_ADDJID: + case IDC_APPLY: + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + return CSuper::Resizer(urc); +} + +INT_PTR __cdecl CJabberProto::OnMenuHandlePrivacyLists( WPARAM, LPARAM ) +{ + UI_SAFE_OPEN(CJabberDlgPrivacyLists, m_pDlgPrivacyLists); + return 0; +} + +void CJabberProto::QueryPrivacyLists( ThreadData *pThreadInfo ) +{ + XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyLists )); + iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); + if ( pThreadInfo ) + pThreadInfo->send( iq ); + else if ( m_ThreadInfo ) + m_ThreadInfo->send( iq ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// builds privacy menu + +INT_PTR __cdecl CJabberProto::menuSetPrivacyList( WPARAM, LPARAM, LPARAM iList ) +{ + m_privacyListManager.Lock(); + CPrivacyList *pList = NULL; + + if (iList) + { + pList = m_privacyListManager.GetFirstList(); + for (int i = 1; pList && (i < iList); ++i) + pList = pList->GetNext(); + } + + XmlNodeIq iq( m_iqManager.AddHandler( &CJabberProto::OnIqResultPrivacyListActive, JABBER_IQ_TYPE_SET, NULL, 0, -1, pList )); + HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVACY_LISTS)); + HXML active = query << XCHILD( _T("active")); + if ( pList ) + active << XATTR( _T("name"), pList->GetListName()); + m_privacyListManager.Unlock(); + + m_ThreadInfo->send( iq ); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// init privacy menu + +void CJabberProto::BuildPrivacyMenu() +{ + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.position = 200005; + mi.pszContactOwner = m_szModuleName; + mi.icolibItem = GetIconHandle(IDI_AGENTS); + mi.flags = CMIF_ROOTPOPUP | CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB | CMIF_HIDDEN; + mi.pszName = LPGEN("Privacy Lists"); + mi.hParentMenu = MO_GetProtoRootMenu( m_szModuleName ); + m_hPrivacyMenuRoot = Menu_AddProtoMenuItem(&mi); + + JCreateService( "/PrivacyLists", &CJabberProto::OnMenuHandlePrivacyLists ); + char srvFce[MAX_PATH + 64]; + mir_snprintf( srvFce, SIZEOF(srvFce), "%s/PrivacyLists", m_szModuleName ); + mi.pszService = srvFce; + mi.position = 3000040000; + mi.flags = CMIF_CHILDPOPUP | CMIF_TCHAR | CMIF_ICONFROMICOLIB; + mi.icolibItem = GetIconHandle(IDI_PRIVACY_LISTS); + mi.ptszName = LPGENT("List Editor..."); + mi.hParentMenu = m_hPrivacyMenuRoot; + Menu_AddProtoMenuItem(&mi); +} + +void CJabberProto::BuildPrivacyListsMenu( bool bDeleteOld ) +{ + int i; + if ( bDeleteOld ) + for ( i=0; i < m_hPrivacyMenuItems.getCount(); i++ ) + CallService( MO_REMOVEMENUITEM, (WPARAM)m_hPrivacyMenuItems[i], 0 ); + m_hPrivacyMenuItems.destroy(); + + m_privacyListManager.Lock(); + + i = 0; + char srvFce[MAX_PATH + 64], *svcName = srvFce+strlen( m_szModuleName ); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.position = 2000040000; + mi.flags = CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB | CMIF_TCHAR; + mi.hParentMenu = m_hPrivacyMenuRoot; + mi.pszService = srvFce; + + mir_snprintf( srvFce, SIZEOF(srvFce), "%s/menuPrivacy%d", m_szModuleName, i ); + if ( i > m_privacyMenuServiceAllocated ) { + JCreateServiceParam( svcName, &CJabberProto::menuSetPrivacyList, i ); + m_privacyMenuServiceAllocated = i; + } + mi.position++; + mi.icolibItem = LoadSkinnedIconHandle( + m_privacyListManager.GetActiveListName() ? + SKINICON_OTHER_SMALLDOT : + SKINICON_OTHER_EMPTYBLOB); + mi.ptszName = LPGENT("<none>"); + m_hPrivacyMenuItems.insert( Menu_AddProtoMenuItem(&mi)); + + for ( CPrivacyList *pList = m_privacyListManager.GetFirstList(); pList; pList = pList->GetNext()) { + ++i; + mir_snprintf( srvFce, SIZEOF(srvFce), "%s/menuPrivacy%d", m_szModuleName, i ); + + if ( i > m_privacyMenuServiceAllocated ) { + JCreateServiceParam( svcName, &CJabberProto::menuSetPrivacyList, i ); + m_privacyMenuServiceAllocated = i; + } + + mi.position++; + mi.icolibItem = LoadSkinnedIconHandle( + lstrcmp( m_privacyListManager.GetActiveListName(), pList->GetListName()) ? + SKINICON_OTHER_SMALLDOT : + SKINICON_OTHER_EMPTYBLOB); + mi.ptszName = pList->GetListName(); + m_hPrivacyMenuItems.insert( Menu_AddProtoMenuItem(&mi)); + } + + m_privacyListManager.Unlock(); +} diff --git a/protocols/JabberG/src/jabber_privacy.h b/protocols/JabberG/src/jabber_privacy.h new file mode 100644 index 0000000000..4a2cfd8f2f --- /dev/null +++ b/protocols/JabberG/src/jabber_privacy.h @@ -0,0 +1,435 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_PRIVACY_H_ +#define _JABBER_PRIVACY_H_ + +#define JABBER_PL_RULE_TYPE_MESSAGE 1 +#define JABBER_PL_RULE_TYPE_PRESENCE_IN 2 +#define JABBER_PL_RULE_TYPE_PRESENCE_OUT 4 +#define JABBER_PL_RULE_TYPE_IQ 8 +#define JABBER_PL_RULE_TYPE_ALL 0x0F + +enum PrivacyListRuleType +{ + Jid, + Group, + Subscription, + Else +}; + +struct CPrivacyListModifyUserParam +{ + BOOL m_bAllOk; + volatile LONG m_dwCount; + CPrivacyListModifyUserParam() : + m_bAllOk( TRUE ), + m_dwCount( 0 ) + { + } +}; + +class CPrivacyList; + +class CPrivacyListRule +{ +protected: + friend class CPrivacyList; +public: + CPrivacyListRule( CJabberProto* ppro, PrivacyListRuleType type = Else, const TCHAR *szValue = _T(""), BOOL bAction = TRUE, DWORD dwOrder = 90, DWORD dwPackets = 0) + { + m_proto = ppro; + m_szValue = mir_tstrdup(szValue); + m_nType = type; + m_bAction = bAction; + m_dwOrder = dwOrder; + m_dwPackets = dwPackets; + m_pNext = NULL; + }; + ~CPrivacyListRule() + { + if (m_szValue) + mir_free(m_szValue); + + if (m_pNext) + delete m_pNext; + }; + __inline CPrivacyListRule* GetNext() + { + return m_pNext; + } + CPrivacyListRule* SetNext(CPrivacyListRule *pNext) + { + CPrivacyListRule *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } + __inline DWORD GetOrder() + { + return m_dwOrder; + } + DWORD SetOrder(DWORD dwOrder) + { + DWORD dwRetVal = m_dwOrder; + m_dwOrder = dwOrder; + return dwRetVal; + } + __inline PrivacyListRuleType GetType() + { + return m_nType; + } + __inline BOOL SetType( PrivacyListRuleType type ) + { + m_nType = type; + return TRUE; + } + __inline TCHAR* GetValue() + { + return m_szValue; + } + __inline BOOL SetValue( TCHAR *szValue ) + { + replaceStrT( m_szValue, szValue ); + return TRUE; + } + __inline DWORD GetPackets() + { + return m_dwPackets; + } + __inline BOOL SetPackets( DWORD dwPackets ) + { + m_dwPackets = dwPackets; + return TRUE; + } + __inline BOOL GetAction() + { + return m_bAction; + } + __inline BOOL SetAction( BOOL bAction ) + { + m_bAction = bAction; + return TRUE; + } + CJabberProto* m_proto; +protected: + PrivacyListRuleType m_nType; + TCHAR *m_szValue; + BOOL m_bAction; + DWORD m_dwOrder; + DWORD m_dwPackets; + CPrivacyListRule *m_pNext; +}; + +class CPrivacyList; +class CPrivacyList +{ +protected: + CPrivacyListRule *m_pRules; + TCHAR *m_szListName; + CPrivacyList *m_pNext; + BOOL m_bLoaded; + BOOL m_bModified; + BOOL m_bDeleted; +public: + CJabberProto* m_proto; + + CPrivacyList(CJabberProto* ppro, TCHAR *szListName) + { + m_proto = ppro; + m_szListName = mir_tstrdup(szListName); + m_pRules = NULL; + m_pNext = NULL; + m_bLoaded = FALSE; + m_bModified = FALSE; + m_bDeleted = FALSE; + }; + ~CPrivacyList() + { + if (m_szListName) + mir_free(m_szListName); + RemoveAllRules(); + if (m_pNext) + delete m_pNext; + }; + BOOL RemoveAllRules() + { + if (m_pRules) + delete m_pRules; + m_pRules = NULL; + return TRUE; + } + __inline TCHAR* GetListName() + { + return m_szListName; + } + __inline CPrivacyListRule* GetFirstRule() + { + return m_pRules; + } + __inline CPrivacyList* GetNext() + { + return m_pNext; + } + CPrivacyList* SetNext(CPrivacyList *pNext) + { + CPrivacyList *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } + BOOL AddRule(PrivacyListRuleType type, const TCHAR *szValue, BOOL bAction, DWORD dwOrder, DWORD dwPackets) + { + CPrivacyListRule *pRule = new CPrivacyListRule( m_proto, type, szValue, bAction, dwOrder, dwPackets ); + if ( !pRule ) + return FALSE; + pRule->SetNext( m_pRules ); + m_pRules = pRule; + return TRUE; + } + BOOL AddRule(CPrivacyListRule *pRule) + { + pRule->SetNext( m_pRules ); + m_pRules = pRule; + return TRUE; + } + BOOL RemoveRule(CPrivacyListRule *pRuleToRemove) + { + if ( !m_pRules ) + return FALSE; + + if ( m_pRules == pRuleToRemove ) { + m_pRules = m_pRules->GetNext(); + pRuleToRemove->SetNext( NULL ); + delete pRuleToRemove; + return TRUE; + } + + CPrivacyListRule *pRule = m_pRules; + while ( pRule->GetNext()) { + if ( pRule->GetNext() == pRuleToRemove ) { + pRule->SetNext( pRule->GetNext()->GetNext()); + pRuleToRemove->SetNext( NULL ); + delete pRuleToRemove; + return TRUE; + } + pRule = pRule->GetNext(); + } + return FALSE; + } + BOOL Reorder() + { + // 0 or 1 rules? + if ( !m_pRules ) + return TRUE; + if ( !m_pRules->GetNext()) { + m_pRules->SetOrder( 100 ); + return TRUE; + } + + // get rules count + DWORD dwCount = 0; + CPrivacyListRule *pRule = m_pRules; + while ( pRule ) { + dwCount++; + pRule = pRule->GetNext(); + } + + // create pointer array for sort procedure + CPrivacyListRule **pRules = ( CPrivacyListRule ** )mir_alloc( dwCount * sizeof( CPrivacyListRule * )); + if ( !pRules ) + return FALSE; + DWORD dwPos = 0; + pRule = m_pRules; + while ( pRule ) { + pRules[dwPos++] = pRule; + pRule = pRule->GetNext(); + } + + // sort array of pointers, slow, but working :) + DWORD i, j; + CPrivacyListRule *pTmp; + for ( i = 0; i < dwCount; i++ ) { + for ( j = dwCount - 1; j > i; j-- ) { + if ( pRules[j - 1]->GetOrder() > pRules[j]->GetOrder()) { + pTmp = pRules[j - 1]; + pRules[j - 1] = pRules[j]; + pRules[j] = pTmp; + } + } + } + + // reorder linked list + DWORD dwOrder = 100; + CPrivacyListRule **ppPtr = &m_pRules; + for ( i = 0; i < dwCount; i++ ) { + *ppPtr = pRules[ i ]; + ppPtr = &pRules[ i ]->m_pNext; + pRules[ i ]->SetOrder( dwOrder ); + dwOrder += 10; + } + *ppPtr = NULL; + mir_free( pRules ); + + return TRUE; + } + __inline void SetLoaded(BOOL bLoaded = TRUE) + { + m_bLoaded = bLoaded; + } + __inline BOOL IsLoaded() + { + return m_bLoaded; + } + __inline void SetModified(BOOL bModified = TRUE) + { + m_bModified = bModified; + } + __inline BOOL IsModified() + { + return m_bModified; + } + __inline void SetDeleted(BOOL bDeleted = TRUE) + { + m_bDeleted = bDeleted; + } + __inline BOOL IsDeleted() + { + return m_bDeleted; + } +}; + +class CPrivacyListManager +{ +protected: + TCHAR *m_szActiveListName; + TCHAR *m_szDefaultListName; + CPrivacyList *m_pLists; + CRITICAL_SECTION m_cs; + BOOL m_bModified; + +public: + CJabberProto* m_proto; + + CPrivacyListManager( CJabberProto* ppro ) + { + m_proto = ppro; + m_szActiveListName = NULL; + m_szDefaultListName = NULL; + m_pLists = NULL; + InitializeCriticalSection(&m_cs); + m_bModified = FALSE; + }; + ~CPrivacyListManager() + { + if (m_szActiveListName) + mir_free(m_szActiveListName); + if (m_szDefaultListName) + mir_free(m_szDefaultListName); + RemoveAllLists(); + DeleteCriticalSection(&m_cs); + }; + BOOL Lock() + { + EnterCriticalSection(&m_cs); + return TRUE; + } + BOOL Unlock() + { + LeaveCriticalSection(&m_cs); + return TRUE; + } + void SetActiveListName(const TCHAR *szListName) + { + replaceStrT(m_szActiveListName, szListName); + } + void SetDefaultListName(const TCHAR *szListName) + { + replaceStrT(m_szDefaultListName, szListName); + } + TCHAR* GetDefaultListName() + { + return m_szDefaultListName; + } + TCHAR* GetActiveListName() + { + return m_szActiveListName; + } + BOOL RemoveAllLists() + { + if (m_pLists) + delete m_pLists; + m_pLists = NULL; + return TRUE; + } + CPrivacyList* FindList( const TCHAR *szListName ) + { + CPrivacyList *pList = m_pLists; + while ( pList ) { + if ( !_tcscmp(pList->GetListName(), szListName )) + return pList; + pList = pList->GetNext(); + } + return NULL; + } + CPrivacyList* GetFirstList() + { + return m_pLists; + } + BOOL AddList( TCHAR *szListName ) + { + if (FindList(szListName)) + return FALSE; + CPrivacyList *pList = new CPrivacyList( m_proto, szListName ); + pList->SetNext( m_pLists ); + m_pLists = pList; + return TRUE; + } + BOOL SetModified(BOOL bModified = TRUE) + { + m_bModified = bModified; + return TRUE; + } + BOOL IsModified() + { + if ( m_bModified ) + return TRUE; + CPrivacyList *pList = m_pLists; + while ( pList ) { + if ( pList->IsModified()) + return TRUE; + pList = pList->GetNext(); + } + return FALSE; + } + BOOL IsAllListsLoaded() + { + CPrivacyList *pList = m_pLists; + while ( pList ) { + if ( !pList->IsLoaded()) + return FALSE; + pList = pList->GetNext(); + } + return TRUE; + } +}; + +#endif //_JABBER_PRIVACY_H_ diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp new file mode 100644 index 0000000000..6444482ee6 --- /dev/null +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -0,0 +1,1659 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#include <fcntl.h> +#include <io.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <m_addcontact.h> +#include <m_file.h> +#include <m_genmenu.h> +#include <m_icolib.h> + +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "jabber_disco.h" + +#include "m_proto_listeningto.h" +#include "m_modernopt.h" + +#pragma warning(disable:4355) + +static int compareTransports( const TCHAR* p1, const TCHAR* p2 ) +{ return _tcsicmp( p1, p2 ); +} + +static int compareListItems( const JABBER_LIST_ITEM* p1, const JABBER_LIST_ITEM* p2 ) +{ + if ( p1->list != p2->list ) + return p1->list - p2->list; + + // for bookmarks, temporary contacts & groupchat members + // resource must be used in the comparison + if (( p1->list == LIST_ROSTER && ( p1->bUseResource == TRUE || p2->bUseResource == TRUE )) + || ( p1->list == LIST_BOOKMARK ) || ( p1->list == LIST_VCARD_TEMP )) + return lstrcmpi( p1->jid, p2->jid ); + + TCHAR szp1[ JABBER_MAX_JID_LEN ], szp2[ JABBER_MAX_JID_LEN ]; + JabberStripJid( p1->jid, szp1, SIZEOF( szp1 )); + JabberStripJid( p2->jid, szp2, SIZEOF( szp2 )); + return lstrcmpi( szp1, szp2 ); +} + +CJabberProto::CJabberProto( const char* aProtoName, const TCHAR* aUserName ) : + m_options( this ), + m_lstTransports( 50, compareTransports ), + m_lstRoster( 50, compareListItems ), + m_iqManager( this ), + m_messageManager( this ), + m_presenceManager( this ), + m_sendManager( this ), + m_adhocManager( this ), + m_clientCapsManager( this ), + m_privacyListManager( this ), + m_privacyMenuServiceAllocated( -1 ), + m_priorityMenuVal( 0 ), + m_priorityMenuValSet( false ), + m_hPrivacyMenuRoot( 0 ), + m_hPrivacyMenuItems( 10 ), + m_pLastResourceList( NULL ), + m_lstJabberFeatCapPairsDynamic( 2 ), + m_uEnabledFeatCapsDynamic( 0 ) +{ + InitializeCriticalSection( &m_csModeMsgMutex ); + InitializeCriticalSection( &m_csLists ); + InitializeCriticalSection( &m_csLastResourceMap ); + + m_szXmlStreamToBeInitialized = NULL; + + m_iVersion = 2; + m_tszUserName = mir_tstrdup( aUserName ); + m_szModuleName = mir_strdup( aProtoName ); + m_szProtoName = mir_strdup( aProtoName ); + _strlwr( m_szProtoName ); + m_szProtoName[0] = toupper( m_szProtoName[0] ); + Log( "Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName ); + + // Initialize Jabber API + m_JabberApi.m_psProto = this; + m_JabberSysApi.m_psProto = this; + m_JabberNetApi.m_psProto = this; + + // Jabber dialog list + m_windowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + + // Protocol services and events... + m_hEventNudge = JCreateHookableEvent( JE_NUDGE ); + m_hEventXStatusIconChanged = JCreateHookableEvent( JE_CUSTOMSTATUS_EXTRAICON_CHANGED ); + m_hEventXStatusChanged = JCreateHookableEvent( JE_CUSTOMSTATUS_CHANGED ); + + JCreateService( PS_CREATEACCMGRUI, &CJabberProto::SvcCreateAccMgrUI ); + + JCreateService( PS_GETAVATARINFOT, &CJabberProto::JabberGetAvatarInfo ); + JCreateService( PS_GETMYAWAYMSG, &CJabberProto::GetMyAwayMsg ); + JCreateService( PS_SET_LISTENINGTO, &CJabberProto::OnSetListeningTo ); + + JCreateService( PS_JOINCHAT, &CJabberProto::OnJoinChat ); + JCreateService( PS_LEAVECHAT, &CJabberProto::OnLeaveChat ); + + JCreateService( JS_GETCUSTOMSTATUSICON, &CJabberProto::OnGetXStatusIcon ); + JCreateService( JS_GETXSTATUS, &CJabberProto::OnGetXStatus ); + JCreateService( JS_SETXSTATUS, &CJabberProto::OnSetXStatus ); + JCreateService( JS_SETXSTATUSEX, &CJabberProto::OnSetXStatusEx ); + + // not needed anymore and therefore commented out + // JCreateService( JS_GETXSTATUSEX, &CJabberProto::OnGetXStatusEx ); + + JCreateService( JS_HTTP_AUTH, &CJabberProto::OnHttpAuthRequest ); + JCreateService( JS_INCOMING_NOTE_EVENT, &CJabberProto::OnIncomingNoteEvent ); + + JCreateService( JS_SENDXML, &CJabberProto::ServiceSendXML ); + JCreateService( PS_GETMYAVATART, &CJabberProto::JabberGetAvatar ); + JCreateService( PS_GETAVATARCAPS, &CJabberProto::JabberGetAvatarCaps ); + JCreateService( PS_SETMYAVATART, &CJabberProto::JabberSetAvatar ); + JCreateService( PS_SETMYNICKNAME, &CJabberProto::JabberSetNickname ); + + JCreateService( JS_GETADVANCEDSTATUSICON, &CJabberProto::JGetAdvancedStatusIcon ); + JCreateService( JS_DB_GETEVENTTEXT_CHATSTATES, &CJabberProto::OnGetEventTextChatStates ); + JCreateService( JS_DB_GETEVENTTEXT_PRESENCE, &CJabberProto::OnGetEventTextPresence ); + + JCreateService( JS_GETJABBERAPI, &CJabberProto::JabberGetApi ); + + // XEP-0224 support (Attention/Nudge) + JCreateService( JS_SEND_NUDGE, &CJabberProto::JabberSendNudge ); + + // service to get from protocol chat buddy info + JCreateService( MS_GC_PROTO_GETTOOLTIPTEXT, &CJabberProto::JabberGCGetToolTipText ); + + // XMPP URI parser service for "File Association Manager" plugin + JCreateService( JS_PARSE_XMPP_URI, &CJabberProto::JabberServiceParseXmppURI ); + + JHookEvent( ME_MODERNOPT_INITIALIZE, &CJabberProto::OnModernOptInit ); + JHookEvent( ME_OPT_INITIALISE, &CJabberProto::OnOptionsInit ); + JHookEvent( ME_SKIN2_ICONSCHANGED, &CJabberProto::OnReloadIcons ); + + m_iqManager.FillPermanentHandlers(); + m_iqManager.Start(); + m_messageManager.FillPermanentHandlers(); + m_messageManager.Start(); + m_presenceManager.FillPermanentHandlers(); + m_presenceManager.Start(); + m_sendManager.Start(); + m_adhocManager.FillDefaultNodes(); + m_clientCapsManager.AddDefaultCaps(); + + IconsInit(); + InitPopups(); + GlobalMenuInit(); + WsInit(); + IqInit(); + SerialInit(); + ConsoleInit(); + InitCustomFolders(); + + m_pepServices.insert(new CPepMood(this)); + m_pepServices.insert(new CPepActivity(this)); + + *m_savedPassword = 0; + + char text[ MAX_PATH ]; + mir_snprintf( text, sizeof( text ), "%s/Status", m_szModuleName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + mir_snprintf( text, sizeof( text ), "%s/%s", m_szModuleName, DBSETTING_DISPLAY_UID ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + + mir_snprintf( text, sizeof( text ), "%s/SubscriptionText", m_szModuleName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + mir_snprintf( text, sizeof( text ), "%s/Subscription", m_szModuleName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + mir_snprintf( text, sizeof( text ), "%s/Auth", m_szModuleName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + mir_snprintf( text, sizeof( text ), "%s/Grant", m_szModuleName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + + DBVARIANT dbv; + if ( !JGetStringT( NULL, "XmlLang", &dbv )) { + m_tszSelectedLang = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else m_tszSelectedLang = mir_tstrdup( _T( "en" )); + + if (!DBGetContactSettingString(NULL, m_szModuleName, "Password", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, lstrlenA(dbv.pszVal) + 1, (LPARAM)dbv.pszVal); + TCHAR *pssw = mir_a2t(dbv.pszVal); + JSetStringCrypt(NULL, "LoginPassword", pssw); + mir_free(pssw); + JFreeVariant(&dbv); + JDeleteSetting(NULL, "Password"); + } + + CleanLastResourceMap(); +} + +CJabberProto::~CJabberProto() +{ + WsUninit(); + IqUninit(); + XStatusUninit(); + SerialUninit(); + ConsoleUninit(); + GlobalMenuUninit(); + + delete m_pInfoFrame; + + DestroyHookableEvent( m_hEventNudge ); + DestroyHookableEvent( m_hEventXStatusIconChanged ); + DestroyHookableEvent( m_hEventXStatusChanged ); + if ( m_hInitChat ) + DestroyHookableEvent( m_hInitChat ); + + CleanLastResourceMap(); + + ListWipe(); + DeleteCriticalSection( &m_csLists ); + + mir_free( m_tszSelectedLang ); + mir_free( m_phIconLibItems ); + mir_free( m_AuthMechs.m_gssapiHostName ); + + DeleteCriticalSection( &m_filterInfo.csPatternLock ); + DeleteCriticalSection( &m_csModeMsgMutex ); + DeleteCriticalSection( &m_csLastResourceMap ); + + mir_free( m_modeMsgs.szOnline ); + mir_free( m_modeMsgs.szAway ); + mir_free( m_modeMsgs.szNa ); + mir_free( m_modeMsgs.szDnd ); + mir_free( m_modeMsgs.szFreechat ); + + mir_free( m_transportProtoTableStartIndex ); + + mir_free( m_szStreamId ); + mir_free( m_szProtoName ); + mir_free( m_szModuleName ); + mir_free( m_tszUserName ); + + int i; + for ( i=0; i < m_lstTransports.getCount(); i++ ) + mir_free( m_lstTransports[i] ); + m_lstTransports.destroy(); + + for ( i=0; i < m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { + mir_free( m_lstJabberFeatCapPairsDynamic[i]->szExt ); + mir_free( m_lstJabberFeatCapPairsDynamic[i]->szFeature ); + if ( m_lstJabberFeatCapPairsDynamic[i]->szDescription ) + mir_free( m_lstJabberFeatCapPairsDynamic[i]->szDescription ); + delete m_lstJabberFeatCapPairsDynamic[i]; + } + m_lstJabberFeatCapPairsDynamic.destroy(); + m_hPrivacyMenuItems.destroy(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoadedEx - performs hook registration + +static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + +int CJabberProto::OnModulesLoadedEx( WPARAM, LPARAM ) +{ + JHookEvent( ME_USERINFO_INITIALISE, &CJabberProto::OnUserInfoInit ); + XStatusInit(); + m_pepServices.InitGui(); + + m_pInfoFrame = new CJabberInfoFrame(this); + + if ( ServiceExists( MS_GC_REGISTER )) { + jabberChatDllPresent = true; + + GCREGISTER gcr = {0}; + gcr.cbSize = sizeof( GCREGISTER ); + gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR | GC_TCHAR; + gcr.iMaxText = 0; + gcr.nColors = 16; + gcr.pColors = &crCols[0]; + gcr.ptszModuleDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + CallServiceSync( MS_GC_REGISTER, NULL, ( LPARAM )&gcr ); + + JHookEvent( ME_GC_EVENT, &CJabberProto::JabberGcEventHook ); + JHookEvent( ME_GC_BUILDMENU, &CJabberProto::JabberGcMenuHook ); + + char szEvent[ 200 ]; + mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", m_szModuleName ); + m_hInitChat = CreateHookableEvent( szEvent ); + JHookEvent( szEvent, &CJabberProto::JabberGcInit ); + } + + if ( ServiceExists( MS_MSG_ADDICON )) { + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = m_szModuleName; + sid.hIcon = LoadIconEx("main"); + sid.hIconDisabled = LoadIconEx("main"); + sid.flags = MBF_HIDDEN; + sid.szTooltip = Translate("Jabber Resource"); + CallService(MS_MSG_ADDICON, 0, (LPARAM) &sid); + JHookEvent( ME_MSG_ICONPRESSED, &CJabberProto::OnProcessSrmmIconClick ); + JHookEvent( ME_MSG_WINDOWEVENT, &CJabberProto::OnProcessSrmmEvent ); + + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) + MenuHideSrmmIcon(hContact); + hContact = db_find_next(hContact); + } } + + DBEVENTTYPEDESCR dbEventType = {0}; + dbEventType.cbSize = sizeof(DBEVENTTYPEDESCR); + dbEventType.eventType = JABBER_DB_EVENT_TYPE_CHATSTATES; + dbEventType.module = m_szModuleName; + dbEventType.descr = "Chat state notifications"; + CallService( MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&dbEventType ); + + dbEventType.eventType = JABBER_DB_EVENT_TYPE_PRESENCE; + dbEventType.module = m_szModuleName; + dbEventType.descr = "Presence notifications"; + CallService( MS_DB_EVENT_REGISTERTYPE, 0, (LPARAM)&dbEventType ); + + JHookEvent( ME_IDLE_CHANGED, &CJabberProto::OnIdleChanged ); + + CheckAllContactsAreTransported(); + + // Set all contacts to offline + HANDLE hContact = db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { + SetContactOfflineStatus( hContact ); + + if ( JGetByte( hContact, "IsTransport", 0 )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + TCHAR* domain = NEWTSTR_ALLOCA(dbv.ptszVal); + TCHAR* resourcepos = _tcschr( domain, '/' ); + if ( resourcepos != NULL ) + *resourcepos = '\0'; + m_lstTransports.insert( mir_tstrdup( domain )); + JFreeVariant( &dbv ); + } } } + + hContact = db_find_next(hContact); + } + + CleanLastResourceMap(); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberAddToList - adds a contact to the contact list + +HANDLE CJabberProto::AddToListByJID( const TCHAR* newJid, DWORD flags ) +{ + HANDLE hContact; + TCHAR* jid, *nick; + + Log( "AddToListByJID jid = " TCHAR_STR_PARAM, newJid ); + + if (( hContact=HContactFromJID( newJid )) == NULL ) { + // not already there: add + jid = mir_tstrdup( newJid ); + Log( "Add new jid to contact jid = " TCHAR_STR_PARAM, jid ); + hContact = ( HANDLE ) CallService( MS_DB_CONTACT_ADD, 0, 0 ); + CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )m_szModuleName ); + JSetStringT( hContact, "jid", jid ); + if (( nick=JabberNickFromJID( newJid )) == NULL ) + nick = mir_tstrdup( newJid ); +// JSetStringT( hContact, "Nick", nick ); + mir_free( nick ); + mir_free( jid ); + + // Note that by removing or disable the "NotOnList" will trigger + // the plugin to add a particular contact to the roster list. + // See DBSettingChanged hook at the bottom part of this source file. + // But the add module will delete "NotOnList". So we will not do it here. + // Also because we need "MyHandle" and "Group" info, which are set after + // PS_ADDTOLIST is called but before the add dialog issue deletion of + // "NotOnList". + // If temporary add, "NotOnList" won't be deleted, and that's expected. + DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); + if ( flags & PALF_TEMPORARY ) + DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 ); + } + else { + // already exist + // Set up a dummy "NotOnList" when adding permanently only + if ( !( flags & PALF_TEMPORARY )) + DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 ); + } + + if (hContact && newJid) + DBCheckIsTransportedContact( newJid, hContact ); + return hContact; +} + +HANDLE CJabberProto::AddToList( int flags, PROTOSEARCHRESULT* psr ) +{ + if ( psr->cbSize != sizeof( JABBER_SEARCH_RESULT ) && psr->id == NULL ) + return NULL; + + JABBER_SEARCH_RESULT* jsr = ( JABBER_SEARCH_RESULT* )psr; + TCHAR *jid = psr->id ? psr->id : jsr->jid; + return AddToListByJID( jid, flags ); +} + +HANDLE __cdecl CJabberProto::AddToListByEvent( int flags, int /*iContact*/, HANDLE hDbEvent ) +{ + DBEVENTINFO dbei; + HANDLE hContact; + char* nick, *firstName, *lastName, *jid; + + Log( "AddToListByEvent" ); + ZeroMemory( &dbei, sizeof( dbei )); + dbei.cbSize = sizeof( dbei ); + if (( dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) + return NULL; + if (( dbei.pBlob=( PBYTE ) alloca( dbei.cbBlob )) == NULL ) + return NULL; + if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) + return NULL; + if ( strcmp( dbei.szModule, m_szModuleName )) + return NULL; + +/* + // EVENTTYPE_CONTACTS is when adding from when we receive contact list ( not used in Jabber ) + // EVENTTYPE_ADDED is when adding from when we receive "You are added" ( also not used in Jabber ) + // Jabber will only handle the case of EVENTTYPE_AUTHREQUEST + // EVENTTYPE_AUTHREQUEST is when adding from the authorization request dialog +*/ + + if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) + return NULL; + + nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2); + firstName = nick + strlen( nick ) + 1; + lastName = firstName + strlen( firstName ) + 1; + jid = lastName + strlen( lastName ) + 1; + + TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); + hContact = ( HANDLE ) AddToListByJID( newJid, flags ); + mir_free( newJid ); + return hContact; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberAuthAllow - processes the successful authorization + +int CJabberProto::Authorize( HANDLE hDbEvent ) +{ + DBEVENTINFO dbei; + char* nick, *firstName, *lastName, *jid; + + if ( !m_bJabberOnline ) + return 1; + + memset( &dbei, 0, sizeof( dbei )); + dbei.cbSize = sizeof( dbei ); + if (( dbei.cbBlob=CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) + return 1; + if (( dbei.pBlob=( PBYTE )alloca( dbei.cbBlob )) == NULL ) + return 1; + if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) + return 1; + if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) + return 1; + if ( strcmp( dbei.szModule, m_szModuleName )) + return 1; + + nick = ( char* )(dbei.pBlob + sizeof(DWORD)*2); + firstName = nick + strlen( nick ) + 1; + lastName = firstName + strlen( firstName ) + 1; + jid = lastName + strlen( lastName ) + 1; + + Log( "Send 'authorization allowed' to " TCHAR_STR_PARAM, jid ); + + TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); + + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), newJid) << XATTR( _T("type"), _T("subscribed"))); + + // Automatically add this user to my roster if option is enabled + if ( m_options.AutoAdd == TRUE ) { + HANDLE hContact; + JABBER_LIST_ITEM *item; + + if (( item = ListGetItemPtr( LIST_ROSTER, newJid )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) { + Log( "Try adding contact automatically jid = " TCHAR_STR_PARAM, jid ); + if (( hContact=AddToListByJID( newJid, 0 )) != NULL ) { + // Trigger actual add by removing the "NotOnList" added by AddToListByJID() + // See AddToListByJID() and JabberDbSettingChanged(). + DBDeleteContactSetting( hContact, "CList", "NotOnList" ); + } } } + + mir_free( newJid ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberAuthDeny - handles the unsuccessful authorization + +int CJabberProto::AuthDeny( HANDLE hDbEvent, const TCHAR* /*szReason*/ ) +{ + DBEVENTINFO dbei; + char* nick, *firstName, *lastName, *jid; + + if ( !m_bJabberOnline ) + return 1; + + Log( "Entering AuthDeny" ); + memset( &dbei, 0, sizeof( dbei )); + dbei.cbSize = sizeof( dbei ); + if (( dbei.cbBlob=CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) + return 1; + if (( dbei.pBlob=( PBYTE ) mir_alloc( dbei.cbBlob )) == NULL ) + return 1; + if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )) { + mir_free( dbei.pBlob ); + return 1; + } + if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) { + mir_free( dbei.pBlob ); + return 1; + } + if ( strcmp( dbei.szModule, m_szModuleName )) { + mir_free( dbei.pBlob ); + return 1; + } + + nick = ( char* )( dbei.pBlob + sizeof(DWORD)*2); + firstName = nick + strlen( nick ) + 1; + lastName = firstName + strlen( firstName ) + 1; + jid = lastName + strlen( lastName ) + 1; + + Log( "Send 'authorization denied' to %s" , jid ); + + TCHAR* newJid = dbei.flags & DBEF_UTF ? mir_utf8decodeT( jid ) : mir_a2t( jid ); + + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), newJid) << XATTR( _T("type"), _T("unsubscribed"))); + + mir_free( newJid ); + mir_free( dbei.pBlob ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int __cdecl CJabberProto::AuthRecv( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int __cdecl CJabberProto::AuthRequest( HANDLE, const TCHAR* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// ChangeInfo + +HANDLE __cdecl CJabberProto::ChangeInfo( int /*iInfoType*/, void* ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberFileAllow - starts a file transfer + +HANDLE __cdecl CJabberProto::FileAllow( HANDLE /*hContact*/, HANDLE hTransfer, const TCHAR* szPath ) +{ + if ( !m_bJabberOnline ) + return 0; + + filetransfer* ft = ( filetransfer* )hTransfer; + ft->std.tszWorkingDir = mir_tstrdup( szPath ); + size_t len = _tcslen( ft->std.tszWorkingDir )-1; + if ( ft->std.tszWorkingDir[len] == '/' || ft->std.tszWorkingDir[len] == '\\' ) + ft->std.tszWorkingDir[len] = 0; + + switch ( ft->type ) { + case FT_OOB: + JForkThread(( JThreadFunc )&CJabberProto::FileReceiveThread, ft ); + break; + case FT_BYTESTREAM: + FtAcceptSiRequest( ft ); + break; + case FT_IBB: + FtAcceptIbbRequest( ft ); + break; + } + return hTransfer; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberFileCancel - cancels a file transfer + +int __cdecl CJabberProto::FileCancel( HANDLE /*hContact*/, HANDLE hTransfer ) +{ + filetransfer* ft = ( filetransfer* )hTransfer; + HANDLE hEvent; + + Log( "Invoking FileCancel()" ); + if ( ft->type == FT_OOB ) { + if ( ft->s ) { + Log( "FT canceled" ); + Log( "Closing ft->s = %d", ft->s ); + ft->state = FT_ERROR; + Netlib_CloseHandle( ft->s ); + ft->s = NULL; + if ( ft->hFileEvent != NULL ) { + hEvent = ft->hFileEvent; + ft->hFileEvent = NULL; + SetEvent( hEvent ); + } + Log( "ft->s is now NULL, ft->state is now FT_ERROR" ); + } + } + else FtCancel( ft ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberFileDeny - denies a file transfer + +int __cdecl CJabberProto::FileDeny( HANDLE /*hContact*/, HANDLE hTransfer, const TCHAR* /*reason*/ ) +{ + if ( !m_bJabberOnline ) + return 1; + + filetransfer* ft = ( filetransfer* )hTransfer; + + switch ( ft->type ) { + case FT_OOB: + m_ThreadInfo->send( XmlNodeIq( _T("error"), ft->iqId, ft->jid ) << XCHILD( _T("error"), _T("File transfer refused")) << XATTRI( _T("code"), 406 )); + break; + + case FT_BYTESTREAM: + case FT_IBB: + m_ThreadInfo->send( + XmlNodeIq( _T("error"), ft->iqId, ft->jid ) + << XCHILD( _T("error"), _T("File transfer refused")) << XATTRI( _T("code"), 403 ) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("forbidden"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")) + << XCHILD( _T("text"), _T("File transfer refused")) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + break; + } + delete ft; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberFileResume - processes file renaming etc + +int __cdecl CJabberProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) +{ + filetransfer* ft = ( filetransfer* )hTransfer; + if ( !m_bJabberOnline || ft == NULL ) + return 1; + + if ( *action == FILERESUME_RENAME ) + replaceStrT( ft->std.tszCurrentFile, *szFilename ); + + SetEvent( ft->hWaitEvent ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +DWORD_PTR __cdecl CJabberProto::GetCaps( int type, HANDLE hContact ) +{ + switch( type ) { + case PFLAGNUM_1: + return PF1_IM | PF1_AUTHREQ | PF1_CHAT | PF1_SERVERCLIST | PF1_MODEMSG | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_FILE | PF1_CONTACT; + case PFLAGNUM_2: + return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT; + case PFLAGNUM_3: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT; + case PFLAGNUM_4: + return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_IMSENDUTF | PF4_FORCEADDED; + case PFLAG_UNIQUEIDTEXT: + return ( DWORD_PTR ) JTranslate( "JID" ); + case PFLAG_UNIQUEIDSETTING: + return ( DWORD_PTR ) "jid"; + case PFLAG_MAXCONTACTSPERPACKET: + { + DBVARIANT dbv; + if(JGetStringT( hContact, "jid", &dbv )) + return 0; + TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); + JFreeVariant( &dbv ); + JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); + return (( ~jcb & JABBER_CAPS_ROSTER_EXCHANGE ) ? 0 : 50); + } + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetIcon - loads an icon for the contact list + +HICON __cdecl CJabberProto::GetIcon( int iconIndex ) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)GetIconHandle(IDI_JABBER); + + bool big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = LoadIconEx("main", big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + HICON hIcon2 = CopyIcon(hIcon); + g_ReleaseIcon(hIcon); + return hIcon2; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int __cdecl CJabberProto::GetInfo( HANDLE hContact, int /*infoType*/ ) +{ + if ( !m_bJabberOnline ) + return 1; + + int result = 1; + DBVARIANT dbv; + if ( JGetByte( hContact, "ChatRoom" , 0)) + return 1; + + if ( !JGetStringT( hContact, "jid", &dbv )) { + if ( m_ThreadInfo ) { + TCHAR jid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, jid, SIZEOF( jid )); + + m_ThreadInfo->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultEntityTime, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_HCONTACT )) + << XCHILDNS( _T("time"), _T(JABBER_FEAT_ENTITY_TIME))); + + // XEP-0012, last logoff time + XmlNodeIq iq2( m_iqManager.AddHandler( &CJabberProto::OnIqResultLastActivity, JABBER_IQ_TYPE_GET, dbv.ptszVal, JABBER_IQ_PARSE_FROM )); + iq2 << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)); + m_ThreadInfo->send( iq2 ); + + JABBER_LIST_ITEM *item = NULL; + + if (( item = ListGetItemPtr( LIST_VCARD_TEMP, dbv.ptszVal )) == NULL) + item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); + + if ( !item ) { + TCHAR szBareJid[ JABBER_MAX_JID_LEN ]; + _tcsncpy( szBareJid, dbv.ptszVal, SIZEOF( szBareJid )); + TCHAR* pDelimiter = _tcschr( szBareJid, _T('/')); + if ( pDelimiter ) { + *pDelimiter = 0; + pDelimiter++; + if ( !*pDelimiter ) + pDelimiter = NULL; + } + JABBER_LIST_ITEM *tmpItem = NULL; + if ( pDelimiter && ( tmpItem = ListGetItemPtr( LIST_CHATROOM, szBareJid ))) { + JABBER_RESOURCE_STATUS *him = NULL; + for ( int i=0; i < tmpItem->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& p = tmpItem->resource[i]; + if ( !lstrcmp( p.resourceName, pDelimiter )) him = &p; + } + if ( him ) { + item = ListAdd( LIST_VCARD_TEMP, dbv.ptszVal ); + ListAddResource( LIST_VCARD_TEMP, dbv.ptszVal, him->status, him->statusMessage, him->priority ); + } + } + else + item = ListAdd( LIST_VCARD_TEMP, dbv.ptszVal ); + } + + if ( item ) { + if ( item->resource ) { + for ( int i = 0; i < item->resourceCount; i++ ) { + TCHAR szp1[ JABBER_MAX_JID_LEN ]; + JabberStripJid( dbv.ptszVal, szp1, SIZEOF( szp1 )); + mir_sntprintf( jid, 256, _T("%s/%s"), szp1, item->resource[i].resourceName ); + + XmlNodeIq iq3( m_iqManager.AddHandler( &CJabberProto::OnIqResultLastActivity, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM )); + iq3 << XQUERY( _T(JABBER_FEAT_LAST_ACTIVITY)); + m_ThreadInfo->send( iq3 ); + + if ( !item->resource[i].dwVersionRequestTime ) { + XmlNodeIq iq4( m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE )); + iq4 << XQUERY( _T(JABBER_FEAT_VERSION)); + m_ThreadInfo->send( iq4 ); + } + + if ( !item->resource[i].pSoftwareInfo ) { + XmlNodeIq iq5( m_iqManager.AddHandler( &CJabberProto::OnIqResultCapsDiscoInfoSI, JABBER_IQ_TYPE_GET, jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE | JABBER_IQ_PARSE_HCONTACT )); + iq5 << XQUERY( _T(JABBER_FEAT_DISCO_INFO )); + m_ThreadInfo->send( iq5 ); + } + } + } + else if ( !item->itemResource.dwVersionRequestTime ) { + XmlNodeIq iq4( m_iqManager.AddHandler( &CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, item->jid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE )); + iq4 << XQUERY( _T(JABBER_FEAT_VERSION)); + m_ThreadInfo->send( iq4 ); + } } } + + SendGetVcard( dbv.ptszVal ); + JFreeVariant( &dbv ); + result = 0; + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by JID + +struct JABBER_SEARCH_BASIC +{ int hSearch; + TCHAR jid[128]; +}; + +void __cdecl CJabberProto::BasicSearchThread( JABBER_SEARCH_BASIC *jsb ) +{ + Sleep( 100 ); + + JABBER_SEARCH_RESULT jsr = { 0 }; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + jsr.hdr.flags = PSR_TCHAR; + jsr.hdr.nick = jsb->jid; + jsr.hdr.firstName = _T(""); + jsr.hdr.lastName = _T(""); + jsr.hdr.id = jsb->jid; + + _tcsncpy( jsr.jid, jsb->jid, SIZEOF( jsr.jid )); + + jsr.jid[SIZEOF( jsr.jid )-1] = '\0'; + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) jsb->hSearch, ( LPARAM )&jsr ); + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) jsb->hSearch, 0 ); + mir_free( jsb ); +} + +HANDLE __cdecl CJabberProto::SearchBasic( const TCHAR* szJid ) +{ + Log( "JabberBasicSearch called with lParam = '%s'", szJid ); + + JABBER_SEARCH_BASIC *jsb; + if ( !m_bJabberOnline || ( jsb=( JABBER_SEARCH_BASIC * ) mir_alloc( sizeof( JABBER_SEARCH_BASIC )))==NULL ) + return 0; + + if ( _tcschr( szJid, '@' ) == NULL ) { + TCHAR *szServer = mir_a2t( m_ThreadInfo->server ); + const TCHAR* p = _tcsstr( szJid, szServer ); + if ( !p ) + { + bool numericjid = true; + for (const TCHAR * i = szJid; *i && numericjid; ++i) + numericjid = (*i >= '0') && (*i <= '9'); + + mir_free( szServer ); + szServer = JGetStringT( NULL, "LoginServer" ); + if ( !szServer ) + { + szServer = mir_tstrdup( _T( "jabber.org" )); + } else if (numericjid && !_tcsicmp(szServer, _T("S.ms"))) + { + mir_free(szServer); + szServer = mir_tstrdup(_T("sms")); + } + mir_sntprintf( jsb->jid, SIZEOF(jsb->jid), _T("%s@%s"), szJid, szServer ); + } + else _tcsncpy( jsb->jid, szJid, SIZEOF(jsb->jid)); + mir_free( szServer ); + } + else _tcsncpy( jsb->jid, szJid, SIZEOF(jsb->jid)); + + Log( "Adding '%s' without validation", jsb->jid ); + jsb->hSearch = SerialNext(); + JForkThread(( JThreadFunc )&CJabberProto::BasicSearchThread, jsb ); + return ( HANDLE )jsb->hSearch; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE __cdecl CJabberProto::SearchByEmail( const TCHAR* email ) +{ + if ( !m_bJabberOnline ) return 0; + if ( email == NULL ) return 0; + + char szServerName[100]; + if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) + strcpy( szServerName, "users.jabber.org" ); + + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultSetSearch ); + m_ThreadInfo->send( XmlNodeIq( _T("set"), iqId, _A2T(szServerName)) << XQUERY( _T("jabber:iq:search")) + << XCHILD( _T("email"), email)); + return ( HANDLE )iqId; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSearchByName - searches the contact by its first or last name, or by a nickname + +HANDLE __cdecl CJabberProto::SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName ) +{ + if ( !m_bJabberOnline ) + return NULL; + + BOOL bIsExtFormat = m_options.ExtendedSearch; + + char szServerName[100]; + if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) + strcpy( szServerName, "users.jabber.org" ); + + int iqId = SerialNext(); + XmlNodeIq iq( _T("set"), iqId, _A2T(szServerName)); + HXML query = iq << XQUERY( _T("jabber:iq:search")); + + if ( bIsExtFormat ) { + IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultExtSearch ); + + if ( m_tszSelectedLang ) + iq << XATTR( _T("xml:lang"), m_tszSelectedLang ); + + HXML x = query << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("submit")); + if ( nick[0] != '\0' ) + x << XCHILD( _T("field")) << XATTR( _T("var"), _T("user")) << XATTR( _T("value"), nick); + + if ( firstName[0] != '\0' ) + x << XCHILD( _T("field")) << XATTR( _T("var"), _T("fn")) << XATTR( _T("value"), firstName); + + if ( lastName[0] != '\0' ) + x << XCHILD( _T("field")) << XATTR( _T("var"), _T("given")) << XATTR( _T("value"), lastName); + } + else { + IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultSetSearch ); + if ( nick[0] != '\0' ) + query << XCHILD( _T("nick"), nick); + + if ( firstName[0] != '\0' ) + query << XCHILD( _T("first"), firstName); + + if ( lastName[0] != '\0' ) + query << XCHILD( _T("last"), lastName); + } + + m_ThreadInfo->send( iq ); + return ( HANDLE )iqId; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int __cdecl CJabberProto::RecvContacts( HANDLE /*hContact*/, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvFile + +int __cdecl CJabberProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) +{ + return Proto_RecvFile(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +int __cdecl CJabberProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* evt ) +{ + INT_PTR nDbEvent = Proto_RecvMessage(hContact, evt); + + EnterCriticalSection( &m_csLastResourceMap ); + if (IsLastResourceExists( (void *)evt->lParam)) { + m_ulpResourceToDbEventMap[ m_dwResourceMapPointer++ ] = nDbEvent; + m_ulpResourceToDbEventMap[ m_dwResourceMapPointer++ ] = evt->lParam; + if ( m_dwResourceMapPointer >= SIZEOF( m_ulpResourceToDbEventMap )) + m_dwResourceMapPointer = 0; + } + LeaveCriticalSection( &m_csLastResourceMap ); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvUrl + +int __cdecl CJabberProto::RecvUrl( HANDLE /*hContact*/, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int __cdecl CJabberProto::SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ) +{ + DBVARIANT dbv; + if ( !m_bJabberOnline || JGetStringT( hContact, "jid", &dbv )) { +// JSendBroadcast( hContact, ACKTYPE_CONTACTS, ACKRESULT_FAILED, ( HANDLE ) 1, 0 ); + return 0; + } + + TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); + JFreeVariant( &dbv ); + + JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); + if ( ~jcb & JABBER_CAPS_ROSTER_EXCHANGE ) + return 0; + + XmlNode m( _T("message")); +// m << XCHILD( _T("body"), msg ); + HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_ROSTER_EXCHANGE)); + + for ( int i = 0; i < nContacts; ++i ) { + if (!JGetStringT( hContactsList[i], "jid", &dbv )) { + x << XCHILD( _T("item")) << XATTR( _T("action"), _T("add")) << + XATTR( _T("jid"), dbv.ptszVal); + JFreeVariant( &dbv ); + } + } + + int id = SerialNext(); + m << XATTR( _T("to"), szClientJid ) << XATTRID( id ); + + m_ThreadInfo->send( m ); +// mir_free( msg ); + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE __cdecl CJabberProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) +{ + if ( !m_bJabberOnline ) return 0; + + if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE ) + return 0; + + DBVARIANT dbv; + if ( JGetStringT( hContact, "jid", &dbv )) + return 0; + + int i, j; + struct _stati64 statbuf; + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); + if ( item == NULL ) { + JFreeVariant( &dbv ); + return 0; + } + + // Check if another file transfer session request is pending ( waiting for disco result ) + if ( item->ft != NULL ) { + JFreeVariant( &dbv ); + return 0; + } + + JabberCapsBits jcb = GetResourceCapabilites( item->jid, TRUE ); + if ( jcb == JABBER_RESOURCE_CAPS_IN_PROGRESS ) { + Sleep(600); + jcb = GetResourceCapabilites( item->jid, TRUE ); + } + + // fix for very smart clients, like gajim + if ( !m_options.BsDirect && !m_options.BsProxyManual ) { + // disable bytestreams + jcb &= ~JABBER_CAPS_BYTESTREAMS; + } + + // if only JABBER_CAPS_SI_FT feature set (without BS or IBB), disable JABBER_CAPS_SI_FT + if (( jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_BYTESTREAMS)) == JABBER_CAPS_SI_FT) + jcb &= ~JABBER_CAPS_SI_FT; + + if ( + // can't get caps + ( jcb & JABBER_RESOURCE_CAPS_ERROR ) + // caps not already received + || ( jcb == JABBER_RESOURCE_CAPS_NONE ) + // XEP-0096 and OOB not supported? + || !(jcb & ( JABBER_CAPS_SI_FT | JABBER_CAPS_OOB )) + ) { + JFreeVariant( &dbv ); + MsgPopup( hContact, TranslateT("No compatible file transfer machanism exist"), item->jid ); + return 0; + } + + filetransfer* ft = new filetransfer(this); + ft->std.hContact = hContact; + while( ppszFiles[ ft->std.totalFiles ] != NULL ) + ft->std.totalFiles++; + + ft->std.ptszFiles = ( TCHAR** ) mir_calloc( sizeof( TCHAR* )* ft->std.totalFiles ); + ft->fileSize = ( unsigned __int64* ) mir_calloc( sizeof( unsigned __int64 ) * ft->std.totalFiles ); + for ( i=j=0; i < ft->std.totalFiles; i++ ) { + if ( _tstati64( ppszFiles[i], &statbuf )) + Log( "'%s' is an invalid filename", ppszFiles[i] ); + else { + ft->std.ptszFiles[j] = mir_tstrdup( ppszFiles[i] ); + ft->fileSize[j] = statbuf.st_size; + j++; + ft->std.totalBytes += statbuf.st_size; + } } + if ( j == 0 ) { + delete ft; + JFreeVariant( &dbv ); + return NULL; + } + + ft->std.tszCurrentFile = mir_tstrdup( ppszFiles[0] ); + ft->szDescription = mir_tstrdup( szDescription ); + ft->jid = mir_tstrdup( dbv.ptszVal ); + JFreeVariant( &dbv ); + + if ( jcb & JABBER_CAPS_SI_FT ) + FtInitiate( item->jid, ft ); + else if ( jcb & JABBER_CAPS_OOB ) + JForkThread(( JThreadFunc )&CJabberProto::FileServerThread, ft ); + + return ft; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSendMessage - sends a message + +struct TFakeAckParams +{ + inline TFakeAckParams( HANDLE p1, const char* p2 ) + : hContact( p1 ), msg( p2 ) {} + + HANDLE hContact; + const char* msg; +}; + +void __cdecl CJabberProto::SendMessageAckThread( void* param ) +{ + TFakeAckParams *par = ( TFakeAckParams* )param; + Sleep( 100 ); + Log( "Broadcast ACK" ); + JSendBroadcast( par->hContact, ACKTYPE_MESSAGE, + par->msg ? ACKRESULT_FAILED : ACKRESULT_SUCCESS, + ( HANDLE ) 1, ( LPARAM ) par->msg ); + Log( "Returning from thread" ); + delete par; +} + +static char PGP_PROLOG[] = "-----BEGIN PGP MESSAGE-----\r\n\r\n"; +static char PGP_EPILOG[] = "\r\n-----END PGP MESSAGE-----\r\n"; + +int __cdecl CJabberProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) +{ + int id; + + DBVARIANT dbv; + if ( !m_bJabberOnline || JGetStringT( hContact, "jid", &dbv )) { + TFakeAckParams *param = new TFakeAckParams( hContact, Translate( "Protocol is offline or no jid" )); + JForkThread( &CJabberProto::SendMessageAckThread, param ); + return 1; + } + + TCHAR *msg; + int isEncrypted; + + if ( !strncmp( pszSrc, PGP_PROLOG, strlen( PGP_PROLOG ))) { + const char* szEnd = strstr( pszSrc, PGP_EPILOG ); + char* tempstring = ( char* )alloca( strlen( pszSrc ) + 1 ); + size_t nStrippedLength = strlen(pszSrc) - strlen(PGP_PROLOG) - (szEnd ? strlen(szEnd) : 0); + strncpy( tempstring, pszSrc + strlen(PGP_PROLOG), nStrippedLength ); + tempstring[ nStrippedLength ] = 0; + pszSrc = tempstring; + isEncrypted = 1; + flags &= ~PREF_UNICODE; + } + else isEncrypted = 0; + + if ( flags & PREF_UTF ) { + + mir_utf8decode( NEWSTR_ALLOCA( pszSrc ), &msg ); + + } + else if ( flags & PREF_UNICODE ) + msg = mir_u2t(( wchar_t* )&pszSrc[ strlen( pszSrc )+1 ] ); + else + msg = mir_a2t( pszSrc ); + + int nSentMsgId = 0; + + if ( msg != NULL ) { + TCHAR* msgType; + if ( ListExist( LIST_CHATROOM, dbv.ptszVal ) && _tcschr( dbv.ptszVal, '/' )==NULL ) + msgType = _T("groupchat"); + else + msgType = _T("chat"); + + XmlNode m( _T("message" )); xmlAddAttr( m, _T("type"), msgType ); + if ( !isEncrypted ) + m << XCHILD( _T("body"), msg ); + else { + m << XCHILD( _T("body"), _T("[This message is encrypted.]" )); + m << XCHILD( _T("x"), msg) << XATTR(_T("xmlns"), _T("jabber:x:encrypted")); + } + mir_free( msg ); + + TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); + + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( szClientJid ); + if ( r ) + r->bMessageSessionActive = TRUE; + + JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); + + if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) + jcb = JABBER_RESOURCE_CAPS_NONE; + + if ( jcb & JABBER_CAPS_CHATSTATES ) + m << XCHILDNS( _T("active"), _T(JABBER_FEAT_CHATSTATES)); + + if ( + // if message delivery check disabled by entity caps manager + ( jcb & JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY ) || + // if client knows nothing about delivery + !( jcb & ( JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_RECEIPTS )) || + // if message sent to groupchat + !lstrcmp( msgType, _T("groupchat")) || + // if message delivery check disabled in settings + !m_options.MsgAck || !JGetByte( hContact, "MsgAck", TRUE )) { + if ( !lstrcmp( msgType, _T("groupchat"))) + xmlAddAttr( m, _T("to"), dbv.ptszVal ); + else { + id = SerialNext(); + xmlAddAttr( m, _T("to"), szClientJid ); xmlAddAttrID( m, id ); + } + m_ThreadInfo->send( m ); + + JForkThread( &CJabberProto::SendMessageAckThread, new TFakeAckParams( hContact, 0 )); + + nSentMsgId = 1; + } + else { + id = SerialNext(); + xmlAddAttr( m, _T("to"), szClientJid ); xmlAddAttrID( m, id ); + + // message receipts XEP priority + if ( jcb & JABBER_CAPS_MESSAGE_RECEIPTS ) + m << XCHILDNS( _T("request"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)); + else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { + HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); + x << XCHILD( _T("delivered")); x << XCHILD( _T("offline")); + } + else + id = 1; + + m_ThreadInfo->send( m ); + nSentMsgId = id; + } } + + JFreeVariant( &dbv ); + return nSentMsgId; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int __cdecl CJabberProto::SendUrl( HANDLE /*hContact*/, int /*flags*/, const char* /*url*/ ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSetApparentMode - sets the visibility status + +int __cdecl CJabberProto::SetApparentMode( HANDLE hContact, int mode ) +{ + if ( mode != 0 && mode != ID_STATUS_ONLINE && mode != ID_STATUS_OFFLINE ) + return 1; + + int oldMode = JGetWord( hContact, "ApparentMode", 0 ); + if ( mode == oldMode ) + return 1; + + JSetWord( hContact, "ApparentMode", ( WORD )mode ); + if ( !m_bJabberOnline ) + return 0; + + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + TCHAR* jid = dbv.ptszVal; + switch ( mode ) { + case ID_STATUS_ONLINE: + if ( m_iStatus == ID_STATUS_INVISIBLE || oldMode == ID_STATUS_OFFLINE ) + m_ThreadInfo->send( XmlNode( _T("presence")) << XATTR( _T("to"), jid )); + break; + case ID_STATUS_OFFLINE: + if ( m_iStatus != ID_STATUS_INVISIBLE || oldMode == ID_STATUS_ONLINE ) + SendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL ); + break; + case 0: + if ( oldMode == ID_STATUS_ONLINE && m_iStatus == ID_STATUS_INVISIBLE ) + SendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL ); + else if ( oldMode == ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_INVISIBLE ) + SendPresenceTo( m_iStatus, jid, NULL ); + break; + } + JFreeVariant( &dbv ); + } + + // TODO: update the zebra list ( jabber:iq:privacy ) + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSetStatus - sets the protocol status + +int __cdecl CJabberProto::SetStatus( int iNewStatus ) +{ + if (m_iDesiredStatus == iNewStatus) + return 0; + + int oldStatus = m_iStatus; + + Log( "PS_SETSTATUS( %d )", iNewStatus ); + m_iDesiredStatus = iNewStatus; + + if ( iNewStatus == ID_STATUS_OFFLINE ) { + if ( m_ThreadInfo ) { + if ( m_bJabberOnline ) { + // Quit all chatrooms (will send quit message) + LISTFOREACH(i, this, LIST_CHATROOM) + if (JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex(i)) + GcQuit(item, 0, NULL); + } + + m_ThreadInfo->send( "</stream:stream>" ); + m_ThreadInfo->shutdown(); + + if ( m_bJabberConnected ) { + m_bJabberConnected = m_bJabberOnline = FALSE; + RebuildInfoFrame(); + } + } + + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + } + else if ( !m_bJabberConnected && !m_ThreadInfo && !( m_iStatus >= ID_STATUS_CONNECTING && m_iStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES )) { + m_iStatus = ID_STATUS_CONNECTING; + ThreadData* thread = new ThreadData( this, JABBER_SESSION_NORMAL ); + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + thread->hThread = JForkThreadEx(( JThreadFunc )&CJabberProto::ServerThread, thread ); + + RebuildInfoFrame(); + } + else if ( m_bJabberOnline ) + SetServerStatus( iNewStatus ); + else + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberGetAwayMsg - returns a contact's away message + +void __cdecl CJabberProto::GetAwayMsgThread( void* hContact ) +{ + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + JABBER_RESOURCE_STATUS *r; + int i, msgCount; + size_t len; + + if ( !JGetStringT( hContact, "jid", &dbv )) { + if (( item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) { + JFreeVariant( &dbv ); + if ( item->resourceCount > 0 ) { + Log( "resourceCount > 0" ); + r = item->resource; + len = msgCount = 0; + for ( i=0; i<item->resourceCount; i++ ) + if ( r[i].statusMessage ) { + msgCount++; + len += ( _tcslen( r[i].resourceName ) + _tcslen( r[i].statusMessage ) + 8 ); + } + + TCHAR* str = ( TCHAR* )alloca( sizeof( TCHAR )*( len+1 )); + str[0] = str[len] = '\0'; + for ( i=0; i < item->resourceCount; i++ ) + if ( r[i].statusMessage ) { + if ( str[0] != '\0' ) _tcscat( str, _T("\r\n" )); + if ( msgCount > 1 ) { + _tcscat( str, _T("( ")); + _tcscat( str, r[i].resourceName ); + _tcscat( str, _T(" ): ")); + } + _tcscat( str, r[i].statusMessage ); + } + + JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)str); + return; + } + + if ( item->itemResource.statusMessage != NULL ) { + JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)item->itemResource.statusMessage); + return; + } + } + else JFreeVariant( &dbv ); + } + + JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )0 ); +} + +HANDLE __cdecl CJabberProto::GetAwayMsg( HANDLE hContact ) +{ + Log( "GetAwayMsg called, hContact=%08X", hContact ); + + JForkThread( &CJabberProto::GetAwayMsgThread, hContact ); + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG + +int __cdecl CJabberProto::RecvAwayMsg( HANDLE /*hContact*/, int /*statusMode*/, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AWAYMSG + +int __cdecl CJabberProto::SendAwayMsg( HANDLE /*hContact*/, HANDLE /*hProcess*/, const char* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSetAwayMsg - sets the away status message + +int __cdecl CJabberProto::SetAwayMsg( int status, const TCHAR* msg ) +{ + Log( "SetAwayMsg called, wParam=%d lParam=" TCHAR_STR_PARAM, status, msg ); + + EnterCriticalSection( &m_csModeMsgMutex ); + + TCHAR **szMsg; + + switch ( status ) { + case ID_STATUS_ONLINE: + szMsg = &m_modeMsgs.szOnline; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + szMsg = &m_modeMsgs.szAway; + status = ID_STATUS_AWAY; + break; + case ID_STATUS_NA: + szMsg = &m_modeMsgs.szNa; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + szMsg = &m_modeMsgs.szDnd; + status = ID_STATUS_DND; + break; + case ID_STATUS_FREECHAT: + szMsg = &m_modeMsgs.szFreechat; + break; + default: + LeaveCriticalSection( &m_csModeMsgMutex ); + return 1; + } + + TCHAR* newModeMsg = mir_tstrdup( msg ); + + if (( *szMsg == NULL && newModeMsg == NULL ) || + ( *szMsg != NULL && newModeMsg != NULL && !lstrcmp( *szMsg, newModeMsg ))) { + // Message is the same, no update needed + mir_free( newModeMsg ); + LeaveCriticalSection( &m_csModeMsgMutex ); + } + else { + // Update with the new mode message + if ( *szMsg != NULL ) + mir_free( *szMsg ); + *szMsg = newModeMsg; + // Send a presence update if needed + LeaveCriticalSection( &m_csModeMsgMutex ); + if ( status == m_iStatus ) { + SendPresence( m_iStatus, true ); + } } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberUserIsTyping - sends a UTN notification + +int __cdecl CJabberProto::UserIsTyping( HANDLE hContact, int type ) +{ + if ( !m_bJabberOnline ) return 0; + + DBVARIANT dbv; + if ( JGetStringT( hContact, "jid", &dbv )) return 0; + + JABBER_LIST_ITEM *item; + if (( item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) { + TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; + GetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid )); + + JabberCapsBits jcb = GetResourceCapabilites( szClientJid, TRUE ); + + if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) + jcb = JABBER_RESOURCE_CAPS_NONE; + + XmlNode m( _T("message")); xmlAddAttr( m, _T("to"), szClientJid ); + + if ( jcb & JABBER_CAPS_CHATSTATES ) { + m << XATTR( _T("type"), _T("chat")) << XATTRID( SerialNext()); + switch ( type ) { + case PROTOTYPE_SELFTYPING_OFF: + m << XCHILDNS( _T("paused"), _T(JABBER_FEAT_CHATSTATES)); + m_ThreadInfo->send( m ); + break; + case PROTOTYPE_SELFTYPING_ON: + m << XCHILDNS( _T("composing"), _T(JABBER_FEAT_CHATSTATES)); + m_ThreadInfo->send( m ); + break; + } + } + else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { + HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); + if ( item->messageEventIdStr != NULL ) + x << XCHILD( _T("id"), item->messageEventIdStr ); + + switch ( type ) { + case PROTOTYPE_SELFTYPING_OFF: + m_ThreadInfo->send( m ); + break; + case PROTOTYPE_SELFTYPING_ON: + x << XCHILD( _T("composing")); + m_ThreadInfo->send( m ); + break; + } } } + + JFreeVariant( &dbv ); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Notify dialogs + +void CJabberProto::WindowSubscribe(HWND hwnd) +{ + WindowList_Add(m_windowList, hwnd, NULL); +} + +void CJabberProto::WindowUnsubscribe(HWND hwnd) +{ + WindowList_Remove(m_windowList, hwnd); +} + +void CJabberProto::WindowNotify(UINT msg, bool async) +{ + if (async) + WindowList_BroadcastAsync(m_windowList, msg, 0, 0); + else + WindowList_Broadcast(m_windowList, msg, 0, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// InfoFrame events + +void CJabberProto::InfoFrame_OnSetup(CJabberInfoFrame_Event*) +{ + OnMenuOptions(0,0); +} + +void CJabberProto::InfoFrame_OnTransport(CJabberInfoFrame_Event *evt) +{ + if (evt->m_event == CJabberInfoFrame_Event::CLICK) + { + HANDLE hContact = (HANDLE)evt->m_pUserData; + POINT pt; + + HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + GetCursorPos(&pt); + int res = TrackPopupMenu(hContactMenu, TPM_RETURNCMD, pt.x, pt.y, 0, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL); + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnEvent - maintain protocol events + +int __cdecl CJabberProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ) +{ + switch( eventType ) { + case EV_PROTO_ONLOAD: return OnModulesLoadedEx( 0, 0 ); + case EV_PROTO_ONEXIT: return OnPreShutdown( 0, 0 ); + case EV_PROTO_ONOPTIONS: return OnOptionsInit( wParam, lParam ); + + case EV_PROTO_ONMENU: + MenuInit(); + break; + + case EV_PROTO_ONRENAME: + if ( m_hMenuRoot ) + { + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + clmi.ptszName = m_tszUserName; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_hMenuRoot, ( LPARAM )&clmi ); + } + break; + + case EV_PROTO_ONCONTACTDELETED: + return OnContactDeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return OnDbSettingChanged(wParam, lParam); + } + return 1; +} diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h new file mode 100644 index 0000000000..eff59bb002 --- /dev/null +++ b/protocols/JabberG/src/jabber_proto.h @@ -0,0 +1,1008 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_PROTO_H_ +#define _JABBER_PROTO_H_ + +#include "jabber_disco.h" +#include "jabber_rc.h" +#include "jabber_privacy.h" +#include "jabber_search.h" +#include "jabber_iq.h" +#include "jabber_icolib.h" +#include "jabber_xstatus.h" +#include "jabber_notes.h" +#include "jabber_message_manager.h" +#include "jabber_presence_manager.h" +#include "jabber_send_manager.h" + +struct CJabberProto; +typedef void ( __cdecl CJabberProto::*JThreadFunc )( void* ); +typedef int ( __cdecl CJabberProto::*JEventFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CJabberProto::*JServiceFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CJabberProto::*JServiceFuncParam )( WPARAM, LPARAM, LPARAM ); + +enum TJabberGcLogInfoType { INFO_BAN, INFO_STATUS, INFO_CONFIG, INFO_AFFILIATION, INFO_ROLE }; + +// for JabberEnterString +enum { JES_MULTINE, JES_COMBO, JES_RICHEDIT, JES_PASSWORD }; + +typedef UNIQUE_MAP<TCHAR,TCharKeyCmp> U_TCHAR_MAP; + +#define JABBER_DEFAULT_RECENT_COUNT 10 + +struct JABBER_IQ_FUNC +{ + int iqId; // id to match IQ get/set with IQ result + JABBER_IQ_PROCID procId; // must be unique in the list, except for IQ_PROC_NONE which can have multiple entries + JABBER_IQ_PFUNC func; // callback function + time_t requestTime; // time the request was sent, used to remove relinquent entries +}; + +struct JABBER_GROUPCHAT_INVITE_INFO +{ + TCHAR* roomJid; + TCHAR* from; + TCHAR* reason; + TCHAR* password; +}; + +struct ROSTERREQUSERDATA +{ + HWND hwndDlg; + BYTE bRRAction; + BOOL bReadyToDownload; + BOOL bReadyToUpload; +}; + +struct TFilterInfo +{ + enum Type { T_JID, T_XMLNS, T_ANY, T_OFF }; + + volatile BOOL msg, presence, iq; + volatile Type type; + + CRITICAL_SECTION csPatternLock; + TCHAR pattern[256]; +}; + +struct CJabberSysInterface: public IJabberSysInterface +{ + int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberSysInterface. + int STDMETHODCALLTYPE CompareJIDs(LPCTSTR jid1, LPCTSTR jid2); // Strips resource names from given JIDs and returns result of comparison for these JIDs. + HANDLE STDMETHODCALLTYPE ContactFromJID(LPCTSTR jid); // Returns contact handle for given JID. + LPTSTR STDMETHODCALLTYPE ContactToJID(HANDLE hContact); // Returns JID of hContact. You must free the result using mir_free(). + LPTSTR STDMETHODCALLTYPE GetBestResourceName(LPCTSTR jid); // Returns best resource name for given JID. You must free the result using mir_free(). + LPTSTR STDMETHODCALLTYPE GetResourceList(LPCTSTR jid); // Returns all resource names for a given JID in format "resource1\0resource2\0resource3\0\0" (all resources are separated by \0 character and the whole string is terminated with two \0 characters). You must free the string using mir_free(). + char* STDMETHODCALLTYPE GetModuleName() const; // Returns Jabber module name. + + CJabberProto *m_psProto; +}; + +struct CJabberNetInterface: public IJabberNetInterface +{ + int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberNetInterface. + unsigned int STDMETHODCALLTYPE SerialNext(); // Returns id that can be used for next message sent through SendXmlNode(). + int STDMETHODCALLTYPE SendXmlNode(HXML node); // Sends XML node. + + // In all incoming stanza handlers, return TRUE to continue processing of the stanza (Jabber plugin will then call other handlers). Return FALSE only when you're sure noone else will need to process this stanza. + // Registers incoming <presence/> handler. Returns handler handle on success or NULL on error. + HJHANDLER STDMETHODCALLTYPE AddPresenceHandler(JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority); + // Registers incoming <message/> handler for messages of types specified by iMsgTypes. iMsgTypes is a combination of JABBER_MESSAGE_TYPE_* flags. Returns handler handle on success or NULL on error. + HJHANDLER STDMETHODCALLTYPE AddMessageHandler(JABBER_HANDLER_FUNC Func, int iMsgTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority); + // Registers incoming <iq/> handler. iIqTypes is a combination of JABBER_IQ_TYPE_* flags. Returns handler handle on success or NULL on error. + HJHANDLER STDMETHODCALLTYPE AddIqHandler(JABBER_HANDLER_FUNC Func, int iIqTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority); + // Registers temporary handler for incoming <iq/> stanza of type iIqType with id iIqId. iIqTypes is a combination of JABBER_IQ_TYPE_* flags. Returns handler handle on success or NULL on error. You must free pUserData in the handler by yourself. + HJHANDLER STDMETHODCALLTYPE AddTemporaryIqHandler(JABBER_HANDLER_FUNC Func, int iIqTypes, int iIqId, void *pUserData, DWORD dwTimeout, int iPriority); + + // Registers handler for outgoing nodes. The handler may modify the node if it's necessary. Return TRUE in the handler to continue, or FALSE to abort sending. + HJHANDLER STDMETHODCALLTYPE AddSendHandler(JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority); + + // Unregisters handler by its handle. + int STDMETHODCALLTYPE RemoveHandler(HJHANDLER hHandler); + + int STDMETHODCALLTYPE RegisterFeature(LPCTSTR szFeature, LPCTSTR szDescription); // Registers feature so that it's displayed with proper description in other users' details. Call this function in your ME_SYSTEM_MODULESLOADED handler. Returns TRUE on success or FALSE on error. + int STDMETHODCALLTYPE AddFeatures(LPCTSTR szFeatures); // Adds features to the list of features returned by the client. + int STDMETHODCALLTYPE RemoveFeatures(LPCTSTR szFeatures); // Removes features from the list of features returned by the client. + LPTSTR STDMETHODCALLTYPE GetResourceFeatures(LPCTSTR jid); // Returns all features supported by JID in format "feature1\0feature2\0...\0featureN\0\0". You must free returned string using mir_free(). + + CJabberProto *m_psProto; + +private: + JabberFeatCapPairDynamic *FindFeature(LPCTSTR szFeature); +}; + +struct CJabberInterface: public IJabberInterface +{ + DWORD STDMETHODCALLTYPE GetFlags() const; // Set of JIF_* flags. + int STDMETHODCALLTYPE GetVersion() const; // Returns version of IJabberInterface. + DWORD STDMETHODCALLTYPE GetJabberVersion() const; // Returns Jabber plugin version. + + IJabberSysInterface* STDMETHODCALLTYPE Sys() const; // Jabber system utilities. + IJabberNetInterface* STDMETHODCALLTYPE Net() const; // Jabber network interface. + + CJabberProto *m_psProto; +}; + +struct CJabberProto : public PROTO_INTERFACE, public MZeroedObject +{ + typedef PROTO_INTERFACE CSuper; + + CJabberProto( const char*, const TCHAR* ); + ~CJabberProto(); + + //==================================================================================== + // PROTO_INTERFACE + //==================================================================================== + + virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); + virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); + + virtual int __cdecl Authorize( HANDLE hDbEvent ); + virtual int __cdecl AuthDeny( HANDLE hDbEvent, const TCHAR* szReason ); + virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); + + virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); + + virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); + virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); + virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); + virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); + + virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); + virtual HICON __cdecl GetIcon( int iconIndex ); + virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); + + virtual HANDLE __cdecl SearchBasic( const TCHAR* id ); + virtual HANDLE __cdecl SearchByEmail( const TCHAR* email ); + virtual HANDLE __cdecl SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName ); + virtual HWND __cdecl SearchAdvanced( HWND owner ); + virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); + + virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); + virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); + + virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); + virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); + virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); + virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); + + virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); + virtual int __cdecl SetStatus( int iNewStatus ); + + virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); + virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); + virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); + virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); + + virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); + + virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); + + //====| Services |==================================================================== + INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl GetMyAwayMsg(WPARAM wParam, LPARAM lParam); + + //====| Events |====================================================================== + void __cdecl OnAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + int __cdecl OnContactDeleted( WPARAM, LPARAM ); + int __cdecl OnDbSettingChanged( WPARAM, LPARAM ); + int __cdecl OnIdleChanged( WPARAM, LPARAM ); + int __cdecl OnModernOptInit( WPARAM, LPARAM ); + int __cdecl OnModulesLoadedEx( WPARAM, LPARAM ); + int __cdecl OnOptionsInit( WPARAM, LPARAM ); + int __cdecl OnPreShutdown( WPARAM, LPARAM ); + int __cdecl OnPrebuildContactMenu( WPARAM, LPARAM ); + int __cdecl OnMsgUserTyping( WPARAM, LPARAM ); + int __cdecl OnProcessSrmmIconClick( WPARAM, LPARAM ); + int __cdecl OnProcessSrmmEvent( WPARAM, LPARAM ); + int __cdecl OnReloadIcons( WPARAM, LPARAM ); + void __cdecl OnRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + void __cdecl OnRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact ); + int __cdecl OnUserInfoInit( WPARAM, LPARAM ); + + int __cdecl JabberGcEventHook( WPARAM, LPARAM ); + int __cdecl JabberGcMenuHook( WPARAM, LPARAM ); + int __cdecl JabberGcInit( WPARAM, LPARAM ); + + int __cdecl CListMW_ExtraIconsApply( WPARAM, LPARAM ); + + // Google Shared Status + BOOL m_bGoogleSharedStatus; + BOOL m_bGoogleSharedStatusLock; + void OnIqResultGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo); + BOOL OnIqSetGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo); + void SendIqGoogleSharedStatus(int status, const TCHAR *msg); + + //====| Data |======================================================================== + + ThreadData* m_ThreadInfo; + CJabberOptions m_options; + + HANDLE m_hNetlibUser; + PVOID m_sslCtx; + + HANDLE m_hThreadHandle; + + TCHAR* m_szJabberJID; + char* m_szStreamId; + BOOL m_bJabberConnected; // TCP connection to jabber server established + BOOL m_bJabberOnline; // XMPP connection initialized and we can send XMPP packets + int m_nJabberSearchID; + time_t m_tmJabberLoggedInTime; + time_t m_tmJabberIdleStartTime; + UINT m_nJabberCodePage; + TCHAR* m_tszSelectedLang; + + CMString m_szCurrentEntityCapsHash; + + CRITICAL_SECTION m_csModeMsgMutex; + JABBER_MODEMSGS m_modeMsgs; + BOOL m_bModeMsgStatusChangePending; + + HANDLE m_hHookExtraIconsRebuild; + HANDLE m_hHookExtraIconsApply; + + BOOL m_bChangeStatusMessageOnly; + BOOL m_bSendKeepAlive; + BOOL m_bPepSupported; + BOOL m_bGoogleTalk; + + HWND m_hwndAgentRegInput; + HWND m_hwndRegProgress; + HWND m_hwndJabberChangePassword; + HWND m_hwndMucVoiceList; + HWND m_hwndMucMemberList; + HWND m_hwndMucModeratorList; + HWND m_hwndMucBanList; + HWND m_hwndMucAdminList; + HWND m_hwndMucOwnerList; + HWND m_hwndJabberAddBookmark; + HWND m_hwndPrivacyRule; + + CJabberDlgBase *m_pDlgPrivacyLists; + CJabberDlgBase *m_pDlgBookmarks; + CJabberDlgBase *m_pDlgServiceDiscovery; + CJabberDlgBase *m_pDlgJabberJoinGroupchat; + CJabberDlgBase *m_pDlgNotes; + + HANDLE m_windowList; + + // Service and event handles + HANDLE m_hEventNudge; + HANDLE m_hEventXStatusIconChanged; + HANDLE m_hEventXStatusChanged; + + // Transports list + LIST<TCHAR> m_lstTransports; + + CJabberIqManager m_iqManager; + CJabberMessageManager m_messageManager; + CJabberPresenceManager m_presenceManager; // manager of <presence> stanzas and their handlers + CJabberSendManager m_sendManager; // manager of outgoing stanza handlers + CJabberAdhocManager m_adhocManager; + CJabberClientCapsManager m_clientCapsManager; + CPrivacyListManager m_privacyListManager; + CJabberSDManager m_SDManager; + + //HWND m_hwndConsole; + CJabberDlgBase *m_pDlgConsole; + HANDLE m_hThreadConsole; + UINT m_dwConsoleThreadId; + + // proto frame + CJabberInfoFrame *m_pInfoFrame; + + LIST<JABBER_LIST_ITEM> m_lstRoster; + CRITICAL_SECTION m_csLists; + BOOL m_bListInitialised; + + LIST<JabberFeatCapPairDynamic> m_lstJabberFeatCapPairsDynamic; // list of features registered through IJabberNetInterface::RegisterFeature() + JabberCapsBits m_uEnabledFeatCapsDynamic; + + CRITICAL_SECTION m_csIqList; + JABBER_IQ_FUNC *m_ppIqList; + int m_nIqCount; + int m_nIqAlloced; + + HGENMENU m_hMenuRoot; + HGENMENU m_hMenuChangePassword; + HGENMENU m_hMenuGroupchat; + HGENMENU m_hMenuBookmarks; + HGENMENU m_hMenuNotes; + + HGENMENU m_hMenuPrivacyLists; + HGENMENU m_hMenuRosterControl; + HGENMENU m_hMenuServiceDiscovery; + HGENMENU m_hMenuSDMyTransports; + HGENMENU m_hMenuSDTransports; + HGENMENU m_hMenuSDConferences; + + HWND m_hwndCommandWindow; + + int m_nIqIdRegGetReg; + int m_nIqIdRegSetReg; + + int m_nSDBrowseMode; + DWORD m_dwSDLastRefresh; + DWORD m_dwSDLastAutoDisco; + + HANDLE m_hChooseMenuItem; + int m_privacyMenuServiceAllocated; + + TFilterInfo m_filterInfo; + + CNoteList m_notes; + + CRITICAL_SECTION m_csLastResourceMap; + void *m_pLastResourceList; + ULONG_PTR m_ulpResourceToDbEventMap[256]; // last 128 messages (128+128) + DWORD m_dwResourceMapPointer; + + CJabberInterface m_JabberApi; + CJabberSysInterface m_JabberSysApi; + CJabberNetInterface m_JabberNetApi; + + /******************************************************************* + * Function declarations + *******************************************************************/ + + void JabberUpdateDialogs( BOOL bEnable ); + + void CleanLastResourceMap(); + BOOL IsLastResourceExists(void *pResource); + void* AddToLastResourceMap( LPCTSTR szFullJid ); + TCHAR* FindLastResourceByDbEvent( HANDLE hDbEvent ); + + //---- jabber_adhoc.cpp -------------------------------------------------------------- + + int __cdecl ContactMenuRunCommands(WPARAM wParam, LPARAM lParam); + + HWND GetWindowFromIq( HXML iqNode ); + BOOL HandleAdhocCommandRequest( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL IsRcRequestAllowedByACL( CJabberIqInfo* pInfo ); + + int AdhocSetStatusHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + int AdhocOptionsHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + int AdhocForwardHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + int AdhocLockWSHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + int AdhocQuitMirandaHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + int AdhocLeaveGroupchatsHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + + void OnIqResult_ListOfCommands( HXML iqNode ); + void OnIqResult_CommandExecution( HXML iqNode ); + int AdHoc_RequestListOfCommands( TCHAR * szResponder, HWND hwndDlg ); + int AdHoc_ExecuteCommand( HWND hwndDlg, TCHAR * jid, struct JabberAdHocData* dat ); + int AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData * dat, TCHAR* action); + int AdHoc_AddCommandRadio(HWND hFrame, TCHAR * labelStr, int id, int ypos, int value); + int AdHoc_OnJAHMCommandListResult( HWND hwndDlg, HXML iqNode, JabberAdHocData* dat ); + int AdHoc_OnJAHMProcessResult( HWND hwndDlg, HXML workNode, JabberAdHocData* dat ); + + void ContactMenuAdhocCommands( struct CJabberAdhocStartupParams* param ); + + //---- jabber_bookmarks.c ------------------------------------------------------------ + + INT_PTR __cdecl OnMenuHandleBookmarks( WPARAM wParam, LPARAM lParam ); + + int AddEditBookmark( JABBER_LIST_ITEM* item ); + + //---- jabber_notes.c ----------------------------------------------------------------- + + void CJabberProto::ProcessIncomingNote(CNoteItem *pNote, bool ok); + void CJabberProto::ProcessOutgoingNote(CNoteItem *pNote, bool ok); + + bool CJabberProto::OnIncomingNote(const TCHAR *szFrom, HXML hXml); + + INT_PTR __cdecl CJabberProto::OnMenuSendNote(WPARAM, LPARAM); + INT_PTR __cdecl CJabberProto::OnMenuHandleNotes(WPARAM, LPARAM); + INT_PTR __cdecl CJabberProto::OnIncomingNoteEvent(WPARAM, LPARAM); + + //---- jabber_byte.c ----------------------------------------------------------------- + + void __cdecl ByteSendThread( JABBER_BYTE_TRANSFER *jbt ); + void __cdecl ByteReceiveThread( JABBER_BYTE_TRANSFER *jbt ); + + void IqResultProxyDiscovery( HXML iqNode, CJabberIqInfo* pInfo ); + void ByteInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ); + void ByteSendViaProxy( JABBER_BYTE_TRANSFER *jbt ); + int ByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); + void IqResultStreamActivate( HXML iqNode ); + int ByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); + int ByteSendProxyParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ); + + //---- jabber_caps.cpp --------------------------------------------------------------- + + JabberCapsBits GetTotalJidCapabilites( const TCHAR *jid ); + JabberCapsBits GetResourceCapabilites( const TCHAR *jid, BOOL appendBestResource ); + + //---- jabber_captcha.cpp ------------------------------------------------------------ + + void GetCaptchaImage ( HXML node, char *ImageBuf, const TCHAR *PicType, TCHAR*& CaptchaPath); + void sendCaptchaResult(TCHAR* buf, ThreadData* info, LPCTSTR from, LPCTSTR challenge, LPCTSTR fromjid, LPCTSTR sid); + void sendCaptchaError(ThreadData* info, LPCTSTR from, LPCTSTR to, LPCTSTR challenge); + + //---- jabber_chat.cpp --------------------------------------------------------------- + + void GcLogCreate( JABBER_LIST_ITEM* item ); + void GcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, const TCHAR* resource, const TCHAR* nick, const TCHAR* jid, int action, HXML reason, int nStatusCode = -1 ); + void GcLogShowInformation( JABBER_LIST_ITEM *item, JABBER_RESOURCE_STATUS *user, TJabberGcLogInfoType type ); + void GcQuit( JABBER_LIST_ITEM* jid, int code, HXML reason ); + + void FilterList(HWND hwndList); + void ResetListOptions(HWND hwndList); + void InviteUser(TCHAR *room, TCHAR *pUser, TCHAR *text); + + void AdminSet( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal ); + void AdminGet( const TCHAR* to, const TCHAR* ns, const TCHAR* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo ); + void AdminSetReason( const TCHAR* to, const TCHAR* ns, const TCHAR* szItem, const TCHAR* itemVal, const TCHAR* var, const TCHAR* varVal, const TCHAR* rsn ); + void AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str ); + void AddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str , TCHAR* rsn); + void DeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid ); + + //---- jabber_console.cpp ------------------------------------------------------------ + + INT_PTR __cdecl OnMenuHandleConsole( WPARAM wParam, LPARAM lParam ); + void __cdecl ConsoleThread( void* ); + + void ConsoleInit( void ); + void ConsoleUninit( void ); + + bool FilterXml(HXML node, DWORD flags); + bool RecursiveCheckFilter(HXML node, DWORD flags); + + //---- jabber_disco.cpp -------------------------------------------------------------- + + void LaunchServiceDiscovery(TCHAR *jid); + INT_PTR __cdecl OnMenuHandleServiceDiscovery( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleServiceDiscoveryMyTransports( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleServiceDiscoveryTransports( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleServiceDiscoveryConferences( WPARAM wParam, LPARAM lParam ); + + void OnIqResultServiceDiscoveryInfo( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultServiceDiscoveryItems( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultServiceDiscoveryRootInfo( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultServiceDiscoveryRoot( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultServiceDiscoveryRootItems( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL SendInfoRequest(CJabberSDNode* pNode, HXML parent); + BOOL SendBothRequests(CJabberSDNode* pNode, HXML parent); + void PerformBrowse(HWND hwndDlg); + BOOL IsNodeRegistered(CJabberSDNode *pNode); + void ApplyNodeIcon(HTREELISTITEM hItem, CJabberSDNode *pNode); + BOOL SyncTree(HTREELISTITEM hIndex, CJabberSDNode* pNode); + void ServiceDiscoveryShowMenu(CJabberSDNode *node, HTREELISTITEM hItem, POINT pt); + + int SetupServiceDiscoveryDlg( TCHAR* jid ); + + void OnIqResultCapsDiscoInfo( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultCapsDiscoInfoSI( HXML iqNode, CJabberIqInfo* pInfo ); + + void RegisterAgent( HWND hwndDlg, TCHAR* jid ); + + //---- jabber_file.cpp --------------------------------------------------------------- + + int FileReceiveParse( filetransfer* ft, char* buffer, int datalen ); + int FileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen ); + + void UpdateChatUserStatus( wchar_t* chat_jid, wchar_t* jid, wchar_t* nick, int role, int affil, int status, BOOL update_nick ); + + void GroupchatJoinRoomByJid(HWND hwndParent, TCHAR *jid); + + void RenameParticipantNick( JABBER_LIST_ITEM* item, const TCHAR* oldNick, HXML itemNode ); + void AcceptGroupchatInvite( const TCHAR* roomJid, const TCHAR* reason, const TCHAR* password ); + + //---- jabber_form.c ----------------------------------------------------------------- + + void FormCreateDialog( HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata ); + + //---- jabber_ft.c ------------------------------------------------------------------- + + void __cdecl FileReceiveThread( filetransfer* ft ); + void __cdecl FileServerThread( filetransfer* ft ); + + void FtCancel( filetransfer* ft ); + void FtInitiate( TCHAR* jid, filetransfer* ft ); + void FtHandleSiRequest( HXML iqNode ); + void FtAcceptSiRequest( filetransfer* ft ); + void FtAcceptIbbRequest( filetransfer* ft ); + BOOL FtHandleBytestreamRequest( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL FtHandleIbbRequest( HXML iqNode, BOOL bOpen ); + + //---- jabber_groupchat.c ------------------------------------------------------------ + + INT_PTR __cdecl OnMenuHandleJoinGroupchat( WPARAM wParam, LPARAM lParam ); + void __cdecl GroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo ); + + INT_PTR __cdecl OnJoinChat( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnLeaveChat( WPARAM wParam, LPARAM lParam ); + + JABBER_RESOURCE_STATUS* GcFindResource(JABBER_LIST_ITEM *item, const TCHAR *resource); + void GroupchatJoinRoom( LPCTSTR server, LPCTSTR room, LPCTSTR nick, LPCTSTR password, bool autojoin = false ); + void GroupchatProcessPresence( HXML node ); + void GroupchatProcessMessage( HXML node ); + void GroupchatProcessInvite( LPCTSTR roomJid, LPCTSTR from, LPCTSTR reason, LPCTSTR password ); + void GroupchatJoinDlg( TCHAR* roomJid ); + void OnIqResultDiscovery(HXML iqNode, CJabberIqInfo *pInfo); + + //---- jabber_icolib.cpp ------------------------------------------------------------- + + int* m_transportProtoTableStartIndex; + + void IconsInit( void ); + HANDLE GetIconHandle( int iconId ); + HICON LoadIconEx( const char* name, bool big = false ); + int LoadAdvancedIcons(int iID); + int GetTransportProtoID( TCHAR* TransportDomain ); + int GetTransportStatusIconIndex(int iID, int Status); + BOOL DBCheckIsTransportedContact(const TCHAR* jid, HANDLE hContact); + void CheckAllContactsAreTransported( void ); + INT_PTR __cdecl JGetAdvancedStatusIcon(WPARAM wParam, LPARAM lParam ); + + //---- jabber_iq.c ------------------------------------------------------------------- + + JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId ); + + void __cdecl ExpirerThread( void* ); + + void IqInit(); + void IqUninit(); + void IqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func ); + void IqRemove( int index ); + void IqExpire(); + + void OnIqResultBind( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultDiscoBookmarks( HXML iqNode ); + void OnIqResultEntityTime( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultExtSearch( HXML iqNode ); + void OnIqResultGetAuth( HXML iqNode ); + void OnIqResultGetVCardAvatar( HXML iqNode ); + void OnIqResultGetClientAvatar( HXML iqNode ); + void OnIqResultGetServerAvatar( HXML iqNode ); + void OnIqResultGotAvatar( HANDLE hContact, HXML n, const TCHAR* mimeType ); + void OnIqResultGetMuc( HXML iqNode ); + void OnIqResultGetRegister( HXML iqNode ); + void OnIqResultGetRoster( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultGetVcard( HXML iqNode ); + void OnIqResultLastActivity( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultMucGetAdminList( HXML iqNode ); + void OnIqResultMucGetBanList( HXML iqNode ); + void OnIqResultMucGetMemberList( HXML iqNode ); + void OnIqResultMucGetModeratorList( HXML iqNode ); + void OnIqResultMucGetOwnerList( HXML iqNode ); + void OnIqResultMucGetVoiceList( HXML iqNode ); + void OnIqResultNestedRosterGroups( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultNotes( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultSession( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultSetAuth( HXML iqNode ); + void OnIqResultSetBookmarks( HXML iqNode ); + void OnIqResultSetPassword( HXML iqNode ); + void OnIqResultSetRegister( HXML iqNode ); + void OnIqResultSetSearch( HXML iqNode ); + void OnIqResultSetVcard( HXML iqNode ); + void OnIqResultVersion( HXML node, CJabberIqInfo *pInfo ); + void OnProcessLoginRq( ThreadData* info, DWORD rq ); + void OnLoggedIn( void ); + + //---- jabber_iq_handlers.cpp -------------------------------------------------------- + + BOOL OnIqRequestVersion( HXML node, CJabberIqInfo* pInfo ); + BOOL OnIqRequestLastActivity( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqRequestPing( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqRequestTime( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqProcessIqOldTime( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqRequestAvatar( HXML node, CJabberIqInfo *pInfo ); + BOOL OnSiRequest( HXML node, CJabberIqInfo *pInfo ); + BOOL OnRosterPushRequest( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqRequestOOB( HXML node, CJabberIqInfo *pInfo ); + BOOL OnIqHttpAuth( HXML node, CJabberIqInfo* pInfo ); + BOOL AddClistHttpAuthEvent( CJabberHttpAuthParams *pParams ); + + void __cdecl IbbSendThread( JABBER_IBB_TRANSFER *jibb ); + void __cdecl IbbReceiveThread( JABBER_IBB_TRANSFER *jibb ); + + void OnIbbInitiateResult( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIbbCloseResult( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL OnFtHandleIbbIq( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL OnIbbRecvdData( const TCHAR *data, const TCHAR *sid, const TCHAR *seq ); + + void OnFtSiResult( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL FtIbbSend( int blocksize, filetransfer* ft ); + BOOL FtSend( HANDLE hConn, filetransfer* ft ); + void FtSendFinal( BOOL success, filetransfer* ft ); + int FtReceive( HANDLE hConn, filetransfer* ft, char* buffer, int datalen ); + void FtReceiveFinal( BOOL success, filetransfer* ft ); + + //---- jabber_message_handlers.cpp -------------------------------------------------------- + + BOOL OnMessageError( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + BOOL OnMessageIbb( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + BOOL OnMessagePubsubEvent( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + BOOL OnMessageGroupchat( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + + //---- jabber_list.cpp --------------------------------------------------------------- + + JABBER_LIST_ITEM *ListAdd( JABBER_LIST list, const TCHAR* jid ); + JABBER_LIST_ITEM *ListGetItemPtr( JABBER_LIST list, const TCHAR* jid ); + JABBER_LIST_ITEM *ListGetItemPtrFromIndex( int index ); + + void ListWipe( void ); + int ListExist( JABBER_LIST list, const TCHAR* jid ); + + BOOL ListLock(); + BOOL ListUnlock(); + + void ListRemove( JABBER_LIST list, const TCHAR* jid ); + void ListRemoveList( JABBER_LIST list ); + void ListRemoveByIndex( int index ); + int ListFindNext( JABBER_LIST list, int fromOffset ); + + JABBER_RESOURCE_STATUS *CJabberProto::ListFindResource( JABBER_LIST list, const TCHAR* jid ); + int ListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage, char priority = 0, const TCHAR* nick = NULL ); + void ListRemoveResource( JABBER_LIST list, const TCHAR* jid ); + TCHAR* ListGetBestResourceNamePtr( const TCHAR* jid ); + TCHAR* ListGetBestClientResourceNamePtr( const TCHAR* jid ); + + void SetMucConfig( HXML node, void *from ); + void OnIqResultMucGetJidList( HXML iqNode, JABBER_MUC_JIDLIST_TYPE listType ); + + void OnIqResultServerDiscoInfo( HXML iqNode ); + void OnIqResultGetVcardPhoto( const TCHAR* jid, HXML n, HANDLE hContact, BOOL& hasPhoto ); + void SetBookmarkRequest (XmlNodeIq& iqId); + + //---- jabber_menu.cpp --------------------------------------------------------------- + + INT_PTR __cdecl OnMenuConvertChatContact( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuRosterAdd( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuOptions( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuTransportLogin( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuTransportResolve( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuBookmarkAdd( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuRevokeAuth( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnMenuHandleResource(WPARAM wParam, LPARAM lParam, LPARAM res); + INT_PTR __cdecl OnMenuHandleDirectPresence(WPARAM wParam, LPARAM lParam, LPARAM res); + INT_PTR __cdecl OnMenuSetPriority(WPARAM wParam, LPARAM lParam, LPARAM dwDelta); + + void GlobalMenuInit( void ); + void GlobalMenuUninit( void ); + + void MenuInit( void ); + + void MenuHideSrmmIcon(HANDLE hContact); + void MenuUpdateSrmmIcon(JABBER_LIST_ITEM *item); + + void AuthWorker( HANDLE hContact, char* authReqType ); + + void UpdatePriorityMenu(short priority); + + HGENMENU m_hMenuPriorityRoot; + short m_priorityMenuVal; + bool m_priorityMenuValSet; + + //---- jabber_misc.c ----------------------------------------------------------------- + + INT_PTR __cdecl OnGetEventTextChatStates( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnGetEventTextPresence( WPARAM wParam, LPARAM lParam ); + + void AddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName ); + void DBAddAuthRequest( const TCHAR* jid, const TCHAR* nick ); + BOOL AddDbPresenceEvent(HANDLE hContact, BYTE btEventType); + HANDLE DBCreateContact( const TCHAR* jid, const TCHAR* nick, BOOL temporary, BOOL stripResource ); + void GetAvatarFileName( HANDLE hContact, TCHAR* pszDest, size_t cbLen ); + void ResolveTransportNicks( const TCHAR* jid ); + void SetServerStatus( int iNewStatus ); + void FormatMirVer(JABBER_RESOURCE_STATUS *resource, TCHAR *buf, int bufSize); + void UpdateMirVer(JABBER_LIST_ITEM *item); + void UpdateMirVer(HANDLE hContact, JABBER_RESOURCE_STATUS *resource); + void UpdateSubscriptionInfo(HANDLE hContact, JABBER_LIST_ITEM *item); + void SetContactOfflineStatus( HANDLE hContact ); + void InitCustomFolders( void ); + void InitPopups( void ); + void MsgPopup( HANDLE hContact, const TCHAR *szMsg, const TCHAR *szTitle ); + + //---- jabber_opt.cpp ---------------------------------------------------------------- + + CJabberDlgBase::CreateParam OptCreateAccount; + CJabberDlgBase::CreateParam OptCreateGc; + CJabberDlgBase::CreateParam OptCreateAdvanced; + + INT_PTR __cdecl OnMenuHandleRosterControl( WPARAM wParam, LPARAM lParam ); + + void _RosterExportToFile(HWND hwndDlg); + void _RosterImportFromFile(HWND hwndDlg); + void _RosterSendRequest(HWND hwndDlg, BYTE rrAction); + void _RosterHandleGetRequest( HXML node ); + + //---- jabber_password.cpp -------------------------------------------------------------- + + INT_PTR __cdecl OnMenuHandleChangePassword( WPARAM wParam, LPARAM lParam ); + + //---- jabber_privacy.cpp ------------------------------------------------------------ + ROSTERREQUSERDATA rrud; + + INT_PTR __cdecl menuSetPrivacyList( WPARAM wParam, LPARAM lParam, LPARAM iList ); + INT_PTR __cdecl OnMenuHandlePrivacyLists( WPARAM wParam, LPARAM lParam ); + + void BuildPrivacyMenu( void ); + void BuildPrivacyListsMenu( bool bDeleteOld ); + + void QueryPrivacyLists( ThreadData *pThreadInfo = NULL ); + + BOOL OnIqRequestPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultPrivacyList( HXML iqNode ); + void OnIqResultPrivacyLists( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultPrivacyListActive( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultPrivacyListDefault( HXML iqNode, CJabberIqInfo* pInfo ); + void OnIqResultPrivacyListModify( HXML iqNode, CJabberIqInfo* pInfo ); + + //---- jabber_proto.cpp -------------------------------------------------------------- + + void __cdecl BasicSearchThread( struct JABBER_SEARCH_BASIC *jsb ); + void __cdecl GetAwayMsgThread( void* hContact ); + void __cdecl SendMessageAckThread( void* hContact ); + + HANDLE AddToListByJID( const TCHAR* newJid, DWORD flags ); + void WindowSubscribe(HWND hwnd); + void WindowUnsubscribe(HWND hwnd); + void WindowNotify(UINT msg, bool async = false); + + void InfoFrame_OnSetup(CJabberInfoFrame_Event *evt); + void InfoFrame_OnTransport(CJabberInfoFrame_Event *evt); + + //---- jabber_rc.cpp ----------------------------------------------------------------- + + int RcGetUnreadEventsCount( void ); + + //---- jabber_search.cpp ------------------------------------------------------------- + + void SearchReturnResults( HANDLE id, void* pvUsersInfo, U_TCHAR_MAP* pmAllFields ); + void OnIqResultAdvancedSearch( HXML iqNode ); + void OnIqResultGetSearchFields( HXML iqNode ); + int SearchRenewFields( HWND hwndDlg, JabberSearchData * dat); + void SearchDeleteFromRecent( const TCHAR* szAddr, BOOL deleteLastFromDB = TRUE ); + void SearchAddToRecent( const TCHAR* szAddr, HWND hwndDialog = NULL ); + + //---- jabber_std.cpp ---------------------------------------------- + + void JCreateService( const char* szService, JServiceFunc serviceProc ); + void JCreateServiceParam( const char* szService, JServiceFuncParam serviceProc, LPARAM lParam ); + HANDLE JCreateHookableEvent( const char* szService ); + void JForkThread( JThreadFunc, void* ); + HANDLE JForkThreadEx( JThreadFunc, void*, UINT* threadID = NULL ); + + void JDeleteSetting( HANDLE hContact, const char* valueName ); +// DWORD JGetByte( const char* valueName, int parDefltValue ); + DWORD JGetByte( HANDLE hContact, const char* valueName, int parDefltValue ); + char* JGetContactName( HANDLE hContact ); + DWORD JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue ); + int JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len ); + int JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv ); + int JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv ); + TCHAR *JGetStringT( HANDLE hContact, char* valueName ); + TCHAR *JGetStringT( HANDLE hContact, char* valueName, TCHAR *&out ); + TCHAR *JGetStringT( HANDLE hContact, char* valueName, TCHAR *buf, int size ); + WORD JGetWord( HANDLE hContact, const char* valueName, int parDefltValue ); + void JHookEvent( const char*, JEventFunc ); + int JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam ); +// DWORD JSetByte( const char* valueName, int parValue ); + DWORD JSetByte( HANDLE hContact, const char* valueName, int parValue ); + DWORD JSetDword( HANDLE hContact, const char* valueName, DWORD parValue ); + DWORD JSetString( HANDLE hContact, const char* valueName, const char* parValue ); + DWORD JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue ); + DWORD JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue ); + DWORD JSetWord( HANDLE hContact, const char* valueName, int parValue ); + + TCHAR* JGetStringCrypt( HANDLE hContact, char* valueName ); + DWORD JSetStringCrypt( HANDLE hContact, char* valueName, const TCHAR* parValue ); + + //---- jabber_svc.c ------------------------------------------------------------------ + + void CheckMenuItems(); + void EnableMenuItems( BOOL bEnable ); + + INT_PTR __cdecl JabberGetAvatar( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberGetAvatarCaps( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberGetAvatarInfo( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl ServiceSendXML( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberSetAvatar( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberSetNickname( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberSendNudge( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberGCGetToolTipText( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberServiceParseXmppURI( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl OnHttpAuthRequest( WPARAM wParam, LPARAM lParam ); + INT_PTR __cdecl JabberGetApi( WPARAM wParam, LPARAM lParam ); + + void ExternalTempIqHandler( HXML node, CJabberIqInfo *pInfo ); + BOOL ExternalIqHandler( HXML node, CJabberIqInfo *pInfo ); + BOOL ExternalMessageHandler( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ); + BOOL ExternalPresenceHandler( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ); + BOOL ExternalSendHandler( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ); + + BOOL SendHttpAuthReply( CJabberHttpAuthParams *pParams, BOOL bAuthorized ); + + //---- jabber_thread.c ---------------------------------------------- + + TCHAR m_savedPassword[512]; + + typedef struct { + bool isPlainAvailable; + bool isPlainOldAvailable; + bool isMd5Available; + bool isScramAvailable; + bool isNtlmAvailable; + bool isSpnegoAvailable; + bool isKerberosAvailable; + bool isAuthAvailable; + bool isSessionAvailable; + TCHAR *m_gssapiHostName; + } AUTHMECHS; + + AUTHMECHS m_AuthMechs; + + void __cdecl ServerThread( ThreadData* info ); + + void OnProcessFailure( HXML node, ThreadData *info ); + void OnProcessError( HXML node, ThreadData *info ); + void OnProcessSuccess( HXML node, ThreadData *info ); + void OnProcessChallenge( HXML node, ThreadData *info ); + void OnProcessProceed( HXML node, ThreadData *info ); + void OnProcessCompressed( HXML node, ThreadData *info ); + void OnProcessMessage( HXML node, ThreadData *info ); + void OnProcessPresence( HXML node, ThreadData *info ); + void OnProcessPresenceCapabilites( HXML node ); + void OnProcessPubsubEvent( HXML node ); + + void OnProcessStreamOpening( HXML node, ThreadData *info ); + void OnProcessProtocol( HXML node, ThreadData *info ); + + void UpdateJidDbSettings( const TCHAR *jid ); + HANDLE CreateTemporaryContact( const TCHAR *szJid, JABBER_LIST_ITEM* chatItem ); + + void PerformRegistration( ThreadData* info ); + void PerformIqAuth( ThreadData* info ); + void PerformAuthentication( ThreadData* info ); + void OnProcessFeatures( HXML node, ThreadData* info ); + + void xmlStreamInitialize( char *which ); + void xmlStreamInitializeNow(ThreadData* info); + + BOOL OnProcessJingle( HXML node ); + void OnProcessIq( HXML node ); + void OnProcessRegIq( HXML node, ThreadData* info ); + void OnPingReply( HXML node, CJabberIqInfo* pInfo ); + + bool ProcessCaptcha( HXML node, HXML parentNode, ThreadData *info ); + + //---- jabber_util.c ----------------------------------------------------------------- + + JABBER_RESOURCE_STATUS* ResourceInfoFromJID( const TCHAR* jid ); + + void SerialInit( void ); + void SerialUninit( void ); + int SerialNext( void ); + + HANDLE HContactFromJID( const TCHAR* jid , BOOL bStripResource = 3); + HANDLE ChatRoomHContactFromJID( const TCHAR* jid ); + void Log( const char* fmt, ... ); + void SendVisibleInvisiblePresence( BOOL invisible ); + void SendPresenceTo( int status, TCHAR* to, HXML extra, const TCHAR *msg = NULL ); + void SendPresence( int m_iStatus, bool bSendToAll ); + void StringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ); + TCHAR* GetClientJID( const TCHAR* jid, TCHAR*, size_t ); + void RebuildInfoFrame( void ); + + void ComboLoadRecentStrings(HWND hwndDlg, UINT idcCombo, char *param, int recentCount=JABBER_DEFAULT_RECENT_COUNT); + void ComboAddRecentString(HWND hwndDlg, UINT idcCombo, char *param, TCHAR *string, int recentCount=JABBER_DEFAULT_RECENT_COUNT); + BOOL EnterString(TCHAR *result, size_t resultLen, TCHAR *caption=NULL, int type=0, char *windowName=NULL, int recentCount=JABBER_DEFAULT_RECENT_COUNT, int timeout=0); + BOOL IsMyOwnJID( LPCTSTR szJID ); + + void __cdecl LoadHttpAvatars(void* param); + + //---- jabber_vcard.c ----------------------------------------------- + + int m_vCardUpdates; + HWND m_hwndPhoto; + bool m_bPhotoChanged; + TCHAR m_szPhotoFileName[MAX_PATH]; + void OnUserInfoInit_VCard( WPARAM, LPARAM ); + + void GroupchatJoinByHContact( HANDLE hContact, bool autojoin=false ); + int SendGetVcard( const TCHAR* jid ); + void AppendVcardFromDB( HXML n, char* tag, char* key ); + void SetServerVcard( BOOL bPhotoChanged, TCHAR* szPhotoFileName ); + void SaveVcardToDB( HWND hwndPage, int iPage ); + + //---- jabber_ws.c ------------------------------------------------- + + JABBER_SOCKET WsConnect( char* host, WORD port ); + + BOOL WsInit(void); + void WsUninit(void); + int WsSend( JABBER_SOCKET s, char* data, int datalen, int flags ); + int WsRecv( JABBER_SOCKET s, char* data, long datalen, int flags ); + + //---- jabber_xml.c ------------------------------------------------------------------ + + int OnXmlParse( char* buffer ); + void OnConsoleProcessXml(HXML node, DWORD flags); + + //---- jabber_xmlns.c ---------------------------------------------------------------- + + BOOL OnHandleDiscoInfoRequest( HXML iqNode, CJabberIqInfo* pInfo ); + BOOL OnHandleDiscoItemsRequest( HXML iqNode, CJabberIqInfo* pInfo ); + + //---- jabber_xstatus.c -------------------------------------------------------------- + + INT_PTR __cdecl OnSetListeningTo( WPARAM wParam, LPARAM lParams ); + INT_PTR __cdecl OnGetXStatusIcon( WPARAM wParam, LPARAM lParams ); + INT_PTR __cdecl OnGetXStatus( WPARAM wParam, LPARAM lParams ); + INT_PTR __cdecl OnSetXStatus( WPARAM wParam, LPARAM lParams ); + INT_PTR __cdecl OnSetXStatusEx( WPARAM wParam, LPARAM lParams ); + + HICON GetXStatusIcon(int bStatus, UINT flags); + + void RegisterAdvStatusSlot(const char *pszSlot); + void ResetAdvStatus(HANDLE hContact, const char *pszSlot); + void WriteAdvStatus(HANDLE hContact, const char *pszSlot, const TCHAR *pszMode, const char *pszIcon, const TCHAR *pszTitle, const TCHAR *pszText); + char* ReadAdvStatusA(HANDLE hContact, const char *pszSlot, const char *pszValue); + TCHAR* ReadAdvStatusT(HANDLE hContact, const char *pszSlot, const char *pszValue); + + BOOL SendPepTune( TCHAR* szArtist, TCHAR* szLength, TCHAR* szSource, TCHAR* szTitle, TCHAR* szTrack, TCHAR* szUri ); + + void XStatusInit( void ); + void XStatusUninit( void ); + + void SetContactTune( HANDLE hContact, LPCTSTR szArtist, LPCTSTR szLength, LPCTSTR szSource, LPCTSTR szTitle, LPCTSTR szTrack ); + + void InfoFrame_OnUserMood(CJabberInfoFrame_Event *evt); + void InfoFrame_OnUserActivity(CJabberInfoFrame_Event *evt); + + int m_xsActivity; + + CPepServiceList m_pepServices; + +private: + char* m_szXmlStreamToBeInitialized; + + DWORD m_lastTicks; + + CRITICAL_SECTION m_csSerial; + unsigned int m_nSerial; + + HANDLE m_hInitChat; + HGENMENU m_hPrivacyMenuRoot; + BOOL m_menuItemsStatus; + LIST<void> m_hPrivacyMenuItems; + + int m_nMenuResourceItems; + HANDLE* m_phMenuResourceItems; + + HANDLE* m_phIconLibItems; +}; + +extern LIST<CJabberProto> g_Instances; + +#endif diff --git a/protocols/JabberG/src/jabber_proxy.cpp b/protocols/JabberG/src/jabber_proxy.cpp new file mode 100644 index 0000000000..1702eb52de --- /dev/null +++ b/protocols/JabberG/src/jabber_proxy.cpp @@ -0,0 +1,157 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +int JabberHttpGatewayInit( HANDLE /*hConn*/, NETLIBOPENCONNECTION* /*nloc*/, NETLIBHTTPREQUEST* /*nlhr*/ ) +{ +#ifdef NNNN + WORD wLen, wVersion, wType; + WORD wIpLen; + DWORD dwSid1, dwSid2, dwSid3, dwSid4; + BYTE response[300], *buf; + int responseBytes, recvResult; + char szSid[33], szHttpServer[256], szHttpGetUrl[300], szHttpPostUrl[300]; + NETLIBHTTPPROXYINFO nlhpi = {0}; + + for ( responseBytes = 0; ; ) { + recvResult = Netlib_Recv( hConn, response + responseBytes, sizeof( response ) - responseBytes, MSG_DUMPPROXY ); + if ( recvResult<=0 ) break; + responseBytes += recvResult; + if ( responseBytes == sizeof( response )) + break; + } + if ( responseBytes < 31 ) + { + SetLastError( ERROR_INVALID_DATA ); + return 0; + } + buf = response; + unpackWord( &buf, &wLen ); + unpackWord( &buf, &wVersion ); /* always 0x0443 */ + unpackWord( &buf, &wType ); + buf += 6; /* dunno */ + unpackDWord( &buf, &dwSid1 ); + unpackDWord( &buf, &dwSid2 ); + unpackDWord( &buf, &dwSid3 ); + unpackDWord( &buf, &dwSid4 ); + sprintf( szSid, "%08x%08x%08x%08x", dwSid1, dwSid2, dwSid3, dwSid4 ); + unpackWord( &buf, &wIpLen ); + if ( responseBytes < 30 + wIpLen || wIpLen == 0 || wIpLen > sizeof( szHttpServer ) - 1 ) + { + SetLastError( ERROR_INVALID_DATA ); + return 0; + } + memcpy( szHttpServer, buf, wIpLen ); + szHttpServer[wIpLen] = '\0'; + + nlhpi.cbSize = sizeof( nlhpi ); + nlhpi.flags = NLHPIF_USEPOSTSEQUENCE; + nlhpi.szHttpGetUrl = szHttpGetUrl; + nlhpi.szHttpPostUrl = szHttpPostUrl; + nlhpi.firstPostSequence = 1; + sprintf( szHttpGetUrl, "http://%s/monitor?sid=%s", szHttpServer, szSid ); + sprintf( szHttpPostUrl, "http://%s/data?sid=%s&seq=", szHttpServer, szSid ); + return CallService( MS_NETLIB_SETHTTPPROXYINFO, ( WPARAM )hConn, ( LPARAM )&nlhpi ); +#endif + return 1; +} + +int JabberHttpGatewayBegin( HANDLE /*hConn*/, NETLIBOPENCONNECTION* /*nloc*/ ) +{ + /* + icq_packet packet; + int serverNameLen; + + serverNameLen = strlen( nloc->szHost ); + + packet.wLen = ( WORD )( serverNameLen + 4 ); + write_httphdr( &packet, HTTP_PACKETTYPE_LOGIN ); + packWord( &packet, ( WORD )serverNameLen ); + packString( &packet, nloc->szHost, ( WORD )serverNameLen ); + packWord( &packet, nloc->wPort ); + Netlib_Send( hConn, packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP ); + mir_free( packet.pData ); + return 1; + */ + return 1; +} + +int JabberHttpGatewayWrapSend( HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend ) +{ + TCHAR* strb = mir_utf8decodeW(( char* )buf ); + + TCHAR sid[25] = _T(""); + unsigned __int64 rid = 0; + + XmlNode hPayLoad( strb ); + XmlNode body( _T("body")); + HXML hBody = body << XATTRI64( _T("rid"), rid++ ) << XATTR( _T("sid"), sid ) << + XATTR( _T("xmlns"), _T( "http://jabber.org/protocol/httpbind" )); + xmlAddChild( hBody, hPayLoad ); + + TCHAR* str = xi.toString( hBody, NULL ); + + mir_free( strb ); + char* utfStr = mir_utf8encodeT( str ); + NETLIBBUFFER nlb = { utfStr, (int)strlen( utfStr ), flags }; + int result = pfnNetlibSend(( WPARAM )hConn, ( LPARAM )&nlb); + mir_free( utfStr ); + xi.freeMem( str ); + + return result; +} + +#if 0 +PBYTE JabberHttpGatewayUnwrapRecv( NETLIBHTTPREQUEST *nlhr, PBYTE buf, int len, int *outBufLen, void *( *NetlibRealloc )( void *, size_t )) +{ + WORD wLen, wType; + PBYTE tbuf; + int i, copyBytes; + + tbuf = buf; + for ( i = 0;; ) + { + if ( tbuf - buf + 2 > len ) break; + unpackWord( &tbuf, &wLen ); + if ( wLen < 12 ) break; + if ( tbuf - buf + wLen > len ) break; + tbuf += 2; /* version */ + unpackWord( &tbuf, &wType ); + tbuf += 8; /* flags & subtype */ + if ( wType == HTTP_PACKETTYPE_FLAP ) + { + copyBytes = wLen - 12; + if ( copyBytes > len - i ) + { + /* invalid data - do our best to get something out of it */ + copyBytes = len - i; + } + memcpy( buf + i, tbuf, copyBytes ); + i += copyBytes; + } + tbuf += wLen - 12; + } + *outBufLen = i; + return buf; +} +#endif diff --git a/protocols/JabberG/src/jabber_proxy.h b/protocols/JabberG/src/jabber_proxy.h new file mode 100644 index 0000000000..a42591f81e --- /dev/null +++ b/protocols/JabberG/src/jabber_proxy.h @@ -0,0 +1,29 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_PROXY_H_ +#define _JABBER_PROXY_H_ + +int JabberHttpGatewayInit( HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr ); +int JabberHttpGatewayBegin( HANDLE hConn, NETLIBOPENCONNECTION *nloc ); + +#endif diff --git a/protocols/JabberG/src/jabber_rc.cpp b/protocols/JabberG/src/jabber_rc.cpp new file mode 100644 index 0000000000..0021733356 --- /dev/null +++ b/protocols/JabberG/src/jabber_rc.cpp @@ -0,0 +1,814 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +XEP-0146 support for Miranda IM + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_iq.h" +#include "jabber_rc.h" +#include "m_awaymsg.h" + +CJabberAdhocSession::CJabberAdhocSession( CJabberProto* global ) +{ + m_pNext = NULL; + m_pUserData = NULL; + m_bAutofreeUserData = FALSE; + m_dwStage = 0; + ppro = global; + m_szSessionId.Format(_T("%u%u"), ppro->SerialNext(), GetTickCount()); + m_dwStartTime = GetTickCount(); +} + +BOOL CJabberProto::IsRcRequestAllowedByACL( CJabberIqInfo* pInfo ) +{ + if ( !pInfo || !pInfo->GetFrom()) + return FALSE; + + return IsMyOwnJID( pInfo->GetFrom()); +} + +BOOL CJabberProto::HandleAdhocCommandRequest( HXML iqNode, CJabberIqInfo* pInfo ) +{ + if ( !pInfo->GetChildNode()) + return TRUE; + + if ( !m_options.EnableRemoteControl || !IsRcRequestAllowedByACL( pInfo )) { + // FIXME: send error and return + return TRUE; + } + + const TCHAR* szNode = xmlGetAttrValue( pInfo->GetChildNode(), _T("node")); + if ( !szNode ) + return TRUE; + + m_adhocManager.HandleCommandRequest( iqNode, pInfo, ( TCHAR* )szNode ); + return TRUE; +} + +BOOL CJabberAdhocManager::HandleItemsRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) +{ + if ( !szNode || !m_pProto->m_options.EnableRemoteControl || !m_pProto->IsRcRequestAllowedByACL( pInfo )) + return FALSE; + + if ( !_tcscmp( szNode, _T(JABBER_FEAT_COMMANDS))) + { + XmlNodeIq iq( _T("result"), pInfo ); + HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)) << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)); + + Lock(); + CJabberAdhocNode* pNode = GetFirstNode(); + while ( pNode ) { + TCHAR* szJid = pNode->GetJid(); + if ( !szJid ) + szJid = m_pProto->m_ThreadInfo->fullJID; + + resultQuery << XCHILD( _T("item")) << XATTR( _T("jid"), szJid ) + << XATTR( _T("node"), pNode->GetNode()) << XATTR( _T("name"), pNode->GetName()); + + pNode = pNode->GetNext(); + } + Unlock(); + + m_pProto->m_ThreadInfo->send( iq ); + return TRUE; + } + return FALSE; +} + +BOOL CJabberAdhocManager::HandleInfoRequest( HXML, CJabberIqInfo* pInfo, const TCHAR* szNode ) +{ + if ( !szNode || !m_pProto->m_options.EnableRemoteControl || !m_pProto->IsRcRequestAllowedByACL( pInfo )) + return FALSE; + + // FIXME: same code twice + if ( !_tcscmp( szNode, _T(JABBER_FEAT_COMMANDS))) { + XmlNodeIq iq( _T("result"), pInfo ); + HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)); + resultQuery << XCHILD( _T("identity")) << XATTR( _T("name"), _T("Ad-hoc commands")) + << XATTR( _T("category"), _T("automation")) << XATTR( _T("type"), _T("command-node")); + + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_COMMANDS)); + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DATA_FORMS)); + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_INFO)); + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_ITEMS)); + + m_pProto->m_ThreadInfo->send( iq ); + return TRUE; + } + + Lock(); + CJabberAdhocNode *pNode = FindNode( szNode ); + if ( pNode ) { + XmlNodeIq iq( _T("result"), pInfo ); + HXML resultQuery = iq << XQUERY( _T(JABBER_FEAT_DISCO_INFO)) << XATTR( _T("node"), _T(JABBER_FEAT_DISCO_INFO)); + resultQuery << XCHILD( _T("identity")) << XATTR( _T("name"), pNode->GetName()) + << XATTR( _T("category"), _T("automation")) << XATTR( _T("type"), _T("command-node")); + + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_COMMANDS)); + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DATA_FORMS)); + resultQuery << XCHILD( _T("feature")) << XATTR( _T("var"), _T(JABBER_FEAT_DISCO_INFO)); + + Unlock(); + m_pProto->m_ThreadInfo->send( iq ); + return TRUE; + } + Unlock(); + return FALSE; +} + +BOOL CJabberAdhocManager::HandleCommandRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ) +{ + // ATTN: ACL and db settings checked in calling function + + HXML commandNode = pInfo->GetChildNode(); + + Lock(); + CJabberAdhocNode* pNode = FindNode( szNode ); + if ( !pNode ) { + Unlock(); + + m_pProto->m_ThreadInfo->send( + XmlNodeIq( _T("error"), pInfo ) + << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + + return FALSE; + } + + const TCHAR* szSessionId = xmlGetAttrValue( commandNode, _T("sessionid")); + + CJabberAdhocSession* pSession = NULL; + if ( szSessionId ) { + pSession = FindSession( szSessionId ); + if ( !pSession ) { + Unlock(); + + XmlNodeIq iq( _T("error"), pInfo ); + HXML errorNode = iq << XCHILD( _T("error")) << XATTR( _T("type"), _T("modify")); + errorNode << XCHILDNS( _T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + errorNode << XCHILDNS( _T("bad-sessionid"), _T(JABBER_FEAT_COMMANDS)); + m_pProto->m_ThreadInfo->send( iq ); + return FALSE; + } + } + else + pSession = AddNewSession(); + + if ( !pSession ) { + Unlock(); + + m_pProto->m_ThreadInfo->send( + XmlNodeIq( _T("error"), pInfo ) + << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("forbidden"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); + + return FALSE; + } + + // session id and node exits here, call handler + + int nResultCode = pNode->CallHandler( iqNode, pInfo, pSession ); + + if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_COMPLETED ) { + m_pProto->m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), szNode ) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) + << XCHILD( _T("note"), TranslateT("Command completed successfully")) << XATTR( _T("type"), _T("info"))); + + RemoveSession( pSession ); + pSession = NULL; + } + else if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_CANCEL ) { + m_pProto->m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), szNode ) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("canceled")) + << XCHILD( _T("note"), TranslateT("Error occured during processing command")) << XATTR( _T("type"), _T("error"))); + + RemoveSession( pSession ); + pSession = NULL; + } + else if ( nResultCode == JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION ) { + RemoveSession( pSession ); + pSession = NULL; + } + Unlock(); + return TRUE; +} + +BOOL CJabberAdhocManager::FillDefaultNodes() +{ + AddNode( NULL, _T(JABBER_FEAT_RC_SET_STATUS), TranslateT("Set status"), &CJabberProto::AdhocSetStatusHandler ); + AddNode( NULL, _T(JABBER_FEAT_RC_SET_OPTIONS), TranslateT("Set options"), &CJabberProto::AdhocOptionsHandler ); + AddNode( NULL, _T(JABBER_FEAT_RC_FORWARD), TranslateT("Forward unread messages"), &CJabberProto::AdhocForwardHandler ); + AddNode( NULL, _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS), TranslateT("Leave groupchats"), &CJabberProto::AdhocLeaveGroupchatsHandler ); + AddNode( NULL, _T(JABBER_FEAT_RC_WS_LOCK), TranslateT("Lock workstation"), &CJabberProto::AdhocLockWSHandler ); + AddNode( NULL, _T(JABBER_FEAT_RC_QUIT_MIRANDA), TranslateT("Quit Miranda NG"), &CJabberProto::AdhocQuitMirandaHandler ); + return TRUE; +} + + +static char *StatusModeToDbSetting(int status,const char *suffix) +{ + char *prefix; + static char str[64]; + + switch(status) { + case ID_STATUS_AWAY: prefix="Away"; break; + case ID_STATUS_NA: prefix="Na"; break; + case ID_STATUS_DND: prefix="Dnd"; break; + case ID_STATUS_OCCUPIED: prefix="Occupied"; break; + case ID_STATUS_FREECHAT: prefix="FreeChat"; break; + case ID_STATUS_ONLINE: prefix="On"; break; + case ID_STATUS_OFFLINE: prefix="Off"; break; + case ID_STATUS_INVISIBLE: prefix="Inv"; break; + case ID_STATUS_ONTHEPHONE: prefix="Otp"; break; + case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break; + case ID_STATUS_IDLE: prefix="Idl"; break; + default: return NULL; + } + lstrcpyA(str,prefix); lstrcatA(str,suffix); + return str; +} + +int CJabberProto::AdhocSetStatusHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + if ( pSession->GetStage() == 0 ) { + // first form + pSession->SetStage( 1 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML xNode = iq + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_SET_STATUS)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); + + xNode << XCHILD( _T("title"), TranslateT("Change Status")); + xNode << XCHILD( _T("instructions"), TranslateT("Choose the status and status message")); + + xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) + << XATTR( _T("value"), _T(JABBER_FEAT_RC)); + + HXML fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Status")) + << XATTR( _T("type"), _T("list-single")) << XATTR( _T("var"), _T("status")); + + fieldNode << XCHILD( _T("required")); + + int status = CallService( MS_CLIST_GETSTATUSMODE, 0, 0 ); + switch ( status ) { + case ID_STATUS_INVISIBLE: + fieldNode << XCHILD( _T("value"), _T("invisible")); + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + fieldNode << XCHILD( _T("value"), _T("away")); + break; + case ID_STATUS_NA: + fieldNode << XCHILD( _T("value"), _T("xa")); + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + fieldNode << XCHILD( _T("value"), _T("dnd")); + break; + case ID_STATUS_FREECHAT: + fieldNode << XCHILD( _T("value"), _T("chat")); + break; + case ID_STATUS_ONLINE: + default: + fieldNode << XCHILD( _T("value"), _T("online")); + break; + } + + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Free for chat")) << XCHILD( _T("value"), _T("chat")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Online")) << XCHILD( _T("value"), _T("online")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Away")) << XCHILD( _T("value"), _T("away")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Extended Away (N/A)")) << XCHILD( _T("value"), _T("xa")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Do Not Disturb")) << XCHILD( _T("value"), _T("dnd")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Invisible")) << XCHILD( _T("value"), _T("invisible")); + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), TranslateT("Offline")) << XCHILD( _T("value"), _T("offline")); + + // priority + TCHAR szPriority[ 256 ]; + mir_sntprintf( szPriority, SIZEOF(szPriority), _T("%d"), (short)JGetWord( NULL, "Priority", 5 )); + xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Priority")) << XATTR( _T("type"), _T("text-single")) + << XATTR( _T("var"), _T("status-priority")) << XCHILD( _T("value"), szPriority ); + + // status message text + xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Status message")) + << XATTR( _T("type"), _T("text-multi")) << XATTR( _T("var"), _T("status-message")); + + // global status + fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Change global status")) + << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("status-global")); + + char* szStatusMsg = (char *)CallService( MS_AWAYMSG_GETSTATUSMSG, status, 0 ); + if ( szStatusMsg ) { + fieldNode << XCHILD( _T("value"), _A2T(szStatusMsg)); + mir_free( szStatusMsg ); + } + + m_ThreadInfo->send( iq ); + return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; + } + else if ( pSession->GetStage() == 1 ) { + // result form here + HXML commandNode = pInfo->GetChildNode(); + HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + HXML fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status")); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + HXML valueNode = xmlGetChild( fieldNode , "value" ); + if ( !valueNode || !xmlGetText( valueNode )) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + int status = 0; + + if ( !_tcscmp( xmlGetText( valueNode ), _T("away"))) status = ID_STATUS_AWAY; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("xa"))) status = ID_STATUS_NA; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("dnd"))) status = ID_STATUS_DND; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("chat"))) status = ID_STATUS_FREECHAT; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("online"))) status = ID_STATUS_ONLINE; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("invisible"))) status = ID_STATUS_INVISIBLE; + else if ( !_tcscmp( xmlGetText( valueNode ), _T("offline"))) status = ID_STATUS_OFFLINE; + + if ( !status ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + int priority = -9999; + + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-priority")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode )) + priority = _ttoi( xmlGetText( valueNode )); + } + + if ( priority >= -128 && priority <= 127 ) + JSetWord( NULL, "Priority", (WORD)priority ); + + const TCHAR* szStatusMessage = NULL; + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-message")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode )) + szStatusMessage = xmlGetText( valueNode ); + } + + // skip f...ng away dialog + int nNoDlg = DBGetContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), 0 ); + DBWriteContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), 1 ); + + DBWriteContactSettingTString( NULL, "SRAway", StatusModeToDbSetting( status, "Msg" ), szStatusMessage ? szStatusMessage : _T( "" )); + + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("status-global")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) + CallService( MS_CLIST_SETSTATUSMODE, status, NULL ); + else + CallProtoService( m_szModuleName, PS_SETSTATUS, status, NULL ); + } + SetAwayMsg( status, szStatusMessage ); + + // return NoDlg setting + DBWriteContactSettingByte( NULL, "SRAway", StatusModeToDbSetting( status, "NoDlg" ), (BYTE)nNoDlg ); + + return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; + } + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; +} + +int CJabberProto::AdhocOptionsHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + if ( pSession->GetStage() == 0 ) { + // first form + pSession->SetStage( 1 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML xNode = iq + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_SET_OPTIONS)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); + + xNode << XCHILD( _T("title"), TranslateT("Set Options")); + xNode << XCHILD( _T("instructions"), TranslateT("Set the desired options")); + + xNode << XCHILD( _T("field" )) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) + << XATTR( _T("value"), _T(JABBER_FEAT_RC)); + + // Automatically Accept File Transfers + TCHAR szTmpBuff[ 1024 ]; + mir_sntprintf( szTmpBuff, SIZEOF(szTmpBuff), _T("%d"), DBGetContactSettingByte( NULL, "SRFile", "AutoAccept", 0 )); + xNode << XCHILD( _T("field" )) << XATTR( _T("label"), TranslateT("Automatically Accept File Transfers" )) + << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("auto-files")) << XCHILD( _T("value"), szTmpBuff ); + + // Use sounds + mir_sntprintf( szTmpBuff, SIZEOF(szTmpBuff), _T("%d"), DBGetContactSettingByte( NULL, "Skin", "UseSound", 0 )); + xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Play sounds")) + << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("sounds")) << XCHILD( _T("value"), szTmpBuff ); + + // Disable remote controlling + xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Disable remote controlling (check twice what you are doing)")) + << XATTR( _T("type"), _T("boolean")) << XATTR( _T("var"), _T("enable-rc")) << XCHILD( _T("value"), _T("0")); + + m_ThreadInfo->send( iq ); + return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; + } + + if ( pSession->GetStage() == 1 ) { + // result form here + HXML commandNode = pInfo->GetChildNode(); + HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + HXML fieldNode, valueNode; + + // Automatically Accept File Transfers + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("auto-files")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode )) + DBWriteContactSettingByte( NULL, "SRFile", "AutoAccept", (BYTE)_ttoi( xmlGetText( valueNode )) ); + } + + // Use sounds + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("sounds")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode )) + DBWriteContactSettingByte( NULL, "Skin", "UseSound", (BYTE)_ttoi( xmlGetText( valueNode )) ); + } + + // Disable remote controlling + fieldNode = xmlGetChildByTag( xNode, "field", "var", _T("enable-rc")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) + m_options.EnableRemoteControl = 0; + } + + return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; + } + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; +} + +int CJabberProto::RcGetUnreadEventsCount() +{ + int nEventsSent = 0; + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM)hContact, 0 ); + while ( hDbEvent ) { + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); + if ( dbei.cbBlob != -1 ) { + dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); + int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); + if ( !nGetTextResult && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT)) { + TCHAR* szEventText = DbGetEventTextT( &dbei, CP_ACP ); + if ( szEventText ) { + nEventsSent++; + mir_free( szEventText ); + } + } + mir_free( dbei.pBlob ); + } + hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0 ); + } + JFreeVariant( &dbv ); + } + } + hContact = db_find_next(hContact); + } + return nEventsSent; +} + +int CJabberProto::AdhocForwardHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + TCHAR szMsg[ 1024 ]; + if ( pSession->GetStage() == 0 ) { + int nUnreadEvents = RcGetUnreadEventsCount(); + if ( !nUnreadEvents ) { + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("There is no messages to forward")); + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) + << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); + + return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; + } + + // first form + pSession->SetStage( 1 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML xNode = iq + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); + + xNode << XCHILD( _T("title"), TranslateT("Forward options")); + + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("%d message(s) to be forwarded"), nUnreadEvents ); + xNode << XCHILD( _T("instructions"), szMsg ); + + xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) + << XCHILD( _T("value"), _T(JABBER_FEAT_RC)); + + // remove clist events + xNode << XCHILD( _T("field")) << XATTR( _T("label"), TranslateT("Mark messages as read")) << XATTR( _T("type"), _T("boolean")) + << XATTR( _T("var"), _T("remove-clist-events")) << XCHILD( _T("value"), + m_options.RcMarkMessagesAsRead == 1 ? _T("1") : _T("0")); + + m_ThreadInfo->send( iq ); + return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; + } + + if ( pSession->GetStage() == 1 ) { + // result form here + HXML commandNode = pInfo->GetChildNode(); + HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + HXML fieldNode, valueNode; + + BOOL bRemoveCListEvents = TRUE; + + // remove clist events + fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("remove-clist-events")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) { + if ( xmlGetText( valueNode ) && !_ttoi( xmlGetText( valueNode )) ) { + bRemoveCListEvents = FALSE; + } + } + m_options.RcMarkMessagesAsRead = bRemoveCListEvents ? 1 : 0; + + int nEventsSent = 0; + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + + HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM)hContact, 0 ); + while ( hDbEvent ) { + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); + if ( dbei.cbBlob != -1 ) { + dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); + int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); + if ( !nGetTextResult && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT)) { + TCHAR* szEventText = DbGetEventTextT( &dbei, CP_ACP ); + if ( szEventText ) { + XmlNode msg( _T("message")); + msg << XATTR( _T("to"), pInfo->GetFrom()) << XATTRID( SerialNext()) + << XCHILD( _T("body"), szEventText ); + + HXML addressesNode = msg << XCHILDNS( _T("addresses"), _T(JABBER_FEAT_EXT_ADDRESSING)); + TCHAR szOFrom[ JABBER_MAX_JID_LEN ]; + EnterCriticalSection( &m_csLastResourceMap ); + TCHAR *szOResource = FindLastResourceByDbEvent( hDbEvent ); + if ( szOResource ) + mir_sntprintf( szOFrom, SIZEOF( szOFrom ), _T("%s/%s"), dbv.ptszVal, szOResource ); + else + mir_sntprintf( szOFrom, SIZEOF( szOFrom ), _T("%s"), dbv.ptszVal ); + LeaveCriticalSection( &m_csLastResourceMap ); + addressesNode << XCHILD( _T("address")) << XATTR( _T("type"), _T("ofrom")) << XATTR( _T("jid"), szOFrom ); + addressesNode << XCHILD( _T("address")) << XATTR( _T("type"), _T("oto")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ); + + time_t ltime = ( time_t )dbei.timestamp; + struct tm *gmt = gmtime( <ime ); + TCHAR stime[ 512 ]; + wsprintf(stime, _T("%.4i-%.2i-%.2iT%.2i:%.2i:%.2iZ"), gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, + gmt->tm_hour, gmt->tm_min, gmt->tm_sec); + msg << XCHILDNS( _T("delay"), _T("urn:xmpp:delay")) << XATTR( _T("stamp"), stime ); + + m_ThreadInfo->send( msg ); + + nEventsSent++; + + CallService( MS_DB_EVENT_MARKREAD, (WPARAM)hContact, (LPARAM)hDbEvent ); + if ( bRemoveCListEvents ) + CallService( MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)hDbEvent ); + + mir_free( szEventText ); + } + } + mir_free( dbei.pBlob ); + } + hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0 ); + } + JFreeVariant( &dbv ); + } + } + hContact = db_find_next(hContact); + } + + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("%d message(s) forwarded"), nEventsSent ); + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_FORWARD)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) + << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); + + return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; + } + + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; +} + +typedef BOOL (WINAPI *LWS )( VOID ); + +int CJabberProto::AdhocLockWSHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + BOOL bOk = FALSE; + HMODULE hLibrary = LoadLibrary( _T("user32.dll")); + if ( hLibrary ) { + LWS pLws = (LWS)GetProcAddress( hLibrary, "LockWorkStation" ); + if ( pLws ) + bOk = pLws(); + FreeLibrary( hLibrary ); + } + + TCHAR szMsg[ 1024 ]; + if ( bOk ) + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("Workstation successfully locked")); + else + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("Error %d occured during workstation lock"), GetLastError()); + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_WS_LOCK)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) + << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), bOk ? _T("info") : _T("error"))); + + return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; +} + +static void __stdcall JabberQuitMirandaIMThread( void* ) +{ + CallService( "CloseAction", 0, 0 ); +} + +int CJabberProto::AdhocQuitMirandaHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + if ( pSession->GetStage() == 0 ) { + // first form + pSession->SetStage( 1 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML xNode = iq + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_QUIT_MIRANDA)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); + + xNode << XCHILD( _T("title"), TranslateT("Confirmation needed")); + xNode << XCHILD( _T("instructions"), TranslateT("Please confirm Miranda NG shutdown")); + + xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) + << XCHILD( _T("value"), _T(JABBER_FEAT_RC)); + + // I Agree checkbox + xNode << XCHILD( _T("field")) << XATTR( _T("label"), _T("I agree")) << XATTR( _T("type"), _T("boolean")) + << XATTR( _T("var"), _T("allow-shutdown")) << XCHILD( _T("value"), _T("0")); + + m_ThreadInfo->send( iq ); + return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; + } + + if ( pSession->GetStage() == 1 ) { + // result form here + HXML commandNode = pInfo->GetChildNode(); + HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + HXML fieldNode, valueNode; + + // I Agree checkbox + fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("allow-shutdown")); + if ( fieldNode && (valueNode = xmlGetChild( fieldNode , "value" ))) + if ( xmlGetText( valueNode ) && _ttoi( xmlGetText( valueNode ))) + CallFunctionAsync(JabberQuitMirandaIMThread, 0); + + return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; + } + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; +} + +int CJabberProto::AdhocLeaveGroupchatsHandler( HXML, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) +{ + int i = 0; + if ( pSession->GetStage() == 0 ) { + // first form + TCHAR szMsg[ 1024 ]; + + ListLock(); + int nChatsCount = 0; + LISTFOREACH_NODEF(i, this, LIST_CHATROOM) + { + JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); + if ( item != NULL ) + nChatsCount++; + } + ListUnlock(); + + if ( !nChatsCount ) { + mir_sntprintf( szMsg, SIZEOF(szMsg), TranslateT("There is no groupchats to leave")); + + m_ThreadInfo->send( + XmlNodeIq( _T("result"), pInfo ) + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("completed")) + << XCHILD( _T("note"), szMsg ) << XATTR( _T("type"), _T("info"))); + + return JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION; + } + + pSession->SetStage( 1 ); + + XmlNodeIq iq( _T("result"), pInfo ); + HXML xNode = iq + << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), _T(JABBER_FEAT_RC_LEAVE_GROUPCHATS)) + << XATTR( _T("sessionid"), pSession->GetSessionId()) << XATTR( _T("status"), _T("executing")) + << XCHILDNS( _T("x"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR( _T("type"), _T("form")); + + xNode << XCHILD( _T("title"), TranslateT("Leave groupchats")); + xNode << XCHILD( _T("instructions"), TranslateT("Choose the groupchats you want to leave")); + + xNode << XCHILD( _T("field")) << XATTR( _T("type"), _T("hidden")) << XATTR( _T("var"), _T("FORM_TYPE")) + << XATTR( _T("value"), _T(JABBER_FEAT_RC)); + + // Groupchats + HXML fieldNode = xNode << XCHILD( _T("field")) << XATTR( _T("label"), NULL ) << XATTR( _T("type"), _T("list-multi")) << XATTR( _T("var"), _T("groupchats")); + fieldNode << XCHILD( _T("required")); + + ListLock(); + LISTFOREACH_NODEF(i, this, LIST_CHATROOM) + { + JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); + if ( item != NULL ) + fieldNode << XCHILD( _T("option")) << XATTR( _T("label"), item->jid ) << XCHILD( _T("value"), item->jid ); + } + ListUnlock(); + + m_ThreadInfo->send( iq ); + return JABBER_ADHOC_HANDLER_STATUS_EXECUTING; + } + + if ( pSession->GetStage() == 1 ) { + // result form here + HXML commandNode = pInfo->GetChildNode(); + HXML xNode = xmlGetChildByTag( commandNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if ( !xNode ) + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; + + // Groupchat list here: + HXML fieldNode = xmlGetChildByTag( xNode,"field", "var", _T("groupchats")); + if ( fieldNode ) { + for ( i = 0; i < xmlGetChildCount( fieldNode ); i++ ) { + HXML valueNode = xmlGetChild( fieldNode, i ); + if ( valueNode && xmlGetName( valueNode ) && xmlGetText( valueNode ) && !_tcscmp( xmlGetName( valueNode ), _T("value"))) { + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, xmlGetText( valueNode )); + if ( item ) + GcQuit( item, 0, NULL ); + } + } + } + + return JABBER_ADHOC_HANDLER_STATUS_COMPLETED; + } + return JABBER_ADHOC_HANDLER_STATUS_CANCEL; +} \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_rc.h b/protocols/JabberG/src/jabber_rc.h new file mode 100644 index 0000000000..cb3bf1b9cc --- /dev/null +++ b/protocols/JabberG/src/jabber_rc.h @@ -0,0 +1,314 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +XEP-0146 support for Miranda IM + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_RC_H_ +#define _JABBER_RC_H_ + +class CJabberAdhocSession; + +#define JABBER_ADHOC_HANDLER_STATUS_EXECUTING 1 +#define JABBER_ADHOC_HANDLER_STATUS_COMPLETED 2 +#define JABBER_ADHOC_HANDLER_STATUS_CANCEL 3 +#define JABBER_ADHOC_HANDLER_STATUS_REMOVE_SESSION 4 +typedef int ( CJabberProto::*JABBER_ADHOC_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ); + +// 5 minutes to fill out form :) +#define JABBER_ADHOC_SESSION_EXPIRE_TIME 300000 + +class CJabberAdhocSession +{ +protected: + CMString m_szSessionId; + CJabberAdhocSession* m_pNext; + DWORD m_dwStartTime; + + void* m_pUserData; + BOOL m_bAutofreeUserData; + + DWORD m_dwStage; +public: + CJabberProto* ppro; + CJabberAdhocSession( CJabberProto* global ); + ~CJabberAdhocSession() + { + if ( m_bAutofreeUserData && m_pUserData ) + mir_free( m_pUserData ); + if ( m_pNext ) + delete m_pNext; + } + CJabberAdhocSession* GetNext() + { + return m_pNext; + } + CJabberAdhocSession* SetNext( CJabberAdhocSession *pNext ) + { + CJabberAdhocSession *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } + DWORD GetSessionStartTime() + { + return m_dwStartTime; + } + LPCTSTR GetSessionId() + { + return m_szSessionId; + } + BOOL SetUserData( void* pUserData, BOOL bAutofree = FALSE ) + { + if ( m_bAutofreeUserData && m_pUserData ) + mir_free( m_pUserData ); + m_pUserData = pUserData; + m_bAutofreeUserData = bAutofree; + return TRUE; + } + DWORD SetStage( DWORD dwStage ) + { + DWORD dwRetVal = m_dwStage; + m_dwStage = dwStage; + return dwRetVal; + } + DWORD GetStage() + { + return m_dwStage; + } +}; + +class CJabberAdhocNode; +class CJabberAdhocNode +{ +protected: + TCHAR* m_szJid; + TCHAR* m_szNode; + TCHAR* m_szName; + CJabberAdhocNode* m_pNext; + JABBER_ADHOC_HANDLER m_pHandler; + CJabberProto* m_pProto; +public: + CJabberAdhocNode( CJabberProto* pProto, TCHAR* szJid, TCHAR* szNode, TCHAR* szName, JABBER_ADHOC_HANDLER pHandler ) + { + ZeroMemory( this, sizeof( CJabberAdhocNode )); + replaceStrT( m_szJid, szJid ); + replaceStrT( m_szNode, szNode ); + replaceStrT( m_szName, szName ); + m_pHandler = pHandler; + m_pProto = pProto; + } + ~CJabberAdhocNode() + { + if ( m_szJid) + mir_free( m_szJid ); + if ( m_szNode ) + mir_free( m_szNode ); + if ( m_szName ) + mir_free( m_szName ); + if ( m_pNext ) + delete m_pNext; + } + CJabberAdhocNode* GetNext() + { + return m_pNext; + } + CJabberAdhocNode* SetNext( CJabberAdhocNode *pNext ) + { + CJabberAdhocNode *pRetVal = m_pNext; + m_pNext = pNext; + return pRetVal; + } + TCHAR* GetJid() + { + return m_szJid; + } + TCHAR* GetNode() + { + return m_szNode; + } + TCHAR* GetName() + { + return m_szName; + } + BOOL CallHandler( HXML iqNode, CJabberIqInfo* pInfo, CJabberAdhocSession* pSession ) + { + if ( m_pHandler == NULL ) + return FALSE; + return (m_pProto->*m_pHandler)( iqNode, pInfo, pSession ); + } +}; + +class CJabberAdhocManager +{ +protected: + CJabberProto* m_pProto; + CJabberAdhocNode* m_pNodes; + CJabberAdhocSession* m_pSessions; + CRITICAL_SECTION m_cs; + + CJabberAdhocSession* FindSession( const TCHAR* szSession ) + { + CJabberAdhocSession* pSession = m_pSessions; + while ( pSession ) { + if ( !_tcscmp( pSession->GetSessionId(), szSession )) + return pSession; + pSession = pSession->GetNext(); + } + return NULL; + } + + CJabberAdhocSession* AddNewSession() + { + CJabberAdhocSession* pSession = new CJabberAdhocSession( m_pProto ); + if ( !pSession ) + return NULL; + + pSession->SetNext( m_pSessions ); + m_pSessions = pSession; + + return pSession; + } + + CJabberAdhocNode* FindNode( const TCHAR* szNode ) + { + CJabberAdhocNode* pNode = m_pNodes; + while ( pNode ) { + if ( !_tcscmp( pNode->GetNode(), szNode )) + return pNode; + pNode = pNode->GetNext(); + } + return NULL; + } + + BOOL RemoveSession( CJabberAdhocSession* pSession ) + { + if ( !m_pSessions ) + return FALSE; + + if ( pSession == m_pSessions ) { + m_pSessions = m_pSessions->GetNext(); + pSession->SetNext( NULL ); + delete pSession; + return TRUE; + } + + CJabberAdhocSession* pTmp = m_pSessions; + while ( pTmp->GetNext()) { + if ( pTmp->GetNext() == pSession ) { + pTmp->SetNext( pSession->GetNext()); + pSession->SetNext( NULL ); + delete pSession; + return TRUE; + } + pTmp = pTmp->GetNext(); + } + return FALSE; + } + + BOOL _ExpireSession( DWORD dwExpireTime ) + { + if ( !m_pSessions ) + return FALSE; + + CJabberAdhocSession* pSession = m_pSessions; + if ( pSession->GetSessionStartTime() < dwExpireTime ) { + m_pSessions = pSession->GetNext(); + pSession->SetNext( NULL ); + delete pSession; + return TRUE; + } + + while ( pSession->GetNext()) { + if ( pSession->GetNext()->GetSessionStartTime() < dwExpireTime ) { + CJabberAdhocSession* pRetVal = pSession->GetNext(); + pSession->SetNext( pSession->GetNext()->GetNext()); + pRetVal->SetNext( NULL ); + delete pRetVal; + return TRUE; + } + pSession = pSession->GetNext(); + } + return FALSE; + } + +public: + CJabberAdhocManager( CJabberProto* pProto ) + { + ZeroMemory( this, sizeof( CJabberAdhocManager )); + m_pProto = pProto; + InitializeCriticalSection( &m_cs ); + } + ~CJabberAdhocManager() + { + if ( m_pNodes ) + delete m_pNodes; + if ( m_pSessions ) + delete m_pSessions; + DeleteCriticalSection( &m_cs ); + } + void Lock() + { + EnterCriticalSection( &m_cs ); + } + void Unlock() + { + LeaveCriticalSection( &m_cs ); + } + BOOL FillDefaultNodes(); + BOOL AddNode( TCHAR* szJid, TCHAR* szNode, TCHAR* szName, JABBER_ADHOC_HANDLER pHandler ) + { + CJabberAdhocNode* pNode = new CJabberAdhocNode( m_pProto, szJid, szNode, szName, pHandler ); + if ( !pNode ) + return FALSE; + + Lock(); + if ( !m_pNodes ) + m_pNodes = pNode; + else { + CJabberAdhocNode* pTmp = m_pNodes; + while ( pTmp->GetNext()) + pTmp = pTmp->GetNext(); + pTmp->SetNext( pNode ); + } + Unlock(); + + return TRUE; + } + CJabberAdhocNode* GetFirstNode() + { + return m_pNodes; + } + BOOL HandleItemsRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); + BOOL HandleInfoRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); + BOOL HandleCommandRequest( HXML iqNode, CJabberIqInfo* pInfo, const TCHAR* szNode ); + + BOOL ExpireSessions() + { + Lock(); + DWORD dwExpireTime = GetTickCount() - JABBER_ADHOC_SESSION_EXPIRE_TIME; + while ( _ExpireSession( dwExpireTime )); + Unlock(); + return TRUE; + } +}; + +#endif //_JABBER_RC_H_ diff --git a/protocols/JabberG/src/jabber_search.cpp b/protocols/JabberG/src/jabber_search.cpp new file mode 100644 index 0000000000..e242294a16 --- /dev/null +++ b/protocols/JabberG/src/jabber_search.cpp @@ -0,0 +1,762 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Artem Shpynov + +Module implements a search according to XEP-0055: Jabber Search +http://www.xmpp.org/extensions/xep-0055.html + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <CommCtrl.h> +#include "jabber_iq.h" +#include "jabber_caps.h" + +/////////////////////////////////////////////////////////////////////////////// +// Subclassing of IDC_FRAME to implement more user-friendly fields scrolling +// +static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_COMMAND && lParam != 0 ) { + HWND hwndDlg=GetParent(hwnd); + JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if ( dat && lParam ) { + int pos=dat->curPos; + RECT MineRect; + RECT FrameRect; + GetWindowRect(GetDlgItem( hwndDlg, IDC_FRAME ),&FrameRect); + GetWindowRect((HWND)lParam, &MineRect); + if ( MineRect.top-10 < FrameRect.top ) { + pos=dat->curPos+(MineRect.top-14-FrameRect.top); + if (pos<0) pos=0; + } + else if ( MineRect.bottom > FrameRect.bottom ) { + pos=dat->curPos+(MineRect.bottom-FrameRect.bottom); + if (dat->frameHeight+pos>dat->CurrentHeight) + pos=dat->CurrentHeight-dat->frameHeight; + } + if ( pos != dat->curPos ) { + ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL, &( dat->frameRect )); + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); + RECT Invalid=dat->frameRect; + if (dat->curPos - pos >0) + Invalid.bottom=Invalid.top+(dat->curPos - pos); + else + Invalid.top=Invalid.bottom+(dat->curPos - pos); + + RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW |RDW_ALLCHILDREN); + dat->curPos = pos; + } } + if (HIWORD(wParam)==EN_SETFOCUS) { //Transmit focus set notification to parent window + PostMessage(GetParent(hwndDlg),WM_COMMAND, MAKEWPARAM(0,EN_SETFOCUS), (LPARAM)hwndDlg); + } + } + + if ( msg == WM_PAINT ) { + PAINTSTRUCT ps; + HDC hdc=BeginPaint(hwnd, &ps); + FillRect(hdc,&(ps.rcPaint),GetSysColorBrush(COLOR_BTNFACE)); + EndPaint(hwnd, &ps); + } + + return DefWindowProc(hwnd,msg,wParam,lParam); +} + +/////////////////////////////////////////////////////////////////////////////// +// Add Search field to form +// +static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat ) +{ + if (!FieldDat || !FieldDat->Label || !FieldDat->Var) return FALSE; + HFONT hFont = ( HFONT ) SendMessage( hwndDlg, WM_GETFONT, 0, 0 ); + HWND hwndParent=GetDlgItem(hwndDlg,IDC_FRAME); + LONG frameExStyle = GetWindowLongPtr( hwndParent, GWL_EXSTYLE ); + frameExStyle |= WS_EX_CONTROLPARENT; + SetWindowLongPtr( hwndParent, GWL_EXSTYLE, frameExStyle ); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_FRAME),GWLP_WNDPROC,(LONG_PTR)JabberSearchFrameProc); + + int CornerX=1; + int CornerY=1; + RECT rect; + GetClientRect(hwndParent,&rect); + int width=rect.right-5-CornerX; + + int Order=(FieldDat->bHidden) ? -1 : FieldDat->Order; + + HWND hwndLabel=CreateWindowEx(0,_T("STATIC"),(LPCTSTR)TranslateTS(FieldDat->Label),WS_CHILD, CornerX, CornerY + Order*40, width, 13,hwndParent,NULL,hInst,0); + HWND hwndVar=CreateWindowEx(0|WS_EX_CLIENTEDGE,_T("EDIT"),(LPCTSTR)FieldDat->defValue,WS_CHILD|WS_TABSTOP, CornerX+5, CornerY + Order*40+14, width ,20,hwndParent,NULL,hInst,0); + SendMessage(hwndLabel, WM_SETFONT, (WPARAM)hFont,0); + SendMessage(hwndVar, WM_SETFONT, (WPARAM)hFont,0); + if (!FieldDat->bHidden) + { + ShowWindow(hwndLabel,SW_SHOW); + ShowWindow(hwndVar,SW_SHOW); + EnableWindow(hwndLabel,!FieldDat->bReadOnly); + SendMessage(hwndVar, EM_SETREADONLY, (WPARAM)FieldDat->bReadOnly,0); + } + //remade list + //reallocation + JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if ( dat ) { + dat->pJSInf=(JabberSearchFieldsInfo*) realloc(dat->pJSInf, sizeof(JabberSearchFieldsInfo)*(dat->nJSInfCount+1)); + dat->pJSInf[dat->nJSInfCount].hwndCaptionItem=hwndLabel; + dat->pJSInf[dat->nJSInfCount].hwndValueItem=hwndVar; + dat->pJSInf[dat->nJSInfCount].szFieldCaption=_tcsdup(FieldDat->Label); + dat->pJSInf[dat->nJSInfCount].szFieldName=_tcsdup(FieldDat->Var); + dat->nJSInfCount++; + } + return CornerY + Order*40+14 +20; +} + +//////////////////////////////////////////////////////////////////////////////// +// Available search field request result handler (XEP-0055. Examples 2, 7) + +void CJabberProto::OnIqResultGetSearchFields( HXML iqNode ) +{ + if ( !searchHandleDlg ) + return; + + LPCTSTR type = xmlGetAttrValue( iqNode, _T("type")); + if ( !type ) + return; + + if ( !lstrcmp( type, _T("result"))) { + HXML queryNode = xmlGetNthChild( iqNode, _T("query"), 1 ); + HXML xNode = xmlGetChildByTag( queryNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + + ShowWindow(searchHandleDlg,SW_HIDE); + if ( xNode ) { + //1. Form + PostMessage( searchHandleDlg, WM_USER+11, ( WPARAM )xi.copyNode( xNode ), ( LPARAM )0 ); + HXML xcNode = xmlGetNthChild( xNode, _T("instructions"), 1 ); + if ( xcNode ) + SetDlgItemText( searchHandleDlg, IDC_INSTRUCTIONS, xmlGetText( xcNode )); + } + else { + int Order=0; + for ( int i = 0; ; i++ ) { + HXML chNode = xmlGetChild( queryNode, i ); + if ( !chNode ) + break; + + if ( !_tcsicmp( xmlGetName( chNode ), _T("instructions")) && xmlGetText( chNode )) + SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,TranslateTS(xmlGetText( chNode ))); + else if ( xmlGetName( chNode )) { + Data *MyData=(Data*)malloc(sizeof(Data)); + memset(MyData,0,sizeof(Data)); + + MyData->Label = mir_tstrdup( xmlGetName( chNode )); + MyData->Var = mir_tstrdup( xmlGetName( chNode )); + MyData->defValue = mir_tstrdup(xmlGetText( chNode )); + MyData->Order = Order; + if (MyData->defValue) MyData->bReadOnly = TRUE; + PostMessage(searchHandleDlg,WM_USER+10,(WPARAM)FALSE,(LPARAM)MyData); + Order++; + } } } + const TCHAR* szFrom = xmlGetAttrValue( iqNode, _T("from")); + if (szFrom) + SearchAddToRecent(szFrom,searchHandleDlg); + PostMessage(searchHandleDlg,WM_USER+10,(WPARAM)0,(LPARAM)0); + ShowWindow(searchHandleDlg,SW_SHOW); + } + else if ( !lstrcmp( type, _T("error"))) { + const TCHAR* code=NULL; + const TCHAR* description=NULL; + TCHAR buff[255]; + HXML errorNode = xmlGetChild( iqNode, "error"); + if ( errorNode ) { + code = xmlGetAttrValue( errorNode, _T("code")); + description=xmlGetText( errorNode ); + } + _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s\r\nPlease select other server"),code ? code : _T(""),description?description:_T("")); + SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,buff); + } + else SetDlgItemText( searchHandleDlg, IDC_INSTRUCTIONS, TranslateT( "Error Unknown reply recieved\r\nPlease select other server" )); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Return results to search dialog +// The pmFields is the pointer to map of <field Name, field Label> Not unical but ordered +// This can help to made result parser routines more simple + +void CJabberProto::SearchReturnResults( HANDLE id, void * pvUsersInfo, U_TCHAR_MAP * pmAllFields ) +{ + LIST<TCHAR> ListOfNonEmptyFields(20,(LIST<TCHAR>::FTSortFunc)TCharKeyCmp); + LIST<TCHAR> ListOfFields(20); + LIST<void>* plUsersInfo = ( LIST<void>* )pvUsersInfo; + int i, nUsersFound = plUsersInfo->getCount(); + + // lets fill the ListOfNonEmptyFields but in users order + for ( i=0; i < nUsersFound; i++ ) { + U_TCHAR_MAP* pmUserData = ( U_TCHAR_MAP* )plUsersInfo->operator [](i); + int nUserFields = pmUserData->getCount(); + for (int j=0; j < nUserFields; j++) { + TCHAR* var = pmUserData->getKeyName(j); + if (var && ListOfNonEmptyFields.getIndex(var) < 0) + ListOfNonEmptyFields.insert(var); + } } + + // now fill the ListOfFields but order is from pmAllFields + int nAllCount = pmAllFields->getCount(); + for ( i=0; i < nAllCount; i++ ) { + TCHAR * var=pmAllFields->getUnOrderedKeyName(i); + if ( var && ListOfNonEmptyFields.getIndex(var) < 0 ) + continue; + ListOfFields.insert(var); + } + + // now lets transfer field names + int nFieldCount = ListOfFields.getCount(); + + JABBER_CUSTOMSEARCHRESULTS Results={0}; + Results.nSize=sizeof(Results); + Results.pszFields=(TCHAR**)mir_alloc(sizeof(TCHAR*)*nFieldCount); + Results.nFieldCount=nFieldCount; + + /* Sending Columns Titles */ + for ( i=0; i < nFieldCount; i++ ) { + TCHAR* var = ListOfFields[i]; + if ( var ) + Results.pszFields[i] = pmAllFields->operator [](var); + } + + Results.jsr.hdr.cbSize = 0; // sending column names + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM) &Results ); + + /* Sending Users Data */ + Results.jsr.hdr.cbSize = sizeof(Results.jsr); // sending user data + + for ( i=0; i < nUsersFound; i++ ) { + TCHAR buff[200]=_T(""); + Results.jsr.jid[0]=_T('\0'); + U_TCHAR_MAP * pmUserData = (U_TCHAR_MAP *) plUsersInfo->operator [](i); + for ( int j=0; j < nFieldCount; j++ ) { + TCHAR* var = ListOfFields[j]; + TCHAR* value = pmUserData->operator [](var); + Results.pszFields[j] = value ? value : (TCHAR *)_T(" "); + if (!_tcsicmp(var,_T("jid")) && value ) + _tcsncpy(Results.jsr.jid, value, SIZEOF(Results.jsr.jid)); + } + { + TCHAR * nickfields[]={ _T("nick"), _T("nickname"), + _T("fullname"), _T("name"), + _T("given"), _T("first"), + _T("jid"), NULL }; + TCHAR * nick=NULL; + int k=0; + while (nickfields[k] && !nick) nick=pmUserData->operator [](nickfields[k++]); + if (_tcsicmp(nick, Results.jsr.jid)) + _sntprintf(buff,SIZEOF(buff),_T("%s ( %s )"),nick, Results.jsr.jid); + else + _tcsncpy(buff, nick, SIZEOF(buff)); + Results.jsr.hdr.nick = nick ? buff : NULL; + Results.jsr.hdr.flags = PSR_TCHAR; + } + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM) &Results ); + Results.jsr.hdr.nick=NULL; + + } + mir_free( Results.pszFields ); +} + +void DestroyKey( TCHAR* key ) +{ + mir_free( key ); +} + +TCHAR* CopyKey( TCHAR* key ) +{ + return mir_tstrdup( key ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Search field request result handler (XEP-0055. Examples 3, 8) + +void CJabberProto::OnIqResultAdvancedSearch( HXML iqNode ) +{ + const TCHAR* type; + int id; + + U_TCHAR_MAP mColumnsNames(10); + LIST<void> SearchResults(2); + + if ((( id = JabberGetPacketID( iqNode )) == -1 ) || (( type = xmlGetAttrValue( iqNode, _T("type"))) == NULL )) { + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); + return; + } + + if ( !lstrcmp( type, _T("result"))) { + HXML queryNode = xmlGetNthChild( iqNode, _T("query"), 1 ); + HXML xNode = xmlGetChildByTag( queryNode, "x", "xmlns", _T(JABBER_FEAT_DATA_FORMS)); + if (xNode) { + //1. Form search results info + HXML reportNode = xmlGetNthChild( xNode, _T("reported"), 1 ); + if (reportNode) { + int i = 1; + while ( HXML fieldNode = xmlGetNthChild( reportNode, _T("field"), i++ )) { + TCHAR* var = ( TCHAR* )xmlGetAttrValue( fieldNode, _T( "var" )); + if ( var ) { + TCHAR* Label = ( TCHAR* )xmlGetAttrValue( fieldNode, _T( "label" )); + mColumnsNames.insert(var, (Label!=NULL) ? Label : var); + } } } + + int i=1; + HXML itemNode; + while ( itemNode = xmlGetNthChild( xNode, _T("item"), i++ )) { + U_TCHAR_MAP *pUserColumn = new U_TCHAR_MAP(10); + int j = 1; + while ( HXML fieldNode = xmlGetNthChild( itemNode, _T("field"), j++ )) { + if ( TCHAR* var = (TCHAR*)xmlGetAttrValue( fieldNode, _T("var"))) { + if ( TCHAR* Text = (TCHAR*)xmlGetText( xmlGetChild( fieldNode, _T("value")))) { + if ( !mColumnsNames[var] ) + mColumnsNames.insert(var,var); + pUserColumn->insert(var,Text); + } } } + + SearchResults.insert((void*)pUserColumn); + } + } + else { + //2. Field list search results info + int i=1; + while ( HXML itemNode = xmlGetNthChild( queryNode, _T("item"), i++ )) { + U_TCHAR_MAP *pUserColumn=new U_TCHAR_MAP(10); + + TCHAR* jid = (TCHAR*)xmlGetAttrValue( itemNode, _T("jid")); + TCHAR* keyReturned; + mColumnsNames.insertCopyKey( _T("jid"),_T("jid"),&keyReturned, CopyKey, DestroyKey ); + mColumnsNames.insert( _T("jid"), keyReturned ); + pUserColumn->insertCopyKey( _T("jid"), jid, NULL, CopyKey, DestroyKey ); + + for ( int j=0; ; j++ ) { + HXML child = xmlGetChild( itemNode, j ); + if ( !child ) + break; + + const TCHAR* szColumnName = xmlGetName( child ); + if ( szColumnName ) { + if ( xmlGetText( child ) && xmlGetText( child )[0] != _T('\0')) { + mColumnsNames.insertCopyKey(( TCHAR* )szColumnName,_T(""),&keyReturned, CopyKey, DestroyKey); + mColumnsNames.insert(( TCHAR* )szColumnName,keyReturned); + pUserColumn->insertCopyKey(( TCHAR* )szColumnName, ( TCHAR* )xmlGetText( child ),NULL, CopyKey, DestroyKey); + } } } + + SearchResults.insert((void*)pUserColumn); + } } + } + else if (!lstrcmp( type, _T("error"))) { + const TCHAR* code=NULL; + const TCHAR* description=NULL; + TCHAR buff[255]; + HXML errorNode = xmlGetChild( iqNode , "error" ); + if (errorNode) { + code = xmlGetAttrValue( errorNode, _T("code")); + description = xmlGetText( errorNode ); + } + + _sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s\r\nTry to specify more detailed"),code ? code : _T(""),description?description:_T("")); + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); + if (searchHandleDlg ) + SetDlgItemText(searchHandleDlg,IDC_INSTRUCTIONS,buff); + else + MessageBox(NULL, buff, TranslateT("Search error"), MB_OK|MB_ICONSTOP); + return; + } + + SearchReturnResults((HANDLE)id, (void*)&SearchResults, (U_TCHAR_MAP *)&mColumnsNames); + + for (int i=0; i < SearchResults.getCount(); i++ ) + delete ((U_TCHAR_MAP *)SearchResults[i]); + + //send success to finish searching + JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); +} + +static BOOL CALLBACK DeleteChildWindowsProc( HWND hwnd, LPARAM ) +{ + DestroyWindow(hwnd); + return TRUE; +} + +static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat) +{ + //lock + if ( !dat->fSearchRequestIsXForm && dat->nJSInfCount && dat->pJSInf ) { + for ( int i=0; i < dat->nJSInfCount; i++ ) { + if (dat->pJSInf[i].hwndValueItem) + DestroyWindow(dat->pJSInf[i].hwndValueItem); + if (dat->pJSInf[i].hwndCaptionItem) + DestroyWindow(dat->pJSInf[i].hwndCaptionItem); + if (dat->pJSInf[i].szFieldCaption) + free(dat->pJSInf[i].szFieldCaption); + if (dat->pJSInf[i].szFieldName) + free(dat->pJSInf[i].szFieldName); + } + free(dat->pJSInf); + dat->pJSInf=NULL; + } + else EnumChildWindows(GetDlgItem(hwndDlg,IDC_FRAME),DeleteChildWindowsProc,0); + + if ( dat->xNode ) + xi.destroyNode( dat->xNode ); + + SendMessage(GetDlgItem(hwndDlg,IDC_FRAME), WM_SETFONT, (WPARAM) SendMessage( hwndDlg, WM_GETFONT, 0, 0 ),0 ); + dat->nJSInfCount=0; + ShowWindow(GetDlgItem(hwndDlg,IDC_VSCROLL),SW_HIDE); + SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,TranslateT("Select/type search service URL above and press <Go>")); + //unlock +} + +static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData * dat) +{ + HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME ); + HWND hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL ); + RECT rc; + GetClientRect( hFrame, &rc ); + GetClientRect( hFrame, &dat->frameRect ); + dat->frameHeight = rc.bottom-rc.top; + if ( dat->frameHeight < dat->CurrentHeight) { + ShowWindow( hwndScroll, SW_SHOW ); + EnableWindow( hwndScroll, TRUE ); + } + else ShowWindow( hwndScroll, SW_HIDE ); + + SetScrollRange( hwndScroll, SB_CTL, 0, dat->CurrentHeight-dat->frameHeight, FALSE ); +} + +int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat) +{ + TCHAR szServerName[100]; + EnableWindow(GetDlgItem(hwndDlg, IDC_GO),FALSE); + GetDlgItemText(hwndDlg,IDC_SERVER,szServerName,SIZEOF(szServerName)); + dat->CurrentHeight = 0; + dat->curPos = 0; + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); + + JabberSearchFreeData( hwndDlg, dat ); + JabberSearchRefreshFrameScroll( hwndDlg, dat ); + + SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server")); + + if ( !m_bJabberOnline ) + return 0; + + searchHandleDlg = hwndDlg; + + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_GETSEARCHFIELDS, &CJabberProto::OnIqResultGetSearchFields ); + m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szServerName ) << XQUERY( _T("jabber:iq:search"))); + return iqId; +} + +static void JabberSearchAddUrlToRecentCombo(HWND hwndDlg, const TCHAR* szAddr) +{ + int lResult = SendMessage( GetDlgItem(hwndDlg,IDC_SERVER), (UINT) CB_FINDSTRING, 0, (LPARAM)szAddr ); + if ( lResult == -1 ) + SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )szAddr ); +} + +void CJabberProto::SearchDeleteFromRecent( const TCHAR* szAddr, BOOL deleteLastFromDB ) +{ + DBVARIANT dbv; + char key[30]; + //search in recent + for ( int i=0; i<10; i++ ) { + sprintf(key,"RecentlySearched_%d",i); + if ( !JGetStringT( NULL, key, &dbv )) { + if ( !_tcsicmp( szAddr, dbv.ptszVal )) { + JFreeVariant( &dbv ); + for ( int j=i; j<10; j++ ) { + sprintf( key, "RecentlySearched_%d", j+1 ); + if ( !JGetStringT( NULL, key, &dbv )) { + sprintf(key,"RecentlySearched_%d",j); + JSetStringT(NULL,key,dbv.ptszVal); + JFreeVariant( &dbv ); + } + else { + if ( deleteLastFromDB ) { + sprintf(key,"RecentlySearched_%d",j); + JDeleteSetting(NULL,key); + } + break; + } } + break; + } + else JFreeVariant( &dbv ); +} } } + +void CJabberProto::SearchAddToRecent( const TCHAR* szAddr, HWND hwndDialog ) +{ + DBVARIANT dbv; + char key[30]; + SearchDeleteFromRecent( szAddr ); + for ( int j=9; j > 0; j-- ) { + sprintf( key, "RecentlySearched_%d", j-1 ); + if ( !JGetStringT( NULL, key, &dbv )) { + sprintf(key,"RecentlySearched_%d",j); + JSetStringT(NULL,key,dbv.ptszVal); + JFreeVariant(&dbv); + } } + + sprintf( key, "RecentlySearched_%d", 0 ); + JSetStringT( NULL, key, szAddr ); + if ( hwndDialog ) + JabberSearchAddUrlToRecentCombo( hwndDialog, szAddr ); +} + +static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + JabberSearchData* dat = ( JabberSearchData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + switch ( msg ) { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + dat = ( JabberSearchData * )mir_alloc( sizeof( JabberSearchData )); + memset( dat, 0, sizeof( JabberSearchData )); + dat->ppro = ( CJabberProto* )lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)dat ); + + /* Server Combo box */ + char szServerName[100]; + if ( dat->ppro->JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName )) + strcpy( szServerName, "users.jabber.org" ); + SetDlgItemTextA(hwndDlg,IDC_SERVER,szServerName); + SendDlgItemMessageA(hwndDlg,IDC_SERVER,CB_ADDSTRING,0,(LPARAM)szServerName); + //TO DO: Add Transports here + int i, transpCount = dat->ppro->m_lstTransports.getCount(); + for ( i=0; i < transpCount; i++ ) { + TCHAR* szTransp = dat->ppro->m_lstTransports[i]; + if ( szTransp ) + JabberSearchAddUrlToRecentCombo(hwndDlg, szTransp ); + } + + DBVARIANT dbv; + char key[30]; + for ( i=0; i < 10; i++ ) { + sprintf(key,"RecentlySearched_%d",i); + if ( !dat->ppro->JGetStringT( NULL, key, &dbv )) { + JabberSearchAddUrlToRecentCombo(hwndDlg, dbv.ptszVal ); + JFreeVariant( &dbv ); + } } + + //TO DO: Add 4 recently used + dat->lastRequestIq = dat->ppro->SearchRenewFields(hwndDlg,dat); + } + return TRUE; + + case WM_COMMAND: + if ( LOWORD(wParam) == IDC_SERVER ) { + switch ( HIWORD( wParam )) { + case CBN_SETFOCUS: + PostMessage(GetParent(hwndDlg),WM_COMMAND, MAKEWPARAM(0,EN_SETFOCUS), (LPARAM)hwndDlg); + return TRUE; + + case CBN_EDITCHANGE: + EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); + return TRUE; + + case CBN_EDITUPDATE: + JabberSearchFreeData(hwndDlg, dat); + EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); + return TRUE; + + case CBN_SELENDOK: + EnableWindow(GetDlgItem(hwndDlg, IDC_GO),TRUE); + PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_GO,BN_CLICKED),0); + return TRUE; + } + } + else if ( LOWORD(wParam) == IDC_GO && HIWORD(wParam) == BN_CLICKED ) { + dat->ppro->SearchRenewFields( hwndDlg, dat ); + return TRUE; + } + break; + + case WM_SIZE: + { + //Resize IDC_FRAME to take full size + RECT rcForm; + GetWindowRect(hwndDlg, &rcForm); + RECT rcFrame; + GetWindowRect( GetDlgItem(hwndDlg, IDC_FRAME), &rcFrame ); + rcFrame.bottom = rcForm.bottom; + SetWindowPos(GetDlgItem(hwndDlg,IDC_FRAME),NULL,0,0,rcFrame.right-rcFrame.left,rcFrame.bottom-rcFrame.top,SWP_NOZORDER|SWP_NOMOVE); + GetWindowRect(GetDlgItem(hwndDlg,IDC_VSCROLL), &rcForm); + SetWindowPos(GetDlgItem(hwndDlg,IDC_VSCROLL),NULL,0,0,rcForm.right-rcForm.left,rcFrame.bottom-rcFrame.top,SWP_NOZORDER|SWP_NOMOVE); + JabberSearchRefreshFrameScroll(hwndDlg, dat); + } + return TRUE; + + case WM_USER+11: + { + dat->fSearchRequestIsXForm=TRUE; + dat->xNode = ( HXML )wParam; + JabberFormCreateUI( GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode, &dat->CurrentHeight,TRUE); + ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME), SW_SHOW); + dat->nJSInfCount=1; + return TRUE; + } + case WM_USER+10: + { + Data* MyDat = ( Data* )lParam; + if ( MyDat ) { + dat->fSearchRequestIsXForm = ( BOOL )wParam; + dat->CurrentHeight = JabberSearchAddField(hwndDlg,MyDat); + mir_free( MyDat->Label ); + mir_free( MyDat->Var ); + mir_free( MyDat->defValue ); + free( MyDat ); + } + else + { + JabberSearchRefreshFrameScroll(hwndDlg,dat); + ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - 0, NULL, &( dat->frameRect )); + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); + dat->curPos=0; + } + return TRUE; + } + case WM_MOUSEWHEEL: + { + int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); + if ( zDelta ) { + int nScrollLines=0; + SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,(void*)&nScrollLines,0); + for (int i=0; i<(nScrollLines+1)/2; i++) + SendMessage(hwndDlg,WM_VSCROLL, (zDelta<0)?SB_LINEDOWN:SB_LINEUP,0); + } } + return TRUE; + + case WM_VSCROLL: + { + int pos; + if ( dat != NULL ) { + pos = dat->curPos; + switch ( LOWORD( wParam )) { + case SB_LINEDOWN: + pos += 10; + break; + case SB_LINEUP: + pos -= 10; + break; + case SB_PAGEDOWN: + pos += ( dat->CurrentHeight - 10 ); + break; + case SB_PAGEUP: + pos -= ( dat->CurrentHeight - 10 ); + break; + case SB_THUMBTRACK: + pos = HIWORD( wParam ); + break; + } + if ( pos > ( dat->CurrentHeight - dat->frameHeight )) + pos = dat->CurrentHeight - dat->frameHeight; + if ( pos < 0 ) + pos = 0; + if ( dat->curPos != pos ) { + ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL , &( dat->frameRect )); + SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE ); + RECT Invalid=dat->frameRect; + if (dat->curPos - pos >0) + Invalid.bottom=Invalid.top+(dat->curPos - pos); + else + Invalid.top=Invalid.bottom+(dat->curPos - pos); + + RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_UPDATENOW |RDW_ALLCHILDREN); + dat->curPos = pos; + } } } + return TRUE; + + case WM_DESTROY: + JabberSearchFreeData( hwndDlg, dat ); + JabberFormDestroyUI( GetDlgItem( hwndDlg, IDC_FRAME )); + mir_free( dat ); + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0 ); + return TRUE; + } + return FALSE; +} + +HWND __cdecl CJabberProto::CreateExtendedSearchUI( HWND parent ) +{ + TCHAR szServer[128]; + if (parent && hInst && (!JGetStringT(NULL, "LoginServer", szServer, SIZEOF(szServer)) || _tcsicmp(szServer, _T("S.ms")))) + return CreateDialogParam( hInst, MAKEINTRESOURCE(IDD_SEARCHUSER), parent, JabberSearchAdvancedDlgProc, ( LPARAM )this ); + + return 0; // Failure +} + +////////////////////////////////////////////////////////////////////////// +// The function formats request to server + +HWND __cdecl CJabberProto::SearchAdvanced( HWND hwndDlg ) +{ + if ( !m_bJabberOnline || !hwndDlg ) + return 0; //error + + JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if ( !dat ) + return 0; //error + + // check if server connected (at least one field exists) + if ( dat->nJSInfCount == 0 ) + return 0; + + // formating request + BOOL fRequestNotEmpty=FALSE; + + // get server name + TCHAR szServerName[100]; + GetDlgItemText( hwndDlg, IDC_SERVER, szServerName, SIZEOF( szServerName )); + + // formating query + int iqId = SerialNext(); + XmlNodeIq iq( _T("set"), iqId, szServerName ); + HXML query = iq << XQUERY( _T("jabber:iq:search")); + + if ( m_tszSelectedLang ) + iq << XATTR( _T("xml:lang"), m_tszSelectedLang ); // i'm sure :) + + // next can be 2 cases: + // Forms: XEP-0055 Example 7 + if ( dat->fSearchRequestIsXForm ) { + fRequestNotEmpty=TRUE; + HXML n = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode); + xmlAddChild( query, n ); + xi.destroyNode( n ); + } + else { //and Simple fields: XEP-0055 Example 3 + for ( int i=0; i<dat->nJSInfCount; i++ ) { + TCHAR szFieldValue[100]; + GetWindowText(dat->pJSInf[i].hwndValueItem, szFieldValue, SIZEOF(szFieldValue)); + if ( szFieldValue[0] != _T('\0')) { + xmlAddChild( query, dat->pJSInf[i].szFieldName, szFieldValue ); + fRequestNotEmpty=TRUE; + } } } + + if ( fRequestNotEmpty ) { + // register search request result handler + IqAdd( iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultAdvancedSearch ); + // send request + m_ThreadInfo->send( iq ); + return ( HWND )iqId; + } + return 0; +} diff --git a/protocols/JabberG/src/jabber_search.h b/protocols/JabberG/src/jabber_search.h new file mode 100644 index 0000000000..7450b652d1 --- /dev/null +++ b/protocols/JabberG/src/jabber_search.h @@ -0,0 +1,273 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Artem Shpynov + +Module implements a search according to XEP-0055: Jabber Search +http://www.xmpp.org/extensions/xep-0055.html + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +typedef struct _tagJabberSearchFieldsInfo +{ + TCHAR * szFieldName; + TCHAR * szFieldCaption; + HWND hwndCaptionItem; + HWND hwndValueItem; +} JabberSearchFieldsInfo; + +typedef struct _tagJabberSearchData +{ + struct CJabberProto* ppro; + JabberSearchFieldsInfo * pJSInf; + HXML xNode; + int nJSInfCount; + int lastRequestIq; + int CurrentHeight; + int curPos; + int frameHeight; + RECT frameRect; + BOOL fSearchRequestIsXForm; + +}JabberSearchData; + +typedef struct tag_Data +{ + TCHAR *Label; + TCHAR * Var; + TCHAR * defValue; + BOOL bHidden; + BOOL bReadOnly; + int Order; + +} Data; + + +typedef struct tagJABBER_CUSTOMSEARCHRESULTS +{ + size_t nSize; + int nFieldCount; + TCHAR ** pszFields; + JABBER_SEARCH_RESULT jsr; +}JABBER_CUSTOMSEARCHRESULTS; + +static HWND searchHandleDlg=NULL; + +//local functions declarations +static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam); +static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat ); +static void JabberIqResultGetSearchFields( HXML iqNode, void *userdata ); +static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat); +static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData * dat); +static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +static void JabberSearchDeleteFromRecent(TCHAR * szAddr,BOOL deleteLastFromDB); +void SearchAddToRecent(TCHAR * szAddr, HWND hwnd); + +// Implementation of MAP class (the list +template <typename _KEYTYPE , int (*COMPARATOR)(_KEYTYPE*, _KEYTYPE*) > +class UNIQUE_MAP +{ + +public: + typedef _KEYTYPE* (*COPYKEYPROC)(_KEYTYPE*); + typedef void (*DESTROYKEYPROC)(_KEYTYPE*); + +private: + typedef struct _tagRECORD + { + _tagRECORD(_KEYTYPE * key, TCHAR * value=NULL) { _key=key; _value=value; _order=0; _destroyKeyProc=NULL; } + ~_tagRECORD() + { + if (_key && _destroyKeyProc) + _destroyKeyProc(_key); + _key=NULL; + _destroyKeyProc=NULL; + } + _KEYTYPE *_key; + TCHAR * _value; + int _order; + DESTROYKEYPROC _destroyKeyProc; + } _RECORD; + + int _nextOrder; + LIST<_RECORD> _Records; + + static int _KeysEqual( const _RECORD* p1, const _RECORD* p2 ) + { + if (COMPARATOR) + return (int)(COMPARATOR((p1->_key),(p2->_key))); + else + return (int) (p1->_key < p2->_key); + } + + inline int _remove(_RECORD* p) + { + int _itemOrder=p->_order; + if (_Records.remove(p)) + { + delete(p); + _nextOrder--; + for (int i=0; i<_Records.getCount(); i++) + { + _RECORD * temp=_Records[i]; + if (temp && temp->_order>_itemOrder) + temp->_order--; + } + return 1; + } + return 0; + } + inline _RECORD * _getUnorderedRec (int index) + { + for (int i=0; i<_Records.getCount(); i++) + { + _RECORD * rec=_Records[i]; + if (rec->_order==index) return rec; + } + return NULL; + } + +public: + UNIQUE_MAP(int incr):_Records(incr,_KeysEqual) + { + _nextOrder=0; + }; + ~UNIQUE_MAP() + { + _RECORD * record; + int i=0; + while (record=_Records[i++]) delete record; + } + + int insert(_KEYTYPE* Key, TCHAR *Value) + { + _RECORD * rec= new _RECORD(Key,Value); + int index=_Records.getIndex(rec); + if (index<0) + { + if (!_Records.insert(rec)) delete rec; + else + { + index=_Records.getIndex(rec); + rec->_order=_nextOrder++; + } + } + else + { + _Records[index]->_value=Value; + delete rec; + } + return index; + } + int insertCopyKey(_KEYTYPE* Key, TCHAR *Value, _KEYTYPE** _KeyReturn, COPYKEYPROC CopyProc, DESTROYKEYPROC DestroyProc ) + { + _RECORD * rec= new _RECORD(Key,Value); + int index=_Records.getIndex(rec); + if (index<0) + { + _KEYTYPE* newKey=CopyProc(Key); + if (!_Records.insert(rec)) + { + delete rec; + DestroyProc(newKey); + if (_KeyReturn) *_KeyReturn=NULL; + } + else + { + rec->_key=newKey; + rec->_destroyKeyProc=DestroyProc; + index=_Records.getIndex(rec); + rec->_order=_nextOrder++; + if (_KeyReturn) *_KeyReturn=newKey; + } + } + else + { + _Records[index]->_value=Value; + if (_KeyReturn) *_KeyReturn=_Records[index]->_key; + delete rec; + } + return index; + } + inline TCHAR* operator[]( _KEYTYPE* _KEY ) const + { + _RECORD rec(_KEY); + int index=_Records.getIndex(&rec); + _RECORD * rv=_Records[index]; + if (rv) + { + if (rv->_value) + return rv->_value; + else + return _T(""); + } + else + return NULL; + } + inline TCHAR* operator[]( int index ) const + { + _RECORD * rv=_Records[index]; + if (rv) return rv->_value; + else return NULL; + } + inline _KEYTYPE* getKeyName(int index) + { + _RECORD * rv=_Records[index]; + if (rv) return rv->_key; + else return NULL; + } + inline TCHAR * getUnOrdered(int index) + { + _RECORD * rec=_getUnorderedRec(index); + if (rec) return rec->_value; + else return NULL; + } + inline _KEYTYPE * getUnOrderedKeyName(int index) + { + _RECORD * rec=_getUnorderedRec(index); + if (rec) return rec->_key; + else return NULL; + } + inline int getCount() + { + return _Records.getCount(); + } + inline int removeUnOrdered(int index) + { + _RECORD * p=_getUnorderedRec(index); + if (p) return _remove(p); + else return 0; + } + inline int remove(int index) + { + _RECORD * p=_Records[index]; + if (p) return _remove(p); + else return 0; + } + inline int getIndex(_KEYTYPE * key) + { + _RECORD temp(key); + return _Records.getIndex(&temp); + } +}; + +inline int TCharKeyCmp(TCHAR* a, TCHAR* b) +{ + return (int)(_tcsicmp(a,b)); +} diff --git a/protocols/JabberG/src/jabber_secur.cpp b/protocols/JabberG/src/jabber_secur.cpp new file mode 100644 index 0000000000..c48ded22d6 --- /dev/null +++ b/protocols/JabberG/src/jabber_secur.cpp @@ -0,0 +1,469 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_secur.h" + +typedef BYTE (WINAPI *GetUserNameExType )( int NameFormat, LPTSTR lpNameBuffer, PULONG nSize ); + + +///////////////////////////////////////////////////////////////////////////////////////// +// ntlm auth - LanServer based authorization + +TNtlmAuth::TNtlmAuth( ThreadData* info, const char* mechanism, const TCHAR* hostname ) : + TJabberAuth( info ) +{ + szName = mechanism; + szHostName = hostname; + + const TCHAR *szProvider; + if ( !strcmp( mechanism, "GSS-SPNEGO" )) + szProvider = _T("Negotiate"); + else if ( !strcmp( mechanism, "GSSAPI" )) + szProvider = _T("GSSAPI"); + else if ( !strcmp( mechanism, "NTLM" )) + szProvider = _T("NTLM"); + else { + bIsValid = false; + return; + } + + TCHAR szSpn[ 1024 ] = _T( "" ); + if ( strcmp( mechanism, "NTLM" )) { + if ( !getSpn( szSpn, SIZEOF( szSpn )) && !strcmp( mechanism, "GSSAPI" )) { + bIsValid = false; + return; + } } + + if (( hProvider = Netlib_InitSecurityProvider2( szProvider, szSpn )) == NULL ) + bIsValid = false; +} + +TNtlmAuth::~TNtlmAuth() +{ + if ( hProvider != NULL ) + Netlib_DestroySecurityProvider( NULL, hProvider ); +} + +bool TNtlmAuth::getSpn( TCHAR* szSpn, size_t dwSpnLen ) +{ + GetUserNameExType myGetUserNameEx = + ( GetUserNameExType )GetProcAddress( GetModuleHandleA( "secur32.dll" ), "GetUserNameExW" ); + + if ( !myGetUserNameEx ) return false; + + TCHAR szFullUserName[128] = _T( "" ); + ULONG szFullUserNameLen = SIZEOF( szFullUserName ); + if (!myGetUserNameEx( 12, szFullUserName, &szFullUserNameLen )) { + szFullUserName[ 0 ] = 0; + szFullUserNameLen = SIZEOF( szFullUserName ); + myGetUserNameEx( 2, szFullUserName, &szFullUserNameLen ); + } + + TCHAR* name = _tcsrchr( szFullUserName, '\\' ); + if ( name ) *name = 0; + else return false; + + if ( szHostName && szHostName[0] ) { + TCHAR *szFullUserNameU = _tcsupr( mir_tstrdup( szFullUserName )); + mir_sntprintf( szSpn, dwSpnLen, _T( "xmpp/%s/%s@%s" ), szHostName, szFullUserName, szFullUserNameU ); + mir_free( szFullUserNameU ); + } else { + const char* connectHost = info->manualHost[0] ? info->manualHost : info->server; + + unsigned long ip = inet_addr( connectHost ); + // Convert host name to FQDN +// PHOSTENT host = (ip == INADDR_NONE) ? gethostbyname( szHost ) : gethostbyaddr(( char* )&ip, 4, AF_INET ); + PHOSTENT host = (ip == INADDR_NONE) ? NULL : gethostbyaddr(( char* )&ip, 4, AF_INET ); + if ( host && host->h_name ) + connectHost = host->h_name; + + TCHAR *connectHostT = mir_a2t( connectHost ); + mir_sntprintf( szSpn, dwSpnLen, _T( "xmpp/%s@%s" ), connectHostT, _tcsupr( szFullUserName )); + mir_free( connectHostT ); + } + + Netlib_Logf( NULL, "SPN: " TCHAR_STR_PARAM, szSpn ); + + + return true; +} + +char* TNtlmAuth::getInitialRequest() +{ + if ( !hProvider ) + return NULL; + + // This generates login method advertisement packet + char* result; + if ( info->password[0] != 0 ) + result = Netlib_NtlmCreateResponse2( hProvider, "", info->username, info->password, &complete ); + else + result = Netlib_NtlmCreateResponse2( hProvider, "", NULL, NULL, &complete ); + + return result; +} + +char* TNtlmAuth::getChallenge( const TCHAR* challenge ) +{ + if ( !hProvider ) + return NULL; + + char *text = ( !lstrcmp( challenge, _T("="))) ? mir_strdup( "" ) : mir_t2a( challenge ), *result; + if ( info->password[0] != 0 ) + result = Netlib_NtlmCreateResponse2( hProvider, text, info->username, info->password, &complete ); + else + result = Netlib_NtlmCreateResponse2( hProvider, text, NULL, NULL, &complete ); + + mir_free( text ); + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// md5 auth - digest-based authorization + +TMD5Auth::TMD5Auth( ThreadData* info ) : + TJabberAuth( info ), + iCallCount( 0 ) +{ + szName = "DIGEST-MD5"; +} + +TMD5Auth::~TMD5Auth() +{ +} + +char* TMD5Auth::getChallenge( const TCHAR* challenge ) +{ + if ( iCallCount > 0 ) + return NULL; + + iCallCount++; + + int resultLen; + char* text = JabberBase64DecodeT( challenge, &resultLen ); + + TStringPairs pairs( text ); + const char *realm = pairs["realm"], *nonce = pairs["nonce"]; + + char cnonce[40], tmpBuf[40]; + DWORD digest[4], hash1[4], hash2[4]; + mir_md5_state_t ctx; + + CallService( MS_UTILS_GETRANDOM, sizeof( digest ), ( LPARAM )digest ); + sprintf( cnonce, "%08x%08x%08x%08x", htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); + + char *uname = mir_utf8encodeT( info->username ), + *passw = mir_utf8encodeT( info->password ), + *serv = mir_utf8encode( info->server ); + + mir_md5_init( &ctx ); + mir_md5_append( &ctx, ( BYTE* )uname, (int)strlen( uname )); + mir_md5_append( &ctx, ( BYTE* )":", 1 ); + mir_md5_append( &ctx, ( BYTE* )realm, (int)strlen( realm )); + mir_md5_append( &ctx, ( BYTE* )":", 1 ); + mir_md5_append( &ctx, ( BYTE* )passw, (int)strlen( passw )); + mir_md5_finish( &ctx, ( BYTE* )hash1 ); + + mir_md5_init( &ctx ); + mir_md5_append( &ctx, ( BYTE* )hash1, 16 ); + mir_md5_append( &ctx, ( BYTE* )":", 1 ); + mir_md5_append( &ctx, ( BYTE* )nonce, (int)strlen( nonce )); + mir_md5_append( &ctx, ( BYTE* )":", 1 ); + mir_md5_append( &ctx, ( BYTE* )cnonce, (int)strlen( cnonce )); + mir_md5_finish( &ctx, ( BYTE* )hash1 ); + + mir_md5_init( &ctx ); + mir_md5_append( &ctx, ( BYTE* )"AUTHENTICATE:xmpp/", 18 ); + mir_md5_append( &ctx, ( BYTE* )serv, (int)strlen( serv )); + mir_md5_finish( &ctx, ( BYTE* )hash2 ); + + mir_md5_init( &ctx ); + sprintf( tmpBuf, "%08x%08x%08x%08x", htonl(hash1[0]), htonl(hash1[1]), htonl(hash1[2]), htonl(hash1[3])); + mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); + mir_md5_append( &ctx, ( BYTE* )":", 1 ); + mir_md5_append( &ctx, ( BYTE* )nonce, (int)strlen( nonce )); + sprintf( tmpBuf, ":%08d:", iCallCount ); + mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); + mir_md5_append( &ctx, ( BYTE* )cnonce, (int)strlen( cnonce )); + mir_md5_append( &ctx, ( BYTE* )":auth:", 6 ); + sprintf( tmpBuf, "%08x%08x%08x%08x", htonl(hash2[0]), htonl(hash2[1]), htonl(hash2[2]), htonl(hash2[3])); + mir_md5_append( &ctx, ( BYTE* )tmpBuf, (int)strlen( tmpBuf )); + mir_md5_finish( &ctx, ( BYTE* )digest ); + + char* buf = (char*)alloca(8000); + int cbLen = mir_snprintf( buf, 8000, + "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\",nc=%08d," + "qop=auth,digest-uri=\"xmpp/%s\",charset=utf-8,response=%08x%08x%08x%08x", + uname, realm, nonce, cnonce, iCallCount, serv, + htonl(digest[0]), htonl(digest[1]), htonl(digest[2]), htonl(digest[3])); + + mir_free( uname ); + mir_free( passw ); + mir_free( serv ); + mir_free( text ); + + return JabberBase64Encode( buf, cbLen ); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// SCRAM-SHA-1 authorization + +void hmac_sha1(mir_sha1_byte_t *md, mir_sha1_byte_t *key, size_t keylen, mir_sha1_byte_t *text, size_t textlen) +{ + const unsigned SHA_BLOCKSIZE = 64; + + unsigned char mdkey[MIR_SHA1_HASH_SIZE]; + unsigned char k_ipad[SHA_BLOCKSIZE], k_opad[SHA_BLOCKSIZE]; + mir_sha1_ctx ctx; + + if (keylen > SHA_BLOCKSIZE) + { + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, key, (int)keylen); + mir_sha1_finish(&ctx, mdkey); + keylen = 20; + key = mdkey; + } + + memcpy(k_ipad, key, keylen); + memcpy(k_opad, key, keylen); + memset(k_ipad+keylen, 0x36, SHA_BLOCKSIZE - keylen); + memset(k_opad+keylen, 0x5c, SHA_BLOCKSIZE - keylen); + + for (unsigned i = 0; i < keylen; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, k_ipad, SHA_BLOCKSIZE); + mir_sha1_append(&ctx, text, (int)textlen); + mir_sha1_finish(&ctx, md); + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, k_opad, SHA_BLOCKSIZE); + mir_sha1_append(&ctx, md, MIR_SHA1_HASH_SIZE); + mir_sha1_finish(&ctx, md); +} + +TScramAuth::TScramAuth( ThreadData* info ) : + TJabberAuth( info ) +{ + szName = "SCRAM-SHA-1"; + cnonce = msg1 = serverSignature = NULL; +} + +TScramAuth::~TScramAuth() +{ + mir_free( cnonce ); + mir_free( msg1 ); + mir_free( serverSignature ); +} + +void TScramAuth::Hi( mir_sha1_byte_t* res , char* passw, size_t passwLen, char* salt, size_t saltLen, int ind ) +{ + mir_sha1_byte_t u[ MIR_SHA1_HASH_SIZE ]; + memcpy( u, salt, saltLen ); *( unsigned* )( u + saltLen ) = htonl( 1 ); saltLen += 4; + memset( res, 0, MIR_SHA1_HASH_SIZE ); + + for (int i = 0; i < ind; i++) + { + hmac_sha1( u, (mir_sha1_byte_t*)passw, passwLen, u, saltLen); + saltLen = sizeof( u ); + + for (unsigned j = 0; j < sizeof( u ); j++) + res[j] ^= u[j]; + } +} + +char* TScramAuth::getChallenge( const TCHAR* challenge ) +{ + int chlLen; + char *chl = JabberBase64DecodeT( challenge, &chlLen ); + + char *r = strstr( chl, "r=" ); if ( !r ) { mir_free( chl ); return NULL; } + char *e = strchr( r, ',' ); if ( e ) *e = 0; + char *snonce = mir_strdup(r + 2); + if ( e ) *e = ','; + + size_t cnlen = strlen( cnonce ); + if (strncmp(cnonce, snonce, cnlen )) { mir_free( chl ); mir_free( snonce ); return NULL; } + + char *s = strstr( chl, "s=" ); if ( !s ) { mir_free( chl ); mir_free( snonce ); return NULL; } + e = strchr( s, ',' ); if ( e ) *e = 0; + int saltLen; + char *salt = JabberBase64Decode( s + 2, &saltLen ); + if ( e ) *e = ','; + + if ( saltLen > 16 ) { + mir_free( salt ); + mir_free( snonce ); + mir_free( chl ); + return NULL; + } + + char *in = strstr( chl, "i=" ); if ( !in ) return NULL; + e = strchr( in, ',' ); if ( e ) *e = 0; + int ind = atoi( in + 2 ); + if ( e ) *e = ','; + + char *passw = mir_utf8encodeT( info->password ); + size_t passwLen = strlen( passw ); + + mir_sha1_byte_t saltedPassw[ MIR_SHA1_HASH_SIZE ]; + Hi( saltedPassw, passw, passwLen, salt, saltLen, ind ); + + mir_free( salt ); + mir_free( passw ); + + mir_sha1_byte_t clientKey[ MIR_SHA1_HASH_SIZE ]; + hmac_sha1( clientKey, saltedPassw, sizeof( saltedPassw ), (mir_sha1_byte_t*)"Client Key", 10 ); + + mir_sha1_byte_t storedKey[ MIR_SHA1_HASH_SIZE ]; + + mir_sha1_ctx ctx; + mir_sha1_init( &ctx ); + mir_sha1_append( &ctx, clientKey, MIR_SHA1_HASH_SIZE ); + mir_sha1_finish( &ctx, storedKey ); + + char authmsg[4096]; + int authmsgLen = mir_snprintf( authmsg, sizeof( authmsg ), "%s,%s,c=biws,r=%s", msg1, chl, snonce); + + mir_sha1_byte_t clientSig[ MIR_SHA1_HASH_SIZE ]; + hmac_sha1( clientSig, storedKey, sizeof( storedKey ), (mir_sha1_byte_t*)authmsg, authmsgLen); + + mir_sha1_byte_t clientProof[ MIR_SHA1_HASH_SIZE ]; + for (unsigned j = 0; j < sizeof( clientKey ); j++) + clientProof[j] = clientKey[j] ^ clientSig[j]; + + /* Calculate the server signature */ + mir_sha1_byte_t serverKey[ MIR_SHA1_HASH_SIZE ]; + hmac_sha1( serverKey, saltedPassw, sizeof( saltedPassw ), (mir_sha1_byte_t*)"Server Key", 10 ); + + mir_sha1_byte_t srvSig[ MIR_SHA1_HASH_SIZE ]; + hmac_sha1( srvSig, serverKey, sizeof( serverKey ), (mir_sha1_byte_t*)authmsg, authmsgLen); + serverSignature = JabberBase64Encode(( char* )srvSig, sizeof( srvSig )); + + char buf[4096]; + char *encproof = JabberBase64Encode(( char* )clientProof, sizeof( clientProof )); + int cbLen = mir_snprintf( buf, sizeof( buf ), "c=biws,r=%s,p=%s", snonce, encproof ); + + mir_free( encproof ); + mir_free( snonce ); + mir_free( chl ); + + return JabberBase64Encode( buf, cbLen ); +} + +char* TScramAuth::getInitialRequest() +{ + char *uname = mir_utf8encodeT( info->username ), + *serv = mir_utf8encode( info->server ); + + unsigned char nonce[24]; + CallService( MS_UTILS_GETRANDOM, sizeof(nonce), ( LPARAM )nonce ); + cnonce = JabberBase64Encode(( char* )nonce, sizeof( nonce )); + + char buf[4096]; + int cbLen = mir_snprintf( buf, sizeof( buf ), "n,,n=%s@%s,r=%s", uname, serv, cnonce ); + msg1 = mir_strdup( buf + 3 ); + + mir_free( serv ); + mir_free( uname ); + + return JabberBase64Encode( buf, cbLen ); +} + +bool TScramAuth::validateLogin( const TCHAR* challenge ) +{ + int chlLen; + char* chl = JabberBase64DecodeT( challenge, &chlLen ); + bool res = chl && strncmp( chl + 2, serverSignature, chlLen - 2 ) == 0; + mir_free( chl ); + + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// plain auth - the most simple one + +TPlainAuth::TPlainAuth( ThreadData* info, bool old ) : + TJabberAuth( info ) +{ + szName = "PLAIN"; + bOld = old; +} + +TPlainAuth::~TPlainAuth() +{ +} + +char* TPlainAuth::getInitialRequest() +{ + char *uname = mir_utf8encodeT( info->username ), + *passw = mir_utf8encodeT( info->password ); + + size_t size = 2 * strlen( uname ) + strlen( passw ) + strlen( info->server ) + 4; + char *toEncode = ( char* )alloca( size ); + if ( bOld ) + size = mir_snprintf( toEncode, size, "%s@%s%c%s%c%s", uname, info->server, 0, uname, 0, passw ); + else + size = mir_snprintf( toEncode, size, "%c%s%c%s", 0, uname, 0, passw ); + + mir_free( uname ); + mir_free( passw ); + + return JabberBase64Encode( toEncode, (int)size ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// basic type + +TJabberAuth::TJabberAuth( ThreadData* pInfo ) : + bIsValid( true ), + szName( NULL ), + info( pInfo ) +{ +} + +TJabberAuth::~TJabberAuth() +{ +} + +char* TJabberAuth::getInitialRequest() +{ + return NULL; +} + +char* TJabberAuth::getChallenge( const TCHAR* ) +{ + return NULL; +} + +bool TJabberAuth::validateLogin( const TCHAR* ) +{ + return true; +} + diff --git a/protocols/JabberG/src/jabber_secur.h b/protocols/JabberG/src/jabber_secur.h new file mode 100644 index 0000000000..0c3287b88d --- /dev/null +++ b/protocols/JabberG/src/jabber_secur.h @@ -0,0 +1,113 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +// basic class - provides interface for various Jabber auth + +class TJabberAuth +{ + +protected: bool bIsValid; + const char* szName; + unsigned complete; + ThreadData* info; + +public: + TJabberAuth( ThreadData* ); + virtual ~TJabberAuth(); + + virtual char* getInitialRequest(); + virtual char* getChallenge( const TCHAR* challenge ); + virtual bool validateLogin( const TCHAR* challenge ); + + inline const char* getName() const + { return szName; + } + + inline bool isValid() const + { return bIsValid; + } +}; + +// plain auth - the most simple one + +class TPlainAuth : public TJabberAuth +{ + typedef TJabberAuth CSuper; + + bool bOld; + + +public: TPlainAuth( ThreadData*, bool ); + virtual ~TPlainAuth(); + + virtual char* getInitialRequest(); +}; + +// md5 auth - digest-based authorization + +class TMD5Auth : public TJabberAuth +{ + typedef TJabberAuth CSuper; + + int iCallCount; +public: + TMD5Auth( ThreadData* ); + virtual ~TMD5Auth(); + + virtual char* getChallenge( const TCHAR* challenge ); +}; + +class TScramAuth : public TJabberAuth +{ + typedef TJabberAuth CSuper; + + char *cnonce, *msg1, *serverSignature; +public: + TScramAuth( ThreadData* ); + virtual ~TScramAuth(); + + virtual char* getInitialRequest(); + virtual char* getChallenge( const TCHAR* challenge ); + virtual bool validateLogin( const TCHAR* challenge ); + + void Hi( mir_sha1_byte_t* res , char* passw, size_t passwLen, char* salt, size_t saltLen, int ind ); +}; + +// ntlm auth - LanServer based authorization + +class TNtlmAuth : public TJabberAuth +{ + typedef TJabberAuth CSuper; + + HANDLE hProvider; + const TCHAR *szHostName; +public: + TNtlmAuth( ThreadData*, const char* mechanism, const TCHAR* hostname = NULL ); + virtual ~TNtlmAuth(); + + virtual char* getInitialRequest(); + virtual char* getChallenge( const TCHAR* challenge ); + + bool getSpn( TCHAR* szSpn, size_t dwSpnLen ); +}; diff --git a/protocols/JabberG/src/jabber_send_manager.cpp b/protocols/JabberG/src/jabber_send_manager.cpp new file mode 100644 index 0000000000..b37b1d2f09 --- /dev/null +++ b/protocols/JabberG/src/jabber_send_manager.cpp @@ -0,0 +1,51 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_send_manager.h" + +BOOL CJabberSendManager::FillPermanentHandlers() +{ + return TRUE; +} + +BOOL CJabberSendManager::HandleSendPermanent(HXML node, ThreadData *pThreadData) +{ + BOOL bStopHandling = FALSE; + Lock(); + CJabberSendPermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo && !bStopHandling ) { + CJabberSendInfo sendInfo; + sendInfo.m_pUserData = pInfo->m_pUserData; + + if ((ppro->*(pInfo->m_pHandler))(node, pThreadData, &sendInfo)) { + bStopHandling = TRUE; + break; + } + pInfo = pInfo->m_pNext; + } + Unlock(); + + return bStopHandling; +} diff --git a/protocols/JabberG/src/jabber_send_manager.h b/protocols/JabberG/src/jabber_send_manager.h new file mode 100644 index 0000000000..fe4916686f --- /dev/null +++ b/protocols/JabberG/src/jabber_send_manager.h @@ -0,0 +1,195 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007 Maxim Mluhov +Copyright ( C ) 2008-09 Dmitriy Chervov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_SEND_MANAGER_H_ +#define _JABBER_SEND_MANAGER_H_ + +#include "jabber_xml.h" + +struct CJabberProto; +typedef void ( CJabberProto::*JABBER_SEND_PFUNC )( HXML node, void *usedata ); +typedef void ( *SEND_USER_DATA_FREE_FUNC )( void *pUserData ); + +class CJabberSendInfo; + +typedef BOOL ( CJabberProto::*JABBER_SEND_HANDLER )( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ); + +class CJabberSendInfo +{ +protected: + friend class CJabberSendManager; + JABBER_SEND_HANDLER m_pHandler; + CJabberSendInfo* m_pNext; + +public: + void *m_pUserData; + + CJabberSendInfo() + { + ZeroMemory(this, sizeof(*this)); + } + ~CJabberSendInfo() + { + } + void* GetUserData() + { + return m_pUserData; + } +}; + +class CJabberSendPermanentInfo +{ + friend class CJabberSendManager; + + CJabberSendPermanentInfo* m_pNext; + + JABBER_SEND_HANDLER m_pHandler; + void *m_pUserData; + SEND_USER_DATA_FREE_FUNC m_pUserDataFree; + int m_iPriority; +public: + CJabberSendPermanentInfo() + { + ZeroMemory(this, sizeof(CJabberSendPermanentInfo)); + } + ~CJabberSendPermanentInfo() + { + if ( m_pUserDataFree ) + m_pUserDataFree(m_pUserData); + } +}; + +class CJabberSendManager +{ +protected: + CJabberProto* ppro; + CRITICAL_SECTION m_cs; + CJabberSendPermanentInfo* m_pPermanentHandlers; + +public: + CJabberSendManager( CJabberProto* proto ) + { + InitializeCriticalSection(&m_cs); + m_pPermanentHandlers = NULL; + ppro = proto; + } + ~CJabberSendManager() + { + Lock(); + CJabberSendPermanentInfo *pInfo = m_pPermanentHandlers; + while ( pInfo ) + { + CJabberSendPermanentInfo *pTmp = pInfo->m_pNext; + delete pInfo; + pInfo = pTmp; + } + m_pPermanentHandlers = NULL; + Unlock(); + DeleteCriticalSection(&m_cs); + } + BOOL Start() + { + return TRUE; + } + BOOL Shutdown() + { + return TRUE; + } + void Lock() + { + EnterCriticalSection(&m_cs); + } + void Unlock() + { + LeaveCriticalSection(&m_cs); + } + CJabberSendPermanentInfo* AddPermanentHandler(JABBER_SEND_HANDLER pHandler, void *pUserData = NULL, SEND_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) + { + CJabberSendPermanentInfo* pInfo = new CJabberSendPermanentInfo(); + if (!pInfo) + return NULL; + + pInfo->m_pHandler = pHandler; + pInfo->m_pUserData = pUserData; + pInfo->m_pUserDataFree = pUserDataFree; + pInfo->m_iPriority = iPriority; + + Lock(); + if (!m_pPermanentHandlers) + m_pPermanentHandlers = pInfo; + else + { + if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { + pInfo->m_pNext = m_pPermanentHandlers; + m_pPermanentHandlers = pInfo; + } else + { + CJabberSendPermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) + pTmp = pTmp->m_pNext; + pInfo->m_pNext = pTmp->m_pNext; + pTmp->m_pNext = pInfo; + } + } + Unlock(); + + return pInfo; + } + BOOL DeletePermanentHandler(CJabberSendPermanentInfo *pInfo) + { // returns TRUE when pInfo found, or FALSE otherwise + Lock(); + if (!m_pPermanentHandlers) + { + Unlock(); + return FALSE; + } + if (m_pPermanentHandlers == pInfo) // check first item + { + m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } else + { + CJabberSendPermanentInfo* pTmp = m_pPermanentHandlers; + while (pTmp->m_pNext) + { + if (pTmp->m_pNext == pInfo) + { + pTmp->m_pNext = pTmp->m_pNext->m_pNext; + delete pInfo; + Unlock(); + return TRUE; + } + pTmp = pTmp->m_pNext; + } + } + Unlock(); + return FALSE; + } + BOOL HandleSendPermanent(HXML node, ThreadData *pThreadData); + BOOL FillPermanentHandlers(); +}; + +#endif diff --git a/protocols/JabberG/src/jabber_std.cpp b/protocols/JabberG/src/jabber_std.cpp new file mode 100644 index 0000000000..099c28b993 --- /dev/null +++ b/protocols/JabberG/src/jabber_std.cpp @@ -0,0 +1,246 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +void CJabberProto::JCreateService( const char* szService, JServiceFunc serviceProc ) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + ::CreateServiceFunctionObj( str, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this ); +} + +void CJabberProto::JCreateServiceParam( const char* szService, JServiceFuncParam serviceProc, LPARAM lParam ) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + ::CreateServiceFunctionObjParam( str, ( MIRANDASERVICEOBJPARAM )*( void** )&serviceProc, this, lParam ); +} + +void CJabberProto::JHookEvent( const char* szEvent, JEventFunc handler ) +{ + ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&handler, this ); +} + +HANDLE CJabberProto::JCreateHookableEvent( const char* szService ) +{ + char str[ MAXMODULELABELLENGTH ]; + strcpy( str, m_szModuleName ); + strcat( str, szService ); + return CreateHookableEvent( str ); +} + +void CJabberProto::JForkThread( JThreadFunc pFunc, void *param ) +{ + UINT threadID; + CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, &threadID )); +} + +HANDLE CJabberProto::JForkThreadEx( JThreadFunc pFunc, void *param, UINT* threadID ) +{ + UINT lthreadID; + return ( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner ) *( void** )&pFunc, this, param, threadID ? threadID : <hreadID); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CJabberProto::JDeleteSetting( HANDLE hContact, const char* valueName ) +{ + DBDeleteContactSetting( hContact, m_szModuleName, valueName ); +} +/* +DWORD CJabberProto::JGetByte( const char* valueName, int parDefltValue ) +{ + return DBGetContactSettingByte( NULL, m_szModuleName, valueName, parDefltValue ); +} +*/ +DWORD CJabberProto::JGetByte( HANDLE hContact, const char* valueName, int parDefltValue ) +{ + return DBGetContactSettingByte( hContact, m_szModuleName, valueName, parDefltValue ); +} + +char* __stdcall JGetContactName( HANDLE hContact ) +{ + return ( char* )CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact ), 0 ); +} + +DWORD CJabberProto::JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue ) +{ + return DBGetContactSettingDword( hContact, m_szModuleName, valueName, parDefltValue ); +} + +int CJabberProto::JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len ) +{ + DBVARIANT dbv; + dbv.pszVal = dest; + dbv.cchVal = dest_len; + dbv.type = DBVT_ASCIIZ; + + DBCONTACTGETSETTING sVal; + sVal.pValue = &dbv; + sVal.szModule = m_szModuleName; + sVal.szSetting = valueName; + if ( CallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 ) + return 1; + + return ( dbv.type != DBVT_ASCIIZ ); +} + +int CJabberProto::JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv ) +{ + return DBGetContactSettingStringUtf( hContact, m_szModuleName, valueName, dbv ); +} + +int CJabberProto::JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv ) +{ + return DBGetContactSettingTString( hContact, m_szModuleName, valueName, dbv ); +} + +TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName ) +{ + DBVARIANT dbv = {0}; + if (JGetStringT(hContact, valueName, &dbv)) + return NULL; + + TCHAR *res = mir_tstrdup(dbv.ptszVal); + JFreeVariant(&dbv); + return res; +} + +TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName, TCHAR *&out ) +{ + return out = JGetStringT( hContact, valueName ); +} + +TCHAR *CJabberProto::JGetStringT( HANDLE hContact, char* valueName, TCHAR *buf, int size ) +{ + DBVARIANT dbv = {0}; + if (JGetStringT(hContact, valueName, &dbv)) + return NULL; + + lstrcpyn(buf, dbv.ptszVal, size); + JFreeVariant(&dbv); + return buf; +} + +WORD CJabberProto::JGetWord( HANDLE hContact, const char* valueName, int parDefltValue ) +{ + return DBGetContactSettingWord( hContact, m_szModuleName, valueName, parDefltValue ); +} + +void __fastcall JFreeVariant( DBVARIANT* dbv ) +{ + DBFreeVariant( dbv ); +} + +int CJabberProto::JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam ) +{ + // clear saved passowrd on login error. ugly hack, but at least this is centralized + if (type == ACKTYPE_LOGIN && (lParam == LOGINERR_WRONGPASSWORD || lParam == LOGINERR_BADUSERID)) + *m_savedPassword = 0; + + ACKDATA ack = {0}; + ack.cbSize = sizeof( ACKDATA ); + ack.szModule = m_szModuleName; + ack.hContact = hContact; + ack.type = type; + ack.result = result; + ack.hProcess = hProcess; + ack.lParam = lParam; + return CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack ); +} +/* +DWORD CJabberProto::JSetByte( const char* valueName, int parValue ) +{ + return DBWriteContactSettingByte( NULL, m_szModuleName, valueName, parValue ); +} +*/ +DWORD CJabberProto::JSetByte( HANDLE hContact, const char* valueName, int parValue ) +{ + return DBWriteContactSettingByte( hContact, m_szModuleName, valueName, parValue ); +} + +DWORD CJabberProto::JSetDword( HANDLE hContact, const char* valueName, DWORD parValue ) +{ + return DBWriteContactSettingDword( hContact, m_szModuleName, valueName, parValue ); +} + +DWORD CJabberProto::JSetString( HANDLE hContact, const char* valueName, const char* parValue ) +{ + return DBWriteContactSettingString( hContact, m_szModuleName, valueName, parValue ); +} + +DWORD CJabberProto::JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue ) +{ + return DBWriteContactSettingTString( hContact, m_szModuleName, valueName, parValue ); +} + +DWORD CJabberProto::JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue ) +{ + return DBWriteContactSettingStringUtf( hContact, m_szModuleName, valueName, parValue ); +} + +DWORD CJabberProto::JSetWord( HANDLE hContact, const char* valueName, int parValue ) +{ + return DBWriteContactSettingWord( hContact, m_szModuleName, valueName, parValue ); +} + +char* __fastcall JTranslate( const char* str ) +{ + return Translate( str ); +} + +// save/load crypted strings +void __forceinline sttCryptString(char *str) +{ + for (;*str; ++str) + { + const char c = *str ^ 0xc3; + if (c) *str = c; + } +} + +TCHAR* CJabberProto::JGetStringCrypt( HANDLE hContact, char* valueName ) +{ + DBVARIANT dbv; + + if (DBGetContactSettingString( hContact, m_szModuleName, valueName, &dbv )) + return NULL; + + sttCryptString(dbv.pszVal); + WCHAR *res = mir_utf8decodeW(dbv.pszVal); + + + DBFreeVariant(&dbv); + return res; +} + +DWORD CJabberProto::JSetStringCrypt( HANDLE hContact, char* valueName, const TCHAR* parValue ) +{ + char *tmp = mir_utf8encodeT(parValue); + sttCryptString(tmp); + DWORD res = JSetString( hContact, valueName, tmp ); + mir_free(tmp); + return res; +} diff --git a/protocols/JabberG/src/jabber_svc.cpp b/protocols/JabberG/src/jabber_svc.cpp new file mode 100644 index 0000000000..6344751ead --- /dev/null +++ b/protocols/JabberG/src/jabber_svc.cpp @@ -0,0 +1,1138 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#include <fcntl.h> +#include <io.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_caps.h" +#include "m_file.h" +#include "m_addcontact.h" +#include "jabber_disco.h" +#include "m_proto_listeningto.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// GetMyAwayMsg - obtain the current away message + +INT_PTR __cdecl CJabberProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam) +{ + TCHAR *szStatus = NULL; + INT_PTR nRetVal = 0; + + EnterCriticalSection( &m_csModeMsgMutex ); + switch ( wParam ? (int)wParam : m_iStatus ) { + case ID_STATUS_ONLINE: + szStatus = m_modeMsgs.szOnline; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + szStatus = m_modeMsgs.szAway; + break; + case ID_STATUS_NA: + szStatus = m_modeMsgs.szNa; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + szStatus = m_modeMsgs.szDnd; + break; + case ID_STATUS_FREECHAT: + szStatus = m_modeMsgs.szFreechat; + break; + default: + // Should not reach here + break; + } + if ( szStatus ) + nRetVal = ( lParam & SGMA_UNICODE ) ? ( INT_PTR )mir_t2u( szStatus ) : ( INT_PTR )mir_t2a( szStatus ); + LeaveCriticalSection( &m_csModeMsgMutex ); + + return nRetVal; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetAvatar - retrieves the file name of my own avatar + +INT_PTR __cdecl CJabberProto::JabberGetAvatar( WPARAM wParam, LPARAM lParam ) +{ + TCHAR* buf = ( TCHAR* )wParam; + int size = ( int )lParam; + + if ( buf == NULL || size <= 0 ) + return -1; + + if ( !m_options.EnableAvatars ) + return -2; + + GetAvatarFileName( NULL, buf, size ); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetAvatarCaps - returns directives how to process avatars + +INT_PTR __cdecl CJabberProto::JabberGetAvatarCaps( WPARAM wParam, LPARAM lParam ) +{ + switch( wParam ) { + case AF_MAXSIZE: + { + POINT* size = (POINT*)lParam; + if ( size ) + size->x = size->y = 96; + } + return 0; + + case AF_PROPORTION: + return PIP_NONE; + + case AF_FORMATSUPPORTED: // Jabber supports avatars of virtually all formats + return 1; + + case AF_ENABLED: + return m_options.EnableAvatars; + } + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetAvatarInfo - retrieves the avatar info + +INT_PTR __cdecl CJabberProto::JabberGetAvatarInfo( WPARAM wParam, LPARAM lParam ) +{ + if ( !m_options.EnableAvatars ) + return GAIR_NOAVATAR; + + PROTO_AVATAR_INFORMATIONT* AI = ( PROTO_AVATAR_INFORMATIONT* )lParam; + + char szHashValue[ MAX_PATH ]; + if ( JGetStaticString( "AvatarHash", AI->hContact, szHashValue, sizeof szHashValue )) { + Log( "No avatar" ); + return GAIR_NOAVATAR; + } + + TCHAR tszFileName[ MAX_PATH ]; + GetAvatarFileName( AI->hContact, tszFileName, SIZEOF(tszFileName)); + _tcsncpy( AI->filename, tszFileName, SIZEOF(AI->filename)); + + AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : JGetByte( AI->hContact, "AvatarType", 0 ); + + if ( ::_taccess( AI->filename, 0 ) == 0 ) { + char szSavedHash[ 256 ]; + if ( !JGetStaticString( "AvatarSaved", AI->hContact, szSavedHash, sizeof szSavedHash )) { + if ( !strcmp( szSavedHash, szHashValue )) { + Log( "Avatar is Ok: %s == %s", szSavedHash, szHashValue ); + return GAIR_SUCCESS; + } } } + + if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL && m_bJabberOnline ) { + DBVARIANT dbv; + if ( !JGetStringT( AI->hContact, "jid", &dbv )) { + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); + if ( item != NULL ) { + BOOL isXVcard = JGetByte( AI->hContact, "AvatarXVcard", 0 ); + + TCHAR szJid[ JABBER_MAX_JID_LEN ]; + if ( item->resourceCount != NULL && !isXVcard ) { + TCHAR *bestResName = ListGetBestClientResourceNamePtr(dbv.ptszVal); + mir_sntprintf( szJid, SIZEOF( szJid ), bestResName?_T("%s/%s"):_T("%s"), dbv.ptszVal, bestResName ); + } + else lstrcpyn( szJid, dbv.ptszVal, SIZEOF( szJid )); + + Log( "Rereading %s for " TCHAR_STR_PARAM, isXVcard ? JABBER_FEAT_VCARD_TEMP : JABBER_FEAT_AVATAR, szJid ); + + int iqId = SerialNext(); + if ( isXVcard ) + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetVCardAvatar ); + else + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetClientAvatar ); + + XmlNodeIq iq( _T("get"), iqId, szJid ); + if ( isXVcard ) + iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); + else + iq << XQUERY( isXVcard ? _T("") : _T(JABBER_FEAT_AVATAR)); + m_ThreadInfo->send( iq ); + + JFreeVariant( &dbv ); + return GAIR_WAITFOR; + } + JFreeVariant( &dbv ); + } + } + + Log( "No avatar" ); + return GAIR_NOAVATAR; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberGetEventTextChatStates - retrieves a chat state description from an event + +INT_PTR __cdecl CJabberProto::OnGetEventTextChatStates( WPARAM, LPARAM lParam ) +{ + DBEVENTGETTEXT *pdbEvent = ( DBEVENTGETTEXT * )lParam; + + INT_PTR nRetVal = 0; + + if ( pdbEvent->dbei->cbBlob > 0 ) { + if ( pdbEvent->dbei->pBlob[0] == JABBER_DB_EVENT_CHATSTATES_GONE ) { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("closed chat session"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("closed chat session")); + } + } + + return nRetVal; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnGetEventTextPresence - retrieves presence state description from an event + +INT_PTR __cdecl CJabberProto::OnGetEventTextPresence( WPARAM, LPARAM lParam ) +{ + DBEVENTGETTEXT *pdbEvent = ( DBEVENTGETTEXT * )lParam; + + INT_PTR nRetVal = 0; + + if ( pdbEvent->dbei->cbBlob > 0 ) { + switch ( pdbEvent->dbei->pBlob[0] ) + { + case JABBER_DB_EVENT_PRESENCE_SUBSCRIBE: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent subscription request"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("sent subscription request")); + break; + } + case JABBER_DB_EVENT_PRESENCE_SUBSCRIBED: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("approved subscription request"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("approved subscription request")); + break; + } + case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("declined subscription"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("declined subscription")); + break; + } + case JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("declined subscription"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("declined subscription")); + break; + } + case JABBER_DB_EVENT_PRESENCE_ERROR: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent error presence"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("sent error presence")); + break; + } + default: + { + if ( pdbEvent->datatype == DBVT_WCHAR ) + nRetVal = (INT_PTR)mir_tstrdup(TranslateTS(_T("sent unknown presence type"))); + else if ( pdbEvent->datatype == DBVT_ASCIIZ ) + nRetVal = (INT_PTR)mir_strdup(Translate("sent unknown presence type")); + break; + } + } + } + + return nRetVal; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSetAvatar - sets an avatar without UI + +INT_PTR __cdecl CJabberProto::JabberSetAvatar( WPARAM, LPARAM lParam ) +{ + TCHAR* tszFileName = ( TCHAR* )lParam; + + if ( m_bJabberOnline ) { + SetServerVcard( TRUE, tszFileName ); + SendPresence( m_iDesiredStatus, false ); + } + else if ( tszFileName == NULL || tszFileName[0] == 0 ) { + // Remove avatar + TCHAR tFileName[ MAX_PATH ]; + GetAvatarFileName( NULL, tFileName, MAX_PATH ); + DeleteFile( tFileName ); + + JDeleteSetting( NULL, "AvatarSaved" ); + JDeleteSetting( NULL, "AvatarHash" ); + } + else { + int fileIn = _topen( tszFileName, O_RDWR | O_BINARY, S_IREAD | S_IWRITE ); + if ( fileIn == -1 ) { + mir_free(tszFileName); + return 1; + } + + long dwPngSize = _filelength( fileIn ); + char* pResult = new char[ dwPngSize ]; + if ( pResult == NULL ) { + _close( fileIn ); + mir_free(tszFileName); + return 2; + } + + _read( fileIn, pResult, dwPngSize ); + _close( fileIn ); + + mir_sha1_byte_t digest[MIR_SHA1_HASH_SIZE]; + mir_sha1_ctx sha1ctx; + mir_sha1_init( &sha1ctx ); + mir_sha1_append( &sha1ctx, (mir_sha1_byte_t*)pResult, dwPngSize ); + mir_sha1_finish( &sha1ctx, digest ); + + TCHAR tFileName[ MAX_PATH ]; + GetAvatarFileName( NULL, tFileName, MAX_PATH ); + DeleteFile( tFileName ); + + char buf[MIR_SHA1_HASH_SIZE*2+1]; + for ( int i=0; i<MIR_SHA1_HASH_SIZE; i++ ) + sprintf( buf+( i<<1 ), "%02x", digest[i] ); + + m_options.AvatarType = JabberGetPictureType( pResult ); + + GetAvatarFileName( NULL, tFileName, MAX_PATH ); + FILE* out = _tfopen( tFileName, _T("wb")); + if ( out != NULL ) { + fwrite( pResult, dwPngSize, 1, out ); + fclose( out ); + } + delete[] pResult; + + JSetString( NULL, "AvatarSaved", buf ); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// JabberSetNickname - sets the user nickname without UI + +INT_PTR __cdecl CJabberProto::JabberSetNickname( WPARAM wParam, LPARAM lParam ) +{ + TCHAR *nickname = ( wParam & SMNN_UNICODE ) ? mir_u2t( (WCHAR *) lParam ) : mir_a2t( (char *) lParam ); + + JSetStringT( NULL, "Nick", nickname ); + SetServerVcard( FALSE, _T("")); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// "/SendXML" - Allows external plugins to send XML to the server + +INT_PTR __cdecl CJabberProto::ServiceSendXML( WPARAM, LPARAM lParam ) +{ + return m_ThreadInfo->send( (char*)lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// "/GCGetToolTipText" - gets tooltip text + +static const TCHAR * JabberEnum2AffilationStr[]={ _T("None"), _T("Outcast"), _T("Member"), _T("Admin"), _T("Owner") }; +static const TCHAR * JabberEnum2RoleStr[]={ _T("None"), _T("Visitor"), _T("Participant"), _T("Moderator") }; + +//FIXME Table conversion fast but is not safe +static const TCHAR * JabberEnum2StatusStr[]= { _T("Offline"), _T("Online"), _T("Away"), _T("DND"), + _T("NA"), _T("Occupied"), _T("Free for chat"), + _T("Invisible"), _T("On the phone"), _T("Out to lunch"), + _T("Idle") }; + +static void appendString( bool bIsTipper, const TCHAR* tszTitle, const TCHAR* tszValue, TCHAR* buf, size_t bufSize ) +{ + if ( *buf ) { + const TCHAR* szSeparator = (bIsTipper) ? _T("\n") : ((IsWinVerMEPlus()) ? _T("\r\n") : _T(" | ")); + _tcsncat( buf, szSeparator, bufSize ); + } + + size_t len = _tcslen(buf); + buf += len; + bufSize -= len; + + if ( bIsTipper ) + mir_sntprintf(buf, bufSize, _T("%s%s%s%s"), _T("<b>"), TranslateTS(tszTitle), _T("</b>\t"), tszValue); + else { + TCHAR* p = TranslateTS(tszTitle); + mir_sntprintf(buf, bufSize, _T("%s%s\t%s"), p, _tcslen(p)<=7 ? _T("\t") : _T(""), tszValue); + } +} + +INT_PTR __cdecl CJabberProto::JabberGCGetToolTipText( WPARAM wParam, LPARAM lParam ) +{ + if ( !wParam || !lParam ) + return 0; //room global tooltip not supported yet + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, (TCHAR*)wParam); + if ( item == NULL ) + return 0; //no room found + + JABBER_RESOURCE_STATUS * info = NULL; + for ( int i=0; i < item->resourceCount; i++ ) { + JABBER_RESOURCE_STATUS& p = item->resource[i]; + if ( !lstrcmp( p.resourceName, (TCHAR*)lParam )) { + info = &p; + break; + } } + + if ( info == NULL ) + return 0; //no info found + + // ok process info output will be: + // JID: real@jid/resource or + // Nick: Nickname + // Status: StatusText + // Role: Moderator + // Affiliation: Affiliation + + TCHAR outBuf[2048]; + outBuf[0]=_T('\0'); + + bool bIsTipper = DBGetContactSettingByte(NULL, "Tab_SRMsg", "adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip"); + + //JID: + if ( _tcschr(info->resourceName, _T('@')) != NULL ) + appendString(bIsTipper, _T("JID:"), info->resourceName, outBuf, SIZEOF(outBuf)); + else if (lParam) { //or simple nick + appendString(bIsTipper, _T("Nick:"), (TCHAR*) lParam, outBuf, SIZEOF(outBuf)); + } + + // status + if ( info->status >= ID_STATUS_OFFLINE && info->status <= ID_STATUS_IDLE ) + appendString(bIsTipper, _T("Status:"), TranslateTS(JabberEnum2StatusStr[info->status-ID_STATUS_OFFLINE]), outBuf, SIZEOF(outBuf)); + + // status text + if ( info->statusMessage ) + appendString(bIsTipper, _T("Status text:"), info->statusMessage, outBuf, SIZEOF(outBuf)); + + // Role + appendString(bIsTipper, _T("Role:"), TranslateTS(JabberEnum2RoleStr[info->role]), outBuf, SIZEOF(outBuf)); + + // Affiliation + appendString(bIsTipper, _T("Affiliation:"), TranslateTS(JabberEnum2AffilationStr[info->affiliation]), outBuf, SIZEOF(outBuf)); + + // real jid + if ( info->szRealJid ) + appendString(bIsTipper, _T("Real JID:"), info->szRealJid, outBuf, SIZEOF(outBuf)); + + return (INT_PTR)( outBuf[0] == 0 ? NULL : mir_tstrdup( outBuf )); +} + +// File Association Manager plugin support + +INT_PTR __cdecl CJabberProto::JabberServiceParseXmppURI( WPARAM wParam, LPARAM lParam ) +{ + UNREFERENCED_PARAMETER( wParam ); + + TCHAR *arg = ( TCHAR * )lParam; + if ( arg == NULL ) + return 1; + + TCHAR szUri[ 1024 ]; + mir_sntprintf( szUri, SIZEOF(szUri), _T("%s"), arg ); + + TCHAR *szJid = szUri; + + // skip leading prefix + szJid = _tcschr( szJid, _T( ':' )); + if ( szJid == NULL ) + return 1; + + // skip // + for ( ++szJid; *szJid == _T( '/' ); ++szJid ); + + // empty jid? + if ( !*szJid ) + return 1; + + // command code + TCHAR *szCommand = szJid; + szCommand = _tcschr( szCommand, _T( '?' )); + if ( szCommand ) + *( szCommand++ ) = 0; + + // parameters + TCHAR *szSecondParam = szCommand ? _tcschr( szCommand, _T( ';' )) : NULL; + if ( szSecondParam ) + *( szSecondParam++ ) = 0; + +// TCHAR *szThirdParam = szSecondParam ? _tcschr( szSecondParam, _T( ';' )) : NULL; +// if ( szThirdParam ) +// *( szThirdParam++ ) = 0; + + // no command or message command + if ( !szCommand || ( szCommand && !_tcsicmp( szCommand, _T( "message" )))) { + // message + if ( ServiceExists( MS_MSG_SENDMESSAGE )) { + HANDLE hContact = HContactFromJID( szJid, TRUE ); + TCHAR *szMsgBody = NULL; + if ( !hContact ) + hContact = DBCreateContact( szJid, szJid, TRUE, TRUE ); + if ( !hContact ) + return 1; + + if ( szSecondParam ) { //there are parameters to message + szMsgBody = _tcsstr(szSecondParam, _T( "body=" )); + if ( szMsgBody ) { + szMsgBody += 5; + TCHAR* szDelim = _tcschr( szMsgBody, _T( ';' )); + if ( szDelim ) + szDelim = 0; + JabberHttpUrlDecode( szMsgBody ); + } } + + CallService(MS_MSG_SENDMESSAGE "W",(WPARAM)hContact, (LPARAM)szMsgBody); + + return 0; + } + return 1; + } + else if ( !_tcsicmp( szCommand, _T( "roster" ))) + { + if ( !HContactFromJID( szJid )) { + JABBER_SEARCH_RESULT jsr = { 0 }; + jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); + jsr.hdr.flags = PSR_TCHAR; + jsr.hdr.nick = szJid; + jsr.hdr.id = szJid; + _tcsncpy( jsr.jid, szJid, SIZEOF(jsr.jid) - 1 ); + + ADDCONTACTSTRUCT acs; + acs.handleType = HANDLE_SEARCHRESULT; + acs.szProto = m_szModuleName; + acs.psr = &jsr.hdr; + CallService( MS_ADDCONTACT_SHOW, (WPARAM)NULL, (LPARAM)&acs ); + } + return 0; + } + else if ( !_tcsicmp( szCommand, _T( "join" ))) + { + // chat join invitation + GroupchatJoinRoomByJid( NULL, szJid ); + return 0; + } + else if ( !_tcsicmp( szCommand, _T( "disco" ))) + { + // service discovery request + OnMenuHandleServiceDiscovery( 0, ( LPARAM )szJid ); + return 0; + } + else if ( !_tcsicmp( szCommand, _T( "command" ))) + { + // ad-hoc commands + if ( szSecondParam ) { + if ( !_tcsnicmp( szSecondParam, _T( "node=" ), 5 )) { + szSecondParam += 5; + if (!*szSecondParam) + szSecondParam = NULL; + } + else + szSecondParam = NULL; + } + CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams( this, szJid, szSecondParam ); + ContactMenuRunCommands( 0, ( LPARAM )pStartupParams ); + return 0; + } + else if ( !_tcsicmp( szCommand, _T( "sendfile" ))) + { + // send file + if ( ServiceExists( MS_FILE_SENDFILE )) { + HANDLE hContact = HContactFromJID( szJid, TRUE ); + if ( !hContact ) + hContact = DBCreateContact( szJid, szJid, TRUE, TRUE ); + if ( !hContact ) + return 1; + CallService( MS_FILE_SENDFILE, ( WPARAM )hContact, ( LPARAM )NULL ); + return 0; + } + return 1; + } + + return 1; /* parse failed */ +} + +// XEP-0224 support (Attention/Nudge) +INT_PTR __cdecl CJabberProto::JabberSendNudge( WPARAM wParam, LPARAM ) +{ + if ( !m_bJabberOnline ) + return 0; + + HANDLE hContact = ( HANDLE )wParam; + DBVARIANT dbv; + if ( !JGetStringT( hContact, "jid", &dbv )) { + TCHAR tszJid[ JABBER_MAX_JID_LEN ]; + TCHAR *szResource = ListGetBestClientResourceNamePtr( dbv.ptszVal ); + if ( szResource ) + mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), dbv.ptszVal, szResource ); + else + mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s"), dbv.ptszVal ); + JFreeVariant( &dbv ); + + JabberCapsBits jcb = GetResourceCapabilites( tszJid, FALSE ); + + m_ThreadInfo->send( + XmlNode( _T("message")) << XATTR( _T("type"), _T("headline")) << XATTR( _T("to"), tszJid ) + << XCHILDNS( _T("attention"), + jcb & JABBER_CAPS_ATTENTION ? _T(JABBER_FEAT_ATTENTION) : _T(JABBER_FEAT_ATTENTION_0 ))); + } + return 0; +} + +BOOL CJabberProto::SendHttpAuthReply( CJabberHttpAuthParams *pParams, BOOL bAuthorized ) +{ + if ( !m_bJabberOnline || !pParams || !m_ThreadInfo ) + return FALSE; + + if ( pParams->m_nType == CJabberHttpAuthParams::IQ ) { + XmlNodeIq iq( bAuthorized ? _T("result") : _T("error"), pParams->m_szIqId, pParams->m_szFrom ); + if ( !bAuthorized ) { + iq << XCHILDNS( _T("confirm"), _T(JABBER_FEAT_HTTP_AUTH)) << XATTR( _T("id"), pParams->m_szId ) + << XATTR( _T("method"), pParams->m_szMethod ) << XATTR( _T("url"), pParams->m_szUrl ); + iq << XCHILD( _T("error")) << XATTRI( _T("code"), 401 ) << XATTR( _T("type"), _T("auth")) + << XCHILDNS( _T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); + } + m_ThreadInfo->send( iq ); + } + else if ( pParams->m_nType == CJabberHttpAuthParams::MSG ) { + XmlNode msg( _T("message")); + msg << XATTR( _T("to"), pParams->m_szFrom ); + if ( !bAuthorized ) + msg << XATTR( _T("type"), _T("error")); + if ( pParams->m_szThreadId ) + msg << XCHILD( _T("thread"), pParams->m_szThreadId ); + + msg << XCHILDNS( _T("confirm"), _T(JABBER_FEAT_HTTP_AUTH)) << XATTR( _T("id"), pParams->m_szId ) + << XATTR( _T("method"), pParams->m_szMethod ) << XATTR( _T("url"), pParams->m_szUrl ); + + if ( !bAuthorized ) + msg << XCHILD( _T("error")) << XATTRI( _T("code"), 401 ) << XATTR( _T("type"), _T("auth")) + << XCHILDNS( _T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); + + m_ThreadInfo->send( msg ); + } + else + return FALSE; + + + return TRUE; +} + +class CJabberDlgHttpAuth: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + +public: + CJabberDlgHttpAuth(CJabberProto *proto, HWND hwndParent, CJabberHttpAuthParams *pParams): + CSuper(proto, IDD_HTTP_AUTH, hwndParent, true), + m_txtInfo(this, IDC_EDIT_HTTP_AUTH_INFO), + m_btnAuth(this, IDOK), + m_btnDeny(this, IDCANCEL), + m_pParams(pParams) + { + m_btnAuth.OnClick = Callback( this, &CJabberDlgHttpAuth::btnAuth_OnClick ); + m_btnDeny.OnClick = Callback( this, &CJabberDlgHttpAuth::btnDeny_OnClick ); + } + + void OnInitDialog() + { + CSuper::OnInitDialog(); + + WindowSetIcon( m_hwnd, m_proto, "openid" ); + + SetDlgItemText(m_hwnd, IDC_TXT_URL, m_pParams->m_szUrl); + SetDlgItemText(m_hwnd, IDC_TXT_FROM, m_pParams->m_szFrom); + SetDlgItemText(m_hwnd, IDC_TXT_ID, m_pParams->m_szId); + SetDlgItemText(m_hwnd, IDC_TXT_METHOD, m_pParams->m_szMethod); + } + + BOOL SendReply( BOOL bAuthorized ) + { + BOOL bRetVal = m_proto->SendHttpAuthReply( m_pParams, bAuthorized ); + m_pParams->Free(); + mir_free( m_pParams ); + m_pParams = NULL; + return bRetVal; + } + + void btnAuth_OnClick(CCtrlButton*) + { + SendReply( TRUE ); + Close(); + } + void btnDeny_OnClick(CCtrlButton*) + { + SendReply( FALSE ); + Close(); + } + + UI_MESSAGE_MAP(CJabberDlgHttpAuth, CSuper); + UI_MESSAGE(WM_CTLCOLORSTATIC, OnCtlColorStatic); + UI_MESSAGE_MAP_END(); + + INT_PTR OnCtlColorStatic(UINT, WPARAM, LPARAM) + { + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + +private: + CCtrlEdit m_txtInfo; + CCtrlButton m_btnAuth; + CCtrlButton m_btnDeny; + + CJabberHttpAuthParams *m_pParams; +}; + +// XEP-0070 support (http auth) +INT_PTR __cdecl CJabberProto::OnHttpAuthRequest( WPARAM wParam, LPARAM lParam ) +{ + CLISTEVENT *pCle = (CLISTEVENT *)lParam; + CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)pCle->lParam; + if ( !pParams ) + return 0; + + CJabberDlgHttpAuth *pDlg = new CJabberDlgHttpAuth( this, (HWND)wParam, pParams ); + if ( !pDlg ) { + pParams->Free(); + mir_free( pParams ); + return 0; + } + + pDlg->Show(); + + return 0; +} + + +// Jabber API functions +INT_PTR __cdecl CJabberProto::JabberGetApi( WPARAM wParam, LPARAM lParam ) +{ + IJabberInterface **ji = (IJabberInterface**)lParam; + if ( !ji ) + return -1; + *ji = &m_JabberApi; + return 0; +} + +DWORD CJabberInterface::GetFlags() const +{ + return JIF_UNICODE; +} + +int CJabberInterface::GetVersion() const +{ + return 1; +} + +DWORD CJabberInterface::GetJabberVersion() const +{ + return __VERSION_DWORD; +} + +IJabberSysInterface *CJabberInterface::Sys() const +{ + return &m_psProto->m_JabberSysApi; +} + +IJabberNetInterface *CJabberInterface::Net() const +{ + return &m_psProto->m_JabberNetApi; +} + +int CJabberSysInterface::GetVersion() const +{ + return 1; +} + +int CJabberSysInterface::CompareJIDs( LPCTSTR jid1, LPCTSTR jid2 ) +{ + if ( !jid1 || !jid2 ) return 0; + return JabberCompareJids( jid1, jid2 ); +} + +HANDLE CJabberSysInterface::ContactFromJID( LPCTSTR jid ) +{ + if ( !jid ) return NULL; + return m_psProto->HContactFromJID( jid ); +} + +LPTSTR CJabberSysInterface::ContactToJID( HANDLE hContact ) +{ + return m_psProto->JGetStringT( hContact, m_psProto->JGetByte( hContact, "ChatRoom", 0 ) ? "ChatRoomID" : "jid" ); +} + +LPTSTR CJabberSysInterface::GetBestResourceName( LPCTSTR jid ) +{ + if ( jid == NULL ) + return NULL; + LPCTSTR p = _tcschr( jid, '/' ); + if ( p == NULL ) { + m_psProto->ListLock(); // make sure we allow access to the list only after making mir_tstrdup() of resource name + LPTSTR res = mir_tstrdup( m_psProto->ListGetBestClientResourceNamePtr( jid )); + m_psProto->ListUnlock(); + return res; + } + return mir_tstrdup( jid ); +} + +LPTSTR CJabberSysInterface::GetResourceList( LPCTSTR jid ) +{ + if ( !jid ) + return NULL; + + m_psProto->ListLock(); + JABBER_LIST_ITEM *item = NULL; + if (( item = m_psProto->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) + item = m_psProto->ListGetItemPtr( LIST_ROSTER, jid ); + if ( item == NULL ) { + m_psProto->ListUnlock(); + return NULL; + } + + if ( item->resource == NULL ) { + m_psProto->ListUnlock(); + return NULL; + } + + int i; + int iLen = 1; // 1 for extra zero terminator at the end of the string + // calculate total necessary string length + for ( i=0; i<item->resourceCount; i++ ) { + iLen += lstrlen(item->resource[i].resourceName) + 1; + } + + // allocate memory and fill it + LPTSTR str = (LPTSTR)mir_alloc(iLen * sizeof(TCHAR)); + LPTSTR p = str; + for ( i=0; i<item->resourceCount; i++ ) { + lstrcpy(p, item->resource[i].resourceName); + p += lstrlen(item->resource[i].resourceName) + 1; + } + *p = 0; // extra zero terminator + + m_psProto->ListUnlock(); + return str; +} + +char *CJabberSysInterface::GetModuleName() const +{ + return m_psProto->m_szModuleName; +} + +int CJabberNetInterface::GetVersion() const +{ + return 1; +} + +unsigned int CJabberNetInterface::SerialNext() +{ + return m_psProto->SerialNext(); +} + +int CJabberNetInterface::SendXmlNode( HXML node ) +{ + return m_psProto->m_ThreadInfo->send(node); +} + + +typedef struct +{ + JABBER_HANDLER_FUNC Func; + void *pUserData; +} sHandlerData; + +void CJabberProto::ExternalTempIqHandler( HXML node, CJabberIqInfo *pInfo ) +{ + sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); + d->Func(&m_JabberApi, node, d->pUserData); + free(d); // free IqHandlerData allocated in CJabberNetInterface::AddIqHandler below +} + +BOOL CJabberProto::ExternalIqHandler( HXML node, CJabberIqInfo *pInfo ) +{ + sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); + return d->Func(&m_JabberApi, node, d->pUserData); +} + +BOOL CJabberProto::ExternalMessageHandler( HXML node, ThreadData *pThreadData, CJabberMessageInfo* pInfo ) +{ + sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); + return d->Func(&m_JabberApi, node, d->pUserData); +} + +BOOL CJabberProto::ExternalPresenceHandler( HXML node, ThreadData *pThreadData, CJabberPresenceInfo* pInfo ) +{ + sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); + return d->Func(&m_JabberApi, node, d->pUserData); +} + +BOOL CJabberProto::ExternalSendHandler( HXML node, ThreadData *pThreadData, CJabberSendInfo* pInfo ) +{ + sHandlerData *d = (sHandlerData*)pInfo->GetUserData(); + return d->Func(&m_JabberApi, node, d->pUserData); +} + +HJHANDLER CJabberNetInterface::AddPresenceHandler( JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority ) +{ + sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); + d->Func = Func; + d->pUserData = pUserData; + return (HJHANDLER)m_psProto->m_presenceManager.AddPermanentHandler( &CJabberProto::ExternalPresenceHandler, d, free, iPriority ); +} + +HJHANDLER CJabberNetInterface::AddMessageHandler( JABBER_HANDLER_FUNC Func, int iMsgTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority ) +{ + sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); + d->Func = Func; + d->pUserData = pUserData; + return (HJHANDLER)m_psProto->m_messageManager.AddPermanentHandler( &CJabberProto::ExternalMessageHandler, iMsgTypes, 0, szXmlns, FALSE, szTag, d, free, iPriority ); +} + +HJHANDLER CJabberNetInterface::AddIqHandler( JABBER_HANDLER_FUNC Func, int iIqTypes, LPCTSTR szXmlns, LPCTSTR szTag, void *pUserData, int iPriority ) +{ + sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); + d->Func = Func; + d->pUserData = pUserData; + return (HJHANDLER)m_psProto->m_iqManager.AddPermanentHandler( &CJabberProto::ExternalIqHandler, iIqTypes, 0, szXmlns, FALSE, szTag, d, free, iPriority ); +} + +HJHANDLER CJabberNetInterface::AddTemporaryIqHandler( JABBER_HANDLER_FUNC Func, int iIqTypes, int iIqId, void *pUserData, DWORD dwTimeout, int iPriority ) +{ + sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); + d->Func = Func; + d->pUserData = pUserData; + CJabberIqInfo* pInfo = m_psProto->m_iqManager.AddHandler( &CJabberProto::ExternalTempIqHandler, iIqTypes, NULL, 0, iIqId, d, iPriority ); + if ( pInfo && dwTimeout > 0 ) + pInfo->SetTimeout( dwTimeout ); + return (HJHANDLER)pInfo; +} + +HJHANDLER CJabberNetInterface::AddSendHandler( JABBER_HANDLER_FUNC Func, void *pUserData, int iPriority ) +{ + sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData)); + d->Func = Func; + d->pUserData = pUserData; + return (HJHANDLER)m_psProto->m_sendManager.AddPermanentHandler( &CJabberProto::ExternalSendHandler, d, free, iPriority ); +} + +int CJabberNetInterface::RemoveHandler( HJHANDLER hHandler ) +{ + return m_psProto->m_sendManager.DeletePermanentHandler( (CJabberSendPermanentInfo*)hHandler ) || + m_psProto->m_presenceManager.DeletePermanentHandler( (CJabberPresencePermanentInfo*)hHandler ) || + m_psProto->m_messageManager.DeletePermanentHandler( (CJabberMessagePermanentInfo*)hHandler ) || + m_psProto->m_iqManager.DeletePermanentHandler( (CJabberIqPermanentInfo*)hHandler ) || + m_psProto->m_iqManager.DeleteHandler( (CJabberIqInfo*)hHandler ); +} + +JabberFeatCapPairDynamic *CJabberNetInterface::FindFeature(LPCTSTR szFeature) +{ + int i; + for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) + if ( !lstrcmp( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature, szFeature )) + return m_psProto->m_lstJabberFeatCapPairsDynamic[i]; + return NULL; +} + +int CJabberNetInterface::RegisterFeature( LPCTSTR szFeature, LPCTSTR szDescription ) +{ + if ( !szFeature ) { + return false; + } + + // check for this feature in core features, and return false if it's present, to prevent re-registering a core feature + int i; + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) + { + if ( !lstrcmp( g_JabberFeatCapPairs[i].szFeature, szFeature )) + { + return false; + } + } + + m_psProto->ListLock(); + JabberFeatCapPairDynamic *fcp = FindFeature( szFeature ); + if ( !fcp ) { + // if the feature is not registered yet, allocate new bit for it + JabberCapsBits jcb = JABBER_CAPS_OTHER_SPECIAL; // set all bits not included in g_JabberFeatCapPairs + + // set all bits occupied by g_JabberFeatCapPairs + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) + jcb |= g_JabberFeatCapPairs[i].jcbCap; + + // set all bits already occupied by external plugins + for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) + jcb |= m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap; + + // Now get first zero bit. The line below is a fast way to do it. If there are no zero bits, it returns 0. + jcb = (~jcb) & (JabberCapsBits)(-(__int64)(~jcb)); + + if ( !jcb ) { + // no more free bits + m_psProto->ListUnlock(); + return false; + } + + LPTSTR szExt = mir_tstrdup( szFeature ); + LPTSTR pSrc, pDst; + for ( pSrc = szExt, pDst = szExt; *pSrc; pSrc++ ) { + // remove unnecessary symbols from szFeature to make the string shorter, and use it as szExt + if ( _tcschr( _T("bcdfghjklmnpqrstvwxz0123456789"), *pSrc )) { + *pDst++ = *pSrc; + } + } + *pDst = 0; + m_psProto->m_clientCapsManager.SetClientCaps( _T(JABBER_CAPS_MIRANDA_NODE), szExt, jcb ); + + fcp = new JabberFeatCapPairDynamic(); + fcp->szExt = szExt; // will be deallocated along with other values of JabberFeatCapPairDynamic in CJabberProto destructor + fcp->szFeature = mir_tstrdup( szFeature ); + fcp->szDescription = szDescription ? mir_tstrdup( szDescription ) : NULL; + fcp->jcbCap = jcb; + m_psProto->m_lstJabberFeatCapPairsDynamic.insert( fcp ); + } else if ( szDescription ) { + // update description + if ( fcp->szDescription ) + mir_free( fcp->szDescription ); + fcp->szDescription = mir_tstrdup( szDescription ); + } + m_psProto->ListUnlock(); + return true; +} + +int CJabberNetInterface::AddFeatures( LPCTSTR szFeatures ) +{ + if ( !szFeatures ) { + return false; + } + + m_psProto->ListLock(); + BOOL ret = true; + LPCTSTR szFeat = szFeatures; + while ( szFeat[0] ) { + JabberFeatCapPairDynamic *fcp = FindFeature( szFeat ); + // if someone is trying to add one of core features, RegisterFeature() will return false, so we don't have to perform this check here + if ( !fcp ) { + // if the feature is not registered yet + if ( !RegisterFeature( szFeat, NULL )) { + ret = false; + } else { + fcp = FindFeature( szFeat ); // update fcp after RegisterFeature() + } + } + if ( fcp ) { + m_psProto->m_uEnabledFeatCapsDynamic |= fcp->jcbCap; + } else { + ret = false; + } + szFeat += lstrlen( szFeat ) + 1; + } + m_psProto->ListUnlock(); + + if ( m_psProto->m_bJabberOnline ) { + m_psProto->SendPresence( m_psProto->m_iStatus, true ); + } + return ret; +} + +int CJabberNetInterface::RemoveFeatures( LPCTSTR szFeatures ) +{ + if ( !szFeatures ) { + return false; + } + + m_psProto->ListLock(); + BOOL ret = true; + LPCTSTR szFeat = szFeatures; + while ( szFeat[0] ) { + JabberFeatCapPairDynamic *fcp = FindFeature( szFeat ); + if ( fcp ) { + m_psProto->m_uEnabledFeatCapsDynamic &= ~fcp->jcbCap; + } else { + ret = false; // indicate that there was an error removing at least one of the specified features + } + szFeat += lstrlen( szFeat ) + 1; + } + m_psProto->ListUnlock(); + + if ( m_psProto->m_bJabberOnline ) { + m_psProto->SendPresence( m_psProto->m_iStatus, true ); + } + return ret; +} + +LPTSTR CJabberNetInterface::GetResourceFeatures( LPCTSTR jid ) +{ + JabberCapsBits jcb = m_psProto->GetResourceCapabilites( jid, true ); + if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) { + m_psProto->ListLock(); // contents of m_lstJabberFeatCapPairsDynamic must not change from the moment we calculate total length and to the moment when we fill the string + int i; + int iLen = 1; // 1 for extra zero terminator at the end of the string + // calculate total necessary string length + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) { + if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { + iLen += lstrlen( g_JabberFeatCapPairs[i].szFeature ) + 1; + } + } + for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { + if ( jcb & m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { + iLen += lstrlen( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ) + 1; + } + } + + // allocate memory and fill it + LPTSTR str = (LPTSTR)mir_alloc( iLen * sizeof(TCHAR)); + LPTSTR p = str; + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) { + if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { + lstrcpy( p, g_JabberFeatCapPairs[i].szFeature ); + p += lstrlen( g_JabberFeatCapPairs[i].szFeature ) + 1; + } + } + for ( i = 0; i < m_psProto->m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { + if ( jcb & m_psProto->m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { + lstrcpy( p, m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ); + p += lstrlen( m_psProto->m_lstJabberFeatCapPairsDynamic[i]->szFeature ) + 1; + } + } + *p = 0; // extra zero terminator + m_psProto->ListUnlock(); + return str; + } + return NULL; +} diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp new file mode 100644 index 0000000000..d71fd2ab60 --- /dev/null +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -0,0 +1,2160 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#include <windns.h> // requires Windows Platform SDK + +#include "jabber_list.h" +#include "jabber_iq.h" +#include "jabber_secur.h" +#include "jabber_caps.h" +#include "jabber_privacy.h" +#include "jabber_rc.h" +#include "jabber_proto.h" + +#ifndef DNS_TYPE_SRV +#define DNS_TYPE_SRV 0x0021 +#endif + +// <iq/> identification number for various actions +// for JABBER_REGISTER thread +int iqIdRegGetReg; +int iqIdRegSetReg; + +// XML Console +#define JCPF_IN 0x01UL +#define JCPF_OUT 0x02UL +#define JCPF_ERROR 0x04UL + +//extern int bSecureIM; +static VOID CALLBACK JabberDummyApcFunc( DWORD_PTR ) +{ + return; +} + +struct JabberPasswordDlgParam +{ + CJabberProto* pro; + + BOOL saveOnlinePassword; + WORD dlgResult; + TCHAR onlinePassword[128]; + HANDLE hEventPasswdDlg; + TCHAR* ptszJid; +}; + +static INT_PTR CALLBACK JabberPasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JabberPasswordDlgParam* param = (JabberPasswordDlgParam*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + { + param = (JabberPasswordDlgParam*)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + TCHAR text[512]; + mir_sntprintf( text, SIZEOF(text), _T("%s %s"), TranslateT( "Enter password for" ), ( TCHAR* )param->ptszJid ); + SetDlgItemText( hwndDlg, IDC_JID, text ); + + int bSavePassword = param->pro->JGetByte( NULL, "SaveSessionPassword", 0 ); + CheckDlgButton( hwndDlg, IDC_SAVEPASSWORD, ( bSavePassword ) ? BST_CHECKED : BST_UNCHECKED ); + } + return TRUE; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + param->saveOnlinePassword = IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD ); + param->pro->JSetByte( NULL, "SaveSessionPassword", param->saveOnlinePassword ); + + GetDlgItemText( hwndDlg, IDC_PASSWORD, param->onlinePassword, SIZEOF( param->onlinePassword )); + // Fall through + case IDCANCEL: + param->dlgResult = LOWORD( wParam ); + SetEvent( param->hEventPasswdDlg ); + DestroyWindow( hwndDlg ); + return TRUE; + } + break; + } + + return FALSE; +} + +static VOID CALLBACK JabberPasswordCreateDialogApcProc( void* param ) +{ + CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_PASSWORD ), NULL, JabberPasswordDlgProc, ( LPARAM )param ); +} + +static VOID CALLBACK JabberOfflineChatWindows( void* param ) +{ + CJabberProto* ppro = ( CJabberProto* )param; + GCDEST gcd = { ppro->m_szModuleName, NULL, GC_EVENT_CONTROL }; + GCEVENT gce = { 0 }; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + CallService( MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Jabber keep-alive thread + +void CJabberProto::OnPingReply( HXML, CJabberIqInfo* pInfo ) +{ + if ( !pInfo ) + return; + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_FAIL ) { + // disconnect because of timeout + m_ThreadInfo->send( "</stream:stream>" ); + m_ThreadInfo->shutdown(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +typedef DNS_STATUS (WINAPI *DNSQUERYA)(IN PCSTR pszName, IN WORD wType, IN DWORD Options, IN PIP4_ARRAY aipServers OPTIONAL, IN OUT PDNS_RECORDA *ppQueryResults OPTIONAL, IN OUT PVOID *pReserved OPTIONAL); +typedef void (WINAPI *DNSFREELIST)(IN OUT PDNS_RECORDA pRecordList, IN DNS_FREE_TYPE FreeType); + +static int CompareDNS(const DNS_SRV_DATAA* dns1, const DNS_SRV_DATAA* dns2) +{ + return (int)dns1->wPriority - (int)dns2->wPriority; +} + +void ThreadData::xmpp_client_query( void ) +{ + if (inet_addr(server) != INADDR_NONE) + return; + + HMODULE hDnsapi = LoadLibraryA( "dnsapi.dll" ); + if ( hDnsapi == NULL ) + return; + + DNSQUERYA pDnsQuery = (DNSQUERYA)GetProcAddress(hDnsapi, "DnsQuery_A"); + DNSFREELIST pDnsRecordListFree = (DNSFREELIST)GetProcAddress(hDnsapi, "DnsRecordListFree"); + if ( pDnsQuery == NULL ) { + //dnsapi.dll is not the needed dnsapi ;) + FreeLibrary( hDnsapi ); + return; + } + + char temp[256]; + mir_snprintf( temp, SIZEOF(temp), "_xmpp-client._tcp.%s", server ); + + DNS_RECORDA *results = NULL; + DNS_STATUS status = pDnsQuery(temp, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &results, NULL); + if (SUCCEEDED(status) && results) { + LIST<DNS_SRV_DATAA> dnsList(5, CompareDNS); + + for (DNS_RECORDA *rec = results; rec; rec = rec->pNext) { + if (rec->Data.Srv.pNameTarget && rec->wType == DNS_TYPE_SRV) + dnsList.insert(&rec->Data.Srv); + } + + for (int i = 0; i < dnsList.getCount(); ++i) { + WORD dnsPort = port == 0 || port == 5222 ? dnsList[i]->wPort : port; + char* dnsHost = dnsList[i]->pNameTarget; + + proto->Log("%s%s resolved to %s:%d", "_xmpp-client._tcp.", server, dnsHost, dnsPort); + s = proto->WsConnect(dnsHost, dnsPort); + if (s) { + mir_snprintf( manualHost, SIZEOF( manualHost ), "%s", dnsHost ); + port = dnsPort; + break; + } } + dnsList.destroy(); + pDnsRecordListFree(results, DnsFreeRecordList); + } + else + proto->Log("%s not resolved", temp); + + FreeLibrary(hDnsapi); +} + +void CJabberProto::xmlStreamInitialize(char *szWhich) +{ + Log("Stream will be initialized %s", szWhich); + if ( m_szXmlStreamToBeInitialized ) + free( m_szXmlStreamToBeInitialized ); + m_szXmlStreamToBeInitialized = _strdup( szWhich ); +} + +void CJabberProto::xmlStreamInitializeNow(ThreadData* info) +{ + Log( "Stream is initializing %s", + m_szXmlStreamToBeInitialized ? m_szXmlStreamToBeInitialized : "after connect" ); + if (m_szXmlStreamToBeInitialized) { + free( m_szXmlStreamToBeInitialized ); + m_szXmlStreamToBeInitialized = NULL; + } + + HXML n = xi.createNode( _T("xml"), NULL, 1 ) << XATTR( _T("version"), _T("1.0")) << XATTR( _T("encoding"), _T("UTF-8")); + + HXML stream = n << XCHILDNS( _T("stream:stream" ), _T("jabber:client")) << XATTR( _T("to"), _A2T(info->server)) + << XATTR( _T("xmlns:stream"), _T("http://etherx.jabber.org/streams")); + + if ( m_tszSelectedLang ) + xmlAddAttr( stream, _T("xml:lang"), m_tszSelectedLang ); + + if ( !m_options.Disable3920auth ) + xmlAddAttr( stream, _T("version"), _T("1.0")); + + LPTSTR xmlQuery = xi.toString( n, NULL ); + char* buf = mir_utf8encodeT( xmlQuery ); + int bufLen = (int)strlen( buf ); + if ( bufLen > 2 ) { + strdel( buf + bufLen - 2, 1 ); + bufLen--; + } + + info->send( buf, bufLen ); + mir_free( buf ); + xi.freeMem( xmlQuery ); + xi.destroyNode( n ); +} + +void CJabberProto::ServerThread( ThreadData* info ) +{ + DBVARIANT dbv; + char* buffer; + int datalen; + int oldStatus; + + Log( "Thread started: type=%d", info->type ); + + info->resolveID = -1; + info->auth = NULL; + + if ( m_options.ManualConnect == TRUE ) { + if ( !DBGetContactSettingString( NULL, m_szModuleName, "ManualHost", &dbv )) { + strncpy( info->manualHost, dbv.pszVal, SIZEOF( info->manualHost )); + info->manualHost[SIZEOF( info->manualHost )-1] = '\0'; + JFreeVariant( &dbv ); + } + info->port = JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ); + } + else info->port = JGetWord( NULL, "Port", JABBER_DEFAULT_PORT ); + + info->useSSL = m_options.UseSSL; + + if ( info->type == JABBER_SESSION_NORMAL ) { + + // Normal server connection, we will fetch all connection parameters + // e.g. username, password, etc. from the database. + + if ( m_ThreadInfo != NULL ) { + // Will not start another connection thread if a thread is already running. + // Make APC call to the main thread. This will immediately wake the thread up + // in case it is asleep in the reconnect loop so that it will immediately + // reconnect. + QueueUserAPC( JabberDummyApcFunc, m_ThreadInfo->hThread, 0 ); + Log( "Thread ended, another normal thread is running" ); +LBL_Exit: + delete info; + return; + } + + m_ThreadInfo = info; + if ( m_szStreamId ) mir_free( m_szStreamId ); + m_szStreamId = NULL; + + if ( !JGetStringT( NULL, "LoginName", &dbv )) { + _tcsncpy( info->username, dbv.ptszVal, SIZEOF( info->username )-1 ); + JFreeVariant( &dbv ); + } + + if ( *trtrim(info->username) == '\0' ) { + DWORD dwSize = SIZEOF( info->username ); + if ( GetUserName( info->username, &dwSize )) + JSetStringT( NULL, "LoginName", info->username ); + else + info->username[0] = 0; + } + + if ( *trtrim(info->username) == '\0' ) { + Log( "Thread ended, login name is not configured" ); + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); +LBL_FatalError: + m_ThreadInfo = NULL; + oldStatus = m_iStatus; + m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + goto LBL_Exit; + } + + if ( !DBGetContactSettingString( NULL, m_szModuleName, "LoginServer", &dbv )) { + strncpy( info->server, dbv.pszVal, SIZEOF( info->server )-1 ); + JFreeVariant( &dbv ); + } + else { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + Log( "Thread ended, login server is not configured" ); + goto LBL_FatalError; + } + + if ( m_options.HostNameAsResource == FALSE ) { + if ( !JGetStringT( NULL, "Resource", &dbv )) { + _tcsncpy( info->resource, dbv.ptszVal, SIZEOF( info->resource ) - 1 ); + JFreeVariant( &dbv ); + } + else _tcscpy( info->resource, _T("Miranda")); + } + else { + DWORD dwCompNameLen = SIZEOF( info->resource ) - 1; + if ( !GetComputerName( info->resource, &dwCompNameLen )) + _tcscpy( info->resource, _T( "Miranda" )); + } + + TCHAR jidStr[512]; + mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM) _T("/%s"), info->username, info->server, info->resource ); + _tcsncpy( info->fullJID, jidStr, SIZEOF( info->fullJID )-1 ); + + if ( m_options.SavePassword == FALSE ) { + if (*m_savedPassword) { + _tcsncpy( info->password, m_savedPassword, SIZEOF( info->password )); + info->password[ SIZEOF( info->password )-1] = '\0'; + } + else { + mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server ); + + JabberPasswordDlgParam param; + param.pro = this; + param.ptszJid = jidStr; + param.hEventPasswdDlg = CreateEvent( NULL, FALSE, FALSE, NULL ); + CallFunctionAsync( JabberPasswordCreateDialogApcProc, ¶m ); + WaitForSingleObject( param.hEventPasswdDlg, INFINITE ); + CloseHandle( param.hEventPasswdDlg ); + + if ( param.dlgResult == IDCANCEL ) { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); + Log( "Thread ended, password request dialog was canceled" ); + goto LBL_FatalError; + } + + if ( param.saveOnlinePassword ) lstrcpy(m_savedPassword, param.onlinePassword); + else *m_savedPassword = 0; + + _tcsncpy( info->password, param.onlinePassword, SIZEOF( info->password )); + info->password[ SIZEOF( info->password )-1] = '\0'; + } + } + else { + TCHAR *passw = JGetStringCrypt(NULL, "LoginPassword"); + if ( passw == NULL ) { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID ); + Log( "Thread ended, password is not configured" ); + goto LBL_FatalError; + } + _tcsncpy( info->password, passw, SIZEOF( info->password )); + info->password[SIZEOF( info->password )-1] = '\0'; + mir_free( passw ); + } } + + else if ( info->type == JABBER_SESSION_REGISTER ) { + // Register new user connection, all connection parameters are already filled-in. + // Multiple thread allowed, although not possible : ) + // thinking again.. multiple thread should not be allowed + info->reg_done = FALSE; + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 25, ( LPARAM )TranslateT( "Connecting..." )); + iqIdRegGetReg = -1; + iqIdRegSetReg = -1; + } + else { + Log( "Thread ended, invalid session type" ); + goto LBL_FatalError; + } + + int jabberNetworkBufferSize = 2048; + if (( buffer=( char* )mir_alloc( jabberNetworkBufferSize + 1 )) == NULL ) { // +1 is for '\0' when debug logging this buffer + Log( "Cannot allocate network buffer, thread ended" ); + if ( info->type == JABBER_SESSION_NORMAL ) { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + } + else if ( info->type == JABBER_SESSION_REGISTER ) { + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Not enough memory" )); + } + Log( "Thread ended, network buffer cannot be allocated" ); + goto LBL_FatalError; + } + + if ( info->manualHost[0] == 0 ) { + info->xmpp_client_query(); + if ( info->s == NULL ) { + strncpy( info->manualHost, info->server, SIZEOF(info->manualHost)); + info->s = WsConnect( info->manualHost, info->port ); + } + } + else + info->s = WsConnect( info->manualHost, info->port ); + + Log( "Thread type=%d server='%s' port='%d'", info->type, info->manualHost, info->port ); + if ( info->s == NULL ) { + Log( "Connection failed ( %d )", WSAGetLastError()); + if ( info->type == JABBER_SESSION_NORMAL ) { + if ( m_ThreadInfo == info ) { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + } } + else if ( info->type == JABBER_SESSION_REGISTER ) + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" )); + + Log( "Thread ended, connection failed" ); + mir_free( buffer ); + goto LBL_FatalError; + } + + // Determine local IP + if ( info->useSSL ) { + Log( "Intializing SSL connection" ); + if (!CallService( MS_NETLIB_STARTSSL, ( WPARAM )info->s, 0)) { + Log( "SSL intialization failed" ); + if ( info->type == JABBER_SESSION_NORMAL ) { + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + } + else if ( info->type == JABBER_SESSION_REGISTER ) { + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" )); + } + mir_free( buffer ); + info->close(); + Log( "Thread ended, SSL connection failed" ); + goto LBL_FatalError; + } } + + // User may change status to OFFLINE while we are connecting above + if ( m_iDesiredStatus != ID_STATUS_OFFLINE || info->type == JABBER_SESSION_REGISTER ) { + + if ( info->type == JABBER_SESSION_NORMAL ) { + m_bJabberConnected = TRUE; + size_t len = _tcslen( info->username ) + strlen( info->server )+1; + m_szJabberJID = ( TCHAR* )mir_alloc( sizeof( TCHAR)*( len+1 )); + mir_sntprintf( m_szJabberJID, len+1, _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server ); + m_bSendKeepAlive = m_options.KeepAlive != 0; + JSetStringT(NULL, "jid", m_szJabberJID); // store jid in database + } + + xmlStreamInitializeNow( info ); + const TCHAR* tag = _T("stream:stream"); + + Log( "Entering main recv loop" ); + datalen = 0; + + // cache values + DWORD dwConnectionKeepAliveInterval = m_options.ConnectionKeepAliveInterval; + for ( ;; ) { + if ( !info->useZlib || info->zRecvReady ) { + DWORD dwIdle = GetTickCount() - m_lastTicks; + if ( dwIdle >= dwConnectionKeepAliveInterval ) + dwIdle = dwConnectionKeepAliveInterval - 10; // now! + + NETLIBSELECT nls = {0}; + nls.cbSize = sizeof( NETLIBSELECT ); + nls.dwTimeout = dwConnectionKeepAliveInterval - dwIdle; + nls.hReadConns[0] = info->s; + int nSelRes = CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ); + if ( nSelRes == -1 ) // error + break; + else if ( nSelRes == 0 && m_bSendKeepAlive ) { + if ( m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PING ) { + CJabberIqInfo* pInfo = m_iqManager.AddHandler( &CJabberProto::OnPingReply, JABBER_IQ_TYPE_GET, NULL, 0, -1, this ); + pInfo->SetTimeout( m_options.ConnectionKeepAliveTimeout ); + info->send( XmlNodeIq( pInfo ) << XATTR( _T("from"), m_ThreadInfo->fullJID ) << XCHILDNS( _T("ping"), _T(JABBER_FEAT_PING))); + } + else info->send( " \t " ); + continue; + } } + + int recvResult = info->recv( buffer + datalen, jabberNetworkBufferSize - datalen); + Log( "recvResult = %d", recvResult ); + if ( recvResult <= 0 ) + break; + datalen += recvResult; + +recvRest: + buffer[datalen] = '\0'; + + TCHAR* str; + str = mir_utf8decodeW( buffer ); + + int bytesParsed = 0; + XmlNode root( str, &bytesParsed, tag ); + if ( root && tag ) + { + char *p = strstr( buffer, "stream:stream" ); + if ( p ) p = strchr( p, '>' ); + if ( p ) + bytesParsed = p - buffer + 1; + else { + root = XmlNode(); + bytesParsed = 0; + } + + mir_free(str); + + } + else { + if ( root ) str[ bytesParsed ] = 0; + bytesParsed = ( root ) ? mir_utf8lenW( str ) : 0; + mir_free(str); + } + + Log( "bytesParsed = %d", bytesParsed ); + if ( root ) tag = NULL; + + if ( xmlGetName( root ) == NULL ) { + for ( int i=0; ; i++ ) { + HXML n = xmlGetChild( root , i ); + if ( !n ) + break; + OnProcessProtocol( n, info ); + } + } + else OnProcessProtocol( root, info ); + + if ( bytesParsed > 0 ) { + if ( bytesParsed < datalen ) + memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); + datalen -= bytesParsed; + } + else if ( datalen >= jabberNetworkBufferSize ) { + //jabberNetworkBufferSize += 65536; + jabberNetworkBufferSize *= 2; + Log( "Increasing network buffer size to %d", jabberNetworkBufferSize ); + if (( buffer=( char* )mir_realloc( buffer, jabberNetworkBufferSize + 1 )) == NULL ) { + Log( "Cannot reallocate more network buffer, go offline now" ); + break; + } } + else Log( "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize ); + + if ( m_szXmlStreamToBeInitialized ) { + xmlStreamInitializeNow( info ); + tag = _T("stream:stream"); + } + if ( root && datalen ) + goto recvRest; + } + + if ( info->type == JABBER_SESSION_NORMAL ) { + m_iqManager.ExpireAll( info ); + m_bJabberOnline = FALSE; + m_bJabberConnected = FALSE; + info->zlibUninit(); + EnableMenuItems( FALSE ); + RebuildInfoFrame(); + if ( m_hwndJabberChangePassword ) { + //DestroyWindow( hwndJabberChangePassword ); + // Since this is a different thread, simulate the click on the cancel button instead + SendMessage( m_hwndJabberChangePassword, WM_COMMAND, MAKEWORD( IDCANCEL, 0 ), 0 ); + } + + if ( jabberChatDllPresent ) + CallFunctionAsync( JabberOfflineChatWindows, this ); + + ListRemoveList( LIST_CHATROOM ); + ListRemoveList( LIST_BOOKMARK ); + //UI_SAFE_NOTIFY(m_pDlgJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE); + UI_SAFE_NOTIFY_HWND(m_hwndJabberAddBookmark, WM_JABBER_CHECK_ONLINE); + //UI_SAFE_NOTIFY(m_pDlgBookmarks, WM_JABBER_CHECK_ONLINE); + WindowNotify(WM_JABBER_CHECK_ONLINE); + + // Set status to offline + oldStatus = m_iStatus; + m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + + // Set all contacts to offline + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + if ( !lstrcmpA(( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ), m_szModuleName )) + { + SetContactOfflineStatus( hContact ); + MenuHideSrmmIcon( hContact ); + } + + hContact = db_find_next(hContact); + } + + mir_free( m_szJabberJID ); + m_szJabberJID = NULL; + m_tmJabberLoggedInTime = 0; + ListWipe(); + + WindowNotify(WM_JABBER_REFRESH_VCARD); + } + else if ( info->type==JABBER_SESSION_REGISTER && !info->reg_done ) + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Connection lost" )); + } + else if ( info->type == JABBER_SESSION_NORMAL ) { + oldStatus = m_iStatus; + m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; + JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, m_iStatus ); + } + + Log( "Thread ended: type=%d server='%s'", info->type, info->server ); + + if ( info->type==JABBER_SESSION_NORMAL && m_ThreadInfo==info ) { + if ( m_szStreamId ) mir_free( m_szStreamId ); + m_szStreamId = NULL; + m_ThreadInfo = NULL; + } + + info->close(); + mir_free( buffer ); + Log( "Exiting ServerThread" ); + goto LBL_Exit; +} + +void CJabberProto::PerformRegistration( ThreadData* info ) +{ + iqIdRegGetReg = SerialNext(); + info->send( XmlNodeIq( _T("get"), iqIdRegGetReg, NULL) << XQUERY( _T(JABBER_FEAT_REGISTER ))); + + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 50, ( LPARAM )TranslateT( "Requesting registration instruction..." )); +} + +void CJabberProto::PerformIqAuth( ThreadData* info ) +{ + if ( info->type == JABBER_SESSION_NORMAL ) { + int iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetAuth ); + info->send( XmlNodeIq( _T("get"), iqId ) << XQUERY( _T("jabber:iq:auth" )) << XCHILD( _T("username"), info->username )); + } + else if ( info->type == JABBER_SESSION_REGISTER ) + PerformRegistration( info ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CJabberProto::OnProcessStreamOpening( HXML node, ThreadData *info ) +{ + if ( lstrcmp( xmlGetName( node ), _T("stream:stream"))) + return; + + if ( info->type == JABBER_SESSION_NORMAL ) { + const TCHAR* sid = xmlGetAttrValue( node, _T("id")); + if ( sid != NULL ) { + char* pszSid = mir_t2a( sid ); + replaceStr( info->proto->m_szStreamId, pszSid ); + mir_free( pszSid ); + } } + + // old server - disable SASL then + if ( xmlGetAttrValue( node, _T("version")) == NULL ) + info->proto->m_options.Disable3920auth = TRUE; + + if ( info->proto->m_options.Disable3920auth ) + info->proto->PerformIqAuth( info ); +} + +void CJabberProto::PerformAuthentication( ThreadData* info ) +{ + TJabberAuth* auth = NULL; + char* request = NULL; + + if ( info->auth ) { + delete info->auth; + info->auth = NULL; + } + + if ( m_AuthMechs.isSpnegoAvailable ) { + m_AuthMechs.isSpnegoAvailable = false; + auth = new TNtlmAuth( info, "GSS-SPNEGO" ); + if ( !auth->isValid()) { + delete auth; + auth = NULL; + } } + + if ( auth == NULL && m_AuthMechs.isNtlmAvailable ) { + m_AuthMechs.isNtlmAvailable = false; + auth = new TNtlmAuth( info, "NTLM" ); + if ( !auth->isValid()) { + delete auth; + auth = NULL; + } } + + if ( auth == NULL && m_AuthMechs.isKerberosAvailable ) { + m_AuthMechs.isKerberosAvailable = false; + auth = new TNtlmAuth( info, "GSSAPI", m_AuthMechs.m_gssapiHostName ); + if ( !auth->isValid()) { + delete auth; + auth = NULL; + } else { + request = auth->getInitialRequest(); + if ( !request ) { + delete auth; + auth = NULL; + } } } + + if ( auth == NULL && m_AuthMechs.isScramAvailable ) { + m_AuthMechs.isScramAvailable = false; + auth = new TScramAuth( info ); + } + + if ( auth == NULL && m_AuthMechs.isMd5Available ) { + m_AuthMechs.isMd5Available = false; + auth = new TMD5Auth( info ); + } + + if ( auth == NULL && m_AuthMechs.isPlainAvailable ) { + m_AuthMechs.isPlainAvailable = false; + auth = new TPlainAuth( info, false ); + } + + if ( auth == NULL && m_AuthMechs.isPlainOldAvailable ) { + m_AuthMechs.isPlainOldAvailable = false; + auth = new TPlainAuth( info, true ); + } + + if ( auth == NULL ) { + if ( m_AuthMechs.isAuthAvailable ) { // no known mechanisms but iq_auth is available + m_AuthMechs.isAuthAvailable = false; + PerformIqAuth( info ); + return; + } + + TCHAR text[1024]; + mir_sntprintf( text, SIZEOF( text ), _T("%s %s@")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server ); + MsgPopup( NULL, text, TranslateT( "Jabber Authentication" )); + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); + info->send( "</stream:stream>" ); + m_ThreadInfo = NULL; + return; + } + + info->auth = auth; + + if ( !request ) request = auth->getInitialRequest(); + info->send( XmlNode( _T("auth"), _A2T(request)) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-sasl")) + << XATTR( _T("mechanism"), _A2T(auth->getName()))); + mir_free( request ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CJabberProto::OnProcessFeatures( HXML node, ThreadData* info ) +{ + bool isRegisterAvailable = false; + bool areMechanismsDefined = false; + + for ( int i=0; ;i++ ) { + HXML n = xmlGetChild( node ,i); + if ( !n ) + break; + + if ( !_tcscmp( xmlGetName( n ), _T("starttls"))) { + if ( !info->useSSL && m_options.UseTLS ) { + Log( "Requesting TLS" ); + info->send( XmlNode( xmlGetName( n )) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-tls" ))); + return; + } } + + if ( !_tcscmp( xmlGetName( n ), _T("compression")) && m_options.EnableZlib == TRUE ) { + Log("Server compression available"); + for ( int k=0; ; k++ ) { + HXML c = xmlGetChild( n ,k); + if ( !c ) + break; + + if ( !_tcscmp( xmlGetName( c ), _T("method"))) { + if ( !_tcscmp( xmlGetText( c ), _T("zlib")) && info->zlibInit() == TRUE ) { + Log("Requesting Zlib compression"); + info->send( XmlNode( _T("compress")) << XATTR( _T("xmlns"), _T("http://jabber.org/protocol/compress")) + << XCHILD( _T("method"), _T("zlib"))); + return; + } } } } + + if ( !_tcscmp( xmlGetName( n ), _T("mechanisms"))) { + m_AuthMechs.isPlainAvailable = false; + m_AuthMechs.isPlainOldAvailable = false; + m_AuthMechs.isMd5Available = false; + m_AuthMechs.isScramAvailable = false; + m_AuthMechs.isNtlmAvailable = false; + m_AuthMechs.isSpnegoAvailable = false; + m_AuthMechs.isKerberosAvailable = false; + mir_free( m_AuthMechs.m_gssapiHostName ); m_AuthMechs.m_gssapiHostName = NULL; + + areMechanismsDefined = true; + //JabberLog("%d mechanisms\n",n->numChild); + for ( int k=0; ; k++ ) { + HXML c = xmlGetChild( n ,k); + if ( !c ) + break; + + if ( !_tcscmp( xmlGetName( c ), _T("mechanism"))) { + //JabberLog("Mechanism: %s",xmlGetText( c )); + if ( !_tcscmp( xmlGetText( c ), _T("PLAIN"))) m_AuthMechs.isPlainOldAvailable = m_AuthMechs.isPlainAvailable = true; + else if ( !_tcscmp( xmlGetText( c ), _T("DIGEST-MD5"))) m_AuthMechs.isMd5Available = true; + else if ( !_tcscmp( xmlGetText( c ), _T("SCRAM-SHA-1"))) m_AuthMechs.isScramAvailable = true; + else if ( !_tcscmp( xmlGetText( c ), _T("NTLM"))) m_AuthMechs.isNtlmAvailable = true; + else if ( !_tcscmp( xmlGetText( c ), _T("GSS-SPNEGO"))) m_AuthMechs.isSpnegoAvailable = true; + else if ( !_tcscmp( xmlGetText( c ), _T("GSSAPI"))) m_AuthMechs.isKerberosAvailable = true; + } + else if ( !_tcscmp( xmlGetName( c ), _T("hostname"))) { + const TCHAR *mech = xmlGetAttrValue( c, _T("mechanism")); + if ( mech && _tcsicmp( mech, _T("GSSAPI")) == 0 ) { + m_AuthMechs.m_gssapiHostName = mir_tstrdup( xmlGetText( c )); + } + } + } } + else if ( !_tcscmp( xmlGetName( n ), _T("register" ))) isRegisterAvailable = true; + else if ( !_tcscmp( xmlGetName( n ), _T("auth" ))) m_AuthMechs.isAuthAvailable = true; + else if ( !_tcscmp( xmlGetName( n ), _T("session" ))) m_AuthMechs.isSessionAvailable = true; + } + + if ( areMechanismsDefined ) { + if ( info->type == JABBER_SESSION_NORMAL ) + PerformAuthentication( info ); + else if ( info->type == JABBER_SESSION_REGISTER ) + PerformRegistration( info ); + else + info->send( "</stream:stream>" ); + return; + } + + // mechanisms are not defined. + if ( info->auth ) { //We are already logged-in + info->send( + XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET )) + << XCHILDNS( _T("bind"), _T("urn:ietf:params:xml:ns:xmpp-bind" )) + << XCHILD( _T("resource"), info->resource )); + + if ( m_AuthMechs.isSessionAvailable ) + info->bIsSessionAvailable = TRUE; + + return; + } + + //mechanisms not available and we are not logged in + PerformIqAuth( info ); +} + +void CJabberProto::OnProcessFailure( HXML node, ThreadData* info ) +{ + const TCHAR* type; +//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" + if (( type = xmlGetAttrValue( node, _T("xmlns"))) == NULL ) return; + if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl"))) { + PerformAuthentication( info ); +} } + +void CJabberProto::OnProcessError( HXML node, ThreadData* info ) +{ + TCHAR *buff; + int i; + int pos; + bool skipMsg = false; + + //failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" + if ( !xmlGetChild( node ,0)) + return; + + buff = (TCHAR *)mir_alloc(1024*sizeof(TCHAR)); + pos=0; + for ( i=0; ; i++ ) { + HXML n = xmlGetChild( node , i ); + if ( !n ) + break; + + const TCHAR *name = xmlGetName( n ); + const TCHAR *desc = xmlGetText( n ); + if ( desc ) + pos += mir_sntprintf( buff+pos, 1024-pos, _T("%s: %s\r\n"), name, desc ); + else + pos += mir_sntprintf( buff+pos, 1024-pos, _T("%s\r\n"), name ); + + if ( !_tcscmp( name, _T("conflict"))) + JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION); + else if ( !_tcscmp( name, _T("see-other-host"))) { + skipMsg = true; + } + } + if (!skipMsg) MsgPopup( NULL, buff, TranslateT( "Jabber Error" )); + mir_free(buff); + info->send( "</stream:stream>" ); +} + +void CJabberProto::OnProcessSuccess( HXML node, ThreadData* info ) +{ + const TCHAR* type; +// int iqId; + // RECVED: <success ... + // ACTION: if successfully logged in, continue by requesting roster list and set my initial status + if (( type = xmlGetAttrValue( node, _T("xmlns"))) == NULL ) + return; + + if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl"))) { + DBVARIANT dbv; + + if ( !info->auth->validateLogin( xmlGetText( node ))) { + info->send( "</stream:stream>" ); + return; + } + + Log( "Success: Logged-in." ); + if ( DBGetContactSettingString( NULL, m_szModuleName, "Nick", &dbv )) + JSetStringT( NULL, "Nick", info->username ); + else + JFreeVariant( &dbv ); + xmlStreamInitialize( "after successful sasl" ); + } + else Log( "Success: unknown action "TCHAR_STR_PARAM".",type); +} + +void CJabberProto::OnProcessChallenge( HXML node, ThreadData* info ) +{ + if ( info->auth == NULL ) { + Log( "No previous auth have been made, exiting..." ); + return; + } + + if ( lstrcmp( xmlGetAttrValue( node, _T("xmlns")), _T("urn:ietf:params:xml:ns:xmpp-sasl"))) + return; + + char* challenge = info->auth->getChallenge( xmlGetText( node )); + info->send( XmlNode( _T("response"), _A2T(challenge)) << XATTR( _T("xmlns"), _T("urn:ietf:params:xml:ns:xmpp-sasl"))); + mir_free( challenge ); +} + +void CJabberProto::OnProcessProtocol( HXML node, ThreadData* info ) +{ + OnConsoleProcessXml(node, JCPF_IN); + + if ( !lstrcmp( xmlGetName( node ), _T("proceed"))) + OnProcessProceed( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("compressed"))) + OnProcessCompressed( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("stream:features"))) + OnProcessFeatures( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("stream:stream"))) + OnProcessStreamOpening( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("success"))) + OnProcessSuccess( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("failure"))) + OnProcessFailure( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("stream:error"))) + OnProcessError( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("challenge"))) + OnProcessChallenge( node, info ); + else if ( info->type == JABBER_SESSION_NORMAL ) { + if ( !lstrcmp( xmlGetName( node ), _T("message"))) + OnProcessMessage( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("presence"))) + OnProcessPresence( node, info ); + else if ( !lstrcmp( xmlGetName( node ), _T("iq"))) + OnProcessIq( node ); + else + Log( "Invalid top-level tag ( only <message/> <presence/> and <iq/> allowed )" ); + } + else if ( info->type == JABBER_SESSION_REGISTER ) { + if ( !lstrcmp( xmlGetName( node ), _T("iq"))) + OnProcessRegIq( node, info ); + else + Log( "Invalid top-level tag ( only <iq/> allowed )" ); +} } + +void CJabberProto::OnProcessProceed( HXML node, ThreadData* info ) +{ + const TCHAR* type; + if (( type = xmlGetAttrValue( node, _T("xmlns"))) != NULL && !lstrcmp( type, _T("error"))) + return; + + if ( !lstrcmp( type, _T("urn:ietf:params:xml:ns:xmpp-tls" ))) { + Log("Starting TLS..."); + + char* gtlk = strstr(info->manualHost, "google.com"); + bool isHosted = gtlk && !gtlk[10] && stricmp(info->server, "gmail.com") && + stricmp(info->server, "googlemail.com"); + + NETLIBSSL ssl = {0}; + ssl.cbSize = sizeof(ssl); + ssl.host = isHosted ? info->manualHost : info->server; + if (!CallService( MS_NETLIB_STARTSSL, ( WPARAM )info->s, ( LPARAM )&ssl)) { + Log( "SSL initialization failed" ); + info->send( "</stream:stream>" ); + info->shutdown(); + } + else + xmlStreamInitialize( "after successful StartTLS" ); +} } + +void CJabberProto::OnProcessCompressed( HXML node, ThreadData* info ) +{ + const TCHAR* type; + + Log( "Compression confirmed" ); + + if (( type = xmlGetAttrValue( node, _T("xmlns"))) != NULL && !lstrcmp( type, _T( "error" ))) + return; + if ( lstrcmp( type, _T( "http://jabber.org/protocol/compress" ))) + return; + + Log( "Starting Zlib stream compression..." ); + + info->useZlib = TRUE; + info->zRecvData = ( char* )mir_alloc( ZLIB_CHUNK_SIZE ); + + xmlStreamInitialize( "after successful Zlib init" ); +} + +void CJabberProto::OnProcessPubsubEvent( HXML node ) +{ + const TCHAR* from = xmlGetAttrValue( node, _T("from")); + if ( !from ) + return; + + HXML eventNode = xmlGetChildByTag( node, "event", "xmlns", _T(JABBER_FEAT_PUBSUB_EVENT)); + if ( !eventNode ) + return; + + m_pepServices.ProcessEvent(from, eventNode); + + HANDLE hContact = HContactFromJID( from ); + if ( !hContact ) + return; + + HXML itemsNode; + if ( m_options.EnableUserTune && (itemsNode = xmlGetChildByTag( eventNode, "items", "node", _T(JABBER_FEAT_USER_TUNE)))) { + // node retract? + if ( xmlGetChild( itemsNode , "retract" )) { + SetContactTune( hContact, NULL, NULL, NULL, NULL, NULL ); + return; + } + + HXML tuneNode = XPath( itemsNode, _T("item/tune[@xmlns='") _T(JABBER_FEAT_USER_TUNE) _T("']")); + if ( !tuneNode ) + return; + + const TCHAR *szArtist = XPathT( tuneNode, "artist" ); + const TCHAR *szLength = XPathT( tuneNode, "length" ); + const TCHAR *szSource = XPathT( tuneNode, "source" ); + const TCHAR *szTitle = XPathT( tuneNode, "title" ); + const TCHAR *szTrack = XPathT( tuneNode, "track" ); + + TCHAR szLengthInTime[32]; + szLengthInTime[0] = _T('\0'); + if ( szLength ) { + int nLength = _ttoi( szLength ); + mir_sntprintf( szLengthInTime, SIZEOF( szLengthInTime ), _T("%02d:%02d:%02d"), + nLength / 3600, (nLength / 60) % 60, nLength % 60 ); + } + + SetContactTune( hContact, szArtist, szLength ? szLengthInTime : NULL, szSource, szTitle, szTrack ); + } +} + +// returns 0, if error or no events +DWORD JabberGetLastContactMessageTime( HANDLE hContact ) +{ + // TODO: time cache can improve performance + HANDLE hDbEvent = (HANDLE)CallService( MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0 ); + if ( !hDbEvent ) + return 0; + + DWORD dwTime = 0; + + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0 ); + if ( dbei.cbBlob != -1 ) { + dbei.pBlob = (PBYTE)mir_alloc( dbei.cbBlob + 1 ); + int nGetTextResult = CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); + if ( !nGetTextResult ) + dwTime = dbei.timestamp; + mir_free( dbei.pBlob ); + } + return dwTime; +} + +HANDLE CJabberProto::CreateTemporaryContact( const TCHAR *szJid, JABBER_LIST_ITEM* chatItem ) +{ + HANDLE hContact = NULL; + if ( chatItem ) { + const TCHAR* p = _tcschr( szJid, '/' ); + if ( p != NULL && p[1] != '\0' ) + p++; + else + p = szJid; + hContact = DBCreateContact( szJid, p, TRUE, FALSE ); + + for ( int i=0; i < chatItem->resourceCount; i++ ) { + if ( !lstrcmp( chatItem->resource[i].resourceName, p )) { + JSetWord( hContact, "Status", chatItem->resource[i].status ); + break; + } + } + } + else { + TCHAR *nick = JabberNickFromJID( szJid ); + hContact = DBCreateContact( szJid, nick, TRUE, TRUE ); + mir_free( nick ); + } + return hContact; +} + +void CJabberProto::OnProcessMessage( HXML node, ThreadData* info ) +{ + HXML subjectNode, xNode, inviteNode, idNode, n; + LPCTSTR from, type, idStr, fromResource; + HANDLE hContact; + + if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("message"))) + return; + + type = xmlGetAttrValue( node, _T("type")); + if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) + return; + + idStr = xmlGetAttrValue( node, _T("id")); + JABBER_RESOURCE_STATUS *resourceStatus = ResourceInfoFromJID( from ); + + // Message receipts delivery request. Reply here, before a call to HandleMessagePermanent() to make sure message receipts are handled for external plugins too. + if ( ( !type || _tcsicmp( type, _T("error"))) && xmlGetChildByTag( node, "request", "xmlns", _T( JABBER_FEAT_MESSAGE_RECEIPTS ))) { + info->send( + XmlNode( _T("message")) << XATTR( _T("to"), from ) << XATTR( _T("id"), idStr ) + << XCHILDNS( _T("received"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)) << XATTR( _T("id"), idStr )); + + if ( resourceStatus ) + resourceStatus->jcbManualDiscoveredCaps |= JABBER_CAPS_MESSAGE_RECEIPTS; + } + + if ( m_messageManager.HandleMessagePermanent( node, info )) + return; + + hContact = HContactFromJID( from ); + JABBER_LIST_ITEM *chatItem = ListGetItemPtr( LIST_CHATROOM, from ); + if ( chatItem ) { + HXML xCaptcha = xmlGetChild( node, "captcha" ); + if ( xCaptcha ) + if ( ProcessCaptcha( xCaptcha, node, info )) + return; + } + + const TCHAR* szMessage = NULL; + HXML bodyNode = xmlGetChildByTag( node , "body", "xml:lang", m_tszSelectedLang ); + if ( bodyNode == NULL ) + bodyNode = xmlGetChild( node , "body" ); + if ( bodyNode != NULL && xmlGetText( bodyNode )) + szMessage = xmlGetText( bodyNode ); + if (( subjectNode = xmlGetChild( node , "subject" )) && xmlGetText( subjectNode ) && xmlGetText( subjectNode )[0] != _T('\0')) { + size_t cbLen = (szMessage ? _tcslen( szMessage ) : 0) + _tcslen( xmlGetText( subjectNode )) + 128; + TCHAR* szTmp = ( TCHAR * )alloca( sizeof(TCHAR) * cbLen ); + szTmp[0] = _T('\0'); + if ( szMessage ) + _tcscat( szTmp, _T("Subject: ")); + _tcscat( szTmp, xmlGetText( subjectNode )); + if ( szMessage ) { + _tcscat( szTmp, _T("\r\n")); + _tcscat( szTmp, szMessage ); + } + szMessage = szTmp; + } + + if ( szMessage && (n = xmlGetChildByTag( node, "addresses", "xmlns", _T(JABBER_FEAT_EXT_ADDRESSING)))) { + HXML addressNode = xmlGetChildByTag( n, "address", "type", _T("ofrom")); + if ( addressNode ) { + const TCHAR* szJid = xmlGetAttrValue( addressNode, _T("jid")); + if ( szJid ) { + size_t cbLen = _tcslen( szMessage ) + 1000; + TCHAR* p = ( TCHAR* )alloca( sizeof( TCHAR ) * cbLen ); + mir_sntprintf( p, cbLen, TranslateT("Message redirected from: %s\r\n%s"), from, szMessage ); + szMessage = p; + from = szJid; + // rewrite hContact + hContact = HContactFromJID( from ); + } + } + } + + // If message is from a stranger ( not in roster ), item is NULL + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_ROSTER, from ); + if ( !item ) + item = ListGetItemPtr( LIST_VCARD_TEMP, from ); + + time_t msgTime = 0; + BOOL isChatRoomInvitation = FALSE; + const TCHAR* inviteRoomJid = NULL; + const TCHAR* inviteFromJid = NULL; + const TCHAR* inviteReason = NULL; + const TCHAR* invitePassword = NULL; + BOOL delivered = FALSE; + + // check chatstates availability + if ( resourceStatus && xmlGetChildByTag( node, "active", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) + resourceStatus->jcbManualDiscoveredCaps |= JABBER_CAPS_CHATSTATES; + + // chatstates composing event + if ( hContact && xmlGetChildByTag( node, "composing", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, 60 ); + + // chatstates paused event + if ( hContact && xmlGetChildByTag( node, "paused", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, PROTOTYPE_CONTACTTYPING_OFF ); + + // chatstates inactive event + if ( hContact && xmlGetChildByTag( node, "inactive", "xmlns", _T( JABBER_FEAT_CHATSTATES ))) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM )hContact, PROTOTYPE_CONTACTTYPING_OFF ); + + // message receipts delivery notification + if ( n = xmlGetChildByTag( node, "received", "xmlns", _T( JABBER_FEAT_MESSAGE_RECEIPTS ))) { + int nPacketId = JabberGetPacketID( n ); + if ( nPacketId == -1 ) + nPacketId = JabberGetPacketID( node ); + if ( nPacketId != -1) + JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) nPacketId, 0 ); + } + + // XEP-0203 delay support + if ( n = xmlGetChildByTag( node, "delay", "xmlns", _T("urn:xmpp:delay")) ) { + const TCHAR* ptszTimeStamp = xmlGetAttrValue( n, _T("stamp")); + if ( ptszTimeStamp != NULL ) { + // skip '-' chars + TCHAR* szStamp = mir_tstrdup( ptszTimeStamp ); + int si = 0, sj = 0; + while (1) { + if ( szStamp[si] == _T('-')) + si++; + else + if ( !( szStamp[sj++] = szStamp[si++] )) + break; + }; + msgTime = JabberIsoToUnixTime( szStamp ); + mir_free( szStamp ); + } + } + + // XEP-0224 support (Attention/Nudge) + if ( xmlGetChildByTag( node, "attention", "xmlns", _T( JABBER_FEAT_ATTENTION )) || + xmlGetChildByTag( node, "attention", "xmlns", _T( JABBER_FEAT_ATTENTION_0 ))) { + if ( !hContact ) + hContact = CreateTemporaryContact( from, chatItem ); + if ( hContact ) + NotifyEventHooks( m_hEventNudge, (WPARAM)hContact, 0 ); + } + + // chatstates gone event + if ( hContact && xmlGetChildByTag( node, "gone", "xmlns", _T( JABBER_FEAT_CHATSTATES )) && m_options.LogChatstates ) { + DBEVENTINFO dbei; + BYTE bEventType = JABBER_DB_EVENT_CHATSTATES_GONE; // gone event + dbei.cbSize = sizeof(dbei); + dbei.pBlob = &bEventType; + dbei.cbBlob = 1; + dbei.eventType = JABBER_DB_EVENT_TYPE_CHATSTATES; + dbei.flags = DBEF_READ; + dbei.timestamp = time(NULL); + dbei.szModule = m_szModuleName; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + } + + if (( n = xmlGetChildByTag( node, "confirm", "xmlns", _T( JABBER_FEAT_HTTP_AUTH ))) && m_options.AcceptHttpAuth ) { + const TCHAR *szId = xmlGetAttrValue( n, _T("id")); + const TCHAR *szMethod = xmlGetAttrValue( n, _T("method")); + const TCHAR *szUrl = xmlGetAttrValue( n, _T("url")); + if ( !szId || !szMethod || !szUrl ) + return; + + CJabberHttpAuthParams *pParams = (CJabberHttpAuthParams *)mir_alloc( sizeof( CJabberHttpAuthParams )); + if ( !pParams ) + return; + + ZeroMemory( pParams, sizeof( CJabberHttpAuthParams )); + pParams->m_nType = CJabberHttpAuthParams::MSG; + pParams->m_szFrom = mir_tstrdup( from ); + HXML pThreadNode = xmlGetChild( node , "thread" ); + if ( pThreadNode && xmlGetText( pThreadNode ) && xmlGetText( pThreadNode )[0] ) + pParams->m_szThreadId = mir_tstrdup( xmlGetText( pThreadNode )); + pParams->m_szId = mir_tstrdup( szId ); + pParams->m_szMethod = mir_tstrdup( szMethod ); + pParams->m_szUrl = mir_tstrdup( szUrl ); + + AddClistHttpAuthEvent( pParams ); + return; + } + + for ( int i = 0; ( xNode = xmlGetChild( node, i )) != NULL; i++ ) { + xNode = xmlGetNthChild( node, _T("x"), i + 1 ); + if ( xNode == NULL ) { + xNode = xmlGetNthChild( node, _T("user:x"), i + 1 ); + if ( xNode == NULL ) + continue; + } + + const TCHAR* ptszXmlns = xmlGetAttrValue( xNode, _T("xmlns")); + if ( ptszXmlns == NULL ) + ptszXmlns = xmlGetAttrValue( xNode, _T("xmlns:user")); + if ( ptszXmlns == NULL ) + continue; + + if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MIRANDA_NOTES))) { + if (OnIncomingNote(from, xmlGetChild(xNode, "note"))) + return; + } + else if ( !_tcscmp( ptszXmlns, _T("jabber:x:encrypted" ))) { + if ( xmlGetText( xNode ) == NULL ) + return; + + TCHAR* prolog = _T("-----BEGIN PGP MESSAGE-----\r\n\r\n"); + TCHAR* epilog = _T("\r\n-----END PGP MESSAGE-----\r\n"); + TCHAR* tempstring = ( TCHAR* )alloca( sizeof( TCHAR ) * ( _tcslen( prolog ) + _tcslen( xmlGetText( xNode )) + _tcslen( epilog ) + 3 )); + _tcsncpy( tempstring, prolog, _tcslen( prolog ) + 1 ); + _tcsncpy( tempstring + _tcslen( prolog ), xmlGetText( xNode ), _tcslen( xmlGetText( xNode )) + 1); + _tcsncpy( tempstring + _tcslen( prolog ) + _tcslen(xmlGetText( xNode )), epilog, _tcslen( epilog ) + 1); + szMessage = tempstring; + } + else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_DELAY)) && msgTime == 0 ) { + const TCHAR* ptszTimeStamp = xmlGetAttrValue( xNode, _T("stamp")); + if ( ptszTimeStamp != NULL ) + msgTime = JabberIsoToUnixTime( ptszTimeStamp ); + } + else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MESSAGE_EVENTS))) { + + // set events support only if we discovered caps and if events not already set + JabberCapsBits jcbCaps = GetResourceCapabilites( from, TRUE ); + if ( jcbCaps & JABBER_RESOURCE_CAPS_ERROR ) + jcbCaps = JABBER_RESOURCE_CAPS_NONE; + // FIXME: disabled due to expired XEP-0022 and problems with bombus delivery checks +// if ( jcbCaps && resourceStatus && (!(jcbCaps & JABBER_CAPS_MESSAGE_EVENTS))) +// resourceStatus->jcbManualDiscoveredCaps |= (JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY); + + if ( bodyNode == NULL ) { + idNode = xmlGetChild( xNode , "id" ); + if ( xmlGetChild( xNode , "delivered" ) != NULL || xmlGetChild( xNode , "offline" ) != NULL ) { + int id = -1; + if ( idNode != NULL && xmlGetText( idNode ) != NULL ) + if ( !_tcsncmp( xmlGetText( idNode ), _T(JABBER_IQID), strlen( JABBER_IQID ))) + id = _ttoi(( xmlGetText( idNode ))+strlen( JABBER_IQID )); + + if ( id != -1 ) + JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); + } + + if ( hContact && xmlGetChild( xNode , "composing" ) != NULL ) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 ); + + // Maybe a cancel to the previous composing + HXML child = xmlGetChild( xNode ,0); + if ( hContact && ( !child || ( child && idNode != NULL ))) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF ); + } + else { + // Check whether any event is requested + if ( !delivered && ( n = xmlGetChild( xNode , "delivered" )) != NULL ) { + delivered = TRUE; + + XmlNode m( _T("message" )); m << XATTR( _T("to"), from ); + HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); + x << XCHILD( _T("delivered")); + x << XCHILD( _T("id"), idStr ); + info->send( m ); + } + if ( item != NULL && xmlGetChild( xNode , "composing" ) != NULL ) { + if ( item->messageEventIdStr ) + mir_free( item->messageEventIdStr ); + item->messageEventIdStr = ( idStr==NULL )?NULL:mir_tstrdup( idStr ); + } } + } + else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_OOB2))) { + HXML urlNode; + if ( ((urlNode = xmlGetChild( xNode , "url" )) != NULL) && xmlGetText( urlNode ) && xmlGetText( urlNode )[0] != _T('\0')) { + size_t cbLen = (szMessage ? _tcslen( szMessage ) : 0) + _tcslen( xmlGetText( urlNode )) + 32; + TCHAR* szTmp = ( TCHAR * )alloca( sizeof(TCHAR) * cbLen ); + _tcscpy( szTmp, xmlGetText( urlNode )); + if ( szMessage ) { + _tcscat( szTmp, _T("\r\n")); + _tcscat( szTmp, szMessage ); + } + szMessage = szTmp; + } + } + else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_MUC_USER))) { + inviteNode = xmlGetChild( xNode , _T("invite")); + if ( inviteNode == NULL ) + inviteNode = xmlGetChild( xNode , _T("user:invite")); + + if ( inviteNode != NULL ) { + inviteFromJid = xmlGetAttrValue( inviteNode, _T("from")); + n = xmlGetChild( inviteNode , _T("reason")); + if ( n == NULL ) + n = xmlGetChild( inviteNode , _T("user:reason")); + if ( n != NULL ) + inviteReason = xmlGetText( n ); + } + inviteRoomJid = from; + if ( !inviteReason ) + inviteReason = szMessage; + isChatRoomInvitation = TRUE; + if (( n = xmlGetChild( xNode , "password" )) != NULL ) + invitePassword = xmlGetText( n ); + } + else if ( !_tcscmp( ptszXmlns, _T(JABBER_FEAT_ROSTER_EXCHANGE)) && + item != NULL && (item->subscription == SUB_BOTH || item->subscription == SUB_TO)) { + TCHAR chkJID[JABBER_MAX_JID_LEN] = _T("@"); + JabberStripJid( from, chkJID + 1, SIZEOF(chkJID) - 1 ); + for ( int i = 1; ; ++i ) { + HXML iNode = xmlGetNthChild( xNode , _T("item"), i ); + if ( iNode == NULL ) break; + const TCHAR *action = xmlGetAttrValue( iNode, _T("action")); + const TCHAR *jid = xmlGetAttrValue( iNode, _T("jid")); + const TCHAR *nick = xmlGetAttrValue( iNode, _T("name")); + const TCHAR *group = xmlGetText( xmlGetChild( iNode, _T("group"))); + if ( action && jid && _tcsstr( jid, chkJID )) { + if ( !_tcscmp( action, _T("add"))) { + HANDLE hContact = DBCreateContact( jid, nick, FALSE, FALSE ); + if ( group ) + DBWriteContactSettingTString( hContact, "CList", "Group", group ); + } + else if ( !_tcscmp( action, _T("modify"))) { +// HANDLE hContact = HContactFromJID( jid ); + } + else if ( !_tcscmp( action, _T("delete"))) { + HANDLE hContact = HContactFromJID( jid ); + if ( hContact ) + CallService( MS_DB_CONTACT_DELETE, ( WPARAM ) hContact, 0 ); + } + } + } + } + else if ( !isChatRoomInvitation && !_tcscmp( ptszXmlns, _T("jabber:x:conference"))) { + inviteRoomJid = xmlGetAttrValue( xNode, _T("jid")); + inviteFromJid = from; + if ( inviteReason == NULL ) + inviteReason = xmlGetText( xNode ); + if ( !inviteReason ) + inviteReason = szMessage; + isChatRoomInvitation = TRUE; + } + } + + if ( isChatRoomInvitation ) { + if ( inviteRoomJid != NULL ) { + if ( m_options.IgnoreMUCInvites ) { + // FIXME: temporary disabled due to MUC inconsistence on server side + /* + XmlNode m( "message" ); xmlAddAttr( m, "to", from ); + XmlNode xNode = xmlAddChild( m, "x" ); + xmlAddAttr( xNode, "xmlns", JABBER_FEAT_MUC_USER ); + XmlNode declineNode = xmlAddChild( xNode, "decline" ); + xmlAddAttr( declineNode, "from", inviteRoomJid ); + XmlNode reasonNode = xmlAddChild( declineNode, "reason", "The user has chosen to not accept chat invites" ); + info->send( m ); + */ + } + else + GroupchatProcessInvite( inviteRoomJid, inviteFromJid, inviteReason, invitePassword ); + } + return; + } + + if ( szMessage ) { + if (( szMessage = JabberUnixToDosT( szMessage )) == NULL ) + szMessage = mir_tstrdup( _T("")); + + char* buf = mir_utf8encodeW( szMessage ); + + if ( item != NULL ) { + if ( resourceStatus ) resourceStatus->bMessageSessionActive = TRUE; + if ( hContact != NULL ) + CallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF ); + + // no we will monitor last resource in all modes + if ( /*item->resourceMode==RSMODE_LASTSEEN &&*/ ( fromResource = _tcschr( from, '/' ))!=NULL ) { + fromResource++; + if ( *fromResource != '\0' ) { + for ( int i=0; i<item->resourceCount; i++ ) { + if ( !lstrcmp( item->resource[i].resourceName, fromResource )) { + int nLastSeenResource = item->lastSeenResource; + item->lastSeenResource = i; + if ((item->resourceMode==RSMODE_LASTSEEN) && (i != nLastSeenResource)) + UpdateMirVer(item); + break; + } } } } } + + // Create a temporary contact + if ( hContact == NULL ) + hContact = CreateTemporaryContact( from, chatItem ); + + time_t now = time( NULL ); + if ( !msgTime ) + msgTime = now; + + if ( m_options.FixIncorrectTimestamps && ( msgTime > now || ( msgTime < ( time_t )JabberGetLastContactMessageTime( hContact )))) + msgTime = now; + + PROTORECVEVENT recv; + recv.flags = PREF_UTF; + recv.timestamp = ( DWORD )msgTime; + recv.szMessage = buf; + + EnterCriticalSection( &m_csLastResourceMap ); + recv.lParam = (LPARAM)AddToLastResourceMap( from ); + LeaveCriticalSection( &m_csLastResourceMap ); + + CCSDATA ccs; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.szProtoService = PSR_MESSAGE; + ccs.lParam = ( LPARAM )&recv; + CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs ); + + mir_free(( void* )szMessage ); + mir_free( buf ); + } +} + +// XEP-0115: Entity Capabilities +void CJabberProto::OnProcessPresenceCapabilites( HXML node ) +{ + const TCHAR* from; + if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) + return; + + Log("presence: for jid " TCHAR_STR_PARAM, from); + + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( from ); + if ( r == NULL ) return; + + HXML n; + + // check XEP-0115 support, and old style: + if (( n = xmlGetChildByTag( node, "c", "xmlns", _T(JABBER_FEAT_ENTITY_CAPS))) != NULL || + ( n = xmlGetChildByTag( node, "caps:c", "xmlns:caps", _T(JABBER_FEAT_ENTITY_CAPS))) != NULL || + ( n = xmlGetChild( node, "c" )) != NULL ) { + const TCHAR *szNode = xmlGetAttrValue( n, _T("node")); + const TCHAR *szVer = xmlGetAttrValue( n, _T("ver")); + const TCHAR *szExt = xmlGetAttrValue( n, _T("ext")); + if ( szNode && szVer ) { + replaceStrT( r->szCapsNode, szNode ); + replaceStrT( r->szCapsVer, szVer ); + replaceStrT( r->szCapsExt, szExt ); + HANDLE hContact = HContactFromJID( from ); + if ( hContact ) + UpdateMirVer( hContact, r ); + } + } + + // update user's caps + // JabberCapsBits jcbCaps = GetResourceCapabilites( from, TRUE ); +} + +void CJabberProto::UpdateJidDbSettings( const TCHAR *jid ) +{ + JABBER_LIST_ITEM *item = ListGetItemPtr( LIST_ROSTER, jid ); + if ( !item ) return; + HANDLE hContact = HContactFromJID( jid ); + if ( !hContact ) return; + + int status = ID_STATUS_OFFLINE; + if ( !item->resourceCount ) { + // set offline only if jid has resources + if ( _tcschr( jid, '/' )==NULL ) + status = item->itemResource.status; + if ( item->itemResource.statusMessage ) + DBWriteContactSettingTString( hContact, "CList", "StatusMsg", item->itemResource.statusMessage ); + else + DBDeleteContactSetting( hContact, "CList", "StatusMsg" ); + } + + // Determine status to show for the contact based on the remaining resources + int nSelectedResource = -1, i = 0; + int nMaxPriority = -999; // -128...+127 valid range + for ( i = 0; i < item->resourceCount; i++ ) + { + if ( item->resource[i].priority > nMaxPriority ) { + nMaxPriority = item->resource[i].priority; + status = item->resource[i].status; + nSelectedResource = i; + } + else if ( item->resource[i].priority == nMaxPriority) { + if (( status = JabberCombineStatus( status, item->resource[i].status )) == item->resource[i].status ) + nSelectedResource = i; + } + } + item->itemResource.status = status; + if ( nSelectedResource != -1 ) { + Log("JabberUpdateJidDbSettings: updating jid " TCHAR_STR_PARAM " to rc " TCHAR_STR_PARAM, item->jid, item->resource[nSelectedResource].resourceName ); + if ( item->resource[nSelectedResource].statusMessage ) + DBWriteContactSettingTString( hContact, "CList", "StatusMsg", item->resource[nSelectedResource].statusMessage ); + else + DBDeleteContactSetting( hContact, "CList", "StatusMsg" ); + UpdateMirVer( hContact, &item->resource[nSelectedResource] ); + } + else { + JDeleteSetting( hContact, DBSETTING_DISPLAY_UID ); + } + + if ( _tcschr( jid, '@' )!=NULL || m_options.ShowTransport==TRUE ) + if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status ) + JSetWord( hContact, "Status", ( WORD )status ); + + if (status == ID_STATUS_OFFLINE) + { // remove x-status icon + JDeleteSetting( hContact, DBSETTING_XSTATUSID ); + JDeleteSetting( hContact, DBSETTING_XSTATUSNAME ); + JDeleteSetting( hContact, DBSETTING_XSTATUSMSG ); + //JabberUpdateContactExtraIcon(hContact); + } + + MenuUpdateSrmmIcon( item ); +} + +void CJabberProto::OnProcessPresence( HXML node, ThreadData* info ) +{ + HANDLE hContact; + HXML showNode, statusNode, priorityNode; + JABBER_LIST_ITEM *item; + LPCTSTR from, show, p; + TCHAR *nick; + + if ( !node || !xmlGetName( node ) ||_tcscmp( xmlGetName( node ), _T("presence"))) return; + if (( from = xmlGetAttrValue( node, _T("from"))) == NULL ) return; + + if ( m_presenceManager.HandlePresencePermanent( node, info )) + return; + + if ( ListExist( LIST_CHATROOM, from )) { + GroupchatProcessPresence( node ); + return; + } + + BOOL bSelfPresence = FALSE; + TCHAR szBareFrom[ JABBER_MAX_JID_LEN ]; + JabberStripJid( from, szBareFrom, SIZEOF( szBareFrom )); + TCHAR szBareOurJid[ JABBER_MAX_JID_LEN ]; + JabberStripJid( info->fullJID, szBareOurJid, SIZEOF( szBareOurJid )); + + if ( !_tcsicmp( szBareFrom, szBareOurJid )) + bSelfPresence = TRUE; + + LPCTSTR type = xmlGetAttrValue( node, _T("type")); + if ( type == NULL || !_tcscmp( type, _T("available"))) { + if (( nick = JabberNickFromJID( from )) == NULL ) + return; + + if (( hContact = HContactFromJID( from )) == NULL ) { + if ( !_tcsicmp( info->fullJID, from ) || ( !bSelfPresence && !ListExist( LIST_ROSTER, from ))) { + Log("SKIP Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster and not in list - skiping)", from ); + mir_free( nick ); + return; + } + hContact = DBCreateContact( from, nick, TRUE, TRUE ); + } + if ( !ListExist( LIST_ROSTER, from )) { + Log("Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster )", from ); + ListAdd( LIST_ROSTER, from ); + } + DBCheckIsTransportedContact( from, hContact ); + int status = ID_STATUS_ONLINE; + if (( showNode = xmlGetChild( node , "show" )) != NULL ) { + if (( show = xmlGetText( showNode )) != NULL ) { + if ( !_tcscmp( show, _T("away"))) status = ID_STATUS_AWAY; + else if ( !_tcscmp( show, _T("xa"))) status = ID_STATUS_NA; + else if ( !_tcscmp( show, _T("dnd"))) status = ID_STATUS_DND; + else if ( !_tcscmp( show, _T("chat"))) status = ID_STATUS_FREECHAT; + } } + + char priority = 0; + if (( priorityNode = xmlGetChild( node , "priority" )) != NULL && xmlGetText( priorityNode ) != NULL ) + priority = (char)_ttoi( xmlGetText( priorityNode )); + + if (( statusNode = xmlGetChild( node , "status" )) != NULL && xmlGetText( statusNode ) != NULL ) + p = xmlGetText( statusNode ); + else + p = NULL; + ListAddResource( LIST_ROSTER, from, status, p, priority ); + + // XEP-0115: Entity Capabilities + OnProcessPresenceCapabilites( node ); + + UpdateJidDbSettings( from ); + + if ( _tcschr( from, '@' )==NULL ) { + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); + } + Log( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) online, set contact status to %s", nick, from, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,(WPARAM)status,0 )); + mir_free( nick ); + + HXML xNode; + if ( m_options.EnableAvatars ) { + BOOL hasAvatar = false; + BOOL removedAvatar = false; + + Log( "Avatar enabled" ); + for ( int i = 1; ( xNode=xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) { + if ( !lstrcmp( xmlGetAttrValue( xNode, _T("xmlns")), _T("jabber:x:avatar"))) { + if (( xNode = xmlGetChild( xNode , "hash" )) != NULL && xmlGetText( xNode ) != NULL ) { + JDeleteSetting(hContact,"AvatarXVcard"); + Log( "AvatarXVcard deleted" ); + JSetStringT( hContact, "AvatarHash", xmlGetText( xNode )); + hasAvatar = true; + DBVARIANT dbv; + int result = JGetStringT( hContact, "AvatarSaved", &dbv ); + if ( result || lstrcmp( dbv.ptszVal, xmlGetText( xNode ))) { + Log( "Avatar was changed" ); + JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL ); + } else Log( "Not broadcasting avatar changed" ); + if ( !result ) JFreeVariant( &dbv ); + } else { + removedAvatar = true; + } + } } + if ( !hasAvatar ) { //no jabber:x:avatar. try vcard-temp:x:update + Log( "Not hasXAvatar" ); + for ( int i = 1; ( xNode=xmlGetNthChild( node, _T("x"), i )) != NULL; i++ ) { + if ( !lstrcmp( xmlGetAttrValue( xNode, _T("xmlns")), _T("vcard-temp:x:update"))) { + if (( xNode = xmlGetChild( xNode , "photo" )) != NULL ) { + LPCTSTR txt = xmlGetText( xNode ); + if ( txt != NULL && txt[0] != 0) { + JSetByte( hContact, "AvatarXVcard", 1 ); + Log( "AvatarXVcard set" ); + JSetStringT( hContact, "AvatarHash", txt ); + hasAvatar = true; + DBVARIANT dbv; + int result = JGetStringT( hContact, "AvatarSaved", &dbv ); + if ( result || lstrcmp( dbv.ptszVal, txt )) { + Log( "Avatar was changed. Using vcard-temp:x:update" ); + JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL ); + } + else Log( "Not broadcasting avatar changed" ); + if ( !result ) JFreeVariant( &dbv ); + } else { + removedAvatar = true; + } + } } } } + if ( !hasAvatar && removedAvatar ) { + Log( "Has no avatar" ); + JDeleteSetting( hContact, "AvatarHash" ); + DBVARIANT dbv = {0}; + if ( !JGetStringT( hContact, "AvatarSaved", &dbv )) { + JFreeVariant( &dbv ); + JDeleteSetting( hContact, "AvatarSaved" ); + JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, NULL, NULL ); + } } } + return; + } + + if ( !_tcscmp( type, _T("unavailable"))) { + hContact = HContactFromJID( from ); + if (( item = ListGetItemPtr( LIST_ROSTER, from )) != NULL ) { + ListRemoveResource( LIST_ROSTER, from ); + + hContact = HContactFromJID( from ); + if ( hContact && DBGetContactSettingByte( hContact, "CList", "NotOnList", 0) == 1 ) { + // remove selfcontact, if where is no more another resources + if ( item->resourceCount == 1 && ResourceInfoFromJID( info->fullJID )) + ListRemoveResource( LIST_ROSTER, info->fullJID ); + } + + + // set status only if no more available resources + if ( !item->resourceCount ) + { + item->itemResource.status = ID_STATUS_OFFLINE; + if ((( statusNode = xmlGetChild( node , "status" )) != NULL ) && xmlGetText( statusNode )) + replaceStrT( item->itemResource.statusMessage, xmlGetText( statusNode )); + else + replaceStrT( item->itemResource.statusMessage, NULL ); + } + } + else Log( "SKIP Receive presence offline from " TCHAR_STR_PARAM " ( who is not in my roster )", from ); + + UpdateJidDbSettings( from ); + + if ( _tcschr( from, '@' )==NULL ) { + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); + } + DBCheckIsTransportedContact(from, hContact); + return; + } + + if ( !_tcscmp( type, _T("subscribe"))) { + if (hContact = HContactFromJID( from )) + AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_SUBSCRIBE ); + + // automatically send authorization allowed to agent/transport + if ( _tcschr( from, '@' ) == NULL || m_options.AutoAcceptAuthorization ) { + ListAdd( LIST_ROSTER, from ); + info->send( XmlNode( _T("presence")) << XATTR( _T("to"), from ) << XATTR( _T("type"), _T("subscribed"))); + + if ( m_options.AutoAdd == TRUE ) { + if (( item = ListGetItemPtr( LIST_ROSTER, from )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) { + Log( "Try adding contact automatically jid = " TCHAR_STR_PARAM, from ); + if (( hContact=AddToListByJID( from, 0 )) != NULL ) { + // Trigger actual add by removing the "NotOnList" added by AddToListByJID() + // See AddToListByJID() and JabberDbSettingChanged(). + DBDeleteContactSetting( hContact, "CList", "NotOnList" ); + } } } + RebuildInfoFrame(); + } + else { + HXML n = xmlGetChild( node , "nick" ); + nick = ( n == NULL ) ? JabberNickFromJID( from ) : mir_tstrdup( xmlGetText( n )); + if ( nick != NULL ) { + Log( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) requests authorization", nick, from ); + DBAddAuthRequest( from, nick ); + mir_free( nick ); + } } + return; + } + + if ( !_tcscmp( type, _T("unsubscribe"))) { + if (hContact = HContactFromJID( from )) + AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBE ); + } + + if ( !_tcscmp( type, _T("unsubscribed"))) { + if (hContact = HContactFromJID( from )) + AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_UNSUBSCRIBED ); + } + + if ( !_tcscmp( type, _T("error"))) { + if (hContact = HContactFromJID( from )) { + AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_ERROR ); + } + } + + if ( !_tcscmp( type, _T("subscribed"))) { + + if (hContact = HContactFromJID( from )) + AddDbPresenceEvent( hContact, JABBER_DB_EVENT_PRESENCE_SUBSCRIBED ); + + if (( item=ListGetItemPtr( LIST_ROSTER, from )) != NULL ) { + if ( item->subscription == SUB_FROM ) item->subscription = SUB_BOTH; + else if ( item->subscription == SUB_NONE ) { + item->subscription = SUB_TO; + if ( _tcschr( from, '@' )==NULL ) { + UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); + } + } + UpdateSubscriptionInfo( hContact, item ); + } + } +} + +void CJabberProto::OnIqResultVersion( HXML /*node*/, CJabberIqInfo *pInfo ) +{ + JABBER_RESOURCE_STATUS *r = ResourceInfoFromJID( pInfo->GetFrom()); + if ( r == NULL ) return; + + r->dwVersionRequestTime = -1; + + replaceStrT( r->software, NULL ); + replaceStrT( r->version, NULL ); + replaceStrT( r->system, NULL ); + + HXML queryNode = pInfo->GetChildNode(); + + if ( pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT && queryNode) { + HXML n; + if (( n = xmlGetChild( queryNode , "name" ))!=NULL && xmlGetText( n )) + r->software = mir_tstrdup( xmlGetText( n )); + if (( n = xmlGetChild( queryNode , "version" ))!=NULL && xmlGetText( n )) + r->version = mir_tstrdup( xmlGetText( n )); + if (( n = xmlGetChild( queryNode , "os" ))!=NULL && xmlGetText( n )) + r->system = mir_tstrdup( xmlGetText( n )); + } + + GetResourceCapabilites( pInfo->GetFrom(), TRUE ); + if ( pInfo->GetHContact()) + UpdateMirVer( pInfo->GetHContact(), r ); + + JabberUserInfoUpdate(pInfo->GetHContact()); +} + +BOOL CJabberProto::OnProcessJingle( HXML node ) +{ + LPCTSTR type; + HXML child = xmlGetChildByTag( node, _T("jingle"), _T("xmlns"), _T(JABBER_FEAT_JINGLE)); + + if ( child ) { + if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return FALSE; + if (( !_tcscmp( type, _T("get")) || !_tcscmp( type, _T("set")))) { + LPCTSTR szAction = xmlGetAttrValue( child, _T("action")); + LPCTSTR idStr = xmlGetAttrValue( node, _T("id")); + LPCTSTR from = xmlGetAttrValue( node, _T("from")); + if ( szAction && !_tcscmp( szAction, _T("session-initiate"))) { + // if this is a Jingle 'session-initiate' and noone processed it yet, reply with "unsupported-applications" + m_ThreadInfo->send( XmlNodeIq( _T("result"), idStr, from )); + + XmlNodeIq iq( _T("set"), SerialNext(), from ); + HXML jingleNode = iq << XCHILDNS( _T("jingle"), _T(JABBER_FEAT_JINGLE)); + + jingleNode << XATTR( _T("action"), _T("session-terminate")); + LPCTSTR szInitiator = xmlGetAttrValue( child, _T("initiator")); + if ( szInitiator ) + jingleNode << XATTR( _T("initiator"), szInitiator ); + LPCTSTR szSid = xmlGetAttrValue( child, _T("sid")); + if ( szSid ) + jingleNode << XATTR( _T("sid"), szSid ); + + jingleNode << XCHILD( _T("reason")) + << XCHILD( _T("unsupported-applications")); + m_ThreadInfo->send( iq ); + return TRUE; + } + else { + // if it's something else than 'session-initiate' and noone processed it yet, reply with "unknown-session" + XmlNodeIq iq( _T("error"), idStr, from ); + HXML errNode = iq << XCHILD( _T("error")); + errNode << XATTR( _T("type"), _T("cancel")); + errNode << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + errNode << XCHILDNS( _T("unknown-session"), _T("urn:xmpp:jingle:errors:1")); + m_ThreadInfo->send( iq ); + return TRUE; + } + } + } + return FALSE; +} + +void CJabberProto::OnProcessIq( HXML node ) +{ + HXML queryNode; + const TCHAR *type, *xmlns; + JABBER_IQ_PFUNC pfunc; + + if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("iq"))) return; + if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return; + + int id = JabberGetPacketID( node ); + const TCHAR* idStr = xmlGetAttrValue( node, _T("id")); + + queryNode = xmlGetChild( node , "query" ); + xmlns = xmlGetAttrValue( queryNode, _T("xmlns")); + + // new match by id + if ( m_iqManager.HandleIq( id, node )) + return; + + // new iq handler engine + if ( m_iqManager.HandleIqPermanent( node )) + return; + + // Jingle support + if ( OnProcessJingle( node )) + return; + + ///////////////////////////////////////////////////////////////////////// + // OLD MATCH BY ID + ///////////////////////////////////////////////////////////////////////// + if ( ( !_tcscmp( type, _T("result")) || !_tcscmp( type, _T("error"))) && (( pfunc=JabberIqFetchFunc( id )) != NULL )) { + Log( "Handling iq request for id=%d", id ); + (this->*pfunc)( node ); + return; + } + // RECVED: <iq type='error'> ... + else if ( !_tcscmp( type, _T("error"))) { + Log( "XXX on entry" ); + // Check for file transfer deny by comparing idStr with ft->iqId + LISTFOREACH(i, this, LIST_FILE) + { + JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); + if ( item->ft != NULL && item->ft->state == FT_CONNECTING && !_tcscmp( idStr, item->ft->iqId )) { + Log( "Denying file sending request" ); + item->ft->state = FT_DENIED; + if ( item->ft->hFileEvent != NULL ) + SetEvent( item->ft->hFileEvent ); // Simulate the termination of file server connection + } + } } + else if (( !_tcscmp( type, _T("get")) || !_tcscmp( type, _T("set")))) { + XmlNodeIq iq( _T("error"), idStr, xmlGetAttrValue( node, _T("from"))); + + HXML pFirstChild = xmlGetChild( node , 0 ); + if ( pFirstChild ) + xmlAddChild( iq, pFirstChild ); + + iq << XCHILD( _T("error")) << XATTR( _T("type"), _T("cancel")) + << XCHILDNS( _T("service-unavailable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); + m_ThreadInfo->send( iq ); + } +} + +void CJabberProto::OnProcessRegIq( HXML node, ThreadData* info ) +{ + HXML errorNode; + const TCHAR *type; + + if ( !xmlGetName( node ) || _tcscmp( xmlGetName( node ), _T("iq"))) return; + if (( type=xmlGetAttrValue( node, _T("type"))) == NULL ) return; + + int id = JabberGetPacketID( node ); + + if ( !_tcscmp( type, _T("result"))) { + + // RECVED: result of the request for registration mechanism + // ACTION: send account registration information + if ( id == iqIdRegGetReg ) { + iqIdRegSetReg = SerialNext(); + + XmlNodeIq iq( _T("set"), iqIdRegSetReg ); + HXML query = iq << XQUERY( _T(JABBER_FEAT_REGISTER)); + query << XCHILD( _T("password"), info->password ); + query << XCHILD( _T("username"), info->username ); + info->send( iq ); + + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 75, ( LPARAM )TranslateT( "Sending registration information..." )); + } + // RECVED: result of the registration process + // ACTION: account registration successful + else if ( id == iqIdRegSetReg ) { + info->send( "</stream:stream>" ); + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" )); + info->reg_done = TRUE; + } } + + else if ( !_tcscmp( type, _T("error"))) { + errorNode = xmlGetChild( node , "error" ); + TCHAR* str = JabberErrorMsg( errorNode ); + SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str ); + mir_free( str ); + info->reg_done = TRUE; + info->send( "</stream:stream>" ); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// ThreadData constructor & destructor + +ThreadData::ThreadData( CJabberProto* aproto, JABBER_SESSION_TYPE parType ) +{ + memset( this, 0, sizeof( *this )); + type = parType; + proto = aproto; + iomutex = CreateMutex(NULL, FALSE, NULL); +} + +ThreadData::~ThreadData() +{ + if ( auth ) delete auth; + mir_free( zRecvData ); + CloseHandle( iomutex ); + CloseHandle(hThread); +} + +void ThreadData::close( void ) +{ + if ( s ) { + Netlib_CloseHandle(s); + s = NULL; +} } + +void ThreadData::shutdown( void ) +{ + if ( s ) + Netlib_Shutdown(s); +} + +int ThreadData::recvws( char* buf, size_t len, int flags ) +{ + if ( this == NULL ) + return 0; + + return proto->WsRecv( s, buf, (int)len, flags ); +} + +int ThreadData::recv( char* buf, size_t len ) +{ + if ( useZlib ) + return zlibRecv( buf, (long)len ); + + return recvws( buf, len, MSG_DUMPASTEXT ); +} + +int ThreadData::sendws( char* buffer, size_t bufsize, int flags ) +{ + return proto->WsSend( s, buffer, (int)bufsize, flags ); +} + +int ThreadData::send( char* buffer, int bufsize ) +{ + if ( this == NULL ) + return 0; + + int result; + + WaitForSingleObject( iomutex, 6000 ); + + if ( useZlib ) + result = zlibSend( buffer, bufsize ); + else + result = sendws( buffer, bufsize, MSG_DUMPASTEXT ); + + ReleaseMutex( iomutex ); + return result; +} + +// Caution: DO NOT use ->send() to send binary ( non-string ) data +int ThreadData::send( HXML node ) +{ + if ( this == NULL ) + return 0; + + while ( HXML parent = xi.getParent( node )) + node = parent; + + if ( proto->m_sendManager.HandleSendPermanent( node, this )) + return 0; + + proto->OnConsoleProcessXml(node, JCPF_OUT); + + TCHAR* str = xi.toString( node, NULL ); + + // strip forbidden control characters from outgoing XML stream + TCHAR *q = str; + for (TCHAR *p = str; *p; ++p) { + + WCHAR c = *p; + + if (c < 0x9 || c > 0x9 && c < 0xA || c > 0xA && c < 0xD || c > 0xD && c < 0x20 || c > 0xD7FF && c < 0xE000 || c > 0xFFFD) + continue; + + *q++ = *p; + } + *q = 0; + + + char* utfStr = mir_utf8encodeT( str ); + int result = send( utfStr, (int)strlen( utfStr )); + mir_free( utfStr ); + + xi.freeMem( str ); + return result; +} + +int ThreadData::send( const char* fmt, ... ) +{ + if ( this == NULL ) + return 0; + + va_list vararg; + va_start( vararg, fmt ); + int size = 512; + char* str = ( char* )mir_alloc( size ); + while ( _vsnprintf( str, size, fmt, vararg ) == -1 ) { + size += 512; + str = ( char* )mir_realloc( str, size ); + } + va_end( vararg ); + + int result = send( str, (int)strlen( str )); + + mir_free( str ); + return result; +} diff --git a/protocols/JabberG/src/jabber_treelist.cpp b/protocols/JabberG/src/jabber_treelist.cpp new file mode 100644 index 0000000000..8e1e28cb45 --- /dev/null +++ b/protocols/JabberG/src/jabber_treelist.cpp @@ -0,0 +1,583 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#define TLIF_VISIBLE 0x01 +#define TLIF_EXPANDED 0x02 +#define TLIF_MODIFIED 0x04 +#define TLIF_ROOT 0X08 +#define TLIF_HASITEM 0X10 +#define TLIF_REBUILD 0x20 +#define TLIF_FAKEPARENT 0x40 +#define TLIF_FILTERED 0x80 + +struct TTreeList_ItemInfo +{ + BYTE flags; + int indent, sortIndex; + + struct TTreeList_ItemInfo *parent; + int iIcon, iOverlay; + LIST<TCHAR> text; + LPARAM data; + LIST<TTreeList_ItemInfo> subItems; + + TTreeList_ItemInfo(int columns = 3, int children = 5): + text(columns), subItems(children), parent(NULL), + flags(0), indent(0), sortIndex(0), iIcon(0), iOverlay(0), data(0) {} + ~TTreeList_ItemInfo() + { + int i; + for (i = text.getCount(); i--; ) + mir_free(text[i]); + text.destroy(); + for (i = subItems.getCount(); i--; ) + delete subItems[i]; + subItems.destroy(); + } +}; + +struct TTreeList_Data +{ + int mode, sortMode; + TCHAR *filter; + HTREELISTITEM hItemSelected; + TTreeList_ItemInfo *root; + + TTreeList_Data() + { + sortMode = 0; + filter = NULL; + mode = TLM_TREE; + root = NULL; + } + ~TTreeList_Data() + { + if (root) delete root; + if (filter) mir_free(filter); + } +}; + +// static utilities +static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data); +static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data); +static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data); +static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data); +static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data); +static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); + +static __forceinline void sttTreeList_SeWindowData(HWND hwnd, HANDLE data) +{ + SetPropA(hwnd, "Miranda.TreeList", (HANDLE)data); +} + +static __forceinline HANDLE sttTreeList_GeWindowData(HWND hwnd) +{ + return GetPropA(hwnd, "Miranda.TreeList"); +} + +// tree list implementation +LPARAM TreeList_GetData(HTREELISTITEM hItem) +{ + return hItem->data; +} + +HTREELISTITEM TreeList_GetRoot(HWND hwnd) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + return data->root; +} + +int TreeList_GetChildrenCount(HTREELISTITEM hItem) +{ + return hItem->subItems.getCount(); +} + +HTREELISTITEM TreeList_GetChild(HTREELISTITEM hItem, int i) +{ + return hItem->subItems[i]; +} + +void TreeList_Create(HWND hwnd) +{ + TTreeList_Data *data = new TTreeList_Data; + data->root = new TTreeList_ItemInfo; + data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT; + data->root->indent = -1; + data->hItemSelected = data->root; + sttTreeList_SeWindowData(hwnd, data); + + ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES | LVS_EX_INFOTIP ); + + HIMAGELIST hIml; + hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1); + ListView_SetImageList (hwnd, hIml, LVSIL_SMALL); + + hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1); + ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPOPEN, 0 )); + ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPSHUT, 0 )); + ImageList_AddIcon_Icolib(hIml, (HICON)CallService( MS_SKIN_LOADICON, SKINICON_OTHER_DOWNARROW, 0 )); + ListView_SetImageList (hwnd, hIml, LVSIL_STATE); +} + +void TreeList_Destroy(HWND hwnd) +{ + ListView_DeleteAllItems(hwnd); + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + delete data; +} + +void TreeList_Reset(HWND hwnd) +{ + ListView_DeleteAllItems(hwnd); + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + delete data->root; + data->root = new TTreeList_ItemInfo; + data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT; + data->root->indent = -1; + data->hItemSelected = data->root; +} + +void TreeList_SetMode(HWND hwnd, int mode) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + data->mode = mode; + ListView_DeleteAllItems(hwnd); + TreeList_Update(hwnd); +} + +void TreeList_SetSortMode(HWND hwnd, int col, BOOL descending) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + if ((col >= 0) && (col < 2)) + data->sortMode = 1 + col * 2 + (descending ? 1 : 0); + else + data->sortMode = 0; + TreeList_Update(hwnd); +} + +void TreeList_SetFilter(HWND hwnd, TCHAR *filter) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + if (data->filter) mir_free(data->filter); + data->filter = NULL; + if (filter) data->filter = mir_tstrdup(filter); + TreeList_Update(hwnd); +} + +HTREELISTITEM TreeList_GetActiveItem(HWND hwnd) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED); + if (lvi.iItem < 0) + return (data->hItemSelected->flags & TLIF_ROOT) ? NULL : data->hItemSelected; + ListView_GetItem(hwnd, &lvi); + return (HTREELISTITEM)lvi.lParam; +} + +HTREELISTITEM TreeList_AddItem(HWND hwnd, HTREELISTITEM hParent, TCHAR *text, LPARAM nodeDdata) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + if (!hParent) hParent = data->root; + + TTreeList_ItemInfo *item = new TTreeList_ItemInfo; + item->data = nodeDdata; + item->parent = hParent; + item->text.insert(mir_tstrdup(text)); + item->flags |= TLIF_MODIFIED; + if (hParent->flags & TLIF_ROOT) + { + item->flags |= TLIF_EXPANDED; + data->hItemSelected = item; + } + item->indent = hParent->indent+1; + hParent->subItems.insert(item); + return item; +} + +void TreeList_ResetItem(HWND hwnd, HTREELISTITEM hParent) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + + for (int i = hParent->subItems.getCount(); i--; ) + delete hParent->subItems[i]; + hParent->subItems.destroy(); + + data->hItemSelected = hParent; + ListView_DeleteAllItems(hwnd); +} + +void TreeList_MakeFakeParent(HTREELISTITEM hItem, BOOL flag) +{ + if (flag) + hItem->flags |= TLIF_FAKEPARENT; + else + hItem->flags &= ~TLIF_FAKEPARENT; + hItem->flags |= TLIF_MODIFIED; +} + +void TreeList_AppendColumn(HTREELISTITEM hItem, TCHAR *text) +{ + hItem->text.insert(mir_tstrdup(text)); + hItem->flags |= TLIF_MODIFIED; +} + +int TreeList_AddIcon(HWND hwnd, HICON hIcon, int iOverlay) +{ + HIMAGELIST hIml = ListView_GetImageList(hwnd, LVSIL_SMALL); + int idx = ImageList_AddIcon(hIml, hIcon); + g_ReleaseIcon(hIcon); + if (iOverlay) ImageList_SetOverlayImage(hIml, idx, iOverlay); + return idx; +} + +void TreeList_SetIcon(HTREELISTITEM hItem, int iIcon, int iOverlay) +{ + if (iIcon >= 0) hItem->iIcon = iIcon; + if (iOverlay >= 0) hItem->iOverlay = iOverlay; + if ((iIcon >= 0) || (iOverlay >= 0)) hItem->flags |= TLIF_MODIFIED; +} + +void TreeList_RecursiveApply(HTREELISTITEM hItem, void (*func)(HTREELISTITEM, LPARAM), LPARAM data) +{ + for ( int i = 0; i < hItem->subItems.getCount(); i++ ) { + func( hItem->subItems[i], data ); + TreeList_RecursiveApply( hItem->subItems[i], func, data ); +} } + +void TreeList_Update(HWND hwnd) +{ + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd); + HTREELISTITEM hItem = data->root; + int sortIndex = 0; + + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + if (data->sortMode) + TreeList_RecursiveApply(hItem, sttTreeList_SortItems, (LPARAM)data->sortMode); + TreeList_RecursiveApply(hItem, sttTreeList_ResetIndex, (LPARAM)&sortIndex); + if (data->filter) + TreeList_RecursiveApply(hItem, sttTreeList_FilterItems, (LPARAM)data->filter); + for ( int i = ListView_GetItemCount(hwnd); i--; ) { + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = i; + lvi.iSubItem = 0; + ListView_GetItem(hwnd, &lvi); + + HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam; + if (( ptli->flags & TLIF_VISIBLE ) && (!data->filter || ( ptli->flags & TLIF_FILTERED ))) { + ptli->flags |= TLIF_HASITEM; + if ( ptli->flags & TLIF_MODIFIED ) { + lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE | LVIF_TEXT; + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.pszText = ptli->text[0]; + lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; + lvi.iImage = ptli->iIcon; + if (data->mode == TLM_TREE) + { + lvi.state = + INDEXTOSTATEIMAGEMASK( + ((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 : + (ptli->flags & TLIF_EXPANDED) ? 1 : 2 ) | + INDEXTOOVERLAYMASK( ptli->iOverlay ); + } else + { + lvi.state = + INDEXTOSTATEIMAGEMASK( + ((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) | + INDEXTOOVERLAYMASK( ptli->iOverlay ); + } + ListView_SetItem(hwnd, &lvi); + for (int j = 1; j < ptli->text.getCount(); ++j) + ListView_SetItemText( hwnd, i, j, ptli->text[j]); + } + } + else ListView_DeleteItem(hwnd, i); + } + if (data->mode == TLM_TREE) + TreeList_RecursiveApply(hItem, sttTreeList_CreateItems, (LPARAM)hwnd); + else + { + for (int i = data->hItemSelected->subItems.getCount(); i--; ) + sttTreeList_CreateItems_List(data->hItemSelected->subItems[i], (LPARAM)hwnd); + for (HTREELISTITEM hItem = data->hItemSelected; !(hItem->flags & TLIF_ROOT); hItem = hItem->parent) + sttTreeList_CreateItems_List(hItem, (LPARAM)hwnd); + } + ListView_SortItems(hwnd, sttTreeList_SortFunc, 0); + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + UpdateWindow(hwnd); +} + +BOOL TreeList_ProcessMessage(HWND hwnd, UINT msg, WPARAM, LPARAM lparam, UINT idc, BOOL* ) +{ + LVITEM lvi = {0}; + + switch (msg) { + case WM_NOTIFY: + { + if (((LPNMHDR)lparam)->idFrom != idc) + break; + + TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(GetDlgItem(hwnd, idc)); + switch (((LPNMHDR)lparam)->code) { + case LVN_COLUMNCLICK: + { + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam; + TreeList_SetSortMode(lpnmlv->hdr.hwndFrom, lpnmlv->iSubItem, FALSE); + } + break; + + case LVN_ITEMACTIVATE: + if (data->mode == TLM_REPORT) { + LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam; + lvi.mask = LVIF_PARAM; + lvi.iItem = lpnmia->iItem; + ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi); + + HTREELISTITEM hItem = (lvi.iItem < 0) ? data-> root : (HTREELISTITEM)lvi.lParam; + if (!hItem->subItems.getCount() && !(hItem->flags & TLIF_FAKEPARENT)) break; + data->hItemSelected = hItem; + + NMTREEVIEW nmtv; + nmtv.hdr.code = TVN_ITEMEXPANDED; + nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom; + nmtv.hdr.idFrom = lpnmia->hdr.idFrom; + nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam; + SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv); + + if (data->mode == TLM_REPORT) + { + ListView_DeleteAllItems(lpnmia->hdr.hwndFrom); + TreeList_Update(lpnmia->hdr.hwndFrom); + } + } + break; + + case LVN_KEYDOWN: + if (data->mode == TLM_TREE) { + LPNMLVKEYDOWN lpnmlvk = (LPNMLVKEYDOWN)lparam; + + lvi.mask = LVIF_PARAM|LVIF_INDENT; + lvi.iItem = ListView_GetNextItem(lpnmlvk->hdr.hwndFrom, -1, LVNI_SELECTED); + if (lvi.iItem < 0) return FALSE; + lvi.iSubItem = 0; + ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi); + HTREELISTITEM hItem = (HTREELISTITEM)lvi.lParam; + + switch (lpnmlvk->wVKey) { + case VK_SUBTRACT: + case VK_LEFT: + { + if ( hItem->subItems.getCount() && (hItem->flags & TLIF_EXPANDED )) { + hItem->flags &= ~TLIF_EXPANDED; + hItem->flags |= TLIF_MODIFIED; + TreeList_Update( lpnmlvk->hdr.hwndFrom ); + } + else if ( hItem->indent && (lpnmlvk->wVKey != VK_SUBTRACT )) { + for ( int i = lvi.iItem; i--; ) { + lvi.mask = LVIF_INDENT; + lvi.iItem = i; + lvi.iSubItem = 0; + ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi); + if (lvi.iIndent < hItem->indent) { + lvi.mask = LVIF_STATE; + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.state = lvi.stateMask = LVIS_FOCUSED|LVNI_SELECTED; + ListView_SetItem(lpnmlvk->hdr.hwndFrom, &lvi); + break; + } } } + break; + } + + case VK_ADD: + case VK_RIGHT: + if ( (hItem->subItems.getCount() || (hItem->flags & TLIF_FAKEPARENT)) && + !( hItem->flags & TLIF_EXPANDED )) + { + hItem->flags |= TLIF_EXPANDED; + hItem->flags |= TLIF_MODIFIED; + + NMTREEVIEW nmtv; + nmtv.hdr.code = TVN_ITEMEXPANDED; + nmtv.hdr.hwndFrom = lpnmlvk->hdr.hwndFrom; + nmtv.hdr.idFrom = lpnmlvk->hdr.idFrom; + nmtv.itemNew.hItem = (HTREEITEM)hItem; + SendMessage(hwnd, WM_NOTIFY, lpnmlvk->hdr.idFrom, (LPARAM)&nmtv); + TreeList_Update( lpnmlvk->hdr.hwndFrom ); + } + break; + } } + break; + + case NM_CLICK: + if (data->mode == TLM_TREE) { + LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam; + LVHITTESTINFO lvhti = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = lpnmia->iItem; + ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi); + lvhti.pt = lpnmia->ptAction; + ListView_HitTest(lpnmia->hdr.hwndFrom, &lvhti); + + HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam; + if ((lvhti.iSubItem == 0) && ( (lvhti.flags&LVHT_ONITEM) == LVHT_ONITEMSTATEICON ) && + (ptli->subItems.getCount() || ptli->flags & TLIF_FAKEPARENT)) + { + if ( ptli->flags & TLIF_EXPANDED ) + ptli->flags &= ~TLIF_EXPANDED; + else { + ptli->flags |= TLIF_EXPANDED; + + NMTREEVIEW nmtv; + nmtv.hdr.code = TVN_ITEMEXPANDED; + nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom; + nmtv.hdr.idFrom = lpnmia->hdr.idFrom; + nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam; + SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv); + } + ptli->flags |= TLIF_MODIFIED; + TreeList_Update( lpnmia->hdr.hwndFrom ); + } } + break; + } + break; + } } + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////// +static int sttTreeList_SortItems_Cmp0(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); } +static int sttTreeList_SortItems_Cmp1(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); } +static int sttTreeList_SortItems_Cmp2(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); } +static int sttTreeList_SortItems_Cmp3(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); } +static int sttTreeList_SortItems_Cmp4(const void *p1, const void *p2) { return lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); } +static int sttTreeList_SortItems_Cmp5(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); } + +static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data) +{ + if (!hItem->subItems.getCount()) return; + + typedef int (__cdecl *TQSortCmp)(const void *, const void *); + static TQSortCmp funcs[] = + { + sttTreeList_SortItems_Cmp0, + sttTreeList_SortItems_Cmp1, + sttTreeList_SortItems_Cmp2, + sttTreeList_SortItems_Cmp3, + sttTreeList_SortItems_Cmp4, + sttTreeList_SortItems_Cmp5, + }; + qsort(((SortedList *)&hItem->subItems)->items, hItem->subItems.getCount(), sizeof(void *), funcs[data-1]); +} + +static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data) +{ + hItem->flags &= ~TLIF_HASITEM; + + if ( !hItem->parent || (hItem->parent->flags & TLIF_VISIBLE) && (hItem->parent->flags & TLIF_EXPANDED )) + hItem->flags |= TLIF_VISIBLE; + else + hItem->flags &= ~TLIF_VISIBLE; + + hItem->sortIndex = (*(int *)data)++; +} + +static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data) +{ + int i = 0; + for (i = 0; i < hItem->text.getCount(); ++i) + if (JabberStrIStr(hItem->text[i], (TCHAR *)data)) + break; + + if (i < hItem->text.getCount()) + { + while (!(hItem->flags & TLIF_ROOT)) + { + hItem->flags |= TLIF_FILTERED; + hItem = hItem->parent; + } + } else + { + hItem->flags &= ~TLIF_FILTERED; + } +} + +static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data) +{ + TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data); + if (( hItem->flags & TLIF_VISIBLE ) && (!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) { + LVITEM lvi = {0}; + lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE; + lvi.iIndent = hItem->indent; + lvi.lParam = (LPARAM)hItem; + lvi.pszText = hItem->text[0]; + lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; + lvi.iImage = hItem->iIcon; + lvi.state = + INDEXTOSTATEIMAGEMASK( + ((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 : + (hItem->flags & TLIF_EXPANDED) ? 1 : 2 ) | + INDEXTOOVERLAYMASK(hItem->iOverlay); + + int idx = ListView_InsertItem((HWND)data, &lvi); + for ( int i = 1; i < hItem->text.getCount(); i++ ) + ListView_SetItemText((HWND)data, idx, i, hItem->text[i]); +} } + +static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data) +{ + TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data); + if ((!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) { + LVITEM lvi = {0}; + lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE; + lvi.iIndent = hItem->indent; + lvi.lParam = (LPARAM)hItem; + lvi.pszText = hItem->text[0]; + lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK; + lvi.iImage = hItem->iIcon; + lvi.state = + INDEXTOSTATEIMAGEMASK( + ((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) | + INDEXTOOVERLAYMASK( hItem->iOverlay ); + + int idx = ListView_InsertItem((HWND)data, &lvi); + for ( int i = 1; i < hItem->text.getCount(); i++ ) + ListView_SetItemText((HWND)data, idx, i, hItem->text[i]); +} } + +static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM ) +{ + HTREELISTITEM p1 = ( HTREELISTITEM )lParam1, p2 = ( HTREELISTITEM )lParam2; + if ( p1->sortIndex < p2->sortIndex ) + return -1; + + if ( p1->sortIndex > p2->sortIndex ) + return +1; + + return 0; +} diff --git a/protocols/JabberG/src/jabber_userinfo.cpp b/protocols/JabberG/src/jabber_userinfo.cpp new file mode 100644 index 0000000000..9d8b476851 --- /dev/null +++ b/protocols/JabberG/src/jabber_userinfo.cpp @@ -0,0 +1,896 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "m_icolib.h" + +#include <fcntl.h> +#include <io.h> +#include <sys/stat.h> + +#include "jabber_list.h" + +static HANDLE hUserInfoList = NULL; + +struct UserInfoStringBuf +{ + enum { STRINGBUF_INCREMENT = 1024 }; + + TCHAR *buf; + int size; + int offset; + + UserInfoStringBuf() { buf = 0; size = 0; offset = 0; } + ~UserInfoStringBuf() { mir_free(buf); } + + void append( TCHAR *str ) { + if ( !str ) return; + + int length = lstrlen( str ); + if ( size - offset < length + 1 ) { + size += ( length + STRINGBUF_INCREMENT ); + buf = ( TCHAR * )mir_realloc( buf, size * sizeof( TCHAR )); + } + lstrcpy( buf + offset, str ); + offset += length; + } + + TCHAR *allocate( int length ) { + if ( size - offset < length ) { + size += ( length + STRINGBUF_INCREMENT ); + buf = ( TCHAR * )mir_realloc( buf, size * sizeof( TCHAR )); + } + return buf + offset; + } + + void actualize() { + if ( buf ) offset = lstrlen( buf ); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberUserInfoDlgProc - main user info dialog + +struct JabberUserInfoDlgData +{ + CJabberProto* ppro; + HANDLE hContact; + JABBER_LIST_ITEM* item; + int resourceCount; +}; + +enum +{ + INFOLINE_DELETE = 0x80000000, + INFOLINE_MASK = 0x7fffffff, + INFOLINE_BAD_ID = 0x7fffffff, + + INFOLINE_NAME = 1, + INFOLINE_MOOD, + INFOLINE_ACTIVITY, + INFOLINE_TUNE, + INFOLINE_OFFLINE, + INFOLINE_MESSAGE, + INFOLINE_SOFTWARE, + INFOLINE_VERSION, + INFOLINE_SYSTEM, + INFOLINE_PRIORITY, + INFOLINE_IDLE, + INFOLINE_CAPS, + INFOLINE_SOFTWARE_INFORMATION, + INFOLINE_SUBSCRIPTION, + INFOLINE_LOGOFF, + INFOLINE_LOGOFF_MSG, + INFOLINE_LASTACTIVE, +}; + +__forceinline DWORD sttInfoLineId(DWORD res, DWORD type, DWORD line=0) +{ + return + ( type << 24 ) & 0x7f000000 | + ( res << 12 ) & 0x00fff000 | + ( line ) & 0x00000fff; +} + +static HTREEITEM sttFindInfoLine( HWND hwndTree, HTREEITEM htiRoot, LPARAM id=INFOLINE_BAD_ID ) +{ + if ( id == INFOLINE_BAD_ID ) return NULL; + for (HTREEITEM hti = TreeView_GetChild(hwndTree, htiRoot); hti; hti = TreeView_GetNextSibling(hwndTree, hti)) + { + TVITEMEX tvi = {0}; + tvi.mask = TVIF_HANDLE|TVIF_PARAM; + tvi.hItem = hti; + TreeView_GetItem(hwndTree, &tvi); + if ((tvi.lParam&INFOLINE_MASK) == (id&INFOLINE_MASK)) + return hti; + } + return NULL; +} + +void sttCleanupInfo(HWND hwndTree, int stage) +{ + HTREEITEM hItem = TreeView_GetRoot(hwndTree); + while (hItem) { + TVITEMEX tvi = {0}; + tvi.mask = TVIF_HANDLE|TVIF_PARAM; + tvi.hItem = hItem; + TreeView_GetItem(hwndTree, &tvi); + + switch (stage) { + case 0: + tvi.lParam |= INFOLINE_DELETE; + TreeView_SetItem(hwndTree, &tvi); + break; + + case 1: + if (tvi.lParam & INFOLINE_DELETE) { + hItem = TreeView_GetNextSibling(hwndTree, hItem); + TreeView_DeleteItem(hwndTree, tvi.hItem); + continue; + } + break; + } + + HTREEITEM hItemTmp = 0; + if (hItemTmp = TreeView_GetChild(hwndTree, hItem)) + hItem = hItemTmp; + else if (hItemTmp = TreeView_GetNextSibling(hwndTree, hItem)) + hItem = hItemTmp; + else { + while (1) { + if (!(hItem = TreeView_GetParent(hwndTree, hItem))) break; + if (hItemTmp = TreeView_GetNextSibling(hwndTree, hItem)) { + hItem = hItemTmp; + break; + } + } + } + } +} + +static HTREEITEM sttFillInfoLine( HWND hwndTree, HTREEITEM htiRoot, HICON hIcon, TCHAR *title, TCHAR *value, LPARAM id=INFOLINE_BAD_ID, bool expand=false ) +{ + HTREEITEM hti = sttFindInfoLine(hwndTree, htiRoot, id); + + TCHAR buf[256]; + if ( title ) + mir_sntprintf( buf, SIZEOF(buf), _T("%s: %s"), title, value ); + else + lstrcpyn( buf, value, SIZEOF( buf )); + + TVINSERTSTRUCT tvis = {0}; + tvis.hParent = htiRoot; + tvis.hInsertAfter = TVI_LAST; + tvis.itemex.mask = TVIF_TEXT|TVIF_PARAM; + tvis.itemex.pszText = buf; + tvis.itemex.lParam = id; + + if ( hIcon ) { + HIMAGELIST himl = TreeView_GetImageList( hwndTree, TVSIL_NORMAL ); + tvis.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvis.itemex.iImage = + tvis.itemex.iSelectedImage = ImageList_AddIcon( himl, hIcon ); + g_ReleaseIcon( hIcon ); + } + + if ( hti ) { + tvis.itemex.mask |= TVIF_HANDLE; + tvis.itemex.hItem = hti; + TreeView_SetItem( hwndTree, &tvis.itemex ); + } + else { + tvis.itemex.mask |= TVIF_STATE; + tvis.itemex.stateMask = TVIS_EXPANDED; + tvis.itemex.state = expand ? TVIS_EXPANDED : 0; + hti = TreeView_InsertItem( hwndTree, &tvis ); + } + + return hti; +} + +static void sttFillResourceInfo( CJabberProto* ppro, HWND hwndTree, HTREEITEM htiRoot, JABBER_LIST_ITEM *item, int resource ) +{ + TCHAR buf[256]; + HTREEITEM htiResource = htiRoot; + JABBER_RESOURCE_STATUS *res = resource ? &item->resource[resource-1] : &item->itemResource; + + if ( res->resourceName && *res->resourceName ) + htiResource = sttFillInfoLine( hwndTree, htiRoot, LoadSkinnedProtoIcon( ppro->m_szModuleName, res->status ), + TranslateT("Resource"), res->resourceName, sttInfoLineId(resource, INFOLINE_NAME), true ); + + // StatusMsg + sttFillInfoLine( hwndTree, htiResource, NULL /*LoadSkinnedIcon( SKINICON_EVENT_MESSAGE )*/, + TranslateT( "Message" ), res->statusMessage ? res->statusMessage : TranslateT( "<not specified>" ), + sttInfoLineId(resource, INFOLINE_MESSAGE)); + + // Software + HICON hIcon = NULL; + if (ServiceExists(MS_FP_GETCLIENTICONT)) { + if (res->software != NULL) { + mir_sntprintf(buf, SIZEOF(buf), _T("%s %s"), res->software, res->version); + hIcon = (HICON)CallService( MS_FP_GETCLIENTICONT, (WPARAM)buf, 0 ); + } } + + sttFillInfoLine( hwndTree, htiResource, hIcon, TranslateT( "Software" ), + res->software ? res->software : TranslateT( "<not specified>" ), + sttInfoLineId(resource, INFOLINE_SOFTWARE)); + + if(hIcon) + DestroyIcon(hIcon); + + // Version + sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "Version" ), + res->version ? res->version : TranslateT( "<not specified>" ), + sttInfoLineId(resource, INFOLINE_VERSION)); + + // System + sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "System" ), + res->system ? res->system : TranslateT( "<not specified>" ), + sttInfoLineId(resource, INFOLINE_SYSTEM)); + + // Resource priority + TCHAR szPriority[128]; + mir_sntprintf( szPriority, SIZEOF( szPriority ), _T("%d"), (int)res->priority ); + sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT( "Resource priority" ), szPriority, sttInfoLineId(resource, INFOLINE_PRIORITY)); + + // Idle + if ( res->idleStartTime > 0 ) { + lstrcpyn(buf, _tctime( &res->idleStartTime ), SIZEOF( buf )); + int len = lstrlen(buf); + if (len > 0) buf[len-1] = 0; + } + else if ( !res->idleStartTime ) + lstrcpyn(buf, TranslateT( "unknown" ), SIZEOF( buf )); + else + lstrcpyn(buf, TranslateT( "<not specified>" ), SIZEOF( buf )); + + sttFillInfoLine( hwndTree, htiResource, NULL, TranslateT("Idle since"), buf, sttInfoLineId(resource, INFOLINE_IDLE)); + + // caps + mir_sntprintf( buf, SIZEOF(buf), _T("%s/%s"), item->jid, res->resourceName ); + JabberCapsBits jcb = ppro->GetResourceCapabilites( buf, TRUE ); + + if ( !( jcb & JABBER_RESOURCE_CAPS_ERROR )) { + HTREEITEM htiCaps = sttFillInfoLine( hwndTree, htiResource, ppro->LoadIconEx( "main" ), NULL, TranslateT( "Client capabilities" ), sttInfoLineId(resource, INFOLINE_CAPS)); + int i; + for ( i = 0; g_JabberFeatCapPairs[i].szFeature; i++ ) + if ( jcb & g_JabberFeatCapPairs[i].jcbCap ) { + TCHAR szDescription[ 1024 ]; + if ( g_JabberFeatCapPairs[i].szDescription ) + mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s (%s)"), TranslateTS(g_JabberFeatCapPairs[i].szDescription), g_JabberFeatCapPairs[i].szFeature ); + else + mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s"), g_JabberFeatCapPairs[i].szFeature ); + sttFillInfoLine( hwndTree, htiCaps, NULL, NULL, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i)); + } + + for ( int j = 0; j < ppro->m_lstJabberFeatCapPairsDynamic.getCount(); j++, i++ ) + if ( jcb & ppro->m_lstJabberFeatCapPairsDynamic[j]->jcbCap ) { + TCHAR szDescription[ 1024 ]; + if ( ppro->m_lstJabberFeatCapPairsDynamic[j]->szDescription ) + mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s (%s)"), TranslateTS(ppro->m_lstJabberFeatCapPairsDynamic[j]->szDescription), ppro->m_lstJabberFeatCapPairsDynamic[j]->szFeature ); + else + mir_sntprintf( szDescription, SIZEOF( szDescription ), _T("%s"), ppro->m_lstJabberFeatCapPairsDynamic[j]->szFeature ); + sttFillInfoLine( hwndTree, htiCaps, NULL, NULL, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i)); + } + } + + // Software info + if ( res->pSoftwareInfo ) { + HTREEITEM htiSoftwareInfo = sttFillInfoLine( hwndTree, htiResource, ppro->LoadIconEx( "main" ), NULL, TranslateT( "Software information" ), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION)); + int nLineId = 0; + if ( res->pSoftwareInfo->szOs ) + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Operating system"), res->pSoftwareInfo->szOs, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + if ( res->pSoftwareInfo->szOsVersion ) + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Operating system version"), res->pSoftwareInfo->szOsVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + if ( res->pSoftwareInfo->szSoftware ) + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Software"), res->pSoftwareInfo->szSoftware, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + if ( res->pSoftwareInfo->szSoftwareVersion ) + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Software version"), res->pSoftwareInfo->szSoftwareVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + if ( res->pSoftwareInfo->szXMirandaCoreVersion ) { + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Miranda NG core version"), res->pSoftwareInfo->szXMirandaCoreVersion, sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Unicode build"), res->pSoftwareInfo->bXMirandaIsUnicode ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Alpha build"), res->pSoftwareInfo->bXMirandaIsAlpha ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + sttFillInfoLine( hwndTree, htiSoftwareInfo, NULL, TranslateT("Debug build"), res->pSoftwareInfo->bXMirandaIsDebug ? TranslateT("Yes") : TranslateT("No"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++)); + } + } +} + +static void sttFillAdvStatusInfo( CJabberProto* ppro, HWND hwndTree, HTREEITEM htiRoot, DWORD dwInfoLine, HANDLE hContact, TCHAR *szTitle, char *pszSlot ) +{ + char *szAdvStatusIcon = ppro->ReadAdvStatusA(hContact, pszSlot, ADVSTATUS_VAL_ICON); + TCHAR *szAdvStatusTitle = ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TITLE); + TCHAR *szAdvStatusText = ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TEXT); + + if (szAdvStatusIcon && szAdvStatusTitle && *szAdvStatusTitle) { + TCHAR szText[2048]; + if ( szAdvStatusText && *szAdvStatusText ) + mir_sntprintf(szText, 2047, _T("%s (%s)"), TranslateTS(szAdvStatusTitle), szAdvStatusText); + else + mir_sntprintf(szText, 2047, _T("%s"), TranslateTS(szAdvStatusTitle)); + sttFillInfoLine( hwndTree, htiRoot, (HICON)CallService(MS_SKIN2_GETICON, 0, + (LPARAM)szAdvStatusIcon), szTitle, szText, dwInfoLine); + } + + mir_free(szAdvStatusIcon); + mir_free(szAdvStatusTitle); + mir_free(szAdvStatusText); +} + +static void sttFillUserInfo( CJabberProto* ppro, HWND hwndTree, JABBER_LIST_ITEM *item ) +{ + SendMessage( hwndTree, WM_SETREDRAW, FALSE, 0 ); + + sttCleanupInfo(hwndTree, 0); + + HTREEITEM htiRoot = sttFillInfoLine( hwndTree, NULL, ppro->LoadIconEx( "main" ), _T( "JID" ), item->jid, sttInfoLineId(0, INFOLINE_NAME), true ); + TCHAR buf[256]; + + if (HANDLE hContact = ppro->HContactFromJID(item->jid)) { + sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_MOOD), hContact, TranslateT("Mood"), ADVSTATUS_MOOD ); + sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_ACTIVITY), hContact, TranslateT("Activity"), ADVSTATUS_ACTIVITY ); + sttFillAdvStatusInfo( ppro, hwndTree, htiRoot, sttInfoLineId(0, INFOLINE_TUNE), hContact, TranslateT("Tune"), ADVSTATUS_TUNE ); + } + + // subscription + switch ( item->subscription ) { + case SUB_BOTH: + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "both" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); + break; + case SUB_TO: + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "to" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); + break; + case SUB_FROM: + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "from" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); + break; + default: + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Subscription" ), TranslateT( "none" ), sttInfoLineId(0, INFOLINE_SUBSCRIPTION)); + break; + } + + // logoff + if ( item->itemResource.idleStartTime > 0 ) { + lstrcpyn( buf, _tctime( &item->itemResource.idleStartTime ), SIZEOF( buf )); + int len = lstrlen(buf); + if (len > 0) buf[len-1] = 0; + } + else if ( !item->itemResource.idleStartTime ) + lstrcpyn( buf, TranslateT( "unknown" ), SIZEOF( buf )); + else + lstrcpyn( buf, TranslateT( "<not specified>" ), SIZEOF( buf )); + + sttFillInfoLine( hwndTree, htiRoot, NULL, + ( item->jid && _tcschr( item->jid, _T( '@' ))) ? TranslateT( "Last logoff time" ) : TranslateT( "Uptime"), buf, + sttInfoLineId(0, INFOLINE_LOGOFF)); + + // logoff msg + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Logoff message" ), + item->itemResource.statusMessage ? item->itemResource.statusMessage : TranslateT( "<not specified>" ), sttInfoLineId(0, INFOLINE_LOGOFF_MSG)); + + // activity + if (( item->lastSeenResource >= 0 ) && ( item->lastSeenResource < item->resourceCount )) + lstrcpyn( buf, item->resource[item->lastSeenResource].resourceName, SIZEOF( buf )); + else + lstrcpyn( buf, TranslateT( "<no information available>" ), SIZEOF( buf )); + + sttFillInfoLine( hwndTree, htiRoot, NULL, TranslateT( "Last active resource" ), buf, + sttInfoLineId(0, INFOLINE_LASTACTIVE)); + + // resources + if ( item->resourceCount ) { + for (int i = 0; i < item->resourceCount; ++i) + sttFillResourceInfo( ppro, hwndTree, htiRoot, item, i+1 ); + } + else if ( !_tcschr(item->jid, _T('@')) || (item->itemResource.status != ID_STATUS_OFFLINE)) + sttFillResourceInfo( ppro, hwndTree, htiRoot, item, 0 ); + + sttCleanupInfo(hwndTree, 1); + SendMessage( hwndTree, WM_SETREDRAW, TRUE, 0 ); + + RedrawWindow( hwndTree, NULL, NULL, RDW_INVALIDATE ); +} + +static void sttGetNodeText( HWND hwndTree, HTREEITEM hti, UserInfoStringBuf *buf, int indent = 0 ) +{ + for ( int i = 0; i < indent; ++i ) + buf->append( _T( "\t" )); + + TVITEMEX tvi = {0}; + tvi.mask = TVIF_HANDLE|TVIF_TEXT|TVIF_STATE; + tvi.hItem = hti; + tvi.cchTextMax = 256; + tvi.pszText = buf->allocate( tvi.cchTextMax ); + if (!TreeView_GetItem( hwndTree, &tvi )) { // failure, maybe item was removed... + buf->buf[ buf->offset ] = 0; + buf->actualize(); + return; + } + + buf->actualize(); + buf->append( _T( "\r\n" )); + + if ( tvi.state & TVIS_EXPANDED ) + for ( hti = TreeView_GetChild( hwndTree, hti ); hti; hti = TreeView_GetNextSibling( hwndTree, hti )) + sttGetNodeText( hwndTree, hti, buf, indent + 1 ); +} + +static INT_PTR CALLBACK JabberUserInfoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JabberUserInfoDlgData *dat = (JabberUserInfoDlgData *)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + // lParam is hContact + TranslateDialogDefault( hwndDlg ); + + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_OTHER_USERDETAILS)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS)); + + dat = (JabberUserInfoDlgData *)mir_alloc(sizeof(JabberUserInfoDlgData)); + ZeroMemory(dat, sizeof(JabberUserInfoDlgData)); + dat->resourceCount = -1; + + if ( CallService(MS_DB_CONTACT_IS, (WPARAM)lParam, 0 )) + dat->hContact = (HANDLE)lParam; + else if (!IsBadReadPtr((void *)lParam, sizeof(JABBER_LIST_ITEM))) { + dat->hContact = NULL; + dat->item = (JABBER_LIST_ITEM *)lParam; + } + + { + RECT rc; GetClientRect( hwndDlg, &rc ); + MoveWindow( GetDlgItem( hwndDlg, IDC_TV_INFO ), 5, 5, rc.right-10, rc.bottom-10, TRUE ); + + HIMAGELIST himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR|ILC_COLOR32|ILC_MASK, 5, 1); + ImageList_AddIcon_Icolib(himl, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT)); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TV_INFO), himl, TVSIL_NORMAL); + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + WindowList_Add(hUserInfoList, hwndDlg, dat->hContact); + } + break; + + case WM_JABBER_REFRESH: + if ( !dat ) break; + + if ( !dat->item ) { + DBVARIANT dbv = {0}; + if ( dat->ppro->JGetStringT(dat->hContact, "jid", &dbv)) + break; + + if (!(dat->item = dat->ppro->ListGetItemPtr(LIST_VCARD_TEMP, dbv.ptszVal))) + dat->item = dat->ppro->ListGetItemPtr(LIST_ROSTER, dbv.ptszVal); + + if (!dat->item) + { + HWND hwndTree = GetDlgItem(hwndDlg, IDC_TV_INFO); + TreeView_DeleteAllItems( hwndTree ); + HTREEITEM htiRoot = sttFillInfoLine( hwndTree, NULL, dat->ppro->LoadIconEx( "main" ), _T( "JID" ), dbv.ptszVal, sttInfoLineId(0, INFOLINE_NAME), true ); + sttFillInfoLine( hwndTree, htiRoot, dat->ppro->LoadIconEx("vcard"), NULL, + TranslateT("Please switch online to see more details.")); + + JFreeVariant(&dbv); + break; + } + + JFreeVariant(&dbv); + } + sttFillUserInfo( dat->ppro, GetDlgItem(hwndDlg, IDC_TV_INFO), dat->item); + break; + + case WM_SIZE: + MoveWindow(GetDlgItem(hwndDlg, IDC_TV_INFO), 5, 5, LOWORD(lParam)-10, HIWORD(lParam)-10, TRUE); + break; + + case WM_CONTEXTMENU: + if ( GetWindowLongPtr(( HWND )wParam, GWL_ID ) == IDC_TV_INFO ) { + HWND hwndTree = GetDlgItem( hwndDlg, IDC_TV_INFO ); + POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; + HTREEITEM hItem = 0; + + if (( pt.x == -1 ) && ( pt.y == -1 )) { + if (hItem = TreeView_GetSelection( hwndTree )) { + RECT rc; + TreeView_GetItemRect( hwndTree, hItem, &rc, TRUE ); + pt.x = rc.left; + pt.y = rc.bottom; + ClientToScreen( hwndTree, &pt ); + } + } + else { + TVHITTESTINFO tvhti = {0}; + tvhti.pt = pt; + ScreenToClient( hwndTree, &tvhti.pt ); + TreeView_HitTest( hwndTree, &tvhti ); + if ( tvhti.flags & TVHT_ONITEM ) { + hItem = tvhti.hItem; + TreeView_Select(hwndTree, hItem, TVGN_CARET); + } } + + if ( hItem ) { + HMENU hMenu = CreatePopupMenu(); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy")); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy only this value")); + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); + int nReturnCmd = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL ); + if ( nReturnCmd == 1 ) { + UserInfoStringBuf buf; + sttGetNodeText( hwndTree, hItem, &buf ); + JabberCopyText( hwndDlg, buf.buf ); + } + else if ( nReturnCmd == 2 ) { + TCHAR szBuffer[ 1024 ]; + TVITEMEX tvi = {0}; + tvi.mask = TVIF_HANDLE|TVIF_TEXT|TVIF_STATE; + tvi.hItem = hItem; + tvi.cchTextMax = SIZEOF( szBuffer ); + tvi.pszText = szBuffer; + if ( TreeView_GetItem( hwndTree, &tvi )) { + if (TCHAR *str = _tcsstr(szBuffer, _T(": "))) + JabberCopyText( hwndDlg, str+2 ); + else + JabberCopyText( hwndDlg, szBuffer ); + } } + DestroyMenu( hMenu ); + } } + break; + + case WM_NOTIFY: + if (( ( LPNMHDR )lParam )->idFrom == 0 ) { + switch (( ( LPNMHDR )lParam )->code ) { + case PSN_INFOCHANGED: + { + HANDLE hContact = ( HANDLE ) (( LPPSHNOTIFY ) lParam )->lParam; + SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, ( LPARAM )hContact ); + } + break; + + case PSN_PARAMCHANGED: + dat->ppro = ( CJabberProto* )( CJabberProto* )(( PSHNOTIFY* )lParam )->lParam; + if ( dat->hContact != NULL ) { + DBVARIANT dbv = {0}; + if ( dat->ppro->JGetStringT(dat->hContact, "jid", &dbv)) + break; + + if ( !(dat->item = dat->ppro->ListGetItemPtr( LIST_VCARD_TEMP, dbv.ptszVal ))) + dat->item = dat->ppro->ListGetItemPtr( LIST_ROSTER, dbv.ptszVal ); + JFreeVariant(&dbv); + } + break; + } } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + WindowList_Remove(hUserInfoList, hwndDlg); + if ( dat ) { + mir_free(dat); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + } + ImageList_Destroy(TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TV_INFO), NULL, TVSIL_NORMAL)); + WindowFreeIcon( hwndDlg ); + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberUserPhotoDlgProc - Jabber photo dialog + +struct USER_PHOTO_INFO +{ + HANDLE hContact; + HBITMAP hBitmap; + CJabberProto* ppro; +}; + +static INT_PTR CALLBACK JabberUserPhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + USER_PHOTO_INFO *photoInfo; + + photoInfo = ( USER_PHOTO_INFO * ) GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + // lParam is hContact + TranslateDialogDefault( hwndDlg ); + photoInfo = ( USER_PHOTO_INFO * ) mir_alloc( sizeof( USER_PHOTO_INFO )); + photoInfo->hContact = ( HANDLE ) lParam; + photoInfo->ppro = NULL; + photoInfo->hBitmap = NULL; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR ) photoInfo ); + SendDlgItemMessage( hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_SAVE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); + SendDlgItemMessage( hwndDlg, IDC_SAVE, BUTTONSETASFLATBTN, TRUE, 0); + ShowWindow( GetDlgItem( hwndDlg, IDC_LOAD ), SW_HIDE ); + ShowWindow( GetDlgItem( hwndDlg, IDC_DELETE ), SW_HIDE ); + break; + + case WM_NOTIFY: + switch ((( LPNMHDR )lParam )->idFrom ) { + case 0: + switch ((( LPNMHDR )lParam )->code ) { + case PSN_INFOCHANGED: + SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 ); + break; + + case PSN_PARAMCHANGED: + photoInfo->ppro = ( CJabberProto* )(( PSHNOTIFY* )lParam )->lParam; + break; + } + break; + } + break; + + case WM_JABBER_REFRESH: + { + JABBER_LIST_ITEM *item; + DBVARIANT dbv; + + if ( photoInfo->hBitmap ) { + DeleteObject( photoInfo->hBitmap ); + photoInfo->hBitmap = NULL; + } + ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE ); + if ( !photoInfo->ppro->JGetStringT( photoInfo->hContact, "jid", &dbv )) { + TCHAR* jid = dbv.ptszVal; + if (( item = photoInfo->ppro->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) + item = photoInfo->ppro->ListGetItemPtr( LIST_ROSTER, jid ); + if ( item != NULL ) { + if ( item->photoFileName ) { + photoInfo->ppro->Log( "Showing picture from " TCHAR_STR_PARAM, item->photoFileName ); + char* p = mir_t2a( item->photoFileName ); + photoInfo->hBitmap = ( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p ); + mir_free( p ); + JabberBitmapPremultiplyChannels(photoInfo->hBitmap); + ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_SHOW ); + } + } + JFreeVariant( &dbv ); + } + InvalidateRect( hwndDlg, NULL, TRUE ); + UpdateWindow( hwndDlg ); + } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDC_SAVE: + { + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + HANDLE hFile; + static TCHAR szFilter[512]; + unsigned char buffer[3]; + TCHAR szFileName[MAX_PATH]; + DWORD n; + + if ( photoInfo->ppro->JGetStringT( photoInfo->hContact, "jid", &dbv )) + break; + + TCHAR* jid = dbv.ptszVal; + if (( item = photoInfo->ppro->ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) + item = photoInfo->ppro->ListGetItemPtr( LIST_ROSTER, jid ); + if ( item != NULL ) { + if (( hFile=CreateFile( item->photoFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) { + if ( ReadFile( hFile, buffer, 3, &n, NULL ) && n==3 ) { + if ( !strncmp(( char* )buffer, "BM", 2 )) { + mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("BMP %s ( *.bmp )"), TranslateT( "format" )); + n = (DWORD)_tcslen( szFilter ); + _tcsncpy( szFilter+n+1, _T("*.BMP"), SIZEOF( szFilter )-n-2 ); + } + else if ( !strncmp(( char* )buffer, "GIF", 3 )) { + mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("GIF %s ( *.gif )"), TranslateT( "format" )); + n = (DWORD)_tcslen( szFilter ); + _tcsncpy( szFilter+n+1, _T("*.GIF"), SIZEOF( szFilter )-n-2 ); + } + else if ( buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff ) { + mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("JPEG %s ( *.jpg;*.jpeg )"), TranslateT( "format" )); + n = (DWORD)_tcslen( szFilter ); + _tcsncpy( szFilter+n+1, _T("*.JPG;*.JPEG"), SIZEOF( szFilter )-n-2 ); + } + else { + mir_sntprintf( szFilter, SIZEOF( szFilter ), _T("%s ( *.* )"), TranslateT( "Unknown format" )); + n = (DWORD)_tcslen( szFilter ); + _tcsncpy( szFilter+n+1, _T("*.*"), SIZEOF( szFilter )-n-2 ); + } + szFilter[SIZEOF( szFilter )-1] = 0; + + OPENFILENAME ofn = { 0 }; + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = _MAX_PATH; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = NULL; + ofn.Flags = OFN_OVERWRITEPROMPT; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = NULL; + ofn.lCustData = 0L; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + szFileName[0] = '\0'; + if ( GetSaveFileName( &ofn )) { + photoInfo->ppro->Log( "File selected is %s", szFileName ); + CopyFile( item->photoFileName, szFileName, FALSE ); + } + } + CloseHandle( hFile ); + } + } + JFreeVariant( &dbv ); + + } + break; + } + break; + + case WM_PAINT: + if ( !photoInfo->ppro->m_bJabberOnline ) + SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<Photo not available while offline>" )); + else if ( !photoInfo->hBitmap ) + SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<No photo>" )); + else { + BITMAP bm; + POINT ptSize, ptOrg, pt, ptFitSize; + RECT rect; + + SetDlgItemTextA( hwndDlg, IDC_CANVAS, "" ); + HBITMAP hBitmap = photoInfo->hBitmap; + HWND hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS ); + HDC hdcCanvas = GetDC( hwndCanvas ); + HDC hdcMem = CreateCompatibleDC( hdcCanvas ); + SelectObject( hdcMem, hBitmap ); + SetMapMode( hdcMem, GetMapMode( hdcCanvas )); + GetObject( hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm ); + ptSize.x = bm.bmWidth; + ptSize.y = bm.bmHeight; + DPtoLP( hdcCanvas, &ptSize, 1 ); + ptOrg.x = ptOrg.y = 0; + DPtoLP( hdcMem, &ptOrg, 1 ); + GetClientRect( hwndCanvas, &rect ); + InvalidateRect( hwndCanvas, NULL, TRUE ); + UpdateWindow( hwndCanvas ); + if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) { + pt.x = ( rect.right - ptSize.x )/2; + pt.y = ( rect.bottom - ptSize.y )/2; + ptFitSize = ptSize; + } + else { + if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) { + ptFitSize.x = rect.right; + ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x; + pt.x = 0; + pt.y = ( rect.bottom - ptFitSize.y )/2; + } + else { + ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y; + ptFitSize.y = rect.bottom; + pt.x = ( rect.right - ptFitSize.x )/2; + pt.y = 0; + } + } + + if (JabberIsThemeActive && JabberDrawThemeParentBackground && JabberIsThemeActive()) { + RECT rc; GetClientRect(hwndCanvas, &rc); + JabberDrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc); + } + else { + RECT rc; GetClientRect(hwndCanvas, &rc); + FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE)); + } + + if (JabberAlphaBlend && bm.bmBitsPixel == 32 ) { + BLENDFUNCTION bf = {0}; + bf.AlphaFormat = AC_SRC_ALPHA; + bf.BlendOp = AC_SRC_OVER; + bf.SourceConstantAlpha = 255; + JabberAlphaBlend( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf ); + } + else { + SetStretchBltMode( hdcCanvas, COLORONCOLOR ); + StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY ); + } + + DeleteDC( hdcMem ); + } + break; + + case WM_DESTROY: + DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, 0 )); + if ( photoInfo->hBitmap ) { + photoInfo->ppro->Log( "Delete bitmap" ); + DeleteObject( photoInfo->hBitmap ); + } + if ( photoInfo ) mir_free( photoInfo ); + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnInfoInit - initializes user info option dialogs + +int CJabberProto::OnUserInfoInit( WPARAM wParam, LPARAM lParam ) +{ + if ( !CallService( MS_PROTO_ISPROTOCOLLOADED, 0, ( LPARAM )m_szModuleName )) + return 0; + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof( odp ); + odp.hInstance = hInst; + odp.dwInitParam = ( LPARAM )this; + + HANDLE hContact = ( HANDLE )lParam; + if ( hContact ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( szProto, m_szModuleName )) { + odp.pfnDlgProc = JabberUserInfoDlgProc; + odp.position = -2000000000; + odp.pszTemplate = MAKEINTRESOURCEA( IDD_INFO_JABBER ); + odp.pszTitle = LPGEN("Account"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = JabberUserPhotoDlgProc; + odp.position = 2000000000; + odp.pszTemplate = MAKEINTRESOURCEA( IDD_VCARD_PHOTO ); + odp.pszTitle = LPGEN("Photo"); + UserInfo_AddPage(wParam, &odp); + } + } + else { + // Show our vcard + OnUserInfoInit_VCard(wParam, lParam); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberUserInfoUpdate + +void JabberUserInfoInit() +{ + hUserInfoList = ( HANDLE )CallService( MS_UTILS_ALLOCWINDOWLIST, 0, 0 ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberUserInfoUpdate + +void JabberUserInfoUpdate( HANDLE hContact ) +{ + if ( !hContact ) + WindowList_BroadcastAsync( hUserInfoList, WM_JABBER_REFRESH, 0, 0 ); + else if ( HWND hwnd = WindowList_Find( hUserInfoList, hContact )) + PostMessage( hwnd, WM_JABBER_REFRESH, 0, 0 ); +} diff --git a/protocols/JabberG/src/jabber_util.cpp b/protocols/JabberG/src/jabber_util.cpp new file mode 100644 index 0000000000..a7650c5cd0 --- /dev/null +++ b/protocols/JabberG/src/jabber_util.cpp @@ -0,0 +1,1752 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <richedit.h> + +#include "jabber_list.h" +#include "jabber_caps.h" + +#include "m_clistint.h" + +extern CRITICAL_SECTION mutex; + +extern int bSecureIM; + +void CJabberProto::SerialInit( void ) +{ + InitializeCriticalSection( &m_csSerial ); + m_nSerial = 0; +} + +void CJabberProto::SerialUninit( void ) +{ + DeleteCriticalSection( &m_csSerial ); +} + +int CJabberProto::SerialNext( void ) +{ + unsigned int ret; + + EnterCriticalSection( &m_csSerial ); + ret = m_nSerial; + m_nSerial++; + LeaveCriticalSection( &m_csSerial ); + return ret; +} + +void CJabberProto::Log( const char* fmt, ... ) +{ + va_list vararg; + va_start( vararg, fmt ); + char* str = ( char* )alloca( 32000 ); + mir_vsnprintf( str, 32000, fmt, vararg ); + va_end( vararg ); + + CallService( MS_NETLIB_LOG, ( WPARAM )m_hNetlibUser, ( LPARAM )str ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberChatRoomHContactFromJID - looks for the char room HCONTACT with required JID + +HANDLE CJabberProto::ChatRoomHContactFromJID( const TCHAR* jid ) +{ + if ( jid == NULL ) + return ( HANDLE )NULL; + + HANDLE hContactMatched = NULL; + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( m_szModuleName, szProto )) { + DBVARIANT dbv; + int result = JGetStringT( hContact, "ChatRoomID", &dbv ); + if ( result ) + result = JGetStringT( hContact, "jid", &dbv ); + + if ( !result ) { + int result; + result = lstrcmpi( jid, dbv.ptszVal ); + JFreeVariant( &dbv ); + if ( !result && JGetByte( hContact, "ChatRoom", 0 ) != 0 ) { + hContactMatched = hContact; + break; + } } } + + hContact = db_find_next(hContact); + } + + return hContactMatched; +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberHContactFromJID - looks for the HCONTACT with required JID + +HANDLE CJabberProto::HContactFromJID( const TCHAR* jid , BOOL bStripResource ) +{ + if ( jid == NULL ) + return ( HANDLE )NULL; + + JABBER_LIST_ITEM* item = ListGetItemPtr( LIST_CHATROOM, jid ); + + HANDLE hContactMatched = NULL; + HANDLE hContact = ( HANDLE ) db_find_first(); + while ( hContact != NULL ) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); + if ( szProto != NULL && !strcmp( m_szModuleName, szProto )) { + DBVARIANT dbv; + int result; + //safer way to check UID (coz some contact have both setting from convert to chat) + if(DBGetContactSettingByte(hContact, szProto, "ChatRoom",0)) + result = JGetStringT( hContact, "ChatRoomID", &dbv ); + else + result = JGetStringT( hContact, "jid", &dbv ); + + if ( !result ) { + int result; + if ( item != NULL ) + result = lstrcmpi( jid, dbv.ptszVal ); + else { + if ( bStripResource == 3 ) { + if (JGetByte(hContact, "ChatRoom", 0)) + result = lstrcmpi( jid, dbv.ptszVal ); // for chat room we have to have full contact matched + else if ( TRUE ) + result = _tcsnicmp( jid, dbv.ptszVal, _tcslen(dbv.ptszVal)); + else + result = JabberCompareJids( jid, dbv.ptszVal ); + } + // most probably it should just look full matching contact + else + result = lstrcmpi( jid, dbv.ptszVal ); + + } + JFreeVariant( &dbv ); + if ( !result ) { + hContactMatched = hContact; + break; + } } } + + hContact = db_find_next(hContact); + } + + return hContactMatched; +} + +TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid ) +{ + if (!jid) return mir_tstrdup(_T("")); + + const TCHAR* p; + TCHAR* nick; + + if (( p = _tcschr( jid, '@' )) == NULL ) + p = _tcschr( jid, '/' ); + + if ( p != NULL ) { + if (( nick=( TCHAR* )mir_alloc( sizeof(TCHAR)*( int( p-jid )+1 ))) != NULL ) { + _tcsncpy( nick, jid, p-jid ); + nick[p-jid] = '\0'; + } + } + else nick = mir_tstrdup( jid ); + return nick; +} + +JABBER_RESOURCE_STATUS* CJabberProto::ResourceInfoFromJID( const TCHAR* jid ) +{ + if ( !jid ) + return NULL; + + JABBER_LIST_ITEM *item = NULL; + if (( item = ListGetItemPtr( LIST_VCARD_TEMP, jid )) == NULL) + item = ListGetItemPtr( LIST_ROSTER, jid ); + if ( item == NULL ) return NULL; + + const TCHAR* p = _tcschr( jid, '/' ); + if ( p == NULL ) + return &item->itemResource; + if ( *++p == '\0' ) return NULL; + + JABBER_RESOURCE_STATUS *r = item->resource; + if ( r == NULL ) return NULL; + + int i; + for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, p ); i++, r++ ); + if ( i >= item->resourceCount ) + return NULL; + + return r; +} + +TCHAR* JabberPrepareJid( LPCTSTR jid ) +{ + if ( !jid ) return NULL; + TCHAR* szNewJid = mir_tstrdup( jid ); + if ( !szNewJid ) return NULL; + TCHAR* pDelimiter = _tcschr( szNewJid, _T('/')); + if ( pDelimiter ) *pDelimiter = _T('\0'); + CharLower( szNewJid ); + if ( pDelimiter ) *pDelimiter = _T('/'); + return szNewJid; +} + +void strdel( char* parBuffer, int len ) +{ + char* p; + for ( p = parBuffer+len; *p != 0; p++ ) + p[ -len ] = *p; + + p[ -len ] = '\0'; +} + +char* __stdcall JabberUrlDecode( char* str ) +{ + char* p, *q; + + if ( str == NULL ) + return NULL; + + for ( p=q=str; *p!='\0'; p++,q++ ) { + if ( *p == '<' ) { + // skip CDATA + if ( !strncmp( p, "<![CDATA[", 9 )) + { + p += 9; + char *tail = strstr(p, "]]>"); + size_t count = tail ? (tail-p) : strlen(p); + memmove(q, p, count); + q += count-1; + p = (tail ? (tail+3) : (p+count)) - 1; + } else + { + *q = *p; + } + } else + if ( *p == '&' ) { + if ( !strncmp( p, "&", 5 )) { *q = '&'; p += 4; } + else if ( !strncmp( p, "'", 6 )) { *q = '\''; p += 5; } + else if ( !strncmp( p, ">", 4 )) { *q = '>'; p += 3; } + else if ( !strncmp( p, "<", 4 )) { *q = '<'; p += 3; } + else if ( !strncmp( p, """, 6 )) { *q = '"'; p += 5; } + else { *q = *p; } + } else + { + *q = *p; + } + } + *q = '\0'; + return str; +} + +void __stdcall JabberUrlDecodeW( WCHAR* str ) +{ + if ( str == NULL ) + return; + + WCHAR* p, *q; + for ( p=q=str; *p!='\0'; p++,q++ ) { + if ( *p == '&' ) { + if ( !wcsncmp( p, L"&", 5 )) { *q = '&'; p += 4; } + else if ( !wcsncmp( p, L"'", 6 )) { *q = '\''; p += 5; } + else if ( !wcsncmp( p, L">", 4 )) { *q = '>'; p += 3; } + else if ( !wcsncmp( p, L"<", 4 )) { *q = '<'; p += 3; } + else if ( !wcsncmp( p, L""", 6 )) { *q = '"'; p += 5; } + else { *q = *p; } + } + else { + *q = *p; + } + } + *q = '\0'; +} + +char* __stdcall JabberUrlEncode( const char* str ) +{ + char* s, *p, *q; + int c; + + if ( str == NULL ) + return NULL; + + for ( c=0,p=( char* )str; *p!='\0'; p++ ) { + switch ( *p ) { + case '&': c += 5; break; + case '\'': c += 6; break; + case '>': c += 4; break; + case '<': c += 4; break; + case '"': c += 6; break; + default: c++; break; + } + } + if (( s=( char* )mir_alloc( c+1 )) != NULL ) { + for ( p=( char* )str,q=s; *p!='\0'; p++ ) { + switch ( *p ) { + case '&': strcpy( q, "&" ); q += 5; break; + case '\'': strcpy( q, "'" ); q += 6; break; + case '>': strcpy( q, ">" ); q += 4; break; + case '<': strcpy( q, "<" ); q += 4; break; + case '"': strcpy( q, """ ); q += 6; break; + default: + if ( *p > 0 && *p < 32 ) { + switch( *p ) { + case '\r': + case '\n': + case '\t': + *q = *p; + break; + default: + *q = '?'; + } + } + else *q = *p; + q++; + break; + } + } + *q = '\0'; + } + + return s; +} + +void __stdcall JabberUtfToTchar( const char* pszValue, size_t cbLen, LPTSTR& dest ) +{ + char* pszCopy = NULL; + bool bNeedsFree = false; + __try + { + // this code can cause access violation when a stack overflow occurs + pszCopy = ( char* )alloca( cbLen+1 ); + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + bNeedsFree = true; + pszCopy = ( char* )malloc( cbLen+1 ); + } + if ( pszCopy == NULL ) + return; + + memcpy( pszCopy, pszValue, cbLen ); + pszCopy[ cbLen ] = 0; + + JabberUrlDecode( pszCopy ); + + + mir_utf8decode( pszCopy, &dest ); + + + if ( bNeedsFree ) + free( pszCopy ); +} + +char* __stdcall JabberSha1( char* str ) +{ + mir_sha1_ctx sha; + mir_sha1_byte_t digest[20]; + char* result; + int i; + + if ( str == NULL ) + return NULL; + + mir_sha1_init( &sha ); + mir_sha1_append( &sha, (mir_sha1_byte_t* )str, (int)strlen( str )); + mir_sha1_finish( &sha, digest ); + if (( result=( char* )mir_alloc( 41 )) == NULL ) + return NULL; + + for ( i=0; i<20; i++ ) + sprintf( result+( i<<1 ), "%02x", digest[i] ); + return result; +} + +TCHAR* __stdcall JabberStrFixLines( const TCHAR* str ) +{ + if (!str) return NULL; + + const TCHAR *p; + int add = 0; + bool prev_r = false; + bool prev_n = false; + + for (p = str; p && *p; ++p) + if (*p == _T('\r') || *p == _T('\n')) + ++add; + + TCHAR *buf = (TCHAR *)mir_alloc((lstrlen(str) + add + 1) * sizeof(TCHAR)); + TCHAR *res = buf; + + for (p = str; p && *p; ++p) + { + if (*p == _T('\n') && !prev_r) + *res++ = _T('\r'); + if (*p != _T('\r') && *p != _T('\n') && prev_r) + *res++ = _T('\n'); + *res++ = *p; + prev_r = *p == _T('\r'); + prev_n = *p == _T('\n'); + } + *res = 0; + + return buf; +} + +char* __stdcall JabberUnixToDos( const char* str ) +{ + char* p, *q, *res; + int extra; + + if ( str==NULL || str[0]=='\0' ) + return NULL; + + extra = 0; + for ( p=( char* )str; *p!='\0'; p++ ) { + if ( *p == '\n' ) + extra++; + } + if (( res=( char* )mir_alloc( strlen( str )+extra+1 )) != NULL ) { + for ( p=( char* )str,q=res; *p!='\0'; p++,q++ ) { + if ( *p == '\n' ) { + *q = '\r'; + q++; + } + *q = *p; + } + *q = '\0'; + } + return res; +} + +WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str ) +{ + if ( str==NULL || str[0]=='\0' ) + return NULL; + + const WCHAR* p; + WCHAR* q, *res; + int extra = 0; + + for ( p = str; *p!='\0'; p++ ) { + if ( *p == '\n' ) + extra++; + } + if (( res = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str ) + extra + 1 ))) != NULL ) { + for ( p = str,q=res; *p!='\0'; p++,q++ ) { + if ( *p == '\n' ) { + *q = '\r'; + q++; + } + *q = *p; + } + *q = '\0'; + } + return res; +} + +TCHAR* __stdcall JabberHttpUrlEncode( const TCHAR* str ) +{ + TCHAR* p, *q, *res; + + if ( str == NULL ) return NULL; + res = ( TCHAR* ) mir_alloc( 3*_tcslen( str ) + 1 ); + for ( p = ( TCHAR* )str, q = res; *p!='\0'; p++,q++ ) { + if (( *p>='A' && *p<='Z' ) || ( *p>='a' && *p<='z' ) || ( *p>='0' && *p<='9' ) || strchr( "$-_.+!*'(),", *p )!=NULL ) { + *q = *p; + } + else { + wsprintf( q, _T("%%%02X"), *p ); + q += 2; + } + } + *q = '\0'; + return res; +} + +void __stdcall JabberHttpUrlDecode( TCHAR* str ) +{ + TCHAR* p, *q; + unsigned int code; + + if ( str == NULL ) return; + for ( p = q = ( TCHAR* )str; *p!='\0'; p++,q++ ) { + if ( *p=='%' && *( p+1 )!='\0' && isxdigit( *( p+1 )) && *( p+2 )!='\0' && isxdigit( *( p+2 ))) { + _stscanf(( TCHAR* )p+1, _T("%2x"), &code ); + *q = ( unsigned char ) code; + p += 2; + } + else { + *q = *p; + } } + + *q = '\0'; +} + +int __stdcall JabberCombineStatus( int status1, int status2 ) +{ + // Combine according to the following priority ( high to low ) + // ID_STATUS_FREECHAT + // ID_STATUS_ONLINE + // ID_STATUS_DND + // ID_STATUS_AWAY + // ID_STATUS_NA + // ID_STATUS_INVISIBLE ( valid only for TLEN_PLUGIN ) + // ID_STATUS_OFFLINE + // other ID_STATUS in random order ( actually return status1 ) + if ( status1==ID_STATUS_FREECHAT || status2==ID_STATUS_FREECHAT ) + return ID_STATUS_FREECHAT; + if ( status1==ID_STATUS_ONLINE || status2==ID_STATUS_ONLINE ) + return ID_STATUS_ONLINE; + if ( status1==ID_STATUS_DND || status2==ID_STATUS_DND ) + return ID_STATUS_DND; + if ( status1==ID_STATUS_AWAY || status2==ID_STATUS_AWAY ) + return ID_STATUS_AWAY; + if ( status1==ID_STATUS_NA || status2==ID_STATUS_NA ) + return ID_STATUS_NA; + if ( status1==ID_STATUS_INVISIBLE || status2==ID_STATUS_INVISIBLE ) + return ID_STATUS_INVISIBLE; + if ( status1==ID_STATUS_OFFLINE || status2==ID_STATUS_OFFLINE ) + return ID_STATUS_OFFLINE; + return status1; +} + +struct tagErrorCodeToStr { + int code; + TCHAR* str; +} +static JabberErrorCodeToStrMapping[] = { + { JABBER_ERROR_REDIRECT, _T("Redirect") }, + { JABBER_ERROR_BAD_REQUEST, _T("Bad request") }, + { JABBER_ERROR_UNAUTHORIZED, _T("Unauthorized") }, + { JABBER_ERROR_PAYMENT_REQUIRED, _T("Payment required") }, + { JABBER_ERROR_FORBIDDEN, _T("Forbidden") }, + { JABBER_ERROR_NOT_FOUND, _T("Not found") }, + { JABBER_ERROR_NOT_ALLOWED, _T("Not allowed") }, + { JABBER_ERROR_NOT_ACCEPTABLE, _T("Not acceptable") }, + { JABBER_ERROR_REGISTRATION_REQUIRED, _T("Registration required") }, + { JABBER_ERROR_REQUEST_TIMEOUT, _T("Request timeout") }, + { JABBER_ERROR_CONFLICT, _T("Conflict") }, + { JABBER_ERROR_INTERNAL_SERVER_ERROR, _T("Internal server error") }, + { JABBER_ERROR_NOT_IMPLEMENTED, _T("Not implemented") }, + { JABBER_ERROR_REMOTE_SERVER_ERROR, _T("Remote server error") }, + { JABBER_ERROR_SERVICE_UNAVAILABLE, _T("Service unavailable") }, + { JABBER_ERROR_REMOTE_SERVER_TIMEOUT, _T("Remote server timeout") }, + { -1, _T("Unknown error") } +}; + +TCHAR* __stdcall JabberErrorStr( int errorCode ) +{ + int i; + + for ( i=0; JabberErrorCodeToStrMapping[i].code!=-1 && JabberErrorCodeToStrMapping[i].code!=errorCode; i++ ); + return JabberErrorCodeToStrMapping[i].str; +} + +TCHAR* __stdcall JabberErrorMsg( HXML errorNode, int* pErrorCode ) +{ + TCHAR* errorStr = ( TCHAR* )mir_alloc( 256 * sizeof( TCHAR )); + if ( errorNode == NULL ) { + if ( pErrorCode ) + *pErrorCode = -1; + mir_sntprintf( errorStr, 256, _T("%s -1: %s"), TranslateT( "Error" ), TranslateT( "Unknown error message" )); + return errorStr; + } + + int errorCode = -1; + const TCHAR *str = xmlGetAttrValue( errorNode, _T("code")); + if ( str != NULL ) + errorCode = _ttoi( str ); + + str = xmlGetText( errorNode ); + if ( str == NULL ) + str = xmlGetText( xmlGetChild( errorNode, _T("text"))); + if ( str == NULL ) { + for (int i = 0; ; ++i ) { + HXML c = xmlGetChild( errorNode, i ); + if ( c == NULL ) break; + const TCHAR *attr = xmlGetAttrValue( c, _T("xmlns")); + if ( attr && !_tcscmp( attr, _T("urn:ietf:params:xml:ns:xmpp-stanzas"))) { + str = xmlGetName( c ); + break; + } + } + } + + if ( str != NULL ) + mir_sntprintf( errorStr, 256, _T("%s %d: %s\r\n%s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )), str ); + else + mir_sntprintf( errorStr, 256, _T("%s %d: %s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode ))); + + if ( pErrorCode ) + *pErrorCode = errorCode; + return errorStr; +} + +void CJabberProto::SendVisibleInvisiblePresence( BOOL invisible ) +{ + if ( !m_bJabberOnline ) return; + + LISTFOREACH(i, this, LIST_ROSTER) + { + JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); + if ( item == NULL ) + continue; + + HANDLE hContact = HContactFromJID( item->jid ); + if ( hContact == NULL ) + continue; + + WORD apparentMode = JGetWord( hContact, "ApparentMode", 0 ); + if ( invisible==TRUE && apparentMode==ID_STATUS_OFFLINE ) + m_ThreadInfo->send( XmlNode( _T("presence" )) << XATTR( _T("to"), item->jid ) << XATTR( _T("type"), _T("invisible"))); + else if ( invisible==FALSE && apparentMode==ID_STATUS_ONLINE ) + SendPresenceTo( m_iStatus, item->jid, NULL ); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberBase64Encode + +static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen ) +{ + if ( buffer==NULL || bufferLen<=0 ) + return NULL; + + char* res = (char*)mir_alloc(((( bufferLen+2 )*4 )/3 ) + 1); + if ( res == NULL ) + return NULL; + + unsigned char igroup[3]; + char *r = res; + const char* peob = buffer + bufferLen; + for ( const char* p = buffer; p < peob; ) { + igroup[ 0 ] = igroup[ 1 ] = igroup[ 2 ] = 0; + int n; + for ( n=0; n<3; n++ ) { + if ( p >= peob ) break; + igroup[n] = ( unsigned char ) *p; + p++; + } + + if ( n > 0 ) { + r[0] = b64table[ igroup[0]>>2 ]; + r[1] = b64table[ (( igroup[0]&3 )<<4 ) | ( igroup[1]>>4 ) ]; + r[2] = b64table[ (( igroup[1]&0xf )<<2 ) | ( igroup[2]>>6 ) ]; + r[3] = b64table[ igroup[2]&0x3f ]; + + if ( n < 3 ) { + r[3] = '='; + if ( n < 2 ) + r[2] = '='; + } + r += 4; + } } + + *r = '\0'; + + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberBase64Decode + +static unsigned char b64rtable[256]; + +char* __stdcall JabberBase64DecodeW( const WCHAR* str, int *resultLen ) +{ + char *stra = mir_u2a(str); + char *res = JabberBase64Decode(stra, resultLen); + mir_free(stra); + return res; +} + +char* __stdcall JabberBase64Decode( const char* str, int *resultLen ) +{ + char* res; + unsigned char* r, igroup[4], a[4]; + int n, num, count; + + if ( str==NULL || resultLen==NULL ) return NULL; + if (( res=( char* )mir_alloc(( ( strlen( str )+3 )/4 )*3 )) == NULL ) return NULL; + + for ( n=0; n<256; n++ ) + b64rtable[n] = ( unsigned char ) 0x80; + for ( n=0; n<26; n++ ) + b64rtable['A'+n] = n; + for ( n=0; n<26; n++ ) + b64rtable['a'+n] = n + 26; + for ( n=0; n<10; n++ ) + b64rtable['0'+n] = n + 52; + b64rtable['+'] = 62; + b64rtable['/'] = 63; + b64rtable['='] = 0; + count = 0; + for ( r=( unsigned char* )res; *str != '\0'; ) { + for ( n=0; n<4; n++ ) { + if ( BYTE(*str) == '\r' || BYTE(*str) == '\n' ) { + n--; str++; + continue; + } + + if ( BYTE(*str)=='\0' ) { + if ( n == 0 ) + goto LBL_Exit; + mir_free( res ); + return NULL; + } + + if ( b64rtable[BYTE(*str)]==0x80 ) { + mir_free( res ); + return NULL; + } + + a[n] = BYTE(*str); + igroup[n] = b64rtable[BYTE(*str)]; + str++; + } + r[0] = igroup[0]<<2 | igroup[1]>>4; + r[1] = igroup[1]<<4 | igroup[2]>>2; + r[2] = igroup[2]<<6 | igroup[3]; + r += 3; + num = ( a[2]=='='?1:( a[3]=='='?2:3 )); + count += num; + if ( num < 3 ) break; + } +LBL_Exit: + *resultLen = count; + return res; +} + +time_t __stdcall JabberIsoToUnixTime( const TCHAR* stamp ) +{ + struct tm timestamp; + TCHAR date[9]; + int i, y; + time_t t; + + if ( stamp == NULL ) return ( time_t ) 0; + + const TCHAR *p = stamp; + + // Get the date part + for ( i=0; *p!='\0' && i<8 && isdigit( *p ); p++,i++ ) + date[i] = *p; + + // Parse year + if ( i == 6 ) { + // 2-digit year ( 1970-2069 ) + y = ( date[0]-'0' )*10 + ( date[1]-'0' ); + if ( y < 70 ) y += 100; + } + else if ( i == 8 ) { + // 4-digit year + y = ( date[0]-'0' )*1000 + ( date[1]-'0' )*100 + ( date[2]-'0' )*10 + date[3]-'0'; + y -= 1900; + } + else + return ( time_t ) 0; + timestamp.tm_year = y; + // Parse month + timestamp.tm_mon = ( date[i-4]-'0' )*10 + date[i-3]-'0' - 1; + // Parse date + timestamp.tm_mday = ( date[i-2]-'0' )*10 + date[i-1]-'0'; + + // Skip any date/time delimiter + for ( ; *p!='\0' && !isdigit( *p ); p++ ); + + // Parse time + if ( _stscanf( p, _T("%d:%d:%d"), ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec ) != 3 ) + return ( time_t ) 0; + + timestamp.tm_isdst = 0; // DST is already present in _timezone below + t = mktime( ×tamp ); + + _tzset(); + t -= _timezone; + + if ( t >= 0 ) + return t; + else + return ( time_t ) 0; +} + +void CJabberProto::SendPresenceTo( int status, TCHAR* to, HXML extra, const TCHAR *msg ) +{ + if ( !m_bJabberOnline ) return; + + // Send <presence/> update for status ( we won't handle ID_STATUS_OFFLINE here ) + short iPriority = (short)JGetWord( NULL, "Priority", 0 ); + UpdatePriorityMenu(iPriority); + + TCHAR szPriority[40]; + _itot( iPriority, szPriority, 10 ); + + XmlNode p( _T("presence")); p << XCHILD( _T("priority"), szPriority ); + if ( to != NULL ) + p << XATTR( _T("to"), to ); + + if ( extra ) + xmlAddChild( p, extra ); + + // XEP-0115:Entity Capabilities + HXML c = p << XCHILDNS( _T("c"), _T(JABBER_FEAT_ENTITY_CAPS)) << XATTR( _T("node"), _T(JABBER_CAPS_MIRANDA_NODE)) + << XATTR( _T("ver"), szCoreVersion); + + TCHAR szExtCaps[ 512 ] = _T(""); + + if ( m_bGoogleTalk ) + _tcscat( szExtCaps, _T(JABBER_EXT_GTALK_PMUC)); + + if ( bSecureIM ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_SECUREIM)); + } + + if ( m_options.EnableRemoteControl ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_COMMANDS)); + } + + if ( m_options.EnableUserMood ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_USER_MOOD)); + } + + if ( m_options.EnableUserTune ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_USER_TUNE)); + } + + if ( m_options.EnableUserActivity ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_USER_ACTIVITY)); + } + + if ( m_options.AcceptNotes ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, _T(JABBER_EXT_MIR_NOTES)); + } + + // add features enabled through IJabberNetInterface::AddFeatures() + for ( int i = 0; i < m_lstJabberFeatCapPairsDynamic.getCount(); i++ ) { + if ( m_uEnabledFeatCapsDynamic & m_lstJabberFeatCapPairsDynamic[i]->jcbCap ) { + if ( szExtCaps[0] ) + _tcscat( szExtCaps, _T(" ")); + _tcscat( szExtCaps, m_lstJabberFeatCapPairsDynamic[i]->szExt ); + } + } + + if ( szExtCaps[0] ) + xmlAddAttr( c, _T("ext"), szExtCaps ); + + if ( m_options.EnableAvatars ) { + char hashValue[ 50 ]; + if ( !JGetStaticString( "AvatarHash", NULL, hashValue, sizeof( hashValue ))) { + // XEP-0153: vCard-Based Avatars + HXML x = p << XCHILDNS( _T("x"), _T("vcard-temp:x:update")); + x << XCHILD( _T("photo"), _A2T(hashValue)); + } else { + HXML x = p << XCHILDNS( _T("x"), _T("vcard-temp:x:update")); + x << XCHILD( _T("photo")); + } + } + + EnterCriticalSection( &m_csModeMsgMutex ); + switch ( status ) { + case ID_STATUS_ONLINE: + if ( !msg ) msg = m_modeMsgs.szOnline; + break; + case ID_STATUS_INVISIBLE: + if (!m_bGoogleSharedStatus) p << XATTR( _T("type"), _T("invisible")); + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + p << XCHILD( _T("show"), _T("away")); + if ( !msg ) msg = m_modeMsgs.szAway; + break; + case ID_STATUS_NA: + p << XCHILD( _T("show"), _T("xa")); + if ( !msg ) msg = m_modeMsgs.szNa; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + p << XCHILD( _T("show"), _T("dnd")); + if ( !msg ) msg = m_modeMsgs.szDnd; + break; + case ID_STATUS_FREECHAT: + p << XCHILD( _T("show"), _T("chat")); + if ( !msg ) msg = m_modeMsgs.szFreechat; + break; + default: + // Should not reach here + break; + } + + if ( msg ) + p << XCHILD( _T("status"), msg ); + + if ( m_bGoogleSharedStatus && !to ) + SendIqGoogleSharedStatus( status, msg ); + + LeaveCriticalSection( &m_csModeMsgMutex ); + m_ThreadInfo->send( p ); +} + +void CJabberProto::SendPresence( int status, bool bSendToAll ) +{ + SendPresenceTo( status, NULL, NULL ); + SendVisibleInvisiblePresence( status == ID_STATUS_INVISIBLE ); + + // Also update status in all chatrooms + if ( bSendToAll ) { + LISTFOREACH(i, this, LIST_CHATROOM) + { + JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex( i ); + if ( item != NULL ) { + TCHAR text[ 1024 ]; + mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), item->jid, item->nick ); + SendPresenceTo( status == ID_STATUS_INVISIBLE ? ID_STATUS_ONLINE : status, text, NULL ); +} } } } + +///////////////////////////////////////////////////////////////////////////////////////// +// Google Shared Status + +void CJabberProto::OnIqResultGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo) { + m_bGoogleSharedStatus = (JABBER_IQ_TYPE_RESULT == pInfo->GetIqType()); + m_bGoogleSharedStatusLock = FALSE; +} + +BOOL CJabberProto::OnIqSetGoogleSharedStatus(HXML iqNode, CJabberIqInfo* pInfo) { + if (JABBER_IQ_TYPE_SET != pInfo->GetIqType()) return FALSE; + if (m_bGoogleSharedStatusLock) return TRUE; + + int status; + HXML query = xmlGetChild(iqNode, _T("query")); + HXML node = xmlGetChild(query, _T("invisible")); + if (0 == _tcsicmp(_T("true"), xmlGetAttrValue(node, _T("value")))) + status = ID_STATUS_INVISIBLE; + else { + LPCTSTR txt = xmlGetText(xmlGetChild(query, _T("show"))); + if (txt && 0 == _tcsicmp(_T("dnd"), txt)) + status = ID_STATUS_DND; + else if (m_iStatus == ID_STATUS_DND || m_iStatus == ID_STATUS_INVISIBLE) + status = ID_STATUS_ONLINE; + else + status = m_iStatus; + } + + if (status != m_iStatus) SetStatus(status); + + return TRUE; +} + +void CJabberProto::SendIqGoogleSharedStatus(int status, const TCHAR *msg) { + XmlNodeIq iq(m_iqManager.AddHandler(&CJabberProto::OnIqResultGoogleSharedStatus, JABBER_IQ_TYPE_SET)); + HXML query = iq << XQUERY(_T(JABBER_FEAT_GTALK_SHARED_STATUS)) << XATTR(_T("version"), _T("2")); + query << XCHILD(_T("status"), msg); + if (status == ID_STATUS_INVISIBLE) { + query << XCHILD(_T("show"), _T("default")); + query << XCHILD(_T("invisible")) << XATTR(_T("value"), _T("true")); + } else { + if (status == ID_STATUS_DND) + query << XCHILD(_T("show"), _T("dnd")); + else + query << XCHILD(_T("show"), _T("default")); + + query << XCHILD(_T("invisible")) << XATTR(_T("value"), _T("false")); + } + m_bGoogleSharedStatusLock = TRUE; + m_ThreadInfo->send(iq); +} + +void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... ) +{ + va_list vararg; + char* p; + size_t size, len; + + if ( str == NULL ) return; + + if ( *str==NULL || *sizeAlloced<=0 ) { + *sizeAlloced = 2048; + size = 2048; + *str = ( char* )mir_alloc( size ); + len = 0; + } + else { + len = strlen( *str ); + size = *sizeAlloced - strlen( *str ); + } + + p = *str + len; + va_start( vararg, fmt ); + while ( _vsnprintf( p, size, fmt, vararg ) == -1 ) { + size += 2048; + ( *sizeAlloced ) += 2048; + *str = ( char* )mir_realloc( *str, *sizeAlloced ); + p = *str + len; + } + va_end( vararg ); +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberGetPacketID - converts the xml id attribute into an integer + +int __stdcall JabberGetPacketID( HXML n ) +{ + int result = -1; + + const TCHAR* str = xmlGetAttrValue( n, _T("id")); + if ( str ) + if ( !_tcsncmp( str, _T(JABBER_IQID), SIZEOF( JABBER_IQID )-1 )) + result = _ttoi( str + SIZEOF( JABBER_IQID )-1 ); + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberGetClientJID - adds a resource postfix to a JID + +TCHAR* CJabberProto::GetClientJID( const TCHAR* jid, TCHAR* dest, size_t destLen ) +{ + if ( jid == NULL ) + return NULL; + + size_t len = _tcslen( jid ); + if ( len >= destLen ) + len = destLen-1; + + _tcsncpy( dest, jid, len ); + dest[ len ] = '\0'; + + TCHAR* p = _tcschr( dest, '/' ); + + JABBER_LIST_ITEM* LI = ListGetItemPtr( LIST_ROSTER, jid ); + if ( LI && LI->resourceCount == 1 && LI->resource[ 0 ].szCapsNode && + _tcsicmp( LI->resource[ 0 ].szCapsNode, _T( "http://talk.google.com/xmpp/bot/caps")) == 0) + { + if ( p ) *p = 0; + return dest; + } + + if ( p == NULL ) { + TCHAR* resource = ListGetBestResourceNamePtr( jid ); + if ( resource != NULL ) + mir_sntprintf( dest+len, destLen-len-1, _T("/%s"), resource ); + } + + return dest; +} + +/////////////////////////////////////////////////////////////////////////////// +// JabberStripJid - strips a resource postfix from a JID + +TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen ) +{ + if ( jid == NULL ) + *dest = 0; + else { + size_t len = _tcslen( jid ); + if ( len >= destLen ) + len = destLen-1; + + memcpy( dest, jid, len * sizeof( TCHAR )); + dest[ len ] = 0; + + TCHAR* p = _tcschr( dest, '/' ); + if ( p != NULL ) + *p = 0; + } + + return dest; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetPictureType - tries to autodetect the picture type from the buffer + +int __stdcall JabberGetPictureType( const char* buf ) +{ + if ( buf != NULL ) { + if ( memcmp( buf, "GIF8", 4 ) == 0 ) return PA_FORMAT_GIF; + if ( memcmp( buf, "\x89PNG", 4 ) == 0 ) return PA_FORMAT_PNG; + if ( memcmp( buf, "BM", 2 ) == 0 ) return PA_FORMAT_BMP; + if ( memcmp( buf, "\xFF\xD8", 2 ) == 0 ) return PA_FORMAT_JPEG; + } + + return PA_FORMAT_UNKNOWN; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// TStringPairs class members + +TStringPairs::TStringPairs( char* buffer ) : + elems( NULL ) +{ + TStringPairsElem tempElem[ 100 ]; + + char* token = strtok( buffer, "," ); + + for ( numElems=0; token != NULL; numElems++ ) { + char* p = strchr( token, '=' ), *p1; + if ( p == NULL ) + break; + + while( isspace( *token )) + token++; + + tempElem[ numElems ].name = rtrim( token ); + *p++ = 0; + if (( p1 = strchr( p, '\"' )) != NULL ) { + *p1 = 0; + p = p1+1; + } + + if (( p1 = strrchr( p, '\"' )) != NULL ) + *p1 = 0; + + tempElem[ numElems ].value = rtrim( p ); + token = strtok( NULL, "," ); + } + + if ( numElems ) { + elems = new TStringPairsElem[ numElems ]; + memcpy( elems, tempElem, sizeof(tempElem[0]) * numElems ); +} } + +TStringPairs::~TStringPairs() +{ + delete[] elems; +} + +const char* TStringPairs::operator[]( const char* key ) const +{ + for ( int i = 0; i < numElems; i++ ) + if ( !strcmp( elems[i].name, key )) + return elems[i].value; + + return ""; +} + +//////////////////////////////////////////////////////////////////////// +// Manage combo boxes with recent item list + +void CJabberProto::ComboLoadRecentStrings(HWND hwndDlg, UINT idcCombo, char *param, int recentCount) +{ + for (int i = 0; i < recentCount; ++i) { + DBVARIANT dbv; + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "%s%d", param, i); + if (!JGetStringT(NULL, setting, &dbv)) { + SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)dbv.ptszVal); + JFreeVariant(&dbv); + } } + if (!SendDlgItemMessage(hwndDlg, idcCombo, CB_GETCOUNT, 0, 0)) + SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)_T("")); +} + +void CJabberProto::ComboAddRecentString(HWND hwndDlg, UINT idcCombo, char *param, TCHAR *string, int recentCount) +{ + if (!string || !*string) + return; + if (SendDlgItemMessage(hwndDlg, idcCombo, CB_FINDSTRING, (WPARAM)-1, (LPARAM)string) != CB_ERR) + return; + + int id; + SendDlgItemMessage(hwndDlg, idcCombo, CB_ADDSTRING, 0, (LPARAM)string); + if ((id = SendDlgItemMessage(hwndDlg, idcCombo, CB_FINDSTRING, (WPARAM)-1, (LPARAM)_T(""))) != CB_ERR) + SendDlgItemMessage(hwndDlg, idcCombo, CB_DELETESTRING, id, 0); + + id = JGetByte(NULL, param, 0); + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, sizeof(setting), "%s%d", param, id); + JSetStringT(NULL, setting, string); + JSetByte(NULL, param, (id+1)%recentCount); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// jabber frame maintenance code + +static VOID CALLBACK sttRebuildInfoFrameApcProc( void* param ) +{ + CJabberProto *ppro = (CJabberProto *)param; + if (!ppro->m_pInfoFrame) + return; + + ppro->m_pInfoFrame->LockUpdates(); + if (!ppro->m_bJabberOnline) + { + ppro->m_pInfoFrame->RemoveInfoItem("$/PEP"); + ppro->m_pInfoFrame->RemoveInfoItem("$/Transports"); + ppro->m_pInfoFrame->UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), TranslateT("Offline")); + } else + { + ppro->m_pInfoFrame->UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), ppro->m_szJabberJID); + + if (!ppro->m_bPepSupported) + { + ppro->m_pInfoFrame->RemoveInfoItem("$/PEP"); + } else + { + ppro->m_pInfoFrame->RemoveInfoItem("$/PEP/"); + ppro->m_pInfoFrame->CreateInfoItem("$/PEP", false); + ppro->m_pInfoFrame->UpdateInfoItem("$/PEP", ppro->GetIconHandle(IDI_PL_LIST_ANY), TranslateT("Advanced Status")); + + ppro->m_pInfoFrame->CreateInfoItem("$/PEP/mood", true); + ppro->m_pInfoFrame->SetInfoItemCallback("$/PEP/mood", &CJabberProto::InfoFrame_OnUserMood); + ppro->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); + + ppro->m_pInfoFrame->CreateInfoItem("$/PEP/activity", true); + ppro->m_pInfoFrame->SetInfoItemCallback("$/PEP/activity", &CJabberProto::InfoFrame_OnUserActivity); + ppro->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); + } + + ppro->m_pInfoFrame->RemoveInfoItem("$/Transports/"); + ppro->m_pInfoFrame->CreateInfoItem("$/Transports", false); + ppro->m_pInfoFrame->UpdateInfoItem("$/Transports", ppro->GetIconHandle(IDI_TRANSPORT), TranslateT("Transports")); + + JABBER_LIST_ITEM *item = NULL; + LISTFOREACH(i, ppro, LIST_ROSTER) + { + if (( item=ppro->ListGetItemPtrFromIndex( i )) != NULL ) { + if ( _tcschr( item->jid, '@' )==NULL && _tcschr( item->jid, '/' )==NULL && item->subscription!=SUB_NONE ) { + HANDLE hContact = ppro->HContactFromJID( item->jid ); + if ( hContact == NULL ) continue; + + char name[128]; + char *jid_copy = mir_t2a(item->jid); + mir_snprintf(name, SIZEOF(name), "$/Transports/%s", jid_copy); + ppro->m_pInfoFrame->CreateInfoItem(name, true, (LPARAM)hContact); + ppro->m_pInfoFrame->UpdateInfoItem(name, ppro->GetIconHandle(IDI_TRANSPORTL), (TCHAR *)item->jid); + ppro->m_pInfoFrame->SetInfoItemCallback(name, &CJabberProto::InfoFrame_OnTransport); + mir_free(jid_copy); + } } + } + } + ppro->m_pInfoFrame->Update(); +} + +void CJabberProto::RebuildInfoFrame() +{ + CallFunctionAsync(sttRebuildInfoFrameApcProc, this); +} + +//////////////////////////////////////////////////////////////////////// +// case-insensitive _tcsstr +const TCHAR *JabberStrIStr( const TCHAR *str, const TCHAR *substr) +{ + TCHAR *str_up = NEWTSTR_ALLOCA(str); + TCHAR *substr_up = NEWTSTR_ALLOCA(substr); + + CharUpperBuff(str_up, lstrlen(str_up)); + CharUpperBuff(substr_up, lstrlen(substr_up)); + + TCHAR* p = _tcsstr(str_up, substr_up); + return p ? (str + (p - str_up)) : NULL; +} + +//////////////////////////////////////////////////////////////////////// +// clipboard processing +void JabberCopyText(HWND hwnd, TCHAR *text) +{ + if (!hwnd || !text) return; + + OpenClipboard(hwnd); + EmptyClipboard(); + HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR)*(lstrlen(text)+1)); + TCHAR *s = (TCHAR *)GlobalLock(hMem); + lstrcpy(s, text); + GlobalUnlock(hMem); + SetClipboardData(CF_UNICODETEXT, hMem); + CloseClipboard(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// One string entry dialog + +struct JabberEnterStringParams +{ + CJabberProto* ppro; + + int type; + TCHAR* caption; + TCHAR* result; + size_t resultLen; + char *windowName; + int recentCount; + int timeout; + + int idcControl; + int height; +}; + +static int sttEnterStringResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_TXT_MULTILINE: + case IDC_TXT_COMBO: + case IDC_TXT_RICHEDIT: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + case IDOK: + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +static INT_PTR CALLBACK sttEnterStringDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + JabberEnterStringParams *params = (JabberEnterStringParams *)GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + { + //SetWindowPos( hwndDlg, HWND_TOPMOST ,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE ); + TranslateDialogDefault( hwndDlg ); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_OTHER_RENAME)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_RENAME)); + JabberEnterStringParams *params = (JabberEnterStringParams *)lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )params ); + SetWindowText( hwndDlg, params->caption ); + + RECT rc; GetWindowRect(hwndDlg, &rc); + switch (params->type) + { + case JES_PASSWORD: + { + params->idcControl = IDC_TXT_PASSWORD; + params->height = rc.bottom-rc.top; + break; + } + case JES_MULTINE: + { + params->idcControl = IDC_TXT_MULTILINE; + params->height = 0; + rc.bottom += (rc.bottom-rc.top) * 2; + SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE|SWP_NOREPOSITION); + break; + } + case JES_COMBO: + { + params->idcControl = IDC_TXT_COMBO; + params->height = rc.bottom-rc.top; + if (params->windowName && params->recentCount) + params->ppro->ComboLoadRecentStrings(hwndDlg, IDC_TXT_COMBO, params->windowName, params->recentCount); + break; + } + case JES_RICHEDIT: + { + params->idcControl = IDC_TXT_RICHEDIT; + SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_AUTOURLDETECT, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_SETEVENTMASK, 0, ENM_LINK); + params->height = 0; + rc.bottom += (rc.bottom-rc.top) * 2; + SetWindowPos(hwndDlg, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE|SWP_NOREPOSITION); + break; + } + } + + ShowWindow(GetDlgItem(hwndDlg, params->idcControl), SW_SHOW); + SetDlgItemText( hwndDlg, params->idcControl, params->result ); + + if (params->windowName) + Utils_RestoreWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); + + SetTimer(hwndDlg, 1000, 50, NULL); + + if (params->timeout > 0) + { + SetTimer(hwndDlg, 1001, 1000, NULL); + TCHAR buf[128]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), params->timeout); + SetDlgItemText(hwndDlg, IDOK, buf); + } + + return TRUE; + } + case WM_DESTROY: + WindowFreeIcon( hwndDlg ); + break; + case WM_TIMER: + { + switch (wParam) + { + case 1000: + KillTimer(hwndDlg,1000); + EnableWindow(GetParent(hwndDlg), TRUE); + return TRUE; + + case 1001: + { + TCHAR buf[128]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), --params->timeout); + SetDlgItemText(hwndDlg, IDOK, buf); + + if (params->timeout < 0) + { + KillTimer(hwndDlg, 1001); + UIEmulateBtnClick(hwndDlg, IDOK); + } + + return TRUE; + } + } + } + case WM_SIZE: + { + UTILRESIZEDIALOG urd = {0}; + urd.cbSize = sizeof(urd); + urd.hInstance = hInst; + urd.hwndDlg = hwndDlg; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_GROUPCHAT_INPUT); + urd.pfnResizer = sttEnterStringResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + break; + } + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + if (params && params->height) + lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y = params->height; + break; + } + case WM_NOTIFY: + { + ENLINK *param = (ENLINK *)lParam; + if (param->nmhdr.idFrom != IDC_TXT_RICHEDIT) break; + if (param->nmhdr.code != EN_LINK) break; + if (param->msg != WM_LBUTTONUP) break; + + CHARRANGE sel; + SendMessage(param->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin != sel.cpMax) break; // allow link selection + + TEXTRANGE tr; + tr.chrg = param->chrg; + tr.lpstrText = (TCHAR *)mir_alloc(sizeof(TCHAR)*(tr.chrg.cpMax - tr.chrg.cpMin + 2)); + SendMessage(param->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM) & tr); + + char *tmp = mir_t2a(tr.lpstrText); + CallService(MS_UTILS_OPENURL, 1, (LPARAM)tmp); + mir_free(tmp); + mir_free(tr.lpstrText); + return TRUE; + } + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + GetDlgItemText( hwndDlg, params->idcControl, params->result, (int)params->resultLen ); + params->result[ params->resultLen-1 ] = 0; + + if ((params->type == JES_COMBO) && params->windowName && params->recentCount) + params->ppro->ComboAddRecentString(hwndDlg, IDC_TXT_COMBO, params->windowName, params->result, params->recentCount); + if (params->windowName) + Utils_SaveWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); + + EndDialog( hwndDlg, 1 ); + break; + + case IDCANCEL: + if (params->windowName) + Utils_SaveWindowPosition(hwndDlg, NULL, params->ppro->m_szModuleName, params->windowName); + + EndDialog( hwndDlg, 0 ); + break; + + case IDC_TXT_MULTILINE: + case IDC_TXT_RICHEDIT: + if ((HIWORD(wParam) != EN_SETFOCUS) && (HIWORD(wParam) != EN_KILLFOCUS)) + { + SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); + KillTimer(hwndDlg, 1001); + } + break; + + case IDC_TXT_COMBO: + if ((HIWORD(wParam) != CBN_SETFOCUS) && (HIWORD(wParam) != CBN_KILLFOCUS)) + { + SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); + KillTimer(hwndDlg, 1001); + } + break; + } } + + return FALSE; +} + +BOOL CJabberProto::EnterString(TCHAR *result, size_t resultLen, TCHAR *caption, int type, char *windowName, int recentCount, int timeout) +{ + bool free_caption = false; + if (!caption || (caption==result)) + { + free_caption = true; + caption = mir_tstrdup( result ); + result[ 0 ] = _T('\0'); + } + + JabberEnterStringParams params = { this, type, caption, result, resultLen, windowName, recentCount, timeout }; + + BOOL bRetVal = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INPUT ), GetForegroundWindow(), sttEnterStringDlgProc, LPARAM( ¶ms )); + + if (free_caption) mir_free( caption ); + + return bRetVal; +} + +//////////////////////////////////////////////////////////////////////// +// Premultiply bitmap channels for 32-bit bitmaps +void JabberBitmapPremultiplyChannels(HBITMAP hBitmap) +{ + BITMAP bmp; + DWORD dwLen; + BYTE *p; + int x, y; + + GetObject(hBitmap, sizeof(bmp), &bmp); + + if (bmp.bmBitsPixel != 32) + return; + + dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); + p = (BYTE *)malloc(dwLen); + if (p == NULL) + return; + memset(p, 0, dwLen); + + GetBitmapBits(hBitmap, dwLen, p); + + for (y = 0; y < bmp.bmHeight; ++y) + { + BYTE *px = p + bmp.bmWidth * 4 * y; + + for (x = 0; x < bmp.bmWidth; ++x) + { + px[0] = px[0] * px[3] / 255; + px[1] = px[1] * px[3] / 255; + px[2] = px[2] * px[3] / 255; + + px += 4; + } + } + + SetBitmapBits(hBitmap, dwLen, p); + + free(p); +} + +// Last resource map +void CJabberProto::CleanLastResourceMap() +{ + EnterCriticalSection( &m_csLastResourceMap ); + + m_dwResourceMapPointer = 0; + ZeroMemory( m_ulpResourceToDbEventMap, sizeof( m_ulpResourceToDbEventMap )); + + while ( m_pLastResourceList ) { + void *pNext = (( void ** )m_pLastResourceList )[ 0 ]; + mir_free( m_pLastResourceList ); + m_pLastResourceList = pNext; + } + + LeaveCriticalSection( &m_csLastResourceMap ); +} + +// lock CS before use +BOOL CJabberProto::IsLastResourceExists( void *pResource ) +{ + if ( !pResource ) + return FALSE; + + void *pOurResource = m_pLastResourceList; + while ( pOurResource ) { + if ( pOurResource == pResource ) + return TRUE; + pOurResource = (( void ** )pOurResource)[ 0 ]; + } + return FALSE; +} + +// lock CS before use +void* CJabberProto::AddToLastResourceMap( LPCTSTR szFullJid ) +{ + // detach resource from full jid + const TCHAR* szResource = _tcschr( szFullJid, '/' ); + if ( szResource == NULL ) + return NULL; + if ( *++szResource == '\0' ) + return NULL; + + DWORD dwResourceCount = 0; + + void *pNewTailResource = NULL; + void *pOurResource = m_pLastResourceList; + while ( pOurResource ) { + dwResourceCount++; + + if ( !_tcscmp(( TCHAR * )(( BYTE * )pOurResource + sizeof( void * )), szResource )) + return pOurResource; + + void *pTmp = (( void ** )pOurResource )[ 0 ]; + if ( pTmp && !((( void ** )pTmp )[ 0 ])) + pNewTailResource = pOurResource; + pOurResource = pTmp; + } + + if ( pNewTailResource && ( dwResourceCount > ( SIZEOF( m_ulpResourceToDbEventMap ) / 2 ))) { + void *pTmp = (( void ** )pNewTailResource )[ 0 ]; + (( void ** )pNewTailResource )[ 0 ] = NULL; + mir_free( pTmp ); + } + + void *pNewResource = mir_alloc( sizeof( void * ) + sizeof( TCHAR ) * ( _tcslen( szResource ) + 1 )); + if ( !pNewResource ) + return NULL; + + (( void ** )pNewResource)[ 0 ] = m_pLastResourceList; + _tcscpy(( TCHAR * )(( BYTE * )pNewResource + sizeof( void * )), szResource ); + + m_pLastResourceList = pNewResource; + + return pNewResource; +} + +// lock CS before use +TCHAR* CJabberProto::FindLastResourceByDbEvent( HANDLE hDbEvent ) +{ + for ( int i = 0; i < SIZEOF( m_ulpResourceToDbEventMap ); i += 2 ) { + if ( m_ulpResourceToDbEventMap[ i ] == ( ULONG_PTR )hDbEvent ) { + TCHAR *szRetVal = ( TCHAR * )( m_ulpResourceToDbEventMap[ i + 1 ] + sizeof( void * )); + m_ulpResourceToDbEventMap[ i ] = 0; + m_ulpResourceToDbEventMap[ i + 1 ] = 0; + return szRetVal; + } + } + return NULL; +} + +BOOL CJabberProto::IsMyOwnJID( LPCTSTR szJID ) +{ + if ( !m_ThreadInfo ) + return FALSE; + + TCHAR* szFrom = JabberPrepareJid( szJID ); + if ( !szFrom ) + return FALSE; + + TCHAR* szTo = JabberPrepareJid( m_ThreadInfo->fullJID ); + if ( !szTo ) { + mir_free( szFrom ); + return FALSE; + } + + TCHAR* pDelimiter = _tcschr( szFrom, _T('/')); + if ( pDelimiter ) *pDelimiter = _T('\0'); + + pDelimiter = _tcschr( szTo, _T('/')); + if ( pDelimiter ) *pDelimiter = _T('\0'); + + BOOL bRetVal = _tcscmp( szFrom, szTo ) == 0; + + mir_free( szFrom ); + mir_free( szTo ); + + return bRetVal; +} + +void __cdecl CJabberProto::LoadHttpAvatars(void* param) +{ + OBJLIST<JABBER_HTTP_AVATARS> &avs = *(OBJLIST<JABBER_HTTP_AVATARS>*)param; + HANDLE hHttpCon = NULL; + for (int i = 0; i < avs.getCount(); ++i) + { + NETLIBHTTPREQUEST nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT; + nlhr.szUrl = avs[i].Url; + nlhr.nlc = hHttpCon; + + NETLIBHTTPREQUEST * res = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&nlhr); + if (res) + { + hHttpCon = res->nlc; + if ( res->resultCode == 200 && res->dataLength ) + { + int pictureType = JabberGetPictureType( res->pData ); + if (pictureType != PA_FORMAT_UNKNOWN) + { + TCHAR tszFileName[ MAX_PATH ]; + + PROTO_AVATAR_INFORMATIONT AI; + AI.cbSize = sizeof(AI); + AI.format = pictureType; + AI.hContact = avs[i].hContact; + + if ( JGetByte( AI.hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) { + GetAvatarFileName( AI.hContact, tszFileName, SIZEOF(tszFileName)); + DeleteFile( tszFileName ); + } + + JSetByte( AI.hContact, "AvatarType", pictureType ); + + char cmpsha[ 41 ]; + char buffer[ 41 ]; + mir_sha1_byte_t digest[20]; + mir_sha1_ctx sha; + mir_sha1_init( &sha ); + mir_sha1_append( &sha, ( mir_sha1_byte_t* )res->pData, res->dataLength ); + mir_sha1_finish( &sha, digest ); + for ( int i=0; i<20; i++ ) + sprintf( buffer+( i<<1 ), "%02x", digest[i] ); + + if (JGetStaticString("AvatarSaved", AI.hContact, cmpsha, sizeof(cmpsha)) || strnicmp(cmpsha, buffer, sizeof(buffer))) + { + GetAvatarFileName( AI.hContact, tszFileName, SIZEOF(tszFileName)); + _tcsncpy(AI.filename, tszFileName, SIZEOF(AI.filename)); + FILE* out = _tfopen( tszFileName, _T("wb")); + if ( out != NULL ) { + fwrite( res->pData, res->dataLength, 1, out ); + fclose( out ); + JSetString( AI.hContact, "AvatarSaved", buffer ); + JSendBroadcast( AI.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0 ); + Log("Broadcast new avatar: %s",AI.filename); + } + else JSendBroadcast( AI.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, &AI, 0 ); + } + } + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)res); + } + else + hHttpCon = NULL; + } + delete &avs; + if ( hHttpCon ) + Netlib_CloseHandle(hHttpCon); +} \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_vcard.cpp b/protocols/JabberG/src/jabber_vcard.cpp new file mode 100644 index 0000000000..691f3516ed --- /dev/null +++ b/protocols/JabberG/src/jabber_vcard.cpp @@ -0,0 +1,1250 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include <sys/stat.h> +#include <fcntl.h> +#include <io.h> +#include "jabber_iq.h" +#include "jabber_caps.h" + +///////////////////////////////////////////////////////////////////////////////////////// + +int CJabberProto::SendGetVcard( const TCHAR* jid ) +{ + if (!m_bJabberOnline) return 0; + + int iqId = SerialNext(); + JABBER_IQ_PROCID procId = !lstrcmp( jid, m_szJabberJID ) ? IQ_PROC_GETVCARD : IQ_PROC_NONE; + + IqAdd( iqId, procId, &CJabberProto::OnIqResultGetVcard ); + m_ThreadInfo->send( + XmlNodeIq( _T("get"), iqId, jid ) << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)) + << XATTR( _T("prodid"), _T("-//HandGen//NONSGML vGen v1.0//EN")) << XATTR( _T("version"), _T("2.0"))); + + return iqId; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void SetDialogField( CJabberProto* ppro, HWND hwndDlg, int nDlgItem, char* key, bool bTranslate = false ) +{ + DBVARIANT dbv; + + if ( !DBGetContactSettingTString( NULL, ppro->m_szModuleName, key, &dbv )) { + SetDlgItemText( hwndDlg, nDlgItem, ( bTranslate ) ? TranslateTS(dbv.ptszVal) : dbv.ptszVal ); + JFreeVariant( &dbv ); + } + else SetDlgItemTextA( hwndDlg, nDlgItem, "" ); +} + +static INT_PTR CALLBACK PersonalDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + const unsigned long iPageId = 0; + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + if ( lParam ) { + ppro = ( CJabberProto* )lParam; + TranslateDialogDefault( hwndDlg ); + SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Male" )); + SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Female" )); + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); + ppro->WindowSubscribe(hwndDlg); + } + break; + + case WM_JABBER_REFRESH_VCARD: + SetDialogField( ppro, hwndDlg, IDC_FULLNAME, "FullName" ); + SetDialogField( ppro, hwndDlg, IDC_NICKNAME, "Nick" ); + SetDialogField( ppro, hwndDlg, IDC_FIRSTNAME, "FirstName" ); + SetDialogField( ppro, hwndDlg, IDC_MIDDLE, "MiddleName" ); + SetDialogField( ppro, hwndDlg, IDC_LASTNAME, "LastName" ); + SetDialogField( ppro, hwndDlg, IDC_BIRTH, "BirthDate" ); + SetDialogField( ppro, hwndDlg, IDC_GENDER, "GenderString", true ); + SetDialogField( ppro, hwndDlg, IDC_OCCUPATION, "Role" ); + SetDialogField( ppro, hwndDlg, IDC_HOMEPAGE, "Homepage" ); + break; + + case WM_COMMAND: + if (( ( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) || + (( HWND )lParam==GetDlgItem( hwndDlg, IDC_GENDER ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) + { + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + ppro->m_vCardUpdates &= ~(1UL<<iPageId); + ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!ppro->m_vCardUpdates) + ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); + break; + } } + break; + + case WM_DESTROY: + ppro->WindowUnsubscribe(hwndDlg); + break; + } + return FALSE; +} + +static INT_PTR CALLBACK HomeDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + const unsigned long iPageId = 1; + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + if ( lParam ) { + ppro = ( CJabberProto* )lParam; + TranslateDialogDefault( hwndDlg ); + for (int i = 0; i < g_cbCountries; i++) { + if ( g_countries[i].id != 0xFFFF && g_countries[i].id != 0) { + TCHAR *country = mir_a2t(g_countries[i].szName); + SendMessage( GetDlgItem( hwndDlg, IDC_COUNTRY ), CB_ADDSTRING, 0, ( LPARAM )TranslateTS(country)); + mir_free(country); + } + } + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); + ppro->WindowSubscribe(hwndDlg); + } + break; + + case WM_JABBER_REFRESH_VCARD: + SetDialogField( ppro, hwndDlg, IDC_ADDRESS1, "Street" ); + SetDialogField( ppro, hwndDlg, IDC_ADDRESS2, "Street2" ); + SetDialogField( ppro, hwndDlg, IDC_CITY, "City" ); + SetDialogField( ppro, hwndDlg, IDC_STATE, "State" ); + SetDialogField( ppro, hwndDlg, IDC_ZIP, "ZIP" ); + SetDialogField( ppro, hwndDlg, IDC_COUNTRY, "Country", true ); + break; + + case WM_COMMAND: + if ((( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE) || + (( HWND )lParam==GetDlgItem( hwndDlg, IDC_COUNTRY ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) + { + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + ppro->m_vCardUpdates &= ~(1UL<<iPageId); + ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!ppro->m_vCardUpdates) + ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); + break; + } } + break; + + case WM_DESTROY: + ppro->WindowUnsubscribe(hwndDlg); + break; + } + return FALSE; +} + +static INT_PTR CALLBACK WorkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + const unsigned long iPageId = 2; + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + if ( lParam ) { // proto info is available + ppro = ( CJabberProto* )lParam; + TranslateDialogDefault( hwndDlg ); + for (int i = 0; i < g_cbCountries; i++) { + if ( g_countries[i].id != 0xFFFF && g_countries[i].id != 0 ) { + TCHAR *country = mir_a2t( g_countries[i].szName ); + SendMessage( GetDlgItem( hwndDlg, IDC_COUNTRY ), CB_ADDSTRING, 0, ( LPARAM )TranslateTS(country)); + mir_free(country); + } + } + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); + ppro->WindowSubscribe(hwndDlg); + } + break; + + case WM_JABBER_REFRESH_VCARD: + SetDialogField( ppro, hwndDlg, IDC_COMPANY, "Company" ); + SetDialogField( ppro, hwndDlg, IDC_DEPARTMENT, "CompanyDepartment" ); + SetDialogField( ppro, hwndDlg, IDC_TITLE, "CompanyPosition" ); + SetDialogField( ppro, hwndDlg, IDC_ADDRESS1, "CompanyStreet" ); + SetDialogField( ppro, hwndDlg, IDC_ADDRESS2, "CompanyStreet2" ); + SetDialogField( ppro, hwndDlg, IDC_CITY, "CompanyCity" ); + SetDialogField( ppro, hwndDlg, IDC_STATE, "CompanyState" ); + SetDialogField( ppro, hwndDlg, IDC_ZIP, "CompanyZIP" ); + SetDialogField( ppro, hwndDlg, IDC_COUNTRY, "CompanyCountry", true ); + break; + + case WM_COMMAND: + if ((( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE) || + (( HWND )lParam==GetDlgItem( hwndDlg, IDC_COUNTRY ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE ))) + { + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + ppro->m_vCardUpdates &= ~(1UL<<iPageId); + ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!ppro->m_vCardUpdates) + ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); + break; + } } + break; + + case WM_DESTROY: + ppro->WindowUnsubscribe(hwndDlg); + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct PhotoDlgProcData +{ + CJabberProto* ppro; +// char szPhotoFileName[MAX_PATH]; +// BOOL bPhotoChanged; + HBITMAP hBitmap; +}; + +static INT_PTR CALLBACK PhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + const unsigned long iPageId = 3; + + TCHAR szAvatarFileName[ MAX_PATH ], szTempPath[MAX_PATH], szTempFileName[MAX_PATH]; + PhotoDlgProcData* dat = ( PhotoDlgProcData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + if (!lParam) break; // Launched from userinfo + TranslateDialogDefault( hwndDlg ); + SendDlgItemMessage( hwndDlg, IDC_LOAD, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_OPEN ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); + SendDlgItemMessage( hwndDlg, IDC_LOAD, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage( hwndDlg, IDC_DELETE, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 )); + SendDlgItemMessage( hwndDlg, IDC_DELETE, BUTTONSETASFLATBTN, TRUE, 0); + ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE ); + { + dat = new PhotoDlgProcData; + dat->ppro = ( CJabberProto* )lParam; + dat->hBitmap = NULL; + dat->ppro->m_bPhotoChanged = FALSE; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, ( LONG_PTR )dat ); + dat->ppro->WindowSubscribe(hwndDlg); + } + SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); + break; + + case WM_JABBER_REFRESH_VCARD: + if ( dat->hBitmap ) { + DeleteObject( dat->hBitmap ); + dat->hBitmap = NULL; + DeleteFile( dat->ppro->m_szPhotoFileName ); + dat->ppro->m_szPhotoFileName[0] = '\0'; + } + EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE ); + dat->ppro->GetAvatarFileName( NULL, szAvatarFileName, SIZEOF( szAvatarFileName )); + if ( _taccess( szAvatarFileName, 0 ) == 0 ) { + if ( GetTempPath( SIZEOF( szTempPath ), szTempPath ) <= 0 ) + _tcscpy( szTempPath, _T(".\\")); + if ( GetTempFileName( szTempPath, _T("jab"), 0, szTempFileName ) > 0 ) { + dat->ppro->Log( "Temp file = " TCHAR_STR_PARAM, szTempFileName ); + if ( CopyFile( szAvatarFileName, szTempFileName, FALSE ) == TRUE ) { + char* p = mir_t2a( szTempFileName ); + if (( dat->hBitmap=( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )p )) != NULL ) { + JabberBitmapPremultiplyChannels( dat->hBitmap ); + _tcscpy( dat->ppro->m_szPhotoFileName, szTempFileName ); + EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE ); + } + else DeleteFile( szTempFileName ); + mir_free(p); + } + else DeleteFile( szTempFileName ); + } } + + dat->ppro->m_bPhotoChanged = FALSE; + InvalidateRect( hwndDlg, NULL, TRUE ); + UpdateWindow( hwndDlg ); + break; + + case WM_JABBER_CHANGED: + dat->ppro->SetServerVcard( dat->ppro->m_bPhotoChanged, dat->ppro->m_szPhotoFileName ); + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDC_LOAD: + { + TCHAR szFilter[512]; + TCHAR szFileName[MAX_PATH]; + + CallService( MS_UTILS_GETBITMAPFILTERSTRINGST, SIZEOF( szFilter ), ( LPARAM )szFilter ); + + OPENFILENAME ofn = {0}; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwndDlg; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_DONTADDTORECENT; + szFileName[0] = '\0'; + if ( GetOpenFileName( &ofn )) { + struct _stat st; + HBITMAP hNewBitmap; + + dat->ppro->Log( "File selected is " TCHAR_STR_PARAM, szFileName ); + if ( _tstat( szFileName, &st )<0 || st.st_size>40*1024 ) { + MessageBox( hwndDlg, TranslateT( "Only JPG, GIF, and BMP image files smaller than 40 KB are supported." ), TranslateT( "Jabber vCard" ), MB_OK|MB_SETFOREGROUND ); + break; + } + if ( GetTempPath( SIZEOF( szTempPath ), szTempPath ) <= 0 ) + _tcscpy( szTempPath, _T(".\\")); + if ( GetTempFileName( szTempPath, _T("jab"), 0, szTempFileName ) > 0 ) { + dat->ppro->Log( "Temp file = " TCHAR_STR_PARAM, szTempFileName ); + if ( CopyFile( szFileName, szTempFileName, FALSE ) == TRUE ) { + char* pszTemp = mir_t2a( szTempFileName ); + if (( hNewBitmap=( HBITMAP ) CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )pszTemp )) != NULL ) { + if ( dat->hBitmap ) { + DeleteObject( dat->hBitmap ); + DeleteFile( dat->ppro->m_szPhotoFileName ); + } + + dat->hBitmap = hNewBitmap; + _tcscpy( dat->ppro->m_szPhotoFileName, szTempFileName ); + dat->ppro->m_bPhotoChanged = TRUE; + EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE ); + InvalidateRect( hwndDlg, NULL, TRUE ); + UpdateWindow( hwndDlg ); + dat->ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + else DeleteFile( szTempFileName ); + + mir_free( pszTemp ); + } + else DeleteFile( szTempFileName ); + } + } + } + break; + case IDC_DELETE: + if ( dat->hBitmap ) { + DeleteObject( dat->hBitmap ); + dat->hBitmap = NULL; + DeleteFile( dat->ppro->m_szPhotoFileName ); + dat->ppro->m_szPhotoFileName[0] = '\0'; + dat->ppro->m_bPhotoChanged = TRUE; + EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE ); + InvalidateRect( hwndDlg, NULL, TRUE ); + UpdateWindow( hwndDlg ); + dat->ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + } + break; + case WM_PAINT: + if ( dat->hBitmap ) { + BITMAP bm; + HDC hdcMem; + HWND hwndCanvas; + HDC hdcCanvas; + POINT ptSize, ptOrg, pt, ptFitSize; + RECT rect; + + hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS ); + hdcCanvas = GetDC( hwndCanvas ); + hdcMem = CreateCompatibleDC( hdcCanvas ); + SelectObject( hdcMem, dat->hBitmap ); + SetMapMode( hdcMem, GetMapMode( hdcCanvas )); + GetObject( dat->hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm ); + ptSize.x = bm.bmWidth; + ptSize.y = bm.bmHeight; + DPtoLP( hdcCanvas, &ptSize, 1 ); + ptOrg.x = ptOrg.y = 0; + DPtoLP( hdcMem, &ptOrg, 1 ); + GetClientRect( hwndCanvas, &rect ); + InvalidateRect( hwndCanvas, NULL, TRUE ); + UpdateWindow( hwndCanvas ); + if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) { + pt.x = ( rect.right - ptSize.x )/2; + pt.y = ( rect.bottom - ptSize.y )/2; + ptFitSize = ptSize; + } + else { + if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) { + ptFitSize.x = rect.right; + ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x; + pt.x = 0; + pt.y = ( rect.bottom - ptFitSize.y )/2; + } + else { + ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y; + ptFitSize.y = rect.bottom; + pt.x = ( rect.right - ptFitSize.x )/2; + pt.y = 0; + } + } + + RECT rc; + GetClientRect(hwndCanvas, &rc); + if (JabberIsThemeActive && JabberDrawThemeParentBackground && JabberIsThemeActive()) + JabberDrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc); + else + FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE)); + + if (JabberAlphaBlend && (bm.bmBitsPixel == 32)) { + BLENDFUNCTION bf = {0}; + bf.AlphaFormat = AC_SRC_ALPHA; + bf.BlendOp = AC_SRC_OVER; + bf.SourceConstantAlpha = 255; + JabberAlphaBlend( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf ); + } + else { + SetStretchBltMode( hdcCanvas, COLORONCOLOR ); + StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY ); + } + + DeleteDC( hdcMem ); + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + dat->ppro->m_vCardUpdates &= ~(1UL<<iPageId); + dat->ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!dat->ppro->m_vCardUpdates) + dat->ppro->SetServerVcard( dat->ppro->m_bPhotoChanged, dat->ppro->m_szPhotoFileName ); + break; + } } + break; + + case WM_DESTROY: + DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_LOAD, BM_SETIMAGE, IMAGE_ICON, 0 )); + DestroyIcon(( HICON )SendDlgItemMessage( hwndDlg, IDC_DELETE, BM_SETIMAGE, IMAGE_ICON, 0 )); + dat->ppro->WindowUnsubscribe(hwndDlg); + if ( dat->hBitmap ) { + dat->ppro->Log( "Delete bitmap" ); + DeleteObject( dat->hBitmap ); + DeleteFile( dat->ppro->m_szPhotoFileName ); + } + delete dat; + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static INT_PTR CALLBACK NoteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + const unsigned long iPageId = 4; + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + if (!lParam) break; // Launched from userinfo + ppro = ( CJabberProto* )lParam; + TranslateDialogDefault( hwndDlg ); + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + SendMessage( hwndDlg, WM_JABBER_REFRESH_VCARD, 0, 0 ); + ppro->WindowSubscribe(hwndDlg); + break; + case WM_JABBER_REFRESH_VCARD: + { + SetDialogField( ppro, hwndDlg, IDC_DESC, "About" ); + break; + } + case WM_COMMAND: + if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) + { + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + ppro->m_vCardUpdates &= ~(1UL<<iPageId); + ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!ppro->m_vCardUpdates) + ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); + break; + } } + break; + case WM_DESTROY: + ppro->WindowUnsubscribe(hwndDlg); + break; + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct EditDlgParam +{ + int id; + CJabberProto* ppro; +}; + +static INT_PTR CALLBACK EditEmailDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + EditDlgParam* dat = ( EditDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + { + EditDlgParam* dat = ( EditDlgParam* )lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + TranslateDialogDefault( hwndDlg ); + + if ( lParam >= 0 ) { + DBVARIANT dbv; + char idstr[33]; + WORD nFlag; + + SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Email Address" )); + wsprintfA( idstr, "e-mail%d", dat->id ); + if ( !DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) { + SetDlgItemTextA( hwndDlg, IDC_EMAIL, dbv.pszVal ); + JFreeVariant( &dbv ); + wsprintfA( idstr, "e-mailFlag%d", lParam ); + nFlag = DBGetContactSettingWord( NULL, dat->ppro->m_szModuleName, idstr, 0 ); + if ( nFlag & JABBER_VCEMAIL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE ); + if ( nFlag & JABBER_VCEMAIL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE ); + if ( nFlag & JABBER_VCEMAIL_INTERNET ) CheckDlgButton( hwndDlg, IDC_INTERNET, TRUE ); + if ( nFlag & JABBER_VCEMAIL_X400 ) CheckDlgButton( hwndDlg, IDC_X400, TRUE ); + } } } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + { + TCHAR text[128]; + char idstr[33]; + DBVARIANT dbv; + WORD nFlag; + + if ( dat->id < 0 ) { + for ( dat->id=0;;dat->id++ ) { + mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", dat->id ); + if ( DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) break; + JFreeVariant( &dbv ); + } } + GetDlgItemText( hwndDlg, IDC_EMAIL, text, SIZEOF( text )); + mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", dat->id ); + dat->ppro->JSetStringT( NULL, idstr, text ); + + nFlag = 0; + if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCEMAIL_HOME; + if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCEMAIL_WORK; + if ( IsDlgButtonChecked( hwndDlg, IDC_INTERNET )) nFlag |= JABBER_VCEMAIL_INTERNET; + if ( IsDlgButtonChecked( hwndDlg, IDC_X400 )) nFlag |= JABBER_VCEMAIL_X400; + mir_snprintf( idstr, SIZEOF(idstr), "e-mailFlag%d", dat->id ); + dat->ppro->JSetWord( NULL, idstr, nFlag ); + } + // fall through + case IDCANCEL: + EndDialog( hwndDlg, wParam ); + break; + } + } + return FALSE; +} + +static INT_PTR CALLBACK EditPhoneDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + EditDlgParam* dat = ( EditDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch ( msg ) { + case WM_INITDIALOG: + { + EditDlgParam* dat = ( EditDlgParam* )lParam; + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + TranslateDialogDefault( hwndDlg ); + if ( dat->id >= 0 ) { + DBVARIANT dbv; + char idstr[33]; + WORD nFlag; + + SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Phone Number" )); + wsprintfA( idstr, "Phone%d", dat->id ); + if ( !DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) { + SetDlgItemTextA( hwndDlg, IDC_PHONE, dbv.pszVal ); + JFreeVariant( &dbv ); + wsprintfA( idstr, "PhoneFlag%d", dat->id ); + nFlag = dat->ppro->JGetWord( NULL, idstr, 0 ); + if ( nFlag & JABBER_VCTEL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE ); + if ( nFlag & JABBER_VCTEL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE ); + if ( nFlag & JABBER_VCTEL_VOICE ) CheckDlgButton( hwndDlg, IDC_VOICE, TRUE ); + if ( nFlag & JABBER_VCTEL_FAX ) CheckDlgButton( hwndDlg, IDC_FAX, TRUE ); + if ( nFlag & JABBER_VCTEL_PAGER ) CheckDlgButton( hwndDlg, IDC_PAGER, TRUE ); + if ( nFlag & JABBER_VCTEL_MSG ) CheckDlgButton( hwndDlg, IDC_MSG, TRUE ); + if ( nFlag & JABBER_VCTEL_CELL ) CheckDlgButton( hwndDlg, IDC_CELL, TRUE ); + if ( nFlag & JABBER_VCTEL_VIDEO ) CheckDlgButton( hwndDlg, IDC_VIDEO, TRUE ); + if ( nFlag & JABBER_VCTEL_BBS ) CheckDlgButton( hwndDlg, IDC_BBS, TRUE ); + if ( nFlag & JABBER_VCTEL_MODEM ) CheckDlgButton( hwndDlg, IDC_MODEM, TRUE ); + if ( nFlag & JABBER_VCTEL_ISDN ) CheckDlgButton( hwndDlg, IDC_ISDN, TRUE ); + if ( nFlag & JABBER_VCTEL_PCS ) CheckDlgButton( hwndDlg, IDC_PCS, TRUE ); + } } } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + { + char text[128]; + char idstr[33]; + DBVARIANT dbv; + WORD nFlag; + + if ( dat->id < 0 ) { + for ( dat->id=0;;dat->id++ ) { + wsprintfA( idstr, "Phone%d", dat->id ); + if ( DBGetContactSettingString( NULL, dat->ppro->m_szModuleName, idstr, &dbv )) break; + JFreeVariant( &dbv ); + } + } + GetDlgItemTextA( hwndDlg, IDC_PHONE, text, SIZEOF( text )); + wsprintfA( idstr, "Phone%d", dat->id ); + dat->ppro->JSetString( NULL, idstr, text ); + nFlag = 0; + if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCTEL_HOME; + if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCTEL_WORK; + if ( IsDlgButtonChecked( hwndDlg, IDC_VOICE )) nFlag |= JABBER_VCTEL_VOICE; + if ( IsDlgButtonChecked( hwndDlg, IDC_FAX )) nFlag |= JABBER_VCTEL_FAX; + if ( IsDlgButtonChecked( hwndDlg, IDC_PAGER )) nFlag |= JABBER_VCTEL_PAGER; + if ( IsDlgButtonChecked( hwndDlg, IDC_MSG )) nFlag |= JABBER_VCTEL_MSG; + if ( IsDlgButtonChecked( hwndDlg, IDC_CELL )) nFlag |= JABBER_VCTEL_CELL; + if ( IsDlgButtonChecked( hwndDlg, IDC_VIDEO )) nFlag |= JABBER_VCTEL_VIDEO; + if ( IsDlgButtonChecked( hwndDlg, IDC_BBS )) nFlag |= JABBER_VCTEL_BBS; + if ( IsDlgButtonChecked( hwndDlg, IDC_MODEM )) nFlag |= JABBER_VCTEL_MODEM; + if ( IsDlgButtonChecked( hwndDlg, IDC_ISDN )) nFlag |= JABBER_VCTEL_ISDN; + if ( IsDlgButtonChecked( hwndDlg, IDC_PCS )) nFlag |= JABBER_VCTEL_PCS; + wsprintfA( idstr, "PhoneFlag%d", dat->id ); + dat->ppro->JSetWord( NULL, idstr, nFlag ); + } + // fall through + case IDCANCEL: + EndDialog( hwndDlg, wParam ); + break; + } + } + return FALSE; +} + +#define M_REMAKELISTS ( WM_USER+1 ) +static INT_PTR CALLBACK ContactDlgProc( HWND hwndDlg, UINT msg, WPARAM, LPARAM lParam ) +{ + const unsigned long iPageId = 5; + CJabberProto* ppro = ( CJabberProto* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch( msg ) { + case WM_INITDIALOG: + if (!lParam) break; // Launched from userinfo + ppro = ( CJabberProto* )lParam; + { + LVCOLUMN lvc; + RECT rc; + + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam ); + + TranslateDialogDefault( hwndDlg ); + GetClientRect( GetDlgItem( hwndDlg,IDC_EMAILS ), &rc ); + rc.right -= GetSystemMetrics( SM_CXVSCROLL ); + lvc.mask = LVCF_WIDTH; + lvc.cx = 30; + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 0, &lvc ); + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 0, &lvc ); + lvc.cx = rc.right - 30 - 40; + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 1, &lvc ); + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 1, &lvc ); + lvc.cx = 20; + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 2, &lvc ); + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 3, &lvc ); + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 2, &lvc ); + ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 3, &lvc ); + SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); + + ppro->WindowSubscribe(hwndDlg); + } + break; + case M_REMAKELISTS: + { + LVITEM lvi; + int i; + char idstr[33]; + TCHAR number[20]; + DBVARIANT dbv; + + //e-mails + ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_EMAILS )); + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.iSubItem = 0; + lvi.iItem = 0; + for ( i=0;;i++ ) { + wsprintfA( idstr, "e-mail%d", i ); + if ( DBGetContactSettingTString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; + wsprintf( number, _T("%d"), i+1 ); + lvi.pszText = number; + lvi.lParam = ( LPARAM )i; + ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi ); + ListView_SetItemText( GetDlgItem( hwndDlg, IDC_EMAILS ), lvi.iItem, 1, dbv.ptszVal ); + JFreeVariant( &dbv ); + lvi.iItem++; + } + lvi.mask = LVIF_PARAM; + lvi.lParam = ( LPARAM )( -1 ); + ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi ); + //phones + ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_PHONES )); + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.iSubItem = 0; + lvi.iItem = 0; + for ( i=0;;i++ ) { + wsprintfA( idstr, "Phone%d", i ); + if ( DBGetContactSettingTString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; + wsprintf( number, _T("%d"), i+1 ); + lvi.pszText = number; + lvi.lParam = ( LPARAM )i; + ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi ); + ListView_SetItemText( GetDlgItem( hwndDlg, IDC_PHONES ), lvi.iItem, 1, dbv.ptszVal ); + JFreeVariant( &dbv ); + lvi.iItem++; + } + lvi.mask = LVIF_PARAM; + lvi.lParam = ( LPARAM )( -1 ); + ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi ); + } + break; + case WM_NOTIFY: + switch (( ( LPNMHDR )lParam )->idFrom ) { + case 0: { + switch (((LPNMHDR)lParam)->code) { + case PSN_PARAMCHANGED: + SendMessage(hwndDlg, WM_INITDIALOG, 0, ((PSHNOTIFY*)lParam)->lParam); + break; + case PSN_APPLY: + ppro->m_vCardUpdates &= ~(1UL<<iPageId); + ppro->SaveVcardToDB( hwndDlg, iPageId ); + if (!ppro->m_vCardUpdates) + ppro->SetServerVcard( ppro->m_bPhotoChanged, ppro->m_szPhotoFileName ); + break; + } } + break; + + case IDC_EMAILS: + case IDC_PHONES: + switch (( ( LPNMHDR )lParam )->code ) { + case NM_CUSTOMDRAW: + { + NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam; + + switch ( nm->nmcd.dwDrawStage ) { + case CDDS_PREPAINT: + case CDDS_ITEMPREPAINT: + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW ); + return TRUE; + case CDDS_SUBITEM|CDDS_ITEMPREPAINT: + { + RECT rc; + HICON hIcon; + + ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc ); + if ( nm->nmcd.lItemlParam==( LPARAM )( -1 ) && nm->iSubItem==3 ) + hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); + else if ( nm->iSubItem==2 && nm->nmcd.lItemlParam!=( LPARAM )( -1 )) + hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_EDIT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); + else if ( nm->iSubItem==3 && nm->nmcd.lItemlParam!=( LPARAM )( -1 )) + hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ); + else break; + DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, NULL, DI_NORMAL ); + DestroyIcon( hIcon ); + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT ); + } + return TRUE; + } + } + break; + case NM_CLICK: + { + NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam; + LVITEM lvi; + const char* szIdTemplate = nm->hdr.idFrom==IDC_PHONES?"Phone%d":"e-mail%d"; + const char* szFlagTemplate = nm->hdr.idFrom==IDC_PHONES?"PhoneFlag%d":"e-mailFlag%d"; + LVHITTESTINFO hti; + + if ( nm->iSubItem < 2 ) break; + hti.pt.x = ( short ) LOWORD( GetMessagePos()); + hti.pt.y = ( short ) HIWORD( GetMessagePos()); + ScreenToClient( nm->hdr.hwndFrom, &hti.pt ); + if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 ) break; + lvi.mask = LVIF_PARAM; + lvi.iItem = hti.iItem; + lvi.iSubItem = 0; + ListView_GetItem( nm->hdr.hwndFrom, &lvi ); + if ( lvi.lParam == ( LPARAM )( -1 )) { + if ( hti.iSubItem == 3 ) { + //add + EditDlgParam param = { -1, ppro }; + int res; + if ( nm->hdr.idFrom == IDC_PHONES ) + res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDPHONE ), hwndDlg, EditPhoneDlgProc, ( LPARAM )¶m ); + else + res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDEMAIL ), hwndDlg, EditEmailDlgProc, ( LPARAM )¶m ); + if ( res != IDOK ) + break; + SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + } + else { + if ( hti.iSubItem == 3 ) { + //delete + int i; + char idstr[33]; + DBVARIANT dbv; + + for ( i=lvi.lParam;;i++ ) { + WORD nFlag; + + wsprintfA( idstr, szIdTemplate, i+1 ); + if ( DBGetContactSettingString( NULL, ppro->m_szModuleName, idstr, &dbv )) break; + wsprintfA( idstr,szIdTemplate,i ); + ppro->JSetString( NULL, idstr, dbv.pszVal ); + wsprintfA( idstr, szFlagTemplate, i+1 ); + JFreeVariant( &dbv ); + nFlag = ppro->JGetWord( NULL, idstr, 0 ); + wsprintfA( idstr, szFlagTemplate, i ); + ppro->JSetWord( NULL, idstr, nFlag ); + } + wsprintfA( idstr, szIdTemplate, i ); + ppro->JDeleteSetting( NULL, idstr ); + wsprintfA( idstr, szFlagTemplate, i ); + ppro->JDeleteSetting( NULL, idstr ); + SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 ); + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + else if ( hti.iSubItem == 2 ) { + EditDlgParam param = { lvi.lParam, ppro }; + int res; + if ( nm->hdr.idFrom == IDC_PHONES ) + res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDPHONE ), hwndDlg, EditPhoneDlgProc, ( LPARAM )¶m ); + else + res = DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_VCARD_ADDEMAIL ), hwndDlg, EditEmailDlgProc, ( LPARAM )¶m ); + if ( res != IDOK ) + break; + SendMessage( hwndDlg,M_REMAKELISTS,0,0 ); + ppro->m_vCardUpdates |= (1UL<<iPageId); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + } + } + break; + } + break; + } + break; + case WM_SETCURSOR: + if ( LOWORD( lParam ) != HTCLIENT ) break; + if ( GetForegroundWindow() == GetParent( hwndDlg )) { + POINT pt; + GetCursorPos( &pt ); + ScreenToClient( hwndDlg,&pt ); + SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click + } + break; + case WM_DESTROY: + ppro->WindowUnsubscribe(hwndDlg); + break; + } + return FALSE; +} + +void CJabberProto::SaveVcardToDB( HWND hwndPage, int iPage ) +{ + TCHAR text[2048]; + + // Page 0: Personal + switch (iPage) { + case 0: + GetDlgItemText( hwndPage, IDC_FULLNAME, text, SIZEOF( text )); + JSetStringT( NULL, "FullName", text ); + GetDlgItemText( hwndPage, IDC_NICKNAME, text, SIZEOF( text )); + JSetStringT( NULL, "Nick", text ); + GetDlgItemText( hwndPage, IDC_FIRSTNAME, text, SIZEOF( text )); + JSetStringT( NULL, "FirstName", text ); + GetDlgItemText( hwndPage, IDC_MIDDLE, text, SIZEOF( text )); + JSetStringT( NULL, "MiddleName", text ); + GetDlgItemText( hwndPage, IDC_LASTNAME, text, SIZEOF( text )); + JSetStringT( NULL, "LastName", text ); + GetDlgItemText( hwndPage, IDC_BIRTH, text, SIZEOF( text )); + JSetStringT( NULL, "BirthDate", text ); + switch( SendMessage( GetDlgItem( hwndPage, IDC_GENDER ), CB_GETCURSEL, 0, 0 )) { + case 0: JSetString( NULL, "GenderString", "Male" ); break; + case 1: JSetString( NULL, "GenderString", "Female" ); break; + default: JSetString( NULL, "GenderString", "" ); break; + } + GetDlgItemText( hwndPage, IDC_OCCUPATION, text, SIZEOF( text )); + JSetStringT( NULL, "Role", text ); + GetDlgItemText( hwndPage, IDC_HOMEPAGE, text, SIZEOF( text )); + JSetStringT( NULL, "Homepage", text ); + break; + + // Page 1: Home + case 1: + GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text )); + JSetStringT( NULL, "Street", text ); + GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text )); + JSetStringT( NULL, "Street2", text ); + GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text )); + JSetStringT( NULL, "City", text ); + GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text )); + JSetStringT( NULL, "State", text ); + GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text )); + JSetStringT( NULL, "ZIP", text ); + { + int i = SendMessage( GetDlgItem( hwndPage, IDC_COUNTRY ), CB_GETCURSEL, 0, 0 ); + TCHAR *country = mir_a2t((i) ? g_countries[i+2].szName : g_countries[1].szName); + JSetStringT( NULL, "Country", country ); + mir_free(country); + } + break; + + // Page 2: Work + case 2: + GetDlgItemText( hwndPage, IDC_COMPANY, text, SIZEOF( text )); + JSetStringT( NULL, "Company", text ); + GetDlgItemText( hwndPage, IDC_DEPARTMENT, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyDepartment", text ); + GetDlgItemText( hwndPage, IDC_TITLE, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyPosition", text ); + GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyStreet", text ); + GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyStreet2", text ); + GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyCity", text ); + GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyState", text ); + GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text )); + JSetStringT( NULL, "CompanyZIP", text ); + { + int i = SendMessage( GetDlgItem( hwndPage, IDC_COUNTRY ), CB_GETCURSEL, 0, 0 ); + TCHAR *country = mir_a2t((i) ? g_countries[i+2].szName : g_countries[1].szName); + JSetStringT( NULL, "CompanyCountry", country ); + mir_free(country); + } + break; + + // Page 3: Photo + // not needed to be saved into db + + // Page 4: Note + case 4: + GetDlgItemText( hwndPage, IDC_DESC, text, SIZEOF( text )); + JSetStringT( NULL, "About", text ); + break; + + // Page 5: Contacts + // is always synced with db +} } + +void CJabberProto::AppendVcardFromDB( HXML n, char* tag, char* key ) +{ + if ( n == NULL || tag == NULL || key == NULL ) + return; + + DBVARIANT dbv; + if ( DBGetContactSettingTString( NULL, m_szModuleName, key, &dbv )) + n << XCHILD( _A2T(tag)); + else { + n << XCHILD( _A2T(tag), dbv.ptszVal ); + JFreeVariant( &dbv ); +} } + +void CJabberProto::SetServerVcard( BOOL bPhotoChanged, TCHAR* szPhotoFileName ) +{ + if (!m_bJabberOnline) return; + + DBVARIANT dbv; + int iqId; + TCHAR *szFileName; + int i; + char idstr[33]; + WORD nFlag; + + iqId = SerialNext(); + IqAdd( iqId, IQ_PROC_SETVCARD, &CJabberProto::OnIqResultSetVcard ); + + XmlNodeIq iq( _T("set"), iqId ); + HXML v = iq << XCHILDNS( _T("vCard"), _T(JABBER_FEAT_VCARD_TEMP)); + + AppendVcardFromDB( v, "FN", "FullName" ); + + HXML n = v << XCHILD( _T("N")); + AppendVcardFromDB( n, "GIVEN", "FirstName" ); + AppendVcardFromDB( n, "MIDDLE", "MiddleName" ); + AppendVcardFromDB( n, "FAMILY", "LastName" ); + + AppendVcardFromDB( v, "NICKNAME", "Nick" ); + AppendVcardFromDB( v, "BDAY", "BirthDate" ); + AppendVcardFromDB( v, "GENDER", "GenderString" ); + + for ( i=0;;i++ ) { + wsprintfA( idstr, "e-mail%d", i ); + if ( DBGetContactSettingTString( NULL, m_szModuleName, idstr, &dbv )) + break; + + HXML e = v << XCHILD( _T("EMAIL"), dbv.ptszVal ); + JFreeVariant( &dbv ); + AppendVcardFromDB( e, "USERID", idstr ); + + wsprintfA( idstr, "e-mailFlag%d", i ); + nFlag = DBGetContactSettingWord( NULL, m_szModuleName, idstr, 0 ); + if ( nFlag & JABBER_VCEMAIL_HOME ) e << XCHILD( _T("HOME")); + if ( nFlag & JABBER_VCEMAIL_WORK ) e << XCHILD( _T("WORK")); + if ( nFlag & JABBER_VCEMAIL_INTERNET ) e << XCHILD( _T("INTERNET")); + if ( nFlag & JABBER_VCEMAIL_X400 ) e << XCHILD( _T("X400")); + } + + n = v << XCHILD( _T("ADR")); + n << XCHILD( _T("HOME")); + AppendVcardFromDB( n, "STREET", "Street" ); + AppendVcardFromDB( n, "EXTADR", "Street2" ); + AppendVcardFromDB( n, "EXTADD", "Street2" ); // for compatibility with client using old vcard format + AppendVcardFromDB( n, "LOCALITY", "City" ); + AppendVcardFromDB( n, "REGION", "State" ); + AppendVcardFromDB( n, "PCODE", "ZIP" ); + AppendVcardFromDB( n, "CTRY", "Country" ); + AppendVcardFromDB( n, "COUNTRY", "Country" ); // for compatibility with client using old vcard format + + n = v << XCHILD( _T("ADR")); + n << XCHILD( _T("WORK")); + AppendVcardFromDB( n, "STREET", "CompanyStreet" ); + AppendVcardFromDB( n, "EXTADR", "CompanyStreet2" ); + AppendVcardFromDB( n, "EXTADD", "CompanyStreet2" ); // for compatibility with client using old vcard format + AppendVcardFromDB( n, "LOCALITY", "CompanyCity" ); + AppendVcardFromDB( n, "REGION", "CompanyState" ); + AppendVcardFromDB( n, "PCODE", "CompanyZIP" ); + AppendVcardFromDB( n, "CTRY", "CompanyCountry" ); + AppendVcardFromDB( n, "COUNTRY", "CompanyCountry" ); // for compatibility with client using old vcard format + + n = v << XCHILD( _T("ORG")); + AppendVcardFromDB( n, "ORGNAME", "Company" ); + AppendVcardFromDB( n, "ORGUNIT", "CompanyDepartment" ); + + AppendVcardFromDB( v, "TITLE", "CompanyPosition" ); + AppendVcardFromDB( v, "ROLE", "Role" ); + AppendVcardFromDB( v, "URL", "Homepage" ); + AppendVcardFromDB( v, "DESC", "About" ); + + for ( i=0;;i++ ) { + wsprintfA( idstr, "Phone%d", i ); + if ( DBGetContactSettingTString( NULL, m_szModuleName, idstr, &dbv )) break; + JFreeVariant( &dbv ); + + n = v << XCHILD( _T("TEL")); + AppendVcardFromDB( n, "NUMBER", idstr ); + + wsprintfA( idstr, "PhoneFlag%d", i ); + nFlag = JGetWord( NULL, idstr, 0 ); + if ( nFlag & JABBER_VCTEL_HOME ) n << XCHILD( _T("HOME")); + if ( nFlag & JABBER_VCTEL_WORK ) n << XCHILD( _T("WORK")); + if ( nFlag & JABBER_VCTEL_VOICE ) n << XCHILD( _T("VOICE")); + if ( nFlag & JABBER_VCTEL_FAX ) n << XCHILD( _T("FAX")); + if ( nFlag & JABBER_VCTEL_PAGER ) n << XCHILD( _T("PAGER")); + if ( nFlag & JABBER_VCTEL_MSG ) n << XCHILD( _T("MSG")); + if ( nFlag & JABBER_VCTEL_CELL ) n << XCHILD( _T("CELL")); + if ( nFlag & JABBER_VCTEL_VIDEO ) n << XCHILD( _T("VIDEO")); + if ( nFlag & JABBER_VCTEL_BBS ) n << XCHILD( _T("BBS")); + if ( nFlag & JABBER_VCTEL_MODEM ) n << XCHILD( _T("MODEM")); + if ( nFlag & JABBER_VCTEL_ISDN ) n << XCHILD( _T("ISDN")); + if ( nFlag & JABBER_VCTEL_PCS ) n << XCHILD( _T("PCS")); + } + + TCHAR szAvatarName[ MAX_PATH ]; + GetAvatarFileName( NULL, szAvatarName, SIZEOF( szAvatarName )); + if ( bPhotoChanged ) + szFileName = szPhotoFileName; + else + szFileName = szAvatarName; + + // Set photo element, also update the global jabberVcardPhotoFileName to reflect the update + Log( "Before update, file name = " TCHAR_STR_PARAM, szFileName ); + if ( szFileName == NULL || szFileName[0] == 0 ) { + v << XCHILD( _T("PHOTO")); + DeleteFile( szAvatarName ); + JDeleteSetting( NULL, "AvatarSaved" ); + JDeleteSetting( NULL, "AvatarHash" ); + } + else { + HANDLE hFile; + struct _stat st; + char* buffer, *str; + DWORD nRead; + + Log( "Saving picture from " TCHAR_STR_PARAM, szFileName ); + if ( _tstat( szFileName, &st ) >= 0 ) { + // Note the FILE_SHARE_READ attribute so that the CopyFile can succeed + if (( hFile=CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) { + if (( buffer=( char* )mir_alloc( st.st_size )) != NULL ) { + if ( ReadFile( hFile, buffer, st.st_size, &nRead, NULL )) { + if (( str=JabberBase64Encode( buffer, nRead )) != NULL ) { + n = v << XCHILD( _T("PHOTO")); + TCHAR* szFileType; + switch( JabberGetPictureType( buffer )) { + case PA_FORMAT_PNG: szFileType = _T("image/png"); break; + case PA_FORMAT_GIF: szFileType = _T("image/gif"); break; + case PA_FORMAT_BMP: szFileType = _T("image/bmp"); break; + default: szFileType = _T("image/jpeg"); break; + } + n << XCHILD( _T("TYPE"), szFileType ); + + n << XCHILD( _T("BINVAL"), _A2T(str)); + mir_free( str ); + + // NEED TO UPDATE OUR AVATAR HASH: + + mir_sha1_byte_t digest[MIR_SHA1_HASH_SIZE]; + mir_sha1_ctx sha1ctx; + mir_sha1_init( &sha1ctx ); + mir_sha1_append( &sha1ctx, (mir_sha1_byte_t*)buffer, nRead ); + mir_sha1_finish( &sha1ctx, digest ); + + char buf[MIR_SHA1_HASH_SIZE*2+1]; + for ( int j=0; j<MIR_SHA1_HASH_SIZE; j++ ) + sprintf( buf+( j<<1 ), "%02x", digest[j] ); + + m_options.AvatarType = JabberGetPictureType( buffer ); + + if ( bPhotoChanged ) { + DeleteFile( szAvatarName ); + + GetAvatarFileName( NULL, szAvatarName, SIZEOF( szAvatarName )); + + CopyFile( szFileName, szAvatarName, FALSE ); + } + + JSetString( NULL, "AvatarHash", buf ); + JSetString( NULL, "AvatarSaved", buf ); + } } + mir_free( buffer ); + } + CloseHandle( hFile ); + } } } + + m_ThreadInfo->send( iq ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CJabberProto::OnUserInfoInit_VCard( WPARAM wParam, LPARAM ) +{ + m_vCardUpdates = 0; + m_bPhotoChanged = FALSE; + m_szPhotoFileName[0] = 0; + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.dwInitParam = (LPARAM)this; + odp.flags = ODPF_TCHAR|ODPF_USERINFOTAB|ODPF_DONTTRANSLATE; + odp.ptszTitle = m_tszUserName; + + odp.pfnDlgProc = PersonalDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_PERSONAL); + odp.ptszTab = LPGENT("General"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = ContactDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_CONTACT); + odp.ptszTab = LPGENT("Contacts"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = HomeDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_HOME); + odp.ptszTab = LPGENT("Home"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = WorkDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_WORK); + odp.ptszTab = LPGENT("Work"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = PhotoDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_PHOTO); + odp.ptszTab = LPGENT("Photo"); + UserInfo_AddPage(wParam, &odp); + + odp.pfnDlgProc = NoteDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_VCARD_NOTE); + odp.ptszTab = LPGENT("Note"); + UserInfo_AddPage(wParam, &odp); + + SendGetVcard( m_szJabberJID ); +} diff --git a/protocols/JabberG/src/jabber_ws.cpp b/protocols/JabberG/src/jabber_ws.cpp new file mode 100644 index 0000000000..494dcf3454 --- /dev/null +++ b/protocols/JabberG/src/jabber_ws.cpp @@ -0,0 +1,90 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +BOOL CJabberProto::WsInit( void ) +{ + m_lastTicks = ::GetTickCount(); + + TCHAR name[128]; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); + + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof( nlu ); + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR; // | NUF_HTTPGATEWAY; + nlu.ptszDescriptiveName = name; + nlu.szSettingsModule = m_szModuleName; + //nlu.szHttpGatewayHello = "http://http.proxy.icq.com/hello"; + //nlu.szHttpGatewayUserAgent = "Mozilla/4.08 [en] ( WinNT; U ;Nav )"; + //nlu.pfnHttpGatewayInit = JabberHttpGatewayInit; + //nlu.pfnHttpGatewayBegin = JabberHttpGatewayBegin; + //nlu.pfnHttpGatewayWrapSend = JabberHttpGatewayWrapSend; + //nlu.pfnHttpGatewayUnwrapRecv = JabberHttpGatewayUnwrapRecv; + m_hNetlibUser = ( HANDLE ) CallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu ); + + return m_hNetlibUser != NULL; +} + +void CJabberProto::WsUninit( void ) +{ + Netlib_CloseHandle( m_hNetlibUser ); + m_hNetlibUser = NULL; +} + +JABBER_SOCKET CJabberProto::WsConnect( char* host, WORD port ) +{ + NETLIBOPENCONNECTION nloc = { 0 }; + nloc.cbSize = sizeof( nloc ); + nloc.szHost = host; + nloc.wPort = port; + nloc.timeout = 6; + return ( HANDLE )CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); +} + +int CJabberProto::WsSend( JABBER_SOCKET hConn, char* data, int datalen, int flags ) +{ + m_lastTicks = ::GetTickCount(); + int len; + + if (( len = Netlib_Send( hConn, data, datalen, flags )) == SOCKET_ERROR || len != datalen ) { + Log( "Netlib_Send() failed, error=%d", WSAGetLastError()); + return SOCKET_ERROR; + } + return len; +} + +int CJabberProto::WsRecv( JABBER_SOCKET hConn, char* data, long datalen, int flags ) +{ + int ret; + + ret = Netlib_Recv( hConn, data, datalen, flags ); + if ( ret == SOCKET_ERROR ) { + Log( "Netlib_Recv() failed, error=%d", WSAGetLastError()); + return 0; + } + if ( ret == 0 ) { + Log( "Connection closed gracefully" ); + return 0; + } + return ret; +} diff --git a/protocols/JabberG/src/jabber_xml.cpp b/protocols/JabberG/src/jabber_xml.cpp new file mode 100644 index 0000000000..287a335243 --- /dev/null +++ b/protocols/JabberG/src/jabber_xml.cpp @@ -0,0 +1,524 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +#define TAG_MAX_LEN 128 +#define ATTR_MAX_LEN 8192 + +#define T2UTF(A) A + +///////////////////////////////////////////////////////////////////////////////////////// +// XmlNodeIq class members + +XmlNodeIq::XmlNodeIq( const TCHAR* type, int id, LPCTSTR to ) : + XmlNode( _T( "iq" )) +{ + if ( type != NULL ) *this << XATTR( _T("type"), type ); + if ( to != NULL ) *this << XATTR( _T("to"), to ); + if ( id != -1 ) *this << XATTRID( id ); +} + +XmlNodeIq::XmlNodeIq( const TCHAR* type, LPCTSTR idStr, LPCTSTR to ) : + XmlNode( _T( "iq" )) +{ + if ( type != NULL ) *this << XATTR( _T("type"), type ); + if ( to != NULL ) *this << XATTR( _T("to"), to ); + if ( idStr != NULL ) *this << XATTR( _T("id"), idStr ); +} + +XmlNodeIq::XmlNodeIq( const TCHAR* type, HXML node, LPCTSTR to ) : + XmlNode( _T( "iq" )) +{ + if ( type != NULL ) *this << XATTR( _T("type"), type ); + if ( to != NULL ) *this << XATTR( _T("to"), to ); + if ( node != NULL ) { + const TCHAR *iqId = xmlGetAttrValue( *this, _T( "id" )); + if ( iqId != NULL ) *this << XATTR( _T("id"), iqId ); + } +} + +XmlNodeIq::XmlNodeIq( CJabberIqInfo* pInfo ) : + XmlNode( _T( "iq" )) +{ + if ( pInfo ) { + if ( pInfo->GetCharIqType() != NULL ) *this << XATTR( _T("type"), _A2T(pInfo->GetCharIqType())); + if ( pInfo->GetReceiver() != NULL ) *this << XATTR( _T("to"), pInfo->GetReceiver()); + if ( pInfo->GetIqId() != -1 ) *this << XATTRID( pInfo->GetIqId()); + } +} + +XmlNodeIq::XmlNodeIq( const TCHAR* type, CJabberIqInfo* pInfo ) : + XmlNode( _T( "iq" )) +{ + if ( type != NULL ) *this << XATTR( _T("type"), type ); + if ( pInfo ) { + if ( pInfo->GetFrom() != NULL ) *this << XATTR( _T("to"), pInfo->GetFrom()); + if ( pInfo->GetIdStr() != NULL ) *this << XATTR( _T("id"), pInfo->GetIdStr()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// XmlNode class members + +XmlNode::XmlNode( LPCTSTR pszName ) +{ + m_hXml = xi.createNode( T2UTF(pszName), NULL, 0 ); +} + +XmlNode::XmlNode( LPCTSTR pszName, LPCTSTR ptszText ) +{ + m_hXml = xi.createNode( T2UTF(pszName), ptszText, 0 ); +} + +XmlNode::XmlNode( const XmlNode& n ) +{ + m_hXml = xi.copyNode( n ); +} + +XmlNode& XmlNode::operator =( const XmlNode& n ) +{ + if ( m_hXml ) + xi.destroyNode( m_hXml ); + m_hXml = xi.copyNode( n ); + return *this; +} + +XmlNode::~XmlNode() +{ + if ( m_hXml ) { + xi.destroyNode( m_hXml ); + m_hXml = NULL; +} } + +///////////////////////////////////////////////////////////////////////////////////////// + +HXML __fastcall operator<<( HXML node, const XCHILDNS& child ) +{ + HXML res = xmlAddChild( node, child.name ); + xmlAddAttr( res, _T("xmlns"), child.ns ); + return res; +} + +HXML __fastcall operator<<( HXML node, const XQUERY& child ) +{ + HXML n = xmlAddChild( node, _T("query")); + if ( n ) + xmlAddAttr( n, _T("xmlns"), child.ns ); + return n; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void __fastcall xmlAddAttr( HXML hXml, LPCTSTR name, LPCTSTR value ) +{ + if ( value ) + xi.addAttr( hXml, name, T2UTF(value)); +} + +void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, int value ) +{ + xi.addAttrInt( hXml, T2UTF(pszName), value ); +} + +void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, unsigned __int64 value ) +{ + TCHAR buf[60]; + _ui64tot( value, buf, 10 ); + + xi.addAttr( hXml, T2UTF(pszName), T2UTF(buf)); +} + +void __fastcall xmlAddAttrID( HXML hXml, int id ) +{ + TCHAR text[ 100 ]; + mir_sntprintf( text, SIZEOF(text), _T("mir_%d"), id ); + xmlAddAttr( hXml, _T("id"), text ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +LPCTSTR __fastcall xmlGetAttr( HXML hXml, int n ) +{ + return xi.getAttr( hXml, n ); +} + +int __fastcall xmlGetAttrCount( HXML hXml ) +{ + return xi.getAttrCount( hXml ); +} + +LPCTSTR __fastcall xmlGetAttrName( HXML hXml, int n ) +{ + return xi.getAttrName( hXml, n ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void __fastcall xmlAddChild( HXML hXml, HXML n ) +{ + xi.addChild2( n, hXml ); +} + +HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name ) +{ + return xi.addChild( hXml, T2UTF(name), NULL ); +} + +HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name, LPCTSTR value ) +{ + return xi.addChild( hXml, T2UTF(name), T2UTF(value)); +} + +HXML __fastcall xmlAddChild( HXML hXml, LPCTSTR name, int value ) +{ + TCHAR buf[40]; + _itot( value, buf, 10 ); + return xi.addChild( hXml, T2UTF(name), buf ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +LPCTSTR __fastcall xmlGetAttrValue( HXML hXml, LPCTSTR key ) +{ + return xi.getAttrValue( hXml, key ); +} + +HXML __fastcall xmlGetChild( HXML hXml, int n ) +{ + return xi.getChild( hXml, n ); +} + +HXML __fastcall xmlGetChild( HXML hXml, LPCTSTR key ) +{ + return xi.getNthChild( hXml, key, 0 ); +} + +HXML __fastcall xmlGetChild( HXML hXml, LPCSTR key ) +{ + LPTSTR wszKey = mir_a2t( key ); + HXML result = xi.getNthChild( hXml, wszKey, 0 ); + mir_free( wszKey ); + return result; +} + +HXML __fastcall xmlGetChildByTag( HXML hXml, LPCTSTR key, LPCTSTR attrName, LPCTSTR attrValue ) +{ + return xi.getChildByAttrValue( hXml, key, attrName, attrValue ); +} + +HXML __fastcall xmlGetChildByTag( HXML hXml, LPCSTR key, LPCSTR attrName, LPCTSTR attrValue ) +{ + LPTSTR wszKey = mir_a2t( key ), wszName = mir_a2t( attrName ); + HXML result = xi.getChildByAttrValue( hXml, wszKey, wszName, attrValue ); + mir_free( wszKey ), mir_free( wszName ); + return result; +} + +int __fastcall xmlGetChildCount( HXML hXml ) +{ + return xi.getChildCount( hXml ); +} + +HXML __fastcall xmlGetNthChild( HXML hXml, LPCTSTR tag, int nth ) +{ + int i, num; + + if ( !hXml || tag == NULL || _tcslen( tag ) <= 0 || nth < 1 ) + return NULL; + + num = 1; + for ( i=0; ; i++ ) { + HXML n = xi.getChild( hXml, i ); + if ( !n ) + break; + if ( !lstrcmp( tag, xmlGetName( n ))) { + if ( num == nth ) + return n; + + num++; + } } + + return NULL; +} + +LPCTSTR __fastcall xmlGetName( HXML xml ) +{ + return xi.getName( xml ); +} + +LPCTSTR __fastcall xmlGetText( HXML xml ) +{ + return xi.getText( xml ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void XPath::ProcessPath(LookupInfo &info, bool bCreate) +{ + if (!info.nodeName) return; + + TCHAR *nodeName = (TCHAR *)alloca(sizeof(TCHAR) * (info.nodeName.length+1)); + lstrcpyn(nodeName, info.nodeName.p, info.nodeName.length+1); + + if (info.attrName && info.attrValue) + { + TCHAR *attrName = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrName.length+1)); + lstrcpyn(attrName, info.attrName.p, info.attrName.length+1); + TCHAR *attrValue = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrValue.length+1)); + lstrcpyn(attrValue, info.attrValue.p, info.attrValue.length+1); + HXML hXml = xmlGetChildByTag(m_hXml, nodeName, attrName, attrValue); + + m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName) << XATTR(attrName, attrValue)); + } else + if (info.nodeIndex) + { + int idx = _ttoi(info.nodeIndex.p); + m_hXml = lstrcmp(nodeName, _T("*")) ? xmlGetNthChild(m_hXml, nodeName, idx) : xmlGetChild(m_hXml, idx-1); + + // no support for such creation mode + } else + { + HXML hXml = xmlGetChild(m_hXml, nodeName); + m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName)); + } + + info.Reset(); +} + +XPath::PathType XPath::LookupImpl(bool bCreate) +{ + LookupState state = S_START; + LookupInfo info = {0}; + + for (LPCTSTR p = m_szPath; state < S_FINAL; ++p) + { + switch (state) + { + case S_START: + { + ProcessPath(info, bCreate); + if (!m_hXml) + { + state = S_FINAL_ERROR; + break; + } + + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T('@'): + info.attrName.Begin(p+1); + state = S_ATTR_STEP; + break; + case _T('/'): + break; + default: + info.nodeName.Begin(p); + state = S_NODE_NAME; + break; + }; + break; + } + case S_ATTR_STEP: + { + switch (*p) + { + case 0: + info.attrName.End(p); + state = S_FINAL_ATTR; + break; + default: + break; + }; + break; + } + case S_NODE_NAME: + { + switch (*p) + { + case 0: + info.nodeName.End(p); + state = S_FINAL_NODESET; + break; + case _T('['): + info.nodeName.End(p); + state = S_NODE_OPENBRACKET; + break; + case _T('/'): + info.nodeName.End(p); + state = S_START; + break; + default: + break; + }; + break; + } + case S_NODE_OPENBRACKET: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T('@'): + info.attrName.Begin(p+1); + state = S_NODE_ATTRNAME; + break; + case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): + case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): + info.nodeIndex.Begin(p); + state = S_NODE_INDEX; + break; + default: + state = S_FINAL_ERROR; + break; + }; + break; + } + case S_NODE_INDEX: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T(']'): + info.nodeIndex.End(p); + state = S_NODE_CLOSEBRACKET; + break; + case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): + case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): + break; + default: + state = S_FINAL_ERROR; + break; + }; + break; + } + case S_NODE_ATTRNAME: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T('='): + info.attrName.End(p); + state = S_NODE_ATTREQUALS; + break; + default: + break; + }; + break; + } + case S_NODE_ATTREQUALS: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T('\''): + info.attrValue.Begin(p+1); + state = S_NODE_ATTRVALUE; + break; + default: + state = S_FINAL_ERROR; + break; + }; + break; + } + case S_NODE_ATTRVALUE: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T('\''): + info.attrValue.End(p); + state = S_NODE_ATTRCLOSEVALUE; + break; + default: + break; + }; + break; + } + case S_NODE_ATTRCLOSEVALUE: + { + switch (*p) + { + case 0: + state = S_FINAL_ERROR; + break; + case _T(']'): + state = S_NODE_CLOSEBRACKET; + break; + default: + state = S_FINAL_ERROR; + break; + }; + break; + } + case S_NODE_CLOSEBRACKET: + { + switch (*p) + { + case 0: + state = S_FINAL_NODE; + break; + case _T('/'): + state = S_START; + break; + default: + state = S_FINAL_ERROR; + break; + }; + break; + } + } + + if (!*p && (state < S_FINAL)) + { + state = S_FINAL_ERROR; + } + } + + switch (state) + { + case S_FINAL_ATTR: + m_szParam = info.attrName.p; + return T_ATTRIBUTE; + case S_FINAL_NODE: + ProcessPath(info, bCreate); + return T_NODE; + case S_FINAL_NODESET: + m_szParam = info.nodeName.p; + return T_NODESET; + } + + return T_ERROR; +} diff --git a/protocols/JabberG/src/jabber_xml.h b/protocols/JabberG/src/jabber_xml.h new file mode 100644 index 0000000000..0a1b41e511 --- /dev/null +++ b/protocols/JabberG/src/jabber_xml.h @@ -0,0 +1,382 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_XML_H_ +#define _JABBER_XML_H_ + +#include <m_xml.h> + +void __fastcall xmlAddChild( HXML, HXML ); +HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName ); +HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName, LPCTSTR ptszValue ); +HXML __fastcall xmlAddChild( HXML, LPCTSTR pszName, int iValue ); + +LPCTSTR __fastcall xmlGetAttrValue( HXML, LPCTSTR key ); +HXML __fastcall xmlGetChild( HXML, int n = 0 ); +HXML __fastcall xmlGetChild( HXML, LPCSTR key ); +HXML __fastcall xmlGetChild( HXML, LPCTSTR key ); +int __fastcall xmlGetChildCount( HXML ); +HXML __fastcall xmlGetChildByTag( HXML, LPCTSTR key, LPCTSTR attrName, LPCTSTR attrValue ); +HXML __fastcall xmlGetChildByTag( HXML, LPCSTR key, LPCSTR attrName, LPCTSTR attrValue ); +HXML __fastcall xmlGetNthChild( HXML, LPCTSTR key, int n = 0 ); + +LPCTSTR __fastcall xmlGetName( HXML ); +LPCTSTR __fastcall xmlGetText( HXML ); + +void __fastcall xmlAddAttr( HXML, LPCTSTR pszName, LPCTSTR ptszValue ); +void __fastcall xmlAddAttr( HXML, LPCTSTR pszName, int value ); +void __fastcall xmlAddAttr( HXML hXml, LPCTSTR pszName, unsigned __int64 value ); +void __fastcall xmlAddAttrID( HXML, int id ); + +int __fastcall xmlGetAttrCount( HXML ); +LPCTSTR __fastcall xmlGetAttr( HXML, int n ); +LPCTSTR __fastcall xmlGetAttrName( HXML, int n ); +LPCTSTR __fastcall xmlGetAttrValue( HXML, LPCTSTR key ); + +struct XmlNode +{ + __forceinline XmlNode() { m_hXml = NULL; } + + __forceinline XmlNode( LPCTSTR pszString, int* numBytes, LPCTSTR ptszTag ) + { + m_hXml = xi.parseString( pszString, numBytes, ptszTag ); + } + + XmlNode( const XmlNode& n ); + XmlNode( LPCTSTR name ); + XmlNode( LPCTSTR pszName, LPCTSTR ptszText ); + ~XmlNode(); + + XmlNode& operator =( const XmlNode& n ); + + __forceinline operator HXML() const + { return m_hXml; + } + +private: + HXML m_hXml; +}; + +class CJabberIqInfo; + +struct XmlNodeIq : public XmlNode +{ + XmlNodeIq( const TCHAR* type, int id = -1, const TCHAR* to = NULL ); + XmlNodeIq( const TCHAR* type, const TCHAR* idStr, const TCHAR* to ); + XmlNodeIq( const TCHAR* type, HXML node, const TCHAR* to ); + // new request + XmlNodeIq( CJabberIqInfo* pInfo ); + // answer to request + XmlNodeIq( const TCHAR* type, CJabberIqInfo* pInfo ); +}; + +typedef void ( *JABBER_XML_CALLBACK )( HXML, void* ); + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XATTR +{ + LPCTSTR name, value; + + __forceinline XATTR( LPCTSTR _name, LPCTSTR _value ) : + name( _name ), + value( _value ) + {} +}; + +HXML __forceinline operator<<( HXML node, const XATTR& attr ) +{ xmlAddAttr( node, attr.name, attr.value ); + return node; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XATTRI +{ + LPCTSTR name; + int value; + + __forceinline XATTRI( LPCTSTR _name, int _value ) : + name( _name ), + value( _value ) + {} +}; + +HXML __forceinline operator<<( HXML node, const XATTRI& attr ) +{ xmlAddAttr( node, attr.name, attr.value ); + return node; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XATTRI64 +{ + LPCTSTR name; + unsigned __int64 value; + + __forceinline XATTRI64( LPCTSTR _name, unsigned __int64 _value ) : + name( _name ), + value( _value ) + {} +}; + +HXML __forceinline operator<<( HXML node, const XATTRI64& attr ) +{ xmlAddAttr( node, attr.name, attr.value ); + return node; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XATTRID +{ + int id; + + __forceinline XATTRID( int _value ) : + id( _value ) + {} +}; + +HXML __forceinline operator<<( HXML node, const XATTRID& attr ) +{ xmlAddAttrID( node, attr.id ); + return node; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XCHILD +{ + LPCTSTR name, value; + + __forceinline XCHILD( LPCTSTR _name, LPCTSTR _value = NULL ) : + name( _name ), + value( _value ) + {} +}; + +HXML __forceinline operator<<( HXML node, const XCHILD& child ) +{ return xmlAddChild( node, child.name, child.value ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XCHILDNS +{ + LPCTSTR name, ns; + + __forceinline XCHILDNS( LPCTSTR _name, LPCTSTR _ns = NULL ) : + name( _name ), + ns( _ns ) + {} +}; + +HXML __fastcall operator<<( HXML node, const XCHILDNS& child ); + +///////////////////////////////////////////////////////////////////////////////////////// + +struct XQUERY +{ + LPCTSTR ns; + + __forceinline XQUERY( LPCTSTR _ns ) : + ns( _ns ) + {} +}; + +HXML __fastcall operator<<( HXML node, const XQUERY& child ); + +///////////////////////////////////////////////////////////////////////////////////////// +// Limited XPath support +// path should look like: "node-spec/node-spec/.../result-spec" +// where "node-spec" can be "node-name", "node-name[@attr-name='attr-value']" or "node-name[node-index]" +// result may be either "node-spec", or "@attr-name" +// +// Samples: +// LPCTSTR s = XPathT(node, "child/subchild[@attr='value']"); // get node text +// LPCTSTR s = XPathT(node, "child/subchild[2]/@attr"); // get attribute value +// XPathT(node, "child/subchild[@name='test']/@attr") = _T("Hello"); // create path if needed and set attribute value +// +// XPathT(node, "child/subchild[@name='test']") = _T("Hello"); // TODO: create path if needed and set node text + +#define XPathT(a,b) XPath(a, _T(b)) + +class XPath +{ +public: + __forceinline XPath(HXML hXml, TCHAR *path): + m_type(T_UNKNOWN), + m_hXml(hXml), + m_szPath(path), + m_szParam(NULL) + {} + + // Read data + operator HXML() + { + switch (Lookup()) + { + case T_NODE: return m_hXml; + case T_NODESET: return xmlGetNthChild(m_hXml, m_szParam, 1); + } + return NULL; + } + operator LPTSTR() + { + switch (Lookup()) + { + case T_ATTRIBUTE: return (TCHAR *)xmlGetAttrValue(m_hXml, m_szParam); + case T_NODE: return (TCHAR *)xmlGetText(m_hXml); + case T_NODESET: return (TCHAR *)xmlGetText(xmlGetNthChild(m_hXml, m_szParam, 1)); + } + return NULL; + } + operator int() + { + if (TCHAR *s = *this) return _ttoi(s); + return 0; + } + __forceinline bool operator== (TCHAR *str) + { + return !lstrcmp((LPCTSTR)*this, str); + } + __forceinline bool operator!= (TCHAR *str) + { + return lstrcmp((LPCTSTR)*this, str) ? true : false; + } + HXML operator[] (int idx) + { + return (Lookup() == T_NODESET) ? xmlGetNthChild(m_hXml, m_szParam, idx) : NULL; + } + + // Write data + void operator= (LPCTSTR value) + { + switch (Lookup(true)) + { + case T_ATTRIBUTE: xmlAddAttr(m_hXml, m_szParam, value); break; + case T_NODE: break; // TODO: set node text + } + } + void operator= (int value) + { + TCHAR buf[16]; + _itot(value, buf, 10); + *this = buf; + } + +private: + enum PathType + { + T_UNKNOWN, + T_ERROR, + T_NODE, + T_ATTRIBUTE, + T_NODESET + }; + + __forceinline PathType Lookup(bool bCreate=false) + { + return (m_type == T_UNKNOWN) ? LookupImpl(bCreate) : m_type; + } + + enum LookupState + { + S_START, + S_ATTR_STEP, + S_NODE_NAME, + S_NODE_OPENBRACKET, + S_NODE_INDEX, + S_NODE_ATTRNAME, + S_NODE_ATTREQUALS, + S_NODE_ATTRVALUE, + S_NODE_ATTRCLOSEVALUE, + S_NODE_CLOSEBRACKET, + + S_FINAL, + S_FINAL_ERROR, + S_FINAL_ATTR, + S_FINAL_NODESET, + S_FINAL_NODE + }; + + struct LookupString + { + void Begin(const TCHAR *p_) { p = p_; } + void End(const TCHAR *p_) { length = p_ - p; } + operator bool() { return p ? true : false; } + + const TCHAR *p; + int length; + + }; + + struct LookupInfo + { + void Reset() { memset(this, 0, sizeof(*this)); } + LookupString nodeName; + LookupString attrName; + LookupString attrValue; + LookupString nodeIndex; + }; + + void ProcessPath(LookupInfo &info, bool bCreate); + PathType LookupImpl(bool bCreate); + + PathType m_type; + HXML m_hXml; + LPCTSTR m_szPath; + LPCTSTR m_szParam; +}; + +class XPathFmt: public XPath +{ +public: + enum { BUFSIZE = 512 }; + XPathFmt(HXML hXml, TCHAR *path, ...): XPath(hXml, m_buf) + { + *m_buf = 0; + + va_list args; + va_start(args, path); + _vsntprintf(m_buf, BUFSIZE, path, args); + m_buf[BUFSIZE-1] = 0; + va_end(args); + } + + XPathFmt(HXML hXml, char *path, ...): XPath(hXml, m_buf) + { + *m_buf = 0; + char buf[BUFSIZE]; + + va_list args; + va_start(args, path); + _vsnprintf(buf, BUFSIZE, path, args); + buf[BUFSIZE-1] = 0; + MultiByteToWideChar(CP_ACP, 0, buf, -1, m_buf, BUFSIZE); + va_end(args); + } + +private: + TCHAR m_buf[BUFSIZE]; +}; + +#endif diff --git a/protocols/JabberG/src/jabber_xstatus.cpp b/protocols/JabberG/src/jabber_xstatus.cpp new file mode 100644 index 0000000000..d15cae2bcd --- /dev/null +++ b/protocols/JabberG/src/jabber_xstatus.cpp @@ -0,0 +1,2138 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Maxim Mluhov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" +#include "jabber_caps.h" + +#include <m_genmenu.h> +#include <m_icolib.h> +#include <m_fontservice.h> + +#include <m_cluiframes.h> + +#include "m_proto_listeningto.h" +#include "m_skin_eng.h" +#include "m_extraicons.h" + +/////////////////////////////////////////////////////////////////////////////// +// Simple dialog with timer and ok/cancel buttons +class CJabberDlgPepBase: public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; +public: + CJabberDlgPepBase(CJabberProto *proto, int id); + +protected: + CPepService *m_pepService; + + CCtrlButton m_btnOk; + CCtrlButton m_btnCancel; + + void OnInitDialog(); + int Resizer(UTILRESIZECONTROL *urc); + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + void StopTimer(); + +private: + int m_time; +}; + +CJabberDlgPepBase::CJabberDlgPepBase(CJabberProto *proto, int id): + CJabberDlgBase(proto, id, NULL), + m_btnOk(this, IDOK), + m_btnCancel(this, IDCANCEL) +{ +} + +void CJabberDlgPepBase::OnInitDialog() +{ + CSuper::OnInitDialog(); + + m_time = 5; + SetTimer(m_hwnd, 1, 1000, NULL); + + TCHAR buf[128]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), m_time); + m_btnOk.SetText(buf); +} + +int CJabberDlgPepBase::Resizer(UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDOK: + case IDCANCEL: + return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; + } + + return CSuper::Resizer(urc); +} + +INT_PTR CJabberDlgPepBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_TIMER: + if (wParam == 1) { + TCHAR buf[128]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s (%d)"), TranslateT("OK"), --m_time); + m_btnOk.SetText(buf); + + if (m_time < 0) { + KillTimer(m_hwnd, 1); + UIEmulateBtnClick(m_hwnd, IDOK); + } + + return TRUE; + } + + break; + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +void CJabberDlgPepBase::StopTimer() +{ + KillTimer(m_hwnd, 1); + m_btnOk.SetText(TranslateT("OK")); +} + +/////////////////////////////////////////////////////////////////////////////// +// Simple PEP status +class CJabberDlgPepSimple: public CJabberDlgPepBase +{ + typedef CJabberDlgPepBase CSuper; +public: + CJabberDlgPepSimple(CJabberProto *proto, TCHAR *title); + ~CJabberDlgPepSimple(); + + bool OkClicked() { return m_bOkClicked; } + void AddStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem = false); + void SetActiveStatus(LPARAM id, TCHAR *text); + LPARAM GetStatusMode(); + TCHAR *GetStatusText(); + +protected: + CCtrlCombo m_cbModes; + CCtrlEdit m_txtDescription; + + void OnInitDialog(); + int Resizer(UTILRESIZECONTROL *urc); + + UI_MESSAGE_MAP(CJabberDlgPepSimple, CSuper); + UI_MESSAGE(WM_MEASUREITEM, OnWmMeasureItem); + UI_MESSAGE(WM_DRAWITEM, OnWmDrawItem); + UI_MESSAGE(WM_GETMINMAXINFO, OnWmGetMinMaxInfo); + UI_MESSAGE_MAP_END(); + + BOOL OnWmMeasureItem(UINT msg, WPARAM wParam, LPARAM lParam); + BOOL OnWmDrawItem(UINT msg, WPARAM wParam, LPARAM lParam); + BOOL OnWmGetMinMaxInfo(UINT msg, WPARAM wParam, LPARAM lParam); + +private: + struct CStatusMode + { + LPARAM m_id; + char *m_name; + HICON m_hIcon; + TCHAR *m_title; + bool m_subitem; + + CStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem): m_id(id), m_name(name), m_hIcon(hIcon), m_title(title), m_subitem(subitem) {} + ~CStatusMode() { g_ReleaseIcon( m_hIcon ); } + }; + + OBJLIST<CStatusMode> m_modes; + TCHAR *m_text; + TCHAR *m_title; + int m_time; + int m_prevSelected; + int m_selected; + bool m_bOkClicked; + + LPARAM m_active; + TCHAR *m_activeText; + + void btnOk_OnClick(CCtrlButton *btn); + void global_OnChange(CCtrlData *); + void cbModes_OnChange(CCtrlData *); +}; + +CJabberDlgPepSimple::CJabberDlgPepSimple(CJabberProto *proto, TCHAR *title): + CJabberDlgPepBase(proto, IDD_PEP_SIMPLE), + m_cbModes(this, IDC_CB_MODES), + m_txtDescription(this, IDC_TXT_DESCRIPTION), + m_modes(10), + m_text(NULL), + m_selected(0), + m_prevSelected(-1), + m_active(-1), + m_bOkClicked(false), + m_title(title) +{ + m_btnOk.OnClick = Callback(this, &CJabberDlgPepSimple::btnOk_OnClick); + m_cbModes.OnChange = Callback(this, &CJabberDlgPepSimple::cbModes_OnChange); + m_cbModes.OnDropdown = + m_txtDescription.OnChange = Callback(this, &CJabberDlgPepSimple::global_OnChange); + + m_modes.insert(new CStatusMode(-1, "<none>", LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT), TranslateT("None"), false)); +} + +CJabberDlgPepSimple::~CJabberDlgPepSimple() +{ + mir_free(m_text); +} + +void CJabberDlgPepSimple::AddStatusMode(LPARAM id, char *name, HICON hIcon, TCHAR *title, bool subitem) +{ + m_modes.insert(new CStatusMode(id, name, hIcon, title, subitem)); +} + +void CJabberDlgPepSimple::SetActiveStatus(LPARAM id, TCHAR *text) +{ + m_active = id; + m_activeText = text; +} + +LPARAM CJabberDlgPepSimple::GetStatusMode() +{ + return m_modes[m_selected].m_id; +} + +TCHAR *CJabberDlgPepSimple::GetStatusText() +{ + return m_text; +} + +void CJabberDlgPepSimple::OnInitDialog() +{ + CSuper::OnInitDialog(); + + WindowSetIcon( m_hwnd, m_proto, "main" ); + SetWindowText(m_hwnd, m_title); + + m_txtDescription.Enable(false); + for (int i = 0; i < m_modes.getCount(); ++i) + { + int idx = m_cbModes.AddString(m_modes[i].m_title, i); + if ((m_modes[i].m_id == m_active) || !idx) + { + m_prevSelected = idx; + m_cbModes.SetCurSel(idx); + if (idx) m_txtDescription.Enable(); + } + } + if (m_activeText) + { + m_txtDescription.SetText(m_activeText); + } +} + +int CJabberDlgPepSimple::Resizer(UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_CB_MODES: + return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; + case IDC_TXT_DESCRIPTION: + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + } + + return CSuper::Resizer(urc); +} + +void CJabberDlgPepSimple::btnOk_OnClick(CCtrlButton*) +{ + m_text = m_txtDescription.GetText(); + m_selected = m_cbModes.GetCurSel(); + m_bOkClicked = true; +} + +void CJabberDlgPepSimple::global_OnChange(CCtrlData *) +{ + StopTimer(); +} + +void CJabberDlgPepSimple::cbModes_OnChange(CCtrlData *) +{ + StopTimer(); + + if (m_prevSelected == m_cbModes.GetCurSel()) + return; + + char szSetting[128]; + + if ((m_prevSelected >= 0) && (m_modes[m_cbModes.GetItemData(m_prevSelected)].m_id >= 0)) + { + TCHAR *txt = m_txtDescription.GetText(); + mir_snprintf(szSetting, SIZEOF(szSetting), "PepMsg_%s", m_modes[m_cbModes.GetItemData(m_prevSelected)].m_name); + m_proto->JSetStringT(NULL, szSetting, txt); + mir_free(txt); + } + + m_prevSelected = m_cbModes.GetCurSel(); + if ((m_prevSelected >= 0) && (m_modes[m_cbModes.GetItemData(m_prevSelected)].m_id >= 0)) + { + mir_snprintf(szSetting, SIZEOF(szSetting), "PepMsg_%s", m_modes[m_cbModes.GetItemData(m_prevSelected)].m_name); + + DBVARIANT dbv; + if (!m_proto->JGetStringT(NULL, szSetting, &dbv)) + { + m_txtDescription.SetText(dbv.ptszVal); + JFreeVariant(&dbv); + } else + { + m_txtDescription.SetTextA(""); + } + m_txtDescription.Enable(true); + } else + { + m_txtDescription.SetTextA(""); + m_txtDescription.Enable(false); + } +} + +BOOL CJabberDlgPepSimple::OnWmMeasureItem(UINT, WPARAM, LPARAM lParam) +{ + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; + if (lpmis->CtlID != IDC_CB_MODES) + return FALSE; + + TEXTMETRIC tm = {0}; + HDC hdc = GetDC(m_cbModes.GetHwnd()); + GetTextMetrics(hdc, &tm); + ReleaseDC(m_cbModes.GetHwnd(), hdc); + + lpmis->itemHeight = max(tm.tmHeight, 18); + if (lpmis->itemHeight < 18) lpmis->itemHeight = 18; + + return TRUE; +} + +BOOL CJabberDlgPepSimple::OnWmDrawItem(UINT, WPARAM, LPARAM lParam) +{ + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + if (lpdis->CtlID != IDC_CB_MODES) + return FALSE; + + if (lpdis->itemData == -1) return FALSE; + + CStatusMode *mode = &m_modes[lpdis->itemData]; + + TEXTMETRIC tm = {0}; + GetTextMetrics(lpdis->hDC, &tm); + + SetBkMode(lpdis->hDC, TRANSPARENT); + if (lpdis->itemState & ODS_SELECTED) + { + SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + } else + { + SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT)); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW)); + } + + if (!mode->m_subitem || (lpdis->itemState & ODS_COMBOBOXEDIT)) + { + TCHAR text[128]; + if (mode->m_subitem) + { + for (int i = lpdis->itemData; i >= 0; --i) + if (!m_modes[i].m_subitem) + { + mir_sntprintf(text, SIZEOF(text), _T("%s [%s]"), m_modes[i].m_title, mode->m_title); + break; + } + } else + { + lstrcpyn(text, mode->m_title, SIZEOF(text)); + } + + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+2, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, mode->m_hIcon, 16, 16, 0, NULL, DI_NORMAL); + TextOut(lpdis->hDC, lpdis->rcItem.left + 23, (lpdis->rcItem.top+lpdis->rcItem.bottom-tm.tmHeight)/2, text, lstrlen(text)); + } else + { + TCHAR text[128]; + mir_sntprintf(text, SIZEOF(text), _T("...%s"), mode->m_title); + DrawIconEx(lpdis->hDC, lpdis->rcItem.left+23, (lpdis->rcItem.top+lpdis->rcItem.bottom-16)/2, mode->m_hIcon, 16, 16, 0, NULL, DI_NORMAL); + TextOut(lpdis->hDC, lpdis->rcItem.left + 44, (lpdis->rcItem.top+lpdis->rcItem.bottom-tm.tmHeight)/2, text, lstrlen(text)); + } + + return TRUE; +} + +BOOL CJabberDlgPepSimple::OnWmGetMinMaxInfo(UINT, WPARAM, LPARAM lParam) +{ + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; + lpmmi->ptMinTrackSize.x = 200; + lpmmi->ptMinTrackSize.y = 200; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// CPepService base class +CPepService::CPepService(CJabberProto *proto, char *name, TCHAR *node): + m_proto(proto), + m_name(name), + m_node(node), + m_hMenuItem(NULL) +{ +} + +CPepService::~CPepService() +{ +} + +void CPepService::Publish() +{ + XmlNodeIq iq( _T("set"), m_proto->SerialNext()); + CreateData( + iq << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) + << XCHILD( _T("publish")) << XATTR( _T("node"), m_node ) + << XCHILD( _T("item")) << XATTR( _T("id"), _T("current"))); + m_proto->m_ThreadInfo->send( iq ); + + m_wasPublished = TRUE; +} + +void CPepService::Retract() +{ + TCHAR* tempName = mir_a2t( m_name ); + _tcslwr( tempName ); + + m_proto->m_ThreadInfo->send( + XmlNodeIq( _T("set"), m_proto->SerialNext()) + << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) + << XCHILD( _T("publish")) << XATTR( _T("node"), m_node ) + << XCHILD( _T("item")) + << XCHILDNS( tempName, m_node )); + + mir_free( tempName ); +} + +void CPepService::ResetPublish() +{ + m_wasPublished = FALSE; +} + +void CPepService::ForceRepublishOnLogin() +{ + if (!m_wasPublished) + Publish(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CPepGuiService base class + +CPepGuiService::CPepGuiService(CJabberProto *proto, char *name, TCHAR *node): + CPepService(proto, name, node), + m_bGuiOpen(false), + m_hIcolibItem(NULL), + m_szText(NULL), + m_hMenuService(NULL) +{ +} + +CPepGuiService::~CPepGuiService() +{ + if (m_hMenuService) + { + DestroyServiceFunction(m_hMenuService); + m_hMenuService = NULL; + } + + if (m_szText) mir_free(m_szText); +} + +void CPepGuiService::InitGui() +{ + char szService[128]; + mir_snprintf(szService, SIZEOF(szService), "%s/AdvStatusSet/%s", m_proto->m_szModuleName, m_name); + + int (__cdecl CPepGuiService::*serviceProc)(WPARAM, LPARAM); + serviceProc = &CPepGuiService::OnMenuItemClick; + m_hMenuService = CreateServiceFunctionObj(szService, (MIRANDASERVICEOBJ)*(void **)&serviceProc, this); + + RebuildMenu(); +} + +void CPepGuiService::RebuildMenu() +{ + HGENMENU hJabberRoot = MO_GetProtoRootMenu( m_proto->m_szModuleName ); + if ( hJabberRoot ) { + char szService[128]; + mir_snprintf(szService, SIZEOF(szService), "%s/AdvStatusSet/%s", m_proto->m_szModuleName, m_name); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.hParentMenu = hJabberRoot; + mi.pszService = szService; + mi.position = 200010; + mi.flags = CMIF_TCHAR | CMIF_ICONFROMICOLIB | CMIF_HIDDEN | CMIF_ROOTHANDLE; + + mi.icolibItem = m_hIcolibItem; + mi.ptszName = m_szText ? m_szText : _T("<advanced status slot>"); + m_hMenuItem = Menu_AddProtoMenuItem(&mi); +} } + +bool CPepGuiService::LaunchSetGui(BYTE bQuiet) +{ + if (m_bGuiOpen) return false; + + m_bGuiOpen = true; + ShowSetDialog(bQuiet); + m_bGuiOpen = false; + + return true; +} + +void CPepGuiService::UpdateMenuItem(HANDLE hIcolibIcon, TCHAR *text) +{ + m_hIcolibItem = hIcolibIcon; + if (m_szText) mir_free(m_szText); + m_szText = text ? mir_tstrdup(text) : NULL; + + if (!m_hMenuItem) return; + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIM_ICON|CMIM_NAME; + mi.icolibItem = m_hIcolibItem; + mi.ptszName = m_szText ? m_szText : _T("<advanced status slot>"); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)m_hMenuItem, (LPARAM)&mi); +} + +int CPepGuiService::OnMenuItemClick(WPARAM, LPARAM) +{ + LaunchSetGui(0); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// CPepMood + +struct +{ + TCHAR *szName; + char* szTag; +} static g_arrMoods[] = +{ + { LPGENT("None"), NULL }, + { LPGENT("Afraid"), "afraid" }, + { LPGENT("Amazed"), "amazed" }, + { LPGENT("Amorous"), "amorous" }, + { LPGENT("Angry"), "angry" }, + { LPGENT("Annoyed"), "annoyed" }, + { LPGENT("Anxious"), "anxious" }, + { LPGENT("Aroused"), "aroused" }, + { LPGENT("Ashamed"), "ashamed" }, + { LPGENT("Bored"), "bored" }, + { LPGENT("Brave"), "brave" }, + { LPGENT("Calm"), "calm" }, + { LPGENT("Cautious"), "cautious" }, + { LPGENT("Cold"), "cold" }, + { LPGENT("Confident"), "confident" }, + { LPGENT("Confused"), "confused" }, + { LPGENT("Contemplative"),"contemplative" }, + { LPGENT("Contented"), "contented" }, + { LPGENT("Cranky"), "cranky" }, + { LPGENT("Crazy"), "crazy" }, + { LPGENT("Creative"), "creative" }, + { LPGENT("Curious"), "curious" }, + { LPGENT("Dejected"), "dejected" }, + { LPGENT("Depressed"), "depressed" }, + { LPGENT("Disappointed"), "disappointed" }, + { LPGENT("Disgusted"), "disgusted" }, + { LPGENT("Dismayed"), "dismayed" }, + { LPGENT("Distracted"), "distracted" }, + { LPGENT("Embarrassed"), "embarrassed" }, + { LPGENT("Envious"), "envious" }, + { LPGENT("Excited"), "excited" }, + { LPGENT("Flirtatious"), "flirtatious" }, + { LPGENT("Frustrated"), "frustrated" }, + { LPGENT("Grateful"), "grateful" }, + { LPGENT("Grieving"), "grieving" }, + { LPGENT("Grumpy"), "grumpy" }, + { LPGENT("Guilty"), "guilty" }, + { LPGENT("Happy"), "happy" }, + { LPGENT("Hopeful"), "hopeful" }, + { LPGENT("Hot"), "hot" }, + { LPGENT("Humbled"), "humbled" }, + { LPGENT("Humiliated"), "humiliated" }, + { LPGENT("Hungry"), "hungry" }, + { LPGENT("Hurt"), "hurt" }, + { LPGENT("Impressed"), "impressed" }, + { LPGENT("In awe"), "in_awe" }, + { LPGENT("In love"), "in_love" }, + { LPGENT("Indignant"), "indignant" }, + { LPGENT("Interested"), "interested" }, + { LPGENT("Intoxicated"), "intoxicated" }, + { LPGENT("Invincible"), "invincible" }, + { LPGENT("Jealous"), "jealous" }, + { LPGENT("Lonely"), "lonely" }, + { LPGENT("Lost"), "lost" }, + { LPGENT("Lucky"), "lucky" }, + { LPGENT("Mean"), "mean" }, + { LPGENT("Moody"), "moody" }, + { LPGENT("Nervous"), "nervous" }, + { LPGENT("Neutral"), "neutral" }, + { LPGENT("Offended"), "offended" }, + { LPGENT("Outraged"), "outraged" }, + { LPGENT("Playful"), "playful" }, + { LPGENT("Proud"), "proud" }, + { LPGENT("Relaxed"), "relaxed" }, + { LPGENT("Relieved"), "relieved" }, + { LPGENT("Remorseful"), "remorseful" }, + { LPGENT("Restless"), "restless" }, + { LPGENT("Sad"), "sad" }, + { LPGENT("Sarcastic"), "sarcastic" }, + { LPGENT("Satisfied"), "satisfied" }, + { LPGENT("Serious"), "serious" }, + { LPGENT("Shocked"), "shocked" }, + { LPGENT("Shy"), "shy" }, + { LPGENT("Sick"), "sick" }, + { LPGENT("Sleepy"), "sleepy" }, + { LPGENT("Spontaneous"), "spontaneous" }, + { LPGENT("Stressed"), "stressed" }, + { LPGENT("Strong"), "strong" }, + { LPGENT("Surprised"), "surprised" }, + { LPGENT("Thankful"), "thankful" }, + { LPGENT("Thirsty"), "thirsty" }, + { LPGENT("Tired"), "tired" }, + { LPGENT("Undefined"), "undefined" }, + { LPGENT("Weak"), "weak" }, + { LPGENT("Worried"), "worried" }, +}; + +CPepMood::CPepMood(CJabberProto *proto): + CPepGuiService(proto, "Mood", _T(JABBER_FEAT_USER_MOOD)), + m_icons(proto), + m_text(NULL), + m_mode(-1) +{ + UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set mood...")); +} + +CPepMood::~CPepMood() +{ + if (m_text) mir_free(m_text); +} + +void CPepMood::InitGui() +{ + CSuper::InitGui(); + + char szFile[MAX_PATH]; + GetModuleFileNameA(hInst, szFile, MAX_PATH); + if (char *p = strrchr(szFile, '\\')) + strcpy( p+1, "..\\Icons\\xstatus_jabber.dll" ); + + TCHAR szSection[100]; + + mir_sntprintf(szSection, SIZEOF(szSection), _T("Status Icons/%s/Moods"), m_proto->m_tszUserName); + for (int i = 1; i < SIZEOF(g_arrMoods); i++) + m_icons.RegisterIcon( g_arrMoods[i].szTag, szFile, -(200+i), szSection, TranslateTS(g_arrMoods[i].szName)); +} + +void CPepMood::ProcessItems(const TCHAR *from, HXML itemsNode) +{ + HANDLE hContact = NULL, hSelfContact = NULL; + if ( !m_proto->IsMyOwnJID( from )) + { + hContact = m_proto->HContactFromJID(from); + if (!hContact) return; + } + else + hSelfContact = m_proto->HContactFromJID(from); + + if ( xmlGetChild( itemsNode, _T("retract"))) + { + if (hSelfContact) + SetMood(hSelfContact, NULL, NULL); + SetMood(hContact, NULL, NULL); + return; + } + + HXML n, moodNode = XPath( itemsNode, _T("item/mood[@xmlns='") _T(JABBER_FEAT_USER_MOOD) _T("']")); + if ( !moodNode ) return; + + LPCTSTR moodType = NULL, moodText = NULL; + for ( int i = 0; n = xmlGetChild( moodNode, i ); i++ ) { + if ( !_tcscmp( xmlGetName( n ), _T("text"))) + moodText = xmlGetText( n ); + else + moodType = xmlGetName( n ); + } + + TCHAR *fixedText = JabberStrFixLines( moodText ); + if (hSelfContact) + SetMood(hSelfContact, moodType, fixedText); + SetMood(hContact, moodType, fixedText); + mir_free( fixedText ); + + if (!hContact && m_mode >= 0) + ForceRepublishOnLogin(); +} + +void CPepMood::CreateData( HXML n ) +{ + HXML moodNode = n << XCHILDNS( _T("mood"), _T(JABBER_FEAT_USER_MOOD)); + moodNode << XCHILD( _A2T(g_arrMoods[m_mode].szTag)); + if ( m_text ) + moodNode << XCHILD( _T("text"), m_text ); +} + +void CPepMood::ResetExtraIcon(HANDLE hContact) +{ + char *szMood = m_proto->ReadAdvStatusA(hContact, ADVSTATUS_MOOD, "id"); + SetExtraIcon(hContact, szMood); + mir_free(szMood); +} + +void CPepMood::SetExtraIcon(HANDLE hContact, char *szMood) +{ + if (hExtraMood != NULL) + { + ExtraIcon_SetIcon(hExtraMood, hContact, szMood == NULL ? NULL : m_icons.GetIcolibName(szMood)); + } + else + { + IconExtraColumn iec; + iec.cbSize = sizeof(iec); + iec.hImage = m_icons.GetClistHandle(szMood); + iec.ColumnType = EXTRA_ICON_ADV1; + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); + } +} + +void CPepMood::SetMood(HANDLE hContact, const TCHAR *szMood, const TCHAR *szText) +{ + int mood = -1; + if (szMood) + { + char* p = mir_t2a( szMood ); + + for (int i = 1; i < SIZEOF(g_arrMoods); ++i) + if (!lstrcmpA(g_arrMoods[i].szTag, p )) + { + mood = i; + break; + } + + mir_free( p ); + + if (mood < 0) + return; + } + + if (!hContact) + { + m_mode = mood; + replaceStrT(m_text, szText); + + HANDLE hIcon = (mood >= 0) ? m_icons.GetIcolibHandle(g_arrMoods[mood].szTag) : LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT); + TCHAR title[128]; + + if (mood >= 0) + { + mir_sntprintf(title, SIZEOF(title), TranslateT("Mood: %s"), TranslateTS(g_arrMoods[mood].szName)); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", m_icons.GetIcolibHandle(g_arrMoods[mood].szTag), TranslateTS(g_arrMoods[mood].szName)); + } else + { + lstrcpy(title, LPGENT("Set mood...")); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); + } + + UpdateMenuItem(hIcon, title); + } else + { + SetExtraIcon(hContact, mood < 0 ? NULL : g_arrMoods[mood].szTag); + } + + if (szMood) + { + m_proto->JSetByte(hContact, DBSETTING_XSTATUSID, mood); + m_proto->JSetStringT(hContact, DBSETTING_XSTATUSNAME, TranslateTS(g_arrMoods[mood].szName)); + if (szText) + m_proto->JSetStringT(hContact, DBSETTING_XSTATUSMSG, szText); + else + m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSMSG); + + m_proto->WriteAdvStatus(hContact, ADVSTATUS_MOOD, szMood, m_icons.GetIcolibName(g_arrMoods[mood].szTag), TranslateTS(g_arrMoods[mood].szName), szText); + } else + { + m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSID); + m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSNAME); + m_proto->JDeleteSetting(hContact, DBSETTING_XSTATUSMSG); + + m_proto->ResetAdvStatus(hContact, ADVSTATUS_MOOD); + } + + NotifyEventHooks(m_proto->m_hEventXStatusChanged, (WPARAM)hContact, 0); +} + +void CPepMood::ShowSetDialog(BYTE bQuiet) +{ + if ( !bQuiet ) { + CJabberDlgPepSimple dlg(m_proto, TranslateT("Set Mood")); + for (int i = 1; i < SIZEOF(g_arrMoods); ++i) + dlg.AddStatusMode(i, g_arrMoods[i].szTag, m_icons.GetIcon(g_arrMoods[i].szTag), TranslateTS(g_arrMoods[i].szName)); + dlg.SetActiveStatus(m_mode, m_text); + dlg.DoModal(); + if (!dlg.OkClicked()) + return; + + m_mode = dlg.GetStatusMode(); + replaceStrT(m_text, dlg.GetStatusText()); + } + + if (m_mode >= 0) + { + Publish(); + + UpdateMenuItem(m_icons.GetIcolibHandle(g_arrMoods[m_mode].szTag), g_arrMoods[m_mode].szName); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", m_icons.GetIcolibHandle(g_arrMoods[m_mode].szTag), TranslateTS(g_arrMoods[m_mode].szName)); + } else + { + Retract(); + UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set mood...")); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/mood", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set mood...")); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// CPepActivity +#define ACTIVITY_ICON(section, item) -(300 + (section) * 20 + (item)) + +struct +{ + char *szFirst; + char *szSecond; + TCHAR *szTitle; + int iconid; +} g_arrActivities[] = +{ + { "doing_chores", NULL, _T("Doing chores"), ACTIVITY_ICON( 0, 0) }, + { NULL, "buying_groceries", _T("buying groceries"), ACTIVITY_ICON( 0, 1) }, + { NULL, "cleaning", _T("cleaning"), ACTIVITY_ICON( 0, 2) }, + { NULL, "cooking", _T("cooking"), ACTIVITY_ICON( 0, 3) }, + { NULL, "doing_maintenance", _T("doing maintenance"), ACTIVITY_ICON( 0, 4) }, + { NULL, "doing_the_dishes", _T("doing the dishes"), ACTIVITY_ICON( 0, 5) }, + { NULL, "doing_the_laundry", _T("doing the laundry"), ACTIVITY_ICON( 0, 6) }, + { NULL, "gardening", _T("gardening"), ACTIVITY_ICON( 0, 7) }, + { NULL, "running_an_errand", _T("running an errand"), ACTIVITY_ICON( 0, 8) }, + { NULL, "walking_the_dog", _T("walking the dog"), ACTIVITY_ICON( 0, 9) }, + { "drinking", NULL, _T("Drinking"), ACTIVITY_ICON( 1, 0) }, + { NULL, "having_a_beer", _T("having a beer"), ACTIVITY_ICON( 1, 1) }, + { NULL, "having_coffee", _T("having coffee"), ACTIVITY_ICON( 1, 2) }, + { NULL, "having_tea", _T("having tea"), ACTIVITY_ICON( 1, 3) }, + { "eating", NULL, _T("Eating"), ACTIVITY_ICON( 2, 0) }, + { NULL, "having_a_snack", _T("having a snack"), ACTIVITY_ICON( 2, 1) }, + { NULL, "having_breakfast", _T("having breakfast"), ACTIVITY_ICON( 2, 2) }, + { NULL, "having_dinner", _T("having dinner"), ACTIVITY_ICON( 2, 3) }, + { NULL, "having_lunch", _T("having lunch"), ACTIVITY_ICON( 2, 4) }, + { "exercising", NULL, _T("Exercising"), ACTIVITY_ICON( 3, 0) }, + { NULL, "cycling", _T("cycling"), ACTIVITY_ICON( 3, 1) }, + { NULL, "dancing", _T("dancing"), ACTIVITY_ICON( 3, 2) }, + { NULL, "hiking", _T("hiking"), ACTIVITY_ICON( 3, 3) }, + { NULL, "jogging", _T("jogging"), ACTIVITY_ICON( 3, 4) }, + { NULL, "playing_sports", _T("playing sports"), ACTIVITY_ICON( 3, 5) }, + { NULL, "running", _T("running"), ACTIVITY_ICON( 3, 6) }, + { NULL, "skiing", _T("skiing"), ACTIVITY_ICON( 3, 7) }, + { NULL, "swimming", _T("swimming"), ACTIVITY_ICON( 3, 8) }, + { NULL, "working_out", _T("working out"), ACTIVITY_ICON( 3, 9) }, + { "grooming", NULL, _T("Grooming"), ACTIVITY_ICON( 4, 0) }, + { NULL, "at_the_spa", _T("at the spa"), ACTIVITY_ICON( 4, 1) }, + { NULL, "brushing_teeth", _T("brushing teeth"), ACTIVITY_ICON( 4, 2) }, + { NULL, "getting_a_haircut", _T("getting a haircut"), ACTIVITY_ICON( 4, 3) }, + { NULL, "shaving", _T("shaving"), ACTIVITY_ICON( 4, 4) }, + { NULL, "taking_a_bath", _T("taking a bath"), ACTIVITY_ICON( 4, 5) }, + { NULL, "taking_a_shower", _T("taking a shower"), ACTIVITY_ICON( 4, 6) }, + { "having_appointment", NULL, _T("Having appointment"), ACTIVITY_ICON( 5, 0) }, + { "inactive", NULL, _T("Inactive"), ACTIVITY_ICON( 6, 0) }, + { NULL, "day_off", _T("day off"), ACTIVITY_ICON( 6, 1) }, + { NULL, "hanging_out", _T("hanging out"), ACTIVITY_ICON( 6, 2) }, + { NULL, "hiding", _T("hiding"), ACTIVITY_ICON( 6, 3) }, + { NULL, "on_vacation", _T("on vacation"), ACTIVITY_ICON( 6, 4) }, + { NULL, "praying", _T("praying"), ACTIVITY_ICON( 6, 5) }, + { NULL, "scheduled_holiday", _T("scheduled holiday"), ACTIVITY_ICON( 6, 6) }, + { NULL, "sleeping", _T("sleeping"), ACTIVITY_ICON( 6, 7) }, + { NULL, "thinking", _T("thinking"), ACTIVITY_ICON( 6, 8) }, + { "relaxing", NULL, _T("Relaxing"), ACTIVITY_ICON( 7, 0) }, + { NULL, "fishing", _T("fishing"), ACTIVITY_ICON( 7, 1) }, + { NULL, "gaming", _T("gaming"), ACTIVITY_ICON( 7, 2) }, + { NULL, "going_out", _T("going out"), ACTIVITY_ICON( 7, 3) }, + { NULL, "partying", _T("partying"), ACTIVITY_ICON( 7, 4) }, + { NULL, "reading", _T("reading"), ACTIVITY_ICON( 7, 5) }, + { NULL, "rehearsing", _T("rehearsing"), ACTIVITY_ICON( 7, 6) }, + { NULL, "shopping", _T("shopping"), ACTIVITY_ICON( 7, 7) }, + { NULL, "smoking", _T("smoking"), ACTIVITY_ICON( 7, 8) }, + { NULL, "socializing", _T("socializing"), ACTIVITY_ICON( 7, 9) }, + { NULL, "sunbathing", _T("sunbathing"), ACTIVITY_ICON( 7, 10) }, + { NULL, "watching_tv", _T("watching TV"), ACTIVITY_ICON( 7, 11) }, + { NULL, "watching_a_movie", _T("watching a movie"), ACTIVITY_ICON( 7, 12) }, + { "talking", NULL, _T("Talking"), ACTIVITY_ICON( 8, 0) }, + { NULL, "in_real_life", _T("in real life"), ACTIVITY_ICON( 8, 1) }, + { NULL, "on_the_phone", _T("on the phone"), ACTIVITY_ICON( 8, 2) }, + { NULL, "on_video_phone", _T("on video phone"), ACTIVITY_ICON( 8, 3) }, + { "traveling", NULL, _T("Traveling"), ACTIVITY_ICON( 9, 0) }, + { NULL, "commuting", _T("commuting"), ACTIVITY_ICON( 9, 1) }, + { NULL, "cycling", _T("cycling"), ACTIVITY_ICON( 9, 2) }, + { NULL, "driving", _T("driving"), ACTIVITY_ICON( 9, 3) }, + { NULL, "in_a_car", _T("in a car"), ACTIVITY_ICON( 9, 4) }, + { NULL, "on_a_bus", _T("on a bus"), ACTIVITY_ICON( 9, 5) }, + { NULL, "on_a_plane", _T("on a plane"), ACTIVITY_ICON( 9, 6) }, + { NULL, "on_a_train", _T("on a train"), ACTIVITY_ICON( 9, 7) }, + { NULL, "on_a_trip", _T("on a trip"), ACTIVITY_ICON( 9, 8) }, + { NULL, "walking", _T("walking"), ACTIVITY_ICON( 9, 9) }, + { "working", NULL, _T("Working"), ACTIVITY_ICON(10, 0) }, + { NULL, "coding", _T("coding"), ACTIVITY_ICON(10, 1) }, + { NULL, "in_a_meeting", _T("in a meeting"), ACTIVITY_ICON(10, 2) }, + { NULL, "studying", _T("studying"), ACTIVITY_ICON(10, 3) }, + { NULL, "writing", _T("writing"), ACTIVITY_ICON(10, 4) }, + { NULL, NULL, NULL } // the end, don't delete this +}; + +inline char *ActivityGetId(int id) +{ + return g_arrActivities[id].szSecond ? g_arrActivities[id].szSecond : g_arrActivities[id].szFirst; +} + +// -1 if not found, otherwise activity number +static int ActivityCheck( LPCTSTR szFirstNode, LPCTSTR szSecondNode ) +{ + if (!szFirstNode) return 0; + + char *s1 = mir_t2a( szFirstNode ), *s2 = mir_t2a( szSecondNode ); + + int i = 0, nFirst = -1, nSecond = -1; + while ( g_arrActivities[i].szFirst || g_arrActivities[i].szSecond ) { + // check first node + if ( g_arrActivities[i].szFirst && !strcmp( s1, g_arrActivities[i].szFirst )) { + // first part found + nFirst = i; + if ( !s2 ) { + nSecond = i; + break; + } + i++; // move to next + while ( g_arrActivities[i].szSecond ) { + if ( !strcmp( g_arrActivities[i].szSecond, s2 )) { + nSecond = i; + break; + } + i++; + } + break; + } + i++; + } + + mir_free( s1 ); + mir_free( s2 ); + + if ( nSecond != -1 ) + return nSecond; + + return nFirst; +} + +char *returnActivity (int id){ + if (g_arrActivities[id].szFirst) + return g_arrActivities[id].szFirst; + if (g_arrActivities[id].szSecond) + return g_arrActivities[id].szSecond; + return NULL;} + +char *ActivityGetFirst(int id) +{ + if (id >= SIZEOF(g_arrActivities) - 1) + return NULL; + + while (id >= 0) + { + if (g_arrActivities[id].szFirst) + return g_arrActivities[id].szFirst; + --id; + } + + return NULL; +} + +char *ActivityGetFirst(char *szId) +{ + if (!szId) return NULL; + + int id = SIZEOF(g_arrActivities) - 1; + bool found_second = false; + + while (id >= 0) + { + if (g_arrActivities[id].szFirst && (found_second || !lstrcmpA(g_arrActivities[id].szFirst, szId))) + return g_arrActivities[id].szFirst; + if (g_arrActivities[id].szSecond && !found_second && !lstrcmpA(g_arrActivities[id].szSecond, szId)) + found_second = true; + --id; + } + + return NULL; +} + +char *ActivityGetSecond(int id) +{ + return (id >= 0) ? g_arrActivities[id].szSecond : NULL; +} + +TCHAR *ActivityGetFirstTitle(int id) +{ + if (id >= SIZEOF(g_arrActivities) - 1) + return NULL; + + while (id >= 0) + { + if (g_arrActivities[id].szFirst) + return g_arrActivities[id].szTitle; + --id; + } + + return NULL; +} + +TCHAR *ActivityGetSecondTitle(int id) +{ + return ((id >= 0) && g_arrActivities[id].szSecond) ? g_arrActivities[id].szTitle : NULL; +} + +void ActivityBuildTitle(int id, TCHAR *buf, int size) +{ + TCHAR *szFirst = ActivityGetFirstTitle(id); + TCHAR *szSecond = ActivityGetSecondTitle(id); + + if (szFirst) + { + if (szSecond) + mir_sntprintf(buf, size, _T("%s [%s]"), TranslateTS(szFirst), TranslateTS(szSecond)); + else + lstrcpyn(buf, TranslateTS(szFirst), size); + } else + *buf = 0; +} + +CPepActivity::CPepActivity(CJabberProto *proto): + CPepGuiService(proto, "Activity", _T(JABBER_FEAT_USER_ACTIVITY)), + m_icons(proto), + m_text(NULL), + m_mode(-1) +{ + UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set activity...")); +} + +CPepActivity::~CPepActivity() +{ + if (m_text) mir_free(m_text); +} + +void CPepActivity::InitGui() +{ + CSuper::InitGui(); + + char szFile[MAX_PATH]; + GetModuleFileNameA(hInst, szFile, MAX_PATH); + if (char *p = strrchr(szFile, '\\')) + strcpy( p+1, "..\\Icons\\xstatus_jabber.dll" ); + + TCHAR szSection[100]; + + mir_sntprintf(szSection, SIZEOF(szSection), _T("Status Icons/%s/Activities"), m_proto->m_tszUserName); + for (int i = 0; i < SIZEOF(g_arrActivities); i++) { + if (g_arrActivities[i].szFirst) + m_icons.RegisterIcon(g_arrActivities[i].szFirst, szFile, g_arrActivities[i].iconid, szSection, TranslateTS(g_arrActivities[i].szTitle)); + if (g_arrActivities[i].szSecond) + m_icons.RegisterIcon(g_arrActivities[i].szSecond, szFile, g_arrActivities[i].iconid, szSection, TranslateTS(g_arrActivities[i].szTitle));} + +} + +void CPepActivity::ProcessItems(const TCHAR *from, HXML itemsNode) +{ + HANDLE hContact = NULL, hSelfContact = NULL; + if ( !m_proto->IsMyOwnJID( from )) + { + hContact = m_proto->HContactFromJID(from); + if (!hContact) return; + } + else + hSelfContact = m_proto->HContactFromJID(from); + + if ( xmlGetChild( itemsNode, "retract")) + { + if (hSelfContact) + SetActivity(hSelfContact, NULL, NULL, NULL); + SetActivity(hContact, NULL, NULL, NULL); + return; + } + + HXML actNode = XPath( itemsNode, _T("item/activity[@xmlns='") _T(JABBER_FEAT_USER_ACTIVITY) _T("']")); + if ( !actNode ) return; + + LPCTSTR szText = XPathT( actNode, "text" ); + LPCTSTR szFirstNode = NULL, szSecondNode = NULL; + + HXML n; + for ( int i = 0; n = xmlGetChild( actNode, i ); i++ ) { + if ( lstrcmp( xmlGetName( n ), _T("text"))) + { + szFirstNode = xmlGetName( n ); + HXML secondNode = xmlGetChild( n, 0 ); + if (szFirstNode && secondNode && xmlGetName( secondNode )) + szSecondNode = xmlGetName( secondNode ); + break; + } + } + + TCHAR *fixedText = JabberStrFixLines( szText ); + if (hSelfContact) + SetActivity(hSelfContact, szFirstNode, szSecondNode, fixedText); + SetActivity(hContact, szFirstNode, szSecondNode, fixedText); + mir_free( fixedText ); + + if (!hContact && m_mode >= 0) + ForceRepublishOnLogin(); +} + +void CPepActivity::CreateData( HXML n ) +{ + char *szFirstNode = ActivityGetFirst(m_mode); + char *szSecondNode = ActivityGetSecond(m_mode); + + HXML activityNode = n << XCHILDNS( _T("activity"), _T(JABBER_FEAT_USER_ACTIVITY)); + HXML firstNode = activityNode << XCHILD( _A2T( szFirstNode )); + + if (firstNode && szSecondNode) + firstNode << XCHILD( _A2T(szSecondNode)); + + if (m_text) + activityNode << XCHILD( _T("text"), m_text); +} + +void CPepActivity::ResetExtraIcon(HANDLE hContact) +{ + char *szActivity = m_proto->ReadAdvStatusA(hContact, ADVSTATUS_ACTIVITY, "id"); + SetExtraIcon(hContact, szActivity); + mir_free(szActivity); +} + +void CPepActivity::SetExtraIcon(HANDLE hContact, char *szActivity) +{ + if (hExtraActivity != NULL) + { + ExtraIcon_SetIcon(hExtraActivity, hContact, + szActivity == NULL ? NULL : m_icons.GetIcolibName(szActivity)); + } + else + { + IconExtraColumn iec; + iec.cbSize = sizeof(iec); + iec.hImage = m_icons.GetClistHandle(szActivity); + iec.ColumnType = EXTRA_ICON_ADV2; + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); + } +} + +void CPepActivity::SetActivity(HANDLE hContact, LPCTSTR szFirst, LPCTSTR szSecond, LPCTSTR szText) +{ + int activity = -1; + if (szFirst || szSecond) + { + activity = ActivityCheck(szFirst, szSecond); + + if (activity < 0) + return; + } + + TCHAR activityTitle[128]; + ActivityBuildTitle(activity, activityTitle, SIZEOF(activityTitle)); + + if (!hContact) + { + m_mode = activity; + replaceStrT(m_text, szText); + + HANDLE hIcon = (activity >= 0) ? m_icons.GetIcolibHandle(returnActivity(activity)) : LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT); + TCHAR title[128]; + + if (activity >= 0) + { + mir_sntprintf(title, SIZEOF(title), TranslateT("Activity: %s"), activityTitle); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", m_icons.GetIcolibHandle(returnActivity(activity)), activityTitle); + } else + { + lstrcpy(title, LPGENT("Set activity...")); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); + } + + UpdateMenuItem(hIcon, title); + } else + { + SetExtraIcon(hContact, activity < 0 ? NULL : returnActivity(activity)); + } + + + if (activity >= 0) { + TCHAR* p = mir_a2t( ActivityGetId(activity)); + m_proto->WriteAdvStatus(hContact, ADVSTATUS_ACTIVITY, p, m_icons.GetIcolibName(returnActivity(activity)), activityTitle, szText); + mir_free( p ); + } + else + m_proto->ResetAdvStatus(hContact, ADVSTATUS_ACTIVITY); +} + +void CPepActivity::ShowSetDialog(BYTE bQuiet) +{ + CJabberDlgPepSimple dlg(m_proto, TranslateT("Set Activity")); + for (int i = 0; i < SIZEOF(g_arrActivities); ++i) + if (g_arrActivities[i].szFirst || g_arrActivities[i].szSecond) + dlg.AddStatusMode(i, ActivityGetId(i), m_icons.GetIcon(returnActivity(i)), TranslateTS(g_arrActivities[i].szTitle), (g_arrActivities[i].szSecond != NULL)); + dlg.SetActiveStatus(m_mode, m_text); + dlg.DoModal(); + + if (!dlg.OkClicked()) return; + + m_mode = dlg.GetStatusMode(); + if (m_mode >= 0) + { + replaceStrT(m_text, dlg.GetStatusText()); + Publish(); + + UpdateMenuItem(m_icons.GetIcolibHandle(returnActivity(m_mode)), g_arrActivities[m_mode].szTitle); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", m_icons.GetIcolibHandle(returnActivity(m_mode)), TranslateTS(g_arrActivities[m_mode].szTitle)); + } else + { + Retract(); + UpdateMenuItem(LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), LPGENT("Set activity...")); + m_proto->m_pInfoFrame->UpdateInfoItem("$/PEP/activity", LoadSkinnedIconHandle(SKINICON_OTHER_SMALLDOT), TranslateT("Set activity...")); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// icq api emulation + +HICON CJabberProto::GetXStatusIcon(int bStatus, UINT flags) +{ + CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); + HICON icon = pepMood->m_icons.GetIcon(g_arrMoods[bStatus].szTag, (flags & LR_BIGICON) != 0); + return ( flags & LR_SHARED ) ? icon : CopyIcon( icon ); +} + +int CJabberProto::CListMW_ExtraIconsApply( WPARAM wParam, LPARAM ) +{ + if (m_bJabberOnline && m_bPepSupported && ServiceExists(MS_CLIST_EXTRA_SET_ICON)) + { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 ); + if ( szProto==NULL || strcmp( szProto, m_szModuleName )) + return 0; // only apply icons to our contacts, do not mess others + + m_pepServices.ResetExtraIcon((HANDLE)wParam); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetXStatus - gets the extended status info (mood) + +INT_PTR __cdecl CJabberProto::OnGetXStatus( WPARAM wParam, LPARAM lParam ) +{ + if ( !m_bJabberOnline || !m_bPepSupported ) + return 0; + + if ( wParam ) *(( char** )wParam ) = DBSETTING_XSTATUSNAME; + if ( lParam ) *(( char** )lParam ) = DBSETTING_XSTATUSMSG; + return ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; +} + +// not needed anymore and therefore commented out + +/*INT_PTR __cdecl CJabberProto::OnGetXStatusEx( WPARAM wParam, LPARAM lParam ) +{ + JABBER_CUSTOM_STATUS *pData = (JABBER_CUSTOM_STATUS*)lParam; + HANDLE hContact = (HANDLE)wParam; + + if ( !m_bJabberOnline || !m_bPepSupported ) + return 1; + + if (pData->cbSize < sizeof(JABBER_CUSTOM_STATUS)) return 1; // Failure + + + if ( wParam ) *(( char** )wParam ) = DBSETTING_XSTATUSNAME; + if ( lParam ) *(( char** )lParam ) = DBSETTING_XSTATUSMSG; + return ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; +}*/ +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetXStatusIcon - Retrieves specified custom status icon +//wParam = (int)N // custom status id, 0 = my current custom status +//lParam = flags // use LR_SHARED for shared HICON +//return = HICON // custom status icon (use DestroyIcon to release resources if not LR_SHARED) + +INT_PTR __cdecl CJabberProto::OnGetXStatusIcon( WPARAM wParam, LPARAM lParam ) +{ + if ( !m_bJabberOnline ) + return 0; + + if ( !wParam ) + wParam = ((CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)))->m_mode; + + if ( wParam < 1 || wParam >= SIZEOF(g_arrMoods)) + return 0; + + int flags = 0; + if ( lParam & LR_SHARED ) flags |= LR_SHARED; + if ( lParam & LR_BIGICON ) flags |= LR_BIGICON; + + return (INT_PTR)GetXStatusIcon( wParam, flags ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// SendPepMood - sends mood + +BOOL CJabberProto::SendPepTune( TCHAR* szArtist, TCHAR* szLength, TCHAR* szSource, TCHAR* szTitle, TCHAR* szTrack, TCHAR* szUri ) +{ + if ( !m_bJabberOnline || !m_bPepSupported ) + return FALSE; + + XmlNodeIq iq( _T("set"), SerialNext()); + HXML tuneNode = iq << XCHILDNS( _T("pubsub"), _T(JABBER_FEAT_PUBSUB)) + << XCHILD( _T("publish")) << XATTR( _T("node"), _T(JABBER_FEAT_USER_TUNE)) + << XCHILD( _T("item")) << XCHILDNS( _T("tune"), _T(JABBER_FEAT_USER_TUNE)); + + if ( szArtist || szLength || szSource || szTitle || szUri ) { + if ( szArtist ) tuneNode << XCHILD( _T("artist"), szArtist ); + if ( szLength ) tuneNode << XCHILD( _T("length"), szLength ); + if ( szSource ) tuneNode << XCHILD( _T("source"), szSource ); + if ( szTitle ) tuneNode << XCHILD( _T("title"), szTitle ); + if ( szTrack ) tuneNode << XCHILD( _T("track"), szTrack ); + if ( szUri ) tuneNode << XCHILD( _T("uri"), szUri ); + } + m_ThreadInfo->send( iq ); + + return TRUE; +} + +void CJabberProto::SetContactTune( HANDLE hContact, LPCTSTR szArtist, LPCTSTR szLength, LPCTSTR szSource, LPCTSTR szTitle, LPCTSTR szTrack ) +{ + if ( !szArtist && !szTitle ) { + JDeleteSetting( hContact, "ListeningTo" ); + ResetAdvStatus( hContact, ADVSTATUS_TUNE ); + return; + } + + TCHAR *szListeningTo; + if ( ServiceExists( MS_LISTENINGTO_GETPARSEDTEXT )) { + LISTENINGTOINFO li; + ZeroMemory( &li, sizeof( li )); + li.cbSize = sizeof( li ); + li.dwFlags = LTI_TCHAR; + li.ptszArtist = ( TCHAR* )szArtist; + li.ptszLength = ( TCHAR* )szLength; + li.ptszAlbum = ( TCHAR* )szSource; + li.ptszTitle = ( TCHAR* )szTitle; + li.ptszTrack = ( TCHAR* )szTrack; + szListeningTo = (TCHAR *)CallService( MS_LISTENINGTO_GETPARSEDTEXT, (WPARAM)_T("%title% - %artist%"), (LPARAM)&li ); + } + else { + szListeningTo = (TCHAR *) mir_alloc( 2048 * sizeof( TCHAR )); + mir_sntprintf( szListeningTo, 2047, _T("%s - %s"), szTitle ? szTitle : _T(""), szArtist ? szArtist : _T("")); + } + + JSetStringT( hContact, "ListeningTo", szListeningTo ); + + char tuneIcon[128]; + mir_snprintf(tuneIcon, SIZEOF(tuneIcon), "%s_%s", m_szModuleName, "main"); + WriteAdvStatus( hContact, ADVSTATUS_TUNE, _T("listening_to"), tuneIcon, TranslateT("Listening To"), szListeningTo ); + + mir_free( szListeningTo ); +} + +TCHAR* a2tf( const TCHAR* str, BOOL unicode ) +{ + if ( str == NULL ) + return NULL; + + return ( unicode ) ? mir_tstrdup( str ) : mir_a2t(( char* )str ); +} + +void overrideStr( TCHAR*& dest, const TCHAR* src, BOOL unicode, const TCHAR* def = NULL ) +{ + if ( dest != NULL ) + { + mir_free( dest ); + dest = NULL; + } + + if ( src != NULL ) + dest = a2tf( src, unicode ); + else if ( def != NULL ) + dest = mir_tstrdup( def ); +} + +INT_PTR __cdecl CJabberProto::OnSetListeningTo( WPARAM, LPARAM lParam ) +{ + LISTENINGTOINFO *cm = (LISTENINGTOINFO *)lParam; + if ( !cm || cm->cbSize != sizeof(LISTENINGTOINFO)) { + SendPepTune( NULL, NULL, NULL, NULL, NULL, NULL ); + JDeleteSetting( NULL, "ListeningTo" ); + } + else { + TCHAR *szArtist = NULL, *szLength = NULL, *szSource = NULL; + TCHAR *szTitle = NULL, *szTrack = NULL; + + BOOL unicode = cm->dwFlags & LTI_UNICODE; + + overrideStr( szArtist, cm->ptszArtist, unicode ); + overrideStr( szSource, cm->ptszAlbum, unicode ); + overrideStr( szTitle, cm->ptszTitle, unicode ); + overrideStr( szTrack, cm->ptszTrack, unicode ); + overrideStr( szLength, cm->ptszLength, unicode ); + + TCHAR szLengthInSec[ 32 ]; + szLengthInSec[ 0 ] = _T('\0'); + if ( szLength ) { + unsigned int multiplier = 1, result = 0; + for ( TCHAR *p = szLength; *p; p++ ) { + if ( *p == _T(':')) multiplier *= 60; + } + if ( multiplier <= 3600 ) { + TCHAR *szTmp = szLength; + while ( szTmp[0] ) { + result += ( _ttoi( szTmp ) * multiplier ); + multiplier /= 60; + szTmp = _tcschr( szTmp, _T(':')); + if ( !szTmp ) + break; + szTmp++; + } + } + mir_sntprintf( szLengthInSec, SIZEOF( szLengthInSec ), _T("%d"), result ); + } + + SendPepTune( szArtist, szLength ? szLengthInSec : NULL, szSource, szTitle, szTrack, NULL ); + SetContactTune( NULL, szArtist, szLength, szSource, szTitle, szTrack ); + + mir_free( szArtist ); + mir_free( szLength ); + mir_free( szSource ); + mir_free( szTitle ); + mir_free( szTrack ); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// process InfoFrame clicks + +void CJabberProto::InfoFrame_OnUserMood(CJabberInfoFrame_Event*) +{ + m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD))->LaunchSetGui(); +} + +void CJabberProto::InfoFrame_OnUserActivity(CJabberInfoFrame_Event*) +{ + m_pepServices.Find(_T(JABBER_FEAT_USER_ACTIVITY))->LaunchSetGui(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// builds xstatus menu + +void CJabberProto::XStatusInit() +{ + if (hExtraMood == NULL) + JHookEvent( ME_CLIST_EXTRA_IMAGE_APPLY, &CJabberProto::CListMW_ExtraIconsApply ); + + RegisterAdvStatusSlot( ADVSTATUS_MOOD ); + RegisterAdvStatusSlot( ADVSTATUS_TUNE ); + RegisterAdvStatusSlot( ADVSTATUS_ACTIVITY ); +} + +void CJabberProto::XStatusUninit() +{ + if ( m_hHookExtraIconsRebuild ) + UnhookEvent( m_hHookExtraIconsRebuild ); + + if ( m_hHookExtraIconsApply ) + UnhookEvent( m_hHookExtraIconsApply ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberSetXStatus - sets the extended status info (mood) + +INT_PTR __cdecl CJabberProto::OnSetXStatus( WPARAM wParam, LPARAM ) +{ + if ( !m_bPepSupported || !m_bJabberOnline ) + return 0; + + CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); + if ( !wParam ) { + pepMood->m_mode = -1; + pepMood->Retract(); + return 0; + } + + if ( wParam > 0 && wParam < SIZEOF(g_arrMoods)) { + pepMood->m_mode = wParam; + pepMood->LaunchSetGui( 0 ); + return wParam; + } + + return 0; +} + +INT_PTR __cdecl CJabberProto::OnSetXStatusEx( WPARAM wParam, LPARAM lParam) +{ + JABBER_CUSTOM_STATUS *pData = (JABBER_CUSTOM_STATUS*)lParam; + + if ( !m_bPepSupported || !m_bJabberOnline ) + return 1; + + if (pData->cbSize < sizeof(JABBER_CUSTOM_STATUS)) return 1; // Failure + + CPepMood *pepMood = (CPepMood *)m_pepServices.Find(_T(JABBER_FEAT_USER_MOOD)); + + int status = *pData->status; + if (status > 0 && status < SIZEOF(g_arrMoods)) { + pepMood->m_mode = status; + pepMood->m_text = JabberStrFixLines( pData->ptszMessage ); + pepMood->LaunchSetGui( 1 ); + return 0; + } + + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Advanced status slots +// DB data format: +// Contact / AdvStatus / Proto/Status/id = mode_id +// Contact / AdvStatus / Proto/Status/icon = icon +// Contact / AdvStatus / Proto/Status/title = title +// Contact / AdvStatus / Proto/Status/text = title + +void CJabberProto::RegisterAdvStatusSlot(const char *pszSlot) +{ + char szSetting[256]; + mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/id", m_szModuleName, pszSlot); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); + mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/icon", m_szModuleName, pszSlot); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); + mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/title", m_szModuleName, pszSlot); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); + mir_snprintf(szSetting, SIZEOF(szSetting), "AdvStatus/%s/%s/text", m_szModuleName, pszSlot); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)szSetting); +} + +void CJabberProto::ResetAdvStatus(HANDLE hContact, const char *pszSlot) +{ // set empty text before DBDeleteContactSetting to make resident setting manager happy + char szSetting[128]; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/id", m_szModuleName, pszSlot); + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); + DBDeleteContactSetting(hContact, "AdvStatus", szSetting); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/icon", m_szModuleName, pszSlot); + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); + DBDeleteContactSetting(hContact, "AdvStatus", szSetting); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/title", m_szModuleName, pszSlot); + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); + DBDeleteContactSetting(hContact, "AdvStatus", szSetting); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/text", m_szModuleName, pszSlot); + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); + DBDeleteContactSetting(hContact, "AdvStatus", szSetting); +} + +void CJabberProto::WriteAdvStatus(HANDLE hContact, const char *pszSlot, const TCHAR *pszMode, const char *pszIcon, const TCHAR *pszTitle, const TCHAR *pszText) +{ + char szSetting[128]; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/id", m_szModuleName, pszSlot); + DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszMode); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/icon", m_szModuleName, pszSlot); + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, pszIcon); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/title", m_szModuleName, pszSlot); + DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszTitle); + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/text", m_szModuleName, pszSlot); + if (pszText) { + DBWriteContactSettingTString(hContact, "AdvStatus", szSetting, pszText); + } else + { + // set empty text before DBDeleteContactSetting to make resident setting manager happy + DBWriteContactSettingString(hContact, "AdvStatus", szSetting, ""); + DBDeleteContactSetting(hContact, "AdvStatus", szSetting); + } +} + +char *CJabberProto::ReadAdvStatusA(HANDLE hContact, const char *pszSlot, const char *pszValue) +{ + char szSetting[128]; + DBVARIANT dbv = {0}; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", m_szModuleName, pszSlot, pszValue); + if (DBGetContactSettingString(hContact, "AdvStatus", szSetting, &dbv)) + return NULL; + + char *res = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + return res; +} + +TCHAR *CJabberProto::ReadAdvStatusT(HANDLE hContact, const char *pszSlot, const char *pszValue) +{ + char szSetting[128]; + DBVARIANT dbv = {0}; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", m_szModuleName, pszSlot, pszValue); + if (DBGetContactSettingTString(hContact, "AdvStatus", szSetting, &dbv)) + return NULL; + + TCHAR *res = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CJabberInfoFrame + +class CJabberInfoFrameItem +{ +public: + char *m_pszName; + HANDLE m_hIcolibIcon; + TCHAR *m_pszText; + LPARAM m_pUserData; + bool m_bCompact; + bool m_bShow; + void (CJabberProto::*m_onEvent)(CJabberInfoFrame_Event *); + RECT m_rcItem; + int m_tooltipId; + +public: +/* + CJabberInfoFrameItem(): + m_pszName(NULL), m_hIcolibIcon(NULL), m_pszText(NULL) + { + } +*/ + CJabberInfoFrameItem(char *pszName, bool bCompact=false, LPARAM pUserData=0): + m_pszName(NULL), m_hIcolibIcon(NULL), m_pszText(NULL), m_bShow(true), m_bCompact(bCompact), m_pUserData(pUserData), m_onEvent(NULL) + { + m_pszName = mir_strdup(pszName); + } + ~CJabberInfoFrameItem() + { + mir_free(m_pszName); + mir_free(m_pszText); + } + + void SetInfo(HANDLE hIcolibIcon, TCHAR *pszText) + { + mir_free(m_pszText); + m_pszText = pszText ? mir_tstrdup(pszText) : NULL; + m_hIcolibIcon = hIcolibIcon; + } + + static int cmp(const CJabberInfoFrameItem *p1, const CJabberInfoFrameItem *p2) + { + return lstrcmpA(p1->m_pszName, p2->m_pszName); + } +}; + +CJabberInfoFrame::CJabberInfoFrame(CJabberProto *proto): + m_pItems(3, CJabberInfoFrameItem::cmp), m_compact(false) +{ + m_proto = proto; + m_hwnd = m_hwndToolTip = NULL; + m_clickedItem = -1; + m_hiddenItemCount = 0; + m_bLocked = false; + m_nextTooltipId = 0; + m_hhkFontsChanged = 0; + + if (!proto->m_options.DisableFrame && ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + InitClass(); + + CLISTFrame frame = {0}; + frame.cbSize = sizeof(frame); + HWND hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); + frame.hWnd = CreateWindowEx(0, _T("JabberInfoFrameClass"), NULL, WS_CHILD|WS_VISIBLE, 0, 0, 100, 100, hwndClist, NULL, hInst, this); + frame.align = alBottom; + frame.height = 2 * SZ_FRAMEPADDING + GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING; // compact height by default + frame.Flags = F_VISIBLE|F_LOCKED|F_NOBORDER|F_TCHAR; + frame.tname = mir_a2t(proto->m_szModuleName); + frame.TBtname = proto->m_tszUserName; + m_frameId = CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM)&frame, 0); + mir_free(frame.tname); + if (m_frameId == -1) { + DestroyWindow(frame.hWnd); + return; + } + + m_hhkFontsChanged = HookEventMessage(ME_FONT_RELOAD, m_hwnd, WM_APP); + ReloadFonts(); + + m_hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + m_hwnd, NULL, hInst, NULL); + SetWindowPos(m_hwndToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + CreateInfoItem("$", true); + UpdateInfoItem("$", proto->GetIconHandle(IDI_JABBER), proto->m_tszUserName); + + CreateInfoItem("$/JID", true); + UpdateInfoItem("$/JID", LoadSkinnedIconHandle(SKINICON_OTHER_USERDETAILS), _T("Offline")); + SetInfoItemCallback("$/JID", &CJabberProto::InfoFrame_OnSetup); + } +} + +CJabberInfoFrame::~CJabberInfoFrame() +{ + if (!m_hwnd) return; + + if (m_hhkFontsChanged) UnhookEvent(m_hhkFontsChanged); + CallService(MS_CLIST_FRAMES_REMOVEFRAME, (WPARAM)m_frameId, 0); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + DestroyWindow(m_hwnd); + DestroyWindow(m_hwndToolTip); + DeleteObject(m_hfntText); + DeleteObject(m_hfntTitle); + m_hwnd = NULL; +} + +void CJabberInfoFrame::InitClass() +{ + static bool bClassRegistered = false; + if (bClassRegistered) return; + + WNDCLASSEX wcx = {0}; + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; + wcx.lpfnWndProc = GlobalWndProc; + wcx.hInstance = hInst; + wcx.lpszClassName = _T("JabberInfoFrameClass"); + wcx.hCursor = LoadCursor(NULL, IDC_ARROW); + RegisterClassEx(&wcx); + bClassRegistered = true; +} + +LRESULT CALLBACK CJabberInfoFrame::GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CJabberInfoFrame *pFrame; + + if (msg == WM_CREATE) + { + CREATESTRUCT *pcs = (CREATESTRUCT *)lParam; + pFrame = (CJabberInfoFrame *)pcs->lpCreateParams; + if (pFrame) pFrame->m_hwnd = hwnd; + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pFrame); + } else + { + pFrame = (CJabberInfoFrame *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + + return pFrame ? pFrame->WndProc(msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam); +} + +LRESULT CJabberInfoFrame::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_APP: + { + ReloadFonts(); + return 0; + } + + case WM_PAINT: + { + RECT rc; GetClientRect(m_hwnd, &rc); + m_compact = rc.bottom < (2 * (GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING) + SZ_LINESPACING + 2 * SZ_FRAMEPADDING); + + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwnd, &ps); + m_compact ? PaintCompact(hdc) : PaintNormal(hdc); + EndPaint(m_hwnd, &ps); + return 0; + } + + case WM_RBUTTONUP: + { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + MapWindowPoints(m_hwnd, NULL, &pt, 1); + HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDFRAMECONTEXT, m_frameId, 0); + int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL); + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, 0), m_frameId); + return 0; + } + + case WM_LBUTTONDOWN: + { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + for (int i = 0; i < m_pItems.getCount(); ++i) + if (m_pItems[i].m_onEvent && PtInRect(&m_pItems[i].m_rcItem, pt)) + { + m_clickedItem = i; + return 0; + } + + return 0; + } + + case WM_LBUTTONUP: + { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + if ((m_clickedItem >= 0) && (m_clickedItem < m_pItems.getCount()) && m_pItems[m_clickedItem].m_onEvent && PtInRect(&m_pItems[m_clickedItem].m_rcItem, pt)) + { + CJabberInfoFrame_Event evt; + evt.m_event = CJabberInfoFrame_Event::CLICK; + evt.m_pszName = m_pItems[m_clickedItem].m_pszName; + evt.m_pUserData = m_pItems[m_clickedItem].m_pUserData; + (m_proto->*m_pItems[m_clickedItem].m_onEvent)(&evt); + return 0; + } + + m_clickedItem = -1; + + return 0; + } + + case WM_LBUTTONDBLCLK: + { + m_compact = !m_compact; + UpdateSize(); + return 0; + } + } + + return DefWindowProc(m_hwnd, msg, wParam, lParam); +} + +void CJabberInfoFrame::LockUpdates() +{ + m_bLocked = true; +} + +void CJabberInfoFrame::Update() +{ + m_bLocked = false; + UpdateSize(); +} + +void CJabberInfoFrame::ReloadFonts() +{ + LOGFONT lfFont; + + FontID fontid = {0}; + fontid.cbSize = sizeof(fontid); + lstrcpyA(fontid.group, "Jabber"); + lstrcpyA(fontid.name, "Frame title"); + m_clTitle = CallService(MS_FONT_GET, (WPARAM)&fontid, (LPARAM)&lfFont); + DeleteObject(m_hfntTitle); + m_hfntTitle = CreateFontIndirect(&lfFont); + lstrcpyA(fontid.name, "Frame text"); + m_clText = CallService(MS_FONT_GET, (WPARAM)&fontid, (LPARAM)&lfFont); + DeleteObject(m_hfntText); + m_hfntText = CreateFontIndirect(&lfFont); + + ColourID colourid = {0}; + colourid.cbSize = sizeof(colourid); + lstrcpyA(colourid.group, "Jabber"); + lstrcpyA(colourid.name, "Background"); + m_clBack = CallService(MS_COLOUR_GET, (WPARAM)&colourid, 0); + + UpdateSize(); +} + +void CJabberInfoFrame::UpdateSize() +{ + if (!m_hwnd) return; + if (m_bLocked) return; + + int line_count = m_compact ? 1 : (m_pItems.getCount() - m_hiddenItemCount); + int height = 2 * SZ_FRAMEPADDING + line_count * (GetSystemMetrics(SM_CYSMICON) + SZ_LINEPADDING) + (line_count - 1) * SZ_LINESPACING; + + if (CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, m_frameId), 0) & F_VISIBLE) + { + if (!ServiceExists(MS_SKIN_DRAWGLYPH)) + { + // crazy resizing for clist_nicer... + CallService(MS_CLIST_FRAMES_SHFRAME, m_frameId, 0); + CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); + CallService(MS_CLIST_FRAMES_SHFRAME, m_frameId, 0); + } else + { + CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); + RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); + } + } else + { + CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, m_frameId), height); + } +} + +void CJabberInfoFrame::RemoveTooltip(int id) +{ + TOOLINFO ti = {0}; + ti.cbSize = sizeof(TOOLINFO); + + ti.hwnd = m_hwnd; + ti.uId = id; + SendMessage(m_hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); +} + +void CJabberInfoFrame::SetToolTip(int id, RECT *rc, TCHAR *pszText) +{ + TOOLINFO ti = {0}; + ti.cbSize = sizeof(TOOLINFO); + + ti.hwnd = m_hwnd; + ti.uId = id; + SendMessage(m_hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); + + ti.uFlags = TTF_SUBCLASS; + ti.hwnd = m_hwnd; + ti.uId = id; + ti.hinst = hInst; + ti.lpszText = pszText; + ti.rect = *rc; + SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); +} + +void CJabberInfoFrame::PaintSkinGlyph(HDC hdc, RECT *rc, char **glyphs, COLORREF fallback) +{ + if (ServiceExists(MS_SKIN_DRAWGLYPH)) + { + SKINDRAWREQUEST rq = {0}; + rq.hDC = hdc; + rq.rcDestRect = *rc; + rq.rcClipRect = *rc; + + for ( ; *glyphs; ++glyphs) + { + strncpy(rq.szObjectID, *glyphs, sizeof(rq.szObjectID)); + if (!CallService(MS_SKIN_DRAWGLYPH, (WPARAM)&rq, 0)) + return; + } + } + + if (fallback != 0xFFFFFFFF) + { + HBRUSH hbr = CreateSolidBrush(fallback); + FillRect(hdc, rc, hbr); + DeleteObject(hbr); + } +} + +void CJabberInfoFrame::PaintCompact(HDC hdc) +{ + RECT rc; GetClientRect(m_hwnd, &rc); + char *glyphs[] = { "Main,ID=ProtoInfo", "Main,ID=EventArea", "Main,ID=StatusBar", NULL }; + PaintSkinGlyph(hdc, &rc, glyphs, m_clBack); + + HFONT hfntSave = (HFONT)SelectObject(hdc, m_hfntTitle); + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, m_clTitle); + + int cx_icon = GetSystemMetrics(SM_CXSMICON); + int cy_icon = GetSystemMetrics(SM_CYSMICON); + + int cx = rc.right - cx_icon - SZ_FRAMEPADDING; + for (int i = m_pItems.getCount(); i--; ) + { + CJabberInfoFrameItem &item = m_pItems[i]; + + SetRect(&item.m_rcItem, 0, 0, 0, 0); + if (!item.m_bShow) continue; + if (!item.m_bCompact) continue; + + int depth = 0; + for (char *p = item.m_pszName; p = strchr(p+1, '/'); ++depth) ; + + if (depth == 0) + { + if (item.m_hIcolibIcon) + { + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); + if (hIcon) + { + DrawIconEx(hdc, SZ_FRAMEPADDING, (rc.bottom-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); + g_ReleaseIcon(hIcon); + } + } + + RECT rcText; SetRect(&rcText, cx_icon + SZ_FRAMEPADDING + SZ_ICONSPACING, 0, rc.right - SZ_FRAMEPADDING, rc.bottom); + DrawText(hdc, item.m_pszText, lstrlen(item.m_pszText), &rcText, DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS); + } else + { + if (item.m_hIcolibIcon) + { + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); + if (hIcon) + { + SetRect(&item.m_rcItem, cx, (rc.bottom-cy_icon)/2, cx+cx_icon, (rc.bottom-cy_icon)/2+cy_icon); + DrawIconEx(hdc, cx, (rc.bottom-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); + cx -= cx_icon; + + g_ReleaseIcon(hIcon); + + SetToolTip(item.m_tooltipId, &item.m_rcItem, item.m_pszText); + } + } + } + } + + SelectObject(hdc, hfntSave); +} + +void CJabberInfoFrame::PaintNormal(HDC hdc) +{ + RECT rc; GetClientRect(m_hwnd, &rc); + char *glyphs[] = { "Main,ID=ProtoInfo", "Main,ID=EventArea", "Main,ID=StatusBar", NULL }; + PaintSkinGlyph(hdc, &rc, glyphs, m_clBack); + + HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hdc, TRANSPARENT); + + int cx_icon = GetSystemMetrics(SM_CXSMICON); + int cy_icon = GetSystemMetrics(SM_CYSMICON); + int line_height = cy_icon + SZ_LINEPADDING; + int cy = SZ_FRAMEPADDING; + + for (int i = 0; i < m_pItems.getCount(); ++i) + { + CJabberInfoFrameItem &item = m_pItems[i]; + + if (!item.m_bShow) + { + SetRect(&item.m_rcItem, 0, 0, 0, 0); + continue; + } + + int cx = SZ_FRAMEPADDING; + int depth = 0; + for (char *p = item.m_pszName; p = strchr(p+1, '/'); cx += cx_icon) ++depth; + + SetRect(&item.m_rcItem, cx, cy, rc.right - SZ_FRAMEPADDING, cy + line_height); + + if (item.m_hIcolibIcon) + { + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)item.m_hIcolibIcon); + if (hIcon) + { + DrawIconEx(hdc, cx, cy + (line_height-cy_icon)/2, hIcon, cx_icon, cy_icon, 0, NULL, DI_NORMAL); + cx += cx_icon + SZ_ICONSPACING; + + g_ReleaseIcon(hIcon); + } + } + + SelectObject(hdc, depth ? m_hfntText : m_hfntTitle); + SetTextColor(hdc, depth ? m_clText : m_clTitle); + + RECT rcText; SetRect(&rcText, cx, cy, rc.right - SZ_FRAMEPADDING, cy + line_height); + DrawText(hdc, item.m_pszText, lstrlen(item.m_pszText), &rcText, DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS); + + RemoveTooltip(item.m_tooltipId); + + cy += line_height + SZ_LINESPACING; + } + + SelectObject(hdc, hfntSave); +} + +void CJabberInfoFrame::CreateInfoItem(char *pszName, bool bCompact, LPARAM pUserData) +{ + CJabberInfoFrameItem item(pszName); + if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) + return; + + CJabberInfoFrameItem *newItem = new CJabberInfoFrameItem(pszName, bCompact, pUserData); + newItem->m_tooltipId = m_nextTooltipId++; + m_pItems.insert(newItem); + UpdateSize(); +} + +void CJabberInfoFrame::SetInfoItemCallback(char *pszName, void (CJabberProto::*onEvent)(CJabberInfoFrame_Event *)) +{ + CJabberInfoFrameItem item(pszName); + if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) + { + pItem->m_onEvent = onEvent; + } +} + +void CJabberInfoFrame::UpdateInfoItem(char *pszName, HANDLE hIcolibIcon, TCHAR *pszText) +{ + CJabberInfoFrameItem item(pszName); + if (CJabberInfoFrameItem *pItem = m_pItems.find(&item)) + pItem->SetInfo(hIcolibIcon, pszText); + if (m_hwnd) + RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); +} + +void CJabberInfoFrame::ShowInfoItem(char *pszName, bool bShow) +{ + bool bUpdate = false; + size_t length = strlen(pszName); + for (int i = 0; i < m_pItems.getCount(); ++i) + if ((m_pItems[i].m_bShow != bShow) && !strncmp(m_pItems[i].m_pszName, pszName, length)) + { + m_pItems[i].m_bShow = bShow; + m_hiddenItemCount += bShow ? -1 : 1; + bUpdate = true; + } + + if (bUpdate) + UpdateSize(); +} + +void CJabberInfoFrame::RemoveInfoItem(char *pszName) +{ + bool bUpdate = false; + size_t length = strlen(pszName); + for (int i = 0; i < m_pItems.getCount(); ++i) + if (!strncmp(m_pItems[i].m_pszName, pszName, length)) + { + if (!m_pItems[i].m_bShow) --m_hiddenItemCount; + RemoveTooltip(m_pItems[i].m_tooltipId); + m_pItems.remove(i); + bUpdate = true; + --i; + } + + if (bUpdate) + UpdateSize(); +} diff --git a/protocols/JabberG/src/jabber_xstatus.h b/protocols/JabberG/src/jabber_xstatus.h new file mode 100644 index 0000000000..ae12ebae86 --- /dev/null +++ b/protocols/JabberG/src/jabber_xstatus.h @@ -0,0 +1,191 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _JABBER_XSTATUS_H_ +#define _JABBER_XSTATUS_H_ + +struct CJabberProto; + +class CPepService +{ +public: + CPepService(CJabberProto *proto, char *name, TCHAR *node); + virtual ~CPepService(); + + HANDLE GetMenu() { return m_hMenuItem; } + TCHAR *GetNode() { return m_node; } + virtual void ProcessItems(const TCHAR *from, HXML items) = 0; + + void Publish(); + void Retract(); + void ResetPublish(); + + virtual void InitGui() {} + virtual void RebuildMenu() {} + virtual void ResetExtraIcon(HANDLE /*hContact*/) {} + virtual bool LaunchSetGui() { return false; } + +protected: + CJabberProto *m_proto; + char *m_name; + TCHAR *m_node; + HANDLE m_hMenuItem; + + int m_wasPublished; + + virtual void CreateData( HXML ) = 0; + void ForceRepublishOnLogin(); +}; + +class CPepServiceList: public OBJLIST<CPepService> +{ +public: + CPepServiceList(): OBJLIST<CPepService>(1) {} + + void ProcessEvent(const TCHAR *from, HXML eventNode) + { + for (int i = 0; i < getCount(); ++i) + { + CPepService &pepSvc = (*this)[i]; + HXML itemsNode = xmlGetChildByTag( eventNode, _T("items"), _T("node"), pepSvc.GetNode()); + if ( itemsNode ) + pepSvc.ProcessItems(from, itemsNode); + } + } + + void InitGui() + { + for (int i = 0; i < getCount(); ++i) + (*this)[i].InitGui(); + } + + void RebuildMenu() + { + for (int i = 0; i < getCount(); ++i) + (*this)[i].RebuildMenu(); + } + + void ResetExtraIcon(HANDLE hContact) + { + for (int i = 0; i < getCount(); ++i) + (*this)[i].ResetExtraIcon(hContact); + } + + void PublishAll() + { + for (int i = 0; i < getCount(); ++i) + (*this)[i].Publish(); + } + + void RetractAll() + { + for (int i = 0; i < getCount(); ++i) + (*this)[i].Retract(); + } + + void ResetPublishAll() + { + for(int i = 0; i < getCount(); ++i) + (*this)[i].ResetPublish(); + } + + CPepService *Find(TCHAR *node) + { + for (int i = 0; i < getCount(); ++i) + if (!lstrcmp((*this)[i].GetNode(), node)) + return &((*this)[i]); + return NULL; + } +}; + +class CPepGuiService: public CPepService +{ + typedef CPepService CSuper; +public: + CPepGuiService(CJabberProto *proto, char *name, TCHAR *node); + ~CPepGuiService(); + void InitGui(); + void RebuildMenu(); + bool LaunchSetGui(BYTE bQuiet); + +protected: + void UpdateMenuItem(HANDLE hIcolibIcon, TCHAR *text); + virtual void ShowSetDialog(BYTE bQuiet) = 0; + +private: + HANDLE m_hMenuService; + HANDLE m_hIcolibItem; + TCHAR *m_szText; + + bool m_bGuiOpen; + + int __cdecl OnMenuItemClick(WPARAM, LPARAM); +}; + +class CPepMood: public CPepGuiService +{ + typedef CPepGuiService CSuper; +public: + CPepMood(CJabberProto *proto); + ~CPepMood(); + void InitGui(); + void ProcessItems(const TCHAR *from, HXML items); + void ResetExtraIcon(HANDLE hContact); + +public: // FIXME: ugly hack + CIconPool m_icons; + TCHAR *m_text; + int m_mode; + +protected: + void CreateData( HXML ); + void ShowSetDialog(BYTE bQuiet); + void SetExtraIcon(HANDLE hContact, char *szMood); + + void SetMood(HANDLE hContact, const TCHAR *szMood, const TCHAR *szText); +}; + +class CPepActivity: public CPepGuiService +{ + typedef CPepGuiService CSuper; +public: + CPepActivity(CJabberProto *proto); + ~CPepActivity(); + void InitGui(); + void ProcessItems(const TCHAR *from, HXML items); + void ResetExtraIcon(HANDLE hContact); + +protected: + CIconPool m_icons; + TCHAR *m_text; + int m_mode; + + void CreateData( HXML ); + void ShowSetDialog(BYTE bQuiet); + void SetExtraIcon(HANDLE hContact, char *szActivity); + + void SetActivity(HANDLE hContact, LPCTSTR szFirst, LPCTSTR szSecond, LPCTSTR szText); +}; + +#endif // _JABBER_XSTATUS_H_ diff --git a/protocols/JabberG/src/jabber_zstream.cpp b/protocols/JabberG/src/jabber_zstream.cpp new file mode 100644 index 0000000000..11829bf401 --- /dev/null +++ b/protocols/JabberG/src/jabber_zstream.cpp @@ -0,0 +1,128 @@ +/* + +Jabber Protocol Plugin for Miranda IM +XEP-0138 (Stream Compression) implementation + +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007 Kostya Chukavin, Taras Zackrepa + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +BOOL ThreadData::zlibInit( void ) +{ + proto->Log( "Zlib init..." ); + zStreamIn.zalloc = Z_NULL; + zStreamIn.zfree = Z_NULL; + zStreamIn.opaque = Z_NULL; + zStreamIn.next_in = Z_NULL; + zStreamIn.avail_in = 0; + + zStreamOut.zalloc = Z_NULL; + zStreamOut.zfree = Z_NULL; + zStreamOut.opaque = Z_NULL; + + if ( deflateInit( &zStreamOut, Z_BEST_COMPRESSION) != Z_OK ) return FALSE; + if ( inflateInit( &zStreamIn ) != Z_OK ) return FALSE; + + zRecvReady = true; + return TRUE; +} + +void ThreadData::zlibUninit( void ) +{ + deflateEnd( &zStreamOut ); + inflateEnd( &zStreamIn ); +} + +int ThreadData::zlibSend( char* data, int datalen ) +{ + char send_data[ ZLIB_CHUNK_SIZE ]; + int bytesOut = 0; + + zStreamOut.avail_in = datalen; + zStreamOut.next_in = ( unsigned char* )data; + + do { + zStreamOut.avail_out = ZLIB_CHUNK_SIZE; + zStreamOut.next_out = ( unsigned char* )send_data; + + switch ( deflate( &zStreamOut, Z_SYNC_FLUSH )) { + case Z_OK: proto->Log( "Deflate: Z_OK" ); break; + case Z_BUF_ERROR: proto->Log( "Deflate: Z_BUF_ERROR" ); break; + case Z_DATA_ERROR: proto->Log( "Deflate: Z_DATA_ERROR" ); break; + case Z_MEM_ERROR: proto->Log( "Deflate: Z_MEM_ERROR" ); break; + } + + int len, send_datalen = ZLIB_CHUNK_SIZE - zStreamOut.avail_out; + + if (( len = sendws( send_data, send_datalen, MSG_NODUMP )) == SOCKET_ERROR || len != send_datalen ) { + proto->Log( "Netlib_Send() failed, error=%d", WSAGetLastError()); + return FALSE; + } + + bytesOut += len; + } + while ( zStreamOut.avail_out == 0 ); + + if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) + proto->Log( "(ZLIB) Data sent\n%s\n===OUT: %d(%d) bytes", data, datalen, bytesOut ); + + return TRUE; +} + +int ThreadData::zlibRecv( char* data, long datalen ) +{ + if ( zRecvReady ) { +retry: + zRecvDatalen = recvws( zRecvData, ZLIB_CHUNK_SIZE, MSG_NODUMP ); + if ( zRecvDatalen == SOCKET_ERROR ) { + proto->Log( "Netlib_Recv() failed, error=%d", WSAGetLastError()); + return SOCKET_ERROR; + } + if ( zRecvDatalen == 0 ) + return 0; + + zStreamIn.avail_in = zRecvDatalen; + zStreamIn.next_in = ( Bytef* )zRecvData; + } + + zStreamIn.avail_out = datalen; + zStreamIn.next_out = ( BYTE* )data; + + switch ( inflate( &zStreamIn, Z_NO_FLUSH )) { + case Z_OK: proto->Log( "Inflate: Z_OK" ); break; + case Z_BUF_ERROR: proto->Log( "Inflate: Z_BUF_ERROR" ); break; + case Z_DATA_ERROR: proto->Log( "Inflate: Z_DATA_ERROR" ); break; + case Z_MEM_ERROR: proto->Log( "Inflate: Z_MEM_ERROR" ); break; + } + + int len = datalen - zStreamIn.avail_out; + if ( DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", TRUE ) == TRUE ) { + char* szLogBuffer = ( char* )alloca( len+32 ); + memcpy( szLogBuffer, data, len ); + szLogBuffer[ len ]='\0'; + proto->Log( "(ZLIB) Data received\n%s\n===IN: %d(%d) bytes", szLogBuffer, len, zRecvDatalen ); + } + + if ( len == 0 ) + goto retry; + + zRecvReady = ( zStreamIn.avail_out != 0 ); + return len; +} diff --git a/protocols/JabberG/src/resource.h b/protocols/JabberG/src/resource.h new file mode 100644 index 0000000000..5cbc583aa5 --- /dev/null +++ b/protocols/JabberG/src/resource.h @@ -0,0 +1,358 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by jabber.rc +// +#define IDD_OPT_JABBER 101 +#define IDI_JABBER 102 +#define IDD_INFO_JABBER 103 +#define IDD_OPT_REGISTER 105 +#define IDD_AGENTS 106 +#define IDD_FORM 107 +#define IDI_ADDROSTER 108 +#define IDI_USER2ROOM 109 +#define IDI_REFRESH 110 +#define IDD_PASSWORD 111 +#define IDI_ADDCONTACT 122 +#define IDI_DELETE 123 +#define IDI_EDIT 124 +#define IDD_DATAFORM_TEST 125 +#define IDD_VCARD_HOME 126 +#define IDD_VCARD_PERSONAL 127 +#define IDD_VCARD_WORK 128 +#define IDD_VCARD_CONTACT 129 +#define IDD_VCARD_ADDEMAIL 130 +#define IDD_VCARD_ADDPHONE 131 +#define IDI_OPEN 131 +#define IDD_VCARD_PHOTO 132 +#define IDD_VCARD_NOTE 133 +#define IDD_CHANGEPASSWORD 136 +#define IDD_SEARCHUSER 138 +#define IDD_OPT_JABBER2 140 +#define IDI_REQUEST 141 +#define IDD_GROUPCHAT 141 +#define IDI_GRANT 142 +#define IDI_KEYS 144 +#define IDI_GROUP 147 +#define IDD_GROUPCHAT_JOIN 148 +#define IDI_AGENTS 154 +#define IDI_VCARD 155 +#define IDI_SAVE 166 +#define IDD_GROUPCHAT_INPUT 167 +#define IDD_JIDLIST 171 +#define IDD_AGENT_MANUAL_REGISTER 182 +#define IDD_GROUPCHAT_INVITE 183 +#define IDD_GROUPCHAT_INVITE_ACCEPT 184 +#define IDD_OPT_JABBER3 185 +#define IDI_LOGIN 186 +#define IDI_AUTHREVOKE 187 +#define IDI_COMMAND 188 +#define IDI_DISCO_OK 190 +#define IDI_DISCO_FAIL 191 +#define IDI_VIEW_LIST 192 +#define IDI_VIEW_TREE 193 +#define IDI_FILTER_APPLY 194 +#define IDI_BROWSE 195 +#define IDI_NAV_HOME 196 +#define IDI_NAV_REFRESH 197 +#define IDI_FILTER_RESET 198 +#define IDI_DISCO_PROGRESS 199 +#define IDI_NODE_RSS 200 +#define IDI_NODE_SERVER 201 +#define IDI_NODE_STORE 202 +#define IDI_NODE_WEATHER 203 +#define IDD_CONSOLE 205 +#define IDI_CONSOLE 207 +#define IDD_DATAFORM_PAGE 208 +#define IDI_PL_MSG_ALLOW 209 +#define IDI_PL_MSG_DENY 210 +#define IDI_PL_PRIN_ALLOW 211 +#define IDI_PL_PRIN_DENY 212 +#define IDI_PL_PROUT_ALLOW 213 +#define IDI_PL_PROUT_DENY 214 +#define IDI_PL_QUERY_ALLOW 215 +#define IDD_SETMOODMSG 216 +#define IDI_PL_QUERY_DENY 216 +#define IDI_PL_LIST_ACTIVE 217 +#define IDI_PL_LIST_ANY 218 +#define IDI_PL_LIST_DEFAULT 219 +#define IDI_ARROW_DOWN 220 +#define IDI_ARROW_UP 221 +#define IDI_TRANSPORT 222 +#define IDI_TRANSPORTL 223 +#define IDD_GROUPCHAT_INFO 224 +#define IDD_OPT_JABBER4 226 +#define IDD_ACCMGRUI 227 +#define IDD_HTTP_AUTH 228 +#define IDI_HTTP_AUTH 229 +#define IDD_PEP_SIMPLE 230 +#define IDD_NOTEBOOK 231 +#define IDD_NOTE_EDIT 232 +#define IDI_NOTES 233 +#define IDI_SEND_NOTE 234 +#define IDC_STATUSBAR 999 +#define IDC_EDIT_USERNAME 1000 +#define IDC_SAVE 1000 +#define IDC_EDIT_PASSWORD 1001 +#define IDC_BUTTON_REGISTER 1002 +#define IDC_EDIT_LOGIN_SERVER 1003 +#define IDC_PORT 1004 +#define IDC_BUTTON_CHANGE_PASSWORD 1005 +#define IDC_LINK_PUBLIC_SERVER 1009 +#define IDC_NAME 1009 +#define IDC_PROGRESS_REG 1011 +#define IDC_AGENT_TRANSPORT 1015 +#define IDC_AGENT_REGISTER 1016 +#define IDC_AGENT_LOGON 1017 +#define IDC_AGENT_UNREGISTER 1018 +#define IDC_AGENT_SERVER 1019 +#define IDC_AGENT_LOGOFF 1020 +#define IDC_AGENT_LIST 1021 +#define IDC_AGENT_SEARCH 1022 +#define IDC_SUBMIT 1023 +#define IDC_NEXT 1025 +#define IDC_PREV 1026 +#define IDC_COMPLETE 1027 +#define IDC_AGENT_BROWSE 1029 +#define IDC_INSTRUCTION 1030 +#define IDC_FRAME 1037 +#define IDC_FRAME_TEXT 1038 +#define IDC_SIMPLE 1041 +#define IDC_KEEPALIVE 1042 +#define IDC_HOST 1043 +#define IDC_HOSTPORT 1044 +#define IDC_USE_SSL 1045 +#define IDC_MANUAL 1046 +#define IDC_RESOURCE_T 1047 +#define IDC_SAVEPASSWORD 1048 +#define IDC_MSGLANG 1049 +#define IDC_PASSWORD 1050 +#define IDC_JID 1051 +#define IDC_NEWPASSWD2 1052 +#define IDC_ROSTER_SYNC 1052 +#define IDC_OLDPASSWD 1053 +#define IDC_ADDRESS1 1056 +#define IDC_ADDRESS2 1057 +#define IDC_CITY 1058 +#define IDC_STATE 1059 +#define IDC_COUNTRY 1060 +#define IDC_FULLNAME 1061 +#define IDC_ZIP 1061 +#define IDC_NICKNAME 1062 +#define IDC_COMPANY 1062 +#define IDC_FIRSTNAME 1063 +#define IDC_DEPARTMENT 1063 +#define IDC_LASTNAME 1064 +#define IDC_BIRTH 1065 +#define IDC_OCCUPATION 1066 +#define IDC_HOMEPAGE 1067 +#define IDC_MIDDLE 1072 +#define IDC_EMAIL 1073 +#define IDC_HOME 1074 +#define IDC_INTERNET 1075 +#define IDC_X400 1076 +#define IDC_WORK 1077 +#define IDC_PHONE 1078 +#define IDC_CELL 1079 +#define IDC_VIDEO 1080 +#define IDC_BBS 1081 +#define IDC_MODEM 1082 +#define IDC_PAGER 1083 +#define IDC_MSG 1084 +#define IDC_ISDN 1085 +#define IDC_PCS 1086 +#define IDC_VOICE 1087 +#define IDC_FAX 1088 +#define IDC_TITLE 1089 +#define IDC_DESC 1090 +#define IDC_DELETE 1092 +#define IDC_LOAD 1093 +#define IDC_CANVAS 1094 +#define IDC_GENDER 1096 +#define IDC_JUD 1097 +#define IDC_JUD_LABEL 1098 +#define IDC_MSGLANG_LABEL 1099 +#define IDC_PRIORITY_SPIN 1104 +#define IDC_PRIORITY 1105 +#define IDC_PRIORITY_LABEL 1106 +#define IDC_NEWPASSWD 1107 +#define IDC_COMBO_ACCTYPE 1108 +#define IDD_MODERNOPT 1110 +#define IDC_PROXY_ADDR 1112 +#define IDC_DIRECT_ADDR 1114 +#define IDC_DIRECT_MANUAL 1121 +#define IDC_REG_STATUS 1122 +#define IDC_JOIN 1123 +#define IDC_DIRECT 1123 +#define IDC_ROOM 1124 +#define IDC_PROXY_MANUAL 1124 +#define IDC_SERVER 1125 +#define IDC_BROWSE 1126 +#define IDC_VSCROLL 1128 +#define IDC_NICK 1129 +#define IDC_EDIT 1131 +#define IDC_LIST 1133 +#define IDC_TABS 1141 +#define IDC_TXT_MULTILINE 1141 +#define IDC_TXT_PASSWORD 1142 +#define IDC_MANUAL_REGISTER 1167 +#define IDC_REASON 1171 +#define IDC_CLIST 1172 +#define IDC_NEWJID 1173 +#define IDC_ADDJID 1174 +#define IDC_INVITE 1175 +#define IDC_BTN_ADVANCED 1175 +#define IDC_ACCEPT 1176 +#define IDC_BTN_SIMPLE 1176 +#define IDC_FROM 1177 +#define IDC_USE_TLS 1180 +#define IDC_UNREGISTER 1183 +#define IDC_GO 1196 +#define IDC_HOSTNAME_AS_RESOURCE 1214 +#define IDC_COMMANDS1 1216 +#define IDC_COMMANDS2 1217 +#define IDC_COMBO_RESOURCE 1218 +#define IDC_PL_RULES_LIST 1219 +#define IDC_WHITERECT 1220 +#define IDC_ADD_RULE 1221 +#define IDC_EDIT_RULE 1222 +#define IDC_REMOVE_RULE 1223 +#define IDC_ADD_LIST 1225 +#define IDC_REMOVE_LIST 1226 +#define IDC_COMBO_TYPE 1230 +#define IDC_EDIT_VALUE 1231 +#define IDC_COMBO_ACTION 1232 +#define IDC_CHECK_MESSAGES 1233 +#define IDC_CHECK_QUERIES 1234 +#define IDC_CHECK_PRESENCE_OUT 1235 +#define IDC_CHECK_PRESENCE_IN 1236 +#define IDC_COMBO_VALUE 1237 +#define IDC_EDIT_NAME 1238 +#define IDC_TREE_DISCO 1240 +#define IDC_FRAME1 1241 +#define IDC_FRAME2 1242 +#define IDC_COMBO_JID 1243 +#define IDC_TXT_JID 1243 +#define IDC_COMBO_NODE 1244 +#define IDC_BUTTON_BROWSE 1245 +#define IDC_DOWNLOAD 1245 +#define IDC_ACTIVATE 1245 +#define IDC_BTN_NAVHOME 1246 +#define IDC_UPLOAD 1246 +#define IDC_TXT_FILTERTEXT 1247 +#define IDC_IMPORT 1247 +#define IDC_BTN_FILTERRESET 1248 +#define IDC_EXPORT 1248 +#define IDC_TXT_FILTER 1249 +#define IDC_TXT_NODELABEL 1250 +#define IDC_BTN_FAVORITE 1251 +#define IDC_BTN_REFRESH 1253 +#define IDC_BTN_VIEWTREE 1254 +#define IDC_BTN_VIEWLIST 1255 +#define IDC_BTN_FILTERAPPLY 1258 +#define IDC_ROSTER 1261 +#define IDC_MSG_MOOD 1262 +#define IDC_OPTTREE 1263 +#define IDC_LB_LISTS 1264 +#define IDC_LST_NOTES 1264 +#define IDC_TITLE1 1265 +#define IDC_CONSOLE 1266 +#define IDC_CONSOLEIN 1267 +#define IDC_RESET 1268 +#define IDC_BOOKMARKS 1270 +#define IDC_BTN_MSG 1270 +#define IDC_BTN_ROLE 1270 +#define IDC_DATAFORM 1270 +#define IDC_BTN_PRESENCE 1271 +#define IDC_BTN_AFFILIATION 1271 +#define IDC_SET_DEFAULT 1272 +#define IDC_BTN_IQ 1272 +#define IDC_TXT_RULES 1273 +#define IDC_TXT_LISTS 1274 +#define IDC_TV_INFO 1276 +#define IDC_TXT_OTHERJID 1277 +#define IDC_TXT_MESSAGE 1278 +#define IDC_TXT_QUERY 1279 +#define IDC_TXT_INPRESENCE 1280 +#define IDC_TXT_OUTPRESENCE 1281 +#define IDC_ICO_OUTPRESENCE 1282 +#define IDC_ICO_INPRESENCE 1283 +#define IDC_ICO_QUERY 1284 +#define IDC_ICO_MESSAGE 1285 +#define IDC_ICO_PRESENCEIN 1286 +#define IDC_ICO_PRESENCEOUT 1287 +#define IDC_RECENT1 1288 +#define IDC_RECENT2 1289 +#define IDC_RECENT3 1290 +#define IDC_RECENT4 1291 +#define IDC_RECENT5 1292 +#define IDC_TXT_RECENT 1293 +#define IDC_FILTER 1294 +#define IDC_TXT_NICK 1294 +#define IDC_TXT_QUIT 1294 +#define IDC_EDIT_HTTP_AUTH_INFO 1294 +#define IDC_TXT_URL 1294 +#define IDC_TXT_DESCRIPTION 1294 +#define IDC_TXT_TITLE 1294 +#define IDC_BTN_FILTER 1295 +#define IDC_TXT_ID 1295 +#define IDC_CB_FILTER 1296 +#define IDC_TXT_ROLE 1296 +#define IDC_TXT_COMBO 1296 +#define IDC_CB_TYPE 1296 +#define IDC_TXT_METHOD 1296 +#define IDC_CB_MODES 1296 +#define IDC_BTN_FILTER_REFRESH 1297 +#define IDC_TXT_STATUS 1298 +#define IDC_TXT_FROM 1298 +#define IDC_TXT_AFFILIATION 1299 +#define IDC_ICO_STATUS 1300 +#define IDC_TXT_RICHEDIT 1302 +#define IDC_TXT_SLAP 1304 +#define IDC_TXT_TAGS 1304 +#define IDC_EMAILS 1306 +#define IDC_TV_FILTER 1307 +#define IDC_PHONES 1308 +#define IDC_TXT_TEXT 1308 +#define IDC_ST_TAGS 1309 +#define IDC_INSTRUCTIONS 1315 +#define IDC_COMBO_VALUES 1319 +#define IDC_HEADERBAR 1320 +#define IDC_USEDOMAINLOGIN 1323 +#define IDC_TXT_ALTNICK 1323 +#define IDI_BOOKMARKS 3000 +#define IDD_BOOKMARKS 3001 +#define IDC_BM_LIST 3002 +#define IDC_ADD 3004 +#define IDC_REMOVE 3005 +#define IDD_BOOKMARK_ADD 3006 +#define IDC_UP_RULE 3006 +#define IDC_ROOM_JID 3007 +#define IDD_PRIVACY_LISTS 3007 +#define IDC_DOWN_RULE 3007 +#define IDC_APPLY 3008 +#define IDD_PRIVACY_RULE 3008 +#define IDC_ROOM_RADIO 3009 +#define IDD_PRIVACY_ADD_LIST 3009 +#define IDD_SERVICE_DISCOVERY 3010 +#define IDC_URL_RADIO 3011 +#define IDD_GROUPCHAT_INFO_TABS 3011 +#define IDC_AGENT_RADIO 3012 +#define IDD_GROUPCHAT_ADMLIST 3012 +#define IDC_BOOKMARK_TYPE 3013 +#define IDC_CHECK_BM_AUTOJOIN 3014 +#define IDI_PRIVACY_LISTS 3016 +#define IDI_SERVICE_DISCOVERY 3017 +#define IDD_CAPTCHAFORM 3018 +#define IDC_VALUE 3019 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 235 +#define _APS_NEXT_COMMAND_VALUE 40017 +#define _APS_NEXT_CONTROL_VALUE 1324 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/JabberG/src/ui_utils.cpp b/protocols/JabberG/src/ui_utils.cpp new file mode 100644 index 0000000000..39f63ecae7 --- /dev/null +++ b/protocols/JabberG/src/ui_utils.cpp @@ -0,0 +1,2574 @@ +/* + +Object UI extensions +Copyright (C) 2008 Victor Pavlychko, George Hazan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "jabber.h" + +extern HINSTANCE hInst; + +CDlgBase::CDlgBase(int idDialog, HWND hwndParent) : + m_controls(1, CCtrlBase::cmp) +{ + m_idDialog = idDialog; + m_hwndParent = hwndParent; + m_hwnd = NULL; + m_first = NULL; + m_isModal = false; + m_initialized = false; + m_autoClose = CLOSE_ON_OK|CLOSE_ON_CANCEL; + m_forceResizable = false; +} + +CDlgBase::~CDlgBase() +{ + // remove handlers + m_controls.destroy(); + + if (m_hwnd) + DestroyWindow(m_hwnd); +} + +void CDlgBase::Create() +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_HIDE); +} + +void CDlgBase::Show(int nCmdShow) +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), nCmdShow); +} + +int CDlgBase::DoModal() +{ + m_isModal = true; + return DialogBoxParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this); +} + +int CDlgBase::Resizer(UTILRESIZECONTROL*) +{ + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + m_initialized = false; + TranslateDialogDefault(m_hwnd); + + for ( CCtrlBase* p = m_first; p != NULL; p = p->m_next ) + AddControl( p ); + + NotifyControls(&CCtrlBase::OnInit); + OnInitDialog(); + + m_initialized = true; + return TRUE; + } + + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnMeasureItem(param); + return FALSE; + } + + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDrawItem(param); + return FALSE; + } + + case WM_DELETEITEM: + { + DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDeleteItem(param); + return FALSE; + } + + case WM_COMMAND: + { + HWND hwndCtrl = (HWND)lParam; + WORD idCtrl = LOWORD(wParam); + WORD idCode = HIWORD(wParam); + if (CCtrlBase *ctrl = FindControl(idCtrl)) { + BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode); + if ( result != FALSE ) + return result; + } + + if (idCode == BN_CLICKED && + ((idCtrl == IDOK) && (m_autoClose & CLOSE_ON_OK) || + (idCtrl == IDCANCEL) && (m_autoClose & CLOSE_ON_CANCEL))) + { + PostMessage( m_hwnd, WM_CLOSE, 0, 0 ); + } + return FALSE; + } + + case WM_NOTIFY: + { + int idCtrl = wParam; + NMHDR *pnmh = (NMHDR *)lParam; + + if (pnmh->idFrom == 0) + { + if (pnmh->code == PSN_APPLY) + { + NotifyControls(&CCtrlBase::OnApply); + OnApply(); + } + else if (pnmh->code == PSN_RESET) + { + NotifyControls(&CCtrlBase::OnReset); + OnReset(); + } + } + + if (CCtrlBase *ctrl = FindControl(pnmh->idFrom)) + return ctrl->OnNotify(idCtrl, pnmh); + return FALSE; + } + + case WM_SIZE: + { + if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_SIZEBOX)) + { + UTILRESIZEDIALOG urd; + urd.cbSize = sizeof(urd); + urd.hwndDlg = m_hwnd; + urd.hInstance = hInst; + urd.lpTemplate = MAKEINTRESOURCEA(m_idDialog); + urd.lParam = 0; + urd.pfnResizer = GlobalDlgResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + } + return TRUE; + } + + case WM_CLOSE: + { + m_lresult = FALSE; + OnClose(); + if ( !m_lresult ) + { + if (m_isModal) + EndDialog(m_hwnd, 0); + else + DestroyWindow(m_hwnd); + } + return TRUE; + } + + case WM_DESTROY: + { + OnDestroy(); + NotifyControls(&CCtrlBase::OnDestroy); + + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + m_hwnd = NULL; + if (m_isModal) + { + m_isModal = false; + } else + { // modeless dialogs MUST be allocated with 'new' + delete this; + } + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CDlgBase *wnd = NULL; + if (msg == WM_INITDIALOG) + { + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + wnd = (CDlgBase *)lParam; + wnd->m_hwnd = hwnd; + } else + { + wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + + if (!wnd) return FALSE; + + wnd->m_msg.hwnd = hwnd; + wnd->m_msg.message = msg; + wnd->m_msg.wParam = wParam; + wnd->m_msg.lParam = lParam; + return wnd->DlgProc(msg, wParam, lParam); +} + +int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) +{ + CDlgBase *wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!wnd) return 0; + + return wnd->Resizer(urc); +} + +CDlgBase::pfnEnableThemeDialogTexture CDlgBase::MyEnableThemeDialogTexture = NULL; +void CDlgBase::ThemeDialogBackground(BOOL tabbed) +{ + if (!MyEnableThemeDialogTexture && IsWinVerXPPlus()) + { + HMODULE hThemeAPI = GetModuleHandleA("uxtheme"); + if (hThemeAPI) + MyEnableThemeDialogTexture = (pfnEnableThemeDialogTexture)GetProcAddress(hThemeAPI,"EnableThemeDialogTexture"); + } + + if (MyEnableThemeDialogTexture) + { + MyEnableThemeDialogTexture(m_hwnd,(tabbed?0x00000002:0x00000001)|0x00000004); //0x00000002|0x00000004=ETDT_ENABLETAB + } +} + +void CDlgBase::AddControl(CCtrlBase *ctrl) +{ + m_controls.insert(ctrl); +} + +void CDlgBase::NotifyControls(void (CCtrlBase::*fn)()) +{ + for (int i = 0; i < m_controls.getCount(); ++i) + (m_controls[i]->*fn)(); +} + +CCtrlBase* CDlgBase::FindControl(int idCtrl) +{ + CCtrlBase search(NULL, idCtrl); + return m_controls.find(&search); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo class + +CCtrlCombo::CCtrlCombo( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCombo::AddString(const TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +int CCtrlCombo::AddStringA(const char *text, LPARAM data) +{ + int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::DeleteString(int index) +{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0); +} + +int CCtrlCombo::FindString(const TCHAR *str, int index, bool exact ) +{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::FindStringA(const char *str, int index, bool exact ) +{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::GetCount() +{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0); +} + +int CCtrlCombo::GetCurSel() +{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); +} + +bool CCtrlCombo::GetDroppedState() +{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false; +} + +LPARAM CCtrlCombo::GetItemData(int index) +{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlCombo::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlCombo::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +int CCtrlCombo::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::ResetContent() +{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0); +} + +int CCtrlCombo::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlCombo::SetCurSel(int index) +{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0); +} + +void CCtrlCombo::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data); +} + +void CCtrlCombo::ShowDropdown(bool show) +{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox class + +CCtrlListBox::CCtrlListBox( CDlgBase* dlg, int ctrlId ) : + CCtrlBase( dlg, ctrlId ) +{ +} + +BOOL CCtrlListBox::OnCommand(HWND, WORD, WORD idCode) +{ + switch (idCode) + { + case LBN_DBLCLK: OnDblClick(this); break; + case LBN_SELCANCEL: OnSelCancel(this); break; + case LBN_SELCHANGE: OnSelChange(this); break; + } + return TRUE; +} + +int CCtrlListBox::AddString(TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)text); + SendMessage(m_hwnd, LB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::DeleteString(int index) +{ SendMessage(m_hwnd, LB_DELETESTRING, index, 0); +} + +int CCtrlListBox::FindString( TCHAR *str, int index, bool exact) +{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlListBox::GetCount() +{ return SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); +} + +int CCtrlListBox::GetCurSel() +{ return SendMessage(m_hwnd, LB_GETCURSEL, 0, 0); +} + +LPARAM CCtrlListBox::GetItemData(int index) +{ return SendMessage(m_hwnd, LB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlListBox::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlListBox::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +bool CCtrlListBox::GetSel(int index) +{ return SendMessage(m_hwnd, LB_GETSEL, index, 0) ? true : false; +} + +int CCtrlListBox::GetSelCount() +{ return SendMessage(m_hwnd, LB_GETSELCOUNT, 0, 0); +} + +int* CCtrlListBox::GetSelItems(int *items, int count) +{ + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)items); + return items; +} + +int* CCtrlListBox::GetSelItems() +{ + int count = GetSelCount() + 1; + int *result = (int *)mir_alloc(sizeof(int) * count); + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)result); + result[count-1] = -1; + return result; +} + +int CCtrlListBox::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::ResetContent() +{ SendMessage(m_hwnd, LB_RESETCONTENT, 0, 0); +} + +int CCtrlListBox::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, LB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlListBox::SetCurSel(int index) +{ return SendMessage(m_hwnd, LB_SETCURSEL, index, 0); +} + +void CCtrlListBox::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, LB_SETITEMDATA, index, data); +} + +void CCtrlListBox::SetSel(int index, bool sel) +{ SendMessage(m_hwnd, LB_SETSEL, sel ? TRUE : FALSE, index); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck class + +CCtrlCheck::CCtrlCheck( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCheck::GetState() +{ + return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); +} + +void CCtrlCheck::SetState(int state) +{ + SendMessage(m_hwnd, BM_SETCHECK, state, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit class + +CCtrlEdit::CCtrlEdit( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData class + +CCtrlData::CCtrlData( CDlgBase *wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ), + m_dbLink( NULL ) +{ +} + +void CCtrlData::OnInit() +{ + CCtrlBase::OnInit(); + m_changed = false; +} + +void CCtrlData::NotifyChange() +{ + if (!m_parentWnd || m_parentWnd->IsInitialized()) m_changed = true; + if ( m_parentWnd ) { + m_parentWnd->OnChange(this); + if ( m_parentWnd->IsInitialized()) + ::SendMessage( ::GetParent( m_parentWnd->GetHwnd()), PSM_CHANGED, 0, 0 ); + } + + OnChange(this); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue, bool bSigned ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, type, iValue, bSigned ); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, DBVT_TCHAR, szValue ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlMButton + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( hIcon ), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( LoadSkinnedIcon(iCoreIcon)), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::~CCtrlMButton() +{ + g_ReleaseIcon( m_hIcon ); +} + +void CCtrlMButton::OnInit() +{ + CCtrlButton::OnInit(); + + SendMessage( m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon ); + SendMessage( m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0); + SendMessage( m_hwnd, BUTTONSETASFLATBTN, (WPARAM)m_toolTip, 0); +} + +void CCtrlMButton::MakeFlat() +{ + SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0); +} + +void CCtrlMButton::MakePush() +{ + SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +CCtrlButton::CCtrlButton( CDlgBase* wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ) +{ +} + +BOOL CCtrlButton::OnCommand(HWND, WORD, WORD idCode) +{ + if ( idCode == BN_CLICKED || idCode == STN_CLICKED ) + OnClick(this); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlHyperlink + +CCtrlHyperlink::CCtrlHyperlink( CDlgBase* wnd, int idCtrl, const char* url ) : + CCtrlBase( wnd, idCtrl ), + m_url(url) +{ +} + +BOOL CCtrlHyperlink::OnCommand(HWND, WORD, WORD) +{ + ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +CCtrlClc::CCtrlClc( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh }; + switch (pnmh->code) + { + case CLN_EXPANDED: OnExpanded(&evt); break; + case CLN_LISTREBUILT: OnListRebuilt(&evt); break; + case CLN_ITEMCHECKED: OnItemChecked(&evt); break; + case CLN_DRAGGING: OnDragging(&evt); break; + case CLN_DROPPED: OnDropped(&evt); break; + case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break; + case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break; + case CLN_DRAGSTOP: OnDragStop(&evt); break; + case CLN_NEWCONTACT: OnNewContact(&evt); break; + case CLN_CONTACTMOVED: OnContactMoved(&evt); break; + case CLN_CHECKCHANGED: OnCheckChanged(&evt); break; + case NM_CLICK: OnClick(&evt); break; + } + return FALSE; +} + +void CCtrlClc::AddContact(HANDLE hContact) +{ SendMessage(m_hwnd, CLM_ADDCONTACT, (WPARAM)hContact, 0); +} + +void CCtrlClc::AddGroup(HANDLE hGroup) +{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0); +} + +void CCtrlClc::AutoRebuild() +{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0); +} + +void CCtrlClc::DeleteItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::EditLabel(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0); +} + +void CCtrlClc::EndEditLabel(bool save) +{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0); +} + +void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk) +{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE); +} + +void CCtrlClc::Expand(HANDLE hItem, DWORD flags) +{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags); +} + +HANDLE CCtrlClc::FindContact(HANDLE hContact) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, (WPARAM)hContact, 0); +} + +HANDLE CCtrlClc::FindGroup(HANDLE hGroup) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0); +} + +COLORREF CCtrlClc::GetBkColor() +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0); +} + +bool CCtrlClc::GetCheck(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false; +} + +int CCtrlClc::GetCount() +{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0); +} + +HWND CCtrlClc::GetEditControl() +{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0); +} + +DWORD CCtrlClc::GetExpand(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0); +} + +int CCtrlClc::GetExtraColumns() +{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0); +} + +BYTE CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) +{ return (BYTE)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFF); +} + +HIMAGELIST CCtrlClc::GetExtraImageList() +{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0); +} + +HFONT CCtrlClc::GetFont(int iFontId) +{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0); +} + +HANDLE CCtrlClc::GetSelection() +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0); +} + +HANDLE CCtrlClc::HitTest(int x, int y, DWORD *hitTest) +{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y)); +} + +void CCtrlClc::SelectItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::SetBkBitmap(DWORD mode, HBITMAP hBitmap) +{ SendMessage(m_hwnd, CLM_SETBKBITMAP, mode, (LPARAM)hBitmap); +} + +void CCtrlClc::SetBkColor(COLORREF clBack) +{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0); +} + +void CCtrlClc::SetCheck(HANDLE hItem, bool check) +{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0); +} + +void CCtrlClc::SetExtraColumns(int iColumns) +{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0); +} + +void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); +} + +void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList); +} + +void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw) +{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId)); +} + +void CCtrlClc::SetIndent(int iIndent) +{ SendMessage(m_hwnd, CLM_SETINDENT, (WPARAM)iIndent, 0); +} + +void CCtrlClc::SetItemText(HANDLE hItem, char *szText) +{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText); +} + +void CCtrlClc::SetHideEmptyGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetGreyoutFlags(DWORD flags) +{ SendMessage(m_hwnd, CLM_SETGREYOUTFLAGS, (WPARAM)flags, 0); +} + +bool CCtrlClc::GetHideOfflineRoot() +{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false; +} + +void CCtrlClc::SetHideOfflineRoot(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9); +} + +void CCtrlClc::SetUseGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetOfflineModes(DWORD modes) +{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0); +} + +DWORD CCtrlClc::GetExStyle() +{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0); +} + +void CCtrlClc::SetExStyle(DWORD exStyle) +{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0); +} + +int CCtrlClc::GetLefrMargin() +{ return SendMessage(m_hwnd, CLM_GETLEFTMARGIN, 0, 0); +} + +void CCtrlClc::SetLeftMargin(int iMargin) +{ SendMessage(m_hwnd, CLM_SETLEFTMARGIN, (WPARAM)iMargin, 0); +} + +HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii) +{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii); +} + +int CCtrlClc::GetItemType(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0); +} + +HANDLE CCtrlClc::GetNextItem(HANDLE hItem, DWORD flags) +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem); +} + +COLORREF CCtrlClc::GetTextColot(int iFontId) +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETTEXTCOLOR, (WPARAM)iFontId, 0); +} + +void CCtrlClc::SetTextColor(int iFontId, COLORREF clText) +{ SendMessage(m_hwnd, CLM_SETTEXTCOLOR, (WPARAM)iFontId, (LPARAM)clText); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +CCtrlListView::CCtrlListView( CDlgBase* dlg, int ctrlId ) : + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) { + case NM_DBLCLK: OnDoubleClick(&evt); return TRUE; + case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE; + case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE; + case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE; + case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE; + case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE; + //case LVN_INCREMENTALSEARCH: OnIncrementalSearch(&evt); return TRUE; + case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE; + case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE; + case LVN_ITEMCHANGED: OnItemChanged(&evt); return TRUE; + case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE; + case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE; + case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + } + + return FALSE; +} + +// additional api +HIMAGELIST CCtrlListView::CreateImageList(int iImageList) +{ + HIMAGELIST hIml; + if (hIml = GetImageList(iImageList)) + return hIml; + + hIml = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32|ILC_MASK : ILC_COLOR16|ILC_MASK, 0, 1); + SetImageList(hIml, iImageList); + return hIml; +} + +void CCtrlListView::AddColumn(int iSubItem, TCHAR *name, int cx) +{ + LVCOLUMN lvc; + lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; + lvc.iImage = 0; + lvc.pszText = name; + lvc.cx = cx; + lvc.iSubItem = iSubItem; + InsertColumn(iSubItem, &lvc); +} + +void CCtrlListView::AddGroup(int iGroupId, TCHAR *name) +{ + if (IsWinVerXPPlus()) + { + LVGROUP lvg = {0}; + lvg.cbSize = sizeof(lvg); + lvg.mask = LVGF_HEADER|LVGF_GROUPID; + lvg.pszHeader = name; + lvg.cchHeader = lstrlen(lvg.pszHeader); + lvg.iGroupId = iGroupId; + InsertGroup(-1, &lvg); + } +} + +int CCtrlListView::AddItem(TCHAR *text, int iIcon, LPARAM lParam, int iGroupId) +{ + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM|LVIF_TEXT|LVIF_IMAGE; + lvi.iSubItem = 0; + lvi.pszText = text; + lvi.iImage = iIcon; + lvi.lParam = lParam; + + + if ((iGroupId >= 0) && IsWinVerXPPlus()) + { + lvi.mask |= LVIF_GROUPID; + lvi.iGroupId = iGroupId; + } + + + return InsertItem(&lvi); +} + +void CCtrlListView::SetItem(int iItem, int iSubItem, TCHAR *text, int iIcon) +{ + LVITEM lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = iItem; + lvi.iSubItem = iSubItem; + lvi.pszText = text; + + if (iIcon >= 0) + { + lvi.mask |= LVIF_IMAGE; + lvi.iImage = iIcon; + } + + SetItem(&lvi); +} + +LPARAM CCtrlListView::GetItemData(int iItem) +{ + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = iItem; + GetItem(&lvi); + return lvi.lParam; +} + +// classic api +DWORD CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount) +{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount); +} +void CCtrlListView::Arrange(UINT code) +{ ListView_Arrange(m_hwnd, code); +} +void CCtrlListView::CancelEditLabel() +{ ListView_CancelEditLabel(m_hwnd); +} +HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft) +{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft); +} +void CCtrlListView::DeleteAllItems() +{ ListView_DeleteAllItems(m_hwnd); +} +void CCtrlListView::DeleteColumn(int iCol) +{ ListView_DeleteColumn(m_hwnd, iCol); +} +void CCtrlListView::DeleteItem(int iItem) +{ ListView_DeleteItem(m_hwnd, iItem); +} +HWND CCtrlListView::EditLabel(int iItem) +{ return ListView_EditLabel(m_hwnd, iItem); +} +int CCtrlListView::EnableGroupView(BOOL fEnable) +{ return ListView_EnableGroupView(m_hwnd, fEnable); +} +BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK) +{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK); +} +int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi) +{ return ListView_FindItem(m_hwnd, iStart, plvfi); +} +COLORREF CCtrlListView::GetBkColor() +{ return ListView_GetBkColor(m_hwnd); +} +void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) +{ ListView_GetBkImage(m_hwnd, plvbki); +} +UINT CCtrlListView::GetCallbackMask() +{ return ListView_GetCallbackMask(m_hwnd); +} +BOOL CCtrlListView::GetCheckState(UINT iIndex) +{ return ListView_GetCheckState(m_hwnd, iIndex); +} +void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) +{ ListView_GetColumn(m_hwnd, iCol, pcol); +} +void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) +{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +int CCtrlListView::GetColumnWidth(int iCol) +{ return ListView_GetColumnWidth(m_hwnd, iCol); +} +int CCtrlListView::GetCountPerPage() +{ return ListView_GetCountPerPage(m_hwnd); +} +HWND CCtrlListView::GetEditControl() +{ return ListView_GetEditControl(m_hwnd); +} +//void CCtrlListView::GetEmptyText(PWSTR pszText, UINT cchText) +//{ ListView_GetEmptyText(m_hwnd, pszText, cchText); +//} +DWORD CCtrlListView::GetExtendedListViewStyle() +{ return ListView_GetExtendedListViewStyle(m_hwnd); +} +//INT CCtrlListView::GetFocusedGroup() +//{ return ListView_GetFocusedGroup(m_hwnd); +//} +//void CCtrlListView::GetFooterInfo(LPLVFOOTERINFO plvfi) +//{ ListView_GetFooterInfo(m_hwnd, plvfi); +//} +//void CCtrlListView::GetFooterItem(UINT iItem, LVFOOTERITEM *pfi) +//{ ListView_GetFooterItem(m_hwnd, iItem, pfi); +//} +//void CCtrlListView::GetFooterItemRect(UINT iItem, RECT *prc) +//{ ListView_GetFooterItemRect(m_hwnd, iItem, prc); +//} +//void CCtrlListView::GetFooterRect(RECT *prc) +//{ ListView_GetFooterRect(m_hwnd, prc); +//} +//int CCtrlListView::GetGroupCount() +//{ return ListView_GetGroupCount(m_hwnd); +//} +//HIMAGELIST CCtrlListView::GetGroupHeaderImageList() +//{ return ListView_GetGroupHeaderImageList(m_hwnd); +//} +//void CCtrlListView::GetGroupInfo(int iGroupId, PLVGROUP pgrp) +//{ ListView_GetGroupInfo(m_hwnd, iGroupId, pgrp); +//} +//void CCtrlListView::GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) +//{ ListView_GetGroupInfoByIndex(m_hwnd, iIndex, pgrp); +//} +void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) +{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics); +} +//BOOL CCtrlListView::GetGroupRect(int iGroupId, RECT *prc) +//{ return ListView_GetGroupRect(m_hwnd, iGroupId, prc); +//} +//UINT CCtrlListView::GetGroupState(UINT dwGroupId, UINT dwMask) +//{ return ListView_GetGroupState(m_hwnd, dwGroupId, dwMask); +//} +HWND CCtrlListView::GetHeader() +{ return ListView_GetHeader(m_hwnd); +} +HCURSOR CCtrlListView::GetHotCursor() +{ return ListView_GetHotCursor(m_hwnd); +} +INT CCtrlListView::GetHotItem() +{ return ListView_GetHotItem(m_hwnd); +} +DWORD CCtrlListView::GetHoverTime() +{ return ListView_GetHoverTime(m_hwnd); +} +HIMAGELIST CCtrlListView::GetImageList(int iImageList) +{ return ListView_GetImageList(m_hwnd, iImageList); +} +BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) +{ return ListView_GetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::GetInsertMarkColor() +{ return ListView_GetInsertMarkColor(m_hwnd); +} +int CCtrlListView::GetInsertMarkRect(LPRECT prc) +{ return ListView_GetInsertMarkRect(m_hwnd, prc); +} +BOOL CCtrlListView::GetISearchString(LPSTR lpsz) +{ return ListView_GetISearchString(m_hwnd, lpsz); +} +void CCtrlListView::GetItem(LPLVITEM pitem) +{ ListView_GetItem(m_hwnd, pitem); +} +int CCtrlListView::GetItemCount() +{ return ListView_GetItemCount(m_hwnd); +} +//void CCtrlListView::GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc) +//{ ListView_GetItemIndexRect(m_hwnd, plvii, iSubItem, code, prc); +//} +void CCtrlListView::GetItemPosition(int i, POINT *ppt) +{ ListView_GetItemPosition(m_hwnd, i, ppt); +} +void CCtrlListView::GetItemRect(int i, RECT *prc, int code) +{ ListView_GetItemRect(m_hwnd, i, prc, code); +} +DWORD CCtrlListView::GetItemSpacing(BOOL fSmall) +{ return ListView_GetItemSpacing(m_hwnd, fSmall); +} +UINT CCtrlListView::GetItemState(int i, UINT mask) +{ return ListView_GetItemState(m_hwnd, i, mask); +} +void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) +{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax); +} +int CCtrlListView::GetNextItem(int iStart, UINT flags) +{ return ListView_GetNextItem(m_hwnd, iStart, flags); +} +//BOOL CCtrlListView::GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags) +//{ return ListView_GetNextItemIndex(m_hwnd, plvii, flags); +//} +BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) +{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas); +} +BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) +{ return ListView_GetOrigin(m_hwnd, lpptOrg); +} +COLORREF CCtrlListView::GetOutlineColor() +{ return ListView_GetOutlineColor(m_hwnd); +} +UINT CCtrlListView::GetSelectedColumn() +{ return ListView_GetSelectedColumn(m_hwnd); +} +UINT CCtrlListView::GetSelectedCount() +{ return ListView_GetSelectedCount(m_hwnd); +} +INT CCtrlListView::GetSelectionMark() +{ return ListView_GetSelectionMark(m_hwnd); +} +int CCtrlListView::GetStringWidth(LPCSTR psz) +{ return ListView_GetStringWidth(m_hwnd, psz); +} +BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) +{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect); +} +COLORREF CCtrlListView::GetTextBkColor() +{ return ListView_GetTextBkColor(m_hwnd); +} +COLORREF CCtrlListView::GetTextColor() +{ return ListView_GetTextColor(m_hwnd); +} +void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) +{ ListView_GetTileInfo(m_hwnd, plvtinfo); +} +void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::GetToolTips() +{ return ListView_GetToolTips(m_hwnd); +} +int CCtrlListView::GetTopIndex() +{ return ListView_GetTopIndex(m_hwnd); +} +BOOL CCtrlListView::GetUnicodeFormat() +{ return ListView_GetUnicodeFormat(m_hwnd); +} +DWORD CCtrlListView::GetView() +{ return ListView_GetView(m_hwnd); +} +BOOL CCtrlListView::GetViewRect(RECT *prc) +{ return ListView_GetViewRect(m_hwnd, prc); +} +void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +BOOL CCtrlListView::HasGroup(int dwGroupId) +{ return ListView_HasGroup(m_hwnd, dwGroupId); +} +int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) +{ return ListView_HitTest(m_hwnd, pinfo); +} +//int CCtrlListView::HitTestEx(LPLVHITTESTINFO pinfo) +//{ return ListView_HitTestEx(m_hwnd, pinfo); +//} +int CCtrlListView::InsertColumn(int iCol, const LPLVCOLUMN pcol) +{ return ListView_InsertColumn(m_hwnd, iCol, pcol); +} +int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp) +{ return ListView_InsertGroup(m_hwnd, index, pgrp); +} +void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert) +{ ListView_InsertGroupSorted(m_hwnd, structInsert); +} +int CCtrlListView::InsertItem(const LPLVITEM pitem) +{ return ListView_InsertItem(m_hwnd, pitem); +} +BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim) +{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim); +} +BOOL CCtrlListView::IsGroupViewEnabled() +{ return ListView_IsGroupViewEnabled(m_hwnd); +} +//UINT CCtrlListView::IsItemVisible(UINT index) +//{ return ListView_IsItemVisible(m_hwnd, index); +//} +UINT CCtrlListView::MapIDToIndex(UINT id) +{ return ListView_MapIDToIndex(m_hwnd, id); +} +UINT CCtrlListView::MapIndexToID(UINT index) +{ return ListView_MapIndexToID(m_hwnd, index); +} +BOOL CCtrlListView::RedrawItems(int iFirst, int iLast) +{ return ListView_RedrawItems(m_hwnd, iFirst, iLast); +} +void CCtrlListView::RemoveAllGroups() +{ ListView_RemoveAllGroups(m_hwnd); +} +int CCtrlListView::RemoveGroup(int iGroupId) +{ return ListView_RemoveGroup(m_hwnd, iGroupId); +} +BOOL CCtrlListView::Scroll(int dx, int dy) +{ return ListView_Scroll(m_hwnd, dx, dy); +} +BOOL CCtrlListView::SetBkColor(COLORREF clrBk) +{ return ListView_SetBkColor(m_hwnd, clrBk); +} +BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki) +{ return ListView_SetBkImage(m_hwnd, plvbki); +} +BOOL CCtrlListView::SetCallbackMask(UINT mask) +{ return ListView_SetCallbackMask(m_hwnd, mask); +} +void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck) +{ ListView_SetCheckState(m_hwnd, iIndex, fCheck); +} +BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol) +{ return ListView_SetColumn(m_hwnd, iCol, pcol); +} +BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray) +{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +BOOL CCtrlListView::SetColumnWidth(int iCol, int cx) +{ return ListView_SetColumnWidth(m_hwnd, iCol, cx); +} +void CCtrlListView::SetExtendedListViewStyle(DWORD dwExStyle) +{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle); +} +void CCtrlListView::SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle) +{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle); +} +//HIMAGELIST CCtrlListView::SetGroupHeaderImageList(HIMAGELIST himl) +//{ return ListView_SetGroupHeaderImageList(m_hwnd, himl); +//} +int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp) +{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp); +} +void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) +{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics); +} +//void CCtrlListView::SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState) +//{ ListView_SetGroupState(m_hwnd, dwGroupId, dwMask, dwState); +//} +HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor) +{ return ListView_SetHotCursor(m_hwnd, hCursor); +} +INT CCtrlListView::SetHotItem(INT iIndex) +{ return ListView_SetHotItem(m_hwnd, iIndex); +} +void CCtrlListView::SetHoverTime(DWORD dwHoverTime) +{ ListView_SetHoverTime(m_hwnd, dwHoverTime); +} +DWORD CCtrlListView::SetIconSpacing(int cx, int cy) +{ return ListView_SetIconSpacing(m_hwnd, cx, cy); +} +HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList) +{ return ListView_SetImageList(m_hwnd, himl, iImageList); +} +BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip) +{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip); +} +BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim) +{ return ListView_SetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color) +{ return ListView_SetInsertMarkColor(m_hwnd, color); +} +BOOL CCtrlListView::SetItem(const LPLVITEM pitem) +{ return ListView_SetItem(m_hwnd, pitem); +} +void CCtrlListView::SetItemCount(int cItems) +{ ListView_SetItemCount(m_hwnd, cItems); +} +void CCtrlListView::SetItemCountEx(int cItems, DWORD dwFlags) +{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags); +} +//HRESULT CCtrlListView::SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask) +//{ return ListView_SetItemIndexState(m_hwnd, plvii, data, mask); +//} +BOOL CCtrlListView::SetItemPosition(int i, int x, int y) +{ return ListView_SetItemPosition(m_hwnd, i, x, y); +} +void CCtrlListView::SetItemPosition32(int iItem, int x, int y) +{ ListView_SetItemPosition32(m_hwnd, iItem, x, y); +} +void CCtrlListView::SetItemState(int i, UINT state, UINT mask) +{ ListView_SetItemState(m_hwnd, i, state, mask); +} +void CCtrlListView::SetItemText(int i, int iSubItem, TCHAR *pszText) +{ ListView_SetItemText(m_hwnd, i, iSubItem, pszText); +} +COLORREF CCtrlListView::SetOutlineColor(COLORREF color) +{ return ListView_SetOutlineColor(m_hwnd, color); +} +void CCtrlListView::SetSelectedColumn(int iCol) +{ ListView_SetSelectedColumn(m_hwnd, iCol); +} +INT CCtrlListView::SetSelectionMark(INT iIndex) +{ return ListView_SetSelectionMark(m_hwnd, iIndex); +} +BOOL CCtrlListView::SetTextBkColor(COLORREF clrText) +{ return ListView_SetTextBkColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTextColor(COLORREF clrText) +{ return ListView_SetTextColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo) +{ return ListView_SetTileInfo(m_hwnd, plvtinfo); +} +BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::SetToolTips(HWND ToolTip) +{ return ListView_SetToolTips(m_hwnd, ToolTip); +} +BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode) +{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode); +} +int CCtrlListView::SetView(DWORD iView) +{ return ListView_SetView(m_hwnd, iView); +} +void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv) +{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv); +} +BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort); +} +BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort); +} +INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) +{ return ListView_SubItemHitTest(m_hwnd, pInfo); +} +//INT CCtrlListView::SubItemHitTestEx(LPLVHITTESTINFO plvhti) +//{ return ListView_SubItemHitTestEx(m_hwnd, plvhti); +//} +BOOL CCtrlListView::Update(int iItem) +{ return ListView_Update(m_hwnd, iItem); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlFilterListView + +#define FILTER_BOX_HEIGHT 21 + +struct CFilterData : public MZeroedObject +{ + HFONT m_hfntNormal; + HFONT m_hfntEmpty; + COLORREF m_clGray; + TCHAR *m_filterText; + + RECT m_rcButtonClear; + RECT m_rcEditBox; + + WNDPROC m_oldWndProc; + HWND m_hwndOwner; + HWND m_hwndEditBox; + + void ReleaseFilterData() + { + //DeleteObject(m_hfntNormal); m_hfntNormal = NULL; // managed by system + DeleteObject(m_hfntEmpty); m_hfntEmpty = NULL; + } + + ~CFilterData() + { + ReleaseFilterData(); + } +}; + +CCtrlFilterListView::CCtrlFilterListView(CDlgBase* dlg, int ctrlId, bool trackFilter, bool keepHiglight): + CCtrlListView(dlg, ctrlId), + m_trackFilter(trackFilter), + m_keepHiglight(keepHiglight) +{ + fdat = new CFilterData; +} + +CCtrlFilterListView::~CCtrlFilterListView() +{ + if (fdat->m_filterText) mir_free(fdat->m_filterText); + delete fdat; +} + +TCHAR *CCtrlFilterListView::GetFilterText() +{ + return fdat->m_filterText; +} + +void CCtrlFilterListView::OnInit() +{ + CSuper::OnInit(); + Subclass(); +} + +static LRESULT CALLBACK sttEditBoxSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CFilterData *fdat = (CFilterData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!fdat) return DefWindowProc(hwnd, msg, wParam, lParam); + + switch (msg) + { + case WM_GETDLGCODE: + if ((wParam == VK_RETURN) || (wParam == VK_ESCAPE)) + return DLGC_WANTMESSAGE; + break; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + if (wParam == VK_RETURN) + { + if (fdat->m_filterText) mir_free(fdat->m_filterText); + int length = GetWindowTextLength(hwnd) + 1; + if (length == 1) + { + fdat->m_filterText = 0; + } else + { + fdat->m_filterText = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); + GetWindowText(hwnd, fdat->m_filterText, length); + } + + DestroyWindow(hwnd); + RedrawWindow(fdat->m_hwndOwner, NULL, NULL, RDW_INVALIDATE|RDW_FRAME); + PostMessage(fdat->m_hwndOwner, WM_APP, 0, 0); + } else + if (wParam == VK_ESCAPE) + { + DestroyWindow(hwnd); + return 0; + } else + { + PostMessage(fdat->m_hwndOwner, WM_APP, 1, 0); + } + + break; + } + + case WM_KILLFOCUS: + { + DestroyWindow(hwnd); + return 0; + } + + case WM_DESTROY: + { + fdat->m_hwndEditBox = NULL; + } + } + + return CallWindowProc(fdat->m_oldWndProc, hwnd, msg, wParam, lParam); +} + +void CCtrlFilterListView::FilterHighlight(TCHAR *str) +{ + TCHAR buf[256]; + int count = GetItemCount(); + for (int i = 0; i < count; ++i) + { + bool found = false; + + if (str) + { + for (int j = 0; j < 10; ++j) + { + GetItemText(i, j, buf, SIZEOF(buf)); + if (!*buf) + break; + + if (_tcsstr(buf, str)) + { + found = true; + break; + } + } + } + + SetItemState(i, found ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED); + } +} + +LRESULT CCtrlFilterListView::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_APP: + { + switch (wParam) + { + case 0: + { + OnFilterChanged(this); + if (!m_keepHiglight) FilterHighlight(NULL); + break; + } + + case 1: + { + if (m_trackFilter && fdat->m_hwndEditBox) + { + TCHAR *str = 0; + int length = GetWindowTextLength(fdat->m_hwndEditBox) + 1; + if (length == 1) + { + str = 0; + } else + { + str = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); + GetWindowText(fdat->m_hwndEditBox, str, length); + } + FilterHighlight(str); + if (str) mir_free(str); + } + break; + } + + case 2: + { + fdat->m_hwndOwner = m_hwnd; + fdat->m_hwndEditBox = CreateWindow(_T("edit"), fdat->m_filterText, + WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, + 0, 0, 0, 0, + ::GetParent(m_hwnd), (HMENU)-1, hInst, NULL); + + SendMessage(fdat->m_hwndEditBox, WM_SETFONT, (WPARAM)fdat->m_hfntNormal, 0); + + RECT rc = fdat->m_rcEditBox; + MapWindowPoints(m_hwnd, ::GetParent(m_hwnd), (LPPOINT)&rc, 2); + SetWindowPos(fdat->m_hwndEditBox, HWND_TOP, rc.left-5, rc.top+2, rc.right-rc.left, rc.bottom-rc.top-4, SWP_SHOWWINDOW); + SendMessage(fdat->m_hwndEditBox, EM_SETSEL, 0, -1); + + fdat->m_oldWndProc = (WNDPROC)GetWindowLongPtr(fdat->m_hwndEditBox, GWLP_WNDPROC); + SetWindowLongPtr(fdat->m_hwndEditBox, GWLP_USERDATA, (LONG_PTR)fdat); + SetWindowLongPtr(fdat->m_hwndEditBox, GWLP_WNDPROC, (LONG_PTR)sttEditBoxSubclassProc); + + SetFocus(m_hwnd); // hack to avoid popping of list over the box... + SetFocus(fdat->m_hwndEditBox); + break; + } + } + break; + } + + case WM_NCCALCSIZE: + { + RECT *prect = (RECT *)lParam; + + CSuper::CustomWndProc(msg, wParam, lParam); + prect->bottom -= FILTER_BOX_HEIGHT; + + fdat->ReleaseFilterData(); + + fdat->m_hfntNormal = (HFONT)SendMessage(m_hwnd, WM_GETFONT, 0, 0); + if (!fdat->m_hfntNormal) fdat->m_hfntNormal = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + + LOGFONT lf; + GetObject(fdat->m_hfntNormal, sizeof(lf), &lf); + lf.lfItalic = TRUE; + fdat->m_hfntEmpty = CreateFontIndirect(&lf); + + COLORREF clText = GetSysColor(COLOR_WINDOWTEXT); + COLORREF clBack = GetSysColor(COLOR_WINDOW); + fdat->m_clGray = RGB( + (GetRValue(clBack) + 2*GetRValue(clText)) / 3, + (GetGValue(clBack) + 2*GetGValue(clText)) / 3, + (GetBValue(clBack) + 2*GetBValue(clText)) / 3 + ); + + if (fdat->m_hwndEditBox) DestroyWindow(fdat->m_hwndEditBox); + + return 0; + } + + case WM_NCPAINT: + { +/* + { + HRGN hrgnUpdate, hrgnTmp; + RECT rc; + GetWindowRect(m_hwnd, &rc); + OffsetRect(&rc, -rc.left, -rc.top); + + RECT rcClient; + GetClientRect(m_hwnd, &rcClient); + + hrgnTmp = CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + if (wParam == 1) + { + hrgnUpdate = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); + CombineRgn(hrgnUpdate, hrgnUpdate, hrgnTmp, RGN_DIFF); + } else + { + hrgnUpdate = CreateRectRgn(0, 0, 0, 0); + CombineRgn(hrgnUpdate, (HRGN)wParam, hrgnTmp, RGN_DIFF); + } + DeleteObject(hrgnTmp); + + InflateRect(&rc, -1, -1); + rc.top = rc.bottom - FILTER_BOX_HEIGHT; + hrgnTmp = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); + CombineRgn(hrgnUpdate, hrgnUpdate, hrgnTmp, RGN_DIFF); + DeleteObject(hrgnTmp); + + CSuper::CustomWndProc(msg, (WPARAM)hrgnUpdate, lParam); + DeleteObject(hrgnUpdate); + } +*/ + CSuper::CustomWndProc(msg, wParam, lParam); + + RECT rc; + GetWindowRect(m_hwnd, &rc); + OffsetRect(&rc, -rc.left, -rc.top); + InflateRect(&rc, -1, -1); + rc.top = rc.bottom - FILTER_BOX_HEIGHT; + + POINT pts[] = { + {rc.left, rc.top}, + {rc.left+FILTER_BOX_HEIGHT, rc.top}, + {rc.left+FILTER_BOX_HEIGHT+FILTER_BOX_HEIGHT/2+1, rc.top+FILTER_BOX_HEIGHT/2+1}, + {rc.left+FILTER_BOX_HEIGHT, rc.top+FILTER_BOX_HEIGHT}, + {rc.left, rc.top+FILTER_BOX_HEIGHT}, + }; + HRGN hrgnFilter = CreatePolygonRgn(pts, SIZEOF(pts), ALTERNATE); + + HDC hdc = GetWindowDC(m_hwnd); + + FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW)); + FillRgn(hdc, hrgnFilter, GetSysColorBrush(COLOR_BTNFACE)); + + SetBkMode(hdc, TRANSPARENT); + + if (fdat->m_filterText) + { + SetRect(&fdat->m_rcButtonClear, + rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, + rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2 + 16, rc.top + (FILTER_BOX_HEIGHT-16)/2 + 16); + + DrawIconEx(hdc, rc.left + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, g_LoadIconEx("sd_filter_apply"), 16, 16, 0, NULL, DI_NORMAL); + DrawIconEx(hdc, rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, LoadSkinnedIcon(SKINICON_OTHER_DELETE), 16, 16, 0, NULL, DI_NORMAL); + + rc.left += 5*FILTER_BOX_HEIGHT/3; + rc.right -= 5*FILTER_BOX_HEIGHT/3; + + fdat->m_rcEditBox = rc; + + SelectObject(hdc, fdat->m_hfntNormal); + ::SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + DrawText(hdc, fdat->m_filterText, -1, &rc, DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS); + } else + { + SetRect(&fdat->m_rcButtonClear, 0, 0, 0, 0); + + DrawIconEx(hdc, rc.left + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, g_LoadIconEx("sd_filter_reset"), 16, 16, 0, NULL, DI_NORMAL); + + rc.left += 5*FILTER_BOX_HEIGHT/3; + rc.right -= 5; + + fdat->m_rcEditBox = rc; + + SelectObject(hdc, fdat->m_hfntEmpty); + ::SetTextColor(hdc, fdat->m_clGray); + DrawText(hdc, TranslateT("Set filter..."), -1, &rc, DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS); + } + + ReleaseDC(m_hwnd, hdc); + + DeleteObject(hrgnFilter); + + return 0; + } + + case WM_NCHITTEST: + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + MapWindowPoints(NULL, m_hwnd, &pt, 1); + + if(PtInRect(&fdat->m_rcButtonClear, pt)) + return HTBORDER; + if(PtInRect(&fdat->m_rcEditBox, pt)) + return HTBORDER; + + break; + } + + case WM_NCLBUTTONUP: + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + MapWindowPoints(NULL, m_hwnd, &pt, 1); + + if(PtInRect(&fdat->m_rcButtonClear, pt)) + { + SetFocus(m_hwnd); + if (fdat->m_filterText) mir_free(fdat->m_filterText); + fdat->m_filterText = NULL; + RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME); + OnFilterChanged(this); + FilterHighlight(NULL); + } else + if(PtInRect(&fdat->m_rcEditBox, pt)) + { + PostMessage(m_hwnd, WM_APP, 2, 0); + } + + break; + } + + case WM_KEYDOWN: + { + if (wParam == 'F' && GetAsyncKeyState(VK_CONTROL)) + PostMessage(m_hwnd, WM_APP, 2, 0); + break; + } + } + + return CSuper::CustomWndProc(msg, wParam, lParam); +} +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +CCtrlTreeView::CCtrlTreeView( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) + { + case TVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; + case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; + case TVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; + case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; + case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; + } + + return FALSE; +} + +void CCtrlTreeView::TranslateItem(HTREEITEM hItem) +{ + TCHAR buf[128]; + TVITEMEX tvi; + + GetItem(hItem, &tvi, buf, SIZEOF(buf)); + tvi.pszText = TranslateTS(tvi.pszText); + tvi.cchTextMax = lstrlen(tvi.pszText); + SetItem(&tvi); +} + +void CCtrlTreeView::TranslateTree() +{ + HTREEITEM hItem = GetRoot(); + while (hItem) + { + TranslateItem(hItem); + + HTREEITEM hItemTmp = 0; + if (hItemTmp = GetChild(hItem)) + hItem = hItemTmp; + else if (hItemTmp = GetNextSibling(hItem)) + hItem = hItemTmp; + else + { + while (1) + { + if (!(hItem = GetParent(hItem))) break; + if (hItemTmp = GetNextSibling(hItem)) + { + hItem = hItemTmp; + break; + } + } + } + } +} + +HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const TCHAR *name) +{ + TVITEMEX tvi = {0}; + TCHAR str[MAX_PATH]; + + if (hItem) + tvi.hItem = GetChild(hItem); + else + tvi.hItem = GetRoot(); + + if (!name) + return tvi.hItem; + + tvi.mask = TVIF_TEXT; + tvi.pszText = str; + tvi.cchTextMax = SIZEOF(str); + + while (tvi.hItem) + { + GetItem(&tvi); + + if (!lstrcmp(tvi.pszText, name)) + return tvi.hItem; + + tvi.hItem = GetNextSibling(tvi.hItem); + } + return NULL; +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE; + tvi->hItem = hItem; + GetItem(tvi); +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT; + tvi->hItem = hItem; + tvi->pszText = szText; + tvi->cchTextMax = iTextLength; + GetItem(tvi); +} + +HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) +{ return TreeView_CreateDragImage(m_hwnd, hItem); +} + +void CCtrlTreeView::DeleteAllItems() +{ TreeView_DeleteAllItems(m_hwnd); +} + +void CCtrlTreeView::DeleteItem(HTREEITEM hItem) +{ TreeView_DeleteItem(m_hwnd, hItem); +} + +HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) +{ return TreeView_EditLabel(m_hwnd, hItem); +} + +void CCtrlTreeView::EndEditLabelNow(BOOL cancel) +{ TreeView_EndEditLabelNow(m_hwnd, cancel); +} + +void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) +{ TreeView_EnsureVisible(m_hwnd, hItem); +} + +void CCtrlTreeView::Expand(HTREEITEM hItem, DWORD flag) +{ TreeView_Expand(m_hwnd, hItem, flag); +} + +COLORREF CCtrlTreeView::GetBkColor() +{ return TreeView_GetBkColor(m_hwnd); +} + +DWORD CCtrlTreeView::GetCheckState(HTREEITEM hItem) +{ return TreeView_GetCheckState(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) +{ return TreeView_GetChild(m_hwnd, hItem); +} + +int CCtrlTreeView::GetCount() +{ return TreeView_GetCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetDropHilight() +{ return TreeView_GetDropHilight(m_hwnd); +} + +HWND CCtrlTreeView::GetEditControl() +{ return TreeView_GetEditControl(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetFirstVisible() +{ return TreeView_GetFirstVisible(m_hwnd); +} + +HIMAGELIST CCtrlTreeView::GetImageList(int iImage) +{ return TreeView_GetImageList(m_hwnd, iImage); +} + +int CCtrlTreeView::GetIndent() +{ return TreeView_GetIndent(m_hwnd); +} + +COLORREF CCtrlTreeView::GetInsertMarkColor() +{ return TreeView_GetInsertMarkColor(m_hwnd); +} + +void CCtrlTreeView::GetItem(TVITEMEX *tvi) +{ TreeView_GetItem(m_hwnd, tvi); +} + +int CCtrlTreeView::GetItemHeight() +{ return TreeView_GetItemHeight(m_hwnd); +} + +void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) +{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); +} + +DWORD CCtrlTreeView::GetItemState(HTREEITEM hItem, DWORD stateMask) +{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); +} + +HTREEITEM CCtrlTreeView::GetLastVisible() +{ return TreeView_GetLastVisible(m_hwnd); +} + +COLORREF CCtrlTreeView::GetLineColor() +{ return TreeView_GetLineColor(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, DWORD flag) +{ return TreeView_GetNextItem(m_hwnd, hItem, flag); +} + +HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) +{ return TreeView_GetNextSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) +{ return TreeView_GetNextVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) +{ return TreeView_GetParent(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) +{ return TreeView_GetPrevSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) +{ return TreeView_GetPrevVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetRoot() +{ return TreeView_GetRoot(m_hwnd); +} + +DWORD CCtrlTreeView::GetScrollTime() +{ return TreeView_GetScrollTime(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetSelection() +{ return TreeView_GetSelection(m_hwnd); +} + +COLORREF CCtrlTreeView::GetTextColor() +{ return TreeView_GetTextColor(m_hwnd); +} + +HWND CCtrlTreeView::GetToolTips() +{ return TreeView_GetToolTips(m_hwnd); +} + +BOOL CCtrlTreeView::GetUnicodeFormat() +{ return TreeView_GetUnicodeFormat(m_hwnd); +} + +unsigned CCtrlTreeView::GetVisibleCount() +{ return TreeView_GetVisibleCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) +{ return TreeView_HitTest(m_hwnd, hti); +} + +HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) +{ return TreeView_InsertItem(m_hwnd, tvis); +} + +/* +HTREEITEM CCtrlTreeView::MapAccIDToHTREEITEM(UINT id) +{ return TreeView_MapAccIDToHTREEITEM(m_hwnd, id); +} + +UINT CCtrlTreeView::MapHTREEITEMtoAccID(HTREEITEM hItem) +{ return TreeView_MapHTREEITEMtoAccID(m_hwnd, hItem); +} + +*/ +void CCtrlTreeView::Select(HTREEITEM hItem, DWORD flag) +{ TreeView_Select(m_hwnd, hItem, flag); +} + +void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) +{ TreeView_SelectDropTarget(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectItem(HTREEITEM hItem) +{ TreeView_SelectItem(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) +{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); +} + +COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) +{ return TreeView_SetBkColor(m_hwnd, clBack); +} + +void CCtrlTreeView::SetCheckState(HTREEITEM hItem, DWORD state) +{ TreeView_SetCheckState(m_hwnd, hItem, state); +} + +void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) +{ TreeView_SetImageList(m_hwnd, hIml, iImage); +} + +void CCtrlTreeView::SetIndent(int iIndent) +{ TreeView_SetIndent(m_hwnd, iIndent); +} + +void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) +{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); +} + +COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) +{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); +} + +void CCtrlTreeView::SetItem(TVITEMEX *tvi) +{ TreeView_SetItem(m_hwnd, tvi); +} + +void CCtrlTreeView::SetItemHeight(short cyItem) +{ TreeView_SetItemHeight(m_hwnd, cyItem); +} + +void CCtrlTreeView::SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask) +{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); +} + +COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) +{ return TreeView_SetLineColor(m_hwnd, clLine); +} + +void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) +{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); +} + +COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) +{ return TreeView_SetTextColor(m_hwnd, clText); +} + +HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) +{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); +} + +BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) +{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); +} + +void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) +{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); +} + +void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) +{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlPages + +CCtrlPages::CCtrlPages( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId), m_hIml(NULL), m_pActivePage(NULL) +{ +} + +void CCtrlPages::OnInit() +{ + CSuper::OnInit(); + Subclass(); +} + +LRESULT CCtrlPages::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_SIZE) + { + ShowPage(m_pActivePage); + } + + return CSuper::CustomWndProc(msg, wParam, lParam); +} + +void CCtrlPages::AddPage( TCHAR *ptszName, HICON hIcon, CCallback<void> onCreate, void *param ) +{ + TPageInfo *info = new TPageInfo; + info->m_onCreate = onCreate; + info->m_param = param; + info->m_pDlg = NULL; + + TCITEM tci = {0}; + tci.mask = TCIF_PARAM|TCIF_TEXT; + tci.lParam = (LPARAM)info; + tci.pszText = ptszName; + if (hIcon) + { + if (!m_hIml) + { + m_hIml = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32|ILC_MASK : ILC_COLOR16|ILC_MASK, 0, 1); + TabCtrl_SetImageList(m_hwnd, m_hIml); + } + + tci.mask |= TCIF_IMAGE; + tci.iImage = ImageList_AddIcon(m_hIml, hIcon); + } + + TabCtrl_InsertItem(m_hwnd, TabCtrl_GetItemCount(m_hwnd), &tci); +} + +void CCtrlPages::AttachDialog( int iPage, CDlgBase *pDlg ) +{ + if ((iPage < 0) || (iPage >= TabCtrl_GetItemCount(m_hwnd))) + return; + + TCITEM tci = {0}; + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(m_hwnd, iPage, &tci); + + if (TPageInfo *info = (TPageInfo *)tci.lParam) + { + if (info->m_pDlg) + info->m_pDlg->Close(); + + info->m_pDlg = pDlg; + //SetParent(info->m_pDlg->GetHwnd(), m_hwnd); + + if (iPage == TabCtrl_GetCurSel(m_hwnd)) + { + m_pActivePage = info->m_pDlg; + ShowPage(info->m_pDlg); + } + } +} + +void CCtrlPages::ShowPage(CDlgBase *pDlg) +{ + if (!pDlg) return; + + RECT rc; + GetClientRect(m_hwnd, &rc); + TabCtrl_AdjustRect(m_hwnd, FALSE, &rc); + MapWindowPoints(m_hwnd, ::GetParent(m_hwnd), (LPPOINT)&rc, 2); + SetWindowPos(pDlg->GetHwnd(), HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); +} + +void CCtrlPages::ActivatePage( int iPage ) +{ + TabCtrl_SetCurSel(m_hwnd, iPage); + //ShowPage(iPage); +} + +BOOL CCtrlPages::OnNotify( int /*idCtrl*/, NMHDR *pnmh ) +{ + switch (pnmh->code) + { + case TCN_SELCHANGING: + { + TCITEM tci = {0}; + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(m_hwnd, TabCtrl_GetCurSel(m_hwnd), &tci); + + if (TPageInfo *info = (TPageInfo *)tci.lParam) + { + if (info->m_pDlg) + { + m_pActivePage = NULL; + ShowWindow(info->m_pDlg->GetHwnd(), SW_HIDE); + } + } + + return TRUE; + } + + case TCN_SELCHANGE: + { + TCITEM tci = {0}; + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(m_hwnd, TabCtrl_GetCurSel(m_hwnd), &tci); + + if (TPageInfo *info = (TPageInfo *)tci.lParam) + { + if (info->m_pDlg) + { + m_pActivePage = info->m_pDlg; + ShowPage(info->m_pDlg); + } else + { + m_pActivePage = NULL; + info->m_onCreate(info->m_param); + } + } + + return TRUE; + } + } + + return FALSE; +} + +void CCtrlPages::OnDestroy() +{ + int count = TabCtrl_GetItemCount(m_hwnd); + for (int i = 0; i < count ; ++i) + { + TCITEM tci = {0}; + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(m_hwnd, i, &tci); + + if (TPageInfo *info = (TPageInfo *)tci.lParam) + { + if (info->m_pDlg) + info->m_pDlg->Close(); + + delete info; + } + } + + TabCtrl_DeleteAllItems(m_hwnd); + + if (m_hIml) + { + TabCtrl_SetImageList(m_hwnd, NULL); + ImageList_Destroy(m_hIml); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) : + m_parentWnd( wnd ), + m_idCtrl( idCtrl ), + m_hwnd( NULL ), + m_wndproc( NULL ) +{ + if ( wnd ) { + m_next = wnd->m_first; + wnd->m_first = this; +} } + +void CCtrlBase::OnInit() +{ + m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : NULL; +} + +void CCtrlBase::OnDestroy() +{ + Unsubclass(); + m_hwnd = NULL; +} + +void CCtrlBase::Enable( int bIsEnable ) +{ + ::EnableWindow( m_hwnd, bIsEnable ); +} + +BOOL CCtrlBase::Enabled() const +{ + return ( m_hwnd ) ? IsWindowEnabled( m_hwnd ) : FALSE; +} + +LRESULT CCtrlBase::SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ) +{ + return ::SendMessage( m_hwnd, Msg, wParam, lParam ); +} + +void CCtrlBase::SetText(const TCHAR *text) +{ + ::SetWindowText( m_hwnd, text ); +} + +void CCtrlBase::SetTextA(const char *text) +{ + ::SetWindowTextA( m_hwnd, text ); +} + +void CCtrlBase::SetInt(int value) +{ + TCHAR buf[32] = {0}; + mir_sntprintf(buf, SIZEOF(buf), _T("%d"), value); + SetWindowText(m_hwnd, buf); +} + +TCHAR* CCtrlBase::GetText() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return result; +} + +char* CCtrlBase::GetTextA() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + char *result = (char *)mir_alloc(length * sizeof(char)); + GetWindowTextA(m_hwnd, result, length); + return result; +} + +TCHAR* CCtrlBase::GetText(TCHAR *buf, int size) +{ + GetWindowText(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +char* CCtrlBase::GetTextA(char *buf, int size) +{ + GetWindowTextA(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +int CCtrlBase::GetInt() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)_alloca(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return _ttoi(result); +} + +LRESULT CCtrlBase::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_DESTROY) Unsubclass(); + return CallWindowProc(m_wndproc, m_hwnd, msg, wParam, lParam); +} + +void CCtrlBase::Subclass() +{ + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + m_wndproc = (WNDPROC)SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassWndProc); +} + +void CCtrlBase::Unsubclass() +{ + if (m_wndproc) + { + SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)0); + m_wndproc = 0; +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink class + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue, bool bSigned): CDataLink(type, bSigned) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_iDefault = iValue; + m_szDefault = 0; + dbv.type = DBVT_DELETED; +} + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue): CDataLink(type, false) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_szDefault = mir_tstrdup(szValue); + dbv.type = DBVT_DELETED; +} + +CDbLink::~CDbLink() +{ + mir_free(m_szModule); + mir_free(m_szSetting); + mir_free(m_szDefault); + if (dbv.type != DBVT_DELETED) + DBFreeVariant(&dbv); +} + +DWORD CDbLink::LoadUnsigned() +{ + switch (m_type) { + case DBVT_BYTE: return DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_WORD: return DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_DWORD: return DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); + default: return m_iDefault; + } +} + +int CDbLink::LoadSigned() +{ + switch (m_type) { + case DBVT_BYTE: return (signed char)DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_WORD: return (signed short)DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_DWORD: return (signed int)DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); + default: return m_iDefault; + } +} + +void CDbLink::SaveInt(DWORD value) +{ + switch (m_type) { + case DBVT_BYTE: DBWriteContactSettingByte(NULL, m_szModule, m_szSetting, (BYTE)value); break; + case DBVT_WORD: DBWriteContactSettingWord(NULL, m_szModule, m_szSetting, (WORD)value); break; + case DBVT_DWORD: DBWriteContactSettingDword(NULL, m_szModule, m_szSetting, value); break; + } +} + +TCHAR* CDbLink::LoadText() +{ + if (dbv.type != DBVT_DELETED) DBFreeVariant(&dbv); + if (!DBGetContactSettingTString(NULL, m_szModule, m_szSetting, &dbv)) + { + if (dbv.type == DBVT_TCHAR) + return dbv.ptszVal; + return m_szDefault; + } + + dbv.type = DBVT_DELETED; + return m_szDefault; +} + +void CDbLink::SaveText(TCHAR *value) +{ + DBWriteContactSettingTString(NULL, m_szModule, m_szSetting, value); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Base protocol dialog + +void CProtoIntDlgBase::SetStatusText(TCHAR *statusText) +{ + if (m_hwndStatus) + SendMessage(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)statusText); +} + +INT_PTR CProtoIntDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { // call inherited init code first + INT_PTR result = CSuper::DlgProc(msg, wParam, lParam); + if (m_show_label) + { + m_hwndStatus = CreateStatusWindow(WS_CHILD|WS_VISIBLE, NULL, m_hwnd, IDC_STATUSBAR); + SetWindowPos(m_hwndStatus, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + UpdateStatusBar(); + UpdateProtoTitle(); + } + return result; + } + + case WM_SETTEXT: + if (m_show_label && IsWindowUnicode(m_hwnd)) + + { + TCHAR *szTitle = (TCHAR *)lParam; + if (!_tcsstr(szTitle, m_proto_interface->m_tszUserName)) + { + UpdateProtoTitle(szTitle); + return TRUE; + } + } + break; + + case WM_SIZE: + if (m_hwndStatus) + { + RECT rcStatus; GetWindowRect(m_hwndStatus, &rcStatus); + RECT rcClient; GetClientRect(m_hwnd, &rcClient); + SetWindowPos(m_hwndStatus, NULL, 0, rcClient.bottom-(rcStatus.bottom-rcStatus.top), rcClient.right, (rcStatus.bottom-rcStatus.top), SWP_NOZORDER); + UpdateStatusBar(); + } + break; + + // Protocol events + case WM_PROTO_ACTIVATE: + OnProtoActivate(wParam, lParam); + return m_lresult; + case WM_PROTO_CHECK_ONLINE: + if (m_hwndStatus) + UpdateStatusBar(); + OnProtoCheckOnline(wParam, lParam); + return m_lresult; + case WM_PROTO_REFRESH: + OnProtoRefresh(wParam, lParam); + return m_lresult; + } + + return CSuper::DlgProc(msg, wParam, lParam); +} + +void CProtoIntDlgBase::UpdateProtoTitle(TCHAR *szText) +{ + if (!m_show_label) return; + + int curLength; + TCHAR *curText; + + if (szText) + { + curText = szText; + curLength = lstrlen(curText);; + } else + { + curLength = GetWindowTextLength(m_hwnd) + 1; + curText = (TCHAR *)_alloca(curLength * sizeof(TCHAR)); + GetWindowText(m_hwnd, curText, curLength); + } + + if (!_tcsstr(curText, m_proto_interface->m_tszUserName)) + { + int length = curLength + lstrlen(m_proto_interface->m_tszUserName) + 256; + TCHAR *text = (TCHAR *)_alloca(length * sizeof(TCHAR)); + mir_sntprintf(text, length, _T("%s [%s: %s]"), curText, TranslateT("Account"), m_proto_interface->m_tszUserName); + SetWindowText(m_hwnd, text); + } +} + +void CProtoIntDlgBase::UpdateStatusBar() +{ + SIZE sz; + + HDC hdc = GetDC(m_hwndStatus); + HFONT hFntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + GetTextExtentPoint32(hdc, m_proto_interface->m_tszUserName, lstrlen(m_proto_interface->m_tszUserName), &sz); + sz.cx += GetSystemMetrics(SM_CXSMICON) * 3; + SelectObject(hdc, hFntSave); + ReleaseDC(m_hwndStatus, hdc); + + RECT rcStatus; GetWindowRect(m_hwndStatus, &rcStatus); + int parts[] = { rcStatus.right-rcStatus.left - sz.cx, -1 }; + SendMessage(m_hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); + SendMessage(m_hwndStatus, SB_SETICON, 1, (LPARAM)LoadSkinnedProtoIcon(m_proto_interface->m_szModuleName, m_proto_interface->m_iStatus)); + SendMessage(m_hwndStatus, SB_SETTEXT, 1, (LPARAM)m_proto_interface->m_tszUserName); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Misc utilities + +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) +{ + if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton))) + PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton)); + return 0; +} + +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow) +{ + for (; *idList; ++idList) + ShowWindow(GetDlgItem(hwndDlg, *idList), nCmdShow); +} diff --git a/protocols/JabberG/src/ui_utils.h b/protocols/JabberG/src/ui_utils.h new file mode 100644 index 0000000000..9af9e8ba36 --- /dev/null +++ b/protocols/JabberG/src/ui_utils.h @@ -0,0 +1,1392 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-12 George Hazan +Copyright ( C ) 2007-09 Maxim Mluhov +Copyright ( C ) 2007-09 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or ( at your option ) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __jabber_ui_utils_h__ +#define __jabber_ui_utils_h__ + +#pragma warning(disable:4355) + +#ifndef LPLVCOLUMN +typedef struct tagNMLVSCROLL +{ + NMHDR hdr; + int dx; + int dy; +} NMLVSCROLL; +typedef struct tagLVG +{ + UINT cbSize; + UINT mask; + LPWSTR pszHeader; + int cchHeader; + LPWSTR pszFooter; + int cchFooter; + int iGroupId; + UINT stateMask; + UINT state; + UINT uAlign; +} LVGROUP, *PLVGROUP; +typedef struct tagLVGROUPMETRICS +{ + UINT cbSize; + UINT mask; + UINT Left; + UINT Top; + UINT Right; + UINT Bottom; + COLORREF crLeft; + COLORREF crTop; + COLORREF crRight; + COLORREF crBottom; + COLORREF crHeader; + COLORREF crFooter; +} LVGROUPMETRICS, *PLVGROUPMETRICS; +typedef struct tagLVTILEVIEWINFO +{ + UINT cbSize; + DWORD dwMask; + DWORD dwFlags; + SIZE sizeTile; + int cLines; + RECT rcLabelMargin; +} LVTILEVIEWINFO, *PLVTILEVIEWINFO; +typedef struct tagLVTILEINFO +{ + UINT cbSize; + int iItem; + UINT cColumns; + PUINT puColumns; +} LVTILEINFO, *PLVTILEINFO; +typedef struct +{ + UINT cbSize; + DWORD dwFlags; + int iItem; + DWORD dwReserved; +} LVINSERTMARK, * LPLVINSERTMARK; +typedef int (CALLBACK *PFNLVGROUPCOMPARE)(int, int, void *); +typedef struct tagLVINSERTGROUPSORTED +{ + PFNLVGROUPCOMPARE pfnGroupCompare; + void *pvData; + LVGROUP lvGroup; +} LVINSERTGROUPSORTED, *PLVINSERTGROUPSORTED; +typedef struct tagLVSETINFOTIP +{ + UINT cbSize; + DWORD dwFlags; + LPWSTR pszText; + int iItem; + int iSubItem; +} LVSETINFOTIP, *PLVSETINFOTIP; +#define LPLVCOLUMN LPLVCOLUMNA +#define LPLVITEM LPLVITEMA +#define LVN_BEGINSCROLL (LVN_FIRST-80) +#define LVN_ENDSCROLL (LVN_FIRST-81) +#define LVN_HOTTRACK (LVN_FIRST-21) +#define LVN_MARQUEEBEGIN (LVN_FIRST-56) +#define LVM_MAPINDEXTOID (LVM_FIRST + 180) +#define LVGF_HEADER 0x00000001 +#define LVGF_GROUPID 0x00000010 +#define ListView_MapIndexToID(hwnd, index) \ + (UINT)SendMessage((hwnd), LVM_MAPINDEXTOID, (WPARAM)index, (LPARAM)0) +#define TreeView_GetLineColor(hwnd) \ + (COLORREF)SendMessage((hwnd), TVM_GETLINECOLOR, 0, 0) +#define TreeView_SetLineColor(hwnd, clr) \ + (COLORREF)SendMessage((hwnd), TVM_SETLINECOLOR, 0, (LPARAM)(clr)) +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// Callbacks + +struct CCallbackImp +{ + struct CDummy + { int foo; + }; + +public: + __inline CCallbackImp(): m_object(NULL), m_func(NULL) {} + + __inline CCallbackImp(const CCallbackImp &other): m_object(other.m_object), m_func(other.m_func) {} + __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } + + __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } + __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } + + __inline operator bool() const { return m_object && m_func; } + + __inline bool CheckObject(void *object) const { return (object == m_object) ? true : false; } + +protected: + template<typename TClass, typename TArgument> + __inline CCallbackImp(TClass *object, void ( TClass::*func)(TArgument *argument)): m_object(( CDummy* )object), m_func((TFnCallback)func) {} + + __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } + +private: + typedef void ( CDummy::*TFnCallback)( void *argument ); + + CDummy* m_object; + TFnCallback m_func; +}; + +template<typename TArgument> +struct CCallback: public CCallbackImp +{ + typedef CCallbackImp CSuper; + +public: + __inline CCallback() {} + + template<typename TClass> + __inline CCallback(TClass *object, void ( TClass::*func)(TArgument *argument)): CCallbackImp(object, func) {} + + __inline CCallback& operator=( const CCallbackImp& x ) { CSuper::operator =( x ); return *this; } + + __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } +}; + +template<typename TClass, typename TArgument> +__inline CCallback<TArgument> Callback(TClass *object, void (TClass::*func)(TArgument *argument)) + { return CCallback<TArgument>(object, func); } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink + +class CDataLink +{ +protected: + BYTE m_type; + bool m_bSigned; + +public: + CDataLink(BYTE type, bool bSigned): m_type(type), m_bSigned(bSigned) {} + virtual ~CDataLink() {} + + __inline BYTE GetDataType() { return m_type; } + __inline BYTE GetDataSigned() { return m_bSigned; } + + virtual DWORD LoadUnsigned() = 0; + virtual int LoadSigned() = 0; + virtual void SaveInt(DWORD value) = 0; + + virtual TCHAR *LoadText() = 0; + virtual void SaveText(TCHAR *value) = 0; +}; + +class CDbLink: public CDataLink +{ + char *m_szModule; + char *m_szSetting; + bool m_bSigned; + + DWORD m_iDefault; + TCHAR *m_szDefault; + + DBVARIANT dbv; + +public: + CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue, bool bSigned = false); + CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue); + ~CDbLink(); + + DWORD LoadUnsigned(); + int LoadSigned(); + void SaveInt(DWORD value); + + TCHAR *LoadText(); + void SaveText(TCHAR *value); +}; + +template<class T> +class CMOptionLink: public CDataLink +{ +private: + CMOption<T> *m_option; + +public: + CMOptionLink(CMOption<T> &option): CDataLink(CMDBTraits<sizeof(T)>::DBTypeId, CMIntTraits<T>::IsSigned()), m_option(&option) {} + + DWORD LoadUnsigned() { return (DWORD)(T)*m_option; } + int LoadSigned() { return (int)(T)*m_option; } + void SaveInt(DWORD value) { *m_option = (T)value; } + + TCHAR *LoadText() { return NULL; } + void SaveText(TCHAR*) {} +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CDlgBase - base dialog class + +class CDlgBase +{ + friend class CCtrlBase; + friend class CCtrlData; + +public: + CDlgBase(int idDialog, HWND hwndParent); + virtual ~CDlgBase(); + + // general utilities + void Create(); + void Show(int nCmdShow = SW_SHOW); + int DoModal(); + + __inline HWND GetHwnd() const { return m_hwnd; } + __inline bool IsInitialized() const { return m_initialized; } + __inline void Close() { SendMessage(m_hwnd, WM_CLOSE, 0, 0); } + __inline const MSG *ActiveMessage() const { return &m_msg; } + + // dynamic creation support (mainly to avoid leaks in options) + struct CreateParam + { + CDlgBase *(*create)(void *param); + void *param; + }; + static INT_PTR CALLBACK DynamicDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (msg == WM_INITDIALOG) + { + CreateParam *param = (CreateParam *)lParam; + CDlgBase *wnd = param->create(param->param); + SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)GlobalDlgProc); + return GlobalDlgProc(hwnd, msg, wParam, (LPARAM)wnd); + } + + return FALSE; + } + + LRESULT m_lresult; + +protected: + HWND m_hwnd; + HWND m_hwndParent; + int m_idDialog; + MSG m_msg; + bool m_isModal; + bool m_initialized; + bool m_forceResizable; + + enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; + BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL + + CCtrlBase* m_first; + + // override this handlers to provide custom functionality + // general messages + virtual void OnInitDialog() { } + virtual void OnClose() { } + virtual void OnDestroy() { } + + // miranda-related stuff + virtual int Resizer(UTILRESIZECONTROL *urc); + virtual void OnApply() {} + virtual void OnReset() {} + virtual void OnChange(CCtrlBase*) {} + + // main dialog procedure + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + // resister controls + void AddControl(CCtrlBase *ctrl); + + // win32 stuff + void ThemeDialogBackground(BOOL tabbed); + +private: + LIST<CCtrlBase> m_controls; + + void NotifyControls(void (CCtrlBase::*fn)()); + CCtrlBase *FindControl(int idCtrl); + + static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); + + typedef HRESULT (STDAPICALLTYPE *pfnEnableThemeDialogTexture)(HWND,DWORD); + static pfnEnableThemeDialogTexture MyEnableThemeDialogTexture; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +class CCtrlBase +{ + friend class CDlgBase; + +public: + CCtrlBase(CDlgBase *wnd, int idCtrl ); + virtual ~CCtrlBase() { Unsubclass(); } + + __inline HWND GetHwnd() const { return m_hwnd; } + __inline CDlgBase *GetParent() { return m_parentWnd; } + + void Enable( int bIsEnable = true ); + __inline void Disable() { Enable( false ); } + BOOL Enabled( void ) const; + + LRESULT SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ); + + void SetText(const TCHAR *text); + void SetTextA(const char *text); + void SetInt(int value); + + TCHAR *GetText(); + char *GetTextA(); + + TCHAR *GetText(TCHAR *buf, int size); + char *GetTextA(char *buf, int size); + + int GetInt(); + + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } + virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } + + virtual void OnInit(); + virtual void OnDestroy(); + + virtual void OnApply() {} + virtual void OnReset() {} + + static int cmp(const CCtrlBase *c1, const CCtrlBase *c2) + { + if (c1->m_idCtrl < c2->m_idCtrl) return -1; + if (c1->m_idCtrl > c2->m_idCtrl) return +1; + return 0; + } + +protected: + HWND m_hwnd; + int m_idCtrl; + CCtrlBase* m_next; + CDlgBase* m_parentWnd; + + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + void Subclass(); + void Unsubclass(); + +private: + WNDPROC m_wndproc; + static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (CCtrlBase *ctrl = (CCtrlBase*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) + if (ctrl) + return ctrl->CustomWndProc(msg, wParam, lParam); + + return DefWindowProc(hwnd, msg, wParam, lParam); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +class CCtrlButton : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlButton( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + + CCallback<CCtrlButton> OnClick; +}; + +class CCtrlMButton : public CCtrlButton +{ + typedef CCtrlButton CSuper; + +public: + CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ); + CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ); + ~CCtrlMButton(); + + void MakeFlat(); + void MakePush(); + + virtual void OnInit(); + +protected: + char m_flags; + HICON m_hIcon; + const char* m_toolTip; +}; + +class CCtrlHyperlink : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlHyperlink( CDlgBase* dlg, int ctrlId, const char* url ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + +protected: + const char* m_url; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +class CCtrlClc: public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlClc( CDlgBase* dlg, int ctrlId ); + + void AddContact(HANDLE hContact); + void AddGroup(HANDLE hGroup); + void AutoRebuild(); + void DeleteItem(HANDLE hItem); + void EditLabel(HANDLE hItem); + void EndEditLabel(bool save); + void EnsureVisible(HANDLE hItem, bool partialOk); + void Expand(HANDLE hItem, DWORD flags); + HANDLE FindContact(HANDLE hContact); + HANDLE FindGroup(HANDLE hGroup); + COLORREF GetBkColor(); + bool GetCheck(HANDLE hItem); + int GetCount(); + HWND GetEditControl(); + DWORD GetExpand(HANDLE hItem); + int GetExtraColumns(); + BYTE GetExtraImage(HANDLE hItem, int iColumn); + HIMAGELIST GetExtraImageList(); + HFONT GetFont(int iFontId); + HANDLE GetSelection(); + HANDLE HitTest(int x, int y, DWORD *hitTest); + void SelectItem(HANDLE hItem); + void SetBkBitmap(DWORD mode, HBITMAP hBitmap); + void SetBkColor(COLORREF clBack); + void SetCheck(HANDLE hItem, bool check); + void SetExtraColumns(int iColumns); + void SetExtraImage(HANDLE hItem, int iColumn, int iImage); + void SetExtraImageList(HIMAGELIST hImgList); + void SetFont(int iFontId, HANDLE hFont, bool bRedraw); + void SetIndent(int iIndent); + void SetItemText(HANDLE hItem, char *szText); + void SetHideEmptyGroups(bool state); + void SetGreyoutFlags(DWORD flags); + bool GetHideOfflineRoot(); + void SetHideOfflineRoot(bool state); + void SetUseGroups(bool state); + void SetOfflineModes(DWORD modes); + DWORD GetExStyle(); + void SetExStyle(DWORD exStyle); + int GetLefrMargin(); + void SetLeftMargin(int iMargin); + HANDLE AddInfoItem(CLCINFOITEM *cii); + int GetItemType(HANDLE hItem); + HANDLE GetNextItem(HANDLE hItem, DWORD flags); + COLORREF GetTextColot(int iFontId); + void SetTextColor(int iFontId, COLORREF clText); + + struct TEventInfo + { + CCtrlClc *ctrl; + NMCLISTCONTROL *info; + }; + + CCallback<TEventInfo> OnExpanded; + CCallback<TEventInfo> OnListRebuilt; + CCallback<TEventInfo> OnItemChecked; + CCallback<TEventInfo> OnDragging; + CCallback<TEventInfo> OnDropped; + CCallback<TEventInfo> OnListSizeChange; + CCallback<TEventInfo> OnOptionsChanged; + CCallback<TEventInfo> OnDragStop; + CCallback<TEventInfo> OnNewContact; + CCallback<TEventInfo> OnContactMoved; + CCallback<TEventInfo> OnCheckChanged; + CCallback<TEventInfo> OnClick; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData - data access controls base class + +class CCtrlData : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlData( CDlgBase* dlg, int ctrlId ); + + virtual ~CCtrlData() + { + if (m_dbLink) delete m_dbLink; + } + + __inline bool IsChanged() const { return m_changed; } + + void CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue, bool bSigned = false ); + void CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ); + void CreateDbLink( CDataLink *link ) { m_dbLink = link; } + + virtual void OnInit(); + + // Events + CCallback<CCtrlData> OnChange; + +protected: + CDataLink *m_dbLink; + bool m_changed; + + void NotifyChange(); + + __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } + __inline bool GetDataSigned() { return m_dbLink ? m_dbLink->GetDataSigned() ? true : false : false; } + __inline DWORD LoadUnsigned() { return m_dbLink ? m_dbLink->LoadUnsigned() : 0; } + __inline int LoadSigned() { return m_dbLink ? m_dbLink->LoadSigned() : 0; } + __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } + __inline const TCHAR *LoadText() { return m_dbLink ? m_dbLink->LoadText() : _T(""); } + __inline void SaveText(TCHAR *value) { if (m_dbLink) m_dbLink->SaveText(value); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck + +class CCtrlCheck : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlCheck( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { NotifyChange(); return TRUE; } + virtual void OnInit() + { + CSuper::OnInit(); + OnReset(); + } + virtual void OnApply() + { + SaveInt(GetState()); + } + virtual void OnReset() + { + SetState(LoadUnsigned()); + } + + int GetState(); + void SetState(int state); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit + +class CCtrlEdit : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlEdit( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) + { + if (idCode == EN_CHANGE) + NotifyChange(); + return TRUE; + } + virtual void OnInit() + { + CSuper::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(GetDataSigned() ? LoadSigned() : LoadUnsigned()); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox + +class CCtrlListBox : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlListBox( CDlgBase* dlg, int ctrlId ); + + int AddString(TCHAR *text, LPARAM data=0); + void DeleteString(int index); + int FindString(TCHAR *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + bool GetSel(int index); + int GetSelCount(); + int* GetSelItems(int *items, int count); + int* GetSelItems(); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void SetSel(int index, bool sel=true); + + // Events + CCallback<CCtrlListBox> OnDblClick; + CCallback<CCtrlListBox> OnSelCancel; + CCallback<CCtrlListBox> OnSelChange; + +protected: + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo + +class CCtrlCombo : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlCombo( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) + { + switch (idCode) + { + case CBN_CLOSEUP: OnCloseup(this); break; + case CBN_DROPDOWN: OnDropdown(this); break; + + case CBN_EDITCHANGE: + case CBN_EDITUPDATE: + case CBN_SELCHANGE: + case CBN_SELENDOK: + NotifyChange(); + break; + } + return TRUE; + } + + virtual void OnInit() + { + CSuper::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(LoadUnsigned()); + } + + // Control interface + int AddString(const TCHAR *text, LPARAM data = 0 ); + int AddStringA(const char *text, LPARAM data = 0 ); + void DeleteString(int index); + int FindString(const TCHAR *str, int index = -1, bool exact = false); + int FindStringA(const char *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + bool GetDroppedState(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void ShowDropdown(bool show = true); + + // Events + CCallback<CCtrlCombo> OnCloseup; + CCallback<CCtrlCombo> OnDropdown; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +class CCtrlListView : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlListView( CDlgBase* dlg, int ctrlId ); + + // Classic LV interface + DWORD ApproximateViewRect(int cx, int cy, int iCount); + void Arrange(UINT code); + void CancelEditLabel(); + HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); + void DeleteAllItems(); + void DeleteColumn(int iCol); + void DeleteItem(int iItem); + HWND EditLabel(int iItem); + int EnableGroupView(BOOL fEnable); + BOOL EnsureVisible(int i, BOOL fPartialOK); + int FindItem(int iStart, const LVFINDINFO *plvfi); + COLORREF GetBkColor(); + void GetBkImage(LPLVBKIMAGE plvbki); + UINT GetCallbackMask(); + BOOL GetCheckState(UINT iIndex); + void GetColumn(int iCol, LPLVCOLUMN pcol); + void GetColumnOrderArray(int iCount, int *lpiArray); + int GetColumnWidth(int iCol); + int GetCountPerPage(); + HWND GetEditControl(); + //void GetEmptyText(PWSTR pszText, UINT cchText); + DWORD GetExtendedListViewStyle(); + INT GetFocusedGroup(); + //void GetFooterInfo(LVFOOTERINFO *plvfi); + //void GetFooterItem(UINT iItem, LVFOOTERITEM *pfi); + //void GetFooterItemRect(UINT iItem, RECT *prc); + //void GetFooterRect(RECT *prc); + int GetGroupCount(); + //HIMAGELIST GetGroupHeaderImageList(); + void GetGroupInfo(int iGroupId, PLVGROUP pgrp); + void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp); + void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics); + //BOOL GetGroupRect(int iGroupId, RECT *prc); + UINT GetGroupState(UINT dwGroupId, UINT dwMask); + HWND GetHeader(); + HCURSOR GetHotCursor(); + INT GetHotItem(); + DWORD GetHoverTime(); + HIMAGELIST GetImageList(int iImageList); + BOOL GetInsertMark(LVINSERTMARK *plvim); + COLORREF GetInsertMarkColor(); + int GetInsertMarkRect(LPRECT prc); + BOOL GetISearchString(LPSTR lpsz); + void GetItem(LPLVITEM pitem); + int GetItemCount(); + //void GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc); + void GetItemPosition(int i, POINT *ppt); + void GetItemRect(int i, RECT *prc, int code); + DWORD GetItemSpacing(BOOL fSmall); + UINT GetItemState(int i, UINT mask); + void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax); + int GetNextItem(int iStart, UINT flags); + //BOOL GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags); + BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas); + BOOL GetOrigin(LPPOINT lpptOrg); + COLORREF GetOutlineColor(); + UINT GetSelectedColumn(); + UINT GetSelectedCount(); + INT GetSelectionMark(); + int GetStringWidth(LPCSTR psz); + BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect); + COLORREF GetTextBkColor(); + COLORREF GetTextColor(); + void GetTileInfo(PLVTILEINFO plvtinfo); + void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND GetToolTips(); + int GetTopIndex(); + BOOL GetUnicodeFormat(); + DWORD GetView(); + BOOL GetViewRect(RECT *prc); + void GetWorkAreas(INT nWorkAreas, LPRECT lprc); + BOOL HasGroup(int dwGroupId); + int HitTest(LPLVHITTESTINFO pinfo); + int HitTestEx(LPLVHITTESTINFO pinfo); + int InsertColumn(int iCol, const LPLVCOLUMN pcol); + int InsertGroup(int index, PLVGROUP pgrp); + void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); + int InsertItem(const LPLVITEM pitem); + BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); + BOOL IsGroupViewEnabled(); + UINT IsItemVisible(UINT index); + UINT MapIDToIndex(UINT id); + UINT MapIndexToID(UINT index); + BOOL RedrawItems(int iFirst, int iLast); + void RemoveAllGroups(); + int RemoveGroup(int iGroupId); + BOOL Scroll(int dx, int dy); + BOOL SetBkColor(COLORREF clrBk); + BOOL SetBkImage(LPLVBKIMAGE plvbki); + BOOL SetCallbackMask(UINT mask); + void SetCheckState(UINT iIndex, BOOL fCheck); + BOOL SetColumn(int iCol, LPLVCOLUMN pcol); + BOOL SetColumnOrderArray(int iCount, int *lpiArray); + BOOL SetColumnWidth(int iCol, int cx); + void SetExtendedListViewStyle(DWORD dwExStyle); + void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); + //HIMAGELIST SetGroupHeaderImageList(HIMAGELIST himl); + int SetGroupInfo(int iGroupId, PLVGROUP pgrp); + void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); + void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); + HCURSOR SetHotCursor(HCURSOR hCursor); + INT SetHotItem(INT iIndex); + void SetHoverTime(DWORD dwHoverTime); + DWORD SetIconSpacing(int cx, int cy); + HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); + BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); + BOOL SetInsertMark(LVINSERTMARK *plvim); + COLORREF SetInsertMarkColor(COLORREF color); + BOOL SetItem(const LPLVITEM pitem); + void SetItemCount(int cItems); + void SetItemCountEx(int cItems, DWORD dwFlags); + //HRESULT SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask); + BOOL SetItemPosition(int i, int x, int y); + void SetItemPosition32(int iItem, int x, int y); + void SetItemState(int i, UINT state, UINT mask); + void SetItemText(int i, int iSubItem, TCHAR *pszText); + COLORREF SetOutlineColor(COLORREF color); + void SetSelectedColumn(int iCol); + INT SetSelectionMark(INT iIndex); + BOOL SetTextBkColor(COLORREF clrText); + BOOL SetTextColor(COLORREF clrText); + BOOL SetTileInfo(PLVTILEINFO plvtinfo); + BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND SetToolTips(HWND ToolTip); + BOOL SetUnicodeFormat(BOOL fUnicode); + int SetView(DWORD iView); + void SetWorkAreas(INT nWorkAreas, LPRECT lprc); + int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + INT SubItemHitTest(LPLVHITTESTINFO pInfo); + INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); + BOOL Update(int iItem); + + // Additional APIs + HIMAGELIST CreateImageList(int iImageList); + void AddColumn(int iSubItem, TCHAR *name, int cx); + void AddGroup(int iGroupId, TCHAR *name); + int AddItem(TCHAR *text, int iIcon, LPARAM lParam = 0, int iGroupId = -1); + void SetItem(int iItem, int iSubItem, TCHAR *text, int iIcon = -1); + LPARAM GetItemData(int iItem); + + // Events + struct TEventInfo { + CCtrlListView *treeviewctrl; + union { + NMHDR *nmhdr; + NMLISTVIEW *nmlv; + NMLVDISPINFO *nmlvdi; + NMLVSCROLL *nmlvscr; + NMLVGETINFOTIP *nmlvit; + NMLVFINDITEM *nmlvfi; + NMITEMACTIVATE *nmlvia; + NMLVKEYDOWN *nmlvkey; + }; + }; + + CCallback<TEventInfo> OnBeginDrag; + CCallback<TEventInfo> OnBeginLabelEdit; + CCallback<TEventInfo> OnBeginRDrag; + CCallback<TEventInfo> OnBeginScroll; + CCallback<TEventInfo> OnColumnClick; + //CCallback<TEventInfo> OnColumnDropdown; + //CCallback<TEventInfo> OnColumnOverflowClick; + CCallback<TEventInfo> OnDeleteAllItems; + CCallback<TEventInfo> OnDeleteItem; + CCallback<TEventInfo> OnDoubleClick; + CCallback<TEventInfo> OnEndLabelEdit; + CCallback<TEventInfo> OnEndScroll; + CCallback<TEventInfo> OnGetDispInfo; + //CCallback<TEventInfo> OnGetEmptyMarkup; + CCallback<TEventInfo> OnGetInfoTip; + CCallback<TEventInfo> OnHotTrack; + CCallback<TEventInfo> OnIncrementalSearch; + CCallback<TEventInfo> OnInsertItem; + CCallback<TEventInfo> OnItemActivate; + CCallback<TEventInfo> OnItemChanged; + CCallback<TEventInfo> OnItemChanging; + CCallback<TEventInfo> OnKeyDown; + //CCallback<TEventInfo> OnLinkClick; + CCallback<TEventInfo> OnMarqueeBegin; + CCallback<TEventInfo> OnSetDispInfo; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +struct CFilterData; +class CCtrlFilterListView : public CCtrlListView +{ + typedef CCtrlListView CSuper; + +public: + CCtrlFilterListView(CDlgBase* dlg, int ctrlId, bool trackFilter, bool keepHiglight); + ~CCtrlFilterListView(); + + TCHAR *GetFilterText(); + CCallback<CCtrlFilterListView> OnFilterChanged; + +protected: + CFilterData *fdat; + bool m_trackFilter; + bool m_keepHiglight; + + void OnInit(); + LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + void FilterHighlight(TCHAR *filter); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +class CCtrlTreeView : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlTreeView( CDlgBase* dlg, int ctrlId ); + + // Classic TV interface + HIMAGELIST CreateDragImage(HTREEITEM hItem); + void DeleteAllItems(); + void DeleteItem(HTREEITEM hItem); + HWND EditLabel(HTREEITEM hItem); + void EndEditLabelNow(BOOL cancel); + void EnsureVisible(HTREEITEM hItem); + void Expand(HTREEITEM hItem, DWORD flag); + COLORREF GetBkColor(); + DWORD GetCheckState(HTREEITEM hItem); + HTREEITEM GetChild(HTREEITEM hItem); + int GetCount(); + HTREEITEM GetDropHilight(); + HWND GetEditControl(); + HTREEITEM GetFirstVisible(); + HIMAGELIST GetImageList(int iImage); + int GetIndent(); + COLORREF GetInsertMarkColor(); + void GetItem(TVITEMEX *tvi); + int GetItemHeight(); + void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect); + DWORD GetItemState(HTREEITEM hItem, DWORD stateMask); + HTREEITEM GetLastVisible(); + COLORREF GetLineColor(); + HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag); + HTREEITEM GetNextSibling(HTREEITEM hItem); + HTREEITEM GetNextVisible(HTREEITEM hItem); + HTREEITEM GetParent(HTREEITEM hItem); + HTREEITEM GetPrevSibling(HTREEITEM hItem); + HTREEITEM GetPrevVisible(HTREEITEM hItem); + HTREEITEM GetRoot(); + DWORD GetScrollTime(); + HTREEITEM GetSelection(); + COLORREF GetTextColor(); + HWND GetToolTips(); + BOOL GetUnicodeFormat(); + unsigned GetVisibleCount(); + HTREEITEM HitTest(TVHITTESTINFO *hti); + HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); + //HTREEITEM MapAccIDToHTREEITEM(UINT id); + //UINT MapHTREEITEMtoAccID(HTREEITEM hItem); + void Select(HTREEITEM hItem, DWORD flag); + void SelectDropTarget(HTREEITEM hItem); + void SelectItem(HTREEITEM hItem); + void SelectSetFirstVisible(HTREEITEM hItem); + COLORREF SetBkColor(COLORREF clBack); + void SetCheckState(HTREEITEM hItem, DWORD state); + void SetImageList(HIMAGELIST hIml, int iImage); + void SetIndent(int iIndent); + void SetInsertMark(HTREEITEM hItem, BOOL fAfter); + COLORREF SetInsertMarkColor(COLORREF clMark); + void SetItem(TVITEMEX *tvi); + void SetItemHeight(short cyItem); + void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); + COLORREF SetLineColor(COLORREF clLine); + void SetScrollTime(UINT uMaxScrollTime); + COLORREF SetTextColor(COLORREF clText); + HWND SetToolTips(HWND hwndToolTips); + BOOL SetUnicodeFormat(BOOL fUnicode); + void SortChildren(HTREEITEM hItem, BOOL fRecurse); + void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); + + // Additional stuff + void TranslateItem(HTREEITEM hItem); + void TranslateTree(); + HTREEITEM FindNamedItem(HTREEITEM hItem, const TCHAR *name); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength); + + // Events + struct TEventInfo { + CCtrlTreeView *treeviewctrl; + union { + NMHDR *nmhdr; + NMTREEVIEW *nmtv; + NMTVDISPINFO *nmtvdi; + NMTVGETINFOTIP *nmtvit; + NMTVKEYDOWN *nmtvkey; + }; + }; + + CCallback<TEventInfo> OnBeginDrag; + CCallback<TEventInfo> OnBeginLabelEdit; + CCallback<TEventInfo> OnBeginRDrag; + CCallback<TEventInfo> OnDeleteItem; + CCallback<TEventInfo> OnEndLabelEdit; + CCallback<TEventInfo> OnGetDispInfo; + CCallback<TEventInfo> OnGetInfoTip; + CCallback<TEventInfo> OnItemExpanded; + CCallback<TEventInfo> OnItemExpanding; + CCallback<TEventInfo> OnKeyDown; + CCallback<TEventInfo> OnSelChanged; + CCallback<TEventInfo> OnSelChanging; + CCallback<TEventInfo> OnSetDispInfo; + CCallback<TEventInfo> OnSingleExpand; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +class CCtrlPages: public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlPages( CDlgBase* dlg, int ctrlId ); + + void AddPage( TCHAR *ptszName, HICON hIcon, CCallback<void> onCreate = CCallback<void>(), void *param = NULL ); + void AttachDialog( int iPage, CDlgBase *pDlg ); + + void ActivatePage( int iPage ); + + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); + void OnInit(); + void OnDestroy(); + + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + +private: + HIMAGELIST m_hIml; + CDlgBase *m_pActivePage; + + struct TPageInfo + { + CCallback<void> m_onCreate; + void *m_param; + CDlgBase *m_pDlg; + }; + + void ShowPage(CDlgBase *pDlg); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCustom + +template<typename TDlg> +class CCtrlCustom : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +private: + void (TDlg::*m_pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode); + void (TDlg::*m_pfnOnNotify)(int idCtrl, NMHDR *pnmh); + void (TDlg::*m_pfnOnMeasureItem)(MEASUREITEMSTRUCT *param); + void (TDlg::*m_pfnOnDrawItem)(DRAWITEMSTRUCT *param); + void (TDlg::*m_pfnOnDeleteItem)(DELETEITEMSTRUCT *param); + +public: + CCtrlCustom(TDlg *wnd, int idCtrl, + void (TDlg::*pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode), + void (TDlg::*pfnOnNotify)(int idCtrl, NMHDR *pnmh), + void (TDlg::*pfnOnMeasureItem)(MEASUREITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDrawItem)(DRAWITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDeleteItem)(DELETEITEMSTRUCT *param) = NULL): CCtrlBase(wnd, idCtrl) + { + m_pfnOnCommand = pfnOnCommand; + m_pfnOnNotify = pfnOnNotify; + m_pfnOnMeasureItem = pfnOnMeasureItem; + m_pfnOnDrawItem = pfnOnDrawItem; + m_pfnOnDeleteItem = pfnOnDeleteItem; + } + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) + { + if (m_parentWnd && m_pfnOnCommand) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnCommand)(hwndCtrl, idCtrl, idCode); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnNotify(int idCtrl, NMHDR *pnmh) + { + if (m_parentWnd && m_pfnOnNotify) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnNotify)(idCtrl, pnmh); + return m_parentWnd->m_lresult; + } + return FALSE; + } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnMeasureItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnMeasureItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDrawItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDrawItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDeleteItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDeleteItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CProtoDlgBase + +#define WM_PROTO_REFRESH (WM_USER + 100) +#define WM_PROTO_CHECK_ONLINE (WM_USER + 101) +#define WM_PROTO_ACTIVATE (WM_USER + 102) +#define WM_PROTO_LAST (WM_USER + 200) + +typedef struct tagPROTO_INTERFACE PROTO_INTERFACE; + +class CProtoIntDlgBase : public CDlgBase +{ + typedef CDlgBase CSuper; + +public: + __inline CProtoIntDlgBase(PROTO_INTERFACE *proto, int idDialog, HWND parent, bool show_label=true) : + CDlgBase( idDialog, parent ), + m_proto_interface( proto ), + m_show_label( show_label ), + m_hwndStatus( NULL ) + { + } + + __inline void CreateLink( CCtrlData& ctrl, char *szSetting, BYTE type, DWORD iValue, bool bSigned = false ) + { + ctrl.CreateDbLink(m_proto_interface->m_szModuleName, szSetting, type, iValue, bSigned ); + } + __inline void CreateLink( CCtrlData& ctrl, const char *szSetting, TCHAR *szValue ) + { + ctrl.CreateDbLink(m_proto_interface->m_szModuleName, szSetting, szValue); + } + + template<class T> + __inline void CreateLink( CCtrlData& ctrl, CMOption<T> &option ) + { + ctrl.CreateDbLink(new CMOptionLink<T>(option)); + } + + __inline PROTO_INTERFACE *GetProtoInterface() { return m_proto_interface; } + + void SetStatusText(TCHAR *statusText); + +protected: + PROTO_INTERFACE *m_proto_interface; + bool m_show_label; + HWND m_hwndStatus; + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + virtual void OnProtoRefresh(WPARAM, LPARAM) {} + virtual void OnProtoActivate(WPARAM, LPARAM) {} + virtual void OnProtoCheckOnline(WPARAM, LPARAM) {} + +private: + void UpdateProtoTitle(TCHAR *szText = NULL); + void UpdateStatusBar(); +}; + +template<typename TProto> +class CProtoDlgBase : public CProtoIntDlgBase +{ + typedef CProtoIntDlgBase CSuper; + +public: + __inline CProtoDlgBase<TProto>(TProto *proto, int idDialog, HWND parent, bool show_label=true ) : + CProtoIntDlgBase( proto, idDialog, parent, show_label ), + m_proto( proto ) + { + } + + __inline TProto *GetProto() { return m_proto; } + +protected: + TProto* m_proto; + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) + { + case WM_INITDIALOG: + m_proto->WindowSubscribe(m_hwnd); + break; + case WM_DESTROY: + WindowFreeIcon(m_hwnd); + m_proto->WindowUnsubscribe(m_hwnd); + break; + } + + return CSuper::DlgProc(msg, wParam, lParam); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Safe open/close dialogs +#define UI_SAFE_OPEN(dlgClass, dlgPtr) \ + { \ + if (dlgPtr) \ + { \ + SetForegroundWindow((dlgPtr)->GetHwnd()); \ + } else \ + { \ + (dlgPtr) = new dlgClass(this); \ + (dlgPtr)->Show(); \ + } \ + } + +#define UI_SAFE_OPEN_EX(dlgClass, dlgPtr, dlgLocal) \ + if (dlgPtr) \ + { \ + ::SetForegroundWindow((dlgPtr)->GetHwnd()); \ + } else \ + { \ + (dlgPtr) = new dlgClass(this); \ + (dlgPtr)->Show(); \ + } \ + dlgClass *dlgLocal = (dlgClass *)(dlgPtr); + +#define UI_SAFE_CLOSE(dlg) \ + { \ + if ( dlg ) { \ + (dlg)->Close(); \ + (dlg) = NULL; \ + } \ + } + +#define UI_SAFE_CLOSE_HWND(hwnd) \ + { \ + if ( hwnd ) { \ + ::SendMessage( (hwnd), WM_CLOSE, 0, 0 ); \ + (hwnd) = NULL; \ + } \ + } + +///////////////////////////////////////////////////////////////////////////////////////// +// NULL-Safe dialog notifications +#define UI_SAFE_NOTIFY(dlg, msg) \ + { \ + if ( dlg ) \ + ::SendMessage((dlg)->GetHwnd(), msg, 0, 0); \ + } + +#define UI_SAFE_NOTIFY_HWND(hwnd, msg) \ + { \ + if ( hwnd ) \ + ::SendMessage((hwnd), msg, 0, 0); \ + } + +///////////////////////////////////////////////////////////////////////////////////////// +// Define message maps +#define UI_MESSAGE_MAP(dlgClass, baseDlgClass) \ + typedef baseDlgClass CMessageMapSuperClass; \ + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) \ + { \ + switch (msg) \ + { \ + case 0: \ + break /* just to handle ";" symbol after macro */ + +#define UI_MESSAGE(msg, proc) \ + case msg: \ + proc(msg, wParam, lParam); \ + break + +#define UI_MESSAGE_EX(msg, func) \ + case msg: \ + return func(msg, wParam, lParam) + +#define UI_POSTPROCESS_MESSAGE(msg, proc) \ + case msg: \ + CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + return FALSE + +#define UI_POSTPROCESS_MESSAGE_EX(msg, func) \ + case msg: \ + CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + return func(msg, wParam, lParam) + +#define UI_MESSAGE_MAP_END() \ + } \ + return CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + } + +///////////////////////////////////////////////////////////////////////////////////////// +// Misc utitlities +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton); +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow); + +#endif // __jabber_ui_utils_h__ diff --git a/protocols/JabberG/src/version.h b/protocols/JabberG/src/version.h new file mode 100644 index 0000000000..cf7a422dc2 --- /dev/null +++ b/protocols/JabberG/src/version.h @@ -0,0 +1,3 @@ +#define __FILEVERSION_STRING 0,11,0,1 +#define __VERSION_STRING "0.11.0.1" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0,11,0,1) diff --git a/protocols/JabberG/ui_utils.cpp b/protocols/JabberG/ui_utils.cpp deleted file mode 100644 index 39f63ecae7..0000000000 --- a/protocols/JabberG/ui_utils.cpp +++ /dev/null @@ -1,2574 +0,0 @@ -/* - -Object UI extensions -Copyright (C) 2008 Victor Pavlychko, George Hazan - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "jabber.h" - -extern HINSTANCE hInst; - -CDlgBase::CDlgBase(int idDialog, HWND hwndParent) : - m_controls(1, CCtrlBase::cmp) -{ - m_idDialog = idDialog; - m_hwndParent = hwndParent; - m_hwnd = NULL; - m_first = NULL; - m_isModal = false; - m_initialized = false; - m_autoClose = CLOSE_ON_OK|CLOSE_ON_CANCEL; - m_forceResizable = false; -} - -CDlgBase::~CDlgBase() -{ - // remove handlers - m_controls.destroy(); - - if (m_hwnd) - DestroyWindow(m_hwnd); -} - -void CDlgBase::Create() -{ - ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_HIDE); -} - -void CDlgBase::Show(int nCmdShow) -{ - ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), nCmdShow); -} - -int CDlgBase::DoModal() -{ - m_isModal = true; - return DialogBoxParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this); -} - -int CDlgBase::Resizer(UTILRESIZECONTROL*) -{ - return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; -} - -INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - { - m_initialized = false; - TranslateDialogDefault(m_hwnd); - - for ( CCtrlBase* p = m_first; p != NULL; p = p->m_next ) - AddControl( p ); - - NotifyControls(&CCtrlBase::OnInit); - OnInitDialog(); - - m_initialized = true; - return TRUE; - } - - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnMeasureItem(param); - return FALSE; - } - - case WM_DRAWITEM: - { - DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnDrawItem(param); - return FALSE; - } - - case WM_DELETEITEM: - { - DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam; - if (param && param->CtlID) - if (CCtrlBase *ctrl = FindControl(param->CtlID)) - return ctrl->OnDeleteItem(param); - return FALSE; - } - - case WM_COMMAND: - { - HWND hwndCtrl = (HWND)lParam; - WORD idCtrl = LOWORD(wParam); - WORD idCode = HIWORD(wParam); - if (CCtrlBase *ctrl = FindControl(idCtrl)) { - BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode); - if ( result != FALSE ) - return result; - } - - if (idCode == BN_CLICKED && - ((idCtrl == IDOK) && (m_autoClose & CLOSE_ON_OK) || - (idCtrl == IDCANCEL) && (m_autoClose & CLOSE_ON_CANCEL))) - { - PostMessage( m_hwnd, WM_CLOSE, 0, 0 ); - } - return FALSE; - } - - case WM_NOTIFY: - { - int idCtrl = wParam; - NMHDR *pnmh = (NMHDR *)lParam; - - if (pnmh->idFrom == 0) - { - if (pnmh->code == PSN_APPLY) - { - NotifyControls(&CCtrlBase::OnApply); - OnApply(); - } - else if (pnmh->code == PSN_RESET) - { - NotifyControls(&CCtrlBase::OnReset); - OnReset(); - } - } - - if (CCtrlBase *ctrl = FindControl(pnmh->idFrom)) - return ctrl->OnNotify(idCtrl, pnmh); - return FALSE; - } - - case WM_SIZE: - { - if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_SIZEBOX)) - { - UTILRESIZEDIALOG urd; - urd.cbSize = sizeof(urd); - urd.hwndDlg = m_hwnd; - urd.hInstance = hInst; - urd.lpTemplate = MAKEINTRESOURCEA(m_idDialog); - urd.lParam = 0; - urd.pfnResizer = GlobalDlgResizer; - CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); - } - return TRUE; - } - - case WM_CLOSE: - { - m_lresult = FALSE; - OnClose(); - if ( !m_lresult ) - { - if (m_isModal) - EndDialog(m_hwnd, 0); - else - DestroyWindow(m_hwnd); - } - return TRUE; - } - - case WM_DESTROY: - { - OnDestroy(); - NotifyControls(&CCtrlBase::OnDestroy); - - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); - m_hwnd = NULL; - if (m_isModal) - { - m_isModal = false; - } else - { // modeless dialogs MUST be allocated with 'new' - delete this; - } - return TRUE; - } - } - - return FALSE; -} - -INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CDlgBase *wnd = NULL; - if (msg == WM_INITDIALOG) - { - SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); - wnd = (CDlgBase *)lParam; - wnd->m_hwnd = hwnd; - } else - { - wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - } - - if (!wnd) return FALSE; - - wnd->m_msg.hwnd = hwnd; - wnd->m_msg.message = msg; - wnd->m_msg.wParam = wParam; - wnd->m_msg.lParam = lParam; - return wnd->DlgProc(msg, wParam, lParam); -} - -int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) -{ - CDlgBase *wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!wnd) return 0; - - return wnd->Resizer(urc); -} - -CDlgBase::pfnEnableThemeDialogTexture CDlgBase::MyEnableThemeDialogTexture = NULL; -void CDlgBase::ThemeDialogBackground(BOOL tabbed) -{ - if (!MyEnableThemeDialogTexture && IsWinVerXPPlus()) - { - HMODULE hThemeAPI = GetModuleHandleA("uxtheme"); - if (hThemeAPI) - MyEnableThemeDialogTexture = (pfnEnableThemeDialogTexture)GetProcAddress(hThemeAPI,"EnableThemeDialogTexture"); - } - - if (MyEnableThemeDialogTexture) - { - MyEnableThemeDialogTexture(m_hwnd,(tabbed?0x00000002:0x00000001)|0x00000004); //0x00000002|0x00000004=ETDT_ENABLETAB - } -} - -void CDlgBase::AddControl(CCtrlBase *ctrl) -{ - m_controls.insert(ctrl); -} - -void CDlgBase::NotifyControls(void (CCtrlBase::*fn)()) -{ - for (int i = 0; i < m_controls.getCount(); ++i) - (m_controls[i]->*fn)(); -} - -CCtrlBase* CDlgBase::FindControl(int idCtrl) -{ - CCtrlBase search(NULL, idCtrl); - return m_controls.find(&search); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCombo class - -CCtrlCombo::CCtrlCombo( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -int CCtrlCombo::AddString(const TCHAR *text, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); - if ( data ) - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -int CCtrlCombo::AddStringA(const char *text, LPARAM data) -{ - int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); - if ( data ) - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlCombo::DeleteString(int index) -{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0); -} - -int CCtrlCombo::FindString(const TCHAR *str, int index, bool exact ) -{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlCombo::FindStringA(const char *str, int index, bool exact ) -{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlCombo::GetCount() -{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0); -} - -int CCtrlCombo::GetCurSel() -{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); -} - -bool CCtrlCombo::GetDroppedState() -{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false; -} - -LPARAM CCtrlCombo::GetItemData(int index) -{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0); -} - -TCHAR* CCtrlCombo::GetItemText(int index) -{ - TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); - return result; -} - -TCHAR* CCtrlCombo::GetItemText(int index, TCHAR *buf, int size) -{ - TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); - lstrcpyn(buf, result, size); - return buf; -} - -int CCtrlCombo::InsertString(TCHAR *text, int pos, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlCombo::ResetContent() -{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0); -} - -int CCtrlCombo::SelectString(TCHAR *str) -{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str); -} - -int CCtrlCombo::SetCurSel(int index) -{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0); -} - -void CCtrlCombo::SetItemData(int index, LPARAM data) -{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data); -} - -void CCtrlCombo::ShowDropdown(bool show) -{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListBox class - -CCtrlListBox::CCtrlListBox( CDlgBase* dlg, int ctrlId ) : - CCtrlBase( dlg, ctrlId ) -{ -} - -BOOL CCtrlListBox::OnCommand(HWND, WORD, WORD idCode) -{ - switch (idCode) - { - case LBN_DBLCLK: OnDblClick(this); break; - case LBN_SELCANCEL: OnSelCancel(this); break; - case LBN_SELCHANGE: OnSelChange(this); break; - } - return TRUE; -} - -int CCtrlListBox::AddString(TCHAR *text, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)text); - SendMessage(m_hwnd, LB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlListBox::DeleteString(int index) -{ SendMessage(m_hwnd, LB_DELETESTRING, index, 0); -} - -int CCtrlListBox::FindString( TCHAR *str, int index, bool exact) -{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str); -} - -int CCtrlListBox::GetCount() -{ return SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); -} - -int CCtrlListBox::GetCurSel() -{ return SendMessage(m_hwnd, LB_GETCURSEL, 0, 0); -} - -LPARAM CCtrlListBox::GetItemData(int index) -{ return SendMessage(m_hwnd, LB_GETITEMDATA, index, 0); -} - -TCHAR* CCtrlListBox::GetItemText(int index) -{ - TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); - return result; -} - -TCHAR* CCtrlListBox::GetItemText(int index, TCHAR *buf, int size) -{ - TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); - SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); - lstrcpyn(buf, result, size); - return buf; -} - -bool CCtrlListBox::GetSel(int index) -{ return SendMessage(m_hwnd, LB_GETSEL, index, 0) ? true : false; -} - -int CCtrlListBox::GetSelCount() -{ return SendMessage(m_hwnd, LB_GETSELCOUNT, 0, 0); -} - -int* CCtrlListBox::GetSelItems(int *items, int count) -{ - SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)items); - return items; -} - -int* CCtrlListBox::GetSelItems() -{ - int count = GetSelCount() + 1; - int *result = (int *)mir_alloc(sizeof(int) * count); - SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)result); - result[count-1] = -1; - return result; -} - -int CCtrlListBox::InsertString(TCHAR *text, int pos, LPARAM data) -{ - int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); - SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); - return iItem; -} - -void CCtrlListBox::ResetContent() -{ SendMessage(m_hwnd, LB_RESETCONTENT, 0, 0); -} - -int CCtrlListBox::SelectString(TCHAR *str) -{ return SendMessage(m_hwnd, LB_SELECTSTRING, 0, (LPARAM)str); -} - -int CCtrlListBox::SetCurSel(int index) -{ return SendMessage(m_hwnd, LB_SETCURSEL, index, 0); -} - -void CCtrlListBox::SetItemData(int index, LPARAM data) -{ SendMessage(m_hwnd, LB_SETITEMDATA, index, data); -} - -void CCtrlListBox::SetSel(int index, bool sel) -{ SendMessage(m_hwnd, LB_SETSEL, sel ? TRUE : FALSE, index); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCheck class - -CCtrlCheck::CCtrlCheck( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -int CCtrlCheck::GetState() -{ - return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); -} - -void CCtrlCheck::SetState(int state) -{ - SendMessage(m_hwnd, BM_SETCHECK, state, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlEdit class - -CCtrlEdit::CCtrlEdit( CDlgBase* dlg, int ctrlId ) : - CCtrlData( dlg, ctrlId ) -{ -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlData class - -CCtrlData::CCtrlData( CDlgBase *wnd, int idCtrl ) : - CCtrlBase( wnd, idCtrl ), - m_dbLink( NULL ) -{ -} - -void CCtrlData::OnInit() -{ - CCtrlBase::OnInit(); - m_changed = false; -} - -void CCtrlData::NotifyChange() -{ - if (!m_parentWnd || m_parentWnd->IsInitialized()) m_changed = true; - if ( m_parentWnd ) { - m_parentWnd->OnChange(this); - if ( m_parentWnd->IsInitialized()) - ::SendMessage( ::GetParent( m_parentWnd->GetHwnd()), PSM_CHANGED, 0, 0 ); - } - - OnChange(this); -} - -void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue, bool bSigned ) -{ - m_dbLink = new CDbLink( szModuleName, szSetting, type, iValue, bSigned ); -} - -void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ) -{ - m_dbLink = new CDbLink( szModuleName, szSetting, DBVT_TCHAR, szValue ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlMButton - -CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ) : - CCtrlButton( dlg, ctrlId ), - m_hIcon( hIcon ), - m_toolTip( tooltip ) -{ -} - -CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ) : - CCtrlButton( dlg, ctrlId ), - m_hIcon( LoadSkinnedIcon(iCoreIcon)), - m_toolTip( tooltip ) -{ -} - -CCtrlMButton::~CCtrlMButton() -{ - g_ReleaseIcon( m_hIcon ); -} - -void CCtrlMButton::OnInit() -{ - CCtrlButton::OnInit(); - - SendMessage( m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon ); - SendMessage( m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0); - SendMessage( m_hwnd, BUTTONSETASFLATBTN, (WPARAM)m_toolTip, 0); -} - -void CCtrlMButton::MakeFlat() -{ - SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0); -} - -void CCtrlMButton::MakePush() -{ - SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -CCtrlButton::CCtrlButton( CDlgBase* wnd, int idCtrl ) : - CCtrlBase( wnd, idCtrl ) -{ -} - -BOOL CCtrlButton::OnCommand(HWND, WORD, WORD idCode) -{ - if ( idCode == BN_CLICKED || idCode == STN_CLICKED ) - OnClick(this); - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlHyperlink - -CCtrlHyperlink::CCtrlHyperlink( CDlgBase* wnd, int idCtrl, const char* url ) : - CCtrlBase( wnd, idCtrl ), - m_url(url) -{ -} - -BOOL CCtrlHyperlink::OnCommand(HWND, WORD, WORD) -{ - ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW); - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlClc -CCtrlClc::CCtrlClc( CDlgBase* dlg, int ctrlId ): - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh }; - switch (pnmh->code) - { - case CLN_EXPANDED: OnExpanded(&evt); break; - case CLN_LISTREBUILT: OnListRebuilt(&evt); break; - case CLN_ITEMCHECKED: OnItemChecked(&evt); break; - case CLN_DRAGGING: OnDragging(&evt); break; - case CLN_DROPPED: OnDropped(&evt); break; - case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break; - case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break; - case CLN_DRAGSTOP: OnDragStop(&evt); break; - case CLN_NEWCONTACT: OnNewContact(&evt); break; - case CLN_CONTACTMOVED: OnContactMoved(&evt); break; - case CLN_CHECKCHANGED: OnCheckChanged(&evt); break; - case NM_CLICK: OnClick(&evt); break; - } - return FALSE; -} - -void CCtrlClc::AddContact(HANDLE hContact) -{ SendMessage(m_hwnd, CLM_ADDCONTACT, (WPARAM)hContact, 0); -} - -void CCtrlClc::AddGroup(HANDLE hGroup) -{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0); -} - -void CCtrlClc::AutoRebuild() -{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0); -} - -void CCtrlClc::DeleteItem(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0); -} - -void CCtrlClc::EditLabel(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0); -} - -void CCtrlClc::EndEditLabel(bool save) -{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0); -} - -void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk) -{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE); -} - -void CCtrlClc::Expand(HANDLE hItem, DWORD flags) -{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags); -} - -HANDLE CCtrlClc::FindContact(HANDLE hContact) -{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, (WPARAM)hContact, 0); -} - -HANDLE CCtrlClc::FindGroup(HANDLE hGroup) -{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0); -} - -COLORREF CCtrlClc::GetBkColor() -{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0); -} - -bool CCtrlClc::GetCheck(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false; -} - -int CCtrlClc::GetCount() -{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0); -} - -HWND CCtrlClc::GetEditControl() -{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0); -} - -DWORD CCtrlClc::GetExpand(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0); -} - -int CCtrlClc::GetExtraColumns() -{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0); -} - -BYTE CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) -{ return (BYTE)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFF); -} - -HIMAGELIST CCtrlClc::GetExtraImageList() -{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0); -} - -HFONT CCtrlClc::GetFont(int iFontId) -{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0); -} - -HANDLE CCtrlClc::GetSelection() -{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0); -} - -HANDLE CCtrlClc::HitTest(int x, int y, DWORD *hitTest) -{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y)); -} - -void CCtrlClc::SelectItem(HANDLE hItem) -{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0); -} - -void CCtrlClc::SetBkBitmap(DWORD mode, HBITMAP hBitmap) -{ SendMessage(m_hwnd, CLM_SETBKBITMAP, mode, (LPARAM)hBitmap); -} - -void CCtrlClc::SetBkColor(COLORREF clBack) -{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0); -} - -void CCtrlClc::SetCheck(HANDLE hItem, bool check) -{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0); -} - -void CCtrlClc::SetExtraColumns(int iColumns) -{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0); -} - -void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage) -{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); -} - -void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList) -{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList); -} - -void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw) -{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId)); -} - -void CCtrlClc::SetIndent(int iIndent) -{ SendMessage(m_hwnd, CLM_SETINDENT, (WPARAM)iIndent, 0); -} - -void CCtrlClc::SetItemText(HANDLE hItem, char *szText) -{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText); -} - -void CCtrlClc::SetHideEmptyGroups(bool state) -{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0); -} - -void CCtrlClc::SetGreyoutFlags(DWORD flags) -{ SendMessage(m_hwnd, CLM_SETGREYOUTFLAGS, (WPARAM)flags, 0); -} - -bool CCtrlClc::GetHideOfflineRoot() -{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false; -} - -void CCtrlClc::SetHideOfflineRoot(bool state) -{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9); -} - -void CCtrlClc::SetUseGroups(bool state) -{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0); -} - -void CCtrlClc::SetOfflineModes(DWORD modes) -{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0); -} - -DWORD CCtrlClc::GetExStyle() -{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0); -} - -void CCtrlClc::SetExStyle(DWORD exStyle) -{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0); -} - -int CCtrlClc::GetLefrMargin() -{ return SendMessage(m_hwnd, CLM_GETLEFTMARGIN, 0, 0); -} - -void CCtrlClc::SetLeftMargin(int iMargin) -{ SendMessage(m_hwnd, CLM_SETLEFTMARGIN, (WPARAM)iMargin, 0); -} - -HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii) -{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii); -} - -int CCtrlClc::GetItemType(HANDLE hItem) -{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0); -} - -HANDLE CCtrlClc::GetNextItem(HANDLE hItem, DWORD flags) -{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem); -} - -COLORREF CCtrlClc::GetTextColot(int iFontId) -{ return (COLORREF)SendMessage(m_hwnd, CLM_GETTEXTCOLOR, (WPARAM)iFontId, 0); -} - -void CCtrlClc::SetTextColor(int iFontId, COLORREF clText) -{ SendMessage(m_hwnd, CLM_SETTEXTCOLOR, (WPARAM)iFontId, (LPARAM)clText); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListView - -CCtrlListView::CCtrlListView( CDlgBase* dlg, int ctrlId ) : - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, pnmh }; - - switch (pnmh->code) { - case NM_DBLCLK: OnDoubleClick(&evt); return TRUE; - case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; - case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; - case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; - case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE; - case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE; - case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE; - case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; - case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; - case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE; - case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; - case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; - case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE; - //case LVN_INCREMENTALSEARCH: OnIncrementalSearch(&evt); return TRUE; - case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE; - case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE; - case LVN_ITEMCHANGED: OnItemChanged(&evt); return TRUE; - case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE; - case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE; - case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE; - case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; - } - - return FALSE; -} - -// additional api -HIMAGELIST CCtrlListView::CreateImageList(int iImageList) -{ - HIMAGELIST hIml; - if (hIml = GetImageList(iImageList)) - return hIml; - - hIml = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32|ILC_MASK : ILC_COLOR16|ILC_MASK, 0, 1); - SetImageList(hIml, iImageList); - return hIml; -} - -void CCtrlListView::AddColumn(int iSubItem, TCHAR *name, int cx) -{ - LVCOLUMN lvc; - lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; - lvc.iImage = 0; - lvc.pszText = name; - lvc.cx = cx; - lvc.iSubItem = iSubItem; - InsertColumn(iSubItem, &lvc); -} - -void CCtrlListView::AddGroup(int iGroupId, TCHAR *name) -{ - if (IsWinVerXPPlus()) - { - LVGROUP lvg = {0}; - lvg.cbSize = sizeof(lvg); - lvg.mask = LVGF_HEADER|LVGF_GROUPID; - lvg.pszHeader = name; - lvg.cchHeader = lstrlen(lvg.pszHeader); - lvg.iGroupId = iGroupId; - InsertGroup(-1, &lvg); - } -} - -int CCtrlListView::AddItem(TCHAR *text, int iIcon, LPARAM lParam, int iGroupId) -{ - LVITEM lvi = {0}; - lvi.mask = LVIF_PARAM|LVIF_TEXT|LVIF_IMAGE; - lvi.iSubItem = 0; - lvi.pszText = text; - lvi.iImage = iIcon; - lvi.lParam = lParam; - - - if ((iGroupId >= 0) && IsWinVerXPPlus()) - { - lvi.mask |= LVIF_GROUPID; - lvi.iGroupId = iGroupId; - } - - - return InsertItem(&lvi); -} - -void CCtrlListView::SetItem(int iItem, int iSubItem, TCHAR *text, int iIcon) -{ - LVITEM lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = iItem; - lvi.iSubItem = iSubItem; - lvi.pszText = text; - - if (iIcon >= 0) - { - lvi.mask |= LVIF_IMAGE; - lvi.iImage = iIcon; - } - - SetItem(&lvi); -} - -LPARAM CCtrlListView::GetItemData(int iItem) -{ - LVITEM lvi = {0}; - lvi.mask = LVIF_PARAM; - lvi.iItem = iItem; - GetItem(&lvi); - return lvi.lParam; -} - -// classic api -DWORD CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount) -{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount); -} -void CCtrlListView::Arrange(UINT code) -{ ListView_Arrange(m_hwnd, code); -} -void CCtrlListView::CancelEditLabel() -{ ListView_CancelEditLabel(m_hwnd); -} -HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft) -{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft); -} -void CCtrlListView::DeleteAllItems() -{ ListView_DeleteAllItems(m_hwnd); -} -void CCtrlListView::DeleteColumn(int iCol) -{ ListView_DeleteColumn(m_hwnd, iCol); -} -void CCtrlListView::DeleteItem(int iItem) -{ ListView_DeleteItem(m_hwnd, iItem); -} -HWND CCtrlListView::EditLabel(int iItem) -{ return ListView_EditLabel(m_hwnd, iItem); -} -int CCtrlListView::EnableGroupView(BOOL fEnable) -{ return ListView_EnableGroupView(m_hwnd, fEnable); -} -BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK) -{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK); -} -int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi) -{ return ListView_FindItem(m_hwnd, iStart, plvfi); -} -COLORREF CCtrlListView::GetBkColor() -{ return ListView_GetBkColor(m_hwnd); -} -void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) -{ ListView_GetBkImage(m_hwnd, plvbki); -} -UINT CCtrlListView::GetCallbackMask() -{ return ListView_GetCallbackMask(m_hwnd); -} -BOOL CCtrlListView::GetCheckState(UINT iIndex) -{ return ListView_GetCheckState(m_hwnd, iIndex); -} -void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) -{ ListView_GetColumn(m_hwnd, iCol, pcol); -} -void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) -{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray); -} -int CCtrlListView::GetColumnWidth(int iCol) -{ return ListView_GetColumnWidth(m_hwnd, iCol); -} -int CCtrlListView::GetCountPerPage() -{ return ListView_GetCountPerPage(m_hwnd); -} -HWND CCtrlListView::GetEditControl() -{ return ListView_GetEditControl(m_hwnd); -} -//void CCtrlListView::GetEmptyText(PWSTR pszText, UINT cchText) -//{ ListView_GetEmptyText(m_hwnd, pszText, cchText); -//} -DWORD CCtrlListView::GetExtendedListViewStyle() -{ return ListView_GetExtendedListViewStyle(m_hwnd); -} -//INT CCtrlListView::GetFocusedGroup() -//{ return ListView_GetFocusedGroup(m_hwnd); -//} -//void CCtrlListView::GetFooterInfo(LPLVFOOTERINFO plvfi) -//{ ListView_GetFooterInfo(m_hwnd, plvfi); -//} -//void CCtrlListView::GetFooterItem(UINT iItem, LVFOOTERITEM *pfi) -//{ ListView_GetFooterItem(m_hwnd, iItem, pfi); -//} -//void CCtrlListView::GetFooterItemRect(UINT iItem, RECT *prc) -//{ ListView_GetFooterItemRect(m_hwnd, iItem, prc); -//} -//void CCtrlListView::GetFooterRect(RECT *prc) -//{ ListView_GetFooterRect(m_hwnd, prc); -//} -//int CCtrlListView::GetGroupCount() -//{ return ListView_GetGroupCount(m_hwnd); -//} -//HIMAGELIST CCtrlListView::GetGroupHeaderImageList() -//{ return ListView_GetGroupHeaderImageList(m_hwnd); -//} -//void CCtrlListView::GetGroupInfo(int iGroupId, PLVGROUP pgrp) -//{ ListView_GetGroupInfo(m_hwnd, iGroupId, pgrp); -//} -//void CCtrlListView::GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) -//{ ListView_GetGroupInfoByIndex(m_hwnd, iIndex, pgrp); -//} -void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) -{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics); -} -//BOOL CCtrlListView::GetGroupRect(int iGroupId, RECT *prc) -//{ return ListView_GetGroupRect(m_hwnd, iGroupId, prc); -//} -//UINT CCtrlListView::GetGroupState(UINT dwGroupId, UINT dwMask) -//{ return ListView_GetGroupState(m_hwnd, dwGroupId, dwMask); -//} -HWND CCtrlListView::GetHeader() -{ return ListView_GetHeader(m_hwnd); -} -HCURSOR CCtrlListView::GetHotCursor() -{ return ListView_GetHotCursor(m_hwnd); -} -INT CCtrlListView::GetHotItem() -{ return ListView_GetHotItem(m_hwnd); -} -DWORD CCtrlListView::GetHoverTime() -{ return ListView_GetHoverTime(m_hwnd); -} -HIMAGELIST CCtrlListView::GetImageList(int iImageList) -{ return ListView_GetImageList(m_hwnd, iImageList); -} -BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) -{ return ListView_GetInsertMark(m_hwnd, plvim); -} -COLORREF CCtrlListView::GetInsertMarkColor() -{ return ListView_GetInsertMarkColor(m_hwnd); -} -int CCtrlListView::GetInsertMarkRect(LPRECT prc) -{ return ListView_GetInsertMarkRect(m_hwnd, prc); -} -BOOL CCtrlListView::GetISearchString(LPSTR lpsz) -{ return ListView_GetISearchString(m_hwnd, lpsz); -} -void CCtrlListView::GetItem(LPLVITEM pitem) -{ ListView_GetItem(m_hwnd, pitem); -} -int CCtrlListView::GetItemCount() -{ return ListView_GetItemCount(m_hwnd); -} -//void CCtrlListView::GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc) -//{ ListView_GetItemIndexRect(m_hwnd, plvii, iSubItem, code, prc); -//} -void CCtrlListView::GetItemPosition(int i, POINT *ppt) -{ ListView_GetItemPosition(m_hwnd, i, ppt); -} -void CCtrlListView::GetItemRect(int i, RECT *prc, int code) -{ ListView_GetItemRect(m_hwnd, i, prc, code); -} -DWORD CCtrlListView::GetItemSpacing(BOOL fSmall) -{ return ListView_GetItemSpacing(m_hwnd, fSmall); -} -UINT CCtrlListView::GetItemState(int i, UINT mask) -{ return ListView_GetItemState(m_hwnd, i, mask); -} -void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) -{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax); -} -int CCtrlListView::GetNextItem(int iStart, UINT flags) -{ return ListView_GetNextItem(m_hwnd, iStart, flags); -} -//BOOL CCtrlListView::GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags) -//{ return ListView_GetNextItemIndex(m_hwnd, plvii, flags); -//} -BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) -{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas); -} -BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) -{ return ListView_GetOrigin(m_hwnd, lpptOrg); -} -COLORREF CCtrlListView::GetOutlineColor() -{ return ListView_GetOutlineColor(m_hwnd); -} -UINT CCtrlListView::GetSelectedColumn() -{ return ListView_GetSelectedColumn(m_hwnd); -} -UINT CCtrlListView::GetSelectedCount() -{ return ListView_GetSelectedCount(m_hwnd); -} -INT CCtrlListView::GetSelectionMark() -{ return ListView_GetSelectionMark(m_hwnd); -} -int CCtrlListView::GetStringWidth(LPCSTR psz) -{ return ListView_GetStringWidth(m_hwnd, psz); -} -BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) -{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect); -} -COLORREF CCtrlListView::GetTextBkColor() -{ return ListView_GetTextBkColor(m_hwnd); -} -COLORREF CCtrlListView::GetTextColor() -{ return ListView_GetTextColor(m_hwnd); -} -void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) -{ ListView_GetTileInfo(m_hwnd, plvtinfo); -} -void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) -{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo); -} -HWND CCtrlListView::GetToolTips() -{ return ListView_GetToolTips(m_hwnd); -} -int CCtrlListView::GetTopIndex() -{ return ListView_GetTopIndex(m_hwnd); -} -BOOL CCtrlListView::GetUnicodeFormat() -{ return ListView_GetUnicodeFormat(m_hwnd); -} -DWORD CCtrlListView::GetView() -{ return ListView_GetView(m_hwnd); -} -BOOL CCtrlListView::GetViewRect(RECT *prc) -{ return ListView_GetViewRect(m_hwnd, prc); -} -void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) -{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc); -} -BOOL CCtrlListView::HasGroup(int dwGroupId) -{ return ListView_HasGroup(m_hwnd, dwGroupId); -} -int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) -{ return ListView_HitTest(m_hwnd, pinfo); -} -//int CCtrlListView::HitTestEx(LPLVHITTESTINFO pinfo) -//{ return ListView_HitTestEx(m_hwnd, pinfo); -//} -int CCtrlListView::InsertColumn(int iCol, const LPLVCOLUMN pcol) -{ return ListView_InsertColumn(m_hwnd, iCol, pcol); -} -int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp) -{ return ListView_InsertGroup(m_hwnd, index, pgrp); -} -void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert) -{ ListView_InsertGroupSorted(m_hwnd, structInsert); -} -int CCtrlListView::InsertItem(const LPLVITEM pitem) -{ return ListView_InsertItem(m_hwnd, pitem); -} -BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim) -{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim); -} -BOOL CCtrlListView::IsGroupViewEnabled() -{ return ListView_IsGroupViewEnabled(m_hwnd); -} -//UINT CCtrlListView::IsItemVisible(UINT index) -//{ return ListView_IsItemVisible(m_hwnd, index); -//} -UINT CCtrlListView::MapIDToIndex(UINT id) -{ return ListView_MapIDToIndex(m_hwnd, id); -} -UINT CCtrlListView::MapIndexToID(UINT index) -{ return ListView_MapIndexToID(m_hwnd, index); -} -BOOL CCtrlListView::RedrawItems(int iFirst, int iLast) -{ return ListView_RedrawItems(m_hwnd, iFirst, iLast); -} -void CCtrlListView::RemoveAllGroups() -{ ListView_RemoveAllGroups(m_hwnd); -} -int CCtrlListView::RemoveGroup(int iGroupId) -{ return ListView_RemoveGroup(m_hwnd, iGroupId); -} -BOOL CCtrlListView::Scroll(int dx, int dy) -{ return ListView_Scroll(m_hwnd, dx, dy); -} -BOOL CCtrlListView::SetBkColor(COLORREF clrBk) -{ return ListView_SetBkColor(m_hwnd, clrBk); -} -BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki) -{ return ListView_SetBkImage(m_hwnd, plvbki); -} -BOOL CCtrlListView::SetCallbackMask(UINT mask) -{ return ListView_SetCallbackMask(m_hwnd, mask); -} -void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck) -{ ListView_SetCheckState(m_hwnd, iIndex, fCheck); -} -BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol) -{ return ListView_SetColumn(m_hwnd, iCol, pcol); -} -BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray) -{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray); -} -BOOL CCtrlListView::SetColumnWidth(int iCol, int cx) -{ return ListView_SetColumnWidth(m_hwnd, iCol, cx); -} -void CCtrlListView::SetExtendedListViewStyle(DWORD dwExStyle) -{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle); -} -void CCtrlListView::SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle) -{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle); -} -//HIMAGELIST CCtrlListView::SetGroupHeaderImageList(HIMAGELIST himl) -//{ return ListView_SetGroupHeaderImageList(m_hwnd, himl); -//} -int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp) -{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp); -} -void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) -{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics); -} -//void CCtrlListView::SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState) -//{ ListView_SetGroupState(m_hwnd, dwGroupId, dwMask, dwState); -//} -HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor) -{ return ListView_SetHotCursor(m_hwnd, hCursor); -} -INT CCtrlListView::SetHotItem(INT iIndex) -{ return ListView_SetHotItem(m_hwnd, iIndex); -} -void CCtrlListView::SetHoverTime(DWORD dwHoverTime) -{ ListView_SetHoverTime(m_hwnd, dwHoverTime); -} -DWORD CCtrlListView::SetIconSpacing(int cx, int cy) -{ return ListView_SetIconSpacing(m_hwnd, cx, cy); -} -HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList) -{ return ListView_SetImageList(m_hwnd, himl, iImageList); -} -BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip) -{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip); -} -BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim) -{ return ListView_SetInsertMark(m_hwnd, plvim); -} -COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color) -{ return ListView_SetInsertMarkColor(m_hwnd, color); -} -BOOL CCtrlListView::SetItem(const LPLVITEM pitem) -{ return ListView_SetItem(m_hwnd, pitem); -} -void CCtrlListView::SetItemCount(int cItems) -{ ListView_SetItemCount(m_hwnd, cItems); -} -void CCtrlListView::SetItemCountEx(int cItems, DWORD dwFlags) -{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags); -} -//HRESULT CCtrlListView::SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask) -//{ return ListView_SetItemIndexState(m_hwnd, plvii, data, mask); -//} -BOOL CCtrlListView::SetItemPosition(int i, int x, int y) -{ return ListView_SetItemPosition(m_hwnd, i, x, y); -} -void CCtrlListView::SetItemPosition32(int iItem, int x, int y) -{ ListView_SetItemPosition32(m_hwnd, iItem, x, y); -} -void CCtrlListView::SetItemState(int i, UINT state, UINT mask) -{ ListView_SetItemState(m_hwnd, i, state, mask); -} -void CCtrlListView::SetItemText(int i, int iSubItem, TCHAR *pszText) -{ ListView_SetItemText(m_hwnd, i, iSubItem, pszText); -} -COLORREF CCtrlListView::SetOutlineColor(COLORREF color) -{ return ListView_SetOutlineColor(m_hwnd, color); -} -void CCtrlListView::SetSelectedColumn(int iCol) -{ ListView_SetSelectedColumn(m_hwnd, iCol); -} -INT CCtrlListView::SetSelectionMark(INT iIndex) -{ return ListView_SetSelectionMark(m_hwnd, iIndex); -} -BOOL CCtrlListView::SetTextBkColor(COLORREF clrText) -{ return ListView_SetTextBkColor(m_hwnd, clrText); -} -BOOL CCtrlListView::SetTextColor(COLORREF clrText) -{ return ListView_SetTextColor(m_hwnd, clrText); -} -BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo) -{ return ListView_SetTileInfo(m_hwnd, plvtinfo); -} -BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) -{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo); -} -HWND CCtrlListView::SetToolTips(HWND ToolTip) -{ return ListView_SetToolTips(m_hwnd, ToolTip); -} -BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode) -{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode); -} -int CCtrlListView::SetView(DWORD iView) -{ return ListView_SetView(m_hwnd, iView); -} -void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc) -{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc); -} -int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv) -{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv); -} -BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) -{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort); -} -BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) -{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort); -} -INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) -{ return ListView_SubItemHitTest(m_hwnd, pInfo); -} -//INT CCtrlListView::SubItemHitTestEx(LPLVHITTESTINFO plvhti) -//{ return ListView_SubItemHitTestEx(m_hwnd, plvhti); -//} -BOOL CCtrlListView::Update(int iItem) -{ return ListView_Update(m_hwnd, iItem); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlFilterListView - -#define FILTER_BOX_HEIGHT 21 - -struct CFilterData : public MZeroedObject -{ - HFONT m_hfntNormal; - HFONT m_hfntEmpty; - COLORREF m_clGray; - TCHAR *m_filterText; - - RECT m_rcButtonClear; - RECT m_rcEditBox; - - WNDPROC m_oldWndProc; - HWND m_hwndOwner; - HWND m_hwndEditBox; - - void ReleaseFilterData() - { - //DeleteObject(m_hfntNormal); m_hfntNormal = NULL; // managed by system - DeleteObject(m_hfntEmpty); m_hfntEmpty = NULL; - } - - ~CFilterData() - { - ReleaseFilterData(); - } -}; - -CCtrlFilterListView::CCtrlFilterListView(CDlgBase* dlg, int ctrlId, bool trackFilter, bool keepHiglight): - CCtrlListView(dlg, ctrlId), - m_trackFilter(trackFilter), - m_keepHiglight(keepHiglight) -{ - fdat = new CFilterData; -} - -CCtrlFilterListView::~CCtrlFilterListView() -{ - if (fdat->m_filterText) mir_free(fdat->m_filterText); - delete fdat; -} - -TCHAR *CCtrlFilterListView::GetFilterText() -{ - return fdat->m_filterText; -} - -void CCtrlFilterListView::OnInit() -{ - CSuper::OnInit(); - Subclass(); -} - -static LRESULT CALLBACK sttEditBoxSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CFilterData *fdat = (CFilterData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!fdat) return DefWindowProc(hwnd, msg, wParam, lParam); - - switch (msg) - { - case WM_GETDLGCODE: - if ((wParam == VK_RETURN) || (wParam == VK_ESCAPE)) - return DLGC_WANTMESSAGE; - break; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - if (wParam == VK_RETURN) - { - if (fdat->m_filterText) mir_free(fdat->m_filterText); - int length = GetWindowTextLength(hwnd) + 1; - if (length == 1) - { - fdat->m_filterText = 0; - } else - { - fdat->m_filterText = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); - GetWindowText(hwnd, fdat->m_filterText, length); - } - - DestroyWindow(hwnd); - RedrawWindow(fdat->m_hwndOwner, NULL, NULL, RDW_INVALIDATE|RDW_FRAME); - PostMessage(fdat->m_hwndOwner, WM_APP, 0, 0); - } else - if (wParam == VK_ESCAPE) - { - DestroyWindow(hwnd); - return 0; - } else - { - PostMessage(fdat->m_hwndOwner, WM_APP, 1, 0); - } - - break; - } - - case WM_KILLFOCUS: - { - DestroyWindow(hwnd); - return 0; - } - - case WM_DESTROY: - { - fdat->m_hwndEditBox = NULL; - } - } - - return CallWindowProc(fdat->m_oldWndProc, hwnd, msg, wParam, lParam); -} - -void CCtrlFilterListView::FilterHighlight(TCHAR *str) -{ - TCHAR buf[256]; - int count = GetItemCount(); - for (int i = 0; i < count; ++i) - { - bool found = false; - - if (str) - { - for (int j = 0; j < 10; ++j) - { - GetItemText(i, j, buf, SIZEOF(buf)); - if (!*buf) - break; - - if (_tcsstr(buf, str)) - { - found = true; - break; - } - } - } - - SetItemState(i, found ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED); - } -} - -LRESULT CCtrlFilterListView::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_APP: - { - switch (wParam) - { - case 0: - { - OnFilterChanged(this); - if (!m_keepHiglight) FilterHighlight(NULL); - break; - } - - case 1: - { - if (m_trackFilter && fdat->m_hwndEditBox) - { - TCHAR *str = 0; - int length = GetWindowTextLength(fdat->m_hwndEditBox) + 1; - if (length == 1) - { - str = 0; - } else - { - str = (TCHAR *)mir_alloc(sizeof(TCHAR) * length); - GetWindowText(fdat->m_hwndEditBox, str, length); - } - FilterHighlight(str); - if (str) mir_free(str); - } - break; - } - - case 2: - { - fdat->m_hwndOwner = m_hwnd; - fdat->m_hwndEditBox = CreateWindow(_T("edit"), fdat->m_filterText, - WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, - 0, 0, 0, 0, - ::GetParent(m_hwnd), (HMENU)-1, hInst, NULL); - - SendMessage(fdat->m_hwndEditBox, WM_SETFONT, (WPARAM)fdat->m_hfntNormal, 0); - - RECT rc = fdat->m_rcEditBox; - MapWindowPoints(m_hwnd, ::GetParent(m_hwnd), (LPPOINT)&rc, 2); - SetWindowPos(fdat->m_hwndEditBox, HWND_TOP, rc.left-5, rc.top+2, rc.right-rc.left, rc.bottom-rc.top-4, SWP_SHOWWINDOW); - SendMessage(fdat->m_hwndEditBox, EM_SETSEL, 0, -1); - - fdat->m_oldWndProc = (WNDPROC)GetWindowLongPtr(fdat->m_hwndEditBox, GWLP_WNDPROC); - SetWindowLongPtr(fdat->m_hwndEditBox, GWLP_USERDATA, (LONG_PTR)fdat); - SetWindowLongPtr(fdat->m_hwndEditBox, GWLP_WNDPROC, (LONG_PTR)sttEditBoxSubclassProc); - - SetFocus(m_hwnd); // hack to avoid popping of list over the box... - SetFocus(fdat->m_hwndEditBox); - break; - } - } - break; - } - - case WM_NCCALCSIZE: - { - RECT *prect = (RECT *)lParam; - - CSuper::CustomWndProc(msg, wParam, lParam); - prect->bottom -= FILTER_BOX_HEIGHT; - - fdat->ReleaseFilterData(); - - fdat->m_hfntNormal = (HFONT)SendMessage(m_hwnd, WM_GETFONT, 0, 0); - if (!fdat->m_hfntNormal) fdat->m_hfntNormal = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - - LOGFONT lf; - GetObject(fdat->m_hfntNormal, sizeof(lf), &lf); - lf.lfItalic = TRUE; - fdat->m_hfntEmpty = CreateFontIndirect(&lf); - - COLORREF clText = GetSysColor(COLOR_WINDOWTEXT); - COLORREF clBack = GetSysColor(COLOR_WINDOW); - fdat->m_clGray = RGB( - (GetRValue(clBack) + 2*GetRValue(clText)) / 3, - (GetGValue(clBack) + 2*GetGValue(clText)) / 3, - (GetBValue(clBack) + 2*GetBValue(clText)) / 3 - ); - - if (fdat->m_hwndEditBox) DestroyWindow(fdat->m_hwndEditBox); - - return 0; - } - - case WM_NCPAINT: - { -/* - { - HRGN hrgnUpdate, hrgnTmp; - RECT rc; - GetWindowRect(m_hwnd, &rc); - OffsetRect(&rc, -rc.left, -rc.top); - - RECT rcClient; - GetClientRect(m_hwnd, &rcClient); - - hrgnTmp = CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); - if (wParam == 1) - { - hrgnUpdate = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); - CombineRgn(hrgnUpdate, hrgnUpdate, hrgnTmp, RGN_DIFF); - } else - { - hrgnUpdate = CreateRectRgn(0, 0, 0, 0); - CombineRgn(hrgnUpdate, (HRGN)wParam, hrgnTmp, RGN_DIFF); - } - DeleteObject(hrgnTmp); - - InflateRect(&rc, -1, -1); - rc.top = rc.bottom - FILTER_BOX_HEIGHT; - hrgnTmp = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); - CombineRgn(hrgnUpdate, hrgnUpdate, hrgnTmp, RGN_DIFF); - DeleteObject(hrgnTmp); - - CSuper::CustomWndProc(msg, (WPARAM)hrgnUpdate, lParam); - DeleteObject(hrgnUpdate); - } -*/ - CSuper::CustomWndProc(msg, wParam, lParam); - - RECT rc; - GetWindowRect(m_hwnd, &rc); - OffsetRect(&rc, -rc.left, -rc.top); - InflateRect(&rc, -1, -1); - rc.top = rc.bottom - FILTER_BOX_HEIGHT; - - POINT pts[] = { - {rc.left, rc.top}, - {rc.left+FILTER_BOX_HEIGHT, rc.top}, - {rc.left+FILTER_BOX_HEIGHT+FILTER_BOX_HEIGHT/2+1, rc.top+FILTER_BOX_HEIGHT/2+1}, - {rc.left+FILTER_BOX_HEIGHT, rc.top+FILTER_BOX_HEIGHT}, - {rc.left, rc.top+FILTER_BOX_HEIGHT}, - }; - HRGN hrgnFilter = CreatePolygonRgn(pts, SIZEOF(pts), ALTERNATE); - - HDC hdc = GetWindowDC(m_hwnd); - - FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW)); - FillRgn(hdc, hrgnFilter, GetSysColorBrush(COLOR_BTNFACE)); - - SetBkMode(hdc, TRANSPARENT); - - if (fdat->m_filterText) - { - SetRect(&fdat->m_rcButtonClear, - rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, - rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2 + 16, rc.top + (FILTER_BOX_HEIGHT-16)/2 + 16); - - DrawIconEx(hdc, rc.left + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, g_LoadIconEx("sd_filter_apply"), 16, 16, 0, NULL, DI_NORMAL); - DrawIconEx(hdc, rc.right - FILTER_BOX_HEIGHT + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, LoadSkinnedIcon(SKINICON_OTHER_DELETE), 16, 16, 0, NULL, DI_NORMAL); - - rc.left += 5*FILTER_BOX_HEIGHT/3; - rc.right -= 5*FILTER_BOX_HEIGHT/3; - - fdat->m_rcEditBox = rc; - - SelectObject(hdc, fdat->m_hfntNormal); - ::SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - DrawText(hdc, fdat->m_filterText, -1, &rc, DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS); - } else - { - SetRect(&fdat->m_rcButtonClear, 0, 0, 0, 0); - - DrawIconEx(hdc, rc.left + (FILTER_BOX_HEIGHT-16)/2, rc.top + (FILTER_BOX_HEIGHT-16)/2, g_LoadIconEx("sd_filter_reset"), 16, 16, 0, NULL, DI_NORMAL); - - rc.left += 5*FILTER_BOX_HEIGHT/3; - rc.right -= 5; - - fdat->m_rcEditBox = rc; - - SelectObject(hdc, fdat->m_hfntEmpty); - ::SetTextColor(hdc, fdat->m_clGray); - DrawText(hdc, TranslateT("Set filter..."), -1, &rc, DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS); - } - - ReleaseDC(m_hwnd, hdc); - - DeleteObject(hrgnFilter); - - return 0; - } - - case WM_NCHITTEST: - { - POINT pt; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - MapWindowPoints(NULL, m_hwnd, &pt, 1); - - if(PtInRect(&fdat->m_rcButtonClear, pt)) - return HTBORDER; - if(PtInRect(&fdat->m_rcEditBox, pt)) - return HTBORDER; - - break; - } - - case WM_NCLBUTTONUP: - { - POINT pt; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - MapWindowPoints(NULL, m_hwnd, &pt, 1); - - if(PtInRect(&fdat->m_rcButtonClear, pt)) - { - SetFocus(m_hwnd); - if (fdat->m_filterText) mir_free(fdat->m_filterText); - fdat->m_filterText = NULL; - RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME); - OnFilterChanged(this); - FilterHighlight(NULL); - } else - if(PtInRect(&fdat->m_rcEditBox, pt)) - { - PostMessage(m_hwnd, WM_APP, 2, 0); - } - - break; - } - - case WM_KEYDOWN: - { - if (wParam == 'F' && GetAsyncKeyState(VK_CONTROL)) - PostMessage(m_hwnd, WM_APP, 2, 0); - break; - } - } - - return CSuper::CustomWndProc(msg, wParam, lParam); -} -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -CCtrlTreeView::CCtrlTreeView( CDlgBase* dlg, int ctrlId ): - CCtrlBase(dlg, ctrlId) -{ -} - -BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, pnmh }; - - switch (pnmh->code) - { - case TVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; - case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; - case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; - case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; - case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; - case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; - case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; - case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; - case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; - case TVN_KEYDOWN: OnKeyDown(&evt); return TRUE; - case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; - case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; - case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; - case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; - } - - return FALSE; -} - -void CCtrlTreeView::TranslateItem(HTREEITEM hItem) -{ - TCHAR buf[128]; - TVITEMEX tvi; - - GetItem(hItem, &tvi, buf, SIZEOF(buf)); - tvi.pszText = TranslateTS(tvi.pszText); - tvi.cchTextMax = lstrlen(tvi.pszText); - SetItem(&tvi); -} - -void CCtrlTreeView::TranslateTree() -{ - HTREEITEM hItem = GetRoot(); - while (hItem) - { - TranslateItem(hItem); - - HTREEITEM hItemTmp = 0; - if (hItemTmp = GetChild(hItem)) - hItem = hItemTmp; - else if (hItemTmp = GetNextSibling(hItem)) - hItem = hItemTmp; - else - { - while (1) - { - if (!(hItem = GetParent(hItem))) break; - if (hItemTmp = GetNextSibling(hItem)) - { - hItem = hItemTmp; - break; - } - } - } - } -} - -HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const TCHAR *name) -{ - TVITEMEX tvi = {0}; - TCHAR str[MAX_PATH]; - - if (hItem) - tvi.hItem = GetChild(hItem); - else - tvi.hItem = GetRoot(); - - if (!name) - return tvi.hItem; - - tvi.mask = TVIF_TEXT; - tvi.pszText = str; - tvi.cchTextMax = SIZEOF(str); - - while (tvi.hItem) - { - GetItem(&tvi); - - if (!lstrcmp(tvi.pszText, name)) - return tvi.hItem; - - tvi.hItem = GetNextSibling(tvi.hItem); - } - return NULL; -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) -{ - ZeroMemory(tvi, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE; - tvi->hItem = hItem; - GetItem(tvi); -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength) -{ - ZeroMemory(tvi, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT; - tvi->hItem = hItem; - tvi->pszText = szText; - tvi->cchTextMax = iTextLength; - GetItem(tvi); -} - -HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) -{ return TreeView_CreateDragImage(m_hwnd, hItem); -} - -void CCtrlTreeView::DeleteAllItems() -{ TreeView_DeleteAllItems(m_hwnd); -} - -void CCtrlTreeView::DeleteItem(HTREEITEM hItem) -{ TreeView_DeleteItem(m_hwnd, hItem); -} - -HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) -{ return TreeView_EditLabel(m_hwnd, hItem); -} - -void CCtrlTreeView::EndEditLabelNow(BOOL cancel) -{ TreeView_EndEditLabelNow(m_hwnd, cancel); -} - -void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) -{ TreeView_EnsureVisible(m_hwnd, hItem); -} - -void CCtrlTreeView::Expand(HTREEITEM hItem, DWORD flag) -{ TreeView_Expand(m_hwnd, hItem, flag); -} - -COLORREF CCtrlTreeView::GetBkColor() -{ return TreeView_GetBkColor(m_hwnd); -} - -DWORD CCtrlTreeView::GetCheckState(HTREEITEM hItem) -{ return TreeView_GetCheckState(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) -{ return TreeView_GetChild(m_hwnd, hItem); -} - -int CCtrlTreeView::GetCount() -{ return TreeView_GetCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetDropHilight() -{ return TreeView_GetDropHilight(m_hwnd); -} - -HWND CCtrlTreeView::GetEditControl() -{ return TreeView_GetEditControl(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetFirstVisible() -{ return TreeView_GetFirstVisible(m_hwnd); -} - -HIMAGELIST CCtrlTreeView::GetImageList(int iImage) -{ return TreeView_GetImageList(m_hwnd, iImage); -} - -int CCtrlTreeView::GetIndent() -{ return TreeView_GetIndent(m_hwnd); -} - -COLORREF CCtrlTreeView::GetInsertMarkColor() -{ return TreeView_GetInsertMarkColor(m_hwnd); -} - -void CCtrlTreeView::GetItem(TVITEMEX *tvi) -{ TreeView_GetItem(m_hwnd, tvi); -} - -int CCtrlTreeView::GetItemHeight() -{ return TreeView_GetItemHeight(m_hwnd); -} - -void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) -{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); -} - -DWORD CCtrlTreeView::GetItemState(HTREEITEM hItem, DWORD stateMask) -{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); -} - -HTREEITEM CCtrlTreeView::GetLastVisible() -{ return TreeView_GetLastVisible(m_hwnd); -} - -COLORREF CCtrlTreeView::GetLineColor() -{ return TreeView_GetLineColor(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, DWORD flag) -{ return TreeView_GetNextItem(m_hwnd, hItem, flag); -} - -HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) -{ return TreeView_GetNextSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) -{ return TreeView_GetNextVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) -{ return TreeView_GetParent(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) -{ return TreeView_GetPrevSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) -{ return TreeView_GetPrevVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetRoot() -{ return TreeView_GetRoot(m_hwnd); -} - -DWORD CCtrlTreeView::GetScrollTime() -{ return TreeView_GetScrollTime(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetSelection() -{ return TreeView_GetSelection(m_hwnd); -} - -COLORREF CCtrlTreeView::GetTextColor() -{ return TreeView_GetTextColor(m_hwnd); -} - -HWND CCtrlTreeView::GetToolTips() -{ return TreeView_GetToolTips(m_hwnd); -} - -BOOL CCtrlTreeView::GetUnicodeFormat() -{ return TreeView_GetUnicodeFormat(m_hwnd); -} - -unsigned CCtrlTreeView::GetVisibleCount() -{ return TreeView_GetVisibleCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) -{ return TreeView_HitTest(m_hwnd, hti); -} - -HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) -{ return TreeView_InsertItem(m_hwnd, tvis); -} - -/* -HTREEITEM CCtrlTreeView::MapAccIDToHTREEITEM(UINT id) -{ return TreeView_MapAccIDToHTREEITEM(m_hwnd, id); -} - -UINT CCtrlTreeView::MapHTREEITEMtoAccID(HTREEITEM hItem) -{ return TreeView_MapHTREEITEMtoAccID(m_hwnd, hItem); -} - -*/ -void CCtrlTreeView::Select(HTREEITEM hItem, DWORD flag) -{ TreeView_Select(m_hwnd, hItem, flag); -} - -void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) -{ TreeView_SelectDropTarget(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectItem(HTREEITEM hItem) -{ TreeView_SelectItem(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) -{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); -} - -COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) -{ return TreeView_SetBkColor(m_hwnd, clBack); -} - -void CCtrlTreeView::SetCheckState(HTREEITEM hItem, DWORD state) -{ TreeView_SetCheckState(m_hwnd, hItem, state); -} - -void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) -{ TreeView_SetImageList(m_hwnd, hIml, iImage); -} - -void CCtrlTreeView::SetIndent(int iIndent) -{ TreeView_SetIndent(m_hwnd, iIndent); -} - -void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) -{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); -} - -COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) -{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); -} - -void CCtrlTreeView::SetItem(TVITEMEX *tvi) -{ TreeView_SetItem(m_hwnd, tvi); -} - -void CCtrlTreeView::SetItemHeight(short cyItem) -{ TreeView_SetItemHeight(m_hwnd, cyItem); -} - -void CCtrlTreeView::SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask) -{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); -} - -COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) -{ return TreeView_SetLineColor(m_hwnd, clLine); -} - -void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) -{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); -} - -COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) -{ return TreeView_SetTextColor(m_hwnd, clText); -} - -HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) -{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); -} - -BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) -{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); -} - -void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) -{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); -} - -void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) -{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlPages - -CCtrlPages::CCtrlPages( CDlgBase* dlg, int ctrlId ): - CCtrlBase(dlg, ctrlId), m_hIml(NULL), m_pActivePage(NULL) -{ -} - -void CCtrlPages::OnInit() -{ - CSuper::OnInit(); - Subclass(); -} - -LRESULT CCtrlPages::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_SIZE) - { - ShowPage(m_pActivePage); - } - - return CSuper::CustomWndProc(msg, wParam, lParam); -} - -void CCtrlPages::AddPage( TCHAR *ptszName, HICON hIcon, CCallback<void> onCreate, void *param ) -{ - TPageInfo *info = new TPageInfo; - info->m_onCreate = onCreate; - info->m_param = param; - info->m_pDlg = NULL; - - TCITEM tci = {0}; - tci.mask = TCIF_PARAM|TCIF_TEXT; - tci.lParam = (LPARAM)info; - tci.pszText = ptszName; - if (hIcon) - { - if (!m_hIml) - { - m_hIml = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32|ILC_MASK : ILC_COLOR16|ILC_MASK, 0, 1); - TabCtrl_SetImageList(m_hwnd, m_hIml); - } - - tci.mask |= TCIF_IMAGE; - tci.iImage = ImageList_AddIcon(m_hIml, hIcon); - } - - TabCtrl_InsertItem(m_hwnd, TabCtrl_GetItemCount(m_hwnd), &tci); -} - -void CCtrlPages::AttachDialog( int iPage, CDlgBase *pDlg ) -{ - if ((iPage < 0) || (iPage >= TabCtrl_GetItemCount(m_hwnd))) - return; - - TCITEM tci = {0}; - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(m_hwnd, iPage, &tci); - - if (TPageInfo *info = (TPageInfo *)tci.lParam) - { - if (info->m_pDlg) - info->m_pDlg->Close(); - - info->m_pDlg = pDlg; - //SetParent(info->m_pDlg->GetHwnd(), m_hwnd); - - if (iPage == TabCtrl_GetCurSel(m_hwnd)) - { - m_pActivePage = info->m_pDlg; - ShowPage(info->m_pDlg); - } - } -} - -void CCtrlPages::ShowPage(CDlgBase *pDlg) -{ - if (!pDlg) return; - - RECT rc; - GetClientRect(m_hwnd, &rc); - TabCtrl_AdjustRect(m_hwnd, FALSE, &rc); - MapWindowPoints(m_hwnd, ::GetParent(m_hwnd), (LPPOINT)&rc, 2); - SetWindowPos(pDlg->GetHwnd(), HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); -} - -void CCtrlPages::ActivatePage( int iPage ) -{ - TabCtrl_SetCurSel(m_hwnd, iPage); - //ShowPage(iPage); -} - -BOOL CCtrlPages::OnNotify( int /*idCtrl*/, NMHDR *pnmh ) -{ - switch (pnmh->code) - { - case TCN_SELCHANGING: - { - TCITEM tci = {0}; - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(m_hwnd, TabCtrl_GetCurSel(m_hwnd), &tci); - - if (TPageInfo *info = (TPageInfo *)tci.lParam) - { - if (info->m_pDlg) - { - m_pActivePage = NULL; - ShowWindow(info->m_pDlg->GetHwnd(), SW_HIDE); - } - } - - return TRUE; - } - - case TCN_SELCHANGE: - { - TCITEM tci = {0}; - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(m_hwnd, TabCtrl_GetCurSel(m_hwnd), &tci); - - if (TPageInfo *info = (TPageInfo *)tci.lParam) - { - if (info->m_pDlg) - { - m_pActivePage = info->m_pDlg; - ShowPage(info->m_pDlg); - } else - { - m_pActivePage = NULL; - info->m_onCreate(info->m_param); - } - } - - return TRUE; - } - } - - return FALSE; -} - -void CCtrlPages::OnDestroy() -{ - int count = TabCtrl_GetItemCount(m_hwnd); - for (int i = 0; i < count ; ++i) - { - TCITEM tci = {0}; - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(m_hwnd, i, &tci); - - if (TPageInfo *info = (TPageInfo *)tci.lParam) - { - if (info->m_pDlg) - info->m_pDlg->Close(); - - delete info; - } - } - - TabCtrl_DeleteAllItems(m_hwnd); - - if (m_hIml) - { - TabCtrl_SetImageList(m_hwnd, NULL); - ImageList_Destroy(m_hIml); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlBase - -CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) : - m_parentWnd( wnd ), - m_idCtrl( idCtrl ), - m_hwnd( NULL ), - m_wndproc( NULL ) -{ - if ( wnd ) { - m_next = wnd->m_first; - wnd->m_first = this; -} } - -void CCtrlBase::OnInit() -{ - m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : NULL; -} - -void CCtrlBase::OnDestroy() -{ - Unsubclass(); - m_hwnd = NULL; -} - -void CCtrlBase::Enable( int bIsEnable ) -{ - ::EnableWindow( m_hwnd, bIsEnable ); -} - -BOOL CCtrlBase::Enabled() const -{ - return ( m_hwnd ) ? IsWindowEnabled( m_hwnd ) : FALSE; -} - -LRESULT CCtrlBase::SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ) -{ - return ::SendMessage( m_hwnd, Msg, wParam, lParam ); -} - -void CCtrlBase::SetText(const TCHAR *text) -{ - ::SetWindowText( m_hwnd, text ); -} - -void CCtrlBase::SetTextA(const char *text) -{ - ::SetWindowTextA( m_hwnd, text ); -} - -void CCtrlBase::SetInt(int value) -{ - TCHAR buf[32] = {0}; - mir_sntprintf(buf, SIZEOF(buf), _T("%d"), value); - SetWindowText(m_hwnd, buf); -} - -TCHAR* CCtrlBase::GetText() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - TCHAR *result = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); - GetWindowText(m_hwnd, result, length); - return result; -} - -char* CCtrlBase::GetTextA() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - char *result = (char *)mir_alloc(length * sizeof(char)); - GetWindowTextA(m_hwnd, result, length); - return result; -} - -TCHAR* CCtrlBase::GetText(TCHAR *buf, int size) -{ - GetWindowText(m_hwnd, buf, size); - buf[size-1] = 0; - return buf; -} - -char* CCtrlBase::GetTextA(char *buf, int size) -{ - GetWindowTextA(m_hwnd, buf, size); - buf[size-1] = 0; - return buf; -} - -int CCtrlBase::GetInt() -{ - int length = GetWindowTextLength(m_hwnd) + 1; - TCHAR *result = (TCHAR *)_alloca(length * sizeof(TCHAR)); - GetWindowText(m_hwnd, result, length); - return _ttoi(result); -} - -LRESULT CCtrlBase::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_DESTROY) Unsubclass(); - return CallWindowProc(m_wndproc, m_hwnd, msg, wParam, lParam); -} - -void CCtrlBase::Subclass() -{ - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); - m_wndproc = (WNDPROC)SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassWndProc); -} - -void CCtrlBase::Unsubclass() -{ - if (m_wndproc) - { - SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)0); - m_wndproc = 0; -} } - -///////////////////////////////////////////////////////////////////////////////////////// -// CDbLink class - -CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue, bool bSigned): CDataLink(type, bSigned) -{ - m_szModule = mir_strdup(szModule); - m_szSetting = mir_strdup(szSetting); - m_iDefault = iValue; - m_szDefault = 0; - dbv.type = DBVT_DELETED; -} - -CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue): CDataLink(type, false) -{ - m_szModule = mir_strdup(szModule); - m_szSetting = mir_strdup(szSetting); - m_szDefault = mir_tstrdup(szValue); - dbv.type = DBVT_DELETED; -} - -CDbLink::~CDbLink() -{ - mir_free(m_szModule); - mir_free(m_szSetting); - mir_free(m_szDefault); - if (dbv.type != DBVT_DELETED) - DBFreeVariant(&dbv); -} - -DWORD CDbLink::LoadUnsigned() -{ - switch (m_type) { - case DBVT_BYTE: return DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_WORD: return DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_DWORD: return DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); - default: return m_iDefault; - } -} - -int CDbLink::LoadSigned() -{ - switch (m_type) { - case DBVT_BYTE: return (signed char)DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_WORD: return (signed short)DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); - case DBVT_DWORD: return (signed int)DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); - default: return m_iDefault; - } -} - -void CDbLink::SaveInt(DWORD value) -{ - switch (m_type) { - case DBVT_BYTE: DBWriteContactSettingByte(NULL, m_szModule, m_szSetting, (BYTE)value); break; - case DBVT_WORD: DBWriteContactSettingWord(NULL, m_szModule, m_szSetting, (WORD)value); break; - case DBVT_DWORD: DBWriteContactSettingDword(NULL, m_szModule, m_szSetting, value); break; - } -} - -TCHAR* CDbLink::LoadText() -{ - if (dbv.type != DBVT_DELETED) DBFreeVariant(&dbv); - if (!DBGetContactSettingTString(NULL, m_szModule, m_szSetting, &dbv)) - { - if (dbv.type == DBVT_TCHAR) - return dbv.ptszVal; - return m_szDefault; - } - - dbv.type = DBVT_DELETED; - return m_szDefault; -} - -void CDbLink::SaveText(TCHAR *value) -{ - DBWriteContactSettingTString(NULL, m_szModule, m_szSetting, value); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Base protocol dialog - -void CProtoIntDlgBase::SetStatusText(TCHAR *statusText) -{ - if (m_hwndStatus) - SendMessage(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)statusText); -} - -INT_PTR CProtoIntDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - { // call inherited init code first - INT_PTR result = CSuper::DlgProc(msg, wParam, lParam); - if (m_show_label) - { - m_hwndStatus = CreateStatusWindow(WS_CHILD|WS_VISIBLE, NULL, m_hwnd, IDC_STATUSBAR); - SetWindowPos(m_hwndStatus, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); - UpdateStatusBar(); - UpdateProtoTitle(); - } - return result; - } - - case WM_SETTEXT: - if (m_show_label && IsWindowUnicode(m_hwnd)) - - { - TCHAR *szTitle = (TCHAR *)lParam; - if (!_tcsstr(szTitle, m_proto_interface->m_tszUserName)) - { - UpdateProtoTitle(szTitle); - return TRUE; - } - } - break; - - case WM_SIZE: - if (m_hwndStatus) - { - RECT rcStatus; GetWindowRect(m_hwndStatus, &rcStatus); - RECT rcClient; GetClientRect(m_hwnd, &rcClient); - SetWindowPos(m_hwndStatus, NULL, 0, rcClient.bottom-(rcStatus.bottom-rcStatus.top), rcClient.right, (rcStatus.bottom-rcStatus.top), SWP_NOZORDER); - UpdateStatusBar(); - } - break; - - // Protocol events - case WM_PROTO_ACTIVATE: - OnProtoActivate(wParam, lParam); - return m_lresult; - case WM_PROTO_CHECK_ONLINE: - if (m_hwndStatus) - UpdateStatusBar(); - OnProtoCheckOnline(wParam, lParam); - return m_lresult; - case WM_PROTO_REFRESH: - OnProtoRefresh(wParam, lParam); - return m_lresult; - } - - return CSuper::DlgProc(msg, wParam, lParam); -} - -void CProtoIntDlgBase::UpdateProtoTitle(TCHAR *szText) -{ - if (!m_show_label) return; - - int curLength; - TCHAR *curText; - - if (szText) - { - curText = szText; - curLength = lstrlen(curText);; - } else - { - curLength = GetWindowTextLength(m_hwnd) + 1; - curText = (TCHAR *)_alloca(curLength * sizeof(TCHAR)); - GetWindowText(m_hwnd, curText, curLength); - } - - if (!_tcsstr(curText, m_proto_interface->m_tszUserName)) - { - int length = curLength + lstrlen(m_proto_interface->m_tszUserName) + 256; - TCHAR *text = (TCHAR *)_alloca(length * sizeof(TCHAR)); - mir_sntprintf(text, length, _T("%s [%s: %s]"), curText, TranslateT("Account"), m_proto_interface->m_tszUserName); - SetWindowText(m_hwnd, text); - } -} - -void CProtoIntDlgBase::UpdateStatusBar() -{ - SIZE sz; - - HDC hdc = GetDC(m_hwndStatus); - HFONT hFntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); - GetTextExtentPoint32(hdc, m_proto_interface->m_tszUserName, lstrlen(m_proto_interface->m_tszUserName), &sz); - sz.cx += GetSystemMetrics(SM_CXSMICON) * 3; - SelectObject(hdc, hFntSave); - ReleaseDC(m_hwndStatus, hdc); - - RECT rcStatus; GetWindowRect(m_hwndStatus, &rcStatus); - int parts[] = { rcStatus.right-rcStatus.left - sz.cx, -1 }; - SendMessage(m_hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); - SendMessage(m_hwndStatus, SB_SETICON, 1, (LPARAM)LoadSkinnedProtoIcon(m_proto_interface->m_szModuleName, m_proto_interface->m_iStatus)); - SendMessage(m_hwndStatus, SB_SETTEXT, 1, (LPARAM)m_proto_interface->m_tszUserName); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Misc utilities - -int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) -{ - if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton))) - PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton)); - return 0; -} - -void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow) -{ - for (; *idList; ++idList) - ShowWindow(GetDlgItem(hwndDlg, *idList), nCmdShow); -} diff --git a/protocols/JabberG/ui_utils.h b/protocols/JabberG/ui_utils.h deleted file mode 100644 index 9af9e8ba36..0000000000 --- a/protocols/JabberG/ui_utils.h +++ /dev/null @@ -1,1392 +0,0 @@ -/* - -Jabber Protocol Plugin for Miranda IM -Copyright ( C ) 2002-04 Santithorn Bunchua -Copyright ( C ) 2005-12 George Hazan -Copyright ( C ) 2007-09 Maxim Mluhov -Copyright ( C ) 2007-09 Victor Pavlychko - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or ( at your option ) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __jabber_ui_utils_h__ -#define __jabber_ui_utils_h__ - -#pragma warning(disable:4355) - -#ifndef LPLVCOLUMN -typedef struct tagNMLVSCROLL -{ - NMHDR hdr; - int dx; - int dy; -} NMLVSCROLL; -typedef struct tagLVG -{ - UINT cbSize; - UINT mask; - LPWSTR pszHeader; - int cchHeader; - LPWSTR pszFooter; - int cchFooter; - int iGroupId; - UINT stateMask; - UINT state; - UINT uAlign; -} LVGROUP, *PLVGROUP; -typedef struct tagLVGROUPMETRICS -{ - UINT cbSize; - UINT mask; - UINT Left; - UINT Top; - UINT Right; - UINT Bottom; - COLORREF crLeft; - COLORREF crTop; - COLORREF crRight; - COLORREF crBottom; - COLORREF crHeader; - COLORREF crFooter; -} LVGROUPMETRICS, *PLVGROUPMETRICS; -typedef struct tagLVTILEVIEWINFO -{ - UINT cbSize; - DWORD dwMask; - DWORD dwFlags; - SIZE sizeTile; - int cLines; - RECT rcLabelMargin; -} LVTILEVIEWINFO, *PLVTILEVIEWINFO; -typedef struct tagLVTILEINFO -{ - UINT cbSize; - int iItem; - UINT cColumns; - PUINT puColumns; -} LVTILEINFO, *PLVTILEINFO; -typedef struct -{ - UINT cbSize; - DWORD dwFlags; - int iItem; - DWORD dwReserved; -} LVINSERTMARK, * LPLVINSERTMARK; -typedef int (CALLBACK *PFNLVGROUPCOMPARE)(int, int, void *); -typedef struct tagLVINSERTGROUPSORTED -{ - PFNLVGROUPCOMPARE pfnGroupCompare; - void *pvData; - LVGROUP lvGroup; -} LVINSERTGROUPSORTED, *PLVINSERTGROUPSORTED; -typedef struct tagLVSETINFOTIP -{ - UINT cbSize; - DWORD dwFlags; - LPWSTR pszText; - int iItem; - int iSubItem; -} LVSETINFOTIP, *PLVSETINFOTIP; -#define LPLVCOLUMN LPLVCOLUMNA -#define LPLVITEM LPLVITEMA -#define LVN_BEGINSCROLL (LVN_FIRST-80) -#define LVN_ENDSCROLL (LVN_FIRST-81) -#define LVN_HOTTRACK (LVN_FIRST-21) -#define LVN_MARQUEEBEGIN (LVN_FIRST-56) -#define LVM_MAPINDEXTOID (LVM_FIRST + 180) -#define LVGF_HEADER 0x00000001 -#define LVGF_GROUPID 0x00000010 -#define ListView_MapIndexToID(hwnd, index) \ - (UINT)SendMessage((hwnd), LVM_MAPINDEXTOID, (WPARAM)index, (LPARAM)0) -#define TreeView_GetLineColor(hwnd) \ - (COLORREF)SendMessage((hwnd), TVM_GETLINECOLOR, 0, 0) -#define TreeView_SetLineColor(hwnd, clr) \ - (COLORREF)SendMessage((hwnd), TVM_SETLINECOLOR, 0, (LPARAM)(clr)) -#endif - -///////////////////////////////////////////////////////////////////////////////////////// -// Callbacks - -struct CCallbackImp -{ - struct CDummy - { int foo; - }; - -public: - __inline CCallbackImp(): m_object(NULL), m_func(NULL) {} - - __inline CCallbackImp(const CCallbackImp &other): m_object(other.m_object), m_func(other.m_func) {} - __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } - - __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } - __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } - - __inline operator bool() const { return m_object && m_func; } - - __inline bool CheckObject(void *object) const { return (object == m_object) ? true : false; } - -protected: - template<typename TClass, typename TArgument> - __inline CCallbackImp(TClass *object, void ( TClass::*func)(TArgument *argument)): m_object(( CDummy* )object), m_func((TFnCallback)func) {} - - __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } - -private: - typedef void ( CDummy::*TFnCallback)( void *argument ); - - CDummy* m_object; - TFnCallback m_func; -}; - -template<typename TArgument> -struct CCallback: public CCallbackImp -{ - typedef CCallbackImp CSuper; - -public: - __inline CCallback() {} - - template<typename TClass> - __inline CCallback(TClass *object, void ( TClass::*func)(TArgument *argument)): CCallbackImp(object, func) {} - - __inline CCallback& operator=( const CCallbackImp& x ) { CSuper::operator =( x ); return *this; } - - __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } -}; - -template<typename TClass, typename TArgument> -__inline CCallback<TArgument> Callback(TClass *object, void (TClass::*func)(TArgument *argument)) - { return CCallback<TArgument>(object, func); } - -///////////////////////////////////////////////////////////////////////////////////////// -// CDbLink - -class CDataLink -{ -protected: - BYTE m_type; - bool m_bSigned; - -public: - CDataLink(BYTE type, bool bSigned): m_type(type), m_bSigned(bSigned) {} - virtual ~CDataLink() {} - - __inline BYTE GetDataType() { return m_type; } - __inline BYTE GetDataSigned() { return m_bSigned; } - - virtual DWORD LoadUnsigned() = 0; - virtual int LoadSigned() = 0; - virtual void SaveInt(DWORD value) = 0; - - virtual TCHAR *LoadText() = 0; - virtual void SaveText(TCHAR *value) = 0; -}; - -class CDbLink: public CDataLink -{ - char *m_szModule; - char *m_szSetting; - bool m_bSigned; - - DWORD m_iDefault; - TCHAR *m_szDefault; - - DBVARIANT dbv; - -public: - CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue, bool bSigned = false); - CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue); - ~CDbLink(); - - DWORD LoadUnsigned(); - int LoadSigned(); - void SaveInt(DWORD value); - - TCHAR *LoadText(); - void SaveText(TCHAR *value); -}; - -template<class T> -class CMOptionLink: public CDataLink -{ -private: - CMOption<T> *m_option; - -public: - CMOptionLink(CMOption<T> &option): CDataLink(CMDBTraits<sizeof(T)>::DBTypeId, CMIntTraits<T>::IsSigned()), m_option(&option) {} - - DWORD LoadUnsigned() { return (DWORD)(T)*m_option; } - int LoadSigned() { return (int)(T)*m_option; } - void SaveInt(DWORD value) { *m_option = (T)value; } - - TCHAR *LoadText() { return NULL; } - void SaveText(TCHAR*) {} -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CDlgBase - base dialog class - -class CDlgBase -{ - friend class CCtrlBase; - friend class CCtrlData; - -public: - CDlgBase(int idDialog, HWND hwndParent); - virtual ~CDlgBase(); - - // general utilities - void Create(); - void Show(int nCmdShow = SW_SHOW); - int DoModal(); - - __inline HWND GetHwnd() const { return m_hwnd; } - __inline bool IsInitialized() const { return m_initialized; } - __inline void Close() { SendMessage(m_hwnd, WM_CLOSE, 0, 0); } - __inline const MSG *ActiveMessage() const { return &m_msg; } - - // dynamic creation support (mainly to avoid leaks in options) - struct CreateParam - { - CDlgBase *(*create)(void *param); - void *param; - }; - static INT_PTR CALLBACK DynamicDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - if (msg == WM_INITDIALOG) - { - CreateParam *param = (CreateParam *)lParam; - CDlgBase *wnd = param->create(param->param); - SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)GlobalDlgProc); - return GlobalDlgProc(hwnd, msg, wParam, (LPARAM)wnd); - } - - return FALSE; - } - - LRESULT m_lresult; - -protected: - HWND m_hwnd; - HWND m_hwndParent; - int m_idDialog; - MSG m_msg; - bool m_isModal; - bool m_initialized; - bool m_forceResizable; - - enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; - BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL - - CCtrlBase* m_first; - - // override this handlers to provide custom functionality - // general messages - virtual void OnInitDialog() { } - virtual void OnClose() { } - virtual void OnDestroy() { } - - // miranda-related stuff - virtual int Resizer(UTILRESIZECONTROL *urc); - virtual void OnApply() {} - virtual void OnReset() {} - virtual void OnChange(CCtrlBase*) {} - - // main dialog procedure - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - // resister controls - void AddControl(CCtrlBase *ctrl); - - // win32 stuff - void ThemeDialogBackground(BOOL tabbed); - -private: - LIST<CCtrlBase> m_controls; - - void NotifyControls(void (CCtrlBase::*fn)()); - CCtrlBase *FindControl(int idCtrl); - - static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); - - typedef HRESULT (STDAPICALLTYPE *pfnEnableThemeDialogTexture)(HWND,DWORD); - static pfnEnableThemeDialogTexture MyEnableThemeDialogTexture; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlBase - -class CCtrlBase -{ - friend class CDlgBase; - -public: - CCtrlBase(CDlgBase *wnd, int idCtrl ); - virtual ~CCtrlBase() { Unsubclass(); } - - __inline HWND GetHwnd() const { return m_hwnd; } - __inline CDlgBase *GetParent() { return m_parentWnd; } - - void Enable( int bIsEnable = true ); - __inline void Disable() { Enable( false ); } - BOOL Enabled( void ) const; - - LRESULT SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ); - - void SetText(const TCHAR *text); - void SetTextA(const char *text); - void SetInt(int value); - - TCHAR *GetText(); - char *GetTextA(); - - TCHAR *GetText(TCHAR *buf, int size); - char *GetTextA(char *buf, int size); - - int GetInt(); - - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } - virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } - - virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } - - virtual void OnInit(); - virtual void OnDestroy(); - - virtual void OnApply() {} - virtual void OnReset() {} - - static int cmp(const CCtrlBase *c1, const CCtrlBase *c2) - { - if (c1->m_idCtrl < c2->m_idCtrl) return -1; - if (c1->m_idCtrl > c2->m_idCtrl) return +1; - return 0; - } - -protected: - HWND m_hwnd; - int m_idCtrl; - CCtrlBase* m_next; - CDlgBase* m_parentWnd; - - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - void Subclass(); - void Unsubclass(); - -private: - WNDPROC m_wndproc; - static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - if (CCtrlBase *ctrl = (CCtrlBase*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) - if (ctrl) - return ctrl->CustomWndProc(msg, wParam, lParam); - - return DefWindowProc(hwnd, msg, wParam, lParam); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -class CCtrlButton : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlButton( CDlgBase* dlg, int ctrlId ); - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); - - CCallback<CCtrlButton> OnClick; -}; - -class CCtrlMButton : public CCtrlButton -{ - typedef CCtrlButton CSuper; - -public: - CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ); - CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ); - ~CCtrlMButton(); - - void MakeFlat(); - void MakePush(); - - virtual void OnInit(); - -protected: - char m_flags; - HICON m_hIcon; - const char* m_toolTip; -}; - -class CCtrlHyperlink : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlHyperlink( CDlgBase* dlg, int ctrlId, const char* url ); - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); - -protected: - const char* m_url; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlClc -class CCtrlClc: public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlClc( CDlgBase* dlg, int ctrlId ); - - void AddContact(HANDLE hContact); - void AddGroup(HANDLE hGroup); - void AutoRebuild(); - void DeleteItem(HANDLE hItem); - void EditLabel(HANDLE hItem); - void EndEditLabel(bool save); - void EnsureVisible(HANDLE hItem, bool partialOk); - void Expand(HANDLE hItem, DWORD flags); - HANDLE FindContact(HANDLE hContact); - HANDLE FindGroup(HANDLE hGroup); - COLORREF GetBkColor(); - bool GetCheck(HANDLE hItem); - int GetCount(); - HWND GetEditControl(); - DWORD GetExpand(HANDLE hItem); - int GetExtraColumns(); - BYTE GetExtraImage(HANDLE hItem, int iColumn); - HIMAGELIST GetExtraImageList(); - HFONT GetFont(int iFontId); - HANDLE GetSelection(); - HANDLE HitTest(int x, int y, DWORD *hitTest); - void SelectItem(HANDLE hItem); - void SetBkBitmap(DWORD mode, HBITMAP hBitmap); - void SetBkColor(COLORREF clBack); - void SetCheck(HANDLE hItem, bool check); - void SetExtraColumns(int iColumns); - void SetExtraImage(HANDLE hItem, int iColumn, int iImage); - void SetExtraImageList(HIMAGELIST hImgList); - void SetFont(int iFontId, HANDLE hFont, bool bRedraw); - void SetIndent(int iIndent); - void SetItemText(HANDLE hItem, char *szText); - void SetHideEmptyGroups(bool state); - void SetGreyoutFlags(DWORD flags); - bool GetHideOfflineRoot(); - void SetHideOfflineRoot(bool state); - void SetUseGroups(bool state); - void SetOfflineModes(DWORD modes); - DWORD GetExStyle(); - void SetExStyle(DWORD exStyle); - int GetLefrMargin(); - void SetLeftMargin(int iMargin); - HANDLE AddInfoItem(CLCINFOITEM *cii); - int GetItemType(HANDLE hItem); - HANDLE GetNextItem(HANDLE hItem, DWORD flags); - COLORREF GetTextColot(int iFontId); - void SetTextColor(int iFontId, COLORREF clText); - - struct TEventInfo - { - CCtrlClc *ctrl; - NMCLISTCONTROL *info; - }; - - CCallback<TEventInfo> OnExpanded; - CCallback<TEventInfo> OnListRebuilt; - CCallback<TEventInfo> OnItemChecked; - CCallback<TEventInfo> OnDragging; - CCallback<TEventInfo> OnDropped; - CCallback<TEventInfo> OnListSizeChange; - CCallback<TEventInfo> OnOptionsChanged; - CCallback<TEventInfo> OnDragStop; - CCallback<TEventInfo> OnNewContact; - CCallback<TEventInfo> OnContactMoved; - CCallback<TEventInfo> OnCheckChanged; - CCallback<TEventInfo> OnClick; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlData - data access controls base class - -class CCtrlData : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlData( CDlgBase* dlg, int ctrlId ); - - virtual ~CCtrlData() - { - if (m_dbLink) delete m_dbLink; - } - - __inline bool IsChanged() const { return m_changed; } - - void CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue, bool bSigned = false ); - void CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ); - void CreateDbLink( CDataLink *link ) { m_dbLink = link; } - - virtual void OnInit(); - - // Events - CCallback<CCtrlData> OnChange; - -protected: - CDataLink *m_dbLink; - bool m_changed; - - void NotifyChange(); - - __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } - __inline bool GetDataSigned() { return m_dbLink ? m_dbLink->GetDataSigned() ? true : false : false; } - __inline DWORD LoadUnsigned() { return m_dbLink ? m_dbLink->LoadUnsigned() : 0; } - __inline int LoadSigned() { return m_dbLink ? m_dbLink->LoadSigned() : 0; } - __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } - __inline const TCHAR *LoadText() { return m_dbLink ? m_dbLink->LoadText() : _T(""); } - __inline void SaveText(TCHAR *value) { if (m_dbLink) m_dbLink->SaveText(value); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCheck - -class CCtrlCheck : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlCheck( CDlgBase* dlg, int ctrlId ); - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { NotifyChange(); return TRUE; } - virtual void OnInit() - { - CSuper::OnInit(); - OnReset(); - } - virtual void OnApply() - { - SaveInt(GetState()); - } - virtual void OnReset() - { - SetState(LoadUnsigned()); - } - - int GetState(); - void SetState(int state); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlEdit - -class CCtrlEdit : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlEdit( CDlgBase* dlg, int ctrlId ); - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) - { - if (idCode == EN_CHANGE) - NotifyChange(); - return TRUE; - } - virtual void OnInit() - { - CSuper::OnInit(); - OnReset(); - } - virtual void OnApply() - { - if (GetDataType() == DBVT_TCHAR) - { - int len = GetWindowTextLength(m_hwnd) + 1; - TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); - GetWindowText(m_hwnd, buf, len); - SaveText(buf); - } - else if (GetDataType() != DBVT_DELETED) - { - SaveInt(GetInt()); - } - } - virtual void OnReset() - { - if (GetDataType() == DBVT_TCHAR) - SetText(LoadText()); - else if (GetDataType() != DBVT_DELETED) - SetInt(GetDataSigned() ? LoadSigned() : LoadUnsigned()); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListBox - -class CCtrlListBox : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlListBox( CDlgBase* dlg, int ctrlId ); - - int AddString(TCHAR *text, LPARAM data=0); - void DeleteString(int index); - int FindString(TCHAR *str, int index = -1, bool exact = false); - int GetCount(); - int GetCurSel(); - LPARAM GetItemData(int index); - TCHAR* GetItemText(int index); - TCHAR* GetItemText(int index, TCHAR *buf, int size); - bool GetSel(int index); - int GetSelCount(); - int* GetSelItems(int *items, int count); - int* GetSelItems(); - int InsertString(TCHAR *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(TCHAR *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void SetSel(int index, bool sel=true); - - // Events - CCallback<CCtrlListBox> OnDblClick; - CCallback<CCtrlListBox> OnSelCancel; - CCallback<CCtrlListBox> OnSelChange; - -protected: - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCombo - -class CCtrlCombo : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlCombo( CDlgBase* dlg, int ctrlId ); - - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) - { - switch (idCode) - { - case CBN_CLOSEUP: OnCloseup(this); break; - case CBN_DROPDOWN: OnDropdown(this); break; - - case CBN_EDITCHANGE: - case CBN_EDITUPDATE: - case CBN_SELCHANGE: - case CBN_SELENDOK: - NotifyChange(); - break; - } - return TRUE; - } - - virtual void OnInit() - { - CSuper::OnInit(); - OnReset(); - } - virtual void OnApply() - { - if (GetDataType() == DBVT_TCHAR) - { - int len = GetWindowTextLength(m_hwnd) + 1; - TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); - GetWindowText(m_hwnd, buf, len); - SaveText(buf); - } - else if (GetDataType() != DBVT_DELETED) - { - SaveInt(GetInt()); - } - } - virtual void OnReset() - { - if (GetDataType() == DBVT_TCHAR) - SetText(LoadText()); - else if (GetDataType() != DBVT_DELETED) - SetInt(LoadUnsigned()); - } - - // Control interface - int AddString(const TCHAR *text, LPARAM data = 0 ); - int AddStringA(const char *text, LPARAM data = 0 ); - void DeleteString(int index); - int FindString(const TCHAR *str, int index = -1, bool exact = false); - int FindStringA(const char *str, int index = -1, bool exact = false); - int GetCount(); - int GetCurSel(); - bool GetDroppedState(); - LPARAM GetItemData(int index); - TCHAR* GetItemText(int index); - TCHAR* GetItemText(int index, TCHAR *buf, int size); - int InsertString(TCHAR *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(TCHAR *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void ShowDropdown(bool show = true); - - // Events - CCallback<CCtrlCombo> OnCloseup; - CCallback<CCtrlCombo> OnDropdown; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListView - -class CCtrlListView : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlListView( CDlgBase* dlg, int ctrlId ); - - // Classic LV interface - DWORD ApproximateViewRect(int cx, int cy, int iCount); - void Arrange(UINT code); - void CancelEditLabel(); - HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); - void DeleteAllItems(); - void DeleteColumn(int iCol); - void DeleteItem(int iItem); - HWND EditLabel(int iItem); - int EnableGroupView(BOOL fEnable); - BOOL EnsureVisible(int i, BOOL fPartialOK); - int FindItem(int iStart, const LVFINDINFO *plvfi); - COLORREF GetBkColor(); - void GetBkImage(LPLVBKIMAGE plvbki); - UINT GetCallbackMask(); - BOOL GetCheckState(UINT iIndex); - void GetColumn(int iCol, LPLVCOLUMN pcol); - void GetColumnOrderArray(int iCount, int *lpiArray); - int GetColumnWidth(int iCol); - int GetCountPerPage(); - HWND GetEditControl(); - //void GetEmptyText(PWSTR pszText, UINT cchText); - DWORD GetExtendedListViewStyle(); - INT GetFocusedGroup(); - //void GetFooterInfo(LVFOOTERINFO *plvfi); - //void GetFooterItem(UINT iItem, LVFOOTERITEM *pfi); - //void GetFooterItemRect(UINT iItem, RECT *prc); - //void GetFooterRect(RECT *prc); - int GetGroupCount(); - //HIMAGELIST GetGroupHeaderImageList(); - void GetGroupInfo(int iGroupId, PLVGROUP pgrp); - void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp); - void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics); - //BOOL GetGroupRect(int iGroupId, RECT *prc); - UINT GetGroupState(UINT dwGroupId, UINT dwMask); - HWND GetHeader(); - HCURSOR GetHotCursor(); - INT GetHotItem(); - DWORD GetHoverTime(); - HIMAGELIST GetImageList(int iImageList); - BOOL GetInsertMark(LVINSERTMARK *plvim); - COLORREF GetInsertMarkColor(); - int GetInsertMarkRect(LPRECT prc); - BOOL GetISearchString(LPSTR lpsz); - void GetItem(LPLVITEM pitem); - int GetItemCount(); - //void GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc); - void GetItemPosition(int i, POINT *ppt); - void GetItemRect(int i, RECT *prc, int code); - DWORD GetItemSpacing(BOOL fSmall); - UINT GetItemState(int i, UINT mask); - void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax); - int GetNextItem(int iStart, UINT flags); - //BOOL GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags); - BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas); - BOOL GetOrigin(LPPOINT lpptOrg); - COLORREF GetOutlineColor(); - UINT GetSelectedColumn(); - UINT GetSelectedCount(); - INT GetSelectionMark(); - int GetStringWidth(LPCSTR psz); - BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect); - COLORREF GetTextBkColor(); - COLORREF GetTextColor(); - void GetTileInfo(PLVTILEINFO plvtinfo); - void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); - HWND GetToolTips(); - int GetTopIndex(); - BOOL GetUnicodeFormat(); - DWORD GetView(); - BOOL GetViewRect(RECT *prc); - void GetWorkAreas(INT nWorkAreas, LPRECT lprc); - BOOL HasGroup(int dwGroupId); - int HitTest(LPLVHITTESTINFO pinfo); - int HitTestEx(LPLVHITTESTINFO pinfo); - int InsertColumn(int iCol, const LPLVCOLUMN pcol); - int InsertGroup(int index, PLVGROUP pgrp); - void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); - int InsertItem(const LPLVITEM pitem); - BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); - BOOL IsGroupViewEnabled(); - UINT IsItemVisible(UINT index); - UINT MapIDToIndex(UINT id); - UINT MapIndexToID(UINT index); - BOOL RedrawItems(int iFirst, int iLast); - void RemoveAllGroups(); - int RemoveGroup(int iGroupId); - BOOL Scroll(int dx, int dy); - BOOL SetBkColor(COLORREF clrBk); - BOOL SetBkImage(LPLVBKIMAGE plvbki); - BOOL SetCallbackMask(UINT mask); - void SetCheckState(UINT iIndex, BOOL fCheck); - BOOL SetColumn(int iCol, LPLVCOLUMN pcol); - BOOL SetColumnOrderArray(int iCount, int *lpiArray); - BOOL SetColumnWidth(int iCol, int cx); - void SetExtendedListViewStyle(DWORD dwExStyle); - void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); - //HIMAGELIST SetGroupHeaderImageList(HIMAGELIST himl); - int SetGroupInfo(int iGroupId, PLVGROUP pgrp); - void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); - void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); - HCURSOR SetHotCursor(HCURSOR hCursor); - INT SetHotItem(INT iIndex); - void SetHoverTime(DWORD dwHoverTime); - DWORD SetIconSpacing(int cx, int cy); - HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); - BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); - BOOL SetInsertMark(LVINSERTMARK *plvim); - COLORREF SetInsertMarkColor(COLORREF color); - BOOL SetItem(const LPLVITEM pitem); - void SetItemCount(int cItems); - void SetItemCountEx(int cItems, DWORD dwFlags); - //HRESULT SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask); - BOOL SetItemPosition(int i, int x, int y); - void SetItemPosition32(int iItem, int x, int y); - void SetItemState(int i, UINT state, UINT mask); - void SetItemText(int i, int iSubItem, TCHAR *pszText); - COLORREF SetOutlineColor(COLORREF color); - void SetSelectedColumn(int iCol); - INT SetSelectionMark(INT iIndex); - BOOL SetTextBkColor(COLORREF clrText); - BOOL SetTextColor(COLORREF clrText); - BOOL SetTileInfo(PLVTILEINFO plvtinfo); - BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); - HWND SetToolTips(HWND ToolTip); - BOOL SetUnicodeFormat(BOOL fUnicode); - int SetView(DWORD iView); - void SetWorkAreas(INT nWorkAreas, LPRECT lprc); - int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); - BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - INT SubItemHitTest(LPLVHITTESTINFO pInfo); - INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); - BOOL Update(int iItem); - - // Additional APIs - HIMAGELIST CreateImageList(int iImageList); - void AddColumn(int iSubItem, TCHAR *name, int cx); - void AddGroup(int iGroupId, TCHAR *name); - int AddItem(TCHAR *text, int iIcon, LPARAM lParam = 0, int iGroupId = -1); - void SetItem(int iItem, int iSubItem, TCHAR *text, int iIcon = -1); - LPARAM GetItemData(int iItem); - - // Events - struct TEventInfo { - CCtrlListView *treeviewctrl; - union { - NMHDR *nmhdr; - NMLISTVIEW *nmlv; - NMLVDISPINFO *nmlvdi; - NMLVSCROLL *nmlvscr; - NMLVGETINFOTIP *nmlvit; - NMLVFINDITEM *nmlvfi; - NMITEMACTIVATE *nmlvia; - NMLVKEYDOWN *nmlvkey; - }; - }; - - CCallback<TEventInfo> OnBeginDrag; - CCallback<TEventInfo> OnBeginLabelEdit; - CCallback<TEventInfo> OnBeginRDrag; - CCallback<TEventInfo> OnBeginScroll; - CCallback<TEventInfo> OnColumnClick; - //CCallback<TEventInfo> OnColumnDropdown; - //CCallback<TEventInfo> OnColumnOverflowClick; - CCallback<TEventInfo> OnDeleteAllItems; - CCallback<TEventInfo> OnDeleteItem; - CCallback<TEventInfo> OnDoubleClick; - CCallback<TEventInfo> OnEndLabelEdit; - CCallback<TEventInfo> OnEndScroll; - CCallback<TEventInfo> OnGetDispInfo; - //CCallback<TEventInfo> OnGetEmptyMarkup; - CCallback<TEventInfo> OnGetInfoTip; - CCallback<TEventInfo> OnHotTrack; - CCallback<TEventInfo> OnIncrementalSearch; - CCallback<TEventInfo> OnInsertItem; - CCallback<TEventInfo> OnItemActivate; - CCallback<TEventInfo> OnItemChanged; - CCallback<TEventInfo> OnItemChanging; - CCallback<TEventInfo> OnKeyDown; - //CCallback<TEventInfo> OnLinkClick; - CCallback<TEventInfo> OnMarqueeBegin; - CCallback<TEventInfo> OnSetDispInfo; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -struct CFilterData; -class CCtrlFilterListView : public CCtrlListView -{ - typedef CCtrlListView CSuper; - -public: - CCtrlFilterListView(CDlgBase* dlg, int ctrlId, bool trackFilter, bool keepHiglight); - ~CCtrlFilterListView(); - - TCHAR *GetFilterText(); - CCallback<CCtrlFilterListView> OnFilterChanged; - -protected: - CFilterData *fdat; - bool m_trackFilter; - bool m_keepHiglight; - - void OnInit(); - LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - void FilterHighlight(TCHAR *filter); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -class CCtrlTreeView : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlTreeView( CDlgBase* dlg, int ctrlId ); - - // Classic TV interface - HIMAGELIST CreateDragImage(HTREEITEM hItem); - void DeleteAllItems(); - void DeleteItem(HTREEITEM hItem); - HWND EditLabel(HTREEITEM hItem); - void EndEditLabelNow(BOOL cancel); - void EnsureVisible(HTREEITEM hItem); - void Expand(HTREEITEM hItem, DWORD flag); - COLORREF GetBkColor(); - DWORD GetCheckState(HTREEITEM hItem); - HTREEITEM GetChild(HTREEITEM hItem); - int GetCount(); - HTREEITEM GetDropHilight(); - HWND GetEditControl(); - HTREEITEM GetFirstVisible(); - HIMAGELIST GetImageList(int iImage); - int GetIndent(); - COLORREF GetInsertMarkColor(); - void GetItem(TVITEMEX *tvi); - int GetItemHeight(); - void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect); - DWORD GetItemState(HTREEITEM hItem, DWORD stateMask); - HTREEITEM GetLastVisible(); - COLORREF GetLineColor(); - HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag); - HTREEITEM GetNextSibling(HTREEITEM hItem); - HTREEITEM GetNextVisible(HTREEITEM hItem); - HTREEITEM GetParent(HTREEITEM hItem); - HTREEITEM GetPrevSibling(HTREEITEM hItem); - HTREEITEM GetPrevVisible(HTREEITEM hItem); - HTREEITEM GetRoot(); - DWORD GetScrollTime(); - HTREEITEM GetSelection(); - COLORREF GetTextColor(); - HWND GetToolTips(); - BOOL GetUnicodeFormat(); - unsigned GetVisibleCount(); - HTREEITEM HitTest(TVHITTESTINFO *hti); - HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); - //HTREEITEM MapAccIDToHTREEITEM(UINT id); - //UINT MapHTREEITEMtoAccID(HTREEITEM hItem); - void Select(HTREEITEM hItem, DWORD flag); - void SelectDropTarget(HTREEITEM hItem); - void SelectItem(HTREEITEM hItem); - void SelectSetFirstVisible(HTREEITEM hItem); - COLORREF SetBkColor(COLORREF clBack); - void SetCheckState(HTREEITEM hItem, DWORD state); - void SetImageList(HIMAGELIST hIml, int iImage); - void SetIndent(int iIndent); - void SetInsertMark(HTREEITEM hItem, BOOL fAfter); - COLORREF SetInsertMarkColor(COLORREF clMark); - void SetItem(TVITEMEX *tvi); - void SetItemHeight(short cyItem); - void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); - COLORREF SetLineColor(COLORREF clLine); - void SetScrollTime(UINT uMaxScrollTime); - COLORREF SetTextColor(COLORREF clText); - HWND SetToolTips(HWND hwndToolTips); - BOOL SetUnicodeFormat(BOOL fUnicode); - void SortChildren(HTREEITEM hItem, BOOL fRecurse); - void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); - - // Additional stuff - void TranslateItem(HTREEITEM hItem); - void TranslateTree(); - HTREEITEM FindNamedItem(HTREEITEM hItem, const TCHAR *name); - void GetItem(HTREEITEM hItem, TVITEMEX *tvi); - void GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength); - - // Events - struct TEventInfo { - CCtrlTreeView *treeviewctrl; - union { - NMHDR *nmhdr; - NMTREEVIEW *nmtv; - NMTVDISPINFO *nmtvdi; - NMTVGETINFOTIP *nmtvit; - NMTVKEYDOWN *nmtvkey; - }; - }; - - CCallback<TEventInfo> OnBeginDrag; - CCallback<TEventInfo> OnBeginLabelEdit; - CCallback<TEventInfo> OnBeginRDrag; - CCallback<TEventInfo> OnDeleteItem; - CCallback<TEventInfo> OnEndLabelEdit; - CCallback<TEventInfo> OnGetDispInfo; - CCallback<TEventInfo> OnGetInfoTip; - CCallback<TEventInfo> OnItemExpanded; - CCallback<TEventInfo> OnItemExpanding; - CCallback<TEventInfo> OnKeyDown; - CCallback<TEventInfo> OnSelChanged; - CCallback<TEventInfo> OnSelChanging; - CCallback<TEventInfo> OnSetDispInfo; - CCallback<TEventInfo> OnSingleExpand; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -class CCtrlPages: public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlPages( CDlgBase* dlg, int ctrlId ); - - void AddPage( TCHAR *ptszName, HICON hIcon, CCallback<void> onCreate = CCallback<void>(), void *param = NULL ); - void AttachDialog( int iPage, CDlgBase *pDlg ); - - void ActivatePage( int iPage ); - - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh); - void OnInit(); - void OnDestroy(); - - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - -private: - HIMAGELIST m_hIml; - CDlgBase *m_pActivePage; - - struct TPageInfo - { - CCallback<void> m_onCreate; - void *m_param; - CDlgBase *m_pDlg; - }; - - void ShowPage(CDlgBase *pDlg); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCustom - -template<typename TDlg> -class CCtrlCustom : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -private: - void (TDlg::*m_pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode); - void (TDlg::*m_pfnOnNotify)(int idCtrl, NMHDR *pnmh); - void (TDlg::*m_pfnOnMeasureItem)(MEASUREITEMSTRUCT *param); - void (TDlg::*m_pfnOnDrawItem)(DRAWITEMSTRUCT *param); - void (TDlg::*m_pfnOnDeleteItem)(DELETEITEMSTRUCT *param); - -public: - CCtrlCustom(TDlg *wnd, int idCtrl, - void (TDlg::*pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode), - void (TDlg::*pfnOnNotify)(int idCtrl, NMHDR *pnmh), - void (TDlg::*pfnOnMeasureItem)(MEASUREITEMSTRUCT *param) = NULL, - void (TDlg::*pfnOnDrawItem)(DRAWITEMSTRUCT *param) = NULL, - void (TDlg::*pfnOnDeleteItem)(DELETEITEMSTRUCT *param) = NULL): CCtrlBase(wnd, idCtrl) - { - m_pfnOnCommand = pfnOnCommand; - m_pfnOnNotify = pfnOnNotify; - m_pfnOnMeasureItem = pfnOnMeasureItem; - m_pfnOnDrawItem = pfnOnDrawItem; - m_pfnOnDeleteItem = pfnOnDeleteItem; - } - - virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) - { - if (m_parentWnd && m_pfnOnCommand) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnCommand)(hwndCtrl, idCtrl, idCode); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnNotify(int idCtrl, NMHDR *pnmh) - { - if (m_parentWnd && m_pfnOnNotify) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnNotify)(idCtrl, pnmh); - return m_parentWnd->m_lresult; - } - return FALSE; - } - - virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnMeasureItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnMeasureItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnDrawItem(DRAWITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnDrawItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnDrawItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } - virtual BOOL OnDeleteItem(DELETEITEMSTRUCT *param) - { - if (m_parentWnd && m_pfnOnDeleteItem) { - m_parentWnd->m_lresult = 0; - (((TDlg *)m_parentWnd)->*m_pfnOnDeleteItem)(param); - return m_parentWnd->m_lresult; - } - return FALSE; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CProtoDlgBase - -#define WM_PROTO_REFRESH (WM_USER + 100) -#define WM_PROTO_CHECK_ONLINE (WM_USER + 101) -#define WM_PROTO_ACTIVATE (WM_USER + 102) -#define WM_PROTO_LAST (WM_USER + 200) - -typedef struct tagPROTO_INTERFACE PROTO_INTERFACE; - -class CProtoIntDlgBase : public CDlgBase -{ - typedef CDlgBase CSuper; - -public: - __inline CProtoIntDlgBase(PROTO_INTERFACE *proto, int idDialog, HWND parent, bool show_label=true) : - CDlgBase( idDialog, parent ), - m_proto_interface( proto ), - m_show_label( show_label ), - m_hwndStatus( NULL ) - { - } - - __inline void CreateLink( CCtrlData& ctrl, char *szSetting, BYTE type, DWORD iValue, bool bSigned = false ) - { - ctrl.CreateDbLink(m_proto_interface->m_szModuleName, szSetting, type, iValue, bSigned ); - } - __inline void CreateLink( CCtrlData& ctrl, const char *szSetting, TCHAR *szValue ) - { - ctrl.CreateDbLink(m_proto_interface->m_szModuleName, szSetting, szValue); - } - - template<class T> - __inline void CreateLink( CCtrlData& ctrl, CMOption<T> &option ) - { - ctrl.CreateDbLink(new CMOptionLink<T>(option)); - } - - __inline PROTO_INTERFACE *GetProtoInterface() { return m_proto_interface; } - - void SetStatusText(TCHAR *statusText); - -protected: - PROTO_INTERFACE *m_proto_interface; - bool m_show_label; - HWND m_hwndStatus; - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - virtual void OnProtoRefresh(WPARAM, LPARAM) {} - virtual void OnProtoActivate(WPARAM, LPARAM) {} - virtual void OnProtoCheckOnline(WPARAM, LPARAM) {} - -private: - void UpdateProtoTitle(TCHAR *szText = NULL); - void UpdateStatusBar(); -}; - -template<typename TProto> -class CProtoDlgBase : public CProtoIntDlgBase -{ - typedef CProtoIntDlgBase CSuper; - -public: - __inline CProtoDlgBase<TProto>(TProto *proto, int idDialog, HWND parent, bool show_label=true ) : - CProtoIntDlgBase( proto, idDialog, parent, show_label ), - m_proto( proto ) - { - } - - __inline TProto *GetProto() { return m_proto; } - -protected: - TProto* m_proto; - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - switch (msg) - { - case WM_INITDIALOG: - m_proto->WindowSubscribe(m_hwnd); - break; - case WM_DESTROY: - WindowFreeIcon(m_hwnd); - m_proto->WindowUnsubscribe(m_hwnd); - break; - } - - return CSuper::DlgProc(msg, wParam, lParam); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Safe open/close dialogs -#define UI_SAFE_OPEN(dlgClass, dlgPtr) \ - { \ - if (dlgPtr) \ - { \ - SetForegroundWindow((dlgPtr)->GetHwnd()); \ - } else \ - { \ - (dlgPtr) = new dlgClass(this); \ - (dlgPtr)->Show(); \ - } \ - } - -#define UI_SAFE_OPEN_EX(dlgClass, dlgPtr, dlgLocal) \ - if (dlgPtr) \ - { \ - ::SetForegroundWindow((dlgPtr)->GetHwnd()); \ - } else \ - { \ - (dlgPtr) = new dlgClass(this); \ - (dlgPtr)->Show(); \ - } \ - dlgClass *dlgLocal = (dlgClass *)(dlgPtr); - -#define UI_SAFE_CLOSE(dlg) \ - { \ - if ( dlg ) { \ - (dlg)->Close(); \ - (dlg) = NULL; \ - } \ - } - -#define UI_SAFE_CLOSE_HWND(hwnd) \ - { \ - if ( hwnd ) { \ - ::SendMessage( (hwnd), WM_CLOSE, 0, 0 ); \ - (hwnd) = NULL; \ - } \ - } - -///////////////////////////////////////////////////////////////////////////////////////// -// NULL-Safe dialog notifications -#define UI_SAFE_NOTIFY(dlg, msg) \ - { \ - if ( dlg ) \ - ::SendMessage((dlg)->GetHwnd(), msg, 0, 0); \ - } - -#define UI_SAFE_NOTIFY_HWND(hwnd, msg) \ - { \ - if ( hwnd ) \ - ::SendMessage((hwnd), msg, 0, 0); \ - } - -///////////////////////////////////////////////////////////////////////////////////////// -// Define message maps -#define UI_MESSAGE_MAP(dlgClass, baseDlgClass) \ - typedef baseDlgClass CMessageMapSuperClass; \ - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) \ - { \ - switch (msg) \ - { \ - case 0: \ - break /* just to handle ";" symbol after macro */ - -#define UI_MESSAGE(msg, proc) \ - case msg: \ - proc(msg, wParam, lParam); \ - break - -#define UI_MESSAGE_EX(msg, func) \ - case msg: \ - return func(msg, wParam, lParam) - -#define UI_POSTPROCESS_MESSAGE(msg, proc) \ - case msg: \ - CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - return FALSE - -#define UI_POSTPROCESS_MESSAGE_EX(msg, func) \ - case msg: \ - CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - return func(msg, wParam, lParam) - -#define UI_MESSAGE_MAP_END() \ - } \ - return CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - } - -///////////////////////////////////////////////////////////////////////////////////////// -// Misc utitlities -int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton); -void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow); - -#endif // __jabber_ui_utils_h__ diff --git a/protocols/JabberG/version.h b/protocols/JabberG/version.h deleted file mode 100644 index cf7a422dc2..0000000000 --- a/protocols/JabberG/version.h +++ /dev/null @@ -1,3 +0,0 @@ -#define __FILEVERSION_STRING 0,11,0,1 -#define __VERSION_STRING "0.11.0.1" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0,11,0,1) diff --git a/protocols/JabberG/version.rc b/protocols/JabberG/version.rc deleted file mode 100644 index 675df2f720..0000000000 --- a/protocols/JabberG/version.rc +++ /dev/null @@ -1,94 +0,0 @@ -#ifdef APSTUDIO_INVOKED -#error this file is not editable by Microsoft Visual C++ -#endif //APSTUDIO_INVOKED - -#include "version.h" -#include "resource.h" -#include "winres.h" -#include "richedit.h" - -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page( 1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Do not edit this dialogs in visual editor!!! -// - -IDD_CONSOLE DIALOGEX 0, 0, 354, 240 -STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "XML Console" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_CONSOLE,RICHEDIT_CLASS,WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x804,5,5,343,137 - CONTROL "Custom1",IDC_BTN_MSG,"MButtonClass",WS_TABSTOP,5,147,16,14 - CONTROL "Custom1",IDC_BTN_PRESENCE,"MButtonClass",WS_TABSTOP,21,147,16,14 - CONTROL "Custom1",IDC_BTN_IQ,"MButtonClass",WS_TABSTOP,37,147,16,14 - CONTROL "Custom1",IDC_BTN_FILTER,"MButtonClass",WS_TABSTOP,68,147,16,14 - COMBOBOX IDC_CB_FILTER,86,147,245,91,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "Custom1",IDC_BTN_FILTER_REFRESH,"MButtonClass",WS_TABSTOP,333,147,16,14 - EDITTEXT IDC_CONSOLEIN,5,166,343,38,ES_MULTILINE | WS_VSCROLL - PUSHBUTTON "Reset log",IDC_RESET,244,209,50,14 - DEFPUSHBUTTON "Send",IDOK,299,209,50,14 -END - -IDD_GROUPCHAT_INPUT DIALOGEX 0, 0, 242, 42 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - EDITTEXT IDC_TXT_MULTILINE,6,6,230,12,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | NOT WS_VISIBLE | WS_VSCROLL - EDITTEXT IDC_TXT_PASSWORD,6,6,230,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | ES_PASSWORD - COMBOBOX IDC_TXT_COMBO,6,6,230,92,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_TXT_RICHEDIT,RICHEDIT_CLASS,NOT WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x1004,6,6,230,12 - DEFPUSHBUTTON "OK",IDOK,131,23,50,14 - PUSHBUTTON "Cancel",IDCANCEL,186,23,50,14 -END - -#ifndef _MAC -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION __FILEVERSION_STRING - PRODUCTVERSION __FILEVERSION_STRING - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "\0" - VALUE "CompanyName", "Miranda\0" - VALUE "FileDescription", "Jabber Protocol Plugin for Miranda NG\0" - VALUE "FileVersion", __VERSION_STRING - VALUE "InternalName", "jabber\0" - VALUE "LegalCopyright", "Copyright ( c) 2002-04 Santithorn Bunchua, 2005 George Hazan \0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "jabber.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "Jabber Protocol Plugin for Miranda NG\0" - VALUE "ProductVersion", __VERSION_STRING - VALUE "SpecialBuild", "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // !_MAC -- cgit v1.2.3